security/nss/cmd/certutil/certutil.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* This Source Code Form is subject to the terms of the Mozilla Public
     2  * License, v. 2.0. If a copy of the MPL was not distributed with this
     3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     5 /*
     6 ** certutil.c
     7 **
     8 ** utility for managing certificates and the cert database
     9 **
    10 */
    11 #include <stdio.h>
    12 #include <string.h>
    13 #include <stdlib.h>
    15 #if defined(WIN32)
    16 #include "fcntl.h"
    17 #include "io.h"
    18 #endif
    20 #include "secutil.h"
    22 #if defined(XP_UNIX)
    23 #include <unistd.h>
    24 #endif
    26 #include "nspr.h"
    27 #include "prtypes.h"
    28 #include "prtime.h"
    29 #include "prlong.h"
    31 #include "pk11func.h"
    32 #include "secasn1.h"
    33 #include "cert.h"
    34 #include "cryptohi.h"
    35 #include "secoid.h"
    36 #include "certdb.h"
    37 #include "nss.h"
    38 #include "certutil.h"
    40 #define MIN_KEY_BITS		512
    41 /* MAX_KEY_BITS should agree with MAX_RSA_MODULUS in freebl */
    42 #define MAX_KEY_BITS		8192
    43 #define DEFAULT_KEY_BITS	1024
    45 #define GEN_BREAK(e) rv=e; break;
    47 char *progName;
    49 static CERTCertificateRequest *
    50 GetCertRequest(const SECItem *reqDER)
    51 {
    52     CERTCertificateRequest *certReq = NULL;
    53     CERTSignedData signedData;
    54     PLArenaPool *arena = NULL;
    55     SECStatus rv;
    57     do {
    58 	arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    59 	if (arena == NULL) {
    60 	    GEN_BREAK (SECFailure);
    61 	}
    63         certReq = (CERTCertificateRequest*) PORT_ArenaZAlloc
    64 		  (arena, sizeof(CERTCertificateRequest));
    65         if (!certReq) { 
    66 	    GEN_BREAK(SECFailure);
    67 	}
    68 	certReq->arena = arena;
    70 	/* Since cert request is a signed data, must decode to get the inner
    71 	   data
    72 	 */
    73 	PORT_Memset(&signedData, 0, sizeof(signedData));
    74 	rv = SEC_ASN1DecodeItem(arena, &signedData, 
    75 		SEC_ASN1_GET(CERT_SignedDataTemplate), reqDER);
    76 	if (rv) {
    77 	    break;
    78 	}
    79 	rv = SEC_ASN1DecodeItem(arena, certReq, 
    80 		SEC_ASN1_GET(CERT_CertificateRequestTemplate), &signedData.data);
    81 	if (rv) {
    82 	    break;
    83 	}
    84    	rv = CERT_VerifySignedDataWithPublicKeyInfo(&signedData, 
    85 		&certReq->subjectPublicKeyInfo, NULL /* wincx */);
    86    } while (0);
    88    if (rv) {
    89    	SECU_PrintError(progName, "bad certificate request\n");
    90    	if (arena) {
    91    	    PORT_FreeArena(arena, PR_FALSE);
    92    	}
    93    	certReq = NULL;
    94    }
    96    return certReq;
    97 }
    99 static SECStatus
   100 AddCert(PK11SlotInfo *slot, CERTCertDBHandle *handle, char *name, char *trusts, 
   101         const SECItem *certDER, PRBool emailcert, void *pwdata)
   102 {
   103     CERTCertTrust *trust = NULL;
   104     CERTCertificate *cert = NULL;
   105     SECStatus rv;
   107     do {
   108 	/* Read in an ASCII cert and return a CERTCertificate */
   109 	cert = CERT_DecodeCertFromPackage((char *)certDER->data, certDER->len);
   110 	if (!cert) {
   111 	    SECU_PrintError(progName, "could not decode certificate");
   112 	    GEN_BREAK(SECFailure);
   113 	}
   115 	/* Create a cert trust */
   116 	trust = (CERTCertTrust *)PORT_ZAlloc(sizeof(CERTCertTrust));
   117 	if (!trust) {
   118 	    SECU_PrintError(progName, "unable to allocate cert trust");
   119 	    GEN_BREAK(SECFailure);
   120 	}
   122 	rv = CERT_DecodeTrustString(trust, trusts);
   123 	if (rv) {
   124 	    SECU_PrintError(progName, "unable to decode trust string");
   125 	    GEN_BREAK(SECFailure);
   126 	}
   128 	rv =  PK11_ImportCert(slot, cert, CK_INVALID_HANDLE, name, PR_FALSE);
   129 	if (rv != SECSuccess) {
   130 	    /* sigh, PK11_Import Cert and CERT_ChangeCertTrust should have 
   131 	     * been coded to take a password arg. */
   132 	    if (PORT_GetError() == SEC_ERROR_TOKEN_NOT_LOGGED_IN) {
   133 		rv = PK11_Authenticate(slot, PR_TRUE, pwdata);
   134 		if (rv != SECSuccess) {
   135                     SECU_PrintError(progName, 
   136 				"could not authenticate to token %s.",
   137 				PK11_GetTokenName(slot));
   138 		    GEN_BREAK(SECFailure);
   139 		}
   140 		rv = PK11_ImportCert(slot, cert, CK_INVALID_HANDLE, 
   141 				     name, PR_FALSE);
   142 	    }
   143 	    if (rv != SECSuccess) {
   144 		SECU_PrintError(progName, 
   145 			"could not add certificate to token or database");
   146 		GEN_BREAK(SECFailure);
   147 	    }
   148 	}
   150 	rv = CERT_ChangeCertTrust(handle, cert, trust);
   151 	if (rv != SECSuccess) {
   152 	    if (PORT_GetError() == SEC_ERROR_TOKEN_NOT_LOGGED_IN) {
   153 		rv = PK11_Authenticate(slot, PR_TRUE, pwdata);
   154 		if (rv != SECSuccess) {
   155                     SECU_PrintError(progName, 
   156 				"could not authenticate to token %s.",
   157 				PK11_GetTokenName(slot));
   158 		    GEN_BREAK(SECFailure);
   159 		}
   160 		rv = CERT_ChangeCertTrust(handle, cert, trust);
   161 	    }
   162 	    if (rv != SECSuccess) {
   163 		SECU_PrintError(progName, 
   164 			"could not change trust on certificate");
   165 		GEN_BREAK(SECFailure);
   166 	    }
   167 	}
   169 	if ( emailcert ) {
   170 	    CERT_SaveSMimeProfile(cert, NULL, pwdata);
   171 	}
   173     } while (0);
   175     CERT_DestroyCertificate (cert);
   176     PORT_Free(trust);
   178     return rv;
   179 }
   181 static SECStatus
   182 CertReq(SECKEYPrivateKey *privk, SECKEYPublicKey *pubk, KeyType keyType,
   183         SECOidTag hashAlgTag, CERTName *subject, char *phone, int ascii, 
   184 	const char *emailAddrs, const char *dnsNames,
   185         certutilExtnList extnList, const char *extGeneric,
   186         /*out*/ SECItem *result)
   187 {
   188     CERTSubjectPublicKeyInfo *spki;
   189     CERTCertificateRequest *cr;
   190     SECItem *encoding;
   191     SECOidTag signAlgTag;
   192     SECStatus rv;
   193     PLArenaPool *arena;
   194     void *extHandle;
   195     SECItem signedReq = { siBuffer, NULL, 0 };
   197     /* Create info about public key */
   198     spki = SECKEY_CreateSubjectPublicKeyInfo(pubk);
   199     if (!spki) {
   200 	SECU_PrintError(progName, "unable to create subject public key");
   201 	return SECFailure;
   202     }
   204     /* Generate certificate request */
   205     cr = CERT_CreateCertificateRequest(subject, spki, NULL);
   206     SECKEY_DestroySubjectPublicKeyInfo(spki);
   207     if (!cr) {
   208 	SECU_PrintError(progName, "unable to make certificate request");
   209 	return SECFailure;
   210     }
   212     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
   213     if ( !arena ) {
   214 	SECU_PrintError(progName, "out of memory");
   215 	return SECFailure;
   216     }
   218     extHandle = CERT_StartCertificateRequestAttributes(cr);
   219     if (extHandle == NULL) {
   220         PORT_FreeArena (arena, PR_FALSE);
   221 	return SECFailure;
   222     }
   223     if (AddExtensions(extHandle, emailAddrs, dnsNames, extnList, extGeneric)
   224                   != SECSuccess) {
   225         PORT_FreeArena (arena, PR_FALSE);
   226         return SECFailure;
   227     }
   228     CERT_FinishExtensions(extHandle);
   229     CERT_FinishCertificateRequestAttributes(cr);
   231     /* Der encode the request */
   232     encoding = SEC_ASN1EncodeItem(arena, NULL, cr,
   233                                   SEC_ASN1_GET(CERT_CertificateRequestTemplate));
   234     CERT_DestroyCertificateRequest(cr);
   235     if (encoding == NULL) {
   236 	PORT_FreeArena (arena, PR_FALSE);
   237 	SECU_PrintError(progName, "der encoding of request failed");
   238 	return SECFailure;
   239     }
   241     /* Sign the request */
   242     signAlgTag = SEC_GetSignatureAlgorithmOidTag(keyType, hashAlgTag);
   243     if (signAlgTag == SEC_OID_UNKNOWN) {
   244 	PORT_FreeArena (arena, PR_FALSE);
   245 	SECU_PrintError(progName, "unknown Key or Hash type");
   246 	return SECFailure;
   247     }
   249     rv = SEC_DerSignData(arena, &signedReq, encoding->data, encoding->len,
   250 			  privk, signAlgTag);
   251     if (rv) {
   252 	PORT_FreeArena (arena, PR_FALSE);
   253 	SECU_PrintError(progName, "signing of data failed");
   254 	return SECFailure;
   255     }
   257     /* Encode request in specified format */
   258     if (ascii) {
   259 	char *obuf;
   260 	char *header, *name, *email, *org, *state, *country;
   262 	obuf = BTOA_ConvertItemToAscii(&signedReq);
   263 	if (!obuf) {
   264 	    goto oom;
   265 	}
   267 	name = CERT_GetCommonName(subject);
   268 	if (!name) {
   269 	    name = PORT_Strdup("(not specified)");
   270 	}
   272 	if (!phone)
   273 	    phone = strdup("(not specified)");
   275 	email = CERT_GetCertEmailAddress(subject);
   276 	if (!email)
   277 	    email = PORT_Strdup("(not specified)");
   279 	org = CERT_GetOrgName(subject);
   280 	if (!org)
   281 	    org = PORT_Strdup("(not specified)");
   283 	state = CERT_GetStateName(subject);
   284 	if (!state)
   285 	    state = PORT_Strdup("(not specified)");
   287 	country = CERT_GetCountryName(subject);
   288 	if (!country)
   289 	    country = PORT_Strdup("(not specified)");
   291 	header = PR_smprintf(
   292 	    "\nCertificate request generated by Netscape certutil\n"
   293 	    "Phone: %s\n\n"
   294 	    "Common Name: %s\n"
   295 	    "Email: %s\n"
   296 	    "Organization: %s\n"
   297 	    "State: %s\n"
   298 	    "Country: %s\n\n"
   299 	    "%s\n",
   300 	    phone, name, email, org, state, country, NS_CERTREQ_HEADER);
   302 	PORT_Free(name);
   303 	PORT_Free(email);
   304 	PORT_Free(org);
   305 	PORT_Free(state);
   306 	PORT_Free(country);
   308 	if (header) {
   309 	    char * trailer = PR_smprintf("\n%s\n", NS_CERTREQ_TRAILER);
   310 	    if (trailer) {
   311 		PRUint32 headerLen = PL_strlen(header);
   312 		PRUint32 obufLen = PL_strlen(obuf);
   313 		PRUint32 trailerLen = PL_strlen(trailer);
   314 		SECITEM_AllocItem(NULL, result,
   315 				  headerLen + obufLen + trailerLen);
   316 		if (result->data) {
   317 		    PORT_Memcpy(result->data, header, headerLen);
   318 		    PORT_Memcpy(result->data + headerLen, obuf, obufLen);
   319 		    PORT_Memcpy(result->data + headerLen + obufLen,
   320 				trailer, trailerLen);
   321 		}
   322 		PR_smprintf_free(trailer);
   323 	    }
   324 	    PR_smprintf_free(header);
   325 	}
   326     } else {
   327 	(void) SECITEM_CopyItem(NULL, result, &signedReq);
   328     }
   330     if (!result->data) {
   331 oom:    SECU_PrintError(progName, "out of memory");
   332 	PORT_SetError(SEC_ERROR_NO_MEMORY);
   333 	rv = SECFailure;
   334     }
   336     PORT_FreeArena (arena, PR_FALSE);
   337     return rv;
   338 }
   340 static SECStatus 
   341 ChangeTrustAttributes(CERTCertDBHandle *handle, PK11SlotInfo *slot,
   342 			char *name, char *trusts, void *pwdata)
   343 {
   344     SECStatus rv;
   345     CERTCertificate *cert;
   346     CERTCertTrust *trust;
   348     cert = CERT_FindCertByNicknameOrEmailAddr(handle, name);
   349     if (!cert) {
   350 	SECU_PrintError(progName, "could not find certificate named \"%s\"",
   351 			name);
   352 	return SECFailure;
   353     }
   355     trust = (CERTCertTrust *)PORT_ZAlloc(sizeof(CERTCertTrust));
   356     if (!trust) {
   357 	SECU_PrintError(progName, "unable to allocate cert trust");
   358 	return SECFailure;
   359     }
   361     /* This function only decodes these characters: pPwcTCu, */
   362     rv = CERT_DecodeTrustString(trust, trusts);
   363     if (rv) {
   364 	SECU_PrintError(progName, "unable to decode trust string");
   365 	return SECFailure;
   366     }
   368     /* CERT_ChangeCertTrust API does not have a way to pass in
   369      * a context, so NSS can't prompt for the password if it needs to.
   370      * check to see if the failure was token not logged in and 
   371      * log in if need be. */
   372     rv = CERT_ChangeCertTrust(handle, cert, trust);
   373     if (rv != SECSuccess) {
   374 	if (PORT_GetError() == SEC_ERROR_TOKEN_NOT_LOGGED_IN) {
   375 	    rv = PK11_Authenticate(slot, PR_TRUE, pwdata);
   376 	    if (rv != SECSuccess) {
   377 		SECU_PrintError(progName, "could not authenticate to token %s.",
   378                                 PK11_GetTokenName(slot));
   379 		return SECFailure;
   380 	    }
   381 	    rv = CERT_ChangeCertTrust(handle, cert, trust);
   382 	}
   383 	if (rv != SECSuccess) {
   384 	    SECU_PrintError(progName, "unable to modify trust attributes");
   385 	    return SECFailure;
   386 	}
   387     }
   388     CERT_DestroyCertificate(cert);
   390     return SECSuccess;
   391 }
   393 static SECStatus
   394 DumpChain(CERTCertDBHandle *handle, char *name, PRBool ascii)
   395 {
   396     CERTCertificate *the_cert;
   397     CERTCertificateList *chain;
   398     int i, j;
   399     the_cert = SECU_FindCertByNicknameOrFilename(handle, name,
   400                                                  ascii, NULL);
   401     if (!the_cert) {
   402 	SECU_PrintError(progName, "Could not find: %s\n", name);
   403 	return SECFailure;
   404     }
   405     chain = CERT_CertChainFromCert(the_cert, 0, PR_TRUE);
   406     CERT_DestroyCertificate(the_cert);
   407     if (!chain) {
   408 	SECU_PrintError(progName, "Could not obtain chain for: %s\n", name);
   409 	return SECFailure;
   410     }
   411     for (i=chain->len-1; i>=0; i--) {
   412 	CERTCertificate *c;
   413 	c = CERT_FindCertByDERCert(handle, &chain->certs[i]);
   414 	for (j=i; j<chain->len-1; j++) printf("  ");
   415 	printf("\"%s\" [%s]\n\n", c->nickname, c->subjectName);
   416 	CERT_DestroyCertificate(c);
   417     }
   418     CERT_DestroyCertificateList(chain);
   419     return SECSuccess;
   420 }
   422 static SECStatus
   423 outputCertOrExtension(CERTCertificate *the_cert, PRBool raw, PRBool ascii,
   424                       SECItem *extensionOID, PRFileDesc *outfile)
   425 {
   426     SECItem data;
   427     PRInt32 numBytes;
   428     SECStatus rv = SECFailure;
   429     if (extensionOID) {
   430 	int i;
   431 	PRBool found = PR_FALSE;
   432 	for (i=0; the_cert->extensions[i] != NULL; i++) {
   433 	    CERTCertExtension *extension = the_cert->extensions[i];
   434 	    if (SECITEM_CompareItem(&extension->id, extensionOID) == SECEqual) {
   435 		found = PR_TRUE;
   436 		numBytes = PR_Write(outfile, extension->value.data,
   437 				    extension->value.len);
   438 		rv = SECSuccess;
   439 		if (numBytes != (PRInt32) extension->value.len) {
   440 		    SECU_PrintSystemError(progName, "error writing extension");
   441 		    rv = SECFailure;
   442 		}
   443 		rv = SECSuccess;
   444 		break;
   445 	    }
   446 	}
   447 	if (!found) {
   448 	    SECU_PrintSystemError(progName, "extension not found");
   449 	    rv = SECFailure;
   450 	}
   451     } else {
   452 	data.data = the_cert->derCert.data;
   453 	data.len = the_cert->derCert.len;
   454 	if (ascii) {
   455 	    PR_fprintf(outfile, "%s\n%s\n%s\n", NS_CERT_HEADER, 
   456 		    BTOA_DataToAscii(data.data, data.len), NS_CERT_TRAILER);
   457 	    rv = SECSuccess;
   458 	} else if (raw) {
   459 	    numBytes = PR_Write(outfile, data.data, data.len);
   460 	    rv = SECSuccess;
   461 	    if (numBytes != (PRInt32) data.len) {
   462 		SECU_PrintSystemError(progName, "error writing raw cert");
   463 		rv = SECFailure;
   464 	    }
   465 	} else {
   466 	    rv = SEC_PrintCertificateAndTrust(the_cert, "Certificate", NULL);
   467 	    if (rv != SECSuccess) {
   468 		SECU_PrintError(progName, "problem printing certificate");
   469 	    }
   470 	}
   471     }
   472     return rv;
   473 }
   475 static SECStatus
   476 listCerts(CERTCertDBHandle *handle, char *name, char *email,
   477 	  PK11SlotInfo *slot, PRBool raw, PRBool ascii,
   478 	  SECItem *extensionOID,
   479 	  PRFileDesc *outfile, void *pwarg)
   480 {
   481     SECStatus rv = SECFailure;
   482     CERTCertList *certs;
   483     CERTCertListNode *node;
   485     /* List certs on a non-internal slot. */
   486     if (!PK11_IsFriendly(slot) && PK11_NeedLogin(slot)) {
   487         SECStatus newrv = PK11_Authenticate(slot, PR_TRUE, pwarg);
   488         if (newrv != SECSuccess) {
   489             SECU_PrintError(progName, "could not authenticate to token %s.",
   490                             PK11_GetTokenName(slot));
   491             return SECFailure;
   492         }
   493     }
   494     if (name) {
   495 	CERTCertificate *the_cert =
   496             SECU_FindCertByNicknameOrFilename(handle, name, ascii, NULL);
   497         if (!the_cert) {
   498             SECU_PrintError(progName, "Could not find cert: %s\n", name);
   499             return SECFailure;
   500         }
   501 	/* Here, we have one cert with the desired nickname or email 
   502 	 * address.  Now, we will attempt to get a list of ALL certs 
   503 	 * with the same subject name as the cert we have.  That list 
   504 	 * should contain, at a minimum, the one cert we have already found.
   505 	 * If the list of certs is empty (NULL), the libraries have failed.
   506 	 */
   507 	certs = CERT_CreateSubjectCertList(NULL, handle, &the_cert->derSubject,
   508 		PR_Now(), PR_FALSE);
   509 	CERT_DestroyCertificate(the_cert);
   510 	if (!certs) {
   511 	    PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
   512 	    SECU_PrintError(progName, "problem printing certificates");
   513 	    return SECFailure;
   514 	}
   515 	for (node = CERT_LIST_HEAD(certs); !CERT_LIST_END(node,certs);
   516 						node = CERT_LIST_NEXT(node)) {
   517 	    rv = outputCertOrExtension(node->cert, raw, ascii, extensionOID,
   518                                        outfile);
   519 	    if (rv != SECSuccess) {
   520 		break;
   521 	    }
   522 	}
   523     } else if (email) {
   524 	certs = PK11_FindCertsFromEmailAddress(email, NULL);
   525 	if (!certs) {
   526 	    SECU_PrintError(progName, 
   527 			"Could not find certificates for email address: %s\n", 
   528 			email);
   529 	    return SECFailure;
   530 	}
   531 	for (node = CERT_LIST_HEAD(certs); !CERT_LIST_END(node,certs);
   532 						node = CERT_LIST_NEXT(node)) {
   533 	    rv = outputCertOrExtension(node->cert, raw, ascii, extensionOID,
   534                                        outfile);
   535 	    if (rv != SECSuccess) {
   536 		break;
   537 	    }
   538 	}
   539     } else {
   540 	certs = PK11_ListCertsInSlot(slot);
   541 	if (certs) {
   542 	    for (node = CERT_LIST_HEAD(certs); !CERT_LIST_END(node,certs);
   543 						node = CERT_LIST_NEXT(node)) {
   544 		SECU_PrintCertNickname(node,stdout);
   545 	    }
   546 	    rv = SECSuccess;
   547 	}
   548     }
   549     if (certs) {
   550         CERT_DestroyCertList(certs);
   551     }
   552     if (rv) {
   553 	SECU_PrintError(progName, "problem printing certificate nicknames");
   554 	return SECFailure;
   555     }
   557     return SECSuccess;	/* not rv ?? */
   558 }
   560 static SECStatus
   561 ListCerts(CERTCertDBHandle *handle, char *nickname, char *email, 
   562           PK11SlotInfo *slot, PRBool raw, PRBool ascii,
   563 	  SECItem *extensionOID,
   564 	  PRFileDesc *outfile, secuPWData *pwdata)
   565 {
   566     SECStatus rv;
   568     if (!ascii && !raw && !nickname && !email) {
   569         PR_fprintf(outfile, "\n%-60s %-5s\n%-60s %-5s\n\n",
   570                    "Certificate Nickname", "Trust Attributes", "",
   571                    "SSL,S/MIME,JAR/XPI");
   572     }
   573     if (slot == NULL) {
   574 	CERTCertList *list;
   575 	CERTCertListNode *node;
   577 	list = PK11_ListCerts(PK11CertListAll, pwdata);
   578 	for (node = CERT_LIST_HEAD(list); !CERT_LIST_END(node, list);
   579 	     node = CERT_LIST_NEXT(node)) {
   580 	    SECU_PrintCertNickname(node, stdout);
   581 	}
   582 	CERT_DestroyCertList(list);
   583 	return SECSuccess;
   584     } 
   585     rv = listCerts(handle, nickname, email, slot, raw, ascii,
   586                    extensionOID, outfile, pwdata);
   587     return rv;
   588 }
   590 static SECStatus 
   591 DeleteCert(CERTCertDBHandle *handle, char *name)
   592 {
   593     SECStatus rv;
   594     CERTCertificate *cert;
   596     cert = CERT_FindCertByNicknameOrEmailAddr(handle, name);
   597     if (!cert) {
   598 	SECU_PrintError(progName, "could not find certificate named \"%s\"",
   599 			name);
   600 	return SECFailure;
   601     }
   603     rv = SEC_DeletePermCertificate(cert);
   604     CERT_DestroyCertificate(cert);
   605     if (rv) {
   606 	SECU_PrintError(progName, "unable to delete certificate");
   607     }
   608     return rv;
   609 }
   611 static SECStatus
   612 ValidateCert(CERTCertDBHandle *handle, char *name, char *date,
   613              char *certUsage, PRBool checkSig, PRBool logit,
   614              PRBool ascii, secuPWData *pwdata)
   615 {
   616     SECStatus rv;
   617     CERTCertificate *cert = NULL;
   618     PRTime timeBoundary;
   619     SECCertificateUsage usage;
   620     CERTVerifyLog reallog;
   621     CERTVerifyLog *log = NULL;
   623     if (!certUsage) {
   624 	    PORT_SetError (SEC_ERROR_INVALID_ARGS);
   625 	    return (SECFailure);
   626     }
   628     switch (*certUsage) {
   629 	case 'O':
   630 	    usage = certificateUsageStatusResponder;
   631 	    break;
   632 	case 'L':
   633 	    usage = certificateUsageSSLCA;
   634 	    break;
   635 	case 'A':
   636 	    usage = certificateUsageAnyCA;
   637 	    break;
   638 	case 'Y':
   639 	    usage = certificateUsageVerifyCA;
   640 	    break;
   641 	case 'C':
   642 	    usage = certificateUsageSSLClient;
   643 	    break;
   644 	case 'V':
   645 	    usage = certificateUsageSSLServer;
   646 	    break;
   647 	case 'S':
   648 	    usage = certificateUsageEmailSigner;
   649 	    break;
   650 	case 'R':
   651 	    usage = certificateUsageEmailRecipient;
   652 	    break;
   653 	case 'J':
   654 	    usage = certificateUsageObjectSigner;
   655 	    break;
   656 	default:
   657 	    PORT_SetError (SEC_ERROR_INVALID_ARGS);
   658 	    return (SECFailure);
   659     }
   660     do {
   661 	cert = SECU_FindCertByNicknameOrFilename(handle, name, ascii,
   662                                                  NULL);
   663 	if (!cert) {
   664 	    SECU_PrintError(progName, "could not find certificate named \"%s\"",
   665 			    name);
   666 	    GEN_BREAK (SECFailure)
   667 	}
   669 	if (date != NULL) {
   670 	    rv = DER_AsciiToTime(&timeBoundary, date);
   671 	    if (rv) {
   672 		SECU_PrintError(progName, "invalid input date");
   673 		GEN_BREAK (SECFailure)
   674 	    }
   675 	} else {
   676 	    timeBoundary = PR_Now();
   677 	}
   679 	if ( logit ) {
   680 	    log = &reallog;
   682 	    log->count = 0;
   683 	    log->head = NULL;
   684 	    log->tail = NULL;
   685 	    log->arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
   686 	    if ( log->arena == NULL ) {
   687 		SECU_PrintError(progName, "out of memory");
   688 		GEN_BREAK (SECFailure)
   689 	    }
   690 	}
   692 	rv = CERT_VerifyCertificate(handle, cert, checkSig, usage,
   693 			     timeBoundary, pwdata, log, &usage);
   694 	if ( log ) {
   695 	    if ( log->head == NULL ) {
   696 		fprintf(stdout, "%s: certificate is valid\n", progName);
   697 		GEN_BREAK (SECSuccess)
   698 	    } else {
   699 		char *name;
   700 		CERTVerifyLogNode *node;
   702 		node = log->head;
   703 		while ( node ) {
   704 		    if ( node->cert->nickname != NULL ) {
   705 			name = node->cert->nickname;
   706 		    } else {
   707 			name = node->cert->subjectName;
   708 		    }
   709 		    fprintf(stderr, "%s : %s\n", name, 
   710 		    	SECU_Strerror(node->error));
   711 		    CERT_DestroyCertificate(node->cert);
   712 		    node = node->next;
   713 		}
   714 	    }
   715 	} else {
   716 	    if (rv != SECSuccess) {
   717 		PRErrorCode perr = PORT_GetError();
   718 		fprintf(stdout, "%s: certificate is invalid: %s\n",
   719 			progName, SECU_Strerror(perr));
   720 		GEN_BREAK (SECFailure)
   721 	    }
   722 	    fprintf(stdout, "%s: certificate is valid\n", progName);
   723 	    GEN_BREAK (SECSuccess)
   724 	}
   725     } while (0);
   727     if (cert) {
   728         CERT_DestroyCertificate(cert);
   729     }
   731     return (rv);
   732 }
   734 static PRBool
   735 ItemIsPrintableASCII(const SECItem * item)
   736 {
   737     unsigned char *src = item->data;
   738     unsigned int   len = item->len;
   739     while (len-- > 0) {
   740         unsigned char uc = *src++;
   741 	if (uc < 0x20 || uc > 0x7e) 
   742 	    return PR_FALSE;
   743     }
   744     return PR_TRUE;
   745 }
   747 /* Caller ensures that dst is at least item->len*2+1 bytes long */
   748 static void
   749 SECItemToHex(const SECItem * item, char * dst)
   750 {
   751     if (dst && item && item->data) {
   752 	unsigned char * src = item->data;
   753 	unsigned int    len = item->len;
   754 	for (; len > 0; --len, dst += 2) {
   755 	    sprintf(dst, "%02x", *src++);
   756 	}
   757 	*dst = '\0';
   758     }
   759 }
   761 static const char * const keyTypeName[] = {
   762   "null", "rsa", "dsa", "fortezza", "dh", "kea", "ec" };
   764 #define MAX_CKA_ID_BIN_LEN 20
   765 #define MAX_CKA_ID_STR_LEN 40
   767 /* print key number, key ID (in hex or ASCII), key label (nickname) */
   768 static SECStatus
   769 PrintKey(PRFileDesc *out, const char *nickName, int count, 
   770          SECKEYPrivateKey *key, void *pwarg)
   771 {
   772     SECItem * ckaID;
   773     char ckaIDbuf[MAX_CKA_ID_STR_LEN + 4];
   775     pwarg = NULL;
   776     ckaID = PK11_GetLowLevelKeyIDForPrivateKey(key);
   777     if (!ckaID) {
   778 	strcpy(ckaIDbuf, "(no CKA_ID)");
   779     } else if (ItemIsPrintableASCII(ckaID)) {
   780 	int len = PR_MIN(MAX_CKA_ID_STR_LEN, ckaID->len);
   781 	ckaIDbuf[0] = '"';
   782 	memcpy(ckaIDbuf + 1, ckaID->data, len);
   783 	ckaIDbuf[1 + len] = '"';
   784 	ckaIDbuf[2 + len] = '\0';
   785     } else {
   786     	/* print ckaid in hex */
   787 	SECItem idItem = *ckaID;
   788 	if (idItem.len > MAX_CKA_ID_BIN_LEN)
   789 	    idItem.len = MAX_CKA_ID_BIN_LEN;
   790         SECItemToHex(&idItem, ckaIDbuf);
   791     }
   793     PR_fprintf(out, "<%2d> %-8.8s %-42.42s %s\n", count, 
   794                keyTypeName[key->keyType], ckaIDbuf, nickName);
   795     SECITEM_ZfreeItem(ckaID, PR_TRUE);
   797     return SECSuccess;
   798 }
   800 /* returns SECSuccess if ANY keys are found, SECFailure otherwise. */
   801 static SECStatus
   802 ListKeysInSlot(PK11SlotInfo *slot, const char *nickName, KeyType keyType, 
   803                void *pwarg)
   804 {
   805     SECKEYPrivateKeyList *list;
   806     SECKEYPrivateKeyListNode *node;
   807     int count = 0;
   809     if (PK11_NeedLogin(slot)) {
   810         SECStatus rv = PK11_Authenticate(slot, PR_TRUE, pwarg);
   811         if (rv != SECSuccess) {
   812             SECU_PrintError(progName, "could not authenticate to token %s.",
   813                             PK11_GetTokenName(slot));
   814             return SECFailure;
   815         }
   816     }
   818     if (nickName && nickName[0]) 
   819 	list = PK11_ListPrivKeysInSlot(slot, (char *)nickName, pwarg);
   820     else
   821 	list = PK11_ListPrivateKeysInSlot(slot);
   822     if (list == NULL) {
   823 	SECU_PrintError(progName, "problem listing keys");
   824 	return SECFailure;
   825     }
   826     for (node=PRIVKEY_LIST_HEAD(list); 
   827              !PRIVKEY_LIST_END(node,list);
   828 	 node=PRIVKEY_LIST_NEXT(node)) {
   829 	char * keyName;
   830 	static const char orphan[] = { "(orphan)" };
   832 	if (keyType != nullKey && keyType != node->key->keyType)
   833 	    continue;
   834         keyName = PK11_GetPrivateKeyNickname(node->key);
   835 	if (!keyName || !keyName[0]) {
   836 	    /* Try extra hard to find nicknames for keys that lack them. */
   837 	    CERTCertificate * cert;
   838 	    PORT_Free((void *)keyName);
   839 	    keyName = NULL;
   840 	    cert = PK11_GetCertFromPrivateKey(node->key);
   841 	    if (cert) {
   842 		if (cert->nickname && cert->nickname[0]) {
   843 		    keyName = PORT_Strdup(cert->nickname);
   844 		} else if (cert->emailAddr && cert->emailAddr[0]) {
   845 		    keyName = PORT_Strdup(cert->emailAddr);
   846 		}
   847 		CERT_DestroyCertificate(cert);
   848 	    }
   849 	}
   850 	if (nickName) {
   851 	    if (!keyName || PL_strcmp(keyName,nickName)) {
   852 		/* PKCS#11 module returned unwanted keys */
   853 	        PORT_Free((void *)keyName);
   854 		continue;
   855 	    }
   856 	}
   857 	if (!keyName)
   858 	    keyName = (char *)orphan;
   860 	PrintKey(PR_STDOUT, keyName, count, node->key, pwarg);
   862 	if (keyName != (char *)orphan)
   863 	    PORT_Free((void *)keyName);
   864 	count++;
   865     }
   866     SECKEY_DestroyPrivateKeyList(list);
   868     if (count == 0) {
   869 	PR_fprintf(PR_STDOUT, "%s: no keys found\n", progName);
   870 	return SECFailure;
   871     }
   872     return SECSuccess;
   873 }
   875 /* returns SECSuccess if ANY keys are found, SECFailure otherwise. */
   876 static SECStatus
   877 ListKeys(PK11SlotInfo *slot, const char *nickName, int index, 
   878          KeyType keyType, PRBool dopriv, secuPWData *pwdata)
   879 {
   880     SECStatus rv = SECFailure;
   881     static const char fmt[] = \
   882     	"%s: Checking token \"%.33s\" in slot \"%.65s\"\n";
   884     if (slot == NULL) {
   885 	PK11SlotList *list;
   886 	PK11SlotListElement *le;
   888 	list= PK11_GetAllTokens(CKM_INVALID_MECHANISM,PR_FALSE,PR_FALSE,pwdata);
   889 	if (list) {
   890 	    for (le = list->head; le; le = le->next) {
   891 		PR_fprintf(PR_STDOUT, fmt, progName, 
   892 			   PK11_GetTokenName(le->slot), 
   893 			   PK11_GetSlotName(le->slot));
   894 		rv &= ListKeysInSlot(le->slot,nickName,keyType,pwdata);
   895 	    }
   896 	    PK11_FreeSlotList(list);
   897 	}
   898     } else {
   899 	PR_fprintf(PR_STDOUT, fmt, progName, PK11_GetTokenName(slot), 
   900 	           PK11_GetSlotName(slot));
   901 	rv = ListKeysInSlot(slot,nickName,keyType,pwdata);
   902     }
   903     return rv;
   904 }
   906 static SECStatus
   907 DeleteKey(char *nickname, secuPWData *pwdata)
   908 {
   909     SECStatus rv;
   910     CERTCertificate *cert;
   911     PK11SlotInfo *slot;
   913     slot = PK11_GetInternalKeySlot();
   914     if (PK11_NeedLogin(slot)) {
   915         SECStatus rv = PK11_Authenticate(slot, PR_TRUE, pwdata);
   916         if (rv != SECSuccess) {
   917             SECU_PrintError(progName, "could not authenticate to token %s.",
   918                             PK11_GetTokenName(slot));
   919             return SECFailure;
   920         }
   921     }
   922     cert = PK11_FindCertFromNickname(nickname, pwdata);
   923     if (!cert) {
   924 	PK11_FreeSlot(slot);
   925 	return SECFailure;
   926     }
   927     rv = PK11_DeleteTokenCertAndKey(cert, pwdata);
   928     if (rv != SECSuccess) {
   929 	SECU_PrintError("problem deleting private key \"%s\"\n", nickname);
   930     }
   931     CERT_DestroyCertificate(cert);
   932     PK11_FreeSlot(slot);
   933     return rv;
   934 }
   937 /*
   938  *  L i s t M o d u l e s
   939  *
   940  *  Print a list of the PKCS11 modules that are
   941  *  available. This is useful for smartcard people to
   942  *  make sure they have the drivers loaded.
   943  *
   944  */
   945 static SECStatus
   946 ListModules(void)
   947 {
   948     PK11SlotList *list;
   949     PK11SlotListElement *le;
   951     /* get them all! */
   952     list = PK11_GetAllTokens(CKM_INVALID_MECHANISM,PR_FALSE,PR_FALSE,NULL);
   953     if (list == NULL) return SECFailure;
   955     /* look at each slot*/
   956     for (le = list->head ; le; le = le->next) {
   957       printf ("\n");
   958       printf ("    slot: %s\n", PK11_GetSlotName(le->slot));
   959       printf ("   token: %s\n", PK11_GetTokenName(le->slot));
   960     }
   961     PK11_FreeSlotList(list);
   963     return SECSuccess;
   964 }
   966 static void 
   967 PrintSyntax(char *progName)
   968 {
   969 #define FPS fprintf(stderr, 
   970     FPS "Type %s -H for more detailed descriptions\n", progName);
   971     FPS "Usage:  %s -N [-d certdir] [-P dbprefix] [-f pwfile] [--empty-password]\n", progName);
   972     FPS "Usage:  %s -T [-d certdir] [-P dbprefix] [-h token-name]\n"
   973 	"\t\t [-f pwfile] [-0 SSO-password]\n", progName);
   974     FPS "\t%s -A -n cert-name -t trustargs [-d certdir] [-P dbprefix] [-a] [-i input]\n", 
   975     	progName);
   976     FPS "\t%s -B -i batch-file\n", progName);
   977     FPS "\t%s -C [-c issuer-name | -x] -i cert-request-file -o cert-file\n"
   978 	"\t\t [-m serial-number] [-w warp-months] [-v months-valid]\n"
   979         "\t\t [-f pwfile] [-d certdir] [-P dbprefix]\n"
   980         "\t\t [-1 | --keyUsage [keyUsageKeyword,..]] [-2] [-3] [-4]\n"
   981         "\t\t [-5 | --nsCertType [nsCertTypeKeyword,...]]\n"
   982         "\t\t [-6 | --extKeyUsage [extKeyUsageKeyword,...]] [-7 emailAddrs]\n"
   983         "\t\t [-8 dns-names] [-a]\n",
   984 	progName);
   985     FPS "\t%s -D -n cert-name [-d certdir] [-P dbprefix]\n", progName);
   986     FPS "\t%s -E -n cert-name -t trustargs [-d certdir] [-P dbprefix] [-a] [-i input]\n", 
   987 	progName);
   988     FPS "\t%s -F -n nickname [-d certdir] [-P dbprefix]\n", 
   989 	progName);
   990     FPS "\t%s -G -n key-name [-h token-name] [-k rsa] [-g key-size] [-y exp]\n" 
   991 	"\t\t [-f pwfile] [-z noisefile] [-d certdir] [-P dbprefix]\n", progName);
   992     FPS "\t%s -G [-h token-name] -k dsa [-q pqgfile -g key-size] [-f pwfile]\n"
   993 	"\t\t [-z noisefile] [-d certdir] [-P dbprefix]\n", progName);
   994 #ifndef NSS_DISABLE_ECC
   995     FPS "\t%s -G [-h token-name] -k ec -q curve [-f pwfile]\n"
   996 	"\t\t [-z noisefile] [-d certdir] [-P dbprefix]\n", progName);
   997     FPS "\t%s -K [-n key-name] [-h token-name] [-k dsa|ec|rsa|all]\n", 
   998 	progName);
   999 #else
  1000     FPS "\t%s -K [-n key-name] [-h token-name] [-k dsa|rsa|all]\n", 
  1001 	progName);
  1002 #endif /* NSS_DISABLE_ECC */
  1003     FPS "\t\t [-f pwfile] [-X] [-d certdir] [-P dbprefix]\n");
  1004     FPS "\t%s --upgrade-merge --source-dir upgradeDir --upgrade-id uniqueID\n",
  1005 	progName);
  1006     FPS "\t\t [--upgrade-token-name tokenName] [-d targetDBDir]\n");
  1007     FPS "\t\t [-P targetDBPrefix] [--source-prefix upgradeDBPrefix]\n");
  1008     FPS "\t\t [-f targetPWfile] [-@ upgradePWFile]\n");
  1009     FPS "\t%s --merge --source-dir sourceDBDir [-d targetDBdir]\n",
  1010 	progName);
  1011     FPS "\t\t [-P targetDBPrefix] [--source-prefix sourceDBPrefix]\n");
  1012     FPS "\t\t [-f targetPWfile] [-@ sourcePWFile]\n");
  1013     FPS "\t%s -L [-n cert-name] [--email email-address] [-X] [-r] [-a]\n",
  1014 	progName);
  1015     FPS "\t\t [--dump-ext-val OID] [-d certdir] [-P dbprefix]\n");
  1016     FPS "\t%s -M -n cert-name -t trustargs [-d certdir] [-P dbprefix]\n",
  1017 	progName);
  1018     FPS "\t%s -O -n cert-name [-X] [-d certdir] [-a] [-P dbprefix]\n", progName);
  1019     FPS "\t%s -R -s subj -o cert-request-file [-d certdir] [-P dbprefix] [-p phone] [-a]\n"
  1020 	"\t\t [-7 emailAddrs] [-k key-type-or-id] [-h token-name] [-f pwfile] [-g key-size]\n",
  1021 	progName);
  1022     FPS "\t%s -V -n cert-name -u usage [-b time] [-e] [-a]\n"
  1023 	"\t\t[-X] [-d certdir] [-P dbprefix]\n",
  1024 	progName);
  1025     FPS "Usage:  %s -W [-d certdir] [-f pwfile] [-@newpwfile]\n",
  1026 	progName);
  1027     FPS "\t%s -S -n cert-name -s subj [-c issuer-name | -x]  -t trustargs\n"
  1028 	"\t\t [-k key-type-or-id] [-q key-params] [-h token-name] [-g key-size]\n"
  1029         "\t\t [-m serial-number] [-w warp-months] [-v months-valid]\n"
  1030 	"\t\t [-f pwfile] [-d certdir] [-P dbprefix]\n"
  1031         "\t\t [-p phone] [-1] [-2] [-3] [-4] [-5] [-6] [-7 emailAddrs]\n"
  1032         "\t\t [-8 DNS-names]\n"
  1033         "\t\t [--extAIA] [--extSIA] [--extCP] [--extPM] [--extPC] [--extIA]\n"
  1034         "\t\t [--extSKID] [--extNC] [--extSAN type:name[,type:name]...]\n"
  1035 	"\t\t [--extGeneric OID:critical-flag:filename[,OID:critical-flag:filename]...]\n", progName);
  1036     FPS "\t%s -U [-X] [-d certdir] [-P dbprefix]\n", progName);
  1037     exit(1);
  1040 enum usage_level {
  1041     usage_all = 0, usage_selected = 1
  1042 };
  1044 static void luCommonDetailsAE();
  1046 static void luA(enum usage_level ul, const char *command)
  1048     int is_my_command = (command && 0 == strcmp(command, "A"));
  1049     if (ul == usage_all || !command || is_my_command)
  1050     FPS "%-15s Add a certificate to the database        (create if needed)\n",
  1051         "-A");
  1052     if (ul == usage_selected && !is_my_command)
  1053         return;
  1054     if (ul == usage_all) {
  1055     FPS "%-20s\n", "   All options under -E apply");
  1057     else {
  1058         luCommonDetailsAE();
  1062 static void luB(enum usage_level ul, const char *command)
  1064     int is_my_command = (command && 0 == strcmp(command, "B"));
  1065     if (ul == usage_all || !command || is_my_command)
  1066     FPS "%-15s Run a series of certutil commands from a batch file\n", "-B");
  1067     if (ul == usage_selected && !is_my_command)
  1068         return;
  1069     FPS "%-20s Specify the batch file\n", "   -i batch-file");
  1072 static void luE(enum usage_level ul, const char *command)
  1074     int is_my_command = (command && 0 == strcmp(command, "E"));
  1075     if (ul == usage_all || !command || is_my_command)
  1076     FPS "%-15s Add an Email certificate to the database (create if needed)\n",
  1077         "-E");
  1078     if (ul == usage_selected && !is_my_command)
  1079         return;
  1080     luCommonDetailsAE();
  1083 static void luCommonDetailsAE()
  1085     FPS "%-20s Specify the nickname of the certificate to add\n",
  1086         "   -n cert-name");
  1087     FPS "%-20s Set the certificate trust attributes:\n",
  1088         "   -t trustargs");
  1089     FPS "%-25s trustargs is of the form x,y,z where x is for SSL, y is for S/MIME,\n", "");
  1090     FPS "%-25s and z is for code signing. Use ,, for no explicit trust.\n", "");
  1091     FPS "%-25s p \t prohibited (explicitly distrusted)\n", "");
  1092     FPS "%-25s P \t trusted peer\n", "");
  1093     FPS "%-25s c \t valid CA\n", "");
  1094     FPS "%-25s T \t trusted CA to issue client certs (implies c)\n", "");
  1095     FPS "%-25s C \t trusted CA to issue server certs (implies c)\n", "");
  1096     FPS "%-25s u \t user cert\n", "");
  1097     FPS "%-25s w \t send warning\n", "");
  1098     FPS "%-25s g \t make step-up cert\n", "");
  1099     FPS "%-20s Specify the password file\n",
  1100         "   -f pwfile");
  1101     FPS "%-20s Cert database directory (default is ~/.netscape)\n",
  1102         "   -d certdir");
  1103     FPS "%-20s Cert & Key database prefix\n",
  1104         "   -P dbprefix");
  1105     FPS "%-20s The input certificate is encoded in ASCII (RFC1113)\n",
  1106         "   -a");
  1107     FPS "%-20s Specify the certificate file (default is stdin)\n",
  1108         "   -i input");
  1109     FPS "\n");
  1112 static void luC(enum usage_level ul, const char *command)
  1114     int is_my_command = (command && 0 == strcmp(command, "C"));
  1115     if (ul == usage_all || !command || is_my_command)
  1116     FPS "%-15s Create a new binary certificate from a BINARY cert request\n",
  1117         "-C");
  1118     if (ul == usage_selected && !is_my_command)
  1119         return;
  1120     FPS "%-20s The nickname of the issuer cert\n",
  1121         "   -c issuer-name");
  1122     FPS "%-20s The BINARY certificate request file\n",
  1123         "   -i cert-request ");
  1124     FPS "%-20s Output binary cert to this file (default is stdout)\n",
  1125         "   -o output-cert");
  1126     FPS "%-20s Self sign\n",
  1127         "   -x");
  1128     FPS "%-20s Cert serial number\n",
  1129         "   -m serial-number");
  1130     FPS "%-20s Time Warp\n",
  1131         "   -w warp-months");
  1132     FPS "%-20s Months valid (default is 3)\n",
  1133         "   -v months-valid");
  1134     FPS "%-20s Specify the password file\n",
  1135         "   -f pwfile");
  1136     FPS "%-20s Cert database directory (default is ~/.netscape)\n",
  1137         "   -d certdir");
  1138     FPS "%-20s Cert & Key database prefix\n",
  1139         "   -P dbprefix");
  1140     FPS "%-20s \n"
  1141               "%-20s Create key usage extension. Possible keywords:\n"
  1142               "%-20s \"digitalSignature\", \"nonRepudiation\", \"keyEncipherment\",\n"
  1143               "%-20s \"dataEncipherment\", \"keyAgreement\", \"certSigning\",\n"
  1144               "%-20s \"crlSigning\", \"critical\"\n",
  1145         "   -1 | --keyUsage keyword,keyword,...", "", "", "", "");
  1146     FPS "%-20s Create basic constraint extension\n",
  1147         "   -2 ");
  1148     FPS "%-20s Create authority key ID extension\n",
  1149         "   -3 ");
  1150     FPS "%-20s Create crl distribution point extension\n",
  1151         "   -4 ");
  1152     FPS "%-20s \n"
  1153               "%-20s Create netscape cert type extension. Possible keywords:\n"
  1154               "%-20s \"sslClient\", \"sslServer\", \"smime\", \"objectSigning\",\n"
  1155               "%-20s \"sslCA\", \"smimeCA\", \"objectSigningCA\", \"critical\".\n",
  1156         "   -5 | --nsCertType keyword,keyword,... ", "", "", "");
  1157     FPS "%-20s \n"
  1158               "%-20s Create extended key usage extension. Possible keywords:\n"
  1159               "%-20s \"serverAuth\", \"clientAuth\",\"codeSigning\",\n"
  1160               "%-20s \"emailProtection\", \"timeStamp\",\"ocspResponder\",\n"
  1161               "%-20s \"stepUp\", \"msTrustListSign\", \"critical\"\n",
  1162         "   -6 | --extKeyUsage keyword,keyword,...", "", "", "", "");
  1163     FPS "%-20s Create an email subject alt name extension\n",
  1164         "   -7 emailAddrs");
  1165     FPS "%-20s Create an dns subject alt name extension\n",
  1166         "   -8 dnsNames");
  1167     FPS "%-20s The input certificate request is encoded in ASCII (RFC1113)\n",
  1168         "   -a");
  1169     FPS "\n");
  1172 static void luG(enum usage_level ul, const char *command)
  1174     int is_my_command = (command && 0 == strcmp(command, "G"));
  1175     if (ul == usage_all || !command || is_my_command)
  1176     FPS "%-15s Generate a new key pair\n",
  1177         "-G");
  1178     if (ul == usage_selected && !is_my_command)
  1179         return;
  1180     FPS "%-20s Name of token in which to generate key (default is internal)\n",
  1181         "   -h token-name");
  1182 #ifndef NSS_DISABLE_ECC
  1183     FPS "%-20s Type of key pair to generate (\"dsa\", \"ec\", \"rsa\" (default))\n",
  1184         "   -k key-type");
  1185     FPS "%-20s Key size in bits, (min %d, max %d, default %d) (not for ec)\n",
  1186         "   -g key-size", MIN_KEY_BITS, MAX_KEY_BITS, DEFAULT_KEY_BITS);
  1187 #else
  1188     FPS "%-20s Type of key pair to generate (\"dsa\", \"rsa\" (default))\n",
  1189         "   -k key-type");
  1190     FPS "%-20s Key size in bits, (min %d, max %d, default %d)\n",
  1191         "   -g key-size", MIN_KEY_BITS, MAX_KEY_BITS, DEFAULT_KEY_BITS);
  1192 #endif /* NSS_DISABLE_ECC */
  1193     FPS "%-20s Set the public exponent value (3, 17, 65537) (rsa only)\n",
  1194         "   -y exp");
  1195     FPS "%-20s Specify the password file\n",
  1196         "   -f password-file");
  1197     FPS "%-20s Specify the noise file to be used\n",
  1198         "   -z noisefile");
  1199     FPS "%-20s read PQG value from pqgfile (dsa only)\n",
  1200         "   -q pqgfile");
  1201 #ifndef NSS_DISABLE_ECC
  1202     FPS "%-20s Elliptic curve name (ec only)\n",
  1203         "   -q curve-name");
  1204     FPS "%-20s One of nistp256, nistp384, nistp521\n", "");
  1205 #ifdef NSS_ECC_MORE_THAN_SUITE_B
  1206     FPS "%-20s sect163k1, nistk163, sect163r1, sect163r2,\n", "");
  1207     FPS "%-20s nistb163, sect193r1, sect193r2, sect233k1, nistk233,\n", "");
  1208     FPS "%-20s sect233r1, nistb233, sect239k1, sect283k1, nistk283,\n", "");
  1209     FPS "%-20s sect283r1, nistb283, sect409k1, nistk409, sect409r1,\n", "");
  1210     FPS "%-20s nistb409, sect571k1, nistk571, sect571r1, nistb571,\n", "");
  1211     FPS "%-20s secp160k1, secp160r1, secp160r2, secp192k1, secp192r1,\n", "");
  1212     FPS "%-20s nistp192, secp224k1, secp224r1, nistp224, secp256k1,\n", "");
  1213     FPS "%-20s secp256r1, secp384r1, secp521r1,\n", "");
  1214     FPS "%-20s prime192v1, prime192v2, prime192v3, \n", "");
  1215     FPS "%-20s prime239v1, prime239v2, prime239v3, c2pnb163v1, \n", "");
  1216     FPS "%-20s c2pnb163v2, c2pnb163v3, c2pnb176v1, c2tnb191v1, \n", "");
  1217     FPS "%-20s c2tnb191v2, c2tnb191v3,  \n", "");
  1218     FPS "%-20s c2pnb208w1, c2tnb239v1, c2tnb239v2, c2tnb239v3, \n", "");
  1219     FPS "%-20s c2pnb272w1, c2pnb304w1, \n", "");
  1220     FPS "%-20s c2tnb359w1, c2pnb368w1, c2tnb431r1, secp112r1, \n", "");
  1221     FPS "%-20s secp112r2, secp128r1, secp128r2, sect113r1, sect113r2\n", "");
  1222     FPS "%-20s sect131r1, sect131r2\n", "");
  1223 #endif /* NSS_ECC_MORE_THAN_SUITE_B */
  1224 #endif
  1225     FPS "%-20s Key database directory (default is ~/.netscape)\n",
  1226         "   -d keydir");
  1227     FPS "%-20s Cert & Key database prefix\n",
  1228         "   -P dbprefix");
  1229     FPS "%-20s\n"
  1230         "%-20s PKCS #11 key Attributes.\n",
  1231         "   --keyAttrFlags attrflags", "");
  1232     FPS "%-20s Comma separated list of key attribute attribute flags,\n", "");
  1233     FPS "%-20s selected from the following list of choices:\n", "");
  1234     FPS "%-20s {token | session} {public | private} {sensitive | insensitive}\n", "");
  1235     FPS "%-20s {modifiable | unmodifiable} {extractable | unextractable}\n", "");
  1236     FPS "%-20s\n",
  1237         "   --keyOpFlagsOn opflags");
  1238     FPS "%-20s\n"
  1239         "%-20s PKCS #11 key Operation Flags.\n",
  1240         "   --keyOpFlagsOff opflags", "");
  1241     FPS "%-20s Comma separated list of one or more of the following:\n", "");
  1242     FPS "%-20s encrypt, decrypt, sign, sign_recover, verify,\n", "");
  1243     FPS "%-20s verify_recover, wrap, unwrap, derive\n", "");
  1244     FPS "\n");
  1247 static void luD(enum usage_level ul, const char *command)
  1249     int is_my_command = (command && 0 == strcmp(command, "D"));
  1250     if (ul == usage_all || !command || is_my_command)
  1251     FPS "%-15s Delete a certificate from the database\n",
  1252         "-D");
  1253     if (ul == usage_selected && !is_my_command)
  1254         return;
  1255     FPS "%-20s The nickname of the cert to delete\n",
  1256         "   -n cert-name");
  1257     FPS "%-20s Cert database directory (default is ~/.netscape)\n",
  1258         "   -d certdir");
  1259     FPS "%-20s Cert & Key database prefix\n",
  1260         "   -P dbprefix");
  1261     FPS "\n");
  1265 static void luF(enum usage_level ul, const char *command)
  1267     int is_my_command = (command && 0 == strcmp(command, "F"));
  1268     if (ul == usage_all || !command || is_my_command)
  1269     FPS "%-15s Delete a key from the database\n",
  1270         "-F");
  1271     if (ul == usage_selected && !is_my_command)
  1272         return;
  1273     FPS "%-20s The nickname of the key to delete\n",
  1274         "   -n cert-name");
  1275     FPS "%-20s Cert database directory (default is ~/.netscape)\n",
  1276         "   -d certdir");
  1277     FPS "%-20s Cert & Key database prefix\n",
  1278         "   -P dbprefix");
  1279     FPS "\n");
  1283 static void luU(enum usage_level ul, const char *command)
  1285     int is_my_command = (command && 0 == strcmp(command, "U"));
  1286     if (ul == usage_all || !command || is_my_command)
  1287     FPS "%-15s List all modules\n", /*, or print out a single named module\n",*/
  1288         "-U");
  1289     if (ul == usage_selected && !is_my_command)
  1290         return;
  1291     FPS "%-20s Module database directory (default is '~/.netscape')\n",
  1292         "   -d moddir");
  1293     FPS "%-20s Cert & Key database prefix\n",
  1294         "   -P dbprefix");
  1295     FPS "%-20s force the database to open R/W\n",
  1296         "   -X");
  1297     FPS "\n");
  1301 static void luK(enum usage_level ul, const char *command)
  1303     int is_my_command = (command && 0 == strcmp(command, "K"));
  1304     if (ul == usage_all || !command || is_my_command)
  1305     FPS "%-15s List all private keys\n",
  1306         "-K");
  1307     if (ul == usage_selected && !is_my_command)
  1308         return;
  1309     FPS "%-20s Name of token to search (\"all\" for all tokens)\n",
  1310         "   -h token-name ");
  1312     FPS "%-20s Key type (\"all\" (default), \"dsa\","
  1313 #ifndef NSS_DISABLE_ECC
  1314                                                     " \"ec\","
  1315 #endif
  1316                                                     " \"rsa\")\n",
  1317         "   -k key-type");
  1318     FPS "%-20s The nickname of the key or associated certificate\n",
  1319         "   -n name");
  1320     FPS "%-20s Specify the password file\n",
  1321         "   -f password-file");
  1322     FPS "%-20s Key database directory (default is ~/.netscape)\n",
  1323         "   -d keydir");
  1324     FPS "%-20s Cert & Key database prefix\n",
  1325         "   -P dbprefix");
  1326     FPS "%-20s force the database to open R/W\n",
  1327         "   -X");
  1328     FPS "\n");
  1331 static void luL(enum usage_level ul, const char *command)
  1333     int is_my_command = (command && 0 == strcmp(command, "L"));
  1334     if (ul == usage_all || !command || is_my_command)
  1335     FPS "%-15s List all certs, or print out a single named cert (or a subset)\n",
  1336         "-L");
  1337     if (ul == usage_selected && !is_my_command)
  1338         return;
  1339     FPS "%-20s Pretty print named cert (list all if unspecified)\n",
  1340         "   -n cert-name");
  1341     FPS "%-20s \n"
  1342               "%-20s Pretty print cert with email address (list all if unspecified)\n",
  1343         "   --email email-address", "");
  1344     FPS "%-20s Cert database directory (default is ~/.netscape)\n",
  1345         "   -d certdir");
  1346     FPS "%-20s Cert & Key database prefix\n",
  1347         "   -P dbprefix");
  1348     FPS "%-20s force the database to open R/W\n",
  1349         "   -X");
  1350     FPS "%-20s For single cert, print binary DER encoding\n",
  1351         "   -r");
  1352     FPS "%-20s For single cert, print ASCII encoding (RFC1113)\n",
  1353         "   -a");
  1354     FPS "%-20s \n"
  1355               "%-20s For single cert, print binary DER encoding of extension OID\n",
  1356         "   --dump-ext-val OID", "");
  1357     FPS "\n");
  1360 static void luM(enum usage_level ul, const char *command)
  1362     int is_my_command = (command && 0 == strcmp(command, "M"));
  1363     if (ul == usage_all || !command || is_my_command)
  1364     FPS "%-15s Modify trust attributes of certificate\n",
  1365         "-M");
  1366     if (ul == usage_selected && !is_my_command)
  1367         return;
  1368     FPS "%-20s The nickname of the cert to modify\n",
  1369         "   -n cert-name");
  1370     FPS "%-20s Set the certificate trust attributes (see -A above)\n",
  1371         "   -t trustargs");
  1372     FPS "%-20s Cert database directory (default is ~/.netscape)\n",
  1373         "   -d certdir");
  1374     FPS "%-20s Cert & Key database prefix\n",
  1375         "   -P dbprefix");
  1376     FPS "\n");
  1379 static void luN(enum usage_level ul, const char *command)
  1381     int is_my_command = (command && 0 == strcmp(command, "N"));
  1382     if (ul == usage_all || !command || is_my_command)
  1383     FPS "%-15s Create a new certificate database\n",
  1384         "-N");
  1385     if (ul == usage_selected && !is_my_command)
  1386         return;
  1387     FPS "%-20s Cert database directory (default is ~/.netscape)\n",
  1388         "   -d certdir");
  1389     FPS "%-20s Cert & Key database prefix\n",
  1390         "   -P dbprefix");
  1391     FPS "%-20s use empty password when creating a new database\n",
  1392         "   --empty-password");
  1393     FPS "\n");
  1396 static void luT(enum usage_level ul, const char *command)
  1398     int is_my_command = (command && 0 == strcmp(command, "T"));
  1399     if (ul == usage_all || !command || is_my_command)
  1400     FPS "%-15s Reset the Key database or token\n",
  1401         "-T");
  1402     if (ul == usage_selected && !is_my_command)
  1403         return;
  1404     FPS "%-20s Cert database directory (default is ~/.netscape)\n",
  1405         "   -d certdir");
  1406     FPS "%-20s Cert & Key database prefix\n",
  1407         "   -P dbprefix");
  1408     FPS "%-20s Token to reset (default is internal)\n",
  1409         "   -h token-name");
  1410     FPS "%-20s Set token's Site Security Officer password\n",
  1411         "   -0 SSO-password");
  1412     FPS "\n");
  1415 static void luO(enum usage_level ul, const char *command)
  1417     int is_my_command = (command && 0 == strcmp(command, "O"));
  1418     if (ul == usage_all || !command || is_my_command)
  1419     FPS "%-15s Print the chain of a certificate\n",
  1420         "-O");
  1421     if (ul == usage_selected && !is_my_command)
  1422         return;
  1423     FPS "%-20s The nickname of the cert to modify\n",
  1424         "   -n cert-name");
  1425     FPS "%-20s Cert database directory (default is ~/.netscape)\n",
  1426         "   -d certdir");
  1427     FPS "%-20s Input the certificate in ASCII (RFC1113); default is binary\n",
  1428         "   -a");
  1429     FPS "%-20s Cert & Key database prefix\n",
  1430         "   -P dbprefix");
  1431     FPS "%-20s force the database to open R/W\n",
  1432         "   -X");
  1433     FPS "\n");
  1436 static void luR(enum usage_level ul, const char *command)
  1438     int is_my_command = (command && 0 == strcmp(command, "R"));
  1439     if (ul == usage_all || !command || is_my_command)
  1440     FPS "%-15s Generate a certificate request (stdout)\n",
  1441         "-R");
  1442     if (ul == usage_selected && !is_my_command)
  1443         return;
  1444     FPS "%-20s Specify the subject name (using RFC1485)\n",
  1445         "   -s subject");
  1446     FPS "%-20s Output the cert request to this file\n",
  1447         "   -o output-req");
  1448 #ifndef NSS_DISABLE_ECC
  1449     FPS "%-20s Type of key pair to generate (\"dsa\", \"ec\", \"rsa\" (default))\n",
  1450 #else
  1451     FPS "%-20s Type of key pair to generate (\"dsa\", \"rsa\" (default))\n",
  1452 #endif /* NSS_DISABLE_ECC */
  1453         "   -k key-type-or-id");
  1454     FPS "%-20s or nickname of the cert key to use \n",
  1455         "");
  1456     FPS "%-20s Name of token in which to generate key (default is internal)\n",
  1457         "   -h token-name");
  1458     FPS "%-20s Key size in bits, RSA keys only (min %d, max %d, default %d)\n",
  1459         "   -g key-size", MIN_KEY_BITS, MAX_KEY_BITS, DEFAULT_KEY_BITS);
  1460     FPS "%-20s Name of file containing PQG parameters (dsa only)\n",
  1461         "   -q pqgfile");
  1462 #ifndef NSS_DISABLE_ECC
  1463     FPS "%-20s Elliptic curve name (ec only)\n",
  1464         "   -q curve-name");
  1465     FPS "%-20s See the \"-G\" option for a full list of supported names.\n",
  1466         "");
  1467 #endif /* NSS_DISABLE_ECC */
  1468     FPS "%-20s Specify the password file\n",
  1469         "   -f pwfile");
  1470     FPS "%-20s Key database directory (default is ~/.netscape)\n",
  1471         "   -d keydir");
  1472     FPS "%-20s Cert & Key database prefix\n",
  1473         "   -P dbprefix");
  1474     FPS "%-20s Specify the contact phone number (\"123-456-7890\")\n",
  1475         "   -p phone");
  1476     FPS "%-20s Output the cert request in ASCII (RFC1113); default is binary\n",
  1477         "   -a");
  1478     FPS "%-20s \n",
  1479         "   See -S for available extension options");
  1480     FPS "%-20s \n",
  1481         "   See -G for available key flag options");
  1482     FPS "\n");
  1485 static void luV(enum usage_level ul, const char *command)
  1487     int is_my_command = (command && 0 == strcmp(command, "V"));
  1488     if (ul == usage_all || !command || is_my_command)
  1489     FPS "%-15s Validate a certificate\n",
  1490         "-V");
  1491     if (ul == usage_selected && !is_my_command)
  1492         return;
  1493     FPS "%-20s The nickname of the cert to Validate\n",
  1494         "   -n cert-name");
  1495     FPS "%-20s validity time (\"YYMMDDHHMMSS[+HHMM|-HHMM|Z]\")\n",
  1496         "   -b time");
  1497     FPS "%-20s Check certificate signature \n",
  1498         "   -e ");   
  1499     FPS "%-20s Specify certificate usage:\n", "   -u certusage");
  1500     FPS "%-25s C \t SSL Client\n", "");
  1501     FPS "%-25s V \t SSL Server\n", "");
  1502     FPS "%-25s L \t SSL CA\n", "");
  1503     FPS "%-25s A \t Any CA\n", "");
  1504     FPS "%-25s Y \t Verify CA\n", "");
  1505     FPS "%-25s S \t Email signer\n", "");
  1506     FPS "%-25s R \t Email Recipient\n", "");   
  1507     FPS "%-25s O \t OCSP status responder\n", "");   
  1508     FPS "%-25s J \t Object signer\n", "");   
  1509     FPS "%-20s Cert database directory (default is ~/.netscape)\n",
  1510         "   -d certdir");
  1511     FPS "%-20s Input the certificate in ASCII (RFC1113); default is binary\n",
  1512         "   -a");
  1513     FPS "%-20s Cert & Key database prefix\n",
  1514         "   -P dbprefix");
  1515     FPS "%-20s force the database to open R/W\n",
  1516         "   -X");
  1517     FPS "\n");
  1520 static void luW(enum usage_level ul, const char *command)
  1522     int is_my_command = (command && 0 == strcmp(command, "W"));
  1523     if (ul == usage_all || !command || is_my_command)
  1524     FPS "%-15s Change the key database password\n",
  1525         "-W");
  1526     if (ul == usage_selected && !is_my_command)
  1527         return;
  1528     FPS "%-20s cert and key database directory\n",
  1529         "   -d certdir");
  1530     FPS "%-20s Specify a file with the current password\n",
  1531         "   -f pwfile");
  1532     FPS "%-20s Specify a file with the new password in two lines\n",
  1533         "   -@ newpwfile");
  1534     FPS "\n");
  1537 static void luUpgradeMerge(enum usage_level ul, const char *command)
  1539     int is_my_command = (command && 0 == strcmp(command, "upgrade-merge"));
  1540     if (ul == usage_all || !command || is_my_command)
  1541     FPS "%-15s Upgrade an old database and merge it into a new one\n",
  1542         "--upgrade-merge");
  1543     if (ul == usage_selected && !is_my_command)
  1544         return;
  1545     FPS "%-20s Cert database directory to merge into (default is ~/.netscape)\n",
  1546         "   -d certdir");
  1547     FPS "%-20s Cert & Key database prefix of the target database\n",
  1548         "   -P dbprefix");
  1549     FPS "%-20s Specify the password file for the target database\n",
  1550         "   -f pwfile");
  1551     FPS "%-20s \n%-20s Cert database directory to upgrade from\n",
  1552         "   --source-dir certdir", "");
  1553     FPS "%-20s \n%-20s Cert & Key database prefix of the upgrade database\n",
  1554         "   --source-prefix dbprefix", "");
  1555     FPS "%-20s \n%-20s Unique identifier for the upgrade database\n",
  1556         "   --upgrade-id uniqueID", "");
  1557     FPS "%-20s \n%-20s Name of the token while it is in upgrade state\n",
  1558         "   --upgrade-token-name name", "");
  1559     FPS "%-20s Specify the password file for the upgrade database\n",
  1560         "   -@ pwfile");
  1561     FPS "\n");
  1564 static void luMerge(enum usage_level ul, const char *command)
  1566     int is_my_command = (command && 0 == strcmp(command, "merge"));
  1567     if (ul == usage_all || !command || is_my_command)
  1568     FPS "%-15s Merge source database into the target database\n",
  1569         "--merge");
  1570     if (ul == usage_selected && !is_my_command)
  1571         return;
  1572     FPS "%-20s Cert database directory of target (default is ~/.netscape)\n",
  1573         "   -d certdir");
  1574     FPS "%-20s Cert & Key database prefix of the target database\n",
  1575         "   -P dbprefix");
  1576     FPS "%-20s Specify the password file for the target database\n",
  1577         "   -f pwfile");
  1578     FPS "%-20s \n%-20s Cert database directory of the source database\n",
  1579         "   --source-dir certdir", "");
  1580     FPS "%-20s \n%-20s Cert & Key database prefix of the source database\n",
  1581         "   --source-prefix dbprefix", "");
  1582     FPS "%-20s Specify the password file for the source database\n",
  1583         "   -@ pwfile");
  1584     FPS "\n");
  1587 static void luS(enum usage_level ul, const char *command)
  1589     int is_my_command = (command && 0 == strcmp(command, "S"));
  1590     if (ul == usage_all || !command || is_my_command)
  1591     FPS "%-15s Make a certificate and add to database\n",
  1592         "-S");
  1593     if (ul == usage_selected && !is_my_command)
  1594         return;
  1595     FPS "%-20s Specify the nickname of the cert\n",
  1596         "   -n key-name");
  1597     FPS "%-20s Specify the subject name (using RFC1485)\n",
  1598         "   -s subject");
  1599     FPS "%-20s The nickname of the issuer cert\n",
  1600         "   -c issuer-name");
  1601     FPS "%-20s Set the certificate trust attributes (see -A above)\n",
  1602         "   -t trustargs");
  1603 #ifndef NSS_DISABLE_ECC
  1604     FPS "%-20s Type of key pair to generate (\"dsa\", \"ec\", \"rsa\" (default))\n",
  1605 #else
  1606     FPS "%-20s Type of key pair to generate (\"dsa\", \"rsa\" (default))\n",
  1607 #endif /* NSS_DISABLE_ECC */
  1608         "   -k key-type-or-id");
  1609     FPS "%-20s Name of token in which to generate key (default is internal)\n",
  1610         "   -h token-name");
  1611     FPS "%-20s Key size in bits, RSA keys only (min %d, max %d, default %d)\n",
  1612         "   -g key-size", MIN_KEY_BITS, MAX_KEY_BITS, DEFAULT_KEY_BITS);
  1613     FPS "%-20s Name of file containing PQG parameters (dsa only)\n",
  1614         "   -q pqgfile");
  1615 #ifndef NSS_DISABLE_ECC
  1616     FPS "%-20s Elliptic curve name (ec only)\n",
  1617         "   -q curve-name");
  1618     FPS "%-20s See the \"-G\" option for a full list of supported names.\n",
  1619         "");
  1620 #endif /* NSS_DISABLE_ECC */
  1621     FPS "%-20s Self sign\n",
  1622         "   -x");
  1623     FPS "%-20s Cert serial number\n",
  1624         "   -m serial-number");
  1625     FPS "%-20s Time Warp\n",
  1626         "   -w warp-months");
  1627     FPS "%-20s Months valid (default is 3)\n",
  1628         "   -v months-valid");
  1629     FPS "%-20s Specify the password file\n",
  1630         "   -f pwfile");
  1631     FPS "%-20s Cert database directory (default is ~/.netscape)\n",
  1632         "   -d certdir");
  1633     FPS "%-20s Cert & Key database prefix\n",
  1634         "   -P dbprefix");
  1635     FPS "%-20s Specify the contact phone number (\"123-456-7890\")\n",
  1636         "   -p phone");
  1637     FPS "%-20s Create key usage extension\n",
  1638         "   -1 ");
  1639     FPS "%-20s Create basic constraint extension\n",
  1640         "   -2 ");
  1641     FPS "%-20s Create authority key ID extension\n",
  1642         "   -3 ");
  1643     FPS "%-20s Create crl distribution point extension\n",
  1644         "   -4 ");
  1645     FPS "%-20s Create netscape cert type extension\n",
  1646         "   -5 ");
  1647     FPS "%-20s Create extended key usage extension\n",
  1648         "   -6 ");
  1649     FPS "%-20s Create an email subject alt name extension\n",
  1650         "   -7 emailAddrs ");
  1651     FPS "%-20s Create a DNS subject alt name extension\n",
  1652         "   -8 DNS-names");
  1653     FPS "%-20s Create an Authority Information Access extension\n",
  1654         "   --extAIA ");
  1655     FPS "%-20s Create a Subject Information Access extension\n",
  1656         "   --extSIA ");
  1657     FPS "%-20s Create a Certificate Policies extension\n",
  1658         "   --extCP ");
  1659     FPS "%-20s Create a Policy Mappings extension\n",
  1660         "   --extPM ");
  1661     FPS "%-20s Create a Policy Constraints extension\n",
  1662         "   --extPC ");
  1663     FPS "%-20s Create an Inhibit Any Policy extension\n",
  1664         "   --extIA ");
  1665     FPS "%-20s Create a subject key ID extension\n",
  1666         "   --extSKID ");
  1667     FPS "%-20s \n",
  1668         "   See -G for available key flag options");
  1669     FPS "%-20s Create a name constraints extension\n",
  1670         "   --extNC ");
  1671     FPS "%-20s \n"
  1672         "%-20s Create a Subject Alt Name extension with one or multiple names\n",
  1673 	"   --extSAN type:name[,type:name]...", "");
  1674     FPS "%-20s - type: directory, dn, dns, edi, ediparty, email, ip, ipaddr,\n", "");
  1675     FPS "%-20s         other, registerid, rfc822, uri, x400, x400addr\n", "");
  1676     FPS "%-20s \n"
  1677         "%-20s Add one or multiple extensions that certutil cannot encode yet,\n"
  1678 	"%-20s by loading their encodings from external files.\n",
  1679         "   --extGeneric OID:critical-flag:filename[,OID:critical-flag:filename]...", "", "");
  1680     FPS "%-20s - OID (example): 1.2.3.4\n", "");
  1681     FPS "%-20s - critical-flag: critical or not-critical\n", "");
  1682     FPS "%-20s - filename: full path to a file containing an encoded extension\n", "");
  1683     FPS "\n");
  1686 static void LongUsage(char *progName, enum usage_level ul, const char *command)
  1688     luA(ul, command);
  1689     luB(ul, command);
  1690     luE(ul, command);
  1691     luC(ul, command);
  1692     luG(ul, command);
  1693     luD(ul, command);
  1694     luF(ul, command);
  1695     luU(ul, command);
  1696     luK(ul, command);
  1697     luL(ul, command);
  1698     luM(ul, command);
  1699     luN(ul, command);
  1700     luT(ul, command);
  1701     luO(ul, command);
  1702     luR(ul, command);
  1703     luV(ul, command);
  1704     luW(ul, command);
  1705     luUpgradeMerge(ul, command);
  1706     luMerge(ul, command);
  1707     luS(ul, command);
  1708 #undef FPS
  1711 static void
  1712 Usage(char *progName)
  1714     PR_fprintf(PR_STDERR,
  1715         "%s - Utility to manipulate NSS certificate databases\n\n"
  1716         "Usage:  %s <command> -d <database-directory> <options>\n\n"
  1717         "Valid commands:\n", progName, progName);
  1718     LongUsage(progName, usage_selected, NULL);
  1719     PR_fprintf(PR_STDERR, "\n"
  1720         "%s -H <command> : Print available options for the given command\n"
  1721         "%s -H : Print complete help output of all commands and options\n"
  1722         "%s --syntax : Print a short summary of all commands and options\n",
  1723         progName, progName, progName);
  1724     exit(1);
  1727 static CERTCertificate *
  1728 MakeV1Cert(	CERTCertDBHandle *	handle, 
  1729 		CERTCertificateRequest *req,
  1730 	    	char *			issuerNickName, 
  1731 		PRBool 			selfsign, 
  1732 		unsigned int 		serialNumber,
  1733 		int 			warpmonths,
  1734                 int                     validityMonths)
  1736     CERTCertificate *issuerCert = NULL;
  1737     CERTValidity *validity;
  1738     CERTCertificate *cert = NULL;
  1739     PRExplodedTime printableTime;
  1740     PRTime now, after;
  1742     if ( !selfsign ) {
  1743 	issuerCert = CERT_FindCertByNicknameOrEmailAddr(handle, issuerNickName);
  1744 	if (!issuerCert) {
  1745 	    SECU_PrintError(progName, "could not find certificate named \"%s\"",
  1746 			    issuerNickName);
  1747 	    return NULL;
  1751     now = PR_Now();
  1752     PR_ExplodeTime (now, PR_GMTParameters, &printableTime);
  1753     if ( warpmonths ) {
  1754 	printableTime.tm_month += warpmonths;
  1755 	now = PR_ImplodeTime (&printableTime);
  1756 	PR_ExplodeTime (now, PR_GMTParameters, &printableTime);
  1758     printableTime.tm_month += validityMonths;
  1759     after = PR_ImplodeTime (&printableTime);
  1761     /* note that the time is now in micro-second unit */
  1762     validity = CERT_CreateValidity (now, after);
  1763     if (validity) {
  1764         cert = CERT_CreateCertificate(serialNumber, 
  1765 				      (selfsign ? &req->subject 
  1766 				                : &issuerCert->subject), 
  1767 	                              validity, req);
  1769         CERT_DestroyValidity(validity);
  1771     if ( issuerCert ) {
  1772 	CERT_DestroyCertificate (issuerCert);
  1775     return(cert);
  1778 static SECStatus
  1779 SignCert(CERTCertDBHandle *handle, CERTCertificate *cert, PRBool selfsign, 
  1780          SECOidTag hashAlgTag,
  1781          SECKEYPrivateKey *privKey, char *issuerNickName,
  1782          int certVersion, void *pwarg)
  1784     SECItem der;
  1785     SECKEYPrivateKey *caPrivateKey = NULL;    
  1786     SECStatus rv;
  1787     PLArenaPool *arena;
  1788     SECOidTag algID;
  1789     void *dummy;
  1791     if( !selfsign ) {
  1792       CERTCertificate *issuer = PK11_FindCertFromNickname(issuerNickName, pwarg);
  1793       if( (CERTCertificate *)NULL == issuer ) {
  1794         SECU_PrintError(progName, "unable to find issuer with nickname %s", 
  1795 	                issuerNickName);
  1796         return SECFailure;
  1799       privKey = caPrivateKey = PK11_FindKeyByAnyCert(issuer, pwarg);
  1800       CERT_DestroyCertificate(issuer);
  1801       if (caPrivateKey == NULL) {
  1802 	SECU_PrintError(progName, "unable to retrieve key %s", issuerNickName);
  1803 	return SECFailure;
  1807     arena = cert->arena;
  1809     algID = SEC_GetSignatureAlgorithmOidTag(privKey->keyType, hashAlgTag);
  1810     if (algID == SEC_OID_UNKNOWN) {
  1811 	fprintf(stderr, "Unknown key or hash type for issuer.");
  1812 	rv = SECFailure;
  1813 	goto done;
  1816     rv = SECOID_SetAlgorithmID(arena, &cert->signature, algID, 0);
  1817     if (rv != SECSuccess) {
  1818 	fprintf(stderr, "Could not set signature algorithm id.");
  1819 	goto done;
  1822     switch(certVersion) {
  1823       case (SEC_CERTIFICATE_VERSION_1):
  1824         /* The initial version for x509 certificates is version one
  1825          * and this default value must be an implicit DER encoding. */
  1826         cert->version.data = NULL;
  1827         cert->version.len = 0;
  1828         break;
  1829       case (SEC_CERTIFICATE_VERSION_2):
  1830       case (SEC_CERTIFICATE_VERSION_3):
  1831       case 3: /* unspecified format (would be version 4 certificate). */
  1832         *(cert->version.data) = certVersion;
  1833         cert->version.len = 1;
  1834         break;
  1835       default:
  1836         PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1837         return SECFailure;
  1840     der.len = 0;
  1841     der.data = NULL;
  1842     dummy = SEC_ASN1EncodeItem (arena, &der, cert,
  1843 			 	SEC_ASN1_GET(CERT_CertificateTemplate));
  1844     if (!dummy) {
  1845 	fprintf (stderr, "Could not encode certificate.\n");
  1846 	rv = SECFailure;
  1847 	goto done;
  1850     rv = SEC_DerSignData(arena, &cert->derCert, der.data, der.len, privKey, algID);
  1851     if (rv != SECSuccess) {
  1852 	fprintf (stderr, "Could not sign encoded certificate data.\n");
  1853 	/* result allocated out of the arena, it will be freed
  1854 	 * when the arena is freed */
  1855 	goto done;
  1857 done:
  1858     if (caPrivateKey) {
  1859 	SECKEY_DestroyPrivateKey(caPrivateKey);
  1861     return rv;
  1864 static SECStatus
  1865 CreateCert(
  1866 	CERTCertDBHandle *handle, 
  1867 	PK11SlotInfo *slot,
  1868 	char *  issuerNickName, 
  1869 	const SECItem * certReqDER,
  1870 	SECKEYPrivateKey **selfsignprivkey,
  1871 	void 	*pwarg,
  1872 	SECOidTag hashAlgTag,
  1873 	unsigned int serialNumber, 
  1874 	int     warpmonths,
  1875 	int     validityMonths,
  1876 	const char *emailAddrs,
  1877 	const char *dnsNames,
  1878 	PRBool ascii,
  1879 	PRBool  selfsign,
  1880 	certutilExtnList extnList,
  1881 	const char *extGeneric,
  1882         int certVersion,
  1883 	SECItem * certDER)
  1885     void *	extHandle;
  1886     CERTCertificate *subjectCert 	= NULL;
  1887     CERTCertificateRequest *certReq	= NULL;
  1888     SECStatus 	rv 			= SECSuccess;
  1889     CERTCertExtension **CRexts;
  1891     do {
  1892 	/* Create a certrequest object from the input cert request der */
  1893 	certReq = GetCertRequest(certReqDER);
  1894 	if (certReq == NULL) {
  1895 	    GEN_BREAK (SECFailure)
  1898 	subjectCert = MakeV1Cert (handle, certReq, issuerNickName, selfsign,
  1899 				  serialNumber, warpmonths, validityMonths);
  1900 	if (subjectCert == NULL) {
  1901 	    GEN_BREAK (SECFailure)
  1905 	extHandle = CERT_StartCertExtensions (subjectCert);
  1906 	if (extHandle == NULL) {
  1907 	    GEN_BREAK (SECFailure)
  1910         rv = AddExtensions(extHandle, emailAddrs, dnsNames, extnList, extGeneric);
  1911         if (rv != SECSuccess) {
  1912 	    GEN_BREAK (SECFailure)
  1915         if (certReq->attributes != NULL &&
  1916 	    certReq->attributes[0] != NULL &&
  1917 	    certReq->attributes[0]->attrType.data != NULL &&
  1918 	    certReq->attributes[0]->attrType.len   > 0    &&
  1919             SECOID_FindOIDTag(&certReq->attributes[0]->attrType)
  1920                 == SEC_OID_PKCS9_EXTENSION_REQUEST) {
  1921             rv = CERT_GetCertificateRequestExtensions(certReq, &CRexts);
  1922             if (rv != SECSuccess)
  1923                 break;
  1924             rv = CERT_MergeExtensions(extHandle, CRexts);
  1925             if (rv != SECSuccess)
  1926                 break;
  1929 	CERT_FinishExtensions(extHandle);
  1931 	/* self-signing a cert request, find the private key */
  1932 	if (selfsign && *selfsignprivkey == NULL) {
  1933 	    *selfsignprivkey = PK11_FindKeyByDERCert(slot, subjectCert, pwarg);
  1934 	    if (!*selfsignprivkey) {
  1935 		fprintf(stderr, "Failed to locate private key.\n");
  1936 		rv = SECFailure;
  1937 		break;
  1941 	rv = SignCert(handle, subjectCert, selfsign, hashAlgTag,
  1942 		      *selfsignprivkey, issuerNickName,
  1943                       certVersion, pwarg);
  1944 	if (rv != SECSuccess)
  1945 	    break;
  1947 	rv = SECFailure;
  1948 	if (ascii) {
  1949 	    char * asciiDER = BTOA_DataToAscii(subjectCert->derCert.data,
  1950 					       subjectCert->derCert.len);
  1951 	    if (asciiDER) {
  1952 	        char * wrapped = PR_smprintf("%s\n%s\n%s\n",
  1953 					     NS_CERT_HEADER,
  1954 					     asciiDER,
  1955 					     NS_CERT_TRAILER);
  1956 	        if (wrapped) {
  1957 		    PRUint32 wrappedLen = PL_strlen(wrapped);
  1958 		    if (SECITEM_AllocItem(NULL, certDER, wrappedLen)) {
  1959 		        PORT_Memcpy(certDER->data, wrapped, wrappedLen);
  1960 		        rv = SECSuccess;
  1962 		    PR_smprintf_free(wrapped);
  1964 		PORT_Free(asciiDER);
  1966 	} else {
  1967 	    rv = SECITEM_CopyItem(NULL, certDER, &subjectCert->derCert);
  1969     } while (0);
  1970     CERT_DestroyCertificateRequest (certReq);
  1971     CERT_DestroyCertificate (subjectCert);
  1972     if (rv != SECSuccess) {
  1973 	PRErrorCode  perr = PR_GetError();
  1974         fprintf(stderr, "%s: unable to create cert (%s)\n", progName,
  1975                SECU_Strerror(perr));
  1977     return (rv);
  1981 /*
  1982  * map a class to a user presentable string
  1983  */
  1984 static const char *objClassArray[] = {
  1985    "Data",
  1986    "Certificate",
  1987    "Public Key",
  1988    "Private Key",
  1989    "Secret Key",
  1990    "Hardware Feature",
  1991    "Domain Parameters",
  1992    "Mechanism"
  1993 };
  1995 static const char *objNSSClassArray[] = {
  1996    "CKO_NSS",
  1997    "Crl",
  1998    "SMIME Record",
  1999    "Trust",
  2000    "Builtin Root List"
  2001 };
  2004 const char *
  2005 getObjectClass(CK_ULONG classType)
  2007     static char buf[sizeof(CK_ULONG)*2+3];
  2009     if (classType <= CKO_MECHANISM) {
  2010 	return objClassArray[classType];
  2012     if (classType >= CKO_NSS && classType <= CKO_NSS_BUILTIN_ROOT_LIST) {
  2013 	return objNSSClassArray[classType - CKO_NSS];
  2015     sprintf(buf, "0x%lx", classType);
  2016     return buf;
  2019 typedef struct {
  2020     char *name;
  2021     int  nameSize;
  2022     CK_ULONG value;
  2023 } flagArray;
  2025 #define NAME_SIZE(x) #x,sizeof(#x)-1
  2027 flagArray opFlagsArray[] =
  2029     {NAME_SIZE(encrypt), CKF_ENCRYPT},
  2030     {NAME_SIZE(decrypt), CKF_DECRYPT},
  2031     {NAME_SIZE(sign), CKF_SIGN},
  2032     {NAME_SIZE(sign_recover), CKF_SIGN_RECOVER},
  2033     {NAME_SIZE(verify), CKF_VERIFY},
  2034     {NAME_SIZE(verify_recover), CKF_VERIFY_RECOVER},
  2035     {NAME_SIZE(wrap), CKF_WRAP},
  2036     {NAME_SIZE(unwrap), CKF_UNWRAP},
  2037     {NAME_SIZE(derive), CKF_DERIVE},
  2038 };
  2040 int opFlagsCount = sizeof(opFlagsArray)/sizeof(flagArray);
  2042 flagArray attrFlagsArray[] =
  2044     {NAME_SIZE(token), PK11_ATTR_TOKEN},
  2045     {NAME_SIZE(session), PK11_ATTR_SESSION},
  2046     {NAME_SIZE(private), PK11_ATTR_PRIVATE},
  2047     {NAME_SIZE(public), PK11_ATTR_PUBLIC},
  2048     {NAME_SIZE(modifiable), PK11_ATTR_MODIFIABLE},
  2049     {NAME_SIZE(unmodifiable), PK11_ATTR_UNMODIFIABLE},
  2050     {NAME_SIZE(sensitive), PK11_ATTR_SENSITIVE},
  2051     {NAME_SIZE(insensitive), PK11_ATTR_INSENSITIVE},
  2052     {NAME_SIZE(extractable), PK11_ATTR_EXTRACTABLE},
  2053     {NAME_SIZE(unextractable), PK11_ATTR_UNEXTRACTABLE}
  2055 };
  2057 int attrFlagsCount = sizeof(attrFlagsArray)/sizeof(flagArray);
  2059 #define MAX_STRING 30
  2060 CK_ULONG
  2061 GetFlags(char *flagsString, flagArray *flagArray, int count)
  2063    CK_ULONG flagsValue = strtol(flagsString, NULL, 0);
  2064    int i;
  2066    if ((flagsValue != 0) || (*flagsString == 0)) {
  2067 	return flagsValue;
  2069    while (*flagsString) {
  2070 	for (i=0; i < count; i++) {
  2071 	    if (strncmp(flagsString, flagArray[i].name, flagArray[i].nameSize) 
  2072 								== 0) {
  2073 		flagsValue |= flagArray[i].value;
  2074 		flagsString += flagArray[i].nameSize;
  2075 		if (*flagsString != 0) {
  2076 		    flagsString++;
  2078 		break;
  2081 	if (i == count) {
  2082 	    char name[MAX_STRING];
  2083 	    char *tok;
  2085 	    strncpy(name,flagsString, MAX_STRING);
  2086 	    name[MAX_STRING-1] = 0;
  2087 	    tok = strchr(name, ',');
  2088 	    if (tok) {
  2089 		*tok = 0;
  2091 	    fprintf(stderr,"Unknown flag (%s)\n",name);
  2092 	    tok = strchr(flagsString, ',');
  2093 	    if (tok == NULL)  {
  2094 		break;
  2096 	    flagsString = tok+1;
  2099     return flagsValue;
  2102 CK_FLAGS
  2103 GetOpFlags(char *flags)
  2105     return GetFlags(flags, opFlagsArray, opFlagsCount);
  2108 PK11AttrFlags
  2109 GetAttrFlags(char *flags)
  2111     return GetFlags(flags, attrFlagsArray, attrFlagsCount);
  2114 char *mkNickname(unsigned char *data, int len)
  2116    char *nick = PORT_Alloc(len+1);
  2117    if (!nick) {
  2118 	return nick;
  2120    PORT_Memcpy(nick, data, len);
  2121    nick[len] = 0;
  2122    return nick;
  2125 /*
  2126  * dump a PK11_MergeTokens error log to the console
  2127  */
  2128 void
  2129 DumpMergeLog(const char *progname, PK11MergeLog *log)
  2131     PK11MergeLogNode *node;
  2133     for (node = log->head; node; node = node->next) {
  2134 	SECItem  attrItem;
  2135 	char *nickname = NULL;
  2136 	const char *objectClass = NULL;
  2137 	SECStatus rv;
  2139 	attrItem.data = NULL;
  2140 	rv = PK11_ReadRawAttribute(PK11_TypeGeneric, node->object, 
  2141 				   CKA_LABEL, &attrItem);
  2142 	if (rv == SECSuccess) {
  2143 	    nickname = mkNickname(attrItem.data, attrItem.len);
  2144 	    PORT_Free(attrItem.data);
  2146 	attrItem.data = NULL;
  2147 	rv = PK11_ReadRawAttribute(PK11_TypeGeneric, node->object, 
  2148 				   CKA_CLASS, &attrItem);
  2149 	if (rv == SECSuccess) {
  2150 	     if (attrItem.len == sizeof(CK_ULONG)) {
  2151 		objectClass = getObjectClass(*(CK_ULONG *)attrItem.data);
  2153 	     PORT_Free(attrItem.data);
  2156 	fprintf(stderr, "%s: Could not merge object %s (type %s): %s\n",
  2157 		progName,
  2158 		nickname ? nickname : "unnamed",
  2159 		objectClass ? objectClass : "unknown",
  2160 		SECU_Strerror(node->error));
  2162 	if (nickname) {
  2163 	    PORT_Free(nickname);
  2168 /*  Certutil commands  */
  2169 enum {
  2170     cmd_AddCert = 0,
  2171     cmd_CreateNewCert,
  2172     cmd_DeleteCert,
  2173     cmd_AddEmailCert,
  2174     cmd_DeleteKey,
  2175     cmd_GenKeyPair,
  2176     cmd_PrintHelp,
  2177     cmd_PrintSyntax,
  2178     cmd_ListKeys,
  2179     cmd_ListCerts,
  2180     cmd_ModifyCertTrust,
  2181     cmd_NewDBs,
  2182     cmd_DumpChain,
  2183     cmd_CertReq,
  2184     cmd_CreateAndAddCert,
  2185     cmd_TokenReset,
  2186     cmd_ListModules,
  2187     cmd_CheckCertValidity,
  2188     cmd_ChangePassword,
  2189     cmd_Version,
  2190     cmd_Batch,
  2191     cmd_Merge,
  2192     cmd_UpgradeMerge, /* test only */
  2193     max_cmd
  2194 };
  2196 /*  Certutil options */
  2197 enum certutilOpts {
  2198     opt_SSOPass = 0,
  2199     opt_AddKeyUsageExt,
  2200     opt_AddBasicConstraintExt,
  2201     opt_AddAuthorityKeyIDExt,
  2202     opt_AddCRLDistPtsExt,
  2203     opt_AddNSCertTypeExt,
  2204     opt_AddExtKeyUsageExt,
  2205     opt_ExtendedEmailAddrs,
  2206     opt_ExtendedDNSNames,
  2207     opt_ASCIIForIO,
  2208     opt_ValidityTime,
  2209     opt_IssuerName,
  2210     opt_CertDir,
  2211     opt_VerifySig,
  2212     opt_PasswordFile,
  2213     opt_KeySize,
  2214     opt_TokenName,
  2215     opt_InputFile,
  2216     opt_Emailaddress,
  2217     opt_KeyIndex,
  2218     opt_KeyType,
  2219     opt_DetailedInfo,
  2220     opt_SerialNumber,
  2221     opt_Nickname,
  2222     opt_OutputFile,
  2223     opt_PhoneNumber,
  2224     opt_DBPrefix,
  2225     opt_PQGFile,
  2226     opt_BinaryDER,
  2227     opt_Subject,
  2228     opt_Trust,
  2229     opt_Usage,
  2230     opt_Validity,
  2231     opt_OffsetMonths,
  2232     opt_SelfSign,
  2233     opt_RW,
  2234     opt_Exponent,
  2235     opt_NoiseFile,
  2236     opt_Hash,
  2237     opt_NewPasswordFile,
  2238     opt_AddAuthInfoAccExt,
  2239     opt_AddSubjInfoAccExt,
  2240     opt_AddCertPoliciesExt,
  2241     opt_AddPolicyMapExt,
  2242     opt_AddPolicyConstrExt,
  2243     opt_AddInhibAnyExt,
  2244     opt_AddNameConstraintsExt,
  2245     opt_AddSubjectKeyIDExt,
  2246     opt_AddCmdKeyUsageExt,
  2247     opt_AddCmdNSCertTypeExt,
  2248     opt_AddCmdExtKeyUsageExt,
  2249     opt_SourceDir,
  2250     opt_SourcePrefix,
  2251     opt_UpgradeID,
  2252     opt_UpgradeTokenName,
  2253     opt_KeyOpFlagsOn,
  2254     opt_KeyOpFlagsOff,
  2255     opt_KeyAttrFlags,
  2256     opt_EmptyPassword,
  2257     opt_CertVersion,
  2258     opt_AddSubjectAltNameExt,
  2259     opt_DumpExtensionValue,
  2260     opt_GenericExtensions,
  2261     opt_Help
  2262 };
  2264 static const
  2265 secuCommandFlag commands_init[] =
  2267 	{ /* cmd_AddCert             */  'A', PR_FALSE, 0, PR_FALSE },
  2268 	{ /* cmd_CreateNewCert       */  'C', PR_FALSE, 0, PR_FALSE },
  2269 	{ /* cmd_DeleteCert          */  'D', PR_FALSE, 0, PR_FALSE },
  2270 	{ /* cmd_AddEmailCert        */  'E', PR_FALSE, 0, PR_FALSE },
  2271 	{ /* cmd_DeleteKey           */  'F', PR_FALSE, 0, PR_FALSE },
  2272 	{ /* cmd_GenKeyPair          */  'G', PR_FALSE, 0, PR_FALSE },
  2273 	{ /* cmd_PrintHelp           */  'H', PR_FALSE, 0, PR_FALSE, "help" },
  2274         { /* cmd_PrintSyntax         */   0,  PR_FALSE, 0, PR_FALSE,
  2275                                                    "syntax" },
  2276 	{ /* cmd_ListKeys            */  'K', PR_FALSE, 0, PR_FALSE },
  2277 	{ /* cmd_ListCerts           */  'L', PR_FALSE, 0, PR_FALSE },
  2278 	{ /* cmd_ModifyCertTrust     */  'M', PR_FALSE, 0, PR_FALSE },
  2279 	{ /* cmd_NewDBs              */  'N', PR_FALSE, 0, PR_FALSE },
  2280 	{ /* cmd_DumpChain           */  'O', PR_FALSE, 0, PR_FALSE },
  2281 	{ /* cmd_CertReq             */  'R', PR_FALSE, 0, PR_FALSE },
  2282 	{ /* cmd_CreateAndAddCert    */  'S', PR_FALSE, 0, PR_FALSE },
  2283 	{ /* cmd_TokenReset          */  'T', PR_FALSE, 0, PR_FALSE },
  2284 	{ /* cmd_ListModules         */  'U', PR_FALSE, 0, PR_FALSE },
  2285 	{ /* cmd_CheckCertValidity   */  'V', PR_FALSE, 0, PR_FALSE },
  2286 	{ /* cmd_ChangePassword      */  'W', PR_FALSE, 0, PR_FALSE },
  2287 	{ /* cmd_Version             */  'Y', PR_FALSE, 0, PR_FALSE },
  2288 	{ /* cmd_Batch               */  'B', PR_FALSE, 0, PR_FALSE },
  2289 	{ /* cmd_Merge               */   0,  PR_FALSE, 0, PR_FALSE, "merge" },
  2290 	{ /* cmd_UpgradeMerge        */   0,  PR_FALSE, 0, PR_FALSE, 
  2291                                                    "upgrade-merge" }
  2292 };
  2293 #define NUM_COMMANDS ((sizeof commands_init) / (sizeof commands_init[0]))
  2295 static const 
  2296 secuCommandFlag options_init[] =
  2298 	{ /* opt_SSOPass             */  '0', PR_TRUE,  0, PR_FALSE },
  2299 	{ /* opt_AddKeyUsageExt      */  '1', PR_FALSE, 0, PR_FALSE },
  2300 	{ /* opt_AddBasicConstraintExt*/ '2', PR_FALSE, 0, PR_FALSE },
  2301 	{ /* opt_AddAuthorityKeyIDExt*/  '3', PR_FALSE, 0, PR_FALSE },
  2302 	{ /* opt_AddCRLDistPtsExt    */  '4', PR_FALSE, 0, PR_FALSE },
  2303 	{ /* opt_AddNSCertTypeExt    */  '5', PR_FALSE, 0, PR_FALSE },
  2304 	{ /* opt_AddExtKeyUsageExt   */  '6', PR_FALSE, 0, PR_FALSE },
  2305 	{ /* opt_ExtendedEmailAddrs  */  '7', PR_TRUE,  0, PR_FALSE },
  2306 	{ /* opt_ExtendedDNSNames    */  '8', PR_TRUE,  0, PR_FALSE },
  2307 	{ /* opt_ASCIIForIO          */  'a', PR_FALSE, 0, PR_FALSE },
  2308 	{ /* opt_ValidityTime        */  'b', PR_TRUE,  0, PR_FALSE },
  2309 	{ /* opt_IssuerName          */  'c', PR_TRUE,  0, PR_FALSE },
  2310 	{ /* opt_CertDir             */  'd', PR_TRUE,  0, PR_FALSE },
  2311 	{ /* opt_VerifySig           */  'e', PR_FALSE, 0, PR_FALSE },
  2312 	{ /* opt_PasswordFile        */  'f', PR_TRUE,  0, PR_FALSE },
  2313 	{ /* opt_KeySize             */  'g', PR_TRUE,  0, PR_FALSE },
  2314 	{ /* opt_TokenName           */  'h', PR_TRUE,  0, PR_FALSE },
  2315 	{ /* opt_InputFile           */  'i', PR_TRUE,  0, PR_FALSE },
  2316 	{ /* opt_Emailaddress        */  0,   PR_TRUE,  0, PR_FALSE, "email" },
  2317 	{ /* opt_KeyIndex            */  'j', PR_TRUE,  0, PR_FALSE },
  2318 	{ /* opt_KeyType             */  'k', PR_TRUE,  0, PR_FALSE },
  2319 	{ /* opt_DetailedInfo        */  'l', PR_FALSE, 0, PR_FALSE },
  2320 	{ /* opt_SerialNumber        */  'm', PR_TRUE,  0, PR_FALSE },
  2321 	{ /* opt_Nickname            */  'n', PR_TRUE,  0, PR_FALSE },
  2322 	{ /* opt_OutputFile          */  'o', PR_TRUE,  0, PR_FALSE },
  2323 	{ /* opt_PhoneNumber         */  'p', PR_TRUE,  0, PR_FALSE },
  2324 	{ /* opt_DBPrefix            */  'P', PR_TRUE,  0, PR_FALSE },
  2325 	{ /* opt_PQGFile             */  'q', PR_TRUE,  0, PR_FALSE },
  2326 	{ /* opt_BinaryDER           */  'r', PR_FALSE, 0, PR_FALSE },
  2327 	{ /* opt_Subject             */  's', PR_TRUE,  0, PR_FALSE },
  2328 	{ /* opt_Trust               */  't', PR_TRUE,  0, PR_FALSE },
  2329 	{ /* opt_Usage               */  'u', PR_TRUE,  0, PR_FALSE },
  2330 	{ /* opt_Validity            */  'v', PR_TRUE,  0, PR_FALSE },
  2331 	{ /* opt_OffsetMonths        */  'w', PR_TRUE,  0, PR_FALSE },
  2332 	{ /* opt_SelfSign            */  'x', PR_FALSE, 0, PR_FALSE },
  2333 	{ /* opt_RW                  */  'X', PR_FALSE, 0, PR_FALSE },
  2334 	{ /* opt_Exponent            */  'y', PR_TRUE,  0, PR_FALSE },
  2335 	{ /* opt_NoiseFile           */  'z', PR_TRUE,  0, PR_FALSE },
  2336 	{ /* opt_Hash                */  'Z', PR_TRUE,  0, PR_FALSE },
  2337 	{ /* opt_NewPasswordFile     */  '@', PR_TRUE,  0, PR_FALSE },
  2338 	{ /* opt_AddAuthInfoAccExt   */  0,   PR_FALSE, 0, PR_FALSE, "extAIA" },
  2339 	{ /* opt_AddSubjInfoAccExt   */  0,   PR_FALSE, 0, PR_FALSE, "extSIA" },
  2340 	{ /* opt_AddCertPoliciesExt  */  0,   PR_FALSE, 0, PR_FALSE, "extCP" },
  2341 	{ /* opt_AddPolicyMapExt     */  0,   PR_FALSE, 0, PR_FALSE, "extPM" },
  2342 	{ /* opt_AddPolicyConstrExt  */  0,   PR_FALSE, 0, PR_FALSE, "extPC" },
  2343 	{ /* opt_AddInhibAnyExt      */  0,   PR_FALSE, 0, PR_FALSE, "extIA" },
  2344 	{ /* opt_AddNameConstraintsExt*/ 0,   PR_FALSE, 0, PR_FALSE, "extNC" },
  2345 	{ /* opt_AddSubjectKeyIDExt  */  0,   PR_FALSE, 0, PR_FALSE, 
  2346 						   "extSKID" },
  2347 	{ /* opt_AddCmdKeyUsageExt   */  0,   PR_TRUE,  0, PR_FALSE,
  2348                                                    "keyUsage" },
  2349 	{ /* opt_AddCmdNSCertTypeExt */   0,   PR_TRUE,  0, PR_FALSE,
  2350                                                    "nsCertType" },
  2351 	{ /* opt_AddCmdExtKeyUsageExt*/  0,   PR_TRUE,  0, PR_FALSE,
  2352                                                    "extKeyUsage" },
  2354 	{ /* opt_SourceDir           */  0,   PR_TRUE,  0, PR_FALSE,
  2355                                                    "source-dir"},
  2356 	{ /* opt_SourcePrefix        */  0,   PR_TRUE,  0, PR_FALSE, 
  2357 						   "source-prefix"},
  2358 	{ /* opt_UpgradeID           */  0,   PR_TRUE,  0, PR_FALSE, 
  2359                                                    "upgrade-id"},
  2360 	{ /* opt_UpgradeTokenName    */  0,   PR_TRUE,  0, PR_FALSE, 
  2361                                                    "upgrade-token-name"},
  2362 	{ /* opt_KeyOpFlagsOn        */  0,   PR_TRUE, 0, PR_FALSE, 
  2363                                                    "keyOpFlagsOn"},
  2364 	{ /* opt_KeyOpFlagsOff       */  0,   PR_TRUE, 0, PR_FALSE, 
  2365                                                    "keyOpFlagsOff"},
  2366 	{ /* opt_KeyAttrFlags        */  0,   PR_TRUE, 0, PR_FALSE, 
  2367                                                    "keyAttrFlags"},
  2368 	{ /* opt_EmptyPassword       */  0,   PR_FALSE, 0, PR_FALSE, 
  2369                                                    "empty-password"},
  2370         { /* opt_CertVersion         */  0,   PR_FALSE, 0, PR_FALSE,
  2371                                                    "certVersion"},
  2372 	{ /* opt_AddSubjectAltExt    */  0,   PR_TRUE,  0, PR_FALSE, "extSAN"},
  2373 	{ /* opt_DumpExtensionValue  */  0,   PR_TRUE, 0, PR_FALSE, 
  2374                                                    "dump-ext-val"},
  2375 	{ /* opt_GenericExtensions   */  0,   PR_TRUE, 0, PR_FALSE, 
  2376                                                    "extGeneric"},
  2377 };
  2378 #define NUM_OPTIONS ((sizeof options_init)  / (sizeof options_init[0]))
  2380 static secuCommandFlag certutil_commands[NUM_COMMANDS];
  2381 static secuCommandFlag certutil_options [NUM_OPTIONS ];
  2383 static const secuCommand certutil = {
  2384     NUM_COMMANDS, 
  2385     NUM_OPTIONS, 
  2386     certutil_commands, 
  2387     certutil_options
  2388 };
  2390 static certutilExtnList certutil_extns;
  2392 static int 
  2393 certutil_main(int argc, char **argv, PRBool initialize)
  2395     CERTCertDBHandle *certHandle;
  2396     PK11SlotInfo *slot = NULL;
  2397     CERTName *  subject         = 0;
  2398     PRFileDesc *inFile          = PR_STDIN;
  2399     PRFileDesc *outFile         = PR_STDOUT;
  2400     SECItem     certReqDER      = { siBuffer, NULL, 0 };
  2401     SECItem     certDER         = { siBuffer, NULL, 0 };
  2402     char *      slotname        = "internal";
  2403     char *      certPrefix      = "";
  2404     char *      sourceDir       = "";
  2405     char *      srcCertPrefix   = "";
  2406     char *      upgradeID        = "";
  2407     char *      upgradeTokenName     = "";
  2408     KeyType     keytype         = rsaKey;
  2409     char *      name            = NULL;
  2410     char *      email            = NULL;
  2411     char *      keysource       = NULL;
  2412     SECOidTag   hashAlgTag      = SEC_OID_UNKNOWN;
  2413     int	        keysize	        = DEFAULT_KEY_BITS;
  2414     int         publicExponent  = 0x010001;
  2415     int         certVersion     = SEC_CERTIFICATE_VERSION_3;
  2416     unsigned int serialNumber   = 0;
  2417     int         warpmonths      = 0;
  2418     int         validityMonths  = 3;
  2419     int         commandsEntered = 0;
  2420     char        commandToRun    = '\0';
  2421     secuPWData  pwdata          = { PW_NONE, 0 };
  2422     secuPWData  pwdata2         = { PW_NONE, 0 };
  2423     PRBool      readOnly        = PR_FALSE;
  2424     PRBool      initialized     = PR_FALSE;
  2425     CK_FLAGS    keyOpFlagsOn = 0;
  2426     CK_FLAGS    keyOpFlagsOff = 0;
  2427     PK11AttrFlags    keyAttrFlags = 
  2428 		PK11_ATTR_TOKEN | PK11_ATTR_SENSITIVE | PK11_ATTR_PRIVATE;
  2430     SECKEYPrivateKey *privkey = NULL;
  2431     SECKEYPublicKey *pubkey = NULL;
  2433     int i;
  2434     SECStatus rv;
  2436     progName = PORT_Strrchr(argv[0], '/');
  2437     progName = progName ? progName+1 : argv[0];
  2438     memcpy(certutil_commands, commands_init, sizeof commands_init);
  2439     memcpy(certutil_options,  options_init,  sizeof options_init);
  2441     rv = SECU_ParseCommandLine(argc, argv, progName, &certutil);
  2443     if (rv != SECSuccess)
  2444 	Usage(progName);
  2446     if (certutil.commands[cmd_PrintSyntax].activated) {
  2447         PrintSyntax(progName);
  2450     if (certutil.commands[cmd_PrintHelp].activated) {
  2451         int i;
  2452         char buf[2];
  2453         const char *command = NULL;
  2454         for (i = 0; i < max_cmd; i++) {
  2455             if (i == cmd_PrintHelp)
  2456                 continue;
  2457             if (certutil.commands[i].activated) {
  2458                 if (certutil.commands[i].flag) {
  2459                     buf[0] = certutil.commands[i].flag;
  2460                     buf[1] = 0;
  2461                     command = buf;
  2463                 else {
  2464                     command = certutil.commands[i].longform;
  2466                 break;
  2469 	LongUsage(progName, (command ? usage_selected : usage_all), command);
  2470         exit(1);
  2473     if (certutil.options[opt_PasswordFile].arg) {
  2474 	pwdata.source = PW_FROMFILE;
  2475 	pwdata.data = certutil.options[opt_PasswordFile].arg;
  2477     if (certutil.options[opt_NewPasswordFile].arg) {
  2478 	pwdata2.source = PW_FROMFILE;
  2479 	pwdata2.data = certutil.options[opt_NewPasswordFile].arg;
  2482     if (certutil.options[opt_CertDir].activated)
  2483 	SECU_ConfigDirectory(certutil.options[opt_CertDir].arg);
  2485     if (certutil.options[opt_SourceDir].activated)
  2486 	sourceDir = certutil.options[opt_SourceDir].arg;
  2488     if (certutil.options[opt_UpgradeID].activated)
  2489 	upgradeID = certutil.options[opt_UpgradeID].arg;
  2491     if (certutil.options[opt_UpgradeTokenName].activated)
  2492 	upgradeTokenName = certutil.options[opt_UpgradeTokenName].arg;
  2494     if (certutil.options[opt_KeySize].activated) {
  2495 	keysize = PORT_Atoi(certutil.options[opt_KeySize].arg);
  2496 	if ((keysize < MIN_KEY_BITS) || (keysize > MAX_KEY_BITS)) {
  2497 	    PR_fprintf(PR_STDERR, 
  2498                        "%s -g:  Keysize must be between %d and %d.\n",
  2499 		       progName, MIN_KEY_BITS, MAX_KEY_BITS);
  2500 	    return 255;
  2502 #ifndef NSS_DISABLE_ECC
  2503 	if (keytype == ecKey) {
  2504 	    PR_fprintf(PR_STDERR, "%s -g:  Not for ec keys.\n", progName);
  2505 	    return 255;
  2507 #endif /* NSS_DISABLE_ECC */
  2511     /*  -h specify token name  */
  2512     if (certutil.options[opt_TokenName].activated) {
  2513 	if (PL_strcmp(certutil.options[opt_TokenName].arg, "all") == 0)
  2514 	    slotname = NULL;
  2515 	else
  2516 	    slotname = PL_strdup(certutil.options[opt_TokenName].arg);
  2519     /*  -Z hash type  */
  2520     if (certutil.options[opt_Hash].activated) {
  2521 	char * arg = certutil.options[opt_Hash].arg;
  2522         hashAlgTag = SECU_StringToSignatureAlgTag(arg);
  2523         if (hashAlgTag == SEC_OID_UNKNOWN) {
  2524 	    PR_fprintf(PR_STDERR, "%s -Z:  %s is not a recognized type.\n",
  2525 	               progName, arg);
  2526 	    return 255;
  2530     /*  -k key type  */
  2531     if (certutil.options[opt_KeyType].activated) {
  2532 	char * arg = certutil.options[opt_KeyType].arg;
  2533 	if (PL_strcmp(arg, "rsa") == 0) {
  2534 	    keytype = rsaKey;
  2535 	} else if (PL_strcmp(arg, "dsa") == 0) {
  2536 	    keytype = dsaKey;
  2537 #ifndef NSS_DISABLE_ECC
  2538 	} else if (PL_strcmp(arg, "ec") == 0) {
  2539 	    keytype = ecKey;
  2540 #endif /* NSS_DISABLE_ECC */
  2541 	} else if (PL_strcmp(arg, "all") == 0) {
  2542 	    keytype = nullKey;
  2543 	} else {
  2544 	    /* use an existing private/public key pair */
  2545 	    keysource = arg;
  2547     } else if (certutil.commands[cmd_ListKeys].activated) {
  2548 	keytype = nullKey;
  2551     if (certutil.options[opt_KeyOpFlagsOn].activated) {
  2552 	keyOpFlagsOn = GetOpFlags(certutil.options[opt_KeyOpFlagsOn].arg);
  2554     if (certutil.options[opt_KeyOpFlagsOff].activated) {
  2555 	keyOpFlagsOff = GetOpFlags(certutil.options[opt_KeyOpFlagsOff].arg);
  2556 	keyOpFlagsOn &=~keyOpFlagsOff; /* make off override on */
  2558     if (certutil.options[opt_KeyAttrFlags].activated) {
  2559 	keyAttrFlags = GetAttrFlags(certutil.options[opt_KeyAttrFlags].arg);
  2562     /*  -m serial number */
  2563     if (certutil.options[opt_SerialNumber].activated) {
  2564 	int sn = PORT_Atoi(certutil.options[opt_SerialNumber].arg);
  2565 	if (sn < 0) {
  2566 	    PR_fprintf(PR_STDERR, "%s -m:  %s is not a valid serial number.\n",
  2567 	               progName, certutil.options[opt_SerialNumber].arg);
  2568 	    return 255;
  2570 	serialNumber = sn;
  2573     /*  -P certdb name prefix */
  2574     if (certutil.options[opt_DBPrefix].activated) {
  2575         if (certutil.options[opt_DBPrefix].arg) {
  2576             certPrefix = strdup(certutil.options[opt_DBPrefix].arg);
  2577         } else {
  2578             Usage(progName);
  2582     /*  --source-prefix certdb name prefix */
  2583     if (certutil.options[opt_SourcePrefix].activated) {
  2584         if (certutil.options[opt_SourcePrefix].arg) {
  2585             srcCertPrefix = strdup(certutil.options[opt_SourcePrefix].arg);
  2586         } else {
  2587             Usage(progName);
  2591     /*  -q PQG file or curve name */
  2592     if (certutil.options[opt_PQGFile].activated) {
  2593 #ifndef NSS_DISABLE_ECC
  2594 	if ((keytype != dsaKey) && (keytype != ecKey)) {
  2595 	    PR_fprintf(PR_STDERR, "%s -q: specifies a PQG file for DSA keys" \
  2596 		       " (-k dsa) or a named curve for EC keys (-k ec)\n)",
  2597 	               progName);
  2598 #else   /* } */
  2599 	if (keytype != dsaKey) {
  2600 	    PR_fprintf(PR_STDERR, "%s -q: PQG file is for DSA key (-k dsa).\n)",
  2601 	               progName);
  2602 #endif /* NSS_DISABLE_ECC */
  2603 	    return 255;
  2607     /*  -s subject name  */
  2608     if (certutil.options[opt_Subject].activated) {
  2609 	subject = CERT_AsciiToName(certutil.options[opt_Subject].arg);
  2610 	if (!subject) {
  2611 	    PR_fprintf(PR_STDERR, "%s -s: improperly formatted name: \"%s\"\n",
  2612 	               progName, certutil.options[opt_Subject].arg);
  2613 	    return 255;
  2617     /*  -v validity period  */
  2618     if (certutil.options[opt_Validity].activated) {
  2619 	validityMonths = PORT_Atoi(certutil.options[opt_Validity].arg);
  2620 	if (validityMonths < 0) {
  2621 	    PR_fprintf(PR_STDERR, "%s -v: incorrect validity period: \"%s\"\n",
  2622 	               progName, certutil.options[opt_Validity].arg);
  2623 	    return 255;
  2627     /*  -w warp months  */
  2628     if (certutil.options[opt_OffsetMonths].activated)
  2629 	warpmonths = PORT_Atoi(certutil.options[opt_OffsetMonths].arg);
  2631     /*  -y public exponent (for RSA)  */
  2632     if (certutil.options[opt_Exponent].activated) {
  2633 	publicExponent = PORT_Atoi(certutil.options[opt_Exponent].arg);
  2634 	if ((publicExponent != 3) &&
  2635 	    (publicExponent != 17) &&
  2636 	    (publicExponent != 65537)) {
  2637 	    PR_fprintf(PR_STDERR, "%s -y: incorrect public exponent %d.", 
  2638 	                           progName, publicExponent);
  2639 	    PR_fprintf(PR_STDERR, "Must be 3, 17, or 65537.\n");
  2640 	    return 255;
  2644     /*  --certVersion */
  2645     if (certutil.options[opt_CertVersion].activated) {
  2646         certVersion = PORT_Atoi(certutil.options[opt_CertVersion].arg);
  2647         if (certVersion < 1 || certVersion > 4) {
  2648             PR_fprintf(PR_STDERR, "%s -certVersion: incorrect certificate version %d.",
  2649                                    progName, certVersion);
  2650             PR_fprintf(PR_STDERR, "Must be 1, 2, 3 or 4.\n");
  2651             return 255;
  2653         certVersion = certVersion - 1;
  2657     /*  Check number of commands entered.  */
  2658     commandsEntered = 0;
  2659     for (i=0; i< certutil.numCommands; i++) {
  2660 	if (certutil.commands[i].activated) {
  2661 	    commandToRun = certutil.commands[i].flag;
  2662 	    commandsEntered++;
  2664 	if (commandsEntered > 1)
  2665 	    break;
  2667     if (commandsEntered > 1) {
  2668 	PR_fprintf(PR_STDERR, "%s: only one command at a time!\n", progName);
  2669 	PR_fprintf(PR_STDERR, "You entered: ");
  2670 	for (i=0; i< certutil.numCommands; i++) {
  2671 	    if (certutil.commands[i].activated)
  2672 		PR_fprintf(PR_STDERR, " -%c", certutil.commands[i].flag);
  2674 	PR_fprintf(PR_STDERR, "\n");
  2675 	return 255;
  2677     if (commandsEntered == 0) {
  2678 	Usage(progName);
  2681     if (certutil.commands[cmd_ListCerts].activated ||
  2682          certutil.commands[cmd_PrintHelp].activated ||
  2683          certutil.commands[cmd_ListKeys].activated ||
  2684          certutil.commands[cmd_ListModules].activated ||
  2685          certutil.commands[cmd_CheckCertValidity].activated ||
  2686          certutil.commands[cmd_Version].activated ) {
  2687 	readOnly = !certutil.options[opt_RW].activated;
  2690     /*  -A, -D, -F, -M, -S, -V, and all require -n  */
  2691     if ((certutil.commands[cmd_AddCert].activated ||
  2692          certutil.commands[cmd_DeleteCert].activated ||
  2693          certutil.commands[cmd_DeleteKey].activated ||
  2694 	 certutil.commands[cmd_DumpChain].activated ||
  2695          certutil.commands[cmd_ModifyCertTrust].activated ||
  2696          certutil.commands[cmd_CreateAndAddCert].activated ||
  2697          certutil.commands[cmd_CheckCertValidity].activated) &&
  2698         !certutil.options[opt_Nickname].activated) {
  2699 	PR_fprintf(PR_STDERR, 
  2700 	          "%s -%c: nickname is required for this command (-n).\n",
  2701 	           progName, commandToRun);
  2702 	return 255;
  2705     /*  -A, -E, -M, -S require trust  */
  2706     if ((certutil.commands[cmd_AddCert].activated ||
  2707          certutil.commands[cmd_AddEmailCert].activated ||
  2708          certutil.commands[cmd_ModifyCertTrust].activated ||
  2709          certutil.commands[cmd_CreateAndAddCert].activated) &&
  2710         !certutil.options[opt_Trust].activated) {
  2711 	PR_fprintf(PR_STDERR, 
  2712 	          "%s -%c: trust is required for this command (-t).\n",
  2713 	           progName, commandToRun);
  2714 	return 255;
  2717     /*  if -L is given raw, ascii or dump mode, it must be for only one cert. */
  2718     if (certutil.commands[cmd_ListCerts].activated &&
  2719         (certutil.options[opt_ASCIIForIO].activated ||
  2720          certutil.options[opt_DumpExtensionValue].activated ||
  2721          certutil.options[opt_BinaryDER].activated) &&
  2722         !certutil.options[opt_Nickname].activated) {
  2723 	PR_fprintf(PR_STDERR, 
  2724 	        "%s: nickname is required to dump cert in raw or ascii mode.\n",
  2725 	           progName);
  2726 	return 255;
  2729     /*  -L can only be in (raw || ascii).  */
  2730     if (certutil.commands[cmd_ListCerts].activated &&
  2731         certutil.options[opt_ASCIIForIO].activated &&
  2732         certutil.options[opt_BinaryDER].activated) {
  2733 	PR_fprintf(PR_STDERR, 
  2734 	           "%s: cannot specify both -r and -a when dumping cert.\n",
  2735 	           progName);
  2736 	return 255;
  2739     /*  If making a cert request, need a subject.  */
  2740     if ((certutil.commands[cmd_CertReq].activated ||
  2741          certutil.commands[cmd_CreateAndAddCert].activated) &&
  2742         !(certutil.options[opt_Subject].activated || keysource)) {
  2743 	PR_fprintf(PR_STDERR, 
  2744 	           "%s -%c: subject is required to create a cert request.\n",
  2745 	           progName, commandToRun);
  2746 	return 255;
  2749     /*  If making a cert, need a serial number.  */
  2750     if ((certutil.commands[cmd_CreateNewCert].activated ||
  2751          certutil.commands[cmd_CreateAndAddCert].activated) &&
  2752          !certutil.options[opt_SerialNumber].activated) {
  2753 	/*  Make a default serial number from the current time.  */
  2754 	PRTime now = PR_Now();
  2755 	LL_USHR(now, now, 19);
  2756 	LL_L2UI(serialNumber, now);
  2759     /*  Validation needs the usage to validate for.  */
  2760     if (certutil.commands[cmd_CheckCertValidity].activated &&
  2761         !certutil.options[opt_Usage].activated) {
  2762 	PR_fprintf(PR_STDERR, 
  2763 	           "%s -V: specify a usage to validate the cert for (-u).\n",
  2764 	           progName);
  2765 	return 255;
  2768     /* Upgrade/Merge needs a source database and a upgrade id. */
  2769     if (certutil.commands[cmd_UpgradeMerge].activated &&
  2770         !(certutil.options[opt_SourceDir].activated &&
  2771           certutil.options[opt_UpgradeID].activated)) {
  2773 	PR_fprintf(PR_STDERR, 
  2774 	           "%s --upgrade-merge: specify an upgrade database directory "
  2775 		   "(--source-dir) and\n"
  2776                    "   an upgrade ID (--upgrade-id).\n",
  2777 	           progName);
  2778 	return 255;
  2781     /* Merge needs a source database */
  2782     if (certutil.commands[cmd_Merge].activated &&
  2783         !certutil.options[opt_SourceDir].activated) {
  2786 	PR_fprintf(PR_STDERR, 
  2787 	           "%s --merge: specify an source database directory "
  2788 		   "(--source-dir)\n",
  2789 	           progName);
  2790 	return 255;
  2794     /*  To make a cert, need either a issuer or to self-sign it.  */
  2795     if (certutil.commands[cmd_CreateAndAddCert].activated &&
  2796 	!(certutil.options[opt_IssuerName].activated ||
  2797           certutil.options[opt_SelfSign].activated)) {
  2798 	PR_fprintf(PR_STDERR,
  2799 	           "%s -S: must specify issuer (-c) or self-sign (-x).\n",
  2800 	           progName);
  2801 	return 255;
  2804     /*  Using slotname == NULL for listing keys and certs on all slots, 
  2805      *  but only that. */
  2806     if (!(certutil.commands[cmd_ListKeys].activated ||
  2807 	  certutil.commands[cmd_DumpChain].activated ||
  2808     	  certutil.commands[cmd_ListCerts].activated) && slotname == NULL) {
  2809 	PR_fprintf(PR_STDERR,
  2810 	           "%s -%c: cannot use \"-h all\" for this command.\n",
  2811 	           progName, commandToRun);
  2812 	return 255;
  2815     /*  Using keytype == nullKey for list all key types, but only that.  */
  2816     if (!certutil.commands[cmd_ListKeys].activated && keytype == nullKey) {
  2817 	PR_fprintf(PR_STDERR,
  2818 	           "%s -%c: cannot use \"-k all\" for this command.\n",
  2819 	           progName, commandToRun);
  2820 	return 255;
  2823     /*  Open the input file.  */
  2824     if (certutil.options[opt_InputFile].activated) {
  2825 	inFile = PR_Open(certutil.options[opt_InputFile].arg, PR_RDONLY, 0);
  2826 	if (!inFile) {
  2827 	    PR_fprintf(PR_STDERR,
  2828 	               "%s:  unable to open \"%s\" for reading (%ld, %ld).\n",
  2829 	               progName, certutil.options[opt_InputFile].arg,
  2830 	               PR_GetError(), PR_GetOSError());
  2831 	    return 255;
  2835     /*  Open the output file.  */
  2836     if (certutil.options[opt_OutputFile].activated) {
  2837 	outFile = PR_Open(certutil.options[opt_OutputFile].arg, 
  2838                           PR_CREATE_FILE | PR_RDWR | PR_TRUNCATE, 00660);
  2839 	if (!outFile) {
  2840 	    PR_fprintf(PR_STDERR,
  2841 	               "%s:  unable to open \"%s\" for writing (%ld, %ld).\n",
  2842 	               progName, certutil.options[opt_OutputFile].arg,
  2843 	               PR_GetError(), PR_GetOSError());
  2844 	    return 255;
  2848     name = SECU_GetOptionArg(&certutil, opt_Nickname);
  2849     email = SECU_GetOptionArg(&certutil, opt_Emailaddress);
  2851     PK11_SetPasswordFunc(SECU_GetModulePassword);
  2853     if (PR_TRUE == initialize) {
  2854         /*  Initialize NSPR and NSS.  */
  2855         PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
  2856 	if (!certutil.commands[cmd_UpgradeMerge].activated) {
  2857             rv = NSS_Initialize(SECU_ConfigDirectory(NULL), 
  2858 			    certPrefix, certPrefix,
  2859                             "secmod.db", readOnly ? NSS_INIT_READONLY: 0);
  2860 	} else {
  2861             rv = NSS_InitWithMerge(SECU_ConfigDirectory(NULL), 
  2862 			    certPrefix, certPrefix, "secmod.db",
  2863 			    sourceDir, srcCertPrefix, srcCertPrefix, 
  2864 			    upgradeID, upgradeTokenName,
  2865                             readOnly ? NSS_INIT_READONLY: 0);
  2867         if (rv != SECSuccess) {
  2868 	    SECU_PrintPRandOSError(progName);
  2869 	    rv = SECFailure;
  2870 	    goto shutdown;
  2872         initialized = PR_TRUE;
  2873     	SECU_RegisterDynamicOids();
  2875     certHandle = CERT_GetDefaultCertDB();
  2877     if (certutil.commands[cmd_Version].activated) {
  2878 	printf("Certificate database content version: command not implemented.\n");
  2881     if (PL_strcmp(slotname, "internal") == 0)
  2882 	slot = PK11_GetInternalKeySlot();
  2883     else if (slotname != NULL)
  2884 	slot = PK11_FindSlotByName(slotname);
  2886     if ( !slot && (certutil.commands[cmd_NewDBs].activated ||
  2887          certutil.commands[cmd_ModifyCertTrust].activated  || 
  2888          certutil.commands[cmd_ChangePassword].activated   ||
  2889          certutil.commands[cmd_TokenReset].activated       ||
  2890          certutil.commands[cmd_CreateAndAddCert].activated ||
  2891          certutil.commands[cmd_AddCert].activated          ||
  2892          certutil.commands[cmd_Merge].activated          ||
  2893          certutil.commands[cmd_UpgradeMerge].activated          ||
  2894          certutil.commands[cmd_AddEmailCert].activated)) {
  2896          SECU_PrintError(progName, "could not find the slot %s",slotname);
  2897          rv = SECFailure;
  2898          goto shutdown;
  2901     /*  If creating new database, initialize the password.  */
  2902     if (certutil.commands[cmd_NewDBs].activated) {
  2903 	if(certutil.options[opt_EmptyPassword].activated && (PK11_NeedUserInit(slot)))
  2904 	    PK11_InitPin(slot, (char*)NULL, "");
  2905 	else
  2906 	    SECU_ChangePW2(slot, 0, 0, certutil.options[opt_PasswordFile].arg,
  2907 				certutil.options[opt_NewPasswordFile].arg);
  2910     /* walk through the upgrade merge if necessary.
  2911      * This option is more to test what some applications will want to do
  2912      * to do an automatic upgrade. The --merge command is more useful for
  2913      * the general case where 2 database need to be merged together.
  2914      */
  2915     if (certutil.commands[cmd_UpgradeMerge].activated) {
  2916 	if (*upgradeTokenName == 0) {
  2917 	    upgradeTokenName = upgradeID;
  2919 	if (!PK11_IsInternal(slot)) {
  2920 	    fprintf(stderr, "Only internal DB's can be upgraded\n");
  2921 	    rv = SECSuccess;
  2922 	    goto shutdown;
  2924 	if (!PK11_IsRemovable(slot)) {
  2925 	    printf("database already upgraded.\n");
  2926 	    rv = SECSuccess;
  2927 	    goto shutdown;
  2929 	if (!PK11_NeedLogin(slot)) {
  2930 	    printf("upgrade complete!\n");
  2931 	    rv = SECSuccess;
  2932 	    goto shutdown;
  2934 	/* authenticate to the old DB if necessary */
  2935 	if (PORT_Strcmp(PK11_GetTokenName(slot), upgradeTokenName) ==  0) {
  2936 	    /* if we need a password, supply it. This will be the password
  2937 	     * for the old database */
  2938 	    rv = PK11_Authenticate(slot, PR_FALSE, &pwdata2);
  2939 	    if (rv != SECSuccess) {
  2940          	SECU_PrintError(progName, "Could not get password for %s",
  2941 				upgradeTokenName);
  2942 		goto shutdown;
  2944 	    /* 
  2945 	     * if we succeeded above, but still aren't logged in, that means
  2946 	     * we just supplied the password for the old database. We may
  2947 	     * need the password for the new database. NSS will automatically
  2948 	     * change the token names at this point
  2949 	     */
  2950 	    if (PK11_IsLoggedIn(slot, &pwdata)) {
  2951 		printf("upgrade complete!\n");
  2952 		rv = SECSuccess;
  2953 		goto shutdown;
  2957 	/* call PK11_IsPresent to update our cached token information */
  2958 	if (!PK11_IsPresent(slot)) {
  2959 	    /* this shouldn't happen. We call isPresent to force a token
  2960 	     * info update */
  2961 	    fprintf(stderr, "upgrade/merge internal error\n");
  2962 	    rv = SECFailure;
  2963 	    goto shutdown;
  2966 	/* the token is now set to the state of the source database,
  2967 	 * if we need a password for it, PK11_Authenticate will 
  2968 	 * automatically prompt us */
  2969 	rv = PK11_Authenticate(slot, PR_FALSE, &pwdata);
  2970 	if (rv == SECSuccess) {
  2971 	    printf("upgrade complete!\n");
  2972 	} else {
  2973             SECU_PrintError(progName, "Could not get password for %s",
  2974 				PK11_GetTokenName(slot));
  2976 	goto shutdown;
  2979     /*
  2980      * merge 2 databases.
  2981      */
  2982     if (certutil.commands[cmd_Merge].activated) {
  2983 	PK11SlotInfo *sourceSlot = NULL;
  2984 	PK11MergeLog *log;
  2985 	char *modspec = PR_smprintf(
  2986 		"configDir='%s' certPrefix='%s' tokenDescription='%s'",
  2987 		sourceDir, srcCertPrefix, 
  2988 		*upgradeTokenName ? upgradeTokenName : "Source Database");
  2990 	if (!modspec) {
  2991 	    rv = SECFailure;
  2992 	    goto shutdown;
  2995 	sourceSlot = SECMOD_OpenUserDB(modspec);
  2996 	PR_smprintf_free(modspec);
  2997 	if (!sourceSlot) {
  2998 	    SECU_PrintError(progName, "couldn't open source database");
  2999 	    rv = SECFailure;
  3000 	    goto shutdown;
  3003 	rv = PK11_Authenticate(slot, PR_FALSE, &pwdata);
  3004 	if (rv != SECSuccess) {
  3005 	    SECU_PrintError(progName, "Couldn't get password for %s",
  3006 					PK11_GetTokenName(slot));
  3007 	    goto merge_fail;
  3010 	rv = PK11_Authenticate(sourceSlot, PR_FALSE, &pwdata2);
  3011 	if (rv != SECSuccess) {
  3012 	    SECU_PrintError(progName, "Couldn't get password for %s",
  3013 					PK11_GetTokenName(sourceSlot));
  3014 	    goto merge_fail;
  3017 	log = PK11_CreateMergeLog();
  3018 	if (!log) {
  3019 	    rv = SECFailure;
  3020 	    SECU_PrintError(progName, "couldn't create error log");
  3021 	    goto merge_fail;
  3024 	rv = PK11_MergeTokens(slot, sourceSlot, log, &pwdata, &pwdata2);
  3025 	if (rv != SECSuccess) {
  3026 	    DumpMergeLog(progName, log);
  3028 	PK11_DestroyMergeLog(log);
  3030 merge_fail:
  3031 	SECMOD_CloseUserDB(sourceSlot);
  3032 	PK11_FreeSlot(sourceSlot);
  3033 	goto shutdown;
  3036     /* The following 8 options are mutually exclusive with all others. */
  3038     /*  List certs (-L)  */
  3039     if (certutil.commands[cmd_ListCerts].activated) {
  3040 	if (certutil.options[opt_DumpExtensionValue].activated) {
  3041 	    const char *oid_str;
  3042 	    SECItem oid_item;
  3043             SECStatus srv;
  3044 	    oid_item.data = NULL;
  3045 	    oid_item.len = 0;
  3046 	    oid_str = certutil.options[opt_DumpExtensionValue].arg;
  3047 	    srv = GetOidFromString(NULL, &oid_item, oid_str, strlen(oid_str));
  3048 	    if (srv != SECSuccess) {
  3049          	SECU_PrintError(progName, "malformed extension OID %s",
  3050 				oid_str);
  3051 		goto shutdown;
  3053 	    rv = ListCerts(certHandle, name, email, slot,
  3054 			   PR_TRUE /*binary*/, PR_FALSE /*ascii*/,
  3055 			   &oid_item,
  3056 			   outFile, &pwdata);
  3057 	} else {
  3058 	    rv = ListCerts(certHandle, name, email, slot,
  3059 			   certutil.options[opt_BinaryDER].activated,
  3060 			   certutil.options[opt_ASCIIForIO].activated,
  3061 			   NULL, outFile, &pwdata);
  3063 	goto shutdown;
  3065     if (certutil.commands[cmd_DumpChain].activated) {
  3066 	rv = DumpChain(certHandle, name,
  3067                        certutil.options[opt_ASCIIForIO].activated);
  3068 	goto shutdown;
  3070     /*  XXX needs work  */
  3071     /*  List keys (-K)  */
  3072     if (certutil.commands[cmd_ListKeys].activated) {
  3073 	rv = ListKeys(slot, name, 0 /*keyindex*/, keytype, PR_FALSE /*dopriv*/,
  3074 	              &pwdata);
  3075 	goto shutdown;
  3077     /*  List modules (-U)  */
  3078     if (certutil.commands[cmd_ListModules].activated) {
  3079 	rv = ListModules();
  3080 	goto shutdown;
  3082     /*  Delete cert (-D)  */
  3083     if (certutil.commands[cmd_DeleteCert].activated) {
  3084 	rv = DeleteCert(certHandle, name);
  3085 	goto shutdown;
  3087     /*  Delete key (-F)  */
  3088     if (certutil.commands[cmd_DeleteKey].activated) {
  3089 	rv = DeleteKey(name, &pwdata);
  3090 	goto shutdown;
  3092     /*  Modify trust attribute for cert (-M)  */
  3093     if (certutil.commands[cmd_ModifyCertTrust].activated) {
  3094 	rv = ChangeTrustAttributes(certHandle, slot, name, 
  3095 	                           certutil.options[opt_Trust].arg, &pwdata);
  3096 	goto shutdown;
  3098     /*  Change key db password (-W) (future - change pw to slot?)  */
  3099     if (certutil.commands[cmd_ChangePassword].activated) {
  3100 	rv = SECU_ChangePW2(slot, 0, 0, certutil.options[opt_PasswordFile].arg,
  3101 				certutil.options[opt_NewPasswordFile].arg);
  3102 	goto shutdown;
  3104     /*  Reset the a token */
  3105     if (certutil.commands[cmd_TokenReset].activated) {
  3106 	char *sso_pass = "";
  3108 	if (certutil.options[opt_SSOPass].activated) {
  3109 	    sso_pass = certutil.options[opt_SSOPass].arg;
  3111 	rv = PK11_ResetToken(slot,sso_pass);
  3113 	goto shutdown;
  3115     /*  Check cert validity against current time (-V)  */
  3116     if (certutil.commands[cmd_CheckCertValidity].activated) {
  3117 	/* XXX temporary hack for fips - must log in to get priv key */
  3118 	if (certutil.options[opt_VerifySig].activated) {
  3119 	    if (slot && PK11_NeedLogin(slot)) {
  3120                 SECStatus newrv = PK11_Authenticate(slot, PR_TRUE, &pwdata);
  3121                 if (newrv != SECSuccess) {
  3122                     SECU_PrintError(progName, "could not authenticate to token %s.",
  3123                                     PK11_GetTokenName(slot));
  3124                     goto shutdown;
  3128 	rv = ValidateCert(certHandle, name, 
  3129 	                  certutil.options[opt_ValidityTime].arg,
  3130 			  certutil.options[opt_Usage].arg,
  3131 			  certutil.options[opt_VerifySig].activated,
  3132 			  certutil.options[opt_DetailedInfo].activated,
  3133 			  certutil.options[opt_ASCIIForIO].activated,
  3134 	                  &pwdata);
  3135 	if (rv != SECSuccess && PR_GetError() == SEC_ERROR_INVALID_ARGS)
  3136             SECU_PrintError(progName, "validation failed");
  3137 	goto shutdown;
  3140     /*
  3141      *  Key generation
  3142      */
  3144     /*  These commands may require keygen.  */
  3145     if (certutil.commands[cmd_CertReq].activated ||
  3146         certutil.commands[cmd_CreateAndAddCert].activated ||
  3147 	certutil.commands[cmd_GenKeyPair].activated) {
  3148 	if (keysource) {
  3149 	    CERTCertificate *keycert;
  3150 	    keycert = CERT_FindCertByNicknameOrEmailAddr(certHandle, keysource);
  3151 	    if (!keycert) {
  3152 		keycert = PK11_FindCertFromNickname(keysource, NULL);
  3153 		if (!keycert) {
  3154 		    SECU_PrintError(progName,
  3155 			    "%s is neither a key-type nor a nickname", keysource);
  3156 		    return SECFailure;
  3159 	    privkey = PK11_FindKeyByDERCert(slot, keycert, &pwdata);
  3160 	    if (privkey)
  3161 		pubkey = CERT_ExtractPublicKey(keycert);
  3162 	    if (!pubkey) {
  3163 		SECU_PrintError(progName,
  3164 				"Could not get keys from cert %s", keysource);
  3165 		rv = SECFailure;
  3166 		CERT_DestroyCertificate(keycert);
  3167 		goto shutdown;
  3169 	    keytype = privkey->keyType;
  3170 	    /* On CertReq for renewal if no subject has been
  3171 	     * specified obtain it from the certificate. 
  3172 	     */
  3173 	    if (certutil.commands[cmd_CertReq].activated && !subject) {
  3174 	        subject = CERT_AsciiToName(keycert->subjectName);
  3175 	        if (!subject) {
  3176 	            SECU_PrintError(progName,
  3177 			"Could not get subject from certificate %s", keysource);
  3178 	            CERT_DestroyCertificate(keycert);
  3179 	            rv = SECFailure;
  3180 	            goto shutdown;
  3183 	    CERT_DestroyCertificate(keycert);
  3184 	} else {
  3185 	    privkey = 
  3186 		CERTUTIL_GeneratePrivateKey(keytype, slot, keysize,
  3187 					    publicExponent, 
  3188 					    certutil.options[opt_NoiseFile].arg,
  3189 					    &pubkey, 
  3190 					    certutil.options[opt_PQGFile].arg,
  3191 					    keyAttrFlags,
  3192 					    keyOpFlagsOn,
  3193 					    keyOpFlagsOff,
  3194 					    &pwdata);
  3195 	    if (privkey == NULL) {
  3196 		SECU_PrintError(progName, "unable to generate key(s)\n");
  3197 		rv = SECFailure;
  3198 		goto shutdown;
  3201 	privkey->wincx = &pwdata;
  3202 	PORT_Assert(pubkey != NULL);
  3204 	/*  If all that was needed was keygen, exit.  */
  3205 	if (certutil.commands[cmd_GenKeyPair].activated) {
  3206 	    rv = SECSuccess;
  3207 	    goto shutdown;
  3211     /* If we need a list of extensions convert the flags into list format */
  3212     if (certutil.commands[cmd_CertReq].activated ||
  3213         certutil.commands[cmd_CreateAndAddCert].activated ||
  3214         certutil.commands[cmd_CreateNewCert].activated) {
  3215         certutil_extns[ext_keyUsage].activated =
  3216             certutil.options[opt_AddCmdKeyUsageExt].activated;
  3217         if (!certutil_extns[ext_keyUsage].activated) {
  3218             certutil_extns[ext_keyUsage].activated =
  3219                 certutil.options[opt_AddKeyUsageExt].activated;
  3220         } else {
  3221             certutil_extns[ext_keyUsage].arg =
  3222                 certutil.options[opt_AddCmdKeyUsageExt].arg;
  3224         certutil_extns[ext_basicConstraint].activated =
  3225 				certutil.options[opt_AddBasicConstraintExt].activated;
  3226         certutil_extns[ext_nameConstraints].activated =
  3227                                 certutil.options[opt_AddNameConstraintsExt].activated;
  3228         certutil_extns[ext_authorityKeyID].activated =
  3229 				certutil.options[opt_AddAuthorityKeyIDExt].activated;
  3230         certutil_extns[ext_subjectKeyID].activated =
  3231 				certutil.options[opt_AddSubjectKeyIDExt].activated;
  3232         certutil_extns[ext_CRLDistPts].activated =
  3233 				certutil.options[opt_AddCRLDistPtsExt].activated;
  3234         certutil_extns[ext_NSCertType].activated =
  3235             certutil.options[opt_AddCmdNSCertTypeExt].activated;
  3236         if (!certutil_extns[ext_NSCertType].activated) {
  3237             certutil_extns[ext_NSCertType].activated =
  3238                 certutil.options[opt_AddNSCertTypeExt].activated;
  3239         } else {
  3240             certutil_extns[ext_NSCertType].arg =
  3241                 certutil.options[opt_AddCmdNSCertTypeExt].arg;
  3244         certutil_extns[ext_extKeyUsage].activated =
  3245             certutil.options[opt_AddCmdExtKeyUsageExt].activated;
  3246         if (!certutil_extns[ext_extKeyUsage].activated) {
  3247             certutil_extns[ext_extKeyUsage].activated =
  3248                 certutil.options[opt_AddExtKeyUsageExt].activated;
  3249         } else {
  3250             certutil_extns[ext_extKeyUsage].arg =
  3251                 certutil.options[opt_AddCmdExtKeyUsageExt].arg;
  3253         certutil_extns[ext_subjectAltName].activated =
  3254                 certutil.options[opt_AddSubjectAltNameExt].activated;
  3255         if (certutil_extns[ext_subjectAltName].activated) {
  3256             certutil_extns[ext_subjectAltName].arg =
  3257                 certutil.options[opt_AddSubjectAltNameExt].arg;
  3260         certutil_extns[ext_authInfoAcc].activated =
  3261 				certutil.options[opt_AddAuthInfoAccExt].activated;
  3262         certutil_extns[ext_subjInfoAcc].activated =
  3263 				certutil.options[opt_AddSubjInfoAccExt].activated;
  3264         certutil_extns[ext_certPolicies].activated =
  3265 				certutil.options[opt_AddCertPoliciesExt].activated;
  3266         certutil_extns[ext_policyMappings].activated =
  3267 				certutil.options[opt_AddPolicyMapExt].activated;
  3268         certutil_extns[ext_policyConstr].activated =
  3269 				certutil.options[opt_AddPolicyConstrExt].activated;
  3270         certutil_extns[ext_inhibitAnyPolicy].activated =
  3271 				certutil.options[opt_AddInhibAnyExt].activated;
  3274     /* -A -C or -E    Read inFile */
  3275     if (certutil.commands[cmd_CreateNewCert].activated ||
  3276 	certutil.commands[cmd_AddCert].activated ||
  3277 	certutil.commands[cmd_AddEmailCert].activated) {
  3278 	PRBool isCreate = certutil.commands[cmd_CreateNewCert].activated;
  3279 	rv = SECU_ReadDERFromFile(isCreate ? &certReqDER : &certDER, inFile,
  3280 				  certutil.options[opt_ASCIIForIO].activated,
  3281 				  PR_TRUE);
  3282 	if (rv)
  3283 	    goto shutdown;
  3286     /*
  3287      *  Certificate request
  3288      */
  3290     /*  Make a cert request (-R).  */
  3291     if (certutil.commands[cmd_CertReq].activated) {
  3292 	rv = CertReq(privkey, pubkey, keytype, hashAlgTag, subject,
  3293 	             certutil.options[opt_PhoneNumber].arg,
  3294 	             certutil.options[opt_ASCIIForIO].activated,
  3295 		     certutil.options[opt_ExtendedEmailAddrs].arg,
  3296 		     certutil.options[opt_ExtendedDNSNames].arg,
  3297                      certutil_extns,
  3298 		     (certutil.options[opt_GenericExtensions].activated ?
  3299 		         certutil.options[opt_GenericExtensions].arg : NULL),
  3300                      &certReqDER);
  3301 	if (rv)
  3302 	    goto shutdown;
  3303 	privkey->wincx = &pwdata;
  3306     /*
  3307      *  Certificate creation
  3308      */
  3310     /*  If making and adding a cert, create a cert request file first without
  3311      *  any extensions, then load it with the command line extensions
  3312      *  and output the cert to another file.
  3313      */
  3314     if (certutil.commands[cmd_CreateAndAddCert].activated) {
  3315 	static certutilExtnList nullextnlist = {{PR_FALSE, NULL}};
  3316 	rv = CertReq(privkey, pubkey, keytype, hashAlgTag, subject,
  3317 	             certutil.options[opt_PhoneNumber].arg,
  3318 		     PR_FALSE, /* do not BASE64-encode regardless of -a option */
  3319 		     NULL,
  3320 		     NULL,
  3321                      nullextnlist,
  3322 		     (certutil.options[opt_GenericExtensions].activated ?
  3323 		         certutil.options[opt_GenericExtensions].arg : NULL),
  3324 		     &certReqDER);
  3325 	if (rv) 
  3326 	    goto shutdown;
  3327 	privkey->wincx = &pwdata;
  3330     /*  Create a certificate (-C or -S).  */
  3331     if (certutil.commands[cmd_CreateAndAddCert].activated ||
  3332          certutil.commands[cmd_CreateNewCert].activated) {
  3333 	rv = CreateCert(certHandle, slot,
  3334 	                certutil.options[opt_IssuerName].arg,
  3335 			&certReqDER, &privkey, &pwdata, hashAlgTag,
  3336 	                serialNumber, warpmonths, validityMonths,
  3337 		        certutil.options[opt_ExtendedEmailAddrs].arg,
  3338 		        certutil.options[opt_ExtendedDNSNames].arg,
  3339 		        certutil.options[opt_ASCIIForIO].activated &&
  3340 			    certutil.commands[cmd_CreateNewCert].activated,
  3341 	                certutil.options[opt_SelfSign].activated,
  3342 	                certutil_extns,
  3343 			(certutil.options[opt_GenericExtensions].activated ?
  3344 			    certutil.options[opt_GenericExtensions].arg : NULL),
  3345                         certVersion,
  3346 			&certDER);
  3347 	if (rv) 
  3348 	    goto shutdown;
  3351     /* 
  3352      * Adding a cert to the database (or slot)
  3353      */
  3355     /* -A -E or -S    Add the cert to the DB */
  3356     if (certutil.commands[cmd_CreateAndAddCert].activated ||
  3357          certutil.commands[cmd_AddCert].activated ||
  3358 	 certutil.commands[cmd_AddEmailCert].activated) {
  3359 	if (strstr(certutil.options[opt_Trust].arg, "u")) {
  3360 	    fprintf(stderr, "Notice: Trust flag u is set automatically if the "
  3361 			    "private key is present.\n");
  3363 	rv = AddCert(slot, certHandle, name, 
  3364 	             certutil.options[opt_Trust].arg,
  3365 	             &certDER,
  3366 	             certutil.commands[cmd_AddEmailCert].activated,&pwdata);
  3367 	if (rv) 
  3368 	    goto shutdown;
  3371     if (certutil.commands[cmd_CertReq].activated ||
  3372 	certutil.commands[cmd_CreateNewCert].activated) {
  3373 	SECItem * item = certutil.commands[cmd_CertReq].activated ? &certReqDER
  3374 								  : &certDER;
  3375 	PRInt32 written = PR_Write(outFile, item->data, item->len);
  3376 	if (written < 0 || (PRUint32) written != item->len) {
  3377 	    rv = SECFailure;
  3381 shutdown:
  3382     if (slot) {
  3383 	PK11_FreeSlot(slot);
  3385     if (privkey) {
  3386 	SECKEY_DestroyPrivateKey(privkey);
  3388     if (pubkey) {
  3389 	SECKEY_DestroyPublicKey(pubkey);
  3391     if (subject) {
  3392 	CERT_DestroyName(subject);
  3394     if (name) {
  3395 	PL_strfree(name);
  3397     if (inFile && inFile != PR_STDIN) {
  3398 	PR_Close(inFile);
  3400     if (outFile && outFile != PR_STDOUT) {
  3401 	PR_Close(outFile);
  3403     SECITEM_FreeItem(&certReqDER, PR_FALSE);
  3404     SECITEM_FreeItem(&certDER, PR_FALSE);
  3405     if (pwdata.data && pwdata.source == PW_PLAINTEXT) {
  3406 	/* Allocated by a PL_strdup call in SECU_GetModulePassword. */
  3407 	PL_strfree(pwdata.data);
  3410     /* Open the batch command file.
  3412      * - If -B <command line> option is specified, the contents in the
  3413      * command file will be interpreted as subsequent certutil
  3414      * commands to be executed in the current certutil process
  3415      * context after the current certutil command has been executed.
  3416      * - Each line in the command file consists of the command
  3417      * line arguments for certutil.
  3418      * - The -d <configdir> option will be ignored if specified in the
  3419      * command file.
  3420      * - Quoting with double quote characters ("...") is supported
  3421      * to allow white space in a command line argument.  The
  3422      * double quote character cannot be escaped and quoting cannot
  3423      * be nested in this version.
  3424      * - each line in the batch file is limited to 512 characters
  3425     */
  3427     if ((SECSuccess == rv) && certutil.commands[cmd_Batch].activated) {
  3428 	FILE* batchFile = NULL;
  3429         char *nextcommand = NULL;
  3430 	PRInt32 cmd_len = 0, buf_size = 0;
  3431 	static const int increment = 512;
  3433         if (!certutil.options[opt_InputFile].activated ||
  3434             !certutil.options[opt_InputFile].arg) {
  3435 	    PR_fprintf(PR_STDERR,
  3436 	               "%s:  no batch input file specified.\n",
  3437 	               progName);
  3438 	    return 255;
  3440         batchFile = fopen(certutil.options[opt_InputFile].arg, "r");
  3441         if (!batchFile) {
  3442 	    PR_fprintf(PR_STDERR,
  3443 	               "%s:  unable to open \"%s\" for reading (%ld, %ld).\n",
  3444 	               progName, certutil.options[opt_InputFile].arg,
  3445 	               PR_GetError(), PR_GetOSError());
  3446 	    return 255;
  3448         /* read and execute command-lines in a loop */
  3449         while ( SECSuccess == rv ) {
  3450             PRBool invalid = PR_FALSE;
  3451             int newargc = 2;
  3452             char* space = NULL;
  3453             char* nextarg = NULL;
  3454             char** newargv = NULL;
  3455             char* crlf;
  3457 	    if (cmd_len + increment > buf_size) {
  3458 	        char * new_buf;
  3459 		buf_size += increment;
  3460 	        new_buf = PORT_Realloc(nextcommand, buf_size);
  3461 		if (!new_buf) {
  3462 		    PR_fprintf(PR_STDERR, "%s: PORT_Realloc(%ld) failed\n",
  3463 			       progName, buf_size);
  3464 		    break;
  3466 		nextcommand = new_buf;
  3467 		nextcommand[cmd_len] = '\0';
  3469 	    if (!fgets(nextcommand + cmd_len, buf_size - cmd_len, batchFile)) {
  3470 		break;
  3472             crlf = PORT_Strrchr(nextcommand, '\n');
  3473             if (crlf) {
  3474                 *crlf = '\0';
  3476 	    cmd_len = strlen(nextcommand);
  3477 	    if (cmd_len && nextcommand[cmd_len - 1] == '\\') {
  3478 	        nextcommand[--cmd_len] = '\0';
  3479 		continue;
  3482             /* we now need to split the command into argc / argv format */
  3484             newargv = PORT_Alloc(sizeof(char*)*(newargc+1));
  3485             newargv[0] = progName;
  3486             newargv[1] = nextcommand;
  3487             nextarg = nextcommand;
  3488             while ((space = PORT_Strpbrk(nextarg, " \f\n\r\t\v")) ) {
  3489                 while (isspace(*space) ) {
  3490                     *space = '\0';
  3491                     space ++;
  3493                 if (*space == '\0') {
  3494                     break;
  3495                 } else if (*space != '\"') {
  3496                     nextarg = space;
  3497                 } else {
  3498                     char* closingquote = strchr(space+1, '\"');
  3499                     if (closingquote) {
  3500                         *closingquote = '\0';
  3501                         space++;
  3502                         nextarg = closingquote+1;
  3503                     } else {
  3504                         invalid = PR_TRUE;
  3505                         nextarg = space;
  3508                 newargc++;
  3509                 newargv = PORT_Realloc(newargv, sizeof(char*)*(newargc+1));
  3510                 newargv[newargc-1] = space;
  3512             newargv[newargc] = NULL;
  3514             /* invoke next command */
  3515             if (PR_TRUE == invalid) {
  3516                 PR_fprintf(PR_STDERR, "Missing closing quote in batch command :\n%s\nNot executed.\n",
  3517                            nextcommand);
  3518                 rv = SECFailure;
  3519             } else {
  3520                 if (0 != certutil_main(newargc, newargv, PR_FALSE) )
  3521                     rv = SECFailure;
  3523             PORT_Free(newargv);
  3524 	    cmd_len = 0;
  3525 	    nextcommand[0] = '\0';
  3527 	PORT_Free(nextcommand);
  3528         fclose(batchFile);
  3531     if ((initialized == PR_TRUE) && NSS_Shutdown() != SECSuccess) {
  3532         exit(1);
  3534     if (rv == SECSuccess) {
  3535 	return 0;
  3536     } else {
  3537 	return 255;
  3541 int
  3542 main(int argc, char **argv)
  3544     int rv = certutil_main(argc, argv, PR_TRUE);
  3545     PL_ArenaFinish();
  3546     PR_Cleanup();
  3547     return rv;

mercurial