nss: import at 3.0.1 beta 1
[mozilla-nss.git] / security / nss / cmd / certutil / certutil.c
blob20ec068c92637807cf2b1eb68c7c305dad4c92f4
1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
12 * License.
14 * The Original Code is the Netscape security libraries.
16 * The Initial Developer of the Original Code is
17 * Netscape Communications Corporation.
18 * Portions created by the Initial Developer are Copyright (C) 1994-2000
19 * the Initial Developer. All Rights Reserved.
21 * Contributor(s):
22 * Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
24 * Alternatively, the contents of this file may be used under the terms of
25 * either the GNU General Public License Version 2 or later (the "GPL"), or
26 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
39 ** certutil.c
41 ** utility for managing certificates and the cert database
44 #include <stdio.h>
45 #include <string.h>
46 #include <stdlib.h>
48 #if defined(WIN32)
49 #include "fcntl.h"
50 #include "io.h"
51 #endif
53 #include "secutil.h"
55 #if defined(XP_UNIX)
56 #include <unistd.h>
57 #endif
59 #include "nspr.h"
60 #include "prtypes.h"
61 #include "prtime.h"
62 #include "prlong.h"
64 #include "pk11func.h"
65 #include "secasn1.h"
66 #include "cert.h"
67 #include "cryptohi.h"
68 #include "secoid.h"
69 #include "certdb.h"
70 #include "nss.h"
71 #include "certutil.h"
73 #define MIN_KEY_BITS 512
74 /* MAX_KEY_BITS should agree with MAX_RSA_MODULUS in freebl */
75 #define MAX_KEY_BITS 8192
76 #define DEFAULT_KEY_BITS 1024
78 #define GEN_BREAK(e) rv=e; break;
80 char *progName;
82 static CERTCertificateRequest *
83 GetCertRequest(PRFileDesc *inFile, PRBool ascii)
85 CERTCertificateRequest *certReq = NULL;
86 CERTSignedData signedData;
87 PRArenaPool *arena = NULL;
88 SECItem reqDER;
89 SECStatus rv;
91 reqDER.data = NULL;
92 do {
93 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
94 if (arena == NULL) {
95 GEN_BREAK (SECFailure);
98 rv = SECU_ReadDERFromFile(&reqDER, inFile, ascii);
99 if (rv) {
100 break;
102 certReq = (CERTCertificateRequest*) PORT_ArenaZAlloc
103 (arena, sizeof(CERTCertificateRequest));
104 if (!certReq) {
105 GEN_BREAK(SECFailure);
107 certReq->arena = arena;
109 /* Since cert request is a signed data, must decode to get the inner
110 data
112 PORT_Memset(&signedData, 0, sizeof(signedData));
113 rv = SEC_ASN1DecodeItem(arena, &signedData,
114 SEC_ASN1_GET(CERT_SignedDataTemplate), &reqDER);
115 if (rv) {
116 break;
118 rv = SEC_ASN1DecodeItem(arena, certReq,
119 SEC_ASN1_GET(CERT_CertificateRequestTemplate), &signedData.data);
120 if (rv) {
121 break;
123 rv = CERT_VerifySignedDataWithPublicKeyInfo(&signedData,
124 &certReq->subjectPublicKeyInfo, NULL /* wincx */);
125 } while (0);
127 if (reqDER.data) {
128 SECITEM_FreeItem(&reqDER, PR_FALSE);
131 if (rv) {
132 SECU_PrintError(progName, "bad certificate request\n");
133 if (arena) {
134 PORT_FreeArena(arena, PR_FALSE);
136 certReq = NULL;
139 return certReq;
142 static SECStatus
143 AddCert(PK11SlotInfo *slot, CERTCertDBHandle *handle, char *name, char *trusts,
144 PRFileDesc *inFile, PRBool ascii, PRBool emailcert, void *pwdata)
146 CERTCertTrust *trust = NULL;
147 CERTCertificate *cert = NULL;
148 SECItem certDER;
149 SECStatus rv;
151 certDER.data = NULL;
152 do {
153 /* Read in the entire file specified with the -i argument */
154 rv = SECU_ReadDERFromFile(&certDER, inFile, ascii);
155 if (rv != SECSuccess) {
156 SECU_PrintError(progName, "unable to read input file");
157 break;
160 /* Read in an ASCII cert and return a CERTCertificate */
161 cert = CERT_DecodeCertFromPackage((char *)certDER.data, certDER.len);
162 if (!cert) {
163 SECU_PrintError(progName, "could not obtain certificate from file");
164 GEN_BREAK(SECFailure);
167 /* Create a cert trust to pass to SEC_AddPermCertificate */
168 trust = (CERTCertTrust *)PORT_ZAlloc(sizeof(CERTCertTrust));
169 if (!trust) {
170 SECU_PrintError(progName, "unable to allocate cert trust");
171 GEN_BREAK(SECFailure);
174 rv = CERT_DecodeTrustString(trust, trusts);
175 if (rv) {
176 SECU_PrintError(progName, "unable to decode trust string");
177 GEN_BREAK(SECFailure);
180 if (PK11_IsFIPS() || !PK11_IsInternal(slot)) {
181 rv = PK11_Authenticate(slot, PR_TRUE, pwdata);
182 if (rv != SECSuccess) {
183 SECU_PrintError(progName, "could not authenticate to token %s.",
184 PK11_GetTokenName(slot));
185 GEN_BREAK(SECFailure);
189 rv = PK11_ImportCert(slot, cert, CK_INVALID_HANDLE, name, PR_FALSE);
190 if (rv != SECSuccess) {
191 SECU_PrintError(progName, "could not add certificate to token or database");
192 GEN_BREAK(SECFailure);
195 rv = CERT_ChangeCertTrust(handle, cert, trust);
196 if (rv != SECSuccess) {
197 if (PORT_GetError() == SEC_ERROR_TOKEN_NOT_LOGGED_IN) {
198 rv = PK11_Authenticate(slot, PR_TRUE, pwdata);
199 if (rv != SECSuccess) {
200 SECU_PrintError(progName, "could not authenticate to token %s.",
201 PK11_GetTokenName(slot));
202 GEN_BREAK(SECFailure);
204 rv = CERT_ChangeCertTrust(handle, cert, trust);
206 if (rv != SECSuccess) {
207 SECU_PrintError(progName,
208 "could not change trust on certificate");
209 GEN_BREAK(SECFailure);
213 if ( emailcert ) {
214 CERT_SaveSMimeProfile(cert, NULL, pwdata);
217 } while (0);
219 CERT_DestroyCertificate (cert);
220 PORT_Free(trust);
221 PORT_Free(certDER.data);
223 return rv;
226 static SECStatus
227 CertReq(SECKEYPrivateKey *privk, SECKEYPublicKey *pubk, KeyType keyType,
228 SECOidTag hashAlgTag, CERTName *subject, char *phone, int ascii,
229 const char *emailAddrs, const char *dnsNames,
230 certutilExtnList extnList,
231 PRFileDesc *outFile)
233 CERTSubjectPublicKeyInfo *spki;
234 CERTCertificateRequest *cr;
235 SECItem *encoding;
236 SECOidTag signAlgTag;
237 SECItem result;
238 SECStatus rv;
239 PRArenaPool *arena;
240 PRInt32 numBytes;
241 void *extHandle;
243 /* Create info about public key */
244 spki = SECKEY_CreateSubjectPublicKeyInfo(pubk);
245 if (!spki) {
246 SECU_PrintError(progName, "unable to create subject public key");
247 return SECFailure;
250 /* Generate certificate request */
251 cr = CERT_CreateCertificateRequest(subject, spki, NULL);
252 if (!cr) {
253 SECU_PrintError(progName, "unable to make certificate request");
254 return SECFailure;
257 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
258 if ( !arena ) {
259 SECU_PrintError(progName, "out of memory");
260 return SECFailure;
263 extHandle = CERT_StartCertificateRequestAttributes(cr);
264 if (extHandle == NULL) {
265 PORT_FreeArena (arena, PR_FALSE);
266 return SECFailure;
268 if (AddExtensions(extHandle, emailAddrs, dnsNames, extnList)
269 != SECSuccess) {
270 PORT_FreeArena (arena, PR_FALSE);
271 return SECFailure;
273 CERT_FinishExtensions(extHandle);
274 CERT_FinishCertificateRequestAttributes(cr);
276 /* Der encode the request */
277 encoding = SEC_ASN1EncodeItem(arena, NULL, cr,
278 SEC_ASN1_GET(CERT_CertificateRequestTemplate));
279 if (encoding == NULL) {
280 SECU_PrintError(progName, "der encoding of request failed");
281 return SECFailure;
284 /* Sign the request */
285 signAlgTag = SEC_GetSignatureAlgorithmOidTag(keyType, hashAlgTag);
286 if (signAlgTag == SEC_OID_UNKNOWN) {
287 SECU_PrintError(progName, "unknown Key or Hash type");
288 return SECFailure;
290 rv = SEC_DerSignData(arena, &result, encoding->data, encoding->len,
291 privk, signAlgTag);
292 if (rv) {
293 SECU_PrintError(progName, "signing of data failed");
294 return SECFailure;
297 /* Encode request in specified format */
298 if (ascii) {
299 char *obuf;
300 char *name, *email, *org, *state, *country;
301 SECItem *it;
302 int total;
304 it = &result;
306 obuf = BTOA_ConvertItemToAscii(it);
307 total = PL_strlen(obuf);
309 name = CERT_GetCommonName(subject);
310 if (!name) {
311 name = strdup("(not specified)");
314 if (!phone)
315 phone = strdup("(not specified)");
317 email = CERT_GetCertEmailAddress(subject);
318 if (!email)
319 email = strdup("(not specified)");
321 org = CERT_GetOrgName(subject);
322 if (!org)
323 org = strdup("(not specified)");
325 state = CERT_GetStateName(subject);
326 if (!state)
327 state = strdup("(not specified)");
329 country = CERT_GetCountryName(subject);
330 if (!country)
331 country = strdup("(not specified)");
333 PR_fprintf(outFile,
334 "\nCertificate request generated by Netscape certutil\n");
335 PR_fprintf(outFile, "Phone: %s\n\n", phone);
336 PR_fprintf(outFile, "Common Name: %s\n", name);
337 PR_fprintf(outFile, "Email: %s\n", email);
338 PR_fprintf(outFile, "Organization: %s\n", org);
339 PR_fprintf(outFile, "State: %s\n", state);
340 PR_fprintf(outFile, "Country: %s\n\n", country);
342 PR_fprintf(outFile, "%s\n", NS_CERTREQ_HEADER);
343 numBytes = PR_Write(outFile, obuf, total);
344 if (numBytes != total) {
345 SECU_PrintSystemError(progName, "write error");
346 return SECFailure;
348 PR_fprintf(outFile, "\n%s\n", NS_CERTREQ_TRAILER);
349 } else {
350 numBytes = PR_Write(outFile, result.data, result.len);
351 if (numBytes != (int)result.len) {
352 SECU_PrintSystemError(progName, "write error");
353 return SECFailure;
356 return SECSuccess;
359 static SECStatus
360 ChangeTrustAttributes(CERTCertDBHandle *handle, PK11SlotInfo *slot,
361 char *name, char *trusts, void *pwdata)
363 SECStatus rv;
364 CERTCertificate *cert;
365 CERTCertTrust *trust;
367 cert = CERT_FindCertByNicknameOrEmailAddr(handle, name);
368 if (!cert) {
369 SECU_PrintError(progName, "could not find certificate named \"%s\"",
370 name);
371 return SECFailure;
374 trust = (CERTCertTrust *)PORT_ZAlloc(sizeof(CERTCertTrust));
375 if (!trust) {
376 SECU_PrintError(progName, "unable to allocate cert trust");
377 return SECFailure;
380 /* This function only decodes these characters: pPwcTCu, */
381 rv = CERT_DecodeTrustString(trust, trusts);
382 if (rv) {
383 SECU_PrintError(progName, "unable to decode trust string");
384 return SECFailure;
387 /* CERT_ChangeCertTrust API does not have a way to pass in
388 * a context, so NSS can't prompt for the password if it needs to.
389 * check to see if the failure was token not logged in and
390 * log in if need be. */
391 rv = CERT_ChangeCertTrust(handle, cert, trust);
392 if (rv != SECSuccess) {
393 if (PORT_GetError() == SEC_ERROR_TOKEN_NOT_LOGGED_IN) {
394 rv = PK11_Authenticate(slot, PR_TRUE, pwdata);
395 if (rv != SECSuccess) {
396 SECU_PrintError(progName, "could not authenticate to token %s.",
397 PK11_GetTokenName(slot));
398 return SECFailure;
400 rv = CERT_ChangeCertTrust(handle, cert, trust);
402 if (rv != SECSuccess) {
403 SECU_PrintError(progName, "unable to modify trust attributes");
404 return SECFailure;
407 CERT_DestroyCertificate(cert);
409 return SECSuccess;
412 static SECStatus
413 DumpChain(CERTCertDBHandle *handle, char *name)
415 CERTCertificate *the_cert;
416 CERTCertificateList *chain;
417 int i, j;
418 the_cert = PK11_FindCertFromNickname(name, NULL);
419 if (!the_cert) {
420 SECU_PrintError(progName, "Could not find: %s\n", name);
421 return SECFailure;
423 chain = CERT_CertChainFromCert(the_cert, 0, PR_TRUE);
424 CERT_DestroyCertificate(the_cert);
425 if (!chain) {
426 SECU_PrintError(progName, "Could not obtain chain for: %s\n", name);
427 return SECFailure;
429 for (i=chain->len-1; i>=0; i--) {
430 CERTCertificate *c;
431 c = CERT_FindCertByDERCert(handle, &chain->certs[i]);
432 for (j=i; j<chain->len-1; j++) printf(" ");
433 printf("\"%s\" [%s]\n\n", c->nickname, c->subjectName);
434 CERT_DestroyCertificate(c);
436 CERT_DestroyCertificateList(chain);
437 return SECSuccess;
440 static SECStatus
441 listCerts(CERTCertDBHandle *handle, char *name, PK11SlotInfo *slot,
442 PRBool raw, PRBool ascii, PRFileDesc *outfile, void *pwarg)
444 SECItem data;
445 PRInt32 numBytes;
446 SECStatus rv = SECFailure;
447 CERTCertList *certs;
448 CERTCertListNode *node;
450 /* List certs on a non-internal slot. */
451 if (!PK11_IsFriendly(slot) && PK11_NeedLogin(slot)) {
452 SECStatus newrv = PK11_Authenticate(slot, PR_TRUE, pwarg);
453 if (newrv != SECSuccess) {
454 SECU_PrintError(progName, "could not authenticate to token %s.",
455 PK11_GetTokenName(slot));
456 return SECFailure;
459 if (name) {
460 CERTCertificate *the_cert;
461 the_cert = CERT_FindCertByNicknameOrEmailAddr(handle, name);
462 if (!the_cert) {
463 the_cert = PK11_FindCertFromNickname(name, NULL);
464 if (!the_cert) {
465 SECU_PrintError(progName, "Could not find: %s\n", name);
466 return SECFailure;
469 certs = CERT_CreateSubjectCertList(NULL, handle, &the_cert->derSubject,
470 PR_Now(), PR_FALSE);
471 CERT_DestroyCertificate(the_cert);
473 for (node = CERT_LIST_HEAD(certs); !CERT_LIST_END(node,certs);
474 node = CERT_LIST_NEXT(node)) {
475 the_cert = node->cert;
476 /* now get the subjectList that matches this cert */
477 data.data = the_cert->derCert.data;
478 data.len = the_cert->derCert.len;
479 if (ascii) {
480 PR_fprintf(outfile, "%s\n%s\n%s\n", NS_CERT_HEADER,
481 BTOA_DataToAscii(data.data, data.len), NS_CERT_TRAILER);
482 rv = SECSuccess;
483 } else if (raw) {
484 numBytes = PR_Write(outfile, data.data, data.len);
485 if (numBytes != (PRInt32) data.len) {
486 SECU_PrintSystemError(progName, "error writing raw cert");
487 rv = SECFailure;
489 rv = SECSuccess;
490 } else {
491 rv = SEC_PrintCertificateAndTrust(the_cert, "Certificate",
492 the_cert->trust);
493 if (rv != SECSuccess) {
494 SECU_PrintError(progName, "problem printing certificate");
498 if (rv != SECSuccess) {
499 break;
502 } else {
504 certs = PK11_ListCertsInSlot(slot);
505 if (certs) {
506 for (node = CERT_LIST_HEAD(certs); !CERT_LIST_END(node,certs);
507 node = CERT_LIST_NEXT(node)) {
508 SECU_PrintCertNickname(node,stdout);
510 rv = SECSuccess;
513 if (certs) {
514 CERT_DestroyCertList(certs);
516 if (rv) {
517 SECU_PrintError(progName, "problem printing certificate nicknames");
518 return SECFailure;
521 return SECSuccess; /* not rv ?? */
524 static SECStatus
525 ListCerts(CERTCertDBHandle *handle, char *nickname, PK11SlotInfo *slot,
526 PRBool raw, PRBool ascii, PRFileDesc *outfile, secuPWData *pwdata)
528 SECStatus rv;
530 if (!ascii && !raw) {
531 PR_fprintf(outfile, "\n%-60s %-5s\n%-60s %-5s\n\n",
532 "Certificate Nickname", "Trust Attributes", "",
533 "SSL,S/MIME,JAR/XPI");
535 if (slot == NULL) {
536 CERTCertList *list;
537 CERTCertListNode *node;
539 list = PK11_ListCerts(PK11CertListAll, pwdata);
540 for (node = CERT_LIST_HEAD(list); !CERT_LIST_END(node, list);
541 node = CERT_LIST_NEXT(node))
543 SECU_PrintCertNickname(node, stdout);
545 CERT_DestroyCertList(list);
546 return SECSuccess;
547 } else {
548 rv = listCerts(handle,nickname,slot,raw,ascii,outfile,pwdata);
550 return rv;
553 static SECStatus
554 DeleteCert(CERTCertDBHandle *handle, char *name)
556 SECStatus rv;
557 CERTCertificate *cert;
559 cert = CERT_FindCertByNicknameOrEmailAddr(handle, name);
560 if (!cert) {
561 SECU_PrintError(progName, "could not find certificate named \"%s\"",
562 name);
563 return SECFailure;
566 rv = SEC_DeletePermCertificate(cert);
567 CERT_DestroyCertificate(cert);
568 if (rv) {
569 SECU_PrintError(progName, "unable to delete certificate");
570 return SECFailure;
573 return SECSuccess;
576 static SECStatus
577 ValidateCert(CERTCertDBHandle *handle, char *name, char *date,
578 char *certUsage, PRBool checkSig, PRBool logit, secuPWData *pwdata)
580 SECStatus rv;
581 CERTCertificate *cert = NULL;
582 int64 timeBoundary;
583 SECCertificateUsage usage;
584 CERTVerifyLog reallog;
585 CERTVerifyLog *log = NULL;
587 if (!certUsage) {
588 PORT_SetError (SEC_ERROR_INVALID_ARGS);
589 return (SECFailure);
592 switch (*certUsage) {
593 case 'O':
594 usage = certificateUsageStatusResponder;
595 break;
596 case 'C':
597 usage = certificateUsageSSLClient;
598 break;
599 case 'V':
600 usage = certificateUsageSSLServer;
601 break;
602 case 'S':
603 usage = certificateUsageEmailSigner;
604 break;
605 case 'R':
606 usage = certificateUsageEmailRecipient;
607 break;
608 case 'J':
609 usage = certificateUsageObjectSigner;
610 break;
611 default:
612 PORT_SetError (SEC_ERROR_INVALID_ARGS);
613 return (SECFailure);
615 do {
616 cert = CERT_FindCertByNicknameOrEmailAddr(handle, name);
617 if (!cert) {
618 SECU_PrintError(progName, "could not find certificate named \"%s\"",
619 name);
620 GEN_BREAK (SECFailure)
623 if (date != NULL) {
624 rv = DER_AsciiToTime(&timeBoundary, date);
625 if (rv) {
626 SECU_PrintError(progName, "invalid input date");
627 GEN_BREAK (SECFailure)
629 } else {
630 timeBoundary = PR_Now();
633 if ( logit ) {
634 log = &reallog;
636 log->count = 0;
637 log->head = NULL;
638 log->tail = NULL;
639 log->arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
640 if ( log->arena == NULL ) {
641 SECU_PrintError(progName, "out of memory");
642 GEN_BREAK (SECFailure)
646 rv = CERT_VerifyCertificate(handle, cert, checkSig, usage,
647 timeBoundary, pwdata, log, &usage);
648 if ( log ) {
649 if ( log->head == NULL ) {
650 fprintf(stdout, "%s: certificate is valid\n", progName);
651 GEN_BREAK (SECSuccess)
652 } else {
653 char *name;
654 CERTVerifyLogNode *node;
656 node = log->head;
657 while ( node ) {
658 if ( node->cert->nickname != NULL ) {
659 name = node->cert->nickname;
660 } else {
661 name = node->cert->subjectName;
663 fprintf(stderr, "%s : %s\n", name,
664 SECU_Strerror(node->error));
665 CERT_DestroyCertificate(node->cert);
666 node = node->next;
669 } else {
670 if (rv != SECSuccess) {
671 PRErrorCode perr = PORT_GetError();
672 fprintf(stdout, "%s: certificate is invalid: %s\n",
673 progName, SECU_Strerror(perr));
674 GEN_BREAK (SECFailure)
676 fprintf(stdout, "%s: certificate is valid\n", progName);
677 GEN_BREAK (SECSuccess)
679 } while (0);
681 if (cert) {
682 CERT_DestroyCertificate(cert);
685 return (rv);
688 static PRBool
689 ItemIsPrintableASCII(const SECItem * item)
691 unsigned char *src = item->data;
692 unsigned int len = item->len;
693 while (len-- > 0) {
694 unsigned char uc = *src++;
695 if (uc < 0x20 || uc > 0x7e)
696 return PR_FALSE;
698 return PR_TRUE;
701 /* Caller ensures that dst is at least item->len*2+1 bytes long */
702 static void
703 SECItemToHex(const SECItem * item, char * dst)
705 if (dst && item && item->data) {
706 unsigned char * src = item->data;
707 unsigned int len = item->len;
708 for (; len > 0; --len, dst += 2) {
709 sprintf(dst, "%02x", *src++);
711 *dst = '\0';
715 static const char * const keyTypeName[] = {
716 "null", "rsa", "dsa", "fortezza", "dh", "kea", "ec" };
718 #define MAX_CKA_ID_BIN_LEN 20
719 #define MAX_CKA_ID_STR_LEN 40
721 /* print key number, key ID (in hex or ASCII), key label (nickname) */
722 static SECStatus
723 PrintKey(PRFileDesc *out, const char *nickName, int count,
724 SECKEYPrivateKey *key, void *pwarg)
726 SECItem * ckaID;
727 char ckaIDbuf[MAX_CKA_ID_STR_LEN + 4];
729 pwarg = NULL;
730 ckaID = PK11_GetLowLevelKeyIDForPrivateKey(key);
731 if (!ckaID) {
732 strcpy(ckaIDbuf, "(no CKA_ID)");
733 } else if (ItemIsPrintableASCII(ckaID)) {
734 int len = PR_MIN(MAX_CKA_ID_STR_LEN, ckaID->len);
735 ckaIDbuf[0] = '"';
736 memcpy(ckaIDbuf + 1, ckaID->data, len);
737 ckaIDbuf[1 + len] = '"';
738 ckaIDbuf[2 + len] = '\0';
739 } else {
740 /* print ckaid in hex */
741 SECItem idItem = *ckaID;
742 if (idItem.len > MAX_CKA_ID_BIN_LEN)
743 idItem.len = MAX_CKA_ID_BIN_LEN;
744 SECItemToHex(&idItem, ckaIDbuf);
747 PR_fprintf(out, "<%2d> %-8.8s %-42.42s %s\n", count,
748 keyTypeName[key->keyType], ckaIDbuf, nickName);
749 SECITEM_ZfreeItem(ckaID, PR_TRUE);
751 return SECSuccess;
754 /* returns SECSuccess if ANY keys are found, SECFailure otherwise. */
755 static SECStatus
756 ListKeysInSlot(PK11SlotInfo *slot, const char *nickName, KeyType keyType,
757 void *pwarg)
759 SECKEYPrivateKeyList *list;
760 SECKEYPrivateKeyListNode *node;
761 int count = 0;
763 if (PK11_NeedLogin(slot)) {
764 SECStatus rv = PK11_Authenticate(slot, PR_TRUE, pwarg);
765 if (rv != SECSuccess) {
766 SECU_PrintError(progName, "could not authenticate to token %s.",
767 PK11_GetTokenName(slot));
768 return SECFailure;
772 if (nickName && nickName[0])
773 list = PK11_ListPrivKeysInSlot(slot, (char *)nickName, pwarg);
774 else
775 list = PK11_ListPrivateKeysInSlot(slot);
776 if (list == NULL) {
777 SECU_PrintError(progName, "problem listing keys");
778 return SECFailure;
780 for (node=PRIVKEY_LIST_HEAD(list);
781 !PRIVKEY_LIST_END(node,list);
782 node=PRIVKEY_LIST_NEXT(node)) {
783 char * keyName;
784 static const char orphan[] = { "(orphan)" };
786 if (keyType != nullKey && keyType != node->key->keyType)
787 continue;
788 keyName = PK11_GetPrivateKeyNickname(node->key);
789 if (!keyName || !keyName[0]) {
790 /* Try extra hard to find nicknames for keys that lack them. */
791 CERTCertificate * cert;
792 PORT_Free((void *)keyName);
793 keyName = NULL;
794 cert = PK11_GetCertFromPrivateKey(node->key);
795 if (cert) {
796 if (cert->nickname && !cert->nickname[0]) {
797 keyName = PORT_Strdup(cert->nickname);
798 } else if (cert->emailAddr && cert->emailAddr[0]) {
799 keyName = PORT_Strdup(cert->emailAddr);
801 CERT_DestroyCertificate(cert);
804 if (nickName) {
805 if (!keyName || PL_strcmp(keyName,nickName)) {
806 /* PKCS#11 module returned unwanted keys */
807 PORT_Free((void *)keyName);
808 continue;
811 if (!keyName)
812 keyName = (char *)orphan;
814 PrintKey(PR_STDOUT, keyName, count, node->key, pwarg);
816 if (keyName != (char *)orphan)
817 PORT_Free((void *)keyName);
818 count++;
820 SECKEY_DestroyPrivateKeyList(list);
822 if (count == 0) {
823 PR_fprintf(PR_STDOUT, "%s: no keys found\n", progName);
824 return SECFailure;
826 return SECSuccess;
829 /* returns SECSuccess if ANY keys are found, SECFailure otherwise. */
830 static SECStatus
831 ListKeys(PK11SlotInfo *slot, const char *nickName, int index,
832 KeyType keyType, PRBool dopriv, secuPWData *pwdata)
834 SECStatus rv = SECFailure;
836 if (slot == NULL) {
837 PK11SlotList *list;
838 PK11SlotListElement *le;
840 list= PK11_GetAllTokens(CKM_INVALID_MECHANISM,PR_FALSE,PR_FALSE,pwdata);
841 if (list) {
842 for (le = list->head; le; le = le->next) {
843 rv &= ListKeysInSlot(le->slot,nickName,keyType,pwdata);
845 PK11_FreeSlotList(list);
847 } else {
848 rv = ListKeysInSlot(slot,nickName,keyType,pwdata);
850 return rv;
853 static SECStatus
854 DeleteKey(char *nickname, secuPWData *pwdata)
856 SECStatus rv;
857 CERTCertificate *cert;
858 PK11SlotInfo *slot;
860 slot = PK11_GetInternalKeySlot();
861 if (PK11_NeedLogin(slot)) {
862 SECStatus rv = PK11_Authenticate(slot, PR_TRUE, pwdata);
863 if (rv != SECSuccess) {
864 SECU_PrintError(progName, "could not authenticate to token %s.",
865 PK11_GetTokenName(slot));
866 return SECFailure;
869 cert = PK11_FindCertFromNickname(nickname, pwdata);
870 if (!cert) {
871 PK11_FreeSlot(slot);
872 return SECFailure;
874 rv = PK11_DeleteTokenCertAndKey(cert, pwdata);
875 if (rv != SECSuccess) {
876 SECU_PrintError("problem deleting private key \"%s\"\n", nickname);
878 CERT_DestroyCertificate(cert);
879 PK11_FreeSlot(slot);
880 return rv;
885 * L i s t M o d u l e s
887 * Print a list of the PKCS11 modules that are
888 * available. This is useful for smartcard people to
889 * make sure they have the drivers loaded.
892 static SECStatus
893 ListModules(void)
895 PK11SlotList *list;
896 PK11SlotListElement *le;
898 /* get them all! */
899 list = PK11_GetAllTokens(CKM_INVALID_MECHANISM,PR_FALSE,PR_FALSE,NULL);
900 if (list == NULL) return SECFailure;
902 /* look at each slot*/
903 for (le = list->head ; le; le = le->next) {
904 printf ("\n");
905 printf (" slot: %s\n", PK11_GetSlotName(le->slot));
906 printf (" token: %s\n", PK11_GetTokenName(le->slot));
908 PK11_FreeSlotList(list);
910 return SECSuccess;
913 static void
914 Usage(char *progName)
916 #define FPS fprintf(stderr,
917 FPS "Type %s -H for more detailed descriptions\n", progName);
918 FPS "Usage: %s -N [-d certdir] [-P dbprefix] [-f pwfile]\n", progName);
919 FPS "Usage: %s -T [-d certdir] [-P dbprefix] [-h token-name] [-f pwfile]\n", progName);
920 FPS "\t%s -A -n cert-name -t trustargs [-d certdir] [-P dbprefix] [-a] [-i input]\n",
921 progName);
922 FPS "\t%s -B -i batch-file\n", progName);
923 FPS "\t%s -C [-c issuer-name | -x] -i cert-request-file -o cert-file\n"
924 "\t\t [-m serial-number] [-w warp-months] [-v months-valid]\n"
925 "\t\t [-f pwfile] [-d certdir] [-P dbprefix] [-1] [-2] [-3] [-4] [-5]\n"
926 "\t\t [-6] [-7 emailAddrs] [-8 dns-names] [-a]\n",
927 progName);
928 FPS "\t%s -D -n cert-name [-d certdir] [-P dbprefix]\n", progName);
929 FPS "\t%s -E -n cert-name -t trustargs [-d certdir] [-P dbprefix] [-a] [-i input]\n",
930 progName);
931 FPS "\t%s -G -n key-name [-h token-name] [-k rsa] [-g key-size] [-y exp]\n"
932 "\t\t [-f pwfile] [-z noisefile] [-d certdir] [-P dbprefix]\n", progName);
933 FPS "\t%s -G [-h token-name] -k dsa [-q pqgfile -g key-size] [-f pwfile]\n"
934 "\t\t [-z noisefile] [-d certdir] [-P dbprefix]\n", progName);
935 #ifdef NSS_ENABLE_ECC
936 FPS "\t%s -G [-h token-name] -k ec -q curve [-f pwfile]\n"
937 "\t\t [-z noisefile] [-d certdir] [-P dbprefix]\n", progName);
938 FPS "\t%s -K [-n key-name] [-h token-name] [-k dsa|ec|rsa|all]\n",
939 progName);
940 #else
941 FPS "\t%s -K [-n key-name] [-h token-name] [-k dsa|rsa|all]\n",
942 progName);
943 #endif /* NSS_ENABLE_ECC */
944 FPS "\t\t [-f pwfile] [-X] [-d certdir] [-P dbprefix]\n");
945 FPS "\t%s --upgrade-merge --source-dir upgradeDir --upgrade-id uniqueID\n",
946 progName);
947 FPS "\t\t [--upgrade-token-name tokenName] [-d targetDBDir]\n");
948 FPS "\t\t [-P targetDBPrefix] [--source-prefix upgradeDBPrefix]\n");
949 FPS "\t\t [-f targetPWfile] [-@ upgradePWFile]\n");
950 FPS "\t%s --merge --source-dir sourceDBDir [-d targetDBdir]\n",
951 progName);
952 FPS "\t\t [-P targetDBPrefix] [--source-prefix sourceDBPrefix]\n");
953 FPS "\t\t [-f targetPWfile] [-@ sourcePWFile]\n");
954 FPS "\t%s -L [-n cert-name] [-X] [-d certdir] [-P dbprefix] [-r] [-a]\n", progName);
955 FPS "\t%s -M -n cert-name -t trustargs [-d certdir] [-P dbprefix]\n",
956 progName);
957 FPS "\t%s -O -n cert-name [-X] [-d certdir] [-P dbprefix]\n", progName);
958 FPS "\t%s -R -s subj -o cert-request-file [-d certdir] [-P dbprefix] [-p phone] [-a]\n"
959 "\t\t [-y emailAddrs] [-k key-type-or-id] [-h token-name] [-f pwfile] [-g key-size]\n",
960 progName);
961 FPS "\t%s -V -n cert-name -u usage [-b time] [-e] \n"
962 "\t\t[-X] [-d certdir] [-P dbprefix]\n",
963 progName);
964 FPS "\t%s -S -n cert-name -s subj [-c issuer-name | -x] -t trustargs\n"
965 "\t\t [-k key-type-or-id] [-q key-params] [-h token-name] [-g key-size]\n"
966 "\t\t [-m serial-number] [-w warp-months] [-v months-valid]\n"
967 "\t\t [-f pwfile] [-d certdir] [-P dbprefix]\n"
968 "\t\t [-p phone] [-1] [-2] [-3] [-4] [-5] [-6] [-7 emailAddrs]\n"
969 "\t\t [-8 DNS-names]\n"
970 "\t\t [--extAIA] [--extSIA] [--extCP] [--extPM] [--extPC] [--extIA]\n"
971 "\t\t [--extSKID]\n", progName);
972 FPS "\t%s -U [-X] [-d certdir] [-P dbprefix]\n", progName);
973 exit(1);
976 static void LongUsage(char *progName)
979 FPS "%-15s Add a certificate to the database (create if needed)\n",
980 "-A");
981 FPS "%-20s\n", " All options under -E apply");
982 FPS "%-15s Run a series of certutil commands from a batch file\n", "-B");
983 FPS "%-20s Specify the batch file\n", " -i batch-file");
984 FPS "%-15s Add an Email certificate to the database (create if needed)\n",
985 "-E");
986 FPS "%-20s Specify the nickname of the certificate to add\n",
987 " -n cert-name");
988 FPS "%-20s Set the certificate trust attributes:\n",
989 " -t trustargs");
990 FPS "%-25s trustargs is of the form x,y,z where x is for SSL, y is for S/MIME,\n", "");
991 FPS "%-25s and z is for code signing\n", "");
992 FPS "%-25s p \t valid peer\n", "");
993 FPS "%-25s P \t trusted peer (implies p)\n", "");
994 FPS "%-25s c \t valid CA\n", "");
995 FPS "%-25s T \t trusted CA to issue client certs (implies c)\n", "");
996 FPS "%-25s C \t trusted CA to issue server certs (implies c)\n", "");
997 FPS "%-25s u \t user cert\n", "");
998 FPS "%-25s w \t send warning\n", "");
999 FPS "%-25s g \t make step-up cert\n", "");
1000 FPS "%-20s Specify the password file\n",
1001 " -f pwfile");
1002 FPS "%-20s Cert database directory (default is ~/.netscape)\n",
1003 " -d certdir");
1004 FPS "%-20s Cert & Key database prefix\n",
1005 " -P dbprefix");
1006 FPS "%-20s The input certificate is encoded in ASCII (RFC1113)\n",
1007 " -a");
1008 FPS "%-20s Specify the certificate file (default is stdin)\n",
1009 " -i input");
1010 FPS "\n");
1012 FPS "%-15s Create a new binary certificate from a BINARY cert request\n",
1013 "-C");
1014 FPS "%-20s The nickname of the issuer cert\n",
1015 " -c issuer-name");
1016 FPS "%-20s The BINARY certificate request file\n",
1017 " -i cert-request ");
1018 FPS "%-20s Output binary cert to this file (default is stdout)\n",
1019 " -o output-cert");
1020 FPS "%-20s Self sign\n",
1021 " -x");
1022 FPS "%-20s Cert serial number\n",
1023 " -m serial-number");
1024 FPS "%-20s Time Warp\n",
1025 " -w warp-months");
1026 FPS "%-20s Months valid (default is 3)\n",
1027 " -v months-valid");
1028 FPS "%-20s Specify the password file\n",
1029 " -f pwfile");
1030 FPS "%-20s Cert database directory (default is ~/.netscape)\n",
1031 " -d certdir");
1032 FPS "%-20s Cert & Key database prefix\n",
1033 " -P dbprefix");
1034 FPS "%-20s Create key usage extension\n",
1035 " -1 ");
1036 FPS "%-20s Create basic constraint extension\n",
1037 " -2 ");
1038 FPS "%-20s Create authority key ID extension\n",
1039 " -3 ");
1040 FPS "%-20s Create crl distribution point extension\n",
1041 " -4 ");
1042 FPS "%-20s Create netscape cert type extension\n",
1043 " -5 ");
1044 FPS "%-20s Create extended key usage extension\n",
1045 " -6 ");
1046 FPS "%-20s Create an email subject alt name extension\n",
1047 " -7 ");
1048 FPS "%-20s Create an dns subject alt name extension\n",
1049 " -8 ");
1050 FPS "%-20s The input certificate request is encoded in ASCII (RFC1113)\n",
1051 " -a");
1052 FPS "\n");
1054 FPS "%-15s Generate a new key pair\n",
1055 "-G");
1056 FPS "%-20s Name of token in which to generate key (default is internal)\n",
1057 " -h token-name");
1058 #ifdef NSS_ENABLE_ECC
1059 FPS "%-20s Type of key pair to generate (\"dsa\", \"ec\", \"rsa\" (default))\n",
1060 " -k key-type");
1061 FPS "%-20s Key size in bits, (min %d, max %d, default %d) (not for ec)\n",
1062 " -g key-size", MIN_KEY_BITS, MAX_KEY_BITS, DEFAULT_KEY_BITS);
1063 #else
1064 FPS "%-20s Type of key pair to generate (\"dsa\", \"rsa\" (default))\n",
1065 " -k key-type");
1066 FPS "%-20s Key size in bits, (min %d, max %d, default %d)\n",
1067 " -g key-size", MIN_KEY_BITS, MAX_KEY_BITS, DEFAULT_KEY_BITS);
1068 #endif /* NSS_ENABLE_ECC */
1069 FPS "%-20s Set the public exponent value (3, 17, 65537) (rsa only)\n",
1070 " -y exp");
1071 FPS "%-20s Specify the password file\n",
1072 " -f password-file");
1073 FPS "%-20s Specify the noise file to be used\n",
1074 " -z noisefile");
1075 FPS "%-20s read PQG value from pqgfile (dsa only)\n",
1076 " -q pqgfile");
1077 #ifdef NSS_ENABLE_ECC
1078 FPS "%-20s Elliptic curve name (ec only)\n",
1079 " -q curve-name");
1080 FPS "%-20s One of nistp256, nistp384, nistp521\n", "");
1081 #ifdef NSS_ECC_MORE_THAN_SUITE_B
1082 FPS "%-20s sect163k1, nistk163, sect163r1, sect163r2,\n", "");
1083 FPS "%-20s nistb163, sect193r1, sect193r2, sect233k1, nistk233,\n", "");
1084 FPS "%-20s sect233r1, nistb233, sect239k1, sect283k1, nistk283,\n", "");
1085 FPS "%-20s sect283r1, nistb283, sect409k1, nistk409, sect409r1,\n", "");
1086 FPS "%-20s nistb409, sect571k1, nistk571, sect571r1, nistb571,\n", "");
1087 FPS "%-20s secp160k1, secp160r1, secp160r2, secp192k1, secp192r1,\n", "");
1088 FPS "%-20s nistp192, secp224k1, secp224r1, nistp224, secp256k1,\n", "");
1089 FPS "%-20s secp256r1, secp384r1, secp521r1,\n", "");
1090 FPS "%-20s prime192v1, prime192v2, prime192v3, \n", "");
1091 FPS "%-20s prime239v1, prime239v2, prime239v3, c2pnb163v1, \n", "");
1092 FPS "%-20s c2pnb163v2, c2pnb163v3, c2pnb176v1, c2tnb191v1, \n", "");
1093 FPS "%-20s c2tnb191v2, c2tnb191v3, \n", "");
1094 FPS "%-20s c2pnb208w1, c2tnb239v1, c2tnb239v2, c2tnb239v3, \n", "");
1095 FPS "%-20s c2pnb272w1, c2pnb304w1, \n", "");
1096 FPS "%-20s c2tnb359w1, c2pnb368w1, c2tnb431r1, secp112r1, \n", "");
1097 FPS "%-20s secp112r2, secp128r1, secp128r2, sect113r1, sect113r2\n", "");
1098 FPS "%-20s sect131r1, sect131r2\n", "");
1099 #endif /* NSS_ECC_MORE_THAN_SUITE_B */
1100 #endif
1101 FPS "%-20s Key database directory (default is ~/.netscape)\n",
1102 " -d keydir");
1103 FPS "%-20s Cert & Key database prefix\n",
1104 " -P dbprefix");
1105 FPS "\n");
1107 FPS "%-15s Delete a certificate from the database\n",
1108 "-D");
1109 FPS "%-20s The nickname of the cert to delete\n",
1110 " -n cert-name");
1111 FPS "%-20s Cert database directory (default is ~/.netscape)\n",
1112 " -d certdir");
1113 FPS "%-20s Cert & Key database prefix\n",
1114 " -P dbprefix");
1115 FPS "\n");
1117 FPS "%-15s List all modules\n", /*, or print out a single named module\n",*/
1118 "-U");
1119 FPS "%-20s Module database directory (default is '~/.netscape')\n",
1120 " -d moddir");
1121 FPS "%-20s Cert & Key database prefix\n",
1122 " -P dbprefix");
1123 FPS "%-20s force the database to open R/W\n",
1124 " -X");
1125 FPS "\n");
1127 FPS "%-15s List all private keys\n",
1128 "-K");
1129 FPS "%-20s Name of token to search (\"all\" for all tokens)\n",
1130 " -h token-name ");
1132 FPS "%-20s Key type (\"all\" (default), \"dsa\","
1133 #ifdef NSS_ENABLE_ECC
1134 " \"ec\","
1135 #endif
1136 " \"rsa\")\n",
1137 " -k key-type");
1138 FPS "%-20s The nickname of the key or associated certificate\n",
1139 " -n name");
1140 FPS "%-20s Specify the password file\n",
1141 " -f password-file");
1142 FPS "%-20s Key database directory (default is ~/.netscape)\n",
1143 " -d keydir");
1144 FPS "%-20s Cert & Key database prefix\n",
1145 " -P dbprefix");
1146 FPS "%-20s force the database to open R/W\n",
1147 " -X");
1148 FPS "\n");
1150 FPS "%-15s List all certs, or print out a single named cert\n",
1151 "-L");
1152 FPS "%-20s Pretty print named cert (list all if unspecified)\n",
1153 " -n cert-name");
1154 FPS "%-20s Cert database directory (default is ~/.netscape)\n",
1155 " -d certdir");
1156 FPS "%-20s Cert & Key database prefix\n",
1157 " -P dbprefix");
1158 FPS "%-20s force the database to open R/W\n",
1159 " -X");
1160 FPS "%-20s For single cert, print binary DER encoding\n",
1161 " -r");
1162 FPS "%-20s For single cert, print ASCII encoding (RFC1113)\n",
1163 " -a");
1164 FPS "\n");
1166 FPS "%-15s Modify trust attributes of certificate\n",
1167 "-M");
1168 FPS "%-20s The nickname of the cert to modify\n",
1169 " -n cert-name");
1170 FPS "%-20s Set the certificate trust attributes (see -A above)\n",
1171 " -t trustargs");
1172 FPS "%-20s Cert database directory (default is ~/.netscape)\n",
1173 " -d certdir");
1174 FPS "%-20s Cert & Key database prefix\n",
1175 " -P dbprefix");
1176 FPS "\n");
1178 FPS "%-15s Create a new certificate database\n",
1179 "-N");
1180 FPS "%-20s Cert database directory (default is ~/.netscape)\n",
1181 " -d certdir");
1182 FPS "%-20s Cert & Key database prefix\n",
1183 " -P dbprefix");
1184 FPS "\n");
1185 FPS "%-15s Reset the Key database or token\n",
1186 "-T");
1187 FPS "%-20s Cert database directory (default is ~/.netscape)\n",
1188 " -d certdir");
1189 FPS "%-20s Cert & Key database prefix\n",
1190 " -P dbprefix");
1191 FPS "%-20s Token to reset (default is internal)\n",
1192 " -h token-name");
1193 FPS "\n");
1195 FPS "\n");
1196 FPS "%-15s Print the chain of a certificate\n",
1197 "-O");
1198 FPS "%-20s The nickname of the cert to modify\n",
1199 " -n cert-name");
1200 FPS "%-20s Cert database directory (default is ~/.netscape)\n",
1201 " -d certdir");
1202 FPS "%-20s Cert & Key database prefix\n",
1203 " -P dbprefix");
1204 FPS "%-20s force the database to open R/W\n",
1205 " -X");
1206 FPS "\n");
1208 FPS "%-15s Generate a certificate request (stdout)\n",
1209 "-R");
1210 FPS "%-20s Specify the subject name (using RFC1485)\n",
1211 " -s subject");
1212 FPS "%-20s Output the cert request to this file\n",
1213 " -o output-req");
1214 #ifdef NSS_ENABLE_ECC
1215 FPS "%-20s Type of key pair to generate (\"dsa\", \"ec\", \"rsa\" (default))\n",
1216 #else
1217 FPS "%-20s Type of key pair to generate (\"dsa\", \"rsa\" (default))\n",
1218 #endif /* NSS_ENABLE_ECC */
1219 " -k key-type-or-id");
1220 FPS "%-20s or nickname of the cert key to use \n",
1221 "");
1222 FPS "%-20s Name of token in which to generate key (default is internal)\n",
1223 " -h token-name");
1224 FPS "%-20s Key size in bits, RSA keys only (min %d, max %d, default %d)\n",
1225 " -g key-size", MIN_KEY_BITS, MAX_KEY_BITS, DEFAULT_KEY_BITS);
1226 FPS "%-20s Name of file containing PQG parameters (dsa only)\n",
1227 " -q pqgfile");
1228 #ifdef NSS_ENABLE_ECC
1229 FPS "%-20s Elliptic curve name (ec only)\n",
1230 " -q curve-name");
1231 FPS "%-20s See the \"-G\" option for a full list of supported names.\n",
1232 "");
1233 #endif /* NSS_ENABLE_ECC */
1234 FPS "%-20s Specify the password file\n",
1235 " -f pwfile");
1236 FPS "%-20s Key database directory (default is ~/.netscape)\n",
1237 " -d keydir");
1238 FPS "%-20s Cert & Key database prefix\n",
1239 " -P dbprefix");
1240 FPS "%-20s Specify the contact phone number (\"123-456-7890\")\n",
1241 " -p phone");
1242 FPS "%-20s Output the cert request in ASCII (RFC1113); default is binary\n",
1243 " -a");
1244 FPS "%-20s \n",
1245 " See -S for available extension options");
1246 FPS "\n");
1248 FPS "%-15s Validate a certificate\n",
1249 "-V");
1250 FPS "%-20s The nickname of the cert to Validate\n",
1251 " -n cert-name");
1252 FPS "%-20s validity time (\"YYMMDDHHMMSS[+HHMM|-HHMM|Z]\")\n",
1253 " -b time");
1254 FPS "%-20s Check certificate signature \n",
1255 " -e ");
1256 FPS "%-20s Specify certificate usage:\n", " -u certusage");
1257 FPS "%-25s C \t SSL Client\n", "");
1258 FPS "%-25s V \t SSL Server\n", "");
1259 FPS "%-25s S \t Email signer\n", "");
1260 FPS "%-25s R \t Email Recipient\n", "");
1261 FPS "%-25s O \t OCSP status responder\n", "");
1262 FPS "%-25s J \t Object signer\n", "");
1263 FPS "%-20s Cert database directory (default is ~/.netscape)\n",
1264 " -d certdir");
1265 FPS "%-20s Cert & Key database prefix\n",
1266 " -P dbprefix");
1267 FPS "%-20s force the database to open R/W\n",
1268 " -X");
1269 FPS "\n");
1271 FPS "%-15s Upgrade an old database and merge it into a new one\n",
1272 "--upgrade-merge");
1273 FPS "%-20s Cert database directory to merge into (default is ~/.netscape)\n",
1274 " -d certdir");
1275 FPS "%-20s Cert & Key database prefix of the target database\n",
1276 " -P dbprefix");
1277 FPS "%-20s Specify the password file for the target database\n",
1278 " -f pwfile");
1279 FPS "%-20s \n%-20s Cert database directory to upgrade from\n",
1280 " --source-dir certdir", "");
1281 FPS "%-20s \n%-20s Cert & Key database prefix of the upgrade database\n",
1282 " --soruce-prefix dbprefix", "");
1283 FPS "%-20s \n%-20s Unique identifier for the upgrade database\n",
1284 " --upgrade-id uniqueID", "");
1285 FPS "%-20s \n%-20s Name of the token while it is in upgrade state\n",
1286 " --upgrade-token-name name", "");
1287 FPS "%-20s Specify the password file for the upgrade database\n",
1288 " -@ pwfile");
1289 FPS "\n");
1291 FPS "%-15s Merge source database into the target database\n",
1292 "--merge");
1293 FPS "%-20s Cert database directory of target (default is ~/.netscape)\n",
1294 " -d certdir");
1295 FPS "%-20s Cert & Key database prefix of the target database\n",
1296 " -P dbprefix");
1297 FPS "%-20s Specify the password file for the target database\n",
1298 " -f pwfile");
1299 FPS "%-20s \n%-20s Cert database directory of the source database\n",
1300 " --source-dir certdir", "");
1301 FPS "%-20s \n%-20s Cert & Key database prefix of the source database\n",
1302 " --source-prefix dbprefix", "");
1303 FPS "%-20s Specify the password file for the source database\n",
1304 " -@ pwfile");
1305 FPS "\n");
1307 FPS "%-15s Make a certificate and add to database\n",
1308 "-S");
1309 FPS "%-20s Specify the nickname of the cert\n",
1310 " -n key-name");
1311 FPS "%-20s Specify the subject name (using RFC1485)\n",
1312 " -s subject");
1313 FPS "%-20s The nickname of the issuer cert\n",
1314 " -c issuer-name");
1315 FPS "%-20s Set the certificate trust attributes (see -A above)\n",
1316 " -t trustargs");
1317 #ifdef NSS_ENABLE_ECC
1318 FPS "%-20s Type of key pair to generate (\"dsa\", \"ec\", \"rsa\" (default))\n",
1319 #else
1320 FPS "%-20s Type of key pair to generate (\"dsa\", \"rsa\" (default))\n",
1321 #endif /* NSS_ENABLE_ECC */
1322 " -k key-type-or-id");
1323 FPS "%-20s Name of token in which to generate key (default is internal)\n",
1324 " -h token-name");
1325 FPS "%-20s Key size in bits, RSA keys only (min %d, max %d, default %d)\n",
1326 " -g key-size", MIN_KEY_BITS, MAX_KEY_BITS, DEFAULT_KEY_BITS);
1327 FPS "%-20s Name of file containing PQG parameters (dsa only)\n",
1328 " -q pqgfile");
1329 #ifdef NSS_ENABLE_ECC
1330 FPS "%-20s Elliptic curve name (ec only)\n",
1331 " -q curve-name");
1332 FPS "%-20s See the \"-G\" option for a full list of supported names.\n",
1333 "");
1334 #endif /* NSS_ENABLE_ECC */
1335 FPS "%-20s Self sign\n",
1336 " -x");
1337 FPS "%-20s Cert serial number\n",
1338 " -m serial-number");
1339 FPS "%-20s Time Warp\n",
1340 " -w warp-months");
1341 FPS "%-20s Months valid (default is 3)\n",
1342 " -v months-valid");
1343 FPS "%-20s Specify the password file\n",
1344 " -f pwfile");
1345 FPS "%-20s Cert database directory (default is ~/.netscape)\n",
1346 " -d certdir");
1347 FPS "%-20s Cert & Key database prefix\n",
1348 " -P dbprefix");
1349 FPS "%-20s Specify the contact phone number (\"123-456-7890\")\n",
1350 " -p phone");
1351 FPS "%-20s Create key usage extension\n",
1352 " -1 ");
1353 FPS "%-20s Create basic constraint extension\n",
1354 " -2 ");
1355 FPS "%-20s Create authority key ID extension\n",
1356 " -3 ");
1357 FPS "%-20s Create crl distribution point extension\n",
1358 " -4 ");
1359 FPS "%-20s Create netscape cert type extension\n",
1360 " -5 ");
1361 FPS "%-20s Create extended key usage extension\n",
1362 " -6 ");
1363 FPS "%-20s Create an email subject alt name extension\n",
1364 " -7 ");
1365 FPS "%-20s Create a DNS subject alt name extension\n",
1366 " -8 ");
1367 FPS "%-20s Create an Authority Information Access extension\n",
1368 " --extAIA ");
1369 FPS "%-20s Create a Subject Information Access extension\n",
1370 " --extSIA ");
1371 FPS "%-20s Create a Certificate Policies extension\n",
1372 " --extCP ");
1373 FPS "%-20s Create a Policy Mappings extension\n",
1374 " --extPM ");
1375 FPS "%-20s Create a Policy Constraints extension\n",
1376 " --extPC ");
1377 FPS "%-20s Create an Inhibit Any Policy extension\n",
1378 " --extIA ");
1379 FPS "%-20s Create a subject key ID extension\n",
1380 " --extSKID ");
1381 FPS "\n");
1383 exit(1);
1384 #undef FPS
1388 static CERTCertificate *
1389 MakeV1Cert( CERTCertDBHandle * handle,
1390 CERTCertificateRequest *req,
1391 char * issuerNickName,
1392 PRBool selfsign,
1393 unsigned int serialNumber,
1394 int warpmonths,
1395 int validityMonths)
1397 CERTCertificate *issuerCert = NULL;
1398 CERTValidity *validity;
1399 CERTCertificate *cert = NULL;
1400 PRExplodedTime printableTime;
1401 PRTime now, after;
1403 if ( !selfsign ) {
1404 issuerCert = CERT_FindCertByNicknameOrEmailAddr(handle, issuerNickName);
1405 if (!issuerCert) {
1406 SECU_PrintError(progName, "could not find certificate named \"%s\"",
1407 issuerNickName);
1408 return NULL;
1412 now = PR_Now();
1413 PR_ExplodeTime (now, PR_GMTParameters, &printableTime);
1414 if ( warpmonths ) {
1415 printableTime.tm_month += warpmonths;
1416 now = PR_ImplodeTime (&printableTime);
1417 PR_ExplodeTime (now, PR_GMTParameters, &printableTime);
1419 printableTime.tm_month += validityMonths;
1420 after = PR_ImplodeTime (&printableTime);
1422 /* note that the time is now in micro-second unit */
1423 validity = CERT_CreateValidity (now, after);
1424 if (validity) {
1425 cert = CERT_CreateCertificate(serialNumber,
1426 (selfsign ? &req->subject
1427 : &issuerCert->subject),
1428 validity, req);
1430 CERT_DestroyValidity(validity);
1432 if ( issuerCert ) {
1433 CERT_DestroyCertificate (issuerCert);
1436 return(cert);
1439 static SECItem *
1440 SignCert(CERTCertDBHandle *handle, CERTCertificate *cert, PRBool selfsign,
1441 SECOidTag hashAlgTag,
1442 SECKEYPrivateKey *privKey, char *issuerNickName, void *pwarg)
1444 SECItem der;
1445 SECItem *result = NULL;
1446 SECKEYPrivateKey *caPrivateKey = NULL;
1447 SECStatus rv;
1448 PRArenaPool *arena;
1449 SECOidTag algID;
1450 void *dummy;
1452 if( !selfsign ) {
1453 CERTCertificate *issuer = PK11_FindCertFromNickname(issuerNickName, pwarg);
1454 if( (CERTCertificate *)NULL == issuer ) {
1455 SECU_PrintError(progName, "unable to find issuer with nickname %s",
1456 issuerNickName);
1457 return (SECItem *)NULL;
1460 privKey = caPrivateKey = PK11_FindKeyByAnyCert(issuer, pwarg);
1461 CERT_DestroyCertificate(issuer);
1462 if (caPrivateKey == NULL) {
1463 SECU_PrintError(progName, "unable to retrieve key %s", issuerNickName);
1464 return NULL;
1468 arena = cert->arena;
1470 algID = SEC_GetSignatureAlgorithmOidTag(privKey->keyType, hashAlgTag);
1471 if (algID == SEC_OID_UNKNOWN) {
1472 fprintf(stderr, "Unknown key or hash type for issuer.");
1473 goto done;
1476 rv = SECOID_SetAlgorithmID(arena, &cert->signature, algID, 0);
1477 if (rv != SECSuccess) {
1478 fprintf(stderr, "Could not set signature algorithm id.");
1479 goto done;
1482 /* we only deal with cert v3 here */
1483 *(cert->version.data) = 2;
1484 cert->version.len = 1;
1486 der.len = 0;
1487 der.data = NULL;
1488 dummy = SEC_ASN1EncodeItem (arena, &der, cert,
1489 SEC_ASN1_GET(CERT_CertificateTemplate));
1490 if (!dummy) {
1491 fprintf (stderr, "Could not encode certificate.\n");
1492 goto done;
1495 result = (SECItem *) PORT_ArenaZAlloc (arena, sizeof (SECItem));
1496 if (result == NULL) {
1497 fprintf (stderr, "Could not allocate item for certificate data.\n");
1498 goto done;
1501 rv = SEC_DerSignData(arena, result, der.data, der.len, privKey, algID);
1502 if (rv != SECSuccess) {
1503 fprintf (stderr, "Could not sign encoded certificate data.\n");
1504 /* result allocated out of the arena, it will be freed
1505 * when the arena is freed */
1506 result = NULL;
1507 goto done;
1509 cert->derCert = *result;
1510 done:
1511 if (caPrivateKey) {
1512 SECKEY_DestroyPrivateKey(caPrivateKey);
1514 return result;
1517 static SECStatus
1518 CreateCert(
1519 CERTCertDBHandle *handle,
1520 char * issuerNickName,
1521 PRFileDesc *inFile,
1522 PRFileDesc *outFile,
1523 SECKEYPrivateKey *selfsignprivkey,
1524 void *pwarg,
1525 SECOidTag hashAlgTag,
1526 unsigned int serialNumber,
1527 int warpmonths,
1528 int validityMonths,
1529 const char *emailAddrs,
1530 const char *dnsNames,
1531 PRBool ascii,
1532 PRBool selfsign,
1533 certutilExtnList extnList)
1535 void * extHandle;
1536 SECItem * certDER;
1537 PRArenaPool *arena = NULL;
1538 CERTCertificate *subjectCert = NULL;
1539 CERTCertificateRequest *certReq = NULL;
1540 SECStatus rv = SECSuccess;
1541 SECItem reqDER;
1542 CERTCertExtension **CRexts;
1544 reqDER.data = NULL;
1545 do {
1546 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1547 if (!arena) {
1548 GEN_BREAK (SECFailure);
1551 /* Create a certrequest object from the input cert request der */
1552 certReq = GetCertRequest(inFile, ascii);
1553 if (certReq == NULL) {
1554 GEN_BREAK (SECFailure)
1557 subjectCert = MakeV1Cert (handle, certReq, issuerNickName, selfsign,
1558 serialNumber, warpmonths, validityMonths);
1559 if (subjectCert == NULL) {
1560 GEN_BREAK (SECFailure)
1564 extHandle = CERT_StartCertExtensions (subjectCert);
1565 if (extHandle == NULL) {
1566 GEN_BREAK (SECFailure)
1569 rv = AddExtensions(extHandle, emailAddrs, dnsNames, extnList);
1570 if (rv != SECSuccess) {
1571 GEN_BREAK (SECFailure)
1574 if (certReq->attributes != NULL &&
1575 certReq->attributes[0] != NULL &&
1576 certReq->attributes[0]->attrType.data != NULL &&
1577 certReq->attributes[0]->attrType.len > 0 &&
1578 SECOID_FindOIDTag(&certReq->attributes[0]->attrType)
1579 == SEC_OID_PKCS9_EXTENSION_REQUEST) {
1580 rv = CERT_GetCertificateRequestExtensions(certReq, &CRexts);
1581 if (rv != SECSuccess)
1582 break;
1583 rv = CERT_MergeExtensions(extHandle, CRexts);
1584 if (rv != SECSuccess)
1585 break;
1588 CERT_FinishExtensions(extHandle);
1590 certDER = SignCert(handle, subjectCert, selfsign, hashAlgTag,
1591 selfsignprivkey, issuerNickName,pwarg);
1593 if (certDER) {
1594 if (ascii) {
1595 PR_fprintf(outFile, "%s\n%s\n%s\n", NS_CERT_HEADER,
1596 BTOA_DataToAscii(certDER->data, certDER->len),
1597 NS_CERT_TRAILER);
1598 } else {
1599 PR_Write(outFile, certDER->data, certDER->len);
1603 } while (0);
1604 CERT_DestroyCertificateRequest (certReq);
1605 CERT_DestroyCertificate (subjectCert);
1606 PORT_FreeArena (arena, PR_FALSE);
1607 if (rv != SECSuccess) {
1608 PRErrorCode perr = PR_GetError();
1609 fprintf(stderr, "%s: unable to create cert (%s)\n", progName,
1610 SECU_Strerror(perr));
1612 return (rv);
1617 * map a class to a user presentable string
1619 static const char *objClassArray[] = {
1620 "Data",
1621 "Certificate",
1622 "Public Key",
1623 "Private Key",
1624 "Secret Key",
1625 "Hardware Feature",
1626 "Domain Parameters",
1627 "Mechanism"
1630 static const char *objNSSClassArray[] = {
1631 "CKO_NSS",
1632 "Crl",
1633 "SMIME Record",
1634 "Trust",
1635 "Builtin Root List"
1639 const char *
1640 getObjectClass(CK_ULONG classType)
1642 static char buf[sizeof(CK_ULONG)*2+3];
1644 if (classType <= CKO_MECHANISM) {
1645 return objClassArray[classType];
1647 if (classType >= CKO_NSS && classType <= CKO_NSS_BUILTIN_ROOT_LIST) {
1648 return objNSSClassArray[classType - CKO_NSS];
1650 sprintf(buf, "0x%lx", classType);
1651 return buf;
1654 char *mkNickname(unsigned char *data, int len)
1656 char *nick = PORT_Alloc(len+1);
1657 if (!nick) {
1658 return nick;
1660 PORT_Memcpy(nick, data, len);
1661 nick[len] = 0;
1662 return nick;
1666 * dump a PK11_MergeTokens error log to the console
1668 void
1669 DumpMergeLog(const char *progname, PK11MergeLog *log)
1671 PK11MergeLogNode *node;
1673 for (node = log->head; node; node = node->next) {
1674 SECItem attrItem;
1675 char *nickname = NULL;
1676 const char *objectClass = NULL;
1677 SECStatus rv;
1679 attrItem.data = NULL;
1680 rv = PK11_ReadRawAttribute(PK11_TypeGeneric, node->object,
1681 CKA_LABEL, &attrItem);
1682 if (rv == SECSuccess) {
1683 nickname = mkNickname(attrItem.data, attrItem.len);
1684 PORT_Free(attrItem.data);
1686 attrItem.data = NULL;
1687 rv = PK11_ReadRawAttribute(PK11_TypeGeneric, node->object,
1688 CKA_CLASS, &attrItem);
1689 if (rv == SECSuccess) {
1690 if (attrItem.len == sizeof(CK_ULONG)) {
1691 objectClass = getObjectClass(*(CK_ULONG *)attrItem.data);
1693 PORT_Free(attrItem.data);
1696 fprintf(stderr, "%s: Could not merge object %s (type %s): %s\n",
1697 progName,
1698 nickname ? nickname : "unnamed",
1699 objectClass ? objectClass : "unknown",
1700 SECU_Strerror(node->error));
1702 if (nickname) {
1703 PORT_Free(nickname);
1708 /* Certutil commands */
1709 enum {
1710 cmd_AddCert = 0,
1711 cmd_CreateNewCert,
1712 cmd_DeleteCert,
1713 cmd_AddEmailCert,
1714 cmd_DeleteKey,
1715 cmd_GenKeyPair,
1716 cmd_PrintHelp,
1717 cmd_ListKeys,
1718 cmd_ListCerts,
1719 cmd_ModifyCertTrust,
1720 cmd_NewDBs,
1721 cmd_DumpChain,
1722 cmd_CertReq,
1723 cmd_CreateAndAddCert,
1724 cmd_TokenReset,
1725 cmd_ListModules,
1726 cmd_CheckCertValidity,
1727 cmd_ChangePassword,
1728 cmd_Version,
1729 cmd_Batch,
1730 cmd_Merge,
1731 cmd_UpgradeMerge, /* test only */
1734 /* Certutil options */
1735 enum certutilOpts {
1736 opt_SSOPass = 0,
1737 opt_AddKeyUsageExt,
1738 opt_AddBasicConstraintExt,
1739 opt_AddAuthorityKeyIDExt,
1740 opt_AddCRLDistPtsExt,
1741 opt_AddNSCertTypeExt,
1742 opt_AddExtKeyUsageExt,
1743 opt_ExtendedEmailAddrs,
1744 opt_ExtendedDNSNames,
1745 opt_ASCIIForIO,
1746 opt_ValidityTime,
1747 opt_IssuerName,
1748 opt_CertDir,
1749 opt_VerifySig,
1750 opt_PasswordFile,
1751 opt_KeySize,
1752 opt_TokenName,
1753 opt_InputFile,
1754 opt_KeyIndex,
1755 opt_KeyType,
1756 opt_DetailedInfo,
1757 opt_SerialNumber,
1758 opt_Nickname,
1759 opt_OutputFile,
1760 opt_PhoneNumber,
1761 opt_DBPrefix,
1762 opt_PQGFile,
1763 opt_BinaryDER,
1764 opt_Subject,
1765 opt_Trust,
1766 opt_Usage,
1767 opt_Validity,
1768 opt_OffsetMonths,
1769 opt_SelfSign,
1770 opt_RW,
1771 opt_Exponent,
1772 opt_NoiseFile,
1773 opt_Hash,
1774 opt_NewPasswordFile,
1775 opt_AddAuthInfoAccExt,
1776 opt_AddSubjInfoAccExt,
1777 opt_AddCertPoliciesExt,
1778 opt_AddPolicyMapExt,
1779 opt_AddPolicyConstrExt,
1780 opt_AddInhibAnyExt,
1781 opt_AddSubjectKeyIDExt,
1782 opt_SourceDir,
1783 opt_SourcePrefix,
1784 opt_UpgradeID,
1785 opt_UpgradeTokenName
1788 static const
1789 secuCommandFlag commands_init[] =
1791 { /* cmd_AddCert */ 'A', PR_FALSE, 0, PR_FALSE },
1792 { /* cmd_CreateNewCert */ 'C', PR_FALSE, 0, PR_FALSE },
1793 { /* cmd_DeleteCert */ 'D', PR_FALSE, 0, PR_FALSE },
1794 { /* cmd_AddEmailCert */ 'E', PR_FALSE, 0, PR_FALSE },
1795 { /* cmd_DeleteKey */ 'F', PR_FALSE, 0, PR_FALSE },
1796 { /* cmd_GenKeyPair */ 'G', PR_FALSE, 0, PR_FALSE },
1797 { /* cmd_PrintHelp */ 'H', PR_FALSE, 0, PR_FALSE },
1798 { /* cmd_ListKeys */ 'K', PR_FALSE, 0, PR_FALSE },
1799 { /* cmd_ListCerts */ 'L', PR_FALSE, 0, PR_FALSE },
1800 { /* cmd_ModifyCertTrust */ 'M', PR_FALSE, 0, PR_FALSE },
1801 { /* cmd_NewDBs */ 'N', PR_FALSE, 0, PR_FALSE },
1802 { /* cmd_DumpChain */ 'O', PR_FALSE, 0, PR_FALSE },
1803 { /* cmd_CertReq */ 'R', PR_FALSE, 0, PR_FALSE },
1804 { /* cmd_CreateAndAddCert */ 'S', PR_FALSE, 0, PR_FALSE },
1805 { /* cmd_TokenReset */ 'T', PR_FALSE, 0, PR_FALSE },
1806 { /* cmd_ListModules */ 'U', PR_FALSE, 0, PR_FALSE },
1807 { /* cmd_CheckCertValidity */ 'V', PR_FALSE, 0, PR_FALSE },
1808 { /* cmd_ChangePassword */ 'W', PR_FALSE, 0, PR_FALSE },
1809 { /* cmd_Version */ 'Y', PR_FALSE, 0, PR_FALSE },
1810 { /* cmd_Batch */ 'B', PR_FALSE, 0, PR_FALSE },
1811 { /* cmd_Merge */ 0, PR_FALSE, 0, PR_FALSE, "merge" },
1812 { /* cmd_UpgradeMerge */ 0, PR_FALSE, 0, PR_FALSE,
1813 "upgrade-merge" }
1815 #define NUM_COMMANDS ((sizeof commands_init) / (sizeof commands_init[0]))
1817 static const
1818 secuCommandFlag options_init[] =
1820 { /* opt_SSOPass */ '0', PR_TRUE, 0, PR_FALSE },
1821 { /* opt_AddKeyUsageExt */ '1', PR_FALSE, 0, PR_FALSE },
1822 { /* opt_AddBasicConstraintExt*/ '2', PR_FALSE, 0, PR_FALSE },
1823 { /* opt_AddAuthorityKeyIDExt*/ '3', PR_FALSE, 0, PR_FALSE },
1824 { /* opt_AddCRLDistPtsExt */ '4', PR_FALSE, 0, PR_FALSE },
1825 { /* opt_AddNSCertTypeExt */ '5', PR_FALSE, 0, PR_FALSE },
1826 { /* opt_AddExtKeyUsageExt */ '6', PR_FALSE, 0, PR_FALSE },
1827 { /* opt_ExtendedEmailAddrs */ '7', PR_TRUE, 0, PR_FALSE },
1828 { /* opt_ExtendedDNSNames */ '8', PR_TRUE, 0, PR_FALSE },
1829 { /* opt_ASCIIForIO */ 'a', PR_FALSE, 0, PR_FALSE },
1830 { /* opt_ValidityTime */ 'b', PR_TRUE, 0, PR_FALSE },
1831 { /* opt_IssuerName */ 'c', PR_TRUE, 0, PR_FALSE },
1832 { /* opt_CertDir */ 'd', PR_TRUE, 0, PR_FALSE },
1833 { /* opt_VerifySig */ 'e', PR_FALSE, 0, PR_FALSE },
1834 { /* opt_PasswordFile */ 'f', PR_TRUE, 0, PR_FALSE },
1835 { /* opt_KeySize */ 'g', PR_TRUE, 0, PR_FALSE },
1836 { /* opt_TokenName */ 'h', PR_TRUE, 0, PR_FALSE },
1837 { /* opt_InputFile */ 'i', PR_TRUE, 0, PR_FALSE },
1838 { /* opt_KeyIndex */ 'j', PR_TRUE, 0, PR_FALSE },
1839 { /* opt_KeyType */ 'k', PR_TRUE, 0, PR_FALSE },
1840 { /* opt_DetailedInfo */ 'l', PR_FALSE, 0, PR_FALSE },
1841 { /* opt_SerialNumber */ 'm', PR_TRUE, 0, PR_FALSE },
1842 { /* opt_Nickname */ 'n', PR_TRUE, 0, PR_FALSE },
1843 { /* opt_OutputFile */ 'o', PR_TRUE, 0, PR_FALSE },
1844 { /* opt_PhoneNumber */ 'p', PR_TRUE, 0, PR_FALSE },
1845 { /* opt_DBPrefix */ 'P', PR_TRUE, 0, PR_FALSE },
1846 { /* opt_PQGFile */ 'q', PR_TRUE, 0, PR_FALSE },
1847 { /* opt_BinaryDER */ 'r', PR_FALSE, 0, PR_FALSE },
1848 { /* opt_Subject */ 's', PR_TRUE, 0, PR_FALSE },
1849 { /* opt_Trust */ 't', PR_TRUE, 0, PR_FALSE },
1850 { /* opt_Usage */ 'u', PR_TRUE, 0, PR_FALSE },
1851 { /* opt_Validity */ 'v', PR_TRUE, 0, PR_FALSE },
1852 { /* opt_OffsetMonths */ 'w', PR_TRUE, 0, PR_FALSE },
1853 { /* opt_SelfSign */ 'x', PR_FALSE, 0, PR_FALSE },
1854 { /* opt_RW */ 'X', PR_FALSE, 0, PR_FALSE },
1855 { /* opt_Exponent */ 'y', PR_TRUE, 0, PR_FALSE },
1856 { /* opt_NoiseFile */ 'z', PR_TRUE, 0, PR_FALSE },
1857 { /* opt_Hash */ 'Z', PR_TRUE, 0, PR_FALSE },
1858 { /* opt_NewPasswordFile */ '@', PR_TRUE, 0, PR_FALSE },
1859 { /* opt_AddAuthInfoAccExt */ 0, PR_FALSE, 0, PR_FALSE, "extAIA" },
1860 { /* opt_AddSubjInfoAccExt */ 0, PR_FALSE, 0, PR_FALSE, "extSIA" },
1861 { /* opt_AddCertPoliciesExt */ 0, PR_FALSE, 0, PR_FALSE, "extCP" },
1862 { /* opt_AddPolicyMapExt */ 0, PR_FALSE, 0, PR_FALSE, "extPM" },
1863 { /* opt_AddPolicyConstrExt */ 0, PR_FALSE, 0, PR_FALSE, "extPC" },
1864 { /* opt_AddInhibAnyExt */ 0, PR_FALSE, 0, PR_FALSE, "extIA" },
1865 { /* opt_AddSubjectKeyIDExt */ 0, PR_FALSE, 0, PR_FALSE,
1866 "extSKID" },
1867 { /* opt_SourceDir */ 0, PR_TRUE, 0, PR_FALSE,
1868 "source-dir"},
1869 { /* opt_SourcePrefix */ 0, PR_TRUE, 0, PR_FALSE,
1870 "source-prefix"},
1871 { /* opt_UpgradeID */ 0, PR_TRUE, 0, PR_FALSE,
1872 "upgrade-id"},
1873 { /* opt_UpgradeTokenName */ 0, PR_TRUE, 0, PR_FALSE,
1874 "upgrade-token-name"},
1876 #define NUM_OPTIONS ((sizeof options_init) / (sizeof options_init[0]))
1878 static secuCommandFlag certutil_commands[NUM_COMMANDS];
1879 static secuCommandFlag certutil_options [NUM_OPTIONS ];
1881 static const secuCommand certutil = {
1882 NUM_COMMANDS,
1883 NUM_OPTIONS,
1884 certutil_commands,
1885 certutil_options
1888 static certutilExtnList certutil_extns;
1890 static int
1891 certutil_main(int argc, char **argv, PRBool initialize)
1893 CERTCertDBHandle *certHandle;
1894 PK11SlotInfo *slot = NULL;
1895 CERTName * subject = 0;
1896 PRFileDesc *inFile = PR_STDIN;
1897 PRFileDesc *outFile = NULL;
1898 char * certfile = "tempcert";
1899 char * certreqfile = "tempcertreq";
1900 char * slotname = "internal";
1901 char * certPrefix = "";
1902 char * sourceDir = "";
1903 char * srcCertPrefix = "";
1904 char * upgradeID = "";
1905 char * upgradeTokenName = "";
1906 KeyType keytype = rsaKey;
1907 char * name = NULL;
1908 char * keysource = NULL;
1909 SECOidTag hashAlgTag = SEC_OID_UNKNOWN;
1910 int keysize = DEFAULT_KEY_BITS;
1911 int publicExponent = 0x010001;
1912 unsigned int serialNumber = 0;
1913 int warpmonths = 0;
1914 int validityMonths = 3;
1915 int commandsEntered = 0;
1916 char commandToRun = '\0';
1917 secuPWData pwdata = { PW_NONE, 0 };
1918 secuPWData pwdata2 = { PW_NONE, 0 };
1919 PRBool readOnly = PR_FALSE;
1920 PRBool initialized = PR_FALSE;
1922 SECKEYPrivateKey *privkey = NULL;
1923 SECKEYPublicKey *pubkey = NULL;
1925 int i;
1926 SECStatus rv;
1928 progName = PORT_Strrchr(argv[0], '/');
1929 progName = progName ? progName+1 : argv[0];
1930 memcpy(certutil_commands, commands_init, sizeof commands_init);
1931 memcpy(certutil_options, options_init, sizeof options_init);
1933 rv = SECU_ParseCommandLine(argc, argv, progName, &certutil);
1935 if (rv != SECSuccess)
1936 Usage(progName);
1938 if (certutil.commands[cmd_PrintHelp].activated)
1939 LongUsage(progName);
1941 if (certutil.options[opt_PasswordFile].arg) {
1942 pwdata.source = PW_FROMFILE;
1943 pwdata.data = certutil.options[opt_PasswordFile].arg;
1945 if (certutil.options[opt_NewPasswordFile].arg) {
1946 pwdata2.source = PW_FROMFILE;
1947 pwdata2.data = certutil.options[opt_NewPasswordFile].arg;
1950 if (certutil.options[opt_CertDir].activated)
1951 SECU_ConfigDirectory(certutil.options[opt_CertDir].arg);
1953 if (certutil.options[opt_SourceDir].activated)
1954 sourceDir = certutil.options[opt_SourceDir].arg;
1956 if (certutil.options[opt_UpgradeID].activated)
1957 upgradeID = certutil.options[opt_UpgradeID].arg;
1959 if (certutil.options[opt_UpgradeTokenName].activated)
1960 upgradeTokenName = certutil.options[opt_UpgradeTokenName].arg;
1962 if (certutil.options[opt_KeySize].activated) {
1963 keysize = PORT_Atoi(certutil.options[opt_KeySize].arg);
1964 if ((keysize < MIN_KEY_BITS) || (keysize > MAX_KEY_BITS)) {
1965 PR_fprintf(PR_STDERR,
1966 "%s -g: Keysize must be between %d and %d.\n",
1967 progName, MIN_KEY_BITS, MAX_KEY_BITS);
1968 return 255;
1970 #ifdef NSS_ENABLE_ECC
1971 if (keytype == ecKey) {
1972 PR_fprintf(PR_STDERR, "%s -g: Not for ec keys.\n", progName);
1973 return 255;
1975 #endif /* NSS_ENABLE_ECC */
1979 /* -h specify token name */
1980 if (certutil.options[opt_TokenName].activated) {
1981 if (PL_strcmp(certutil.options[opt_TokenName].arg, "all") == 0)
1982 slotname = NULL;
1983 else
1984 slotname = PL_strdup(certutil.options[opt_TokenName].arg);
1987 /* -Z hash type */
1988 if (certutil.options[opt_Hash].activated) {
1989 char * arg = certutil.options[opt_Hash].arg;
1990 hashAlgTag = SECU_StringToSignatureAlgTag(arg);
1991 if (hashAlgTag == SEC_OID_UNKNOWN) {
1992 PR_fprintf(PR_STDERR, "%s -Z: %s is not a recognized type.\n",
1993 progName, arg);
1994 return 255;
1998 /* -k key type */
1999 if (certutil.options[opt_KeyType].activated) {
2000 char * arg = certutil.options[opt_KeyType].arg;
2001 if (PL_strcmp(arg, "rsa") == 0) {
2002 keytype = rsaKey;
2003 } else if (PL_strcmp(arg, "dsa") == 0) {
2004 keytype = dsaKey;
2005 #ifdef NSS_ENABLE_ECC
2006 } else if (PL_strcmp(arg, "ec") == 0) {
2007 keytype = ecKey;
2008 #endif /* NSS_ENABLE_ECC */
2009 } else if (PL_strcmp(arg, "all") == 0) {
2010 keytype = nullKey;
2011 } else {
2012 /* use an existing private/public key pair */
2013 keysource = arg;
2015 } else if (certutil.commands[cmd_ListKeys].activated) {
2016 keytype = nullKey;
2019 /* -m serial number */
2020 if (certutil.options[opt_SerialNumber].activated) {
2021 int sn = PORT_Atoi(certutil.options[opt_SerialNumber].arg);
2022 if (sn < 0) {
2023 PR_fprintf(PR_STDERR, "%s -m: %s is not a valid serial number.\n",
2024 progName, certutil.options[opt_SerialNumber].arg);
2025 return 255;
2027 serialNumber = sn;
2030 /* -P certdb name prefix */
2031 if (certutil.options[opt_DBPrefix].activated) {
2032 if (certutil.options[opt_DBPrefix].arg) {
2033 certPrefix = strdup(certutil.options[opt_DBPrefix].arg);
2034 } else {
2035 Usage(progName);
2039 /* --source-prefix certdb name prefix */
2040 if (certutil.options[opt_SourcePrefix].activated) {
2041 if (certutil.options[opt_SourcePrefix].arg) {
2042 srcCertPrefix = strdup(certutil.options[opt_SourcePrefix].arg);
2043 } else {
2044 Usage(progName);
2048 /* -q PQG file or curve name */
2049 if (certutil.options[opt_PQGFile].activated) {
2050 #ifdef NSS_ENABLE_ECC
2051 if ((keytype != dsaKey) && (keytype != ecKey)) {
2052 PR_fprintf(PR_STDERR, "%s -q: specifies a PQG file for DSA keys" \
2053 " (-k dsa) or a named curve for EC keys (-k ec)\n)",
2054 progName);
2055 #else /* } */
2056 if (keytype != dsaKey) {
2057 PR_fprintf(PR_STDERR, "%s -q: PQG file is for DSA key (-k dsa).\n)",
2058 progName);
2059 #endif /* NSS_ENABLE_ECC */
2060 return 255;
2064 /* -s subject name */
2065 if (certutil.options[opt_Subject].activated) {
2066 subject = CERT_AsciiToName(certutil.options[opt_Subject].arg);
2067 if (!subject) {
2068 PR_fprintf(PR_STDERR, "%s -s: improperly formatted name: \"%s\"\n",
2069 progName, certutil.options[opt_Subject].arg);
2070 return 255;
2074 /* -v validity period */
2075 if (certutil.options[opt_Validity].activated) {
2076 validityMonths = PORT_Atoi(certutil.options[opt_Validity].arg);
2077 if (validityMonths < 0) {
2078 PR_fprintf(PR_STDERR, "%s -v: incorrect validity period: \"%s\"\n",
2079 progName, certutil.options[opt_Validity].arg);
2080 return 255;
2084 /* -w warp months */
2085 if (certutil.options[opt_OffsetMonths].activated)
2086 warpmonths = PORT_Atoi(certutil.options[opt_OffsetMonths].arg);
2088 /* -y public exponent (for RSA) */
2089 if (certutil.options[opt_Exponent].activated) {
2090 publicExponent = PORT_Atoi(certutil.options[opt_Exponent].arg);
2091 if ((publicExponent != 3) &&
2092 (publicExponent != 17) &&
2093 (publicExponent != 65537)) {
2094 PR_fprintf(PR_STDERR, "%s -y: incorrect public exponent %d.",
2095 progName, publicExponent);
2096 PR_fprintf(PR_STDERR, "Must be 3, 17, or 65537.\n");
2097 return 255;
2101 /* Check number of commands entered. */
2102 commandsEntered = 0;
2103 for (i=0; i< certutil.numCommands; i++) {
2104 if (certutil.commands[i].activated) {
2105 commandToRun = certutil.commands[i].flag;
2106 commandsEntered++;
2108 if (commandsEntered > 1)
2109 break;
2111 if (commandsEntered > 1) {
2112 PR_fprintf(PR_STDERR, "%s: only one command at a time!\n", progName);
2113 PR_fprintf(PR_STDERR, "You entered: ");
2114 for (i=0; i< certutil.numCommands; i++) {
2115 if (certutil.commands[i].activated)
2116 PR_fprintf(PR_STDERR, " -%c", certutil.commands[i].flag);
2118 PR_fprintf(PR_STDERR, "\n");
2119 return 255;
2121 if (commandsEntered == 0) {
2122 PR_fprintf(PR_STDERR, "%s: you must enter a command!\n", progName);
2123 Usage(progName);
2126 if (certutil.commands[cmd_ListCerts].activated ||
2127 certutil.commands[cmd_PrintHelp].activated ||
2128 certutil.commands[cmd_ListKeys].activated ||
2129 certutil.commands[cmd_ListModules].activated ||
2130 certutil.commands[cmd_CheckCertValidity].activated ||
2131 certutil.commands[cmd_Version].activated ) {
2132 readOnly = !certutil.options[opt_RW].activated;
2135 /* -A, -D, -F, -M, -S, -V, and all require -n */
2136 if ((certutil.commands[cmd_AddCert].activated ||
2137 certutil.commands[cmd_DeleteCert].activated ||
2138 certutil.commands[cmd_DeleteKey].activated ||
2139 certutil.commands[cmd_DumpChain].activated ||
2140 certutil.commands[cmd_ModifyCertTrust].activated ||
2141 certutil.commands[cmd_CreateAndAddCert].activated ||
2142 certutil.commands[cmd_CheckCertValidity].activated) &&
2143 !certutil.options[opt_Nickname].activated) {
2144 PR_fprintf(PR_STDERR,
2145 "%s -%c: nickname is required for this command (-n).\n",
2146 progName, commandToRun);
2147 return 255;
2150 /* -A, -E, -M, -S require trust */
2151 if ((certutil.commands[cmd_AddCert].activated ||
2152 certutil.commands[cmd_AddEmailCert].activated ||
2153 certutil.commands[cmd_ModifyCertTrust].activated ||
2154 certutil.commands[cmd_CreateAndAddCert].activated) &&
2155 !certutil.options[opt_Trust].activated) {
2156 PR_fprintf(PR_STDERR,
2157 "%s -%c: trust is required for this command (-t).\n",
2158 progName, commandToRun);
2159 return 255;
2162 /* if -L is given raw or ascii mode, it must be for only one cert. */
2163 if (certutil.commands[cmd_ListCerts].activated &&
2164 (certutil.options[opt_ASCIIForIO].activated ||
2165 certutil.options[opt_BinaryDER].activated) &&
2166 !certutil.options[opt_Nickname].activated) {
2167 PR_fprintf(PR_STDERR,
2168 "%s: nickname is required to dump cert in raw or ascii mode.\n",
2169 progName);
2170 return 255;
2173 /* -L can only be in (raw || ascii). */
2174 if (certutil.commands[cmd_ListCerts].activated &&
2175 certutil.options[opt_ASCIIForIO].activated &&
2176 certutil.options[opt_BinaryDER].activated) {
2177 PR_fprintf(PR_STDERR,
2178 "%s: cannot specify both -r and -a when dumping cert.\n",
2179 progName);
2180 return 255;
2183 /* For now, deny -C -x combination */
2184 if (certutil.commands[cmd_CreateNewCert].activated &&
2185 certutil.options[opt_SelfSign].activated) {
2186 PR_fprintf(PR_STDERR,
2187 "%s: self-signing a cert request is not supported.\n",
2188 progName);
2189 return 255;
2192 /* If making a cert request, need a subject. */
2193 if ((certutil.commands[cmd_CertReq].activated ||
2194 certutil.commands[cmd_CreateAndAddCert].activated) &&
2195 !certutil.options[opt_Subject].activated) {
2196 PR_fprintf(PR_STDERR,
2197 "%s -%c: subject is required to create a cert request.\n",
2198 progName, commandToRun);
2199 return 255;
2202 /* If making a cert, need a serial number. */
2203 if ((certutil.commands[cmd_CreateNewCert].activated ||
2204 certutil.commands[cmd_CreateAndAddCert].activated) &&
2205 !certutil.options[opt_SerialNumber].activated) {
2206 /* Make a default serial number from the current time. */
2207 PRTime now = PR_Now();
2208 LL_USHR(now, now, 19);
2209 LL_L2UI(serialNumber, now);
2212 /* Validation needs the usage to validate for. */
2213 if (certutil.commands[cmd_CheckCertValidity].activated &&
2214 !certutil.options[opt_Usage].activated) {
2215 PR_fprintf(PR_STDERR,
2216 "%s -V: specify a usage to validate the cert for (-u).\n",
2217 progName);
2218 return 255;
2221 /* Upgrade/Merge needs a source database and a upgrade id. */
2222 if (certutil.commands[cmd_UpgradeMerge].activated &&
2223 !(certutil.options[opt_SourceDir].activated &&
2224 certutil.options[opt_UpgradeID].activated)) {
2226 PR_fprintf(PR_STDERR,
2227 "%s --upgrade-merge: specify an upgrade database directory "
2228 "(--source-dir) and\n"
2229 " an upgrade ID (--upgrade-id).\n",
2230 progName);
2231 return 255;
2234 /* Merge needs a source database */
2235 if (certutil.commands[cmd_Merge].activated &&
2236 !certutil.options[opt_SourceDir].activated) {
2239 PR_fprintf(PR_STDERR,
2240 "%s --merge: specify an source database directory "
2241 "(--source-dir)\n",
2242 progName);
2243 return 255;
2247 /* To make a cert, need either a issuer or to self-sign it. */
2248 if (certutil.commands[cmd_CreateAndAddCert].activated &&
2249 !(certutil.options[opt_IssuerName].activated ||
2250 certutil.options[opt_SelfSign].activated)) {
2251 PR_fprintf(PR_STDERR,
2252 "%s -S: must specify issuer (-c) or self-sign (-x).\n",
2253 progName);
2254 return 255;
2257 /* Using slotname == NULL for listing keys and certs on all slots,
2258 * but only that. */
2259 if (!(certutil.commands[cmd_ListKeys].activated ||
2260 certutil.commands[cmd_DumpChain].activated ||
2261 certutil.commands[cmd_ListCerts].activated) && slotname == NULL) {
2262 PR_fprintf(PR_STDERR,
2263 "%s -%c: cannot use \"-h all\" for this command.\n",
2264 progName, commandToRun);
2265 return 255;
2268 /* Using keytype == nullKey for list all key types, but only that. */
2269 if (!certutil.commands[cmd_ListKeys].activated && keytype == nullKey) {
2270 PR_fprintf(PR_STDERR,
2271 "%s -%c: cannot use \"-k all\" for this command.\n",
2272 progName, commandToRun);
2273 return 255;
2276 /* -S open outFile, temporary file for cert request. */
2277 if (certutil.commands[cmd_CreateAndAddCert].activated) {
2278 outFile = PR_Open(certreqfile,
2279 PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE, 00660);
2280 if (!outFile) {
2281 PR_fprintf(PR_STDERR,
2282 "%s -o: unable to open \"%s\" for writing (%ld, %ld)\n",
2283 progName, certreqfile,
2284 PR_GetError(), PR_GetOSError());
2285 return 255;
2289 /* Open the input file. */
2290 if (certutil.options[opt_InputFile].activated) {
2291 inFile = PR_Open(certutil.options[opt_InputFile].arg, PR_RDONLY, 0);
2292 if (!inFile) {
2293 PR_fprintf(PR_STDERR,
2294 "%s: unable to open \"%s\" for reading (%ld, %ld).\n",
2295 progName, certutil.options[opt_InputFile].arg,
2296 PR_GetError(), PR_GetOSError());
2297 return 255;
2301 /* Open the output file. */
2302 if (certutil.options[opt_OutputFile].activated && !outFile) {
2303 outFile = PR_Open(certutil.options[opt_OutputFile].arg,
2304 PR_CREATE_FILE | PR_RDWR | PR_TRUNCATE, 00660);
2305 if (!outFile) {
2306 PR_fprintf(PR_STDERR,
2307 "%s: unable to open \"%s\" for writing (%ld, %ld).\n",
2308 progName, certutil.options[opt_OutputFile].arg,
2309 PR_GetError(), PR_GetOSError());
2310 return 255;
2314 name = SECU_GetOptionArg(&certutil, opt_Nickname);
2316 PK11_SetPasswordFunc(SECU_GetModulePassword);
2318 if (PR_TRUE == initialize) {
2319 /* Initialize NSPR and NSS. */
2320 PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
2321 if (!certutil.commands[cmd_UpgradeMerge].activated) {
2322 rv = NSS_Initialize(SECU_ConfigDirectory(NULL),
2323 certPrefix, certPrefix,
2324 "secmod.db", readOnly ? NSS_INIT_READONLY: 0);
2325 } else {
2326 rv = NSS_InitWithMerge(SECU_ConfigDirectory(NULL),
2327 certPrefix, certPrefix, "secmod.db",
2328 sourceDir, srcCertPrefix, srcCertPrefix,
2329 upgradeID, upgradeTokenName,
2330 readOnly ? NSS_INIT_READONLY: 0);
2332 if (rv != SECSuccess) {
2333 SECU_PrintPRandOSError(progName);
2334 rv = SECFailure;
2335 goto shutdown;
2337 initialized = PR_TRUE;
2338 SECU_RegisterDynamicOids();
2340 certHandle = CERT_GetDefaultCertDB();
2342 if (certutil.commands[cmd_Version].activated) {
2343 printf("Certificate database content version: command not implemented.\n");
2346 if (PL_strcmp(slotname, "internal") == 0)
2347 slot = PK11_GetInternalKeySlot();
2348 else if (slotname != NULL)
2349 slot = PK11_FindSlotByName(slotname);
2354 if ( !slot && (certutil.commands[cmd_NewDBs].activated ||
2355 certutil.commands[cmd_ModifyCertTrust].activated ||
2356 certutil.commands[cmd_ChangePassword].activated ||
2357 certutil.commands[cmd_TokenReset].activated ||
2358 certutil.commands[cmd_CreateAndAddCert].activated ||
2359 certutil.commands[cmd_AddCert].activated ||
2360 certutil.commands[cmd_Merge].activated ||
2361 certutil.commands[cmd_UpgradeMerge].activated ||
2362 certutil.commands[cmd_AddEmailCert].activated)) {
2364 SECU_PrintError(progName, "could not find the slot %s",slotname);
2365 rv = SECFailure;
2366 goto shutdown;
2369 /* If creating new database, initialize the password. */
2370 if (certutil.commands[cmd_NewDBs].activated) {
2371 SECU_ChangePW2(slot, 0, 0, certutil.options[opt_PasswordFile].arg,
2372 certutil.options[opt_NewPasswordFile].arg);
2375 /* walk through the upgrade merge if necessary.
2376 * This option is more to test what some applications will want to do
2377 * to do an automatic upgrade. The --merge command is more useful for
2378 * the general case where 2 database need to be merged together.
2380 if (certutil.commands[cmd_UpgradeMerge].activated) {
2381 if (*upgradeTokenName == 0) {
2382 upgradeTokenName = upgradeID;
2384 if (!PK11_IsInternal(slot)) {
2385 fprintf(stderr, "Only internal DB's can be upgraded\n");
2386 rv = SECSuccess;
2387 goto shutdown;
2389 if (!PK11_IsRemovable(slot)) {
2390 printf("database already upgraded.\n");
2391 rv = SECSuccess;
2392 goto shutdown;
2394 if (!PK11_NeedLogin(slot)) {
2395 printf("upgrade complete!\n");
2396 rv = SECSuccess;
2397 goto shutdown;
2399 /* authenticate to the old DB if necessary */
2400 if (PORT_Strcmp(PK11_GetTokenName(slot), upgradeTokenName) == 0) {
2401 /* if we need a password, supply it. This will be the password
2402 * for the old database */
2403 rv = PK11_Authenticate(slot, PR_FALSE, &pwdata2);
2404 if (rv != SECSuccess) {
2405 SECU_PrintError(progName, "Could not get password for %s",
2406 upgradeTokenName);
2407 goto shutdown;
2410 * if we succeeded above, but still aren't logged in, that means
2411 * we just supplied the password for the old database. We may
2412 * need the password for the new database. NSS will automatically
2413 * change the token names at this point
2415 if (PK11_IsLoggedIn(slot, &pwdata)) {
2416 printf("upgrade complete!\n");
2417 rv = SECSuccess;
2418 goto shutdown;
2422 /* call PK11_IsPresent to update our cached token information */
2423 if (!PK11_IsPresent(slot)) {
2424 /* this shouldn't happen. We call isPresent to force a token
2425 * info update */
2426 fprintf(stderr, "upgrade/merge internal error\n");
2427 rv = SECFailure;
2428 goto shutdown;
2431 /* the token is now set to the state of the source database,
2432 * if we need a password for it, PK11_Authenticate will
2433 * automatically prompt us */
2434 rv = PK11_Authenticate(slot, PR_FALSE, &pwdata);
2435 if (rv == SECSuccess) {
2436 printf("upgrade complete!\n");
2437 } else {
2438 SECU_PrintError(progName, "Could not get password for %s",
2439 PK11_GetTokenName(slot));
2441 goto shutdown;
2445 * merge 2 databases.
2447 if (certutil.commands[cmd_Merge].activated) {
2448 PK11SlotInfo *sourceSlot = NULL;
2449 PK11MergeLog *log;
2450 char *modspec = PR_smprintf(
2451 "configDir='%s' certPrefix='%s' tokenDescription='%s'",
2452 sourceDir, srcCertPrefix,
2453 *upgradeTokenName ? upgradeTokenName : "Source Database");
2455 if (!modspec) {
2456 rv = SECFailure;
2457 goto shutdown;
2460 sourceSlot = SECMOD_OpenUserDB(modspec);
2461 PR_smprintf_free(modspec);
2462 if (!sourceSlot) {
2463 SECU_PrintError(progName, "couldn't open source database");
2464 rv = SECFailure;
2465 goto shutdown;
2468 rv = PK11_Authenticate(slot, PR_FALSE, &pwdata);
2469 if (rv != SECSuccess) {
2470 SECU_PrintError(progName, "Couldn't get password for %s",
2471 PK11_GetTokenName(slot));
2472 goto merge_fail;
2475 rv = PK11_Authenticate(sourceSlot, PR_FALSE, &pwdata2);
2476 if (rv != SECSuccess) {
2477 SECU_PrintError(progName, "Couldn't get password for %s",
2478 PK11_GetTokenName(sourceSlot));
2479 goto merge_fail;
2482 log = PK11_CreateMergeLog();
2483 if (!log) {
2484 rv = SECFailure;
2485 SECU_PrintError(progName, "couldn't create error log");
2486 goto merge_fail;
2489 rv = PK11_MergeTokens(slot, sourceSlot, log, &pwdata, &pwdata2);
2490 if (rv != SECSuccess) {
2491 DumpMergeLog(progName, log);
2493 PK11_DestroyMergeLog(log);
2495 merge_fail:
2496 SECMOD_CloseUserDB(sourceSlot);
2497 PK11_FreeSlot(sourceSlot);
2498 goto shutdown;
2501 /* The following 8 options are mutually exclusive with all others. */
2503 /* List certs (-L) */
2504 if (certutil.commands[cmd_ListCerts].activated) {
2505 rv = ListCerts(certHandle, name, slot,
2506 certutil.options[opt_BinaryDER].activated,
2507 certutil.options[opt_ASCIIForIO].activated,
2508 (outFile) ? outFile : PR_STDOUT, &pwdata);
2509 goto shutdown;
2511 if (certutil.commands[cmd_DumpChain].activated) {
2512 rv = DumpChain(certHandle, name);
2513 goto shutdown;
2515 /* XXX needs work */
2516 /* List keys (-K) */
2517 if (certutil.commands[cmd_ListKeys].activated) {
2518 rv = ListKeys(slot, name, 0 /*keyindex*/, keytype, PR_FALSE /*dopriv*/,
2519 &pwdata);
2520 goto shutdown;
2522 /* List modules (-U) */
2523 if (certutil.commands[cmd_ListModules].activated) {
2524 rv = ListModules();
2525 goto shutdown;
2527 /* Delete cert (-D) */
2528 if (certutil.commands[cmd_DeleteCert].activated) {
2529 rv = DeleteCert(certHandle, name);
2530 goto shutdown;
2532 /* Delete key (-F) */
2533 if (certutil.commands[cmd_DeleteKey].activated) {
2534 rv = DeleteKey(name, &pwdata);
2535 goto shutdown;
2537 /* Modify trust attribute for cert (-M) */
2538 if (certutil.commands[cmd_ModifyCertTrust].activated) {
2539 if (PK11_IsFIPS() || !PK11_IsFriendly(slot)) {
2540 rv = PK11_Authenticate(slot, PR_TRUE, &pwdata);
2541 if (rv != SECSuccess) {
2542 SECU_PrintError(progName, "could not authenticate to token %s.",
2543 PK11_GetTokenName(slot));
2544 goto shutdown;
2547 rv = ChangeTrustAttributes(certHandle, slot, name,
2548 certutil.options[opt_Trust].arg, &pwdata);
2549 goto shutdown;
2551 /* Change key db password (-W) (future - change pw to slot?) */
2552 if (certutil.commands[cmd_ChangePassword].activated) {
2553 rv = SECU_ChangePW2(slot, 0, 0, certutil.options[opt_PasswordFile].arg,
2554 certutil.options[opt_NewPasswordFile].arg);
2555 goto shutdown;
2557 /* Reset the a token */
2558 if (certutil.commands[cmd_TokenReset].activated) {
2559 char *sso_pass = "";
2561 if (certutil.options[opt_SSOPass].activated) {
2562 sso_pass = certutil.options[opt_SSOPass].arg;
2564 rv = PK11_ResetToken(slot,sso_pass);
2566 goto shutdown;
2568 /* Check cert validity against current time (-V) */
2569 if (certutil.commands[cmd_CheckCertValidity].activated) {
2570 /* XXX temporary hack for fips - must log in to get priv key */
2571 if (certutil.options[opt_VerifySig].activated) {
2572 if (slot && PK11_NeedLogin(slot)) {
2573 SECStatus newrv = PK11_Authenticate(slot, PR_TRUE, &pwdata);
2574 if (newrv != SECSuccess) {
2575 SECU_PrintError(progName, "could not authenticate to token %s.",
2576 PK11_GetTokenName(slot));
2577 goto shutdown;
2581 rv = ValidateCert(certHandle, name,
2582 certutil.options[opt_ValidityTime].arg,
2583 certutil.options[opt_Usage].arg,
2584 certutil.options[opt_VerifySig].activated,
2585 certutil.options[opt_DetailedInfo].activated,
2586 &pwdata);
2587 if (rv != SECSuccess && PR_GetError() == SEC_ERROR_INVALID_ARGS)
2588 SECU_PrintError(progName, "validation failed");
2589 goto shutdown;
2593 * Key generation
2596 /* These commands may require keygen. */
2597 if (certutil.commands[cmd_CertReq].activated ||
2598 certutil.commands[cmd_CreateAndAddCert].activated ||
2599 certutil.commands[cmd_GenKeyPair].activated) {
2600 if (keysource) {
2601 CERTCertificate *keycert;
2602 keycert = CERT_FindCertByNicknameOrEmailAddr(certHandle, keysource);
2603 if (!keycert) {
2604 keycert = PK11_FindCertFromNickname(keysource, NULL);
2605 if (!keycert) {
2606 SECU_PrintError(progName,
2607 "%s is neither a key-type nor a nickname", keysource);
2608 return SECFailure;
2611 privkey = PK11_FindKeyByDERCert(slot, keycert, &pwdata);
2612 if (privkey)
2613 pubkey = CERT_ExtractPublicKey(keycert);
2614 CERT_DestroyCertificate(keycert);
2615 if (!pubkey) {
2616 SECU_PrintError(progName,
2617 "Could not get keys from cert %s", keysource);
2618 rv = SECFailure;
2619 goto shutdown;
2621 keytype = privkey->keyType;
2622 } else {
2623 privkey =
2624 CERTUTIL_GeneratePrivateKey(keytype, slot, keysize,
2625 publicExponent,
2626 certutil.options[opt_NoiseFile].arg,
2627 &pubkey,
2628 certutil.options[opt_PQGFile].arg,
2629 &pwdata);
2630 if (privkey == NULL) {
2631 SECU_PrintError(progName, "unable to generate key(s)\n");
2632 rv = SECFailure;
2633 goto shutdown;
2636 privkey->wincx = &pwdata;
2637 PORT_Assert(pubkey != NULL);
2639 /* If all that was needed was keygen, exit. */
2640 if (certutil.commands[cmd_GenKeyPair].activated) {
2641 rv = SECSuccess;
2642 goto shutdown;
2646 /* If we need a list of extensions convert the flags into list format */
2647 if (certutil.commands[cmd_CertReq].activated ||
2648 certutil.commands[cmd_CreateAndAddCert].activated ||
2649 certutil.commands[cmd_CreateNewCert].activated) {
2650 certutil_extns[ext_keyUsage] =
2651 certutil.options[opt_AddKeyUsageExt].activated;
2652 certutil_extns[ext_basicConstraint] =
2653 certutil.options[opt_AddBasicConstraintExt].activated;
2654 certutil_extns[ext_authorityKeyID] =
2655 certutil.options[opt_AddAuthorityKeyIDExt].activated;
2656 certutil_extns[ext_subjectKeyID] =
2657 certutil.options[opt_AddSubjectKeyIDExt].activated;
2658 certutil_extns[ext_CRLDistPts] =
2659 certutil.options[opt_AddCRLDistPtsExt].activated;
2660 certutil_extns[ext_NSCertType] =
2661 certutil.options[opt_AddNSCertTypeExt].activated;
2662 certutil_extns[ext_extKeyUsage] =
2663 certutil.options[opt_AddExtKeyUsageExt].activated;
2664 certutil_extns[ext_authInfoAcc] =
2665 certutil.options[opt_AddAuthInfoAccExt].activated;
2666 certutil_extns[ext_subjInfoAcc] =
2667 certutil.options[opt_AddSubjInfoAccExt].activated;
2668 certutil_extns[ext_certPolicies] =
2669 certutil.options[opt_AddCertPoliciesExt].activated;
2670 certutil_extns[ext_policyMappings] =
2671 certutil.options[opt_AddPolicyMapExt].activated;
2672 certutil_extns[ext_policyConstr] =
2673 certutil.options[opt_AddPolicyConstrExt].activated;
2674 certutil_extns[ext_inhibitAnyPolicy] =
2675 certutil.options[opt_AddInhibAnyExt].activated;
2678 * Certificate request
2681 /* Make a cert request (-R). */
2682 if (certutil.commands[cmd_CertReq].activated) {
2683 rv = CertReq(privkey, pubkey, keytype, hashAlgTag, subject,
2684 certutil.options[opt_PhoneNumber].arg,
2685 certutil.options[opt_ASCIIForIO].activated,
2686 certutil.options[opt_ExtendedEmailAddrs].arg,
2687 certutil.options[opt_ExtendedDNSNames].arg,
2688 certutil_extns,
2689 outFile ? outFile : PR_STDOUT);
2690 if (rv)
2691 goto shutdown;
2692 privkey->wincx = &pwdata;
2696 * Certificate creation
2699 /* If making and adding a cert, create a cert request file first without
2700 * any extensions, then load it with the command line extensions
2701 * and output the cert to another file.
2703 if (certutil.commands[cmd_CreateAndAddCert].activated) {
2704 static certutilExtnList nullextnlist = {PR_FALSE};
2705 rv = CertReq(privkey, pubkey, keytype, hashAlgTag, subject,
2706 certutil.options[opt_PhoneNumber].arg,
2707 certutil.options[opt_ASCIIForIO].activated,
2708 NULL,
2709 NULL,
2710 nullextnlist,
2711 outFile ? outFile : PR_STDOUT);
2712 if (rv)
2713 goto shutdown;
2714 privkey->wincx = &pwdata;
2715 PR_Close(outFile);
2716 inFile = PR_Open(certreqfile, PR_RDONLY, 0);
2717 if (!inFile) {
2718 PR_fprintf(PR_STDERR, "Failed to open file \"%s\" (%ld, %ld).\n",
2719 certreqfile, PR_GetError(), PR_GetOSError());
2720 rv = SECFailure;
2721 goto shutdown;
2723 outFile = PR_Open(certfile,
2724 PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE, 00660);
2725 if (!outFile) {
2726 PR_fprintf(PR_STDERR, "Failed to open file \"%s\" (%ld, %ld).\n",
2727 certfile, PR_GetError(), PR_GetOSError());
2728 rv = SECFailure;
2729 goto shutdown;
2733 /* Create a certificate (-C or -S). */
2734 if (certutil.commands[cmd_CreateAndAddCert].activated ||
2735 certutil.commands[cmd_CreateNewCert].activated) {
2736 rv = CreateCert(certHandle,
2737 certutil.options[opt_IssuerName].arg,
2738 inFile, outFile, privkey, &pwdata, hashAlgTag,
2739 serialNumber, warpmonths, validityMonths,
2740 certutil.options[opt_ExtendedEmailAddrs].arg,
2741 certutil.options[opt_ExtendedDNSNames].arg,
2742 certutil.options[opt_ASCIIForIO].activated,
2743 certutil.options[opt_SelfSign].activated,
2744 certutil_extns);
2745 if (rv)
2746 goto shutdown;
2750 * Adding a cert to the database (or slot)
2753 if (certutil.commands[cmd_CreateAndAddCert].activated) {
2754 PORT_Assert(inFile != PR_STDIN);
2755 PR_Close(inFile);
2756 PR_Close(outFile);
2757 inFile = PR_Open(certfile, PR_RDONLY, 0);
2758 if (!inFile) {
2759 PR_fprintf(PR_STDERR, "Failed to open file \"%s\" (%ld, %ld).\n",
2760 certfile, PR_GetError(), PR_GetOSError());
2761 rv = SECFailure;
2762 goto shutdown;
2766 /* -A -E or -S Add the cert to the DB */
2767 if (certutil.commands[cmd_CreateAndAddCert].activated ||
2768 certutil.commands[cmd_AddCert].activated ||
2769 certutil.commands[cmd_AddEmailCert].activated) {
2770 rv = AddCert(slot, certHandle, name,
2771 certutil.options[opt_Trust].arg,
2772 inFile,
2773 certutil.options[opt_ASCIIForIO].activated,
2774 certutil.commands[cmd_AddEmailCert].activated,&pwdata);
2775 if (rv)
2776 goto shutdown;
2779 if (certutil.commands[cmd_CreateAndAddCert].activated) {
2780 PORT_Assert(inFile != PR_STDIN);
2781 PR_Close(inFile);
2782 PR_Delete(certfile);
2783 PR_Delete(certreqfile);
2786 shutdown:
2787 if (slot) {
2788 PK11_FreeSlot(slot);
2790 if (privkey) {
2791 SECKEY_DestroyPrivateKey(privkey);
2793 if (pubkey) {
2794 SECKEY_DestroyPublicKey(pubkey);
2797 /* Open the batch command file.
2799 * - If -B <command line> option is specified, the contents in the
2800 * command file will be interpreted as subsequent certutil
2801 * commands to be executed in the current certutil process
2802 * context after the current certutil command has been executed.
2803 * - Each line in the command file consists of the command
2804 * line arguments for certutil.
2805 * - The -d <configdir> option will be ignored if specified in the
2806 * command file.
2807 * - Quoting with double quote characters ("...") is supported
2808 * to allow white space in a command line argument. The
2809 * double quote character cannot be escaped and quoting cannot
2810 * be nested in this version.
2811 * - each line in the batch file is limited to 512 characters
2814 if ((SECSuccess == rv) && certutil.commands[cmd_Batch].activated) {
2815 FILE* batchFile = NULL;
2816 char nextcommand[512];
2817 if (!certutil.options[opt_InputFile].activated ||
2818 !certutil.options[opt_InputFile].arg) {
2819 PR_fprintf(PR_STDERR,
2820 "%s: no batch input file specified.\n",
2821 progName);
2822 return 255;
2824 batchFile = fopen(certutil.options[opt_InputFile].arg, "r");
2825 if (!batchFile) {
2826 PR_fprintf(PR_STDERR,
2827 "%s: unable to open \"%s\" for reading (%ld, %ld).\n",
2828 progName, certutil.options[opt_InputFile].arg,
2829 PR_GetError(), PR_GetOSError());
2830 return 255;
2832 /* read and execute command-lines in a loop */
2833 while ( (SECSuccess == rv ) &&
2834 fgets(nextcommand, sizeof(nextcommand), batchFile)) {
2835 /* we now need to split the command into argc / argv format */
2836 char* commandline = PORT_Strdup(nextcommand);
2837 PRBool invalid = PR_FALSE;
2838 int newargc = 2;
2839 char* space = NULL;
2840 char* nextarg = NULL;
2841 char** newargv = NULL;
2842 char* crlf = PORT_Strrchr(commandline, '\n');
2843 if (crlf) {
2844 *crlf = '\0';
2847 newargv = PORT_Alloc(sizeof(char*)*(newargc+1));
2848 newargv[0] = progName;
2849 newargv[1] = commandline;
2850 nextarg = commandline;
2851 while ((space = PORT_Strpbrk(nextarg, " \f\n\r\t\v")) ) {
2852 while (isspace(*space) ) {
2853 *space = '\0';
2854 space ++;
2856 if (*space == '\0') {
2857 break;
2858 } else if (*space != '\"') {
2859 nextarg = space;
2860 } else {
2861 char* closingquote = strchr(space+1, '\"');
2862 if (closingquote) {
2863 *closingquote = '\0';
2864 space++;
2865 nextarg = closingquote+1;
2866 } else {
2867 invalid = PR_TRUE;
2868 nextarg = space;
2871 newargc++;
2872 newargv = PORT_Realloc(newargv, sizeof(char*)*(newargc+1));
2873 newargv[newargc-1] = space;
2875 newargv[newargc] = NULL;
2877 /* invoke next command */
2878 if (PR_TRUE == invalid) {
2879 PR_fprintf(PR_STDERR, "Missing closing quote in batch command :\n%s\nNot executed.\n",
2880 nextcommand);
2881 rv = SECFailure;
2882 } else {
2883 if (0 != certutil_main(newargc, newargv, PR_FALSE) )
2884 rv = SECFailure;
2886 PORT_Free(newargv);
2887 PORT_Free(commandline);
2889 fclose(batchFile);
2892 if ((initialized == PR_TRUE) && NSS_Shutdown() != SECSuccess) {
2893 exit(1);
2895 PR_Cleanup();
2897 if (rv == SECSuccess) {
2898 return 0;
2899 } else {
2900 return 255;
2905 main(int argc, char **argv)
2907 return certutil_main(argc, argv, PR_TRUE);