summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKai Engert <kaie@kuix.de>2014-05-29 21:42:08 +0200
committerKai Engert <kaie@kuix.de>2014-05-29 21:42:08 +0200
commitb0dc1b6f2fcdcb4ada7c2e89aab7629a2bbc99ee (patch)
treee6979bb899e05730a2f6104157fb39d05db4b3ea
parente5bfc0c985a1ac582192c64e1e886ac284078712 (diff)
downloadnss-hg-b0dc1b6f2fcdcb4ada7c2e89aab7629a2bbc99ee.tar.gz
Bug 970539, NSS tool improvements/fixes: certutil/btoa/pp/httpserv, r=rrelyea
-rw-r--r--cmd/btoa/btoa.c20
-rw-r--r--cmd/certutil/certext.c346
-rw-r--r--cmd/certutil/certutil.c205
-rw-r--r--cmd/certutil/certutil.h7
-rw-r--r--cmd/httpserv/httpserv.c4
-rw-r--r--cmd/lib/secutil.c25
-rw-r--r--cmd/lib/secutil.h3
-rw-r--r--cmd/pp/pp.c50
-rw-r--r--lib/certdb/alg1485.c10
-rw-r--r--lib/certdb/genname.c33
-rw-r--r--lib/certdb/genname.h3
-rw-r--r--lib/nss/nss.def2
-rw-r--r--lib/pk11wrap/pk11load.c37
-rw-r--r--lib/util/oidstring.c31
-rwxr-xr-xtests/cert/cert.sh196
15 files changed, 858 insertions, 114 deletions
diff --git a/cmd/btoa/btoa.c b/cmd/btoa/btoa.c
index 7cee58acd..9416feb47 100644
--- a/cmd/btoa/btoa.c
+++ b/cmd/btoa/btoa.c
@@ -92,6 +92,10 @@ static void Usage(char *progName)
"-i input");
fprintf(stderr, "%-20s Define an output file to use (default is stdout)\n",
"-o output");
+ fprintf(stderr, "%-20s Wrap output in BEGIN/END lines and the given suffix\n",
+ "-w suffix");
+ fprintf(stderr, "%-20s (use \"c\" as a shortcut for suffix CERTIFICATE)\n",
+ "");
exit(-1);
}
@@ -102,6 +106,7 @@ int main(int argc, char **argv)
FILE *inFile, *outFile;
PLOptState *optstate;
PLOptStatus status;
+ char *suffix = NULL;
inFile = 0;
outFile = 0;
@@ -111,7 +116,7 @@ int main(int argc, char **argv)
progName = progName ? progName+1 : argv[0];
/* Parse command line arguments */
- optstate = PL_CreateOptState(argc, argv, "i:o:");
+ optstate = PL_CreateOptState(argc, argv, "i:o:w:");
while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
switch (optstate->option) {
default:
@@ -135,6 +140,13 @@ int main(int argc, char **argv)
return -1;
}
break;
+
+ case 'w':
+ if (!strcmp(optstate->value, "c"))
+ suffix = strdup("CERTIFICATE");
+ else
+ suffix = strdup(optstate->value);
+ break;
}
}
if (status == PL_OPT_BAD)
@@ -171,11 +183,17 @@ int main(int argc, char **argv)
#endif
outFile = stdout;
}
+ if (suffix) {
+ fprintf(outFile, "-----BEGIN %s-----\n", suffix);
+ }
rv = encode_file(outFile, inFile);
if (rv != SECSuccess) {
fprintf(stderr, "%s: lossage: error=%d errno=%d\n",
progName, PORT_GetError(), errno);
return -1;
}
+ if (suffix) {
+ fprintf(outFile, "-----END %s-----\n", suffix);
+ }
return 0;
}
diff --git a/cmd/certutil/certext.c b/cmd/certutil/certext.c
index ea423706f..a87b4b1fa 100644
--- a/cmd/certutil/certext.c
+++ b/cmd/certutil/certext.c
@@ -27,6 +27,8 @@
#include "xconst.h"
#include "prprf.h"
#include "certutil.h"
+#include "genname.h"
+#include "prnetdb.h"
#define GEN_BREAK(e) rv=e; break;
@@ -665,53 +667,213 @@ AddNscpCertType (void *extHandle, const char *userSuppliedValue)
}
+SECStatus
+GetOidFromString(PLArenaPool *arena, SECItem *to,
+ const char *from, size_t fromLen)
+{
+ SECStatus rv;
+ SECOidTag tag;
+ SECOidData *coid;
+
+ /* try dotted form first */
+ rv = SEC_StringToOID(arena, to, from, fromLen);
+ if (rv == SECSuccess) {
+ return rv;
+ }
+
+ /* Check to see if it matches a name in our oid table.
+ * SECOID_FindOIDByTag returns NULL if tag is out of bounds.
+ */
+ tag = SEC_OID_UNKNOWN;
+ coid = SECOID_FindOIDByTag(tag);
+ for ( ; coid; coid = SECOID_FindOIDByTag(++tag)) {
+ if (PORT_Strncasecmp(from, coid->desc, fromLen) == 0) {
+ break;
+ }
+ }
+ if (coid == NULL) {
+ /* none found */
+ return SECFailure;
+ }
+ return SECITEM_CopyItem(arena, to, &coid->oid);
+}
+
static SECStatus
AddSubjectAltNames(PLArenaPool *arena, CERTGeneralName **existingListp,
- const char *names, CERTGeneralNameType type)
+ const char *constNames, CERTGeneralNameType type)
{
CERTGeneralName *nameList = NULL;
CERTGeneralName *current = NULL;
PRCList *prev = NULL;
- const char *cp;
- char *tbuf;
+ char *cp, *nextName = NULL;
SECStatus rv = SECSuccess;
+ PRBool readTypeFromName = (PRBool) (type == 0);
+ char *names = NULL;
+
+ if (constNames)
+ names = PORT_Strdup(constNames);
+
+ if (names == NULL) {
+ return SECFailure;
+ }
/*
* walk down the comma separated list of names. NOTE: there is
* no sanity checks to see if the email address look like
* email addresses.
+ *
+ * Each name may optionally be prefixed with a type: string.
+ * If it isn't, the type from the previous name will be used.
+ * If there wasn't a previous name yet, the type given
+ * as a parameter to this function will be used.
+ * If the type value is zero (undefined), we'll fail.
*/
- for (cp=names; cp; cp = PORT_Strchr(cp,',')) {
+ for (cp=names; cp; cp=nextName) {
int len;
- char *end;
-
+ char *oidString;
+ char *nextComma;
+ CERTName *name;
+ PRStatus status;
+ unsigned char *data;
+ PRNetAddr addr;
+
+ nextName = NULL;
if (*cp == ',') {
cp++;
}
- end = PORT_Strchr(cp,',');
- len = end ? end-cp : PORT_Strlen(cp);
- if (len <= 0) {
+ nextComma = PORT_Strchr(cp, ',');
+ if (nextComma) {
+ *nextComma = 0;
+ nextName = nextComma+1;
+ }
+ if ((*cp) == 0) {
continue;
}
- tbuf = PORT_ArenaAlloc(arena,len+1);
- PORT_Memcpy(tbuf,cp,len);
- tbuf[len] = 0;
- current = (CERTGeneralName *) PORT_ZAlloc(sizeof(CERTGeneralName));
+ if (readTypeFromName) {
+ char *save=cp;
+ /* Because we already replaced nextComma with end-of-string,
+ * a found colon belongs to the current name */
+ cp = PORT_Strchr(cp, ':');
+ if (cp) {
+ *cp = 0;
+ cp++;
+ type = CERT_GetGeneralNameTypeFromString(save);
+ if (*cp == 0) {
+ continue;
+ }
+ } else {
+ if (type == 0) {
+ /* no type known yet */
+ rv = SECFailure;
+ break;
+ }
+ cp = save;
+ }
+ }
+
+ current = PORT_ArenaZNew(arena, CERTGeneralName);
if (!current) {
rv = SECFailure;
break;
}
+
+ current->type = type;
+ switch (type) {
+ /* string types */
+ case certRFC822Name:
+ case certDNSName:
+ case certURI:
+ current->name.other.data =
+ (unsigned char *) PORT_ArenaStrdup(arena,cp);
+ current->name.other.len = PORT_Strlen(cp);
+ break;
+ /* unformated data types */
+ case certX400Address:
+ case certEDIPartyName:
+ /* turn a string into a data and len */
+ rv = SECFailure; /* punt on these for now */
+ fprintf(stderr,"EDI Party Name and X.400 Address not supported\n");
+ break;
+ case certDirectoryName:
+ /* certDirectoryName */
+ name = CERT_AsciiToName(cp);
+ if (name == NULL) {
+ rv = SECFailure;
+ fprintf(stderr, "Invalid Directory Name (\"%s\")\n", cp);
+ break;
+ }
+ rv = CERT_CopyName(arena,&current->name.directoryName,name);
+ CERT_DestroyName(name);
+ break;
+ /* types that require more processing */
+ case certIPAddress:
+ /* convert the string to an ip address */
+ status = PR_StringToNetAddr(cp, &addr);
+ if (status != PR_SUCCESS) {
+ rv = SECFailure;
+ fprintf(stderr, "Invalid IP Address (\"%s\")\n", cp);
+ break;
+ }
+
+ if (PR_NetAddrFamily(&addr) == PR_AF_INET) {
+ len = sizeof(addr.inet.ip);
+ data = (unsigned char *)&addr.inet.ip;
+ } else if (PR_NetAddrFamily(&addr) == PR_AF_INET6) {
+ len = sizeof(addr.ipv6.ip);
+ data = (unsigned char *)&addr.ipv6.ip;
+ } else {
+ fprintf(stderr, "Invalid IP Family\n");
+ rv = SECFailure;
+ break;
+ }
+ current->name.other.data = PORT_ArenaAlloc(arena, len);
+ if (current->name.other.data == NULL) {
+ rv = SECFailure;
+ break;
+ }
+ current->name.other.len = len;
+ PORT_Memcpy(current->name.other.data,data, len);
+ break;
+ case certRegisterID:
+ rv = GetOidFromString(arena, &current->name.other, cp, strlen(cp));
+ break;
+ case certOtherName:
+ oidString = cp;
+ cp = PORT_Strchr(cp,';');
+ if (cp == NULL) {
+ rv = SECFailure;
+ fprintf(stderr, "missing name in other name\n");
+ break;
+ }
+ *cp++ = 0;
+ current->name.OthName.name.data =
+ (unsigned char *) PORT_ArenaStrdup(arena,cp);
+ if (current->name.OthName.name.data == NULL) {
+ rv = SECFailure;
+ break;
+ }
+ current->name.OthName.name.len = PORT_Strlen(cp);
+ rv = GetOidFromString(arena, &current->name.OthName.oid,
+ oidString, strlen(oidString));
+ break;
+ default:
+ rv = SECFailure;
+ fprintf(stderr, "Missing or invalid Subject Alternate Name type\n");
+ break;
+ }
+ if (rv == SECFailure) {
+ break;
+ }
+
if (prev) {
current->l.prev = prev;
prev->next = &(current->l);
} else {
nameList = current;
}
- current->type = type;
- current->name.other.data = (unsigned char *)tbuf;
- current->name.other.len = PORT_Strlen(tbuf);
prev = &(current->l);
}
+ PORT_Free(names);
/* at this point nameList points to the head of a doubly linked,
* but not yet circular, list and current points to its tail. */
if (rv == SECSuccess && nameList) {
@@ -749,6 +911,12 @@ AddDNSSubjectAlt(PLArenaPool *arena, CERTGeneralName **existingListp,
return AddSubjectAltNames(arena, existingListp, dnsNames, certDNSName);
}
+static SECStatus
+AddGeneralSubjectAlt(PLArenaPool *arena, CERTGeneralName **existingListp,
+ const char *altNames)
+{
+ return AddSubjectAltNames(arena, existingListp, altNames, 0);
+}
static SECStatus
AddBasicConstraint(void *extHandle)
@@ -1746,12 +1914,73 @@ AddInfoAccess(void *extHandle, PRBool addSIAExt, PRBool isCACert)
return (rv);
}
+/* Example of valid input:
+ * 1.2.3.4:critical:/tmp/abc,5.6.7.8:not-critical:/tmp/xyz
+ */
+static SECStatus
+parseNextGenericExt(const char *nextExtension, const char **oid, int *oidLen,
+ const char **crit, int *critLen,
+ const char **filename, int *filenameLen,
+ const char **next)
+{
+ const char *nextColon;
+ const char *nextComma;
+ const char *iter = nextExtension;
+
+ if (!iter || !*iter)
+ return SECFailure;
+
+ /* Require colons at earlier positions than nextComma (or end of string ) */
+ nextComma = strchr(iter, ',');
+
+ *oid = iter;
+ nextColon = strchr(iter, ':');
+ if (!nextColon || (nextComma && nextColon > nextComma))
+ return SECFailure;
+ *oidLen = (nextColon - *oid);
+
+ if (!*oidLen)
+ return SECFailure;
+
+ iter = nextColon;
+ ++iter;
+
+ *crit = iter;
+ nextColon = strchr(iter, ':');
+ if (!nextColon || (nextComma && nextColon > nextComma))
+ return SECFailure;
+ *critLen = (nextColon - *crit);
+
+ if (!*critLen)
+ return SECFailure;
+
+ iter = nextColon;
+ ++iter;
+
+ *filename = iter;
+ if (nextComma) {
+ *filenameLen = (nextComma - *filename);
+ iter = nextComma;
+ ++iter;
+ *next = iter;
+ } else {
+ *filenameLen = strlen(*filename);
+ *next = NULL;
+ }
+
+ if (!*filenameLen)
+ return SECFailure;
+
+ return SECSuccess;
+}
+
SECStatus
AddExtensions(void *extHandle, const char *emailAddrs, const char *dnsNames,
- certutilExtnList extList)
+ certutilExtnList extList, const char *extGeneric)
{
SECStatus rv = SECSuccess;
char *errstring = NULL;
+ const char *nextExtension = NULL;
do {
/* Add key usage extension */
@@ -1864,7 +2093,7 @@ AddExtensions(void *extHandle, const char *emailAddrs, const char *dnsNames,
}
}
- if (emailAddrs || dnsNames) {
+ if (emailAddrs || dnsNames || extList[ext_subjectAltName].activated) {
PLArenaPool *arena;
CERTGeneralName *namelist = NULL;
SECItem item = { 0, NULL, 0 };
@@ -1874,10 +2103,21 @@ AddExtensions(void *extHandle, const char *emailAddrs, const char *dnsNames,
rv = SECFailure;
break;
}
+
+ rv = SECSuccess;
+
+ if (emailAddrs) {
+ rv |= AddEmailSubjectAlt(arena, &namelist, emailAddrs);
+ }
- rv = AddEmailSubjectAlt(arena, &namelist, emailAddrs);
+ if (dnsNames) {
+ rv |= AddDNSSubjectAlt(arena, &namelist, dnsNames);
+ }
- rv |= AddDNSSubjectAlt(arena, &namelist, dnsNames);
+ if (extList[ext_subjectAltName].activated) {
+ rv |= AddGeneralSubjectAlt(arena, &namelist,
+ extList[ext_subjectAltName].arg);
+ }
if (rv == SECSuccess) {
rv = CERT_EncodeAltNameExtension(arena, namelist, &item);
@@ -1898,5 +2138,71 @@ AddExtensions(void *extHandle, const char *emailAddrs, const char *dnsNames,
if (rv != SECSuccess) {
SECU_PrintError(progName, "Problem creating %s extension", errstring);
}
+
+ nextExtension = extGeneric;
+ while (nextExtension && *nextExtension) {
+ SECItem oid_item, value;
+ PRBool isCritical;
+ const char *oid, *crit, *filename, *next;
+ int oidLen, critLen, filenameLen;
+ PRFileDesc *inFile = NULL;
+ char *zeroTerminatedFilename = NULL;
+
+ rv = parseNextGenericExt(nextExtension, &oid, &oidLen, &crit, &critLen,
+ &filename, &filenameLen, &next);
+ if (rv!= SECSuccess) {
+ SECU_PrintError(progName,
+ "error parsing generic extension parameter %s",
+ nextExtension);
+ break;
+ }
+ oid_item.data = NULL;
+ oid_item.len = 0;
+ rv = GetOidFromString(NULL, &oid_item, oid, oidLen);
+ if (rv != SECSuccess) {
+ SECU_PrintError(progName, "malformed extension OID %s", nextExtension);
+ break;
+ }
+ if (!strncmp("critical", crit, critLen)) {
+ isCritical = PR_TRUE;
+ } else if (!strncmp("not-critical", crit, critLen)) {
+ isCritical = PR_FALSE;
+ } else {
+ rv = SECFailure;
+ SECU_PrintError(progName, "expected 'critical' or 'not-critical'");
+ break;
+ }
+ zeroTerminatedFilename = PL_strndup(filename, filenameLen);
+ if (!zeroTerminatedFilename) {
+ rv = SECFailure;
+ SECU_PrintError(progName, "out of memory");
+ break;
+ }
+ rv = SECFailure;
+ inFile = PR_Open(zeroTerminatedFilename, PR_RDONLY, 0);
+ if (inFile) {
+ rv = SECU_ReadDERFromFile(&value, inFile, PR_FALSE, PR_FALSE);
+ PR_Close(inFile);
+ inFile = NULL;
+ }
+ if (rv != SECSuccess) {
+ SECU_PrintError(progName, "unable to read file %s",
+ zeroTerminatedFilename);
+ }
+ PL_strfree(zeroTerminatedFilename);
+ if (rv != SECSuccess) {
+ break;
+ }
+ rv = CERT_AddExtensionByOID(extHandle, &oid_item, &value, isCritical,
+ PR_FALSE /*copyData*/);
+ if (rv != SECSuccess) {
+ SECITEM_FreeItem(&oid_item, PR_FALSE);
+ SECITEM_FreeItem(&value, PR_FALSE);
+ SECU_PrintError(progName, "failed to add extension %s", nextExtension);
+ break;
+ }
+ nextExtension = next;
+ }
+
return rv;
}
diff --git a/cmd/certutil/certutil.c b/cmd/certutil/certutil.c
index 1c33e6fcc..5b5d744ae 100644
--- a/cmd/certutil/certutil.c
+++ b/cmd/certutil/certutil.c
@@ -182,7 +182,7 @@ static SECStatus
CertReq(SECKEYPrivateKey *privk, SECKEYPublicKey *pubk, KeyType keyType,
SECOidTag hashAlgTag, CERTName *subject, char *phone, int ascii,
const char *emailAddrs, const char *dnsNames,
- certutilExtnList extnList,
+ certutilExtnList extnList, const char *extGeneric,
/*out*/ SECItem *result)
{
CERTSubjectPublicKeyInfo *spki;
@@ -220,7 +220,7 @@ CertReq(SECKEYPrivateKey *privk, SECKEYPublicKey *pubk, KeyType keyType,
PORT_FreeArena (arena, PR_FALSE);
return SECFailure;
}
- if (AddExtensions(extHandle, emailAddrs, dnsNames, extnList)
+ if (AddExtensions(extHandle, emailAddrs, dnsNames, extnList, extGeneric)
!= SECSuccess) {
PORT_FreeArena (arena, PR_FALSE);
return SECFailure;
@@ -420,12 +420,65 @@ DumpChain(CERTCertDBHandle *handle, char *name, PRBool ascii)
}
static SECStatus
-listCerts(CERTCertDBHandle *handle, char *name, char *email, PK11SlotInfo *slot,
- PRBool raw, PRBool ascii, PRFileDesc *outfile, void *pwarg)
+outputCertOrExtension(CERTCertificate *the_cert, PRBool raw, PRBool ascii,
+ SECItem *extensionOID, PRFileDesc *outfile)
{
SECItem data;
PRInt32 numBytes;
SECStatus rv = SECFailure;
+ if (extensionOID) {
+ int i;
+ PRBool found = PR_FALSE;
+ for (i=0; the_cert->extensions[i] != NULL; i++) {
+ CERTCertExtension *extension = the_cert->extensions[i];
+ if (SECITEM_CompareItem(&extension->id, extensionOID) == SECEqual) {
+ found = PR_TRUE;
+ numBytes = PR_Write(outfile, extension->value.data,
+ extension->value.len);
+ rv = SECSuccess;
+ if (numBytes != (PRInt32) extension->value.len) {
+ SECU_PrintSystemError(progName, "error writing extension");
+ rv = SECFailure;
+ }
+ rv = SECSuccess;
+ break;
+ }
+ }
+ if (!found) {
+ SECU_PrintSystemError(progName, "extension not found");
+ rv = SECFailure;
+ }
+ } else {
+ data.data = the_cert->derCert.data;
+ data.len = the_cert->derCert.len;
+ if (ascii) {
+ PR_fprintf(outfile, "%s\n%s\n%s\n", NS_CERT_HEADER,
+ BTOA_DataToAscii(data.data, data.len), NS_CERT_TRAILER);
+ rv = SECSuccess;
+ } else if (raw) {
+ numBytes = PR_Write(outfile, data.data, data.len);
+ rv = SECSuccess;
+ if (numBytes != (PRInt32) data.len) {
+ SECU_PrintSystemError(progName, "error writing raw cert");
+ rv = SECFailure;
+ }
+ } else {
+ rv = SEC_PrintCertificateAndTrust(the_cert, "Certificate", NULL);
+ if (rv != SECSuccess) {
+ SECU_PrintError(progName, "problem printing certificate");
+ }
+ }
+ }
+ return rv;
+}
+
+static SECStatus
+listCerts(CERTCertDBHandle *handle, char *name, char *email,
+ PK11SlotInfo *slot, PRBool raw, PRBool ascii,
+ SECItem *extensionOID,
+ PRFileDesc *outfile, void *pwarg)
+{
+ SECStatus rv = SECFailure;
CERTCertList *certs;
CERTCertListNode *node;
@@ -461,34 +514,13 @@ listCerts(CERTCertDBHandle *handle, char *name, char *email, PK11SlotInfo *slot,
}
for (node = CERT_LIST_HEAD(certs); !CERT_LIST_END(node,certs);
node = CERT_LIST_NEXT(node)) {
- the_cert = node->cert;
- /* now get the subjectList that matches this cert */
- data.data = the_cert->derCert.data;
- data.len = the_cert->derCert.len;
- if (ascii) {
- PR_fprintf(outfile, "%s\n%s\n%s\n", NS_CERT_HEADER,
- BTOA_DataToAscii(data.data, data.len), NS_CERT_TRAILER);
- rv = SECSuccess;
- } else if (raw) {
- numBytes = PR_Write(outfile, data.data, data.len);
- if (numBytes != (PRInt32) data.len) {
- SECU_PrintSystemError(progName, "error writing raw cert");
- rv = SECFailure;
- }
- rv = SECSuccess;
- } else {
- rv = SEC_PrintCertificateAndTrust(the_cert, "Certificate", NULL);
- if (rv != SECSuccess) {
- SECU_PrintError(progName, "problem printing certificate");
- }
-
- }
+ rv = outputCertOrExtension(node->cert, raw, ascii, extensionOID,
+ outfile);
if (rv != SECSuccess) {
break;
}
}
} else if (email) {
- CERTCertificate *the_cert;
certs = PK11_FindCertsFromEmailAddress(email, NULL);
if (!certs) {
SECU_PrintError(progName,
@@ -498,28 +530,8 @@ listCerts(CERTCertDBHandle *handle, char *name, char *email, PK11SlotInfo *slot,
}
for (node = CERT_LIST_HEAD(certs); !CERT_LIST_END(node,certs);
node = CERT_LIST_NEXT(node)) {
- the_cert = node->cert;
- /* now get the subjectList that matches this cert */
- data.data = the_cert->derCert.data;
- data.len = the_cert->derCert.len;
- if (ascii) {
- PR_fprintf(outfile, "%s\n%s\n%s\n", NS_CERT_HEADER,
- BTOA_DataToAscii(data.data, data.len),
- NS_CERT_TRAILER);
- rv = SECSuccess;
- } else if (raw) {
- numBytes = PR_Write(outfile, data.data, data.len);
- rv = SECSuccess;
- if (numBytes != (PRInt32) data.len) {
- SECU_PrintSystemError(progName, "error writing raw cert");
- rv = SECFailure;
- }
- } else {
- rv = SEC_PrintCertificateAndTrust(the_cert, "Certificate", NULL);
- if (rv != SECSuccess) {
- SECU_PrintError(progName, "problem printing certificate");
- }
- }
+ rv = outputCertOrExtension(node->cert, raw, ascii, extensionOID,
+ outfile);
if (rv != SECSuccess) {
break;
}
@@ -547,8 +559,9 @@ listCerts(CERTCertDBHandle *handle, char *name, char *email, PK11SlotInfo *slot,
static SECStatus
ListCerts(CERTCertDBHandle *handle, char *nickname, char *email,
- PK11SlotInfo *slot, PRBool raw, PRBool ascii, PRFileDesc *outfile,
- secuPWData *pwdata)
+ PK11SlotInfo *slot, PRBool raw, PRBool ascii,
+ SECItem *extensionOID,
+ PRFileDesc *outfile, secuPWData *pwdata)
{
SECStatus rv;
@@ -569,7 +582,8 @@ ListCerts(CERTCertDBHandle *handle, char *nickname, char *email,
CERT_DestroyCertList(list);
return SECSuccess;
}
- rv = listCerts(handle, nickname, email, slot, raw, ascii, outfile, pwdata);
+ rv = listCerts(handle, nickname, email, slot, raw, ascii,
+ extensionOID, outfile, pwdata);
return rv;
}
@@ -615,6 +629,15 @@ ValidateCert(CERTCertDBHandle *handle, char *name, char *date,
case 'O':
usage = certificateUsageStatusResponder;
break;
+ case 'L':
+ usage = certificateUsageSSLCA;
+ break;
+ case 'A':
+ usage = certificateUsageAnyCA;
+ break;
+ case 'Y':
+ usage = certificateUsageVerifyCA;
+ break;
case 'C':
usage = certificateUsageSSLClient;
break;
@@ -989,7 +1012,7 @@ PrintSyntax(char *progName)
FPS "\t\t [-f targetPWfile] [-@ sourcePWFile]\n");
FPS "\t%s -L [-n cert-name] [--email email-address] [-X] [-r] [-a]\n",
progName);
- FPS "\t\t [-d certdir] [-P dbprefix]\n");
+ FPS "\t\t [--dump-ext-val OID] [-d certdir] [-P dbprefix]\n");
FPS "\t%s -M -n cert-name -t trustargs [-d certdir] [-P dbprefix]\n",
progName);
FPS "\t%s -O -n cert-name [-X] [-d certdir] [-a] [-P dbprefix]\n", progName);
@@ -1008,7 +1031,8 @@ PrintSyntax(char *progName)
"\t\t [-p phone] [-1] [-2] [-3] [-4] [-5] [-6] [-7 emailAddrs]\n"
"\t\t [-8 DNS-names]\n"
"\t\t [--extAIA] [--extSIA] [--extCP] [--extPM] [--extPC] [--extIA]\n"
- "\t\t [--extSKID] [--extNC]\n", progName);
+ "\t\t [--extSKID] [--extNC] [--extSAN type:name[,type:name]...]\n"
+ "\t\t [--extGeneric OID:critical-flag:filename[,OID:critical-flag:filename]...]\n", progName);
FPS "\t%s -U [-X] [-d certdir] [-P dbprefix]\n", progName);
exit(1);
}
@@ -1308,7 +1332,7 @@ static void luL(enum usage_level ul, const char *command)
{
int is_my_command = (command && 0 == strcmp(command, "L"));
if (ul == usage_all || !command || is_my_command)
- FPS "%-15s List all certs, or print out a single named cert\n",
+ FPS "%-15s List all certs, or print out a single named cert (or a subset)\n",
"-L");
if (ul == usage_selected && !is_my_command)
return;
@@ -1327,6 +1351,9 @@ static void luL(enum usage_level ul, const char *command)
" -r");
FPS "%-20s For single cert, print ASCII encoding (RFC1113)\n",
" -a");
+ FPS "%-20s \n"
+ "%-20s For single cert, print binary DER encoding of extension OID\n",
+ " --dump-ext-val OID", "");
FPS "\n");
}
@@ -1472,6 +1499,9 @@ static void luV(enum usage_level ul, const char *command)
FPS "%-20s Specify certificate usage:\n", " -u certusage");
FPS "%-25s C \t SSL Client\n", "");
FPS "%-25s V \t SSL Server\n", "");
+ FPS "%-25s L \t SSL CA\n", "");
+ FPS "%-25s A \t Any CA\n", "");
+ FPS "%-25s Y \t Verify CA\n", "");
FPS "%-25s S \t Email signer\n", "");
FPS "%-25s R \t Email Recipient\n", "");
FPS "%-25s O \t OCSP status responder\n", "");
@@ -1638,6 +1668,18 @@ static void luS(enum usage_level ul, const char *command)
" See -G for available key flag options");
FPS "%-20s Create a name constraints extension\n",
" --extNC ");
+ FPS "%-20s \n"
+ "%-20s Create a Subject Alt Name extension with one or multiple names\n",
+ " --extSAN type:name[,type:name]...", "");
+ FPS "%-20s - type: directory, dn, dns, edi, ediparty, email, ip, ipaddr,\n", "");
+ FPS "%-20s other, registerid, rfc822, uri, x400, x400addr\n", "");
+ FPS "%-20s \n"
+ "%-20s Add one or multiple extensions that certutil cannot encode yet,\n"
+ "%-20s by loading their encodings from external files.\n",
+ " --extGeneric OID:critical-flag:filename[,OID:critical-flag:filename]...", "", "");
+ FPS "%-20s - OID (example): 1.2.3.4\n", "");
+ FPS "%-20s - critical-flag: critical or not-critical\n", "");
+ FPS "%-20s - filename: full path to a file containing an encoded extension\n", "");
FPS "\n");
}
@@ -1836,6 +1878,7 @@ CreateCert(
PRBool ascii,
PRBool selfsign,
certutilExtnList extnList,
+ const char *extGeneric,
int certVersion,
SECItem * certDER)
{
@@ -1864,7 +1907,7 @@ CreateCert(
GEN_BREAK (SECFailure)
}
- rv = AddExtensions(extHandle, emailAddrs, dnsNames, extnList);
+ rv = AddExtensions(extHandle, emailAddrs, dnsNames, extnList, extGeneric);
if (rv != SECSuccess) {
GEN_BREAK (SECFailure)
}
@@ -2212,6 +2255,9 @@ enum certutilOpts {
opt_KeyAttrFlags,
opt_EmptyPassword,
opt_CertVersion,
+ opt_AddSubjectAltNameExt,
+ opt_DumpExtensionValue,
+ opt_GenericExtensions,
opt_Help
};
@@ -2323,6 +2369,11 @@ secuCommandFlag options_init[] =
"empty-password"},
{ /* opt_CertVersion */ 0, PR_FALSE, 0, PR_FALSE,
"certVersion"},
+ { /* opt_AddSubjectAltExt */ 0, PR_TRUE, 0, PR_FALSE, "extSAN"},
+ { /* opt_DumpExtensionValue */ 0, PR_TRUE, 0, PR_FALSE,
+ "dump-ext-val"},
+ { /* opt_GenericExtensions */ 0, PR_TRUE, 0, PR_FALSE,
+ "extGeneric"},
};
#define NUM_OPTIONS ((sizeof options_init) / (sizeof options_init[0]))
@@ -2663,9 +2714,10 @@ certutil_main(int argc, char **argv, PRBool initialize)
return 255;
}
- /* if -L is given raw or ascii mode, it must be for only one cert. */
+ /* if -L is given raw, ascii or dump mode, it must be for only one cert. */
if (certutil.commands[cmd_ListCerts].activated &&
(certutil.options[opt_ASCIIForIO].activated ||
+ certutil.options[opt_DumpExtensionValue].activated ||
certutil.options[opt_BinaryDER].activated) &&
!certutil.options[opt_Nickname].activated) {
PR_fprintf(PR_STDERR,
@@ -2985,10 +3037,29 @@ merge_fail:
/* List certs (-L) */
if (certutil.commands[cmd_ListCerts].activated) {
- rv = ListCerts(certHandle, name, email, slot,
- certutil.options[opt_BinaryDER].activated,
- certutil.options[opt_ASCIIForIO].activated,
- outFile, &pwdata);
+ if (certutil.options[opt_DumpExtensionValue].activated) {
+ const char *oid_str;
+ SECItem oid_item;
+ oid_item.data = NULL;
+ oid_item.len = 0;
+ oid_str = certutil.options[opt_DumpExtensionValue].arg;
+ SECStatus srv = GetOidFromString(NULL, &oid_item,
+ oid_str, strlen(oid_str));
+ if (srv != SECSuccess) {
+ SECU_PrintError(progName, "malformed extension OID %s",
+ oid_str);
+ goto shutdown;
+ }
+ rv = ListCerts(certHandle, name, email, slot,
+ PR_TRUE /*binary*/, PR_FALSE /*ascii*/,
+ &oid_item,
+ outFile, &pwdata);
+ } else {
+ rv = ListCerts(certHandle, name, email, slot,
+ certutil.options[opt_BinaryDER].activated,
+ certutil.options[opt_ASCIIForIO].activated,
+ NULL, outFile, &pwdata);
+ }
goto shutdown;
}
if (certutil.commands[cmd_DumpChain].activated) {
@@ -3179,6 +3250,12 @@ merge_fail:
certutil_extns[ext_extKeyUsage].arg =
certutil.options[opt_AddCmdExtKeyUsageExt].arg;
}
+ certutil_extns[ext_subjectAltName].activated =
+ certutil.options[opt_AddSubjectAltNameExt].activated;
+ if (certutil_extns[ext_subjectAltName].activated) {
+ certutil_extns[ext_subjectAltName].arg =
+ certutil.options[opt_AddSubjectAltNameExt].arg;
+ }
certutil_extns[ext_authInfoAcc].activated =
certutil.options[opt_AddAuthInfoAccExt].activated;
@@ -3218,6 +3295,8 @@ merge_fail:
certutil.options[opt_ExtendedEmailAddrs].arg,
certutil.options[opt_ExtendedDNSNames].arg,
certutil_extns,
+ (certutil.options[opt_GenericExtensions].activated ?
+ certutil.options[opt_GenericExtensions].arg : NULL),
&certReqDER);
if (rv)
goto shutdown;
@@ -3240,6 +3319,8 @@ merge_fail:
NULL,
NULL,
nullextnlist,
+ (certutil.options[opt_GenericExtensions].activated ?
+ certutil.options[opt_GenericExtensions].arg : NULL),
&certReqDER);
if (rv)
goto shutdown;
@@ -3259,6 +3340,8 @@ merge_fail:
certutil.commands[cmd_CreateNewCert].activated,
certutil.options[opt_SelfSign].activated,
certutil_extns,
+ (certutil.options[opt_GenericExtensions].activated ?
+ certutil.options[opt_GenericExtensions].arg : NULL),
certVersion,
&certDER);
if (rv)
diff --git a/cmd/certutil/certutil.h b/cmd/certutil/certutil.h
index d4388fc34..928664907 100644
--- a/cmd/certutil/certutil.h
+++ b/cmd/certutil/certutil.h
@@ -35,6 +35,7 @@ enum certutilExtns {
ext_inhibitAnyPolicy,
ext_subjectKeyID,
ext_nameConstraints,
+ ext_subjectAltName,
ext_End
};
@@ -47,7 +48,11 @@ typedef ExtensionEntry certutilExtnList[ext_End];
extern SECStatus
AddExtensions(void *extHandle, const char *emailAddrs, const char *dnsNames,
- certutilExtnList extList);
+ certutilExtnList extList, const char *extGeneric);
+
+extern SECStatus
+GetOidFromString(PLArenaPool *arena, SECItem *to,
+ const char *from, size_t fromLen);
#endif /* _CERTUTIL_H */
diff --git a/cmd/httpserv/httpserv.c b/cmd/httpserv/httpserv.c
index 6f37e42a8..875b62bbd 100644
--- a/cmd/httpserv/httpserv.c
+++ b/cmd/httpserv/httpserv.c
@@ -1312,8 +1312,10 @@ main(int argc, char **argv)
inFile = PR_Open(revoInfo->crlFilename, PR_RDONLY, 0);
if (inFile) {
rv = SECU_ReadDERFromFile(&crlDER, inFile, PR_FALSE, PR_FALSE);
+ PR_Close(inFile);
+ inFile = NULL;
}
- if (!inFile || rv != SECSuccess) {
+ if (rv != SECSuccess) {
fprintf(stderr, "unable to read crl file %s\n",
revoInfo->crlFilename);
exit(1);
diff --git a/cmd/lib/secutil.c b/cmd/lib/secutil.c
index d06dcf3cb..02570103a 100644
--- a/cmd/lib/secutil.c
+++ b/cmd/lib/secutil.c
@@ -52,6 +52,19 @@ static char consoleName[] = {
#include "ssl.h"
#include "sslproto.h"
+static PRBool utf8DisplayEnabled = PR_FALSE;
+
+void
+SECU_EnableUtf8Display(PRBool enable)
+{
+ utf8DisplayEnabled = enable;
+}
+
+PRBool
+SECU_GetUtf8DisplayEnabled(void)
+{
+ return utf8DisplayEnabled;
+}
static void
secu_ClearPassword(char *p)
@@ -609,12 +622,22 @@ secu_PrintRawStringQuotesOptional(FILE *out, SECItem *si, const char *m,
for (i = 0; i < si->len; i++) {
unsigned char val = si->data[i];
+ unsigned char c;
if (SECU_GetWrapEnabled() && column > 76) {
SECU_Newline(out);
SECU_Indent(out, level); column = level*INDENT_MULT;
}
- fprintf(out,"%c", printable[val]); column++;
+ if (utf8DisplayEnabled) {
+ if (val < 32)
+ c = '.';
+ else
+ c = val;
+ } else {
+ c = printable[val];
+ }
+ fprintf(out,"%c", c);
+ column++;
}
if (quotes) {
diff --git a/cmd/lib/secutil.h b/cmd/lib/secutil.h
index 71a7f59b8..2a2999188 100644
--- a/cmd/lib/secutil.h
+++ b/cmd/lib/secutil.h
@@ -139,6 +139,9 @@ SECU_GetClientAuthData(void *arg, PRFileDesc *fd,
extern PRBool SECU_GetWrapEnabled(void);
extern void SECU_EnableWrap(PRBool enable);
+extern PRBool SECU_GetUtf8DisplayEnabled(void);
+extern void SECU_EnableUtf8Display(PRBool enable);
+
/* revalidate the cert and print information about cert verification
* failure at time == now */
extern void
diff --git a/cmd/pp/pp.c b/cmd/pp/pp.c
index c97b3e79b..a739a915e 100644
--- a/cmd/pp/pp.c
+++ b/cmd/pp/pp.c
@@ -22,22 +22,27 @@ extern int fprintf(FILE *, char *, ...);
static void Usage(char *progName)
{
fprintf(stderr,
- "Usage: %s -t type [-a] [-i input] [-o output] [-w]\n",
+ "Usage: %s [-t type] [-a] [-i input] [-o output] [-w] [-u]\n",
progName);
- fprintf(stderr, "%-20s Specify the input type (must be one of %s,\n",
+ fprintf(stderr, "Pretty prints a file containing ASN.1 data in DER or ascii format.\n");
+ fprintf(stderr, "%-14s Specify input and display type: %s (sk),\n",
"-t type", SEC_CT_PRIVATE_KEY);
- fprintf(stderr, "%-20s %s, %s, %s,\n", "", SEC_CT_PUBLIC_KEY,
+ fprintf(stderr, "%-14s %s (pk), %s (c), %s (cr),\n", "", SEC_CT_PUBLIC_KEY,
SEC_CT_CERTIFICATE, SEC_CT_CERTIFICATE_REQUEST);
- fprintf(stderr, "%-20s %s, %s, %s or %s)\n", "", SEC_CT_CERTIFICATE_ID,
+ fprintf(stderr, "%-14s %s (ci), %s (p7), %s or %s (n).\n", "", SEC_CT_CERTIFICATE_ID,
SEC_CT_PKCS7, SEC_CT_CRL, SEC_CT_NAME);
- fprintf(stderr, "%-20s Input is in ascii encoded form (RFC1113)\n",
+ fprintf(stderr, "%-14s (Use either the long type name or the shortcut.)\n", "", SEC_CT_CERTIFICATE_ID,
+ SEC_CT_PKCS7, SEC_CT_CRL, SEC_CT_NAME);
+ fprintf(stderr, "%-14s Input is in ascii encoded form (RFC1113)\n",
"-a");
- fprintf(stderr, "%-20s Define an input file to use (default is stdin)\n",
+ fprintf(stderr, "%-14s Define an input file to use (default is stdin)\n",
"-i input");
- fprintf(stderr, "%-20s Define an output file to use (default is stdout)\n",
+ fprintf(stderr, "%-14s Define an output file to use (default is stdout)\n",
"-o output");
- fprintf(stderr, "%-20s Don't wrap long output lines\n",
+ fprintf(stderr, "%-14s Don't wrap long output lines\n",
"-w");
+ fprintf(stderr, "%-14s Use UTF-8 (default is to show non-ascii as .)\n",
+ "-u");
exit(-1);
}
@@ -59,7 +64,7 @@ int main(int argc, char **argv)
inFile = 0;
outFile = 0;
typeTag = 0;
- optstate = PL_CreateOptState(argc, argv, "at:i:o:w");
+ optstate = PL_CreateOptState(argc, argv, "at:i:o:uw");
while ( PL_GetNextOpt(optstate) == PL_OPT_OK ) {
switch (optstate->option) {
case '?':
@@ -92,6 +97,10 @@ int main(int argc, char **argv)
typeTag = strdup(optstate->value);
break;
+ case 'u':
+ SECU_EnableUtf8Display(PR_TRUE);
+ break;
+
case 'w':
wrap = PR_FALSE;
break;
@@ -125,27 +134,34 @@ int main(int argc, char **argv)
SECU_EnableWrap(wrap);
/* Pretty print it */
- if (PORT_Strcmp(typeTag, SEC_CT_CERTIFICATE) == 0) {
+ if (PORT_Strcmp(typeTag, SEC_CT_CERTIFICATE) == 0 ||
+ PORT_Strcmp(typeTag, "c") == 0) {
rv = SECU_PrintSignedData(outFile, &data, "Certificate", 0,
SECU_PrintCertificate);
- } else if (PORT_Strcmp(typeTag, SEC_CT_CERTIFICATE_ID) == 0) {
+ } else if (PORT_Strcmp(typeTag, SEC_CT_CERTIFICATE_ID) == 0 ||
+ PORT_Strcmp(typeTag, "ci") == 0) {
rv = SECU_PrintSignedContent(outFile, &data, 0, 0,
SECU_PrintDumpDerIssuerAndSerial);
- } else if (PORT_Strcmp(typeTag, SEC_CT_CERTIFICATE_REQUEST) == 0) {
+ } else if (PORT_Strcmp(typeTag, SEC_CT_CERTIFICATE_REQUEST) == 0 ||
+ PORT_Strcmp(typeTag, "cr") == 0) {
rv = SECU_PrintSignedData(outFile, &data, "Certificate Request", 0,
SECU_PrintCertificateRequest);
- } else if (PORT_Strcmp (typeTag, SEC_CT_CRL) == 0) {
+ } else if (PORT_Strcmp(typeTag, SEC_CT_CRL) == 0) {
rv = SECU_PrintSignedData (outFile, &data, "CRL", 0, SECU_PrintCrl);
#ifdef HAVE_EPV_TEMPLATE
- } else if (PORT_Strcmp(typeTag, SEC_CT_PRIVATE_KEY) == 0) {
+ } else if (PORT_Strcmp(typeTag, SEC_CT_PRIVATE_KEY) == 0 ||
+ PORT_Strcmp(typeTag, "sk") == 0) {
rv = SECU_PrintPrivateKey(outFile, &data, "Private Key", 0);
#endif
- } else if (PORT_Strcmp(typeTag, SEC_CT_PUBLIC_KEY) == 0) {
+ } else if (PORT_Strcmp(typeTag, SEC_CT_PUBLIC_KEY) == 0 ||
+ PORT_Strcmp (typeTag, "pk") == 0) {
rv = SECU_PrintSubjectPublicKeyInfo(outFile, &data, "Public Key", 0);
- } else if (PORT_Strcmp(typeTag, SEC_CT_PKCS7) == 0) {
+ } else if (PORT_Strcmp(typeTag, SEC_CT_PKCS7) == 0 ||
+ PORT_Strcmp (typeTag, "p7") == 0) {
rv = SECU_PrintPKCS7ContentInfo(outFile, &data,
"PKCS #7 Content Info", 0);
- } else if (PORT_Strcmp(typeTag, SEC_CT_NAME) == 0) {
+ } else if (PORT_Strcmp(typeTag, SEC_CT_NAME) == 0 ||
+ PORT_Strcmp (typeTag, "n") == 0) {
rv = SECU_PrintDERName(outFile, &data, "Name", 0);
} else {
fprintf(stderr, "%s: don't know how to print out '%s' files\n",
diff --git a/lib/certdb/alg1485.c b/lib/certdb/alg1485.c
index edb95af48..ea1621bcf 100644
--- a/lib/certdb/alg1485.c
+++ b/lib/certdb/alg1485.c
@@ -28,12 +28,12 @@ static const NameToKind name2kinds[] = {
* (See: http://www.iana.org/assignments/ldap-parameters)
*/
/* RFC 3280, 4630 MUST SUPPORT */
- { "CN", 64, SEC_OID_AVA_COMMON_NAME, SEC_ASN1_DS},
+ { "CN", 640, SEC_OID_AVA_COMMON_NAME, SEC_ASN1_DS},
{ "ST", 128, SEC_OID_AVA_STATE_OR_PROVINCE,
SEC_ASN1_DS},
- { "O", 64, SEC_OID_AVA_ORGANIZATION_NAME,
+ { "O", 128, SEC_OID_AVA_ORGANIZATION_NAME,
SEC_ASN1_DS},
- { "OU", 64, SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME,
+ { "OU", 128, SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME,
SEC_ASN1_DS},
{ "dnQualifier", 32767, SEC_OID_AVA_DN_QUALIFIER, SEC_ASN1_PRINTABLE_STRING},
{ "C", 2, SEC_OID_AVA_COUNTRY_NAME, SEC_ASN1_PRINTABLE_STRING},
@@ -377,7 +377,7 @@ ParseRFC1485AVA(PLArenaPool *arena, const char **pbp, const char *endptr)
char sep = 0;
char tagBuf[32];
- char valBuf[384];
+ char valBuf[1024];
PORT_Assert(arena);
if (SECSuccess != scanTag(pbp, endptr, tagBuf, sizeof tagBuf) ||
@@ -889,7 +889,7 @@ get_hex_string(SECItem *data)
static SECStatus
AppendAVA(stringBuf *bufp, CERTAVA *ava, CertStrictnessLevel strict)
{
-#define TMPBUF_LEN 384
+#define TMPBUF_LEN 2048
const NameToKind *pn2k = name2kinds;
SECItem *avaValue = NULL;
char *unknownTag = NULL;
diff --git a/lib/certdb/genname.c b/lib/certdb/genname.c
index de9e1f874..412a9d2c6 100644
--- a/lib/certdb/genname.c
+++ b/lib/certdb/genname.c
@@ -137,6 +137,39 @@ const SEC_ASN1Template CERT_GeneralNamesTemplate[] = {
};
+static struct {
+ CERTGeneralNameType type;
+ char *name;
+} typesArray[] = {
+ { certOtherName, "other" },
+ { certRFC822Name, "email" },
+ { certRFC822Name, "rfc822" },
+ { certDNSName, "dns" },
+ { certX400Address, "x400" },
+ { certX400Address, "x400addr" },
+ { certDirectoryName, "directory" },
+ { certDirectoryName, "dn" },
+ { certEDIPartyName, "edi" },
+ { certEDIPartyName, "ediparty" },
+ { certURI, "uri" },
+ { certIPAddress, "ip" },
+ { certIPAddress, "ipaddr" },
+ { certRegisterID, "registerid" }
+};
+
+CERTGeneralNameType
+CERT_GetGeneralNameTypeFromString(const char *string)
+{
+ int types_count = sizeof(typesArray)/sizeof(typesArray[0]);
+ int i;
+
+ for (i=0; i < types_count; i++) {
+ if (PORT_Strcasecmp(string, typesArray[i].name) == 0) {
+ return typesArray[i].type;
+ }
+ }
+ return 0;
+}
CERTGeneralName *
CERT_NewGeneralName(PLArenaPool *arena, CERTGeneralNameType type)
diff --git a/lib/certdb/genname.h b/lib/certdb/genname.h
index 091c82c12..1d94376d0 100644
--- a/lib/certdb/genname.h
+++ b/lib/certdb/genname.h
@@ -26,6 +26,9 @@ cert_DecodeGeneralNames(PLArenaPool *arena, SECItem **encodedGenName);
extern SECStatus
cert_DestroyGeneralNames(CERTGeneralName *name);
+extern CERTGeneralNameType
+CERT_GetGeneralNameTypeFromString(const char *string);
+
extern SECStatus
cert_EncodeNameConstraints(CERTNameConstraints *constraints, PLArenaPool *arena,
SECItem *dest);
diff --git a/lib/nss/nss.def b/lib/nss/nss.def
index cd1308f09..6f6b67081 100644
--- a/lib/nss/nss.def
+++ b/lib/nss/nss.def
@@ -1055,6 +1055,8 @@ SECMOD_InternaltoPubMechFlags;
;+};
;+NSS_3.16.2 { # NSS 3.16.2 release
;+ global:
+CERT_AddExtensionByOID;
+CERT_GetGeneralNameTypeFromString;
PK11_PubEncrypt;
PK11_PrivDecrypt;
;+ local:
diff --git a/lib/pk11wrap/pk11load.c b/lib/pk11wrap/pk11load.c
index e1e764b16..6700180ad 100644
--- a/lib/pk11wrap/pk11load.c
+++ b/lib/pk11wrap/pk11load.c
@@ -55,6 +55,11 @@ static const CK_C_INITIALIZE_ARGS secmodLockFunctions = {
CKF_OS_LOCKING_OK
,NULL
};
+static const CK_C_INITIALIZE_ARGS secmodNoLockArgs = {
+ NULL, NULL, NULL, NULL,
+ CKF_LIBRARY_CANT_CREATE_OS_THREADS
+ ,NULL
+};
static PRBool loadSingleThreadedModules = PR_TRUE;
static PRBool enforceAlreadyInitializedError = PR_TRUE;
@@ -209,12 +214,18 @@ secmod_ModuleInit(SECMODModule *mod, SECMODModule **reload,
return SECFailure;
}
- if (mod->isThreadSafe == PR_FALSE) {
- pInitArgs = NULL;
- } else if (mod->libraryParams == NULL) {
- pInitArgs = (void *) &secmodLockFunctions;
+ if (mod->libraryParams == NULL) {
+ if (mod->isThreadSafe) {
+ pInitArgs = (void *) &secmodLockFunctions;
+ } else {
+ pInitArgs = NULL;
+ }
} else {
- moduleArgs = secmodLockFunctions;
+ if (mod->isThreadSafe) {
+ moduleArgs = secmodLockFunctions;
+ } else {
+ moduleArgs = secmodNoLockArgs;
+ }
moduleArgs.LibraryParameters = (void *) mod->libraryParams;
pInitArgs = &moduleArgs;
}
@@ -251,18 +262,30 @@ secmod_ModuleInit(SECMODModule *mod, SECMODModule **reload,
}
}
if (crv != CKR_OK) {
- if (pInitArgs == NULL ||
+ if (!mod->isThreadSafe ||
crv == CKR_NETSCAPE_CERTDB_FAILED ||
crv == CKR_NETSCAPE_KEYDB_FAILED) {
PORT_SetError(PK11_MapError(crv));
return SECFailure;
}
+ /* If we had attempted to init a single threaded module "with"
+ * parameters and it failed, should we retry "without" parameters?
+ * (currently we don't retry in this scenario) */
+
if (!loadSingleThreadedModules) {
PORT_SetError(SEC_ERROR_INCOMPATIBLE_PKCS11);
return SECFailure;
}
+ /* If we arrive here, the module failed a ThreadSafe init. */
mod->isThreadSafe = PR_FALSE;
- crv = PK11_GETTAB(mod)->C_Initialize(NULL);
+ if (!mod->libraryParams) {
+ pInitArgs = NULL;
+ } else {
+ moduleArgs = secmodNoLockArgs;
+ moduleArgs.LibraryParameters = (void *) mod->libraryParams;
+ pInitArgs = &moduleArgs;
+ }
+ crv = PK11_GETTAB(mod)->C_Initialize(pInitArgs);
if ((CKR_CRYPTOKI_ALREADY_INITIALIZED == crv) &&
(!enforceAlreadyInitializedError)) {
*alreadyLoaded = PR_TRUE;
diff --git a/lib/util/oidstring.c b/lib/util/oidstring.c
index 8bb963e08..74b2dce4c 100644
--- a/lib/util/oidstring.c
+++ b/lib/util/oidstring.c
@@ -6,6 +6,7 @@
#include "secitem.h"
#include "secport.h"
#include "secerr.h"
+#include "secoid.h"
/* if to->data is not NULL, and to->len is large enough to hold the result,
* then the resultant OID will be copyed into to->data, and to->len will be
@@ -112,3 +113,33 @@ bad_data:
}
return rv;
}
+
+SECStatus
+SEC_NumberOrNameStringToOIDTag(PLArenaPool *arena, SECOidTag *to, const char *from)
+{
+ SECStatus rv;
+ SECOidTag tag;
+ SECOidData *coid;
+
+ /* try dotted form first */
+ rv = SEC_StringToOID(arena, to, from, strlen(from));
+ if (rv == SECSuccess) {
+ return rv;
+ }
+
+ /* Check to see if it matches a name in our oid table.
+ * SECOID_FindOIDByTag returns NULL if tag is out of bounds.
+ */
+ tag = SEC_OID_UNKNOWN;
+ coid = SECOID_FindOIDByTag_Util(tag);
+ for ( ; coid; coid = SECOID_FindOIDByTag(++tag)) {
+ if (PORT_Strcasecmp(from, coid->desc) == 0) {
+ break;
+ }
+ }
+ if (coid == NULL) {
+ /* none found */
+ return SECFailure;
+ }
+ return SECITEM_CopyItem(arena, to, &coid->oid);
+}
diff --git a/tests/cert/cert.sh b/tests/cert/cert.sh
index 313c663f6..1a23c19c4 100755
--- a/tests/cert/cert.sh
+++ b/tests/cert/cert.sh
@@ -1176,6 +1176,201 @@ cert_extensions()
done < ${QADIR}/cert/certext.txt
}
+cert_make_with_param()
+{
+ DIRPASS="$1"
+ CERTNAME="$2"
+ MAKE="$3"
+ SUBJ="$4"
+ EXTRA="$5"
+ EXPECT="$6"
+ TESTNAME="$7"
+
+ echo certutil ${DIRPASS} -s "${SUBJ}" ${MAKE} ${CERTNAME} ${EXTRA}
+ ${BINDIR}/certutil ${DIRPASS} -s "${SUBJ}" ${MAKE} ${CERTNAME} ${EXTRA}
+
+ RET=$?
+ if [ "${RET}" -ne "${EXPECT}" ]; then
+ # if we expected failure to create, then delete unexpected certificate
+ if [ "${EXPECT}" -ne 0 ]; then
+ ${BINDIR}/certutil ${DIRPASS} -D ${CERTNAME}
+ fi
+
+ CERTFAILED=1
+ html_failed "${TESTNAME} (${COUNT}) - ${EXTRA}"
+ cert_log "ERROR: ${TESTNAME} - ${EXTRA} failed"
+ return 1
+ fi
+
+ html_passed "${TESTNAME} (${COUNT})"
+ return 0
+}
+
+cert_list_and_count_dns()
+{
+ DIRPASS="$1"
+ CERTNAME="$2"
+ EXPECT="$3"
+ EXPECTCOUNT="$4"
+ TESTNAME="$5"
+
+ echo certutil ${DIRPASS} -L ${CERTNAME}
+ ${BINDIR}/certutil ${DIRPASS} -L ${CERTNAME}
+
+ RET=$?
+ if [ "${RET}" -ne "${EXPECT}" ]; then
+ CERTFAILED=1
+ html_failed "${TESTNAME} (${COUNT}) - list and count"
+ cert_log "ERROR: ${TESTNAME} - list and count failed"
+ return 1
+ fi
+
+ LISTCOUNT=`${BINDIR}/certutil ${DIRPASS} -L ${CERTNAME} | grep -wc DNS`
+ if [ "${LISTCOUNT}" -ne "${EXPECTCOUNT}" ]; then
+ CERTFAILED=1
+ html_failed "${TESTNAME} (${COUNT}) - list and count"
+ cert_log "ERROR: ${TESTNAME} - list and count failed"
+ return 1
+ fi
+
+ html_passed "${TESTNAME} (${COUNT})"
+ return 0
+}
+
+cert_dump_ext_to_file()
+{
+ DIRPASS="$1"
+ CERTNAME="$2"
+ OID="$3"
+ OUTFILE="$4"
+ EXPECT="$5"
+ TESTNAME="$6"
+
+ echo certutil ${DIRPASS} -L ${CERTNAME} --dump-ext-val ${OID}
+ echo "writing output to ${OUTFILE}"
+ ${BINDIR}/certutil ${DIRPASS} -L ${CERTNAME} --dump-ext-val ${OID} > ${OUTFILE}
+
+ RET=$?
+ if [ "${RET}" -ne "${EXPECT}" ]; then
+ CERTFAILED=1
+ html_failed "${TESTNAME} (${COUNT}) - dump to file"
+ cert_log "ERROR: ${TESTNAME} - dump to file failed"
+ return 1
+ fi
+
+ html_passed "${TESTNAME} (${COUNT})"
+ return 0
+}
+
+cert_delete()
+{
+ DIRPASS="$1"
+ CERTNAME="$2"
+ EXPECT="$3"
+ TESTNAME="$4"
+
+ echo certutil ${DIRPASS} -D ${CERTNAME}
+ ${BINDIR}/certutil ${DIRPASS} -D ${CERTNAME}
+
+ RET=$?
+ if [ "${RET}" -ne "${EXPECT}" ]; then
+ CERTFAILED=1
+ html_failed "${TESTNAME} (${COUNT}) - delete cert"
+ cert_log "ERROR: ${TESTNAME} - delete cert failed"
+ return 1
+ fi
+
+ html_passed "${TESTNAME} (${COUNT})"
+ return 0
+}
+
+cert_inc_count()
+{
+ COUNT=`expr ${COUNT} + 1`
+}
+
+############################## cert_crl_ssl ############################
+# test adding subject-alt-name, dumping, and adding generic extension
+########################################################################
+cert_san_and_generic_extensions()
+{
+ EXTDUMP=${CERT_EXTENSIONS_DIR}/sanext.der
+
+ DIR="-d ${CERT_EXTENSIONS_DIR} -f ${R_PWFILE}"
+ CERTNAME="-n WithSAN"
+ MAKE="-S -t ,, -x -z ${R_NOISE_FILE}"
+ SUBJ="CN=example.com"
+
+ TESTNAME="san-and-generic-extensions"
+
+ cert_inc_count
+ cert_make_with_param "${DIR}" "${CERTNAME}" "${MAKE}" "${SUBJ}" \
+ "--extSAN example.com" 255 \
+ "create cert with invalid SAN parameter"
+
+ cert_inc_count
+ cert_make_with_param "${DIR}" "${CERTNAME}" "${MAKE}" "${SUBJ}" \
+ "--extSAN example.com,dns:www.example.com" 255 \
+ "create cert with invalid SAN parameter"
+
+ TN="create cert with valid SAN parameter"
+
+ cert_inc_count
+ cert_make_with_param "${DIR}" "${CERTNAME}" "${MAKE}" "${SUBJ}" \
+ "--extSAN dns:example.com,dns:www.example.com" 0 \
+ "${TN}"
+
+ cert_inc_count
+ cert_list_and_count_dns "${DIR}" "${CERTNAME}" 0 2 \
+ "${TN}"
+
+ cert_inc_count
+ cert_dump_ext_to_file "${DIR}" "${CERTNAME}" "2.5.29.17" "${EXTDUMP}" 0 \
+ "dump extension 2.5.29.17 to file ${EXTDUMP}"
+
+ cert_inc_count
+ cert_delete "${DIR}" "${CERTNAME}" 0 \
+ "${TN}"
+
+ cert_inc_count
+ cert_list_and_count_dns "${DIR}" "${CERTNAME}" 255 0 \
+ "expect failure to list cert, because we deleted it"
+
+ cert_inc_count
+ cert_make_with_param "${DIR}" "${CERTNAME}" "${MAKE}" "${SUBJ}" \
+ "--extGeneric ${EXTDUMP}" 255 \
+ "create cert with invalid generic ext parameter"
+
+ cert_inc_count
+ cert_make_with_param "${DIR}" "${CERTNAME}" "${MAKE}" "${SUBJ}" \
+ "--extGeneric not-critical:${EXTDUMP}" 255 \
+ "create cert with invalid generic ext parameter"
+
+ cert_inc_count
+ cert_make_with_param "${DIR}" "${CERTNAME}" "${MAKE}" "${SUBJ}" \
+ "--extGeneric not-critical:${EXTDUMP},2.5.29.17:critical:${EXTDUMP}" 255 \
+ "create cert with invalid generic ext parameter"
+
+ TN="create cert with valid generic ext parameter"
+
+ cert_inc_count
+ cert_make_with_param "${DIR}" "${CERTNAME}" "${MAKE}" "${SUBJ}" \
+ "--extGeneric 2.5.29.17:not-critical:${EXTDUMP}" 0 \
+ "${TN}"
+
+ cert_inc_count
+ cert_list_and_count_dns "${DIR}" "${CERTNAME}" 0 2 \
+ "${TN}"
+
+ cert_inc_count
+ cert_delete "${DIR}" "${CERTNAME}" 0 \
+ "${TN}"
+
+ cert_inc_count
+ cert_list_and_count_dns "${DIR}" "${CERTNAME}" 255 0 \
+ "expect failure to list cert, because we deleted it"
+}
+
############################## cert_crl_ssl ############################
# local shell function to generate certs and crls for SSL tests
########################################################################
@@ -1513,6 +1708,7 @@ if [ -z "$NSS_TEST_DISABLE_FIPS" ]; then
fi
cert_eccurves
cert_extensions
+cert_san_and_generic_extensions
cert_test_password
cert_test_distrust
cert_test_ocspresp