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/. */
4 
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>
14 
15 #if defined(WIN32)
16 #include "fcntl.h"
17 #include "io.h"
18 #endif
19 
20 #include "secutil.h"
21 
22 #if defined(XP_UNIX)
23 #include <unistd.h>
24 #endif
25 
26 #include "nspr.h"
27 #include "prtypes.h"
28 #include "prtime.h"
29 #include "prlong.h"
30 
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"
39 #include "basicutil.h"
40 #include "ssl.h"
41 
42 #define MIN_KEY_BITS 512
43 /* MAX_KEY_BITS should agree with RSA_MAX_MODULUS_BITS in freebl */
44 #define MAX_KEY_BITS 8192
45 #define DEFAULT_KEY_BITS 2048
46 
47 #define GEN_BREAK(e) \
48     rv = e;          \
49     break;
50 
51 char *progName;
52 
53 static CERTCertificateRequest *
54 GetCertRequest(const SECItem *reqDER, void *pwarg)
55 {
56     CERTCertificateRequest *certReq = NULL;
57     CERTSignedData signedData;
58     PLArenaPool *arena = NULL;
59     SECStatus rv;
60 
61     do {
62         arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
63         if (arena == NULL) {
64             GEN_BREAK(SECFailure);
65         }
66 
67         certReq = (CERTCertificateRequest *)PORT_ArenaZAlloc(arena, sizeof(CERTCertificateRequest));
68         if (!certReq) {
69             GEN_BREAK(SECFailure);
70         }
71         certReq->arena = arena;
72 
73         /* Since cert request is a signed data, must decode to get the inner
74            data
75          */
76         PORT_Memset(&signedData, 0, sizeof(signedData));
77         rv = SEC_ASN1DecodeItem(arena, &signedData,
78                                 SEC_ASN1_GET(CERT_SignedDataTemplate), reqDER);
79         if (rv) {
80             break;
81         }
82         rv = SEC_ASN1DecodeItem(arena, certReq,
83                                 SEC_ASN1_GET(CERT_CertificateRequestTemplate), &signedData.data);
84         if (rv) {
85             break;
86         }
87         rv = CERT_VerifySignedDataWithPublicKeyInfo(&signedData,
88                                                     &certReq->subjectPublicKeyInfo, pwarg);
89     } while (0);
90 
91     if (rv) {
92         SECU_PrintError(progName, "bad certificate request\n");
93         if (arena) {
94             PORT_FreeArena(arena, PR_FALSE);
95         }
96         certReq = NULL;
97     }
98 
99     return certReq;
100 }
101 
102 static SECStatus
103 AddCert(PK11SlotInfo *slot, CERTCertDBHandle *handle, char *name, char *trusts,
104         const SECItem *certDER, PRBool emailcert, void *pwdata)
105 {
106     CERTCertTrust *trust = NULL;
107     CERTCertificate *cert = NULL;
108     SECStatus rv;
109 
110     do {
111         /* Read in an ASCII cert and return a CERTCertificate */
112         cert = CERT_DecodeCertFromPackage((char *)certDER->data, certDER->len);
113         if (!cert) {
114             SECU_PrintError(progName, "could not decode certificate");
115             GEN_BREAK(SECFailure);
116         }
117 
118         /* Create a cert trust */
119         trust = (CERTCertTrust *)PORT_ZAlloc(sizeof(CERTCertTrust));
120         if (!trust) {
121             SECU_PrintError(progName, "unable to allocate cert trust");
122             GEN_BREAK(SECFailure);
123         }
124 
125         rv = CERT_DecodeTrustString(trust, trusts);
126         if (rv) {
127             SECU_PrintError(progName, "unable to decode trust string");
128             GEN_BREAK(SECFailure);
129         }
130 
131         rv = PK11_ImportCert(slot, cert, CK_INVALID_HANDLE, name, PR_FALSE);
132         if (rv != SECSuccess) {
133             /* sigh, PK11_Import Cert and CERT_ChangeCertTrust should have
134              * been coded to take a password arg. */
135             if (PORT_GetError() == SEC_ERROR_TOKEN_NOT_LOGGED_IN) {
136                 rv = PK11_Authenticate(slot, PR_TRUE, pwdata);
137                 if (rv != SECSuccess) {
138                     SECU_PrintError(progName,
139                                     "could not authenticate to token %s.",
140                                     PK11_GetTokenName(slot));
141                     GEN_BREAK(SECFailure);
142                 }
143                 rv = PK11_ImportCert(slot, cert, CK_INVALID_HANDLE,
144                                      name, PR_FALSE);
145             }
146             if (rv != SECSuccess) {
147                 SECU_PrintError(progName,
148                                 "could not add certificate to token or database");
149                 GEN_BREAK(SECFailure);
150             }
151         }
152 
153         rv = CERT_ChangeCertTrust(handle, cert, trust);
154         if (rv != SECSuccess) {
155             if (PORT_GetError() == SEC_ERROR_TOKEN_NOT_LOGGED_IN) {
156                 rv = PK11_Authenticate(slot, PR_TRUE, pwdata);
157                 if (rv != SECSuccess) {
158                     SECU_PrintError(progName,
159                                     "could not authenticate to token %s.",
160                                     PK11_GetTokenName(slot));
161                     GEN_BREAK(SECFailure);
162                 }
163                 rv = CERT_ChangeCertTrust(handle, cert, trust);
164             }
165             if (rv != SECSuccess) {
166                 SECU_PrintError(progName,
167                                 "could not change trust on certificate");
168                 GEN_BREAK(SECFailure);
169             }
170         }
171 
172         if (emailcert) {
173             CERT_SaveSMimeProfile(cert, NULL, pwdata);
174         }
175 
176     } while (0);
177 
178     CERT_DestroyCertificate(cert);
179     PORT_Free(trust);
180 
181     return rv;
182 }
183 
184 static SECStatus
185 CertReq(SECKEYPrivateKey *privk, SECKEYPublicKey *pubk, KeyType keyType,
186         SECOidTag hashAlgTag, CERTName *subject, const char *phone, int ascii,
187         const char *emailAddrs, const char *dnsNames,
188         certutilExtnList extnList, const char *extGeneric,
189         PRBool pssCertificate, /*out*/ SECItem *result)
190 {
191     CERTSubjectPublicKeyInfo *spki;
192     CERTCertificateRequest *cr;
193     SECItem *encoding;
194     SECOidTag signAlgTag;
195     SECStatus rv;
196     PLArenaPool *arena;
197     void *extHandle;
198     SECItem signedReq = { siBuffer, NULL, 0 };
199     SECAlgorithmID signAlg;
200     SECItem *params = NULL;
201 
202     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
203     if (!arena) {
204         SECU_PrintError(progName, "out of memory");
205         return SECFailure;
206     }
207 
208     /* Create info about public key */
209     spki = SECKEY_CreateSubjectPublicKeyInfo(pubk);
210     if (!spki) {
211         PORT_FreeArena(arena, PR_FALSE);
212         SECU_PrintError(progName, "unable to create subject public key");
213         return SECFailure;
214     }
215 
216     /* Change cert type to RSA-PSS, if desired. */
217     if (pssCertificate) {
218         params = SEC_CreateSignatureAlgorithmParameters(arena,
219                                                         NULL,
220                                                         SEC_OID_PKCS1_RSA_PSS_SIGNATURE,
221                                                         hashAlgTag,
222                                                         NULL,
223                                                         privk);
224         if (!params) {
225             PORT_FreeArena(arena, PR_FALSE);
226             SECKEY_DestroySubjectPublicKeyInfo(spki);
227             SECU_PrintError(progName, "unable to create RSA-PSS parameters");
228             return SECFailure;
229         }
230 
231         spki->algorithm.parameters.data = NULL;
232         rv = SECOID_SetAlgorithmID(arena, &spki->algorithm,
233                                    SEC_OID_PKCS1_RSA_PSS_SIGNATURE,
234                                    hashAlgTag == SEC_OID_UNKNOWN ? NULL : params);
235         if (rv != SECSuccess) {
236             PORT_FreeArena(arena, PR_FALSE);
237             SECKEY_DestroySubjectPublicKeyInfo(spki);
238             SECU_PrintError(progName, "unable to set algorithm ID");
239             return SECFailure;
240         }
241     }
242 
243     /* Generate certificate request */
244     cr = CERT_CreateCertificateRequest(subject, spki, NULL);
245     SECKEY_DestroySubjectPublicKeyInfo(spki);
246     if (!cr) {
247         PORT_FreeArena(arena, PR_FALSE);
248         SECU_PrintError(progName, "unable to make certificate request");
249         return SECFailure;
250     }
251 
252     extHandle = CERT_StartCertificateRequestAttributes(cr);
253     if (extHandle == NULL) {
254         PORT_FreeArena(arena, PR_FALSE);
255         CERT_DestroyCertificateRequest(cr);
256         return SECFailure;
257     }
258     if (AddExtensions(extHandle, emailAddrs, dnsNames, extnList, extGeneric) !=
259         SECSuccess) {
260         PORT_FreeArena(arena, PR_FALSE);
261         CERT_FinishExtensions(extHandle);
262         CERT_DestroyCertificateRequest(cr);
263         return SECFailure;
264     }
265     CERT_FinishExtensions(extHandle);
266     CERT_FinishCertificateRequestAttributes(cr);
267 
268     /* Der encode the request */
269     encoding = SEC_ASN1EncodeItem(arena, NULL, cr,
270                                   SEC_ASN1_GET(CERT_CertificateRequestTemplate));
271     CERT_DestroyCertificateRequest(cr);
272     if (encoding == NULL) {
273         PORT_FreeArena(arena, PR_FALSE);
274         SECU_PrintError(progName, "der encoding of request failed");
275         return SECFailure;
276     }
277 
278     PORT_Memset(&signAlg, 0, sizeof(signAlg));
279     if (pssCertificate) {
280         rv = SECOID_SetAlgorithmID(arena, &signAlg,
281                                    SEC_OID_PKCS1_RSA_PSS_SIGNATURE, params);
282         if (rv != SECSuccess) {
283             PORT_FreeArena(arena, PR_FALSE);
284             SECU_PrintError(progName, "unable to set algorithm ID");
285             return SECFailure;
286         }
287     } else {
288         signAlgTag = SEC_GetSignatureAlgorithmOidTag(keyType, hashAlgTag);
289         if (signAlgTag == SEC_OID_UNKNOWN) {
290             PORT_FreeArena(arena, PR_FALSE);
291             SECU_PrintError(progName, "unknown Key or Hash type");
292             return SECFailure;
293         }
294         rv = SECOID_SetAlgorithmID(arena, &signAlg, signAlgTag, 0);
295         if (rv != SECSuccess) {
296             PORT_FreeArena(arena, PR_FALSE);
297             SECU_PrintError(progName, "unable to set algorithm ID");
298             return SECFailure;
299         }
300     }
301 
302     /* Sign the request */
303     rv = SEC_DerSignDataWithAlgorithmID(arena, &signedReq,
304                                         encoding->data, encoding->len,
305                                         privk, &signAlg);
306     if (rv) {
307         PORT_FreeArena(arena, PR_FALSE);
308         SECU_PrintError(progName, "signing of data failed");
309         return SECFailure;
310     }
311 
312     /* Encode request in specified format */
313     if (ascii) {
314         char *obuf;
315         char *header, *name, *email, *org, *state, *country;
316 
317         obuf = BTOA_ConvertItemToAscii(&signedReq);
318         if (!obuf) {
319             goto oom;
320         }
321 
322         name = CERT_GetCommonName(subject);
323         if (!name) {
324             name = PORT_Strdup("(not specified)");
325         }
326 
327         if (!phone)
328             phone = "(not specified)";
329 
330         email = CERT_GetCertEmailAddress(subject);
331         if (!email)
332             email = PORT_Strdup("(not specified)");
333 
334         org = CERT_GetOrgName(subject);
335         if (!org)
336             org = PORT_Strdup("(not specified)");
337 
338         state = CERT_GetStateName(subject);
339         if (!state)
340             state = PORT_Strdup("(not specified)");
341 
342         country = CERT_GetCountryName(subject);
343         if (!country)
344             country = PORT_Strdup("(not specified)");
345 
346         header = PR_smprintf(
347             "\nCertificate request generated by Netscape certutil\n"
348             "Phone: %s\n\n"
349             "Common Name: %s\n"
350             "Email: %s\n"
351             "Organization: %s\n"
352             "State: %s\n"
353             "Country: %s\n\n"
354             "%s\n",
355             phone, name, email, org, state, country, NS_CERTREQ_HEADER);
356 
357         PORT_Free(name);
358         PORT_Free(email);
359         PORT_Free(org);
360         PORT_Free(state);
361         PORT_Free(country);
362 
363         if (header) {
364             char *trailer = PR_smprintf("\n%s\n", NS_CERTREQ_TRAILER);
365             if (trailer) {
366                 PRUint32 headerLen = PL_strlen(header);
367                 PRUint32 obufLen = PL_strlen(obuf);
368                 PRUint32 trailerLen = PL_strlen(trailer);
369                 SECITEM_AllocItem(NULL, result,
370                                   headerLen + obufLen + trailerLen);
371                 if (result->data) {
372                     PORT_Memcpy(result->data, header, headerLen);
373                     PORT_Memcpy(result->data + headerLen, obuf, obufLen);
374                     PORT_Memcpy(result->data + headerLen + obufLen,
375                                 trailer, trailerLen);
376                 }
377                 PR_smprintf_free(trailer);
378             }
379             PR_smprintf_free(header);
380         }
381         PORT_Free(obuf);
382     } else {
383         (void)SECITEM_CopyItem(NULL, result, &signedReq);
384     }
385 
386     if (!result->data) {
387     oom:
388         SECU_PrintError(progName, "out of memory");
389         PORT_SetError(SEC_ERROR_NO_MEMORY);
390         rv = SECFailure;
391     }
392 
393     PORT_FreeArena(arena, PR_FALSE);
394     return rv;
395 }
396 
397 static SECStatus
398 ChangeTrustAttributes(CERTCertDBHandle *handle, PK11SlotInfo *slot,
399                       char *name, char *trusts, void *pwdata)
400 {
401     SECStatus rv;
402     CERTCertificate *cert;
403     CERTCertTrust *trust;
404 
405     cert = CERT_FindCertByNicknameOrEmailAddrCX(handle, name, pwdata);
406     if (!cert) {
407         SECU_PrintError(progName, "could not find certificate named \"%s\"",
408                         name);
409         return SECFailure;
410     }
411 
412     trust = (CERTCertTrust *)PORT_ZAlloc(sizeof(CERTCertTrust));
413     if (!trust) {
414         SECU_PrintError(progName, "unable to allocate cert trust");
415         return SECFailure;
416     }
417 
418     /* This function only decodes these characters: pPwcTCu, */
419     rv = CERT_DecodeTrustString(trust, trusts);
420     if (rv) {
421         SECU_PrintError(progName, "unable to decode trust string");
422         return SECFailure;
423     }
424 
425     /* CERT_ChangeCertTrust API does not have a way to pass in
426      * a context, so NSS can't prompt for the password if it needs to.
427      * check to see if the failure was token not logged in and
428      * log in if need be. */
429     rv = CERT_ChangeCertTrust(handle, cert, trust);
430     if (rv != SECSuccess) {
431         if (PORT_GetError() == SEC_ERROR_TOKEN_NOT_LOGGED_IN) {
432             rv = PK11_Authenticate(slot, PR_TRUE, pwdata);
433             if (rv != SECSuccess) {
434                 SECU_PrintError(progName, "could not authenticate to token %s.",
435                                 PK11_GetTokenName(slot));
436                 return SECFailure;
437             }
438             rv = CERT_ChangeCertTrust(handle, cert, trust);
439         }
440         if (rv != SECSuccess) {
441             SECU_PrintError(progName, "unable to modify trust attributes");
442             return SECFailure;
443         }
444     }
445     CERT_DestroyCertificate(cert);
446     PORT_Free(trust);
447 
448     return SECSuccess;
449 }
450 
451 static SECStatus
452 DumpChain(CERTCertDBHandle *handle, char *name, PRBool ascii,
453           PRBool simpleSelfSigned)
454 {
455     CERTCertificate *the_cert;
456     CERTCertificateList *chain;
457     int i, j;
458     the_cert = SECU_FindCertByNicknameOrFilename(handle, name,
459                                                  ascii, NULL);
460     if (!the_cert) {
461         SECU_PrintError(progName, "Could not find: %s\n", name);
462         return SECFailure;
463     }
464     if (simpleSelfSigned &&
465         SECEqual == SECITEM_CompareItem(&the_cert->derIssuer,
466                                         &the_cert->derSubject)) {
467         printf("\"%s\" [%s]\n\n", the_cert->nickname, the_cert->subjectName);
468         CERT_DestroyCertificate(the_cert);
469         return SECSuccess;
470     }
471 
472     chain = CERT_CertChainFromCert(the_cert, 0, PR_TRUE);
473     CERT_DestroyCertificate(the_cert);
474     if (!chain) {
475         SECU_PrintError(progName, "Could not obtain chain for: %s\n", name);
476         return SECFailure;
477     }
478     for (i = chain->len - 1; i >= 0; i--) {
479         CERTCertificate *c;
480         c = CERT_FindCertByDERCert(handle, &chain->certs[i]);
481         for (j = i; j < chain->len - 1; j++) {
482             printf("  ");
483         }
484         if (c) {
485             printf("\"%s\" [%s]\n\n", c->nickname, c->subjectName);
486             CERT_DestroyCertificate(c);
487         } else {
488             printf("(null)\n\n");
489         }
490     }
491     CERT_DestroyCertificateList(chain);
492     return SECSuccess;
493 }
494 
495 static SECStatus
496 outputCertOrExtension(CERTCertificate *the_cert, PRBool raw, PRBool ascii,
497                       SECItem *extensionOID, PRFileDesc *outfile)
498 {
499     SECItem data;
500     PRInt32 numBytes;
501     SECStatus rv = SECFailure;
502     if (extensionOID) {
503         int i;
504         PRBool found = PR_FALSE;
505         for (i = 0; the_cert->extensions[i] != NULL; i++) {
506             CERTCertExtension *extension = the_cert->extensions[i];
507             if (SECITEM_CompareItem(&extension->id, extensionOID) == SECEqual) {
508                 found = PR_TRUE;
509                 numBytes = PR_Write(outfile, extension->value.data,
510                                     extension->value.len);
511                 rv = SECSuccess;
512                 if (numBytes != (PRInt32)extension->value.len) {
513                     SECU_PrintSystemError(progName, "error writing extension");
514                     rv = SECFailure;
515                 }
516                 break;
517             }
518         }
519         if (!found) {
520             SECU_PrintSystemError(progName, "extension not found");
521             rv = SECFailure;
522         }
523     } else {
524         data.data = the_cert->derCert.data;
525         data.len = the_cert->derCert.len;
526         if (ascii) {
527             PR_fprintf(outfile, "%s\n%s\n%s\n", NS_CERT_HEADER,
528                        BTOA_DataToAscii(data.data, data.len), NS_CERT_TRAILER);
529             rv = SECSuccess;
530         } else if (raw) {
531             numBytes = PR_Write(outfile, data.data, data.len);
532             rv = SECSuccess;
533             if (numBytes != (PRInt32)data.len) {
534                 SECU_PrintSystemError(progName, "error writing raw cert");
535                 rv = SECFailure;
536             }
537         } else {
538             rv = SEC_PrintCertificateAndTrust(the_cert, "Certificate", NULL);
539             if (rv != SECSuccess) {
540                 SECU_PrintError(progName, "problem printing certificate");
541             }
542         }
543     }
544     return rv;
545 }
546 
547 static SECStatus
548 listCerts(CERTCertDBHandle *handle, char *name, char *email,
549           PK11SlotInfo *slot, PRBool raw, PRBool ascii,
550           SECItem *extensionOID,
551           PRFileDesc *outfile, void *pwarg)
552 {
553     SECStatus rv = SECFailure;
554     CERTCertList *certs;
555     CERTCertListNode *node;
556 
557     /* List certs on a non-internal slot. */
558     if (!PK11_IsFriendly(slot) && PK11_NeedLogin(slot)) {
559         SECStatus newrv = PK11_Authenticate(slot, PR_TRUE, pwarg);
560         if (newrv != SECSuccess) {
561             SECU_PrintError(progName, "could not authenticate to token %s.",
562                             PK11_GetTokenName(slot));
563             return SECFailure;
564         }
565     }
566     if (name) {
567         CERTCertificate *the_cert =
568             SECU_FindCertByNicknameOrFilename(handle, name, ascii, NULL);
569         if (!the_cert) {
570             SECU_PrintError(progName, "Could not find cert: %s\n", name);
571             return SECFailure;
572         }
573         /* Here, we have one cert with the desired nickname or email
574          * address.  Now, we will attempt to get a list of ALL certs
575          * with the same subject name as the cert we have.  That list
576          * should contain, at a minimum, the one cert we have already found.
577          * If the list of certs is empty (NULL), the libraries have failed.
578          */
579         certs = CERT_CreateSubjectCertList(NULL, handle, &the_cert->derSubject,
580                                            PR_Now(), PR_FALSE);
581         CERT_DestroyCertificate(the_cert);
582         if (!certs) {
583             PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
584             SECU_PrintError(progName, "problem printing certificates");
585             return SECFailure;
586         }
587         for (node = CERT_LIST_HEAD(certs); !CERT_LIST_END(node, certs);
588              node = CERT_LIST_NEXT(node)) {
589             rv = outputCertOrExtension(node->cert, raw, ascii, extensionOID,
590                                        outfile);
591             if (rv != SECSuccess) {
592                 break;
593             }
594         }
595     } else if (email) {
596         certs = PK11_FindCertsFromEmailAddress(email, NULL);
597         if (!certs) {
598             SECU_PrintError(progName,
599                             "Could not find certificates for email address: %s\n",
600                             email);
601             return SECFailure;
602         }
603         for (node = CERT_LIST_HEAD(certs); !CERT_LIST_END(node, certs);
604              node = CERT_LIST_NEXT(node)) {
605             rv = outputCertOrExtension(node->cert, raw, ascii, extensionOID,
606                                        outfile);
607             if (rv != SECSuccess) {
608                 break;
609             }
610         }
611     } else {
612         certs = PK11_ListCertsInSlot(slot);
613         if (certs) {
614             for (node = CERT_LIST_HEAD(certs); !CERT_LIST_END(node, certs);
615                  node = CERT_LIST_NEXT(node)) {
616                 SECU_PrintCertNickname(node, stdout);
617             }
618             rv = SECSuccess;
619         }
620     }
621     if (certs) {
622         CERT_DestroyCertList(certs);
623     }
624     if (rv) {
625         SECU_PrintError(progName, "problem printing certificate nicknames");
626         return SECFailure;
627     }
628 
629     return SECSuccess; /* not rv ?? */
630 }
631 
632 static SECStatus
633 ListCerts(CERTCertDBHandle *handle, char *nickname, char *email,
634           PK11SlotInfo *slot, PRBool raw, PRBool ascii,
635           SECItem *extensionOID,
636           PRFileDesc *outfile, secuPWData *pwdata)
637 {
638     SECStatus rv;
639 
640     if (slot && PK11_NeedUserInit(slot)) {
641         printf("\nDatabase needs user init\n");
642     }
643 
644     if (!ascii && !raw && !nickname && !email) {
645         PR_fprintf(outfile, "\n%-60s %-5s\n%-60s %-5s\n\n",
646                    "Certificate Nickname", "Trust Attributes", "",
647                    "SSL,S/MIME,JAR/XPI");
648     }
649     if (slot == NULL) {
650         CERTCertList *list;
651         CERTCertListNode *node;
652 
653         list = PK11_ListCerts(PK11CertListAll, pwdata);
654         for (node = CERT_LIST_HEAD(list); !CERT_LIST_END(node, list);
655              node = CERT_LIST_NEXT(node)) {
656             SECU_PrintCertNickname(node, stdout);
657         }
658         CERT_DestroyCertList(list);
659         return SECSuccess;
660     }
661     rv = listCerts(handle, nickname, email, slot, raw, ascii,
662                    extensionOID, outfile, pwdata);
663     return rv;
664 }
665 
666 static SECStatus
667 DeleteCert(CERTCertDBHandle *handle, char *name, void *pwdata)
668 {
669     SECStatus rv;
670     CERTCertificate *cert;
671 
672     cert = CERT_FindCertByNicknameOrEmailAddrCX(handle, name, pwdata);
673     if (!cert) {
674         SECU_PrintError(progName, "could not find certificate named \"%s\"",
675                         name);
676         return SECFailure;
677     }
678 
679     rv = SEC_DeletePermCertificate(cert);
680     CERT_DestroyCertificate(cert);
681     if (rv) {
682         SECU_PrintError(progName, "unable to delete certificate");
683     }
684     return rv;
685 }
686 
687 static SECStatus
688 RenameCert(CERTCertDBHandle *handle, char *name, char *newName, void *pwdata)
689 {
690     SECStatus rv;
691     CERTCertificate *cert;
692 
693     cert = CERT_FindCertByNicknameOrEmailAddrCX(handle, name, pwdata);
694     if (!cert) {
695         SECU_PrintError(progName, "could not find certificate named \"%s\"",
696                         name);
697         return SECFailure;
698     }
699 
700     rv = __PK11_SetCertificateNickname(cert, newName);
701     CERT_DestroyCertificate(cert);
702     if (rv) {
703         SECU_PrintError(progName, "unable to rename certificate");
704     }
705     return rv;
706 }
707 
708 static SECStatus
709 ValidateCert(CERTCertDBHandle *handle, char *name, char *date,
710              char *certUsage, PRBool checkSig, PRBool logit,
711              PRBool ascii, secuPWData *pwdata)
712 {
713     SECStatus rv;
714     CERTCertificate *cert = NULL;
715     PRTime timeBoundary;
716     SECCertificateUsage usage;
717     CERTVerifyLog reallog;
718     CERTVerifyLog *log = NULL;
719 
720     if (!certUsage) {
721         PORT_SetError(SEC_ERROR_INVALID_ARGS);
722         return (SECFailure);
723     }
724 
725     switch (*certUsage) {
726         case 'O':
727             usage = certificateUsageStatusResponder;
728             break;
729         case 'L':
730             usage = certificateUsageSSLCA;
731             break;
732         case 'A':
733             usage = certificateUsageAnyCA;
734             break;
735         case 'Y':
736             usage = certificateUsageVerifyCA;
737             break;
738         case 'C':
739             usage = certificateUsageSSLClient;
740             break;
741         case 'V':
742             usage = certificateUsageSSLServer;
743             break;
744         case 'I':
745             usage = certificateUsageIPsec;
746             break;
747         case 'S':
748             usage = certificateUsageEmailSigner;
749             break;
750         case 'R':
751             usage = certificateUsageEmailRecipient;
752             break;
753         case 'J':
754             usage = certificateUsageObjectSigner;
755             break;
756         default:
757             PORT_SetError(SEC_ERROR_INVALID_ARGS);
758             return (SECFailure);
759     }
760     do {
761         cert = SECU_FindCertByNicknameOrFilename(handle, name, ascii,
762                                                  NULL);
763         if (!cert) {
764             SECU_PrintError(progName, "could not find certificate named \"%s\"",
765                             name);
766             GEN_BREAK(SECFailure)
767         }
768 
769         if (date != NULL) {
770             rv = DER_AsciiToTime(&timeBoundary, date);
771             if (rv) {
772                 SECU_PrintError(progName, "invalid input date");
773                 GEN_BREAK(SECFailure)
774             }
775         } else {
776             timeBoundary = PR_Now();
777         }
778 
779         if (logit) {
780             log = &reallog;
781 
782             log->count = 0;
783             log->head = NULL;
784             log->tail = NULL;
785             log->arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
786             if (log->arena == NULL) {
787                 SECU_PrintError(progName, "out of memory");
788                 GEN_BREAK(SECFailure)
789             }
790         }
791 
792         rv = CERT_VerifyCertificate(handle, cert, checkSig, usage,
793                                     timeBoundary, pwdata, log, &usage);
794         if (log) {
795             if (log->head == NULL) {
796                 fprintf(stdout, "%s: certificate is valid\n", progName);
797                 GEN_BREAK(SECSuccess)
798             } else {
799                 char *nick;
800                 CERTVerifyLogNode *node;
801 
802                 node = log->head;
803                 while (node) {
804                     if (node->cert->nickname != NULL) {
805                         nick = node->cert->nickname;
806                     } else {
807                         nick = node->cert->subjectName;
808                     }
809                     fprintf(stderr, "%s : %s\n", nick,
810                             SECU_Strerror(node->error));
811                     CERT_DestroyCertificate(node->cert);
812                     node = node->next;
813                 }
814             }
815         } else {
816             if (rv != SECSuccess) {
817                 PRErrorCode perr = PORT_GetError();
818                 fprintf(stdout, "%s: certificate is invalid: %s\n",
819                         progName, SECU_Strerror(perr));
820                 GEN_BREAK(SECFailure)
821             }
822             fprintf(stdout, "%s: certificate is valid\n", progName);
823             GEN_BREAK(SECSuccess)
824         }
825     } while (0);
826 
827     if (cert) {
828         CERT_DestroyCertificate(cert);
829     }
830 
831     return (rv);
832 }
833 
834 static PRBool
835 ItemIsPrintableASCII(const SECItem *item)
836 {
837     unsigned char *src = item->data;
838     unsigned int len = item->len;
839     while (len-- > 0) {
840         unsigned char uc = *src++;
841         if (uc < 0x20 || uc > 0x7e)
842             return PR_FALSE;
843     }
844     return PR_TRUE;
845 }
846 
847 /* Caller ensures that dst is at least item->len*2+1 bytes long */
848 static void
849 SECItemToHex(const SECItem *item, char *dst)
850 {
851     if (dst && item && item->data) {
852         unsigned char *src = item->data;
853         unsigned int len = item->len;
854         for (; len > 0; --len, dst += 2) {
855             sprintf(dst, "%02x", *src++);
856         }
857         *dst = '\0';
858     }
859 }
860 
861 static const char *const keyTypeName[] = {
862     "null", "rsa", "dsa", "fortezza", "dh", "kea", "ec", "rsaPss", "rsaOaep"
863 };
864 
865 #define MAX_CKA_ID_BIN_LEN 20
866 #define MAX_CKA_ID_STR_LEN 40
867 
868 /* output human readable key ID in buffer, which should have at least
869  * MAX_CKA_ID_STR_LEN + 3 octets (quotations and a null terminator) */
870 static void
871 formatPrivateKeyID(SECKEYPrivateKey *privkey, char *buffer)
872 {
873     SECItem *ckaID;
874 
875     ckaID = PK11_GetLowLevelKeyIDForPrivateKey(privkey);
876     if (!ckaID) {
877         strcpy(buffer, "(no CKA_ID)");
878     } else if (ItemIsPrintableASCII(ckaID)) {
879         int len = PR_MIN(MAX_CKA_ID_STR_LEN, ckaID->len);
880         buffer[0] = '"';
881         memcpy(buffer + 1, ckaID->data, len);
882         buffer[1 + len] = '"';
883         buffer[2 + len] = '\0';
884     } else {
885         /* print ckaid in hex */
886         SECItem idItem = *ckaID;
887         if (idItem.len > MAX_CKA_ID_BIN_LEN)
888             idItem.len = MAX_CKA_ID_BIN_LEN;
889         SECItemToHex(&idItem, buffer);
890     }
891     SECITEM_ZfreeItem(ckaID, PR_TRUE);
892 }
893 
894 /* print key number, key ID (in hex or ASCII), key label (nickname) */
895 static SECStatus
896 PrintKey(PRFileDesc *out, const char *nickName, int count,
897          SECKEYPrivateKey *key, void *pwarg)
898 {
899     char ckaIDbuf[MAX_CKA_ID_STR_LEN + 4];
900     CERTCertificate *cert;
901     KeyType keyType;
902 
903     pwarg = NULL;
904 
905     formatPrivateKeyID(key, ckaIDbuf);
906     cert = PK11_GetCertFromPrivateKey(key);
907     if (cert) {
908         keyType = CERT_GetCertKeyType(&cert->subjectPublicKeyInfo);
909         CERT_DestroyCertificate(cert);
910     } else {
911         keyType = key->keyType;
912     }
913     PR_fprintf(out, "<%2d> %-8.8s %-42.42s %s\n", count,
914                keyTypeName[keyType], ckaIDbuf, nickName);
915 
916     return SECSuccess;
917 }
918 
919 /* returns SECSuccess if ANY keys are found, SECFailure otherwise. */
920 static SECStatus
921 ListKeysInSlot(PK11SlotInfo *slot, const char *nickName, KeyType keyType,
922                void *pwarg)
923 {
924     SECKEYPrivateKeyList *list;
925     SECKEYPrivateKeyListNode *node;
926     int count = 0;
927 
928     if (PK11_NeedLogin(slot)) {
929         SECStatus rv = PK11_Authenticate(slot, PR_TRUE, pwarg);
930         if (rv != SECSuccess) {
931             SECU_PrintError(progName, "could not authenticate to token %s.",
932                             PK11_GetTokenName(slot));
933             return SECFailure;
934         }
935     }
936 
937     if (nickName && nickName[0])
938         list = PK11_ListPrivKeysInSlot(slot, (char *)nickName, pwarg);
939     else
940         list = PK11_ListPrivateKeysInSlot(slot);
941     if (list == NULL) {
942         SECU_PrintError(progName, "problem listing keys");
943         return SECFailure;
944     }
945     for (node = PRIVKEY_LIST_HEAD(list);
946          !PRIVKEY_LIST_END(node, list);
947          node = PRIVKEY_LIST_NEXT(node)) {
948         char *keyName;
949         static const char orphan[] = { "(orphan)" };
950 
951         if (keyType != nullKey && keyType != node->key->keyType)
952             continue;
953         keyName = PK11_GetPrivateKeyNickname(node->key);
954         if (!keyName || !keyName[0]) {
955             /* Try extra hard to find nicknames for keys that lack them. */
956             CERTCertificate *cert;
957             PORT_Free((void *)keyName);
958             keyName = NULL;
959             cert = PK11_GetCertFromPrivateKey(node->key);
960             if (cert) {
961                 if (cert->nickname && cert->nickname[0]) {
962                     keyName = PORT_Strdup(cert->nickname);
963                 } else if (cert->emailAddr && cert->emailAddr[0]) {
964                     keyName = PORT_Strdup(cert->emailAddr);
965                 }
966                 CERT_DestroyCertificate(cert);
967             }
968         }
969         if (nickName) {
970             if (!keyName || PL_strcmp(keyName, nickName)) {
971                 /* PKCS#11 module returned unwanted keys */
972                 PORT_Free((void *)keyName);
973                 continue;
974             }
975         }
976         if (!keyName)
977             keyName = (char *)orphan;
978 
979         PrintKey(PR_STDOUT, keyName, count, node->key, pwarg);
980 
981         if (keyName != (char *)orphan)
982             PORT_Free((void *)keyName);
983         count++;
984     }
985     SECKEY_DestroyPrivateKeyList(list);
986 
987     if (count == 0) {
988         PR_fprintf(PR_STDOUT, "%s: no keys found\n", progName);
989         return SECFailure;
990     }
991     return SECSuccess;
992 }
993 
994 /* returns SECSuccess if ANY keys are found, SECFailure otherwise. */
995 static SECStatus
996 ListKeys(PK11SlotInfo *slot, const char *nickName, int index,
997          KeyType keyType, PRBool dopriv, secuPWData *pwdata)
998 {
999     SECStatus rv = SECFailure;
1000     static const char fmt[] =
1001         "%s: Checking token \"%.33s\" in slot \"%.65s\"\n";
1002 
1003     if (slot == NULL) {
1004         PK11SlotList *list;
1005         PK11SlotListElement *le;
1006 
1007         list = PK11_GetAllTokens(CKM_INVALID_MECHANISM, PR_FALSE, PR_FALSE, pwdata);
1008         if (list) {
1009             for (le = list->head; le; le = le->next) {
1010                 PR_fprintf(PR_STDOUT, fmt, progName,
1011                            PK11_GetTokenName(le->slot),
1012                            PK11_GetSlotName(le->slot));
1013                 rv &= ListKeysInSlot(le->slot, nickName, keyType, pwdata);
1014             }
1015             PK11_FreeSlotList(list);
1016         }
1017     } else {
1018         PR_fprintf(PR_STDOUT, fmt, progName, PK11_GetTokenName(slot),
1019                    PK11_GetSlotName(slot));
1020         rv = ListKeysInSlot(slot, nickName, keyType, pwdata);
1021     }
1022     return rv;
1023 }
1024 
1025 static SECStatus
1026 DeleteCertAndKey(char *nickname, secuPWData *pwdata)
1027 {
1028     SECStatus rv;
1029     CERTCertificate *cert;
1030     PK11SlotInfo *slot;
1031 
1032     slot = PK11_GetInternalKeySlot();
1033     if (PK11_NeedLogin(slot)) {
1034         rv = PK11_Authenticate(slot, PR_TRUE, pwdata);
1035         if (rv != SECSuccess) {
1036             SECU_PrintError(progName, "could not authenticate to token %s.",
1037                             PK11_GetTokenName(slot));
1038             return SECFailure;
1039         }
1040     }
1041     cert = PK11_FindCertFromNickname(nickname, pwdata);
1042     if (!cert) {
1043         PK11_FreeSlot(slot);
1044         return SECFailure;
1045     }
1046     rv = PK11_DeleteTokenCertAndKey(cert, pwdata);
1047     if (rv != SECSuccess) {
1048         SECU_PrintError("problem deleting private key \"%s\"\n", nickname);
1049     }
1050     CERT_DestroyCertificate(cert);
1051     PK11_FreeSlot(slot);
1052     return rv;
1053 }
1054 
1055 static SECKEYPrivateKey *
1056 findPrivateKeyByID(PK11SlotInfo *slot, const char *ckaID, secuPWData *pwarg)
1057 {
1058     PORTCheapArenaPool arena;
1059     SECItem ckaIDItem = { 0 };
1060     SECKEYPrivateKey *privkey = NULL;
1061     SECStatus rv;
1062 
1063     if (PK11_NeedLogin(slot)) {
1064         rv = PK11_Authenticate(slot, PR_TRUE, pwarg);
1065         if (rv != SECSuccess) {
1066             SECU_PrintError(progName, "could not authenticate to token %s.",
1067                             PK11_GetTokenName(slot));
1068             return NULL;
1069         }
1070     }
1071 
1072     if (0 == PL_strncasecmp("0x", ckaID, 2)) {
1073         ckaID += 2; /* skip leading "0x" */
1074     }
1075     PORT_InitCheapArena(&arena, DER_DEFAULT_CHUNKSIZE);
1076     if (SECU_HexString2SECItem(&arena.arena, &ckaIDItem, ckaID)) {
1077         privkey = PK11_FindKeyByKeyID(slot, &ckaIDItem, pwarg);
1078     }
1079     PORT_DestroyCheapArena(&arena);
1080     return privkey;
1081 }
1082 
1083 static SECStatus
1084 DeleteKey(SECKEYPrivateKey *privkey, secuPWData *pwarg)
1085 {
1086     SECStatus rv;
1087     PK11SlotInfo *slot;
1088 
1089     slot = PK11_GetSlotFromPrivateKey(privkey);
1090     if (PK11_NeedLogin(slot)) {
1091         rv = PK11_Authenticate(slot, PR_TRUE, pwarg);
1092         if (rv != SECSuccess) {
1093             SECU_PrintError(progName, "could not authenticate to token %s.",
1094                             PK11_GetTokenName(slot));
1095             return SECFailure;
1096         }
1097     }
1098 
1099     rv = PK11_DeleteTokenPrivateKey(privkey, PR_TRUE);
1100     if (rv != SECSuccess) {
1101         char ckaIDbuf[MAX_CKA_ID_STR_LEN + 4];
1102         formatPrivateKeyID(privkey, ckaIDbuf);
1103         SECU_PrintError("problem deleting private key \"%s\"\n", ckaIDbuf);
1104     }
1105 
1106     PK11_FreeSlot(slot);
1107     return rv;
1108 }
1109 
1110 /*
1111  *  L i s t M o d u l e s
1112  *
1113  *  Print a list of the PKCS11 modules that are
1114  *  available. This is useful for smartcard people to
1115  *  make sure they have the drivers loaded.
1116  *
1117  */
1118 static SECStatus
1119 ListModules(void)
1120 {
1121     PK11SlotList *list;
1122     PK11SlotListElement *le;
1123 
1124     /* get them all! */
1125     list = PK11_GetAllTokens(CKM_INVALID_MECHANISM, PR_FALSE, PR_FALSE, NULL);
1126     if (list == NULL)
1127         return SECFailure;
1128 
1129     /* look at each slot*/
1130     for (le = list->head; le; le = le->next) {
1131         char *token_uri = PK11_GetTokenURI(le->slot);
1132         printf("\n");
1133         printf("    slot: %s\n", PK11_GetSlotName(le->slot));
1134         printf("   token: %s\n", PK11_GetTokenName(le->slot));
1135         printf("     uri: %s\n", token_uri);
1136         PORT_Free(token_uri);
1137     }
1138     PK11_FreeSlotList(list);
1139 
1140     return SECSuccess;
1141 }
1142 
1143 static void
1144 PrintBuildFlags()
1145 {
1146 #ifdef NSS_FIPS_DISABLED
1147     PR_fprintf(PR_STDOUT, "NSS_FIPS_DISABLED\n");
1148 #endif
1149 #ifdef NSS_NO_INIT_SUPPORT
1150     PR_fprintf(PR_STDOUT, "NSS_NO_INIT_SUPPORT\n");
1151 #endif
1152     exit(0);
1153 }
1154 
1155 static void
1156 PrintSyntax()
1157 {
1158 #define FPS fprintf(stderr,
1159     FPS "Type %s -H for more detailed descriptions\n", progName);
1160     FPS "Usage:  %s -N [-d certdir] [-P dbprefix] [-f pwfile] [--empty-password]\n", progName);
1161     FPS "Usage:  %s -T [-d certdir] [-P dbprefix] [-h token-name]\n"
1162         "\t\t [-f pwfile] [-0 SSO-password]\n", progName);
1163     FPS "\t%s -A -n cert-name -t trustargs [-d certdir] [-P dbprefix] [-a] [-i input]\n",
1164         progName);
1165     FPS "\t%s -B -i batch-file\n", progName);
1166     FPS "\t%s -C [-c issuer-name | -x] -i cert-request-file -o cert-file\n"
1167         "\t\t [-m serial-number] [-w warp-months] [-v months-valid]\n"
1168         "\t\t [-f pwfile] [-d certdir] [-P dbprefix] [-Z hashAlg]\n"
1169         "\t\t [-1 | --keyUsage [keyUsageKeyword,..]] [-2] [-3] [-4]\n"
1170         "\t\t [-5 | --nsCertType [nsCertTypeKeyword,...]]\n"
1171         "\t\t [-6 | --extKeyUsage [extKeyUsageKeyword,...]] [-7 emailAddrs]\n"
1172         "\t\t [-8 dns-names] [-a]\n",
1173         progName);
1174     FPS "\t%s -D -n cert-name [-d certdir] [-P dbprefix]\n", progName);
1175     FPS "\t%s --rename -n cert-name --new-n new-cert-name\n"
1176         "\t\t [-d certdir] [-P dbprefix]\n", progName);
1177     FPS "\t%s -E -n cert-name -t trustargs [-d certdir] [-P dbprefix] [-a] [-i input]\n",
1178         progName);
1179     FPS "\t%s -F -n cert-name [-d certdir] [-P dbprefix]\n",
1180         progName);
1181     FPS "\t%s -F -k key-id [-d certdir] [-P dbprefix]\n",
1182         progName);
1183     FPS "\t%s -G -n key-name [-h token-name] [-k rsa] [-g key-size] [-y exp]\n"
1184         "\t\t [-f pwfile] [-z noisefile] [-d certdir] [-P dbprefix]\n", progName);
1185     FPS "\t%s -G [-h token-name] -k dsa [-q pqgfile -g key-size] [-f pwfile]\n"
1186         "\t\t [-z noisefile] [-d certdir] [-P dbprefix]\n", progName);
1187     FPS "\t%s -G [-h token-name] -k ec -q curve [-f pwfile]\n"
1188         "\t\t [-z noisefile] [-d certdir] [-P dbprefix]\n", progName);
1189     FPS "\t%s -K [-n key-name] [-h token-name] [-k dsa|ec|rsa|all]\n",
1190         progName);
1191     FPS "\t\t [-f pwfile] [-X] [-d certdir] [-P dbprefix]\n");
1192     FPS "\t%s --upgrade-merge --source-dir upgradeDir --upgrade-id uniqueID\n",
1193         progName);
1194     FPS "\t\t [--upgrade-token-name tokenName] [-d targetDBDir]\n");
1195     FPS "\t\t [-P targetDBPrefix] [--source-prefix upgradeDBPrefix]\n");
1196     FPS "\t\t [-f targetPWfile] [-@ upgradePWFile]\n");
1197     FPS "\t%s --merge --source-dir sourceDBDir [-d targetDBdir]\n",
1198         progName);
1199     FPS "\t\t [-P targetDBPrefix] [--source-prefix sourceDBPrefix]\n");
1200     FPS "\t\t [-f targetPWfile] [-@ sourcePWFile]\n");
1201     FPS "\t%s -L [-n cert-name] [-h token-name] [--email email-address]\n",
1202         progName);
1203     FPS "\t\t [-X] [-r] [-a] [--dump-ext-val OID] [-d certdir] [-P dbprefix]\n");
1204     FPS "\t%s --build-flags\n", progName);
1205     FPS "\t%s -M -n cert-name -t trustargs [-d certdir] [-P dbprefix]\n",
1206         progName);
1207     FPS "\t%s -O -n cert-name [-X] [-d certdir] [-a] [-P dbprefix]\n"
1208         "\t\t [--simple-self-signed]\n",
1209         progName);
1210     FPS "\t%s -R -s subj -o cert-request-file [-d certdir] [-P dbprefix] [-p phone] [-a]\n"
1211         "\t\t [-7 emailAddrs] [-k key-type-or-id] [-h token-name] [-f pwfile]\n"
1212         "\t\t [-g key-size] [-Z hashAlg]\n",
1213         progName);
1214     FPS "\t%s -V -n cert-name -u usage [-b time] [-e] [-a]\n"
1215         "\t\t[-X] [-d certdir] [-P dbprefix]\n",
1216         progName);
1217     FPS "Usage:  %s -W [-d certdir] [-f pwfile] [-@newpwfile]\n",
1218         progName);
1219     FPS "\t%s -S -n cert-name -s subj [-c issuer-name | -x]  -t trustargs\n"
1220         "\t\t [-k key-type-or-id] [-q key-params] [-h token-name] [-g key-size]\n"
1221         "\t\t [-m serial-number] [-w warp-months] [-v months-valid]\n"
1222         "\t\t [-f pwfile] [-d certdir] [-P dbprefix] [-Z hashAlg]\n"
1223         "\t\t [-p phone] [-1] [-2] [-3] [-4] [-5] [-6] [-7 emailAddrs]\n"
1224         "\t\t [-8 DNS-names]\n"
1225         "\t\t [--extAIA] [--extSIA] [--extCP] [--extPM] [--extPC] [--extIA]\n"
1226         "\t\t [--extSKID] [--extNC] [--extSAN type:name[,type:name]...]\n"
1227         "\t\t [--extGeneric OID:critical-flag:filename[,OID:critical-flag:filename]...]\n", progName);
1228     FPS "\t%s -U [-X] [-d certdir] [-P dbprefix]\n", progName);
1229     exit(1);
1230 }
1231 
1232 enum usage_level {
1233     usage_all = 0,
1234     usage_selected = 1
1235 };
1236 
1237 static void luCommonDetailsAE();
1238 
1239 static void
1240 luA(enum usage_level ul, const char *command)
1241 {
1242     int is_my_command = (command && 0 == strcmp(command, "A"));
1243     if (ul == usage_all || !command || is_my_command)
1244     FPS "%-15s Add a certificate to the database        (create if needed)\n",
1245         "-A");
1246     if (ul == usage_selected && !is_my_command)
1247         return;
1248     if (ul == usage_all) {
1249     FPS "%-20s\n", "   All options under -E apply");
1250     } else {
1251         luCommonDetailsAE();
1252     }
1253 }
1254 
1255 static void
1256 luB(enum usage_level ul, const char *command)
1257 {
1258     int is_my_command = (command && 0 == strcmp(command, "B"));
1259     if (ul == usage_all || !command || is_my_command)
1260     FPS "%-15s Run a series of certutil commands from a batch file\n", "-B");
1261     if (ul == usage_selected && !is_my_command)
1262         return;
1263     FPS "%-20s Specify the batch file\n", "   -i batch-file");
1264 }
1265 
1266 static void
1267 luE(enum usage_level ul, const char *command)
1268 {
1269     int is_my_command = (command && 0 == strcmp(command, "E"));
1270     if (ul == usage_all || !command || is_my_command)
1271     FPS "%-15s Add an Email certificate to the database (create if needed)\n",
1272         "-E");
1273     if (ul == usage_selected && !is_my_command)
1274         return;
1275     luCommonDetailsAE();
1276 }
1277 
1278 static void
1279 luCommonDetailsAE()
1280 {
1281     FPS "%-20s Specify the nickname of the certificate to add\n",
1282         "   -n cert-name");
1283     FPS "%-20s Set the certificate trust attributes:\n",
1284         "   -t trustargs");
1285     FPS "%-25s trustargs is of the form x,y,z where x is for SSL, y is for S/MIME,\n", "");
1286     FPS "%-25s and z is for code signing. Use ,, for no explicit trust.\n", "");
1287     FPS "%-25s p \t prohibited (explicitly distrusted)\n", "");
1288     FPS "%-25s P \t trusted peer\n", "");
1289     FPS "%-25s c \t valid CA\n", "");
1290     FPS "%-25s T \t trusted CA to issue client certs (implies c)\n", "");
1291     FPS "%-25s C \t trusted CA to issue server certs (implies c)\n", "");
1292     FPS "%-25s u \t user cert\n", "");
1293     FPS "%-25s w \t send warning\n", "");
1294     FPS "%-25s g \t make step-up cert\n", "");
1295     FPS "%-20s Specify the password file\n",
1296         "   -f pwfile");
1297     FPS "%-20s Cert database directory (default is ~/.netscape)\n",
1298         "   -d certdir");
1299     FPS "%-20s Cert & Key database prefix\n",
1300         "   -P dbprefix");
1301     FPS "%-20s The input certificate is encoded in ASCII (RFC1113)\n",
1302         "   -a");
1303     FPS "%-20s Specify the certificate file (default is stdin)\n",
1304         "   -i input");
1305     FPS "\n");
1306 }
1307 
1308 static void
1309 luC(enum usage_level ul, const char *command)
1310 {
1311     int is_my_command = (command && 0 == strcmp(command, "C"));
1312     if (ul == usage_all || !command || is_my_command)
1313     FPS "%-15s Create a new binary certificate from a BINARY cert request\n",
1314         "-C");
1315     if (ul == usage_selected && !is_my_command)
1316         return;
1317     FPS "%-20s The nickname of the issuer cert\n",
1318         "   -c issuer-name");
1319     FPS "%-20s The BINARY certificate request file\n",
1320         "   -i cert-request ");
1321     FPS "%-20s Output binary cert to this file (default is stdout)\n",
1322         "   -o output-cert");
1323     FPS "%-20s Self sign\n",
1324         "   -x");
1325     FPS "%-20s Sign the certificate with RSA-PSS (the issuer key must be rsa)\n",
1326         "   --pss-sign");
1327     FPS "%-20s Cert serial number\n",
1328         "   -m serial-number");
1329     FPS "%-20s Time Warp\n",
1330         "   -w warp-months");
1331     FPS "%-20s Months valid (default is 3)\n",
1332         "   -v months-valid");
1333     FPS "%-20s Specify the password file\n",
1334         "   -f pwfile");
1335     FPS "%-20s Cert database directory (default is ~/.netscape)\n",
1336         "   -d certdir");
1337     FPS "%-20s Cert & Key database prefix\n",
1338         "   -P dbprefix");
1339     FPS "%-20s \n"
1340               "%-20s Specify the hash algorithm to use. Possible keywords:\n"
1341               "%-20s \"MD2\", \"MD4\", \"MD5\", \"SHA1\", \"SHA224\",\n"
1342               "%-20s \"SHA256\", \"SHA384\", \"SHA512\"\n",
1343         "   -Z hashAlg", "", "", "");
1344     FPS "%-20s \n"
1345               "%-20s Create key usage extension. Possible keywords:\n"
1346               "%-20s \"digitalSignature\", \"nonRepudiation\", \"keyEncipherment\",\n"
1347               "%-20s \"dataEncipherment\", \"keyAgreement\", \"certSigning\",\n"
1348               "%-20s \"crlSigning\", \"critical\"\n",
1349         "   -1 | --keyUsage keyword,keyword,...", "", "", "", "");
1350     FPS "%-20s Create basic constraint extension\n",
1351         "   -2 ");
1352     FPS "%-20s Create authority key ID extension\n",
1353         "   -3 ");
1354     FPS "%-20s Create crl distribution point extension\n",
1355         "   -4 ");
1356     FPS "%-20s \n"
1357               "%-20s Create netscape cert type extension. Possible keywords:\n"
1358               "%-20s \"sslClient\", \"sslServer\", \"smime\", \"objectSigning\",\n"
1359               "%-20s \"sslCA\", \"smimeCA\", \"objectSigningCA\", \"critical\".\n",
1360         "   -5 | --nsCertType keyword,keyword,... ", "", "", "");
1361     FPS "%-20s \n"
1362               "%-20s Create extended key usage extension. Possible keywords:\n"
1363               "%-20s \"serverAuth\", \"clientAuth\",\"codeSigning\",\n"
1364               "%-20s \"emailProtection\", \"timeStamp\",\"ocspResponder\",\n"
1365               "%-20s \"stepUp\", \"msTrustListSign\", \"x509Any\",\n"
1366               "%-20s \"ipsecIKE\", \"ipsecIKEEnd\", \"ipsecIKEIntermediate\",\n"
1367               "%-20s \"ipsecEnd\", \"ipsecTunnel\", \"ipsecUser\",\n"
1368               "%-20s \"critical\"\n",
1369         "   -6 | --extKeyUsage keyword,keyword,...", "", "", "", "", "", "", "");
1370     FPS "%-20s Create an email subject alt name extension\n",
1371         "   -7 emailAddrs");
1372     FPS "%-20s Create an dns subject alt name extension\n",
1373         "   -8 dnsNames");
1374     FPS "%-20s The input certificate request is encoded in ASCII (RFC1113)\n",
1375         "   -a");
1376     FPS "\n");
1377 }
1378 
1379 static void
1380 luG(enum usage_level ul, const char *command)
1381 {
1382     int is_my_command = (command && 0 == strcmp(command, "G"));
1383     if (ul == usage_all || !command || is_my_command)
1384     FPS "%-15s Generate a new key pair\n",
1385         "-G");
1386     if (ul == usage_selected && !is_my_command)
1387         return;
1388     FPS "%-20s Name of token in which to generate key (default is internal)\n",
1389         "   -h token-name");
1390     FPS "%-20s Type of key pair to generate (\"dsa\", \"ec\", \"rsa\" (default))\n",
1391         "   -k key-type");
1392     FPS "%-20s Key size in bits, (min %d, max %d, default %d) (not for ec)\n",
1393         "   -g key-size", MIN_KEY_BITS, MAX_KEY_BITS, DEFAULT_KEY_BITS);
1394     FPS "%-20s Set the public exponent value (3, 17, 65537) (rsa only)\n",
1395         "   -y exp");
1396     FPS "%-20s Specify the password file\n",
1397         "   -f password-file");
1398     FPS "%-20s Specify the noise file to be used\n",
1399         "   -z noisefile");
1400     FPS "%-20s read PQG value from pqgfile (dsa only)\n",
1401         "   -q pqgfile");
1402     FPS "%-20s Elliptic curve name (ec only)\n",
1403         "   -q curve-name");
1404     FPS "%-20s One of nistp256, nistp384, nistp521, curve25519.\n", "");
1405     FPS "%-20s If a custom token is present, the following curves are also supported:\n", "");
1406     FPS "%-20s sect163k1, nistk163, sect163r1, sect163r2,\n", "");
1407     FPS "%-20s nistb163, sect193r1, sect193r2, sect233k1, nistk233,\n", "");
1408     FPS "%-20s sect233r1, nistb233, sect239k1, sect283k1, nistk283,\n", "");
1409     FPS "%-20s sect283r1, nistb283, sect409k1, nistk409, sect409r1,\n", "");
1410     FPS "%-20s nistb409, sect571k1, nistk571, sect571r1, nistb571,\n", "");
1411     FPS "%-20s secp160k1, secp160r1, secp160r2, secp192k1, secp192r1,\n", "");
1412     FPS "%-20s nistp192, secp224k1, secp224r1, nistp224, secp256k1,\n", "");
1413     FPS "%-20s secp256r1, secp384r1, secp521r1,\n", "");
1414     FPS "%-20s prime192v1, prime192v2, prime192v3, \n", "");
1415     FPS "%-20s prime239v1, prime239v2, prime239v3, c2pnb163v1, \n", "");
1416     FPS "%-20s c2pnb163v2, c2pnb163v3, c2pnb176v1, c2tnb191v1, \n", "");
1417     FPS "%-20s c2tnb191v2, c2tnb191v3,  \n", "");
1418     FPS "%-20s c2pnb208w1, c2tnb239v1, c2tnb239v2, c2tnb239v3, \n", "");
1419     FPS "%-20s c2pnb272w1, c2pnb304w1, \n", "");
1420     FPS "%-20s c2tnb359w1, c2pnb368w1, c2tnb431r1, secp112r1, \n", "");
1421     FPS "%-20s secp112r2, secp128r1, secp128r2, sect113r1, sect113r2\n", "");
1422     FPS "%-20s sect131r1, sect131r2\n", "");
1423     FPS "%-20s Key database directory (default is ~/.netscape)\n",
1424         "   -d keydir");
1425     FPS "%-20s Cert & Key database prefix\n",
1426         "   -P dbprefix");
1427     FPS "%-20s\n"
1428         "%-20s PKCS #11 key Attributes.\n",
1429         "   --keyAttrFlags attrflags", "");
1430     FPS "%-20s Comma separated list of key attribute attribute flags,\n", "");
1431     FPS "%-20s selected from the following list of choices:\n", "");
1432     FPS "%-20s {token | session} {public | private} {sensitive | insensitive}\n", "");
1433     FPS "%-20s {modifiable | unmodifiable} {extractable | unextractable}\n", "");
1434     FPS "%-20s\n",
1435         "   --keyOpFlagsOn opflags");
1436     FPS "%-20s\n"
1437         "%-20s PKCS #11 key Operation Flags.\n",
1438         "   --keyOpFlagsOff opflags", "");
1439     FPS "%-20s Comma separated list of one or more of the following:\n", "");
1440     FPS "%-20s encrypt, decrypt, sign, sign_recover, verify,\n", "");
1441     FPS "%-20s verify_recover, wrap, unwrap, derive\n", "");
1442     FPS "\n");
1443 }
1444 
1445 static void
1446 luD(enum usage_level ul, const char *command)
1447 {
1448     int is_my_command = (command && 0 == strcmp(command, "D"));
1449     if (ul == usage_all || !command || is_my_command)
1450     FPS "%-15s Delete a certificate from the database\n",
1451         "-D");
1452     if (ul == usage_selected && !is_my_command)
1453         return;
1454     FPS "%-20s The nickname of the cert to delete\n",
1455         "   -n cert-name");
1456     FPS "%-20s Cert database directory (default is ~/.netscape)\n",
1457         "   -d certdir");
1458     FPS "%-20s Cert & Key database prefix\n",
1459         "   -P dbprefix");
1460     FPS "\n");
1461 }
1462 
1463 static void
1464 luF(enum usage_level ul, const char *command)
1465 {
1466     int is_my_command = (command && 0 == strcmp(command, "F"));
1467     if (ul == usage_all || !command || is_my_command)
1468     FPS "%-15s Delete a key and associated certificate from the database\n",
1469         "-F");
1470     if (ul == usage_selected && !is_my_command)
1471         return;
1472     FPS "%-20s The nickname of the key to delete\n",
1473         "   -n cert-name");
1474     FPS "%-20s The key id of the key to delete, obtained using -K\n",
1475         "   -k key-id");
1476     FPS "%-20s Cert database directory (default is ~/.netscape)\n",
1477         "   -d certdir");
1478     FPS "%-20s Cert & Key database prefix\n",
1479         "   -P dbprefix");
1480     FPS "\n");
1481 }
1482 
1483 static void
1484 luU(enum usage_level ul, const char *command)
1485 {
1486     int is_my_command = (command && 0 == strcmp(command, "U"));
1487     if (ul == usage_all || !command || is_my_command)
1488     FPS "%-15s List all modules\n", /*, or print out a single named module\n",*/
1489         "-U");
1490     if (ul == usage_selected && !is_my_command)
1491         return;
1492     FPS "%-20s Module database directory (default is '~/.netscape')\n",
1493         "   -d moddir");
1494     FPS "%-20s Cert & Key database prefix\n",
1495         "   -P dbprefix");
1496     FPS "%-20s force the database to open R/W\n",
1497         "   -X");
1498     FPS "\n");
1499 }
1500 
1501 static void
1502 luK(enum usage_level ul, const char *command)
1503 {
1504     int is_my_command = (command && 0 == strcmp(command, "K"));
1505     if (ul == usage_all || !command || is_my_command)
1506     FPS "%-15s List all private keys\n",
1507         "-K");
1508     if (ul == usage_selected && !is_my_command)
1509         return;
1510     FPS "%-20s Name of token to search (\"all\" for all tokens)\n",
1511         "   -h token-name ");
1512 
1513     FPS "%-20s Key type (\"all\" (default), \"dsa\","
1514                                                     " \"ec\","
1515                                                     " \"rsa\")\n",
1516         "   -k key-type");
1517     FPS "%-20s The nickname of the key or associated certificate\n",
1518         "   -n name");
1519     FPS "%-20s Specify the password file\n",
1520         "   -f password-file");
1521     FPS "%-20s Key database directory (default is ~/.netscape)\n",
1522         "   -d keydir");
1523     FPS "%-20s Cert & Key database prefix\n",
1524         "   -P dbprefix");
1525     FPS "%-20s force the database to open R/W\n",
1526         "   -X");
1527     FPS "\n");
1528 }
1529 
1530 static void
1531 luL(enum usage_level ul, const char *command)
1532 {
1533     int is_my_command = (command && 0 == strcmp(command, "L"));
1534     if (ul == usage_all || !command || is_my_command)
1535     FPS "%-15s List all certs, or print out a single named cert (or a subset)\n",
1536         "-L");
1537     if (ul == usage_selected && !is_my_command)
1538         return;
1539     FPS "%-20s Name of token to search (\"all\" for all tokens)\n",
1540         "   -h token-name ");
1541     FPS "%-20s Pretty print named cert (list all if unspecified)\n",
1542         "   -n cert-name");
1543     FPS "%-20s \n"
1544               "%-20s Pretty print cert with email address (list all if unspecified)\n",
1545         "   --email email-address", "");
1546     FPS "%-20s Cert database directory (default is ~/.netscape)\n",
1547         "   -d certdir");
1548     FPS "%-20s Cert & Key database prefix\n",
1549         "   -P dbprefix");
1550     FPS "%-20s force the database to open R/W\n",
1551         "   -X");
1552     FPS "%-20s For single cert, print binary DER encoding\n",
1553         "   -r");
1554     FPS "%-20s For single cert, print ASCII encoding (RFC1113)\n",
1555         "   -a");
1556     FPS "%-20s \n"
1557               "%-20s For single cert, print binary DER encoding of extension OID\n",
1558         "   --dump-ext-val OID", "");
1559     FPS "\n");
1560 }
1561 
1562 static void
1563 luM(enum usage_level ul, const char *command)
1564 {
1565     int is_my_command = (command && 0 == strcmp(command, "M"));
1566     if (ul == usage_all || !command || is_my_command)
1567     FPS "%-15s Modify trust attributes of certificate\n",
1568         "-M");
1569     if (ul == usage_selected && !is_my_command)
1570         return;
1571     FPS "%-20s The nickname of the cert to modify\n",
1572         "   -n cert-name");
1573     FPS "%-20s Set the certificate trust attributes (see -A above)\n",
1574         "   -t trustargs");
1575     FPS "%-20s Cert database directory (default is ~/.netscape)\n",
1576         "   -d certdir");
1577     FPS "%-20s Cert & Key database prefix\n",
1578         "   -P dbprefix");
1579     FPS "\n");
1580 }
1581 
1582 static void
1583 luN(enum usage_level ul, const char *command)
1584 {
1585     int is_my_command = (command && 0 == strcmp(command, "N"));
1586     if (ul == usage_all || !command || is_my_command)
1587     FPS "%-15s Create a new certificate database\n",
1588         "-N");
1589     if (ul == usage_selected && !is_my_command)
1590         return;
1591     FPS "%-20s Cert database directory (default is ~/.netscape)\n",
1592         "   -d certdir");
1593     FPS "%-20s Cert & Key database prefix\n",
1594         "   -P dbprefix");
1595     FPS "%-20s Specify the password file\n",
1596         "   -f password-file");
1597     FPS "%-20s use empty password when creating a new database\n",
1598         "   --empty-password");
1599     FPS "\n");
1600 }
1601 
1602 static void
1603 luT(enum usage_level ul, const char *command)
1604 {
1605     int is_my_command = (command && 0 == strcmp(command, "T"));
1606     if (ul == usage_all || !command || is_my_command)
1607     FPS "%-15s Reset the Key database or token\n",
1608         "-T");
1609     if (ul == usage_selected && !is_my_command)
1610         return;
1611     FPS "%-20s Cert database directory (default is ~/.netscape)\n",
1612         "   -d certdir");
1613     FPS "%-20s Cert & Key database prefix\n",
1614         "   -P dbprefix");
1615     FPS "%-20s Token to reset (default is internal)\n",
1616         "   -h token-name");
1617     FPS "%-20s Set token's Site Security Officer password\n",
1618         "   -0 SSO-password");
1619     FPS "\n");
1620 }
1621 
1622 static void
1623 luO(enum usage_level ul, const char *command)
1624 {
1625     int is_my_command = (command && 0 == strcmp(command, "O"));
1626     if (ul == usage_all || !command || is_my_command)
1627     FPS "%-15s Print the chain of a certificate\n",
1628         "-O");
1629     if (ul == usage_selected && !is_my_command)
1630         return;
1631     FPS "%-20s The nickname of the cert to modify\n",
1632         "   -n cert-name");
1633     FPS "%-20s Cert database directory (default is ~/.netscape)\n",
1634         "   -d certdir");
1635     FPS "%-20s Input the certificate in ASCII (RFC1113); default is binary\n",
1636         "   -a");
1637     FPS "%-20s Cert & Key database prefix\n",
1638         "   -P dbprefix");
1639     FPS "%-20s force the database to open R/W\n",
1640         "   -X");
1641     FPS "%-20s don't search for a chain if issuer name equals subject name\n",
1642         "   --simple-self-signed");
1643     FPS "\n");
1644 }
1645 
1646 static void
1647 luR(enum usage_level ul, const char *command)
1648 {
1649     int is_my_command = (command && 0 == strcmp(command, "R"));
1650     if (ul == usage_all || !command || is_my_command)
1651     FPS "%-15s Generate a certificate request (stdout)\n",
1652         "-R");
1653     if (ul == usage_selected && !is_my_command)
1654         return;
1655     FPS "%-20s Specify the subject name (using RFC1485)\n",
1656         "   -s subject");
1657     FPS "%-20s Output the cert request to this file\n",
1658         "   -o output-req");
1659     FPS "%-20s Type of key pair to generate (\"dsa\", \"ec\", \"rsa\" (default))\n",
1660         "   -k key-type-or-id");
1661     FPS "%-20s or nickname of the cert key to use, or key id obtained using -K\n",
1662         "");
1663     FPS "%-20s Name of token in which to generate key (default is internal)\n",
1664         "   -h token-name");
1665     FPS "%-20s Key size in bits, RSA keys only (min %d, max %d, default %d)\n",
1666         "   -g key-size", MIN_KEY_BITS, MAX_KEY_BITS, DEFAULT_KEY_BITS);
1667     FPS "%-20s Create a certificate request restricted to RSA-PSS (rsa only)\n",
1668         "   --pss");
1669     FPS "%-20s Name of file containing PQG parameters (dsa only)\n",
1670         "   -q pqgfile");
1671     FPS "%-20s Elliptic curve name (ec only)\n",
1672         "   -q curve-name");
1673     FPS "%-20s See the \"-G\" option for a full list of supported names.\n",
1674         "");
1675     FPS "%-20s Specify the password file\n",
1676         "   -f pwfile");
1677     FPS "%-20s Key database directory (default is ~/.netscape)\n",
1678         "   -d keydir");
1679     FPS "%-20s Cert & Key database prefix\n",
1680         "   -P dbprefix");
1681     FPS "%-20s Specify the contact phone number (\"123-456-7890\")\n",
1682         "   -p phone");
1683     FPS "%-20s \n"
1684               "%-20s Specify the hash algorithm to use. Possible keywords:\n"
1685               "%-20s \"MD2\", \"MD4\", \"MD5\", \"SHA1\", \"SHA224\",\n"
1686               "%-20s \"SHA256\", \"SHA384\", \"SHA512\"\n",
1687         "   -Z hashAlg", "", "", "");
1688     FPS "%-20s Output the cert request in ASCII (RFC1113); default is binary\n",
1689         "   -a");
1690     FPS "%-20s \n",
1691         "   See -S for available extension options");
1692     FPS "%-20s \n",
1693         "   See -G for available key flag options");
1694     FPS "\n");
1695 }
1696 
1697 static void
1698 luV(enum usage_level ul, const char *command)
1699 {
1700     int is_my_command = (command && 0 == strcmp(command, "V"));
1701     if (ul == usage_all || !command || is_my_command)
1702     FPS "%-15s Validate a certificate\n",
1703         "-V");
1704     if (ul == usage_selected && !is_my_command)
1705         return;
1706     FPS "%-20s The nickname of the cert to Validate\n",
1707         "   -n cert-name");
1708     FPS "%-20s validity time (\"YYMMDDHHMMSS[+HHMM|-HHMM|Z]\")\n",
1709         "   -b time");
1710     FPS "%-20s Check certificate signature \n",
1711         "   -e ");
1712     FPS "%-20s Specify certificate usage:\n", "   -u certusage");
1713     FPS "%-25s C \t SSL Client\n", "");
1714     FPS "%-25s V \t SSL Server\n", "");
1715     FPS "%-25s I \t IPsec\n", "");
1716     FPS "%-25s L \t SSL CA\n", "");
1717     FPS "%-25s A \t Any CA\n", "");
1718     FPS "%-25s Y \t Verify CA\n", "");
1719     FPS "%-25s S \t Email signer\n", "");
1720     FPS "%-25s R \t Email Recipient\n", "");
1721     FPS "%-25s O \t OCSP status responder\n", "");
1722     FPS "%-25s J \t Object signer\n", "");
1723     FPS "%-20s Cert database directory (default is ~/.netscape)\n",
1724         "   -d certdir");
1725     FPS "%-20s Input the certificate in ASCII (RFC1113); default is binary\n",
1726         "   -a");
1727     FPS "%-20s Cert & Key database prefix\n",
1728         "   -P dbprefix");
1729     FPS "%-20s force the database to open R/W\n",
1730         "   -X");
1731     FPS "\n");
1732 }
1733 
1734 static void
1735 luW(enum usage_level ul, const char *command)
1736 {
1737     int is_my_command = (command && 0 == strcmp(command, "W"));
1738     if (ul == usage_all || !command || is_my_command)
1739     FPS "%-15s Change the key database password\n",
1740         "-W");
1741     if (ul == usage_selected && !is_my_command)
1742         return;
1743     FPS "%-20s cert and key database directory\n",
1744         "   -d certdir");
1745     FPS "%-20s Specify a file with the current password\n",
1746         "   -f pwfile");
1747     FPS "%-20s Specify a file with the new password in two lines\n",
1748         "   -@ newpwfile");
1749     FPS "\n");
1750 }
1751 
1752 static void
1753 luRename(enum usage_level ul, const char *command)
1754 {
1755     int is_my_command = (command && 0 == strcmp(command, "rename"));
1756     if (ul == usage_all || !command || is_my_command)
1757     FPS "%-15s Change the database nickname of a certificate\n",
1758         "--rename");
1759     if (ul == usage_selected && !is_my_command)
1760         return;
1761     FPS "%-20s The old nickname of the cert to rename\n",
1762         "   -n cert-name");
1763     FPS "%-20s The new nickname of the cert to rename\n",
1764         "   --new-n new-name");
1765     FPS "%-20s Cert database directory (default is ~/.netscape)\n",
1766         "   -d certdir");
1767     FPS "%-20s Cert & Key database prefix\n",
1768         "   -P dbprefix");
1769     FPS "\n");
1770 }
1771 
1772 static void
1773 luUpgradeMerge(enum usage_level ul, const char *command)
1774 {
1775     int is_my_command = (command && 0 == strcmp(command, "upgrade-merge"));
1776     if (ul == usage_all || !command || is_my_command)
1777     FPS "%-15s Upgrade an old database and merge it into a new one\n",
1778         "--upgrade-merge");
1779     if (ul == usage_selected && !is_my_command)
1780         return;
1781     FPS "%-20s Cert database directory to merge into (default is ~/.netscape)\n",
1782         "   -d certdir");
1783     FPS "%-20s Cert & Key database prefix of the target database\n",
1784         "   -P dbprefix");
1785     FPS "%-20s Specify the password file for the target database\n",
1786         "   -f pwfile");
1787     FPS "%-20s \n%-20s Cert database directory to upgrade from\n",
1788         "   --source-dir certdir", "");
1789     FPS "%-20s \n%-20s Cert & Key database prefix of the upgrade database\n",
1790         "   --source-prefix dbprefix", "");
1791     FPS "%-20s \n%-20s Unique identifier for the upgrade database\n",
1792         "   --upgrade-id uniqueID", "");
1793     FPS "%-20s \n%-20s Name of the token while it is in upgrade state\n",
1794         "   --upgrade-token-name name", "");
1795     FPS "%-20s Specify the password file for the upgrade database\n",
1796         "   -@ pwfile");
1797     FPS "\n");
1798 }
1799 
1800 static void
1801 luMerge(enum usage_level ul, const char *command)
1802 {
1803     int is_my_command = (command && 0 == strcmp(command, "merge"));
1804     if (ul == usage_all || !command || is_my_command)
1805     FPS "%-15s Merge source database into the target database\n",
1806         "--merge");
1807     if (ul == usage_selected && !is_my_command)
1808         return;
1809     FPS "%-20s Cert database directory of target (default is ~/.netscape)\n",
1810         "   -d certdir");
1811     FPS "%-20s Cert & Key database prefix of the target database\n",
1812         "   -P dbprefix");
1813     FPS "%-20s Specify the password file for the target database\n",
1814         "   -f pwfile");
1815     FPS "%-20s \n%-20s Cert database directory of the source database\n",
1816         "   --source-dir certdir", "");
1817     FPS "%-20s \n%-20s Cert & Key database prefix of the source database\n",
1818         "   --source-prefix dbprefix", "");
1819     FPS "%-20s Specify the password file for the source database\n",
1820         "   -@ pwfile");
1821     FPS "\n");
1822 }
1823 
1824 static void
1825 luS(enum usage_level ul, const char *command)
1826 {
1827     int is_my_command = (command && 0 == strcmp(command, "S"));
1828     if (ul == usage_all || !command || is_my_command)
1829     FPS "%-15s Make a certificate and add to database\n",
1830         "-S");
1831     if (ul == usage_selected && !is_my_command)
1832         return;
1833     FPS "%-20s Specify the nickname of the cert\n",
1834         "   -n key-name");
1835     FPS "%-20s Specify the subject name (using RFC1485)\n",
1836         "   -s subject");
1837     FPS "%-20s The nickname of the issuer cert\n",
1838         "   -c issuer-name");
1839     FPS "%-20s Set the certificate trust attributes (see -A above)\n",
1840         "   -t trustargs");
1841     FPS "%-20s Type of key pair to generate (\"dsa\", \"ec\", \"rsa\" (default))\n",
1842         "   -k key-type-or-id");
1843     FPS "%-20s Name of token in which to generate key (default is internal)\n",
1844         "   -h token-name");
1845     FPS "%-20s Key size in bits, RSA keys only (min %d, max %d, default %d)\n",
1846         "   -g key-size", MIN_KEY_BITS, MAX_KEY_BITS, DEFAULT_KEY_BITS);
1847     FPS "%-20s Create a certificate restricted to RSA-PSS (rsa only)\n",
1848         "   --pss");
1849     FPS "%-20s Name of file containing PQG parameters (dsa only)\n",
1850         "   -q pqgfile");
1851     FPS "%-20s Elliptic curve name (ec only)\n",
1852         "   -q curve-name");
1853     FPS "%-20s See the \"-G\" option for a full list of supported names.\n",
1854         "");
1855     FPS "%-20s Self sign\n",
1856         "   -x");
1857     FPS "%-20s Sign the certificate with RSA-PSS (the issuer key must be rsa)\n",
1858         "   --pss-sign");
1859     FPS "%-20s Cert serial number\n",
1860         "   -m serial-number");
1861     FPS "%-20s Time Warp\n",
1862         "   -w warp-months");
1863     FPS "%-20s Months valid (default is 3)\n",
1864         "   -v months-valid");
1865     FPS "%-20s Specify the password file\n",
1866         "   -f pwfile");
1867     FPS "%-20s Cert database directory (default is ~/.netscape)\n",
1868         "   -d certdir");
1869     FPS "%-20s Cert & Key database prefix\n",
1870         "   -P dbprefix");
1871     FPS "%-20s Specify the contact phone number (\"123-456-7890\")\n",
1872         "   -p phone");
1873     FPS "%-20s \n"
1874               "%-20s Specify the hash algorithm to use. Possible keywords:\n"
1875               "%-20s \"MD2\", \"MD4\", \"MD5\", \"SHA1\", \"SHA224\",\n"
1876               "%-20s \"SHA256\", \"SHA384\", \"SHA512\"\n",
1877         "   -Z hashAlg", "", "", "");
1878     FPS "%-20s Create key usage extension\n",
1879         "   -1 ");
1880     FPS "%-20s Create basic constraint extension\n",
1881         "   -2 ");
1882     FPS "%-20s Create authority key ID extension\n",
1883         "   -3 ");
1884     FPS "%-20s Create crl distribution point extension\n",
1885         "   -4 ");
1886     FPS "%-20s Create netscape cert type extension\n",
1887         "   -5 ");
1888     FPS "%-20s Create extended key usage extension\n",
1889         "   -6 ");
1890     FPS "%-20s Create an email subject alt name extension\n",
1891         "   -7 emailAddrs ");
1892     FPS "%-20s Create a DNS subject alt name extension\n",
1893         "   -8 DNS-names");
1894     FPS "%-20s Create an Authority Information Access extension\n",
1895         "   --extAIA ");
1896     FPS "%-20s Create a Subject Information Access extension\n",
1897         "   --extSIA ");
1898     FPS "%-20s Create a Certificate Policies extension\n",
1899         "   --extCP ");
1900     FPS "%-20s Create a Policy Mappings extension\n",
1901         "   --extPM ");
1902     FPS "%-20s Create a Policy Constraints extension\n",
1903         "   --extPC ");
1904     FPS "%-20s Create an Inhibit Any Policy extension\n",
1905         "   --extIA ");
1906     FPS "%-20s Create a subject key ID extension\n",
1907         "   --extSKID ");
1908     FPS "%-20s \n",
1909         "   See -G for available key flag options");
1910     FPS "%-20s Create a name constraints extension\n",
1911         "   --extNC ");
1912     FPS "%-20s \n"
1913         "%-20s Create a Subject Alt Name extension with one or multiple names\n",
1914         "   --extSAN type:name[,type:name]...", "");
1915     FPS "%-20s - type: directory, dn, dns, edi, ediparty, email, ip, ipaddr,\n", "");
1916     FPS "%-20s         other, registerid, rfc822, uri, x400, x400addr\n", "");
1917     FPS "%-20s \n"
1918         "%-20s Add one or multiple extensions that certutil cannot encode yet,\n"
1919         "%-20s by loading their encodings from external files.\n",
1920         "   --extGeneric OID:critical-flag:filename[,OID:critical-flag:filename]...", "", "");
1921     FPS "%-20s - OID (example): 1.2.3.4\n", "");
1922     FPS "%-20s - critical-flag: critical or not-critical\n", "");
1923     FPS "%-20s - filename: full path to a file containing an encoded extension\n", "");
1924     FPS "\n");
1925 }
1926 
1927 static void
1928 luBuildFlags(enum usage_level ul, const char *command)
1929 {
1930     int is_my_command = (command && 0 == strcmp(command, "build-flags"));
1931     if (ul == usage_all || !command || is_my_command)
1932     FPS "%-15s Print enabled build flags relevant for NSS test execution\n",
1933         "--build-flags");
1934     if (ul == usage_selected && !is_my_command)
1935         return;
1936     FPS "\n");
1937 }
1938 
1939 static void
1940 LongUsage(enum usage_level ul, const char *command)
1941 {
1942     luA(ul, command);
1943     luB(ul, command);
1944     luE(ul, command);
1945     luC(ul, command);
1946     luG(ul, command);
1947     luD(ul, command);
1948     luRename(ul, command);
1949     luF(ul, command);
1950     luU(ul, command);
1951     luK(ul, command);
1952     luL(ul, command);
1953     luBuildFlags(ul, command);
1954     luM(ul, command);
1955     luN(ul, command);
1956     luT(ul, command);
1957     luO(ul, command);
1958     luR(ul, command);
1959     luV(ul, command);
1960     luW(ul, command);
1961     luUpgradeMerge(ul, command);
1962     luMerge(ul, command);
1963     luS(ul, command);
1964 #undef FPS
1965 }
1966 
1967 static void
1968 Usage()
1969 {
1970     PR_fprintf(PR_STDERR,
1971                "%s - Utility to manipulate NSS certificate databases\n\n"
1972                "Usage:  %s <command> -d <database-directory> <options>\n\n"
1973                "Valid commands:\n",
1974                progName, progName);
1975     LongUsage(usage_selected, NULL);
1976     PR_fprintf(PR_STDERR, "\n"
1977                           "%s -H <command> : Print available options for the given command\n"
1978                           "%s -H : Print complete help output of all commands and options\n"
1979                           "%s --syntax : Print a short summary of all commands and options\n",
1980                progName, progName, progName);
1981     exit(1);
1982 }
1983 
1984 static CERTCertificate *
1985 MakeV1Cert(CERTCertDBHandle *handle,
1986            CERTCertificateRequest *req,
1987            char *issuerNickName,
1988            PRBool selfsign,
1989            unsigned int serialNumber,
1990            int warpmonths,
1991            int validityMonths)
1992 {
1993     CERTCertificate *issuerCert = NULL;
1994     CERTValidity *validity;
1995     CERTCertificate *cert = NULL;
1996     PRExplodedTime printableTime;
1997     PRTime now, after;
1998 
1999     if (!selfsign) {
2000         issuerCert = CERT_FindCertByNicknameOrEmailAddr(handle, issuerNickName);
2001         if (!issuerCert) {
2002             SECU_PrintError(progName, "could not find certificate named \"%s\"",
2003                             issuerNickName);
2004             return NULL;
2005         }
2006     }
2007 
2008     now = PR_Now();
2009     PR_ExplodeTime(now, PR_GMTParameters, &printableTime);
2010     if (warpmonths) {
2011         printableTime.tm_month += warpmonths;
2012         now = PR_ImplodeTime(&printableTime);
2013         PR_ExplodeTime(now, PR_GMTParameters, &printableTime);
2014     }
2015     printableTime.tm_month += validityMonths;
2016     after = PR_ImplodeTime(&printableTime);
2017 
2018     /* note that the time is now in micro-second unit */
2019     validity = CERT_CreateValidity(now, after);
2020     if (validity) {
2021         cert = CERT_CreateCertificate(serialNumber,
2022                                       (selfsign ? &req->subject
2023                                                 : &issuerCert->subject),
2024                                       validity, req);
2025 
2026         CERT_DestroyValidity(validity);
2027     }
2028     if (issuerCert) {
2029         CERT_DestroyCertificate(issuerCert);
2030     }
2031 
2032     return (cert);
2033 }
2034 
2035 static SECStatus
2036 SetSignatureAlgorithm(PLArenaPool *arena,
2037                       SECAlgorithmID *signAlg,
2038                       SECAlgorithmID *spkiAlg,
2039                       SECOidTag hashAlgTag,
2040                       SECKEYPrivateKey *privKey,
2041                       PRBool pssSign)
2042 {
2043     SECStatus rv;
2044 
2045     if (pssSign ||
2046         SECOID_GetAlgorithmTag(spkiAlg) == SEC_OID_PKCS1_RSA_PSS_SIGNATURE) {
2047         SECItem *srcParams;
2048         SECItem *params;
2049 
2050         if (SECOID_GetAlgorithmTag(spkiAlg) == SEC_OID_PKCS1_RSA_PSS_SIGNATURE) {
2051             srcParams = &spkiAlg->parameters;
2052         } else {
2053             /* If the issuer's public key is RSA, the parameter field
2054              * of the SPKI should be NULL, which can't be used as a
2055              * basis of RSA-PSS parameters. */
2056             srcParams = NULL;
2057         }
2058         params = SEC_CreateSignatureAlgorithmParameters(arena,
2059                                                         NULL,
2060                                                         SEC_OID_PKCS1_RSA_PSS_SIGNATURE,
2061                                                         hashAlgTag,
2062                                                         srcParams,
2063                                                         privKey);
2064         if (!params) {
2065             SECU_PrintError(progName, "Could not create RSA-PSS parameters");
2066             return SECFailure;
2067         }
2068         rv = SECOID_SetAlgorithmID(arena, signAlg,
2069                                    SEC_OID_PKCS1_RSA_PSS_SIGNATURE,
2070                                    params);
2071         if (rv != SECSuccess) {
2072             SECU_PrintError(progName, "Could not set signature algorithm id.");
2073             return rv;
2074         }
2075     } else {
2076         KeyType keyType = SECKEY_GetPrivateKeyType(privKey);
2077         SECOidTag algID;
2078 
2079         algID = SEC_GetSignatureAlgorithmOidTag(keyType, hashAlgTag);
2080         if (algID == SEC_OID_UNKNOWN) {
2081             SECU_PrintError(progName, "Unknown key or hash type for issuer.");
2082             return SECFailure;
2083         }
2084         rv = SECOID_SetAlgorithmID(arena, signAlg, algID, 0);
2085         if (rv != SECSuccess) {
2086             SECU_PrintError(progName, "Could not set signature algorithm id.");
2087             return rv;
2088         }
2089     }
2090     return SECSuccess;
2091 }
2092 
2093 static SECStatus
2094 SignCert(CERTCertDBHandle *handle, CERTCertificate *cert, PRBool selfsign,
2095          SECOidTag hashAlgTag,
2096          SECKEYPrivateKey *privKey, char *issuerNickName,
2097          int certVersion, PRBool pssSign, void *pwarg)
2098 {
2099     SECItem der;
2100     SECKEYPrivateKey *caPrivateKey = NULL;
2101     SECStatus rv;
2102     PLArenaPool *arena;
2103     CERTCertificate *issuer;
2104     void *dummy;
2105 
2106     arena = cert->arena;
2107 
2108     if (selfsign) {
2109         issuer = cert;
2110     } else {
2111         issuer = PK11_FindCertFromNickname(issuerNickName, pwarg);
2112         if ((CERTCertificate *)NULL == issuer) {
2113             SECU_PrintError(progName, "unable to find issuer with nickname %s",
2114                             issuerNickName);
2115             rv = SECFailure;
2116             goto done;
2117         }
2118         privKey = caPrivateKey = PK11_FindKeyByAnyCert(issuer, pwarg);
2119         if (caPrivateKey == NULL) {
2120             SECU_PrintError(progName, "unable to retrieve key %s", issuerNickName);
2121             rv = SECFailure;
2122             CERT_DestroyCertificate(issuer);
2123             goto done;
2124         }
2125     }
2126 
2127     if (pssSign &&
2128         (SECKEY_GetPrivateKeyType(privKey) != rsaKey &&
2129          SECKEY_GetPrivateKeyType(privKey) != rsaPssKey)) {
2130         SECU_PrintError(progName, "unable to create RSA-PSS signature with key %s",
2131                         issuerNickName);
2132         rv = SECFailure;
2133         if (!selfsign) {
2134             CERT_DestroyCertificate(issuer);
2135         }
2136         goto done;
2137     }
2138 
2139     rv = SetSignatureAlgorithm(arena,
2140                                &cert->signature,
2141                                &issuer->subjectPublicKeyInfo.algorithm,
2142                                hashAlgTag,
2143                                privKey,
2144                                pssSign);
2145     if (!selfsign) {
2146         CERT_DestroyCertificate(issuer);
2147     }
2148     if (rv != SECSuccess) {
2149         goto done;
2150     }
2151 
2152     switch (certVersion) {
2153         case (SEC_CERTIFICATE_VERSION_1):
2154             /* The initial version for x509 certificates is version one
2155          * and this default value must be an implicit DER encoding. */
2156             cert->version.data = NULL;
2157             cert->version.len = 0;
2158             break;
2159         case (SEC_CERTIFICATE_VERSION_2):
2160         case (SEC_CERTIFICATE_VERSION_3):
2161         case 3: /* unspecified format (would be version 4 certificate). */
2162             *(cert->version.data) = certVersion;
2163             cert->version.len = 1;
2164             break;
2165         default:
2166             PORT_SetError(SEC_ERROR_INVALID_ARGS);
2167             rv = SECFailure;
2168             goto done;
2169     }
2170 
2171     der.len = 0;
2172     der.data = NULL;
2173     dummy = SEC_ASN1EncodeItem(arena, &der, cert,
2174                                SEC_ASN1_GET(CERT_CertificateTemplate));
2175     if (!dummy) {
2176         fprintf(stderr, "Could not encode certificate.\n");
2177         rv = SECFailure;
2178         goto done;
2179     }
2180 
2181     rv = SEC_DerSignDataWithAlgorithmID(arena, &cert->derCert, der.data, der.len,
2182                                         privKey, &cert->signature);
2183     if (rv != SECSuccess) {
2184         fprintf(stderr, "Could not sign encoded certificate data.\n");
2185         /* result allocated out of the arena, it will be freed
2186          * when the arena is freed */
2187         goto done;
2188     }
2189 done:
2190     if (caPrivateKey) {
2191         SECKEY_DestroyPrivateKey(caPrivateKey);
2192     }
2193     return rv;
2194 }
2195 
2196 static SECStatus
2197 CreateCert(
2198     CERTCertDBHandle *handle,
2199     PK11SlotInfo *slot,
2200     char *issuerNickName,
2201     const SECItem *certReqDER,
2202     SECKEYPrivateKey **selfsignprivkey,
2203     void *pwarg,
2204     SECOidTag hashAlgTag,
2205     unsigned int serialNumber,
2206     int warpmonths,
2207     int validityMonths,
2208     const char *emailAddrs,
2209     const char *dnsNames,
2210     PRBool ascii,
2211     PRBool selfsign,
2212     certutilExtnList extnList,
2213     const char *extGeneric,
2214     int certVersion,
2215     PRBool pssSign,
2216     SECItem *certDER)
2217 {
2218     void *extHandle = NULL;
2219     CERTCertificate *subjectCert = NULL;
2220     CERTCertificateRequest *certReq = NULL;
2221     SECStatus rv = SECSuccess;
2222     CERTCertExtension **CRexts;
2223 
2224     do {
2225         /* Create a certrequest object from the input cert request der */
2226         certReq = GetCertRequest(certReqDER, pwarg);
2227         if (certReq == NULL) {
2228             GEN_BREAK(SECFailure)
2229         }
2230 
2231         subjectCert = MakeV1Cert(handle, certReq, issuerNickName, selfsign,
2232                                  serialNumber, warpmonths, validityMonths);
2233         if (subjectCert == NULL) {
2234             GEN_BREAK(SECFailure)
2235         }
2236 
2237         extHandle = CERT_StartCertExtensions(subjectCert);
2238         if (extHandle == NULL) {
2239             GEN_BREAK(SECFailure)
2240         }
2241 
2242         rv = AddExtensions(extHandle, emailAddrs, dnsNames, extnList, extGeneric);
2243         if (rv != SECSuccess) {
2244             GEN_BREAK(SECFailure)
2245         }
2246 
2247         if (certReq->attributes != NULL &&
2248             certReq->attributes[0] != NULL &&
2249             certReq->attributes[0]->attrType.data != NULL &&
2250             certReq->attributes[0]->attrType.len > 0 &&
2251             SECOID_FindOIDTag(&certReq->attributes[0]->attrType) ==
2252                 SEC_OID_PKCS9_EXTENSION_REQUEST) {
2253             rv = CERT_GetCertificateRequestExtensions(certReq, &CRexts);
2254             if (rv != SECSuccess)
2255                 break;
2256             rv = CERT_MergeExtensions(extHandle, CRexts);
2257             if (rv != SECSuccess)
2258                 break;
2259         }
2260 
2261         CERT_FinishExtensions(extHandle);
2262         extHandle = NULL;
2263 
2264         /* self-signing a cert request, find the private key */
2265         if (selfsign && *selfsignprivkey == NULL) {
2266             *selfsignprivkey = PK11_FindKeyByDERCert(slot, subjectCert, pwarg);
2267             if (!*selfsignprivkey) {
2268                 fprintf(stderr, "Failed to locate private key.\n");
2269                 rv = SECFailure;
2270                 break;
2271             }
2272         }
2273 
2274         rv = SignCert(handle, subjectCert, selfsign, hashAlgTag,
2275                       *selfsignprivkey, issuerNickName,
2276                       certVersion, pssSign, pwarg);
2277         if (rv != SECSuccess)
2278             break;
2279 
2280         rv = SECFailure;
2281         if (ascii) {
2282             char *asciiDER = BTOA_DataToAscii(subjectCert->derCert.data,
2283                                               subjectCert->derCert.len);
2284             if (asciiDER) {
2285                 char *wrapped = PR_smprintf("%s\n%s\n%s\n",
2286                                             NS_CERT_HEADER,
2287                                             asciiDER,
2288                                             NS_CERT_TRAILER);
2289                 if (wrapped) {
2290                     PRUint32 wrappedLen = PL_strlen(wrapped);
2291                     if (SECITEM_AllocItem(NULL, certDER, wrappedLen)) {
2292                         PORT_Memcpy(certDER->data, wrapped, wrappedLen);
2293                         rv = SECSuccess;
2294                     }
2295                     PR_smprintf_free(wrapped);
2296                 }
2297                 PORT_Free(asciiDER);
2298             }
2299         } else {
2300             rv = SECITEM_CopyItem(NULL, certDER, &subjectCert->derCert);
2301         }
2302     } while (0);
2303     if (extHandle) {
2304         CERT_FinishExtensions(extHandle);
2305     }
2306     CERT_DestroyCertificateRequest(certReq);
2307     CERT_DestroyCertificate(subjectCert);
2308     if (rv != SECSuccess) {
2309         PRErrorCode perr = PR_GetError();
2310         fprintf(stderr, "%s: unable to create cert (%s)\n", progName,
2311                 SECU_Strerror(perr));
2312     }
2313     return (rv);
2314 }
2315 
2316 /*
2317  * map a class to a user presentable string
2318  */
2319 static const char *objClassArray[] = {
2320     "Data",
2321     "Certificate",
2322     "Public Key",
2323     "Private Key",
2324     "Secret Key",
2325     "Hardware Feature",
2326     "Domain Parameters",
2327     "Mechanism"
2328 };
2329 
2330 static const char *objNSSClassArray[] = {
2331     "CKO_NSS",
2332     "Crl",
2333     "SMIME Record",
2334     "Trust",
2335     "Builtin Root List"
2336 };
2337 
2338 const char *
2339 getObjectClass(CK_ULONG classType)
2340 {
2341     static char buf[sizeof(CK_ULONG) * 2 + 3];
2342 
2343     if (classType <= CKO_MECHANISM) {
2344         return objClassArray[classType];
2345     }
2346     if (classType >= CKO_NSS && classType <= CKO_NSS_BUILTIN_ROOT_LIST) {
2347         return objNSSClassArray[classType - CKO_NSS];
2348     }
2349     sprintf(buf, "0x%lx", classType);
2350     return buf;
2351 }
2352 
2353 typedef struct {
2354     char *name;
2355     int nameSize;
2356     CK_ULONG value;
2357 } flagArray;
2358 
2359 #define NAME_SIZE(x) #x, sizeof(#x) - 1
2360 
2361 flagArray opFlagsArray[] =
2362     {
2363       { NAME_SIZE(encrypt), CKF_ENCRYPT },
2364       { NAME_SIZE(decrypt), CKF_DECRYPT },
2365       { NAME_SIZE(sign), CKF_SIGN },
2366       { NAME_SIZE(sign_recover), CKF_SIGN_RECOVER },
2367       { NAME_SIZE(verify), CKF_VERIFY },
2368       { NAME_SIZE(verify_recover), CKF_VERIFY_RECOVER },
2369       { NAME_SIZE(wrap), CKF_WRAP },
2370       { NAME_SIZE(unwrap), CKF_UNWRAP },
2371       { NAME_SIZE(derive), CKF_DERIVE }
2372     };
2373 
2374 int opFlagsCount = PR_ARRAY_SIZE(opFlagsArray);
2375 
2376 flagArray attrFlagsArray[] =
2377     {
2378       { NAME_SIZE(token), PK11_ATTR_TOKEN },
2379       { NAME_SIZE(session), PK11_ATTR_SESSION },
2380       { NAME_SIZE(private), PK11_ATTR_PRIVATE },
2381       { NAME_SIZE(public), PK11_ATTR_PUBLIC },
2382       { NAME_SIZE(modifiable), PK11_ATTR_MODIFIABLE },
2383       { NAME_SIZE(unmodifiable), PK11_ATTR_UNMODIFIABLE },
2384       { NAME_SIZE(sensitive), PK11_ATTR_SENSITIVE },
2385       { NAME_SIZE(insensitive), PK11_ATTR_INSENSITIVE },
2386       { NAME_SIZE(extractable), PK11_ATTR_EXTRACTABLE },
2387       { NAME_SIZE(unextractable), PK11_ATTR_UNEXTRACTABLE }
2388     };
2389 
2390 int attrFlagsCount = PR_ARRAY_SIZE(attrFlagsArray);
2391 
2392 #define MAX_STRING 30
2393 CK_ULONG
2394 GetFlags(char *flagsString, flagArray *flags, int count)
2395 {
2396     CK_ULONG flagsValue = strtol(flagsString, NULL, 0);
2397     int i;
2398 
2399     if ((flagsValue != 0) || (*flagsString == 0)) {
2400         return flagsValue;
2401     }
2402     while (*flagsString) {
2403         for (i = 0; i < count; i++) {
2404             if (strncmp(flagsString, flags[i].name, flags[i].nameSize) ==
2405                 0) {
2406                 flagsValue |= flags[i].value;
2407                 flagsString += flags[i].nameSize;
2408                 if (*flagsString != 0) {
2409                     flagsString++;
2410                 }
2411                 break;
2412             }
2413         }
2414         if (i == count) {
2415             char name[MAX_STRING];
2416             char *tok;
2417 
2418             strncpy(name, flagsString, MAX_STRING);
2419             name[MAX_STRING - 1] = 0;
2420             tok = strchr(name, ',');
2421             if (tok) {
2422                 *tok = 0;
2423             }
2424             fprintf(stderr, "Unknown flag (%s)\n", name);
2425             tok = strchr(flagsString, ',');
2426             if (tok == NULL) {
2427                 break;
2428             }
2429             flagsString = tok + 1;
2430         }
2431     }
2432     return flagsValue;
2433 }
2434 
2435 CK_FLAGS
2436 GetOpFlags(char *flags)
2437 {
2438     return GetFlags(flags, opFlagsArray, opFlagsCount);
2439 }
2440 
2441 PK11AttrFlags
2442 GetAttrFlags(char *flags)
2443 {
2444     return GetFlags(flags, attrFlagsArray, attrFlagsCount);
2445 }
2446 
2447 char *
2448 mkNickname(unsigned char *data, int len)
2449 {
2450     char *nick = PORT_Alloc(len + 1);
2451     if (!nick) {
2452         return nick;
2453     }
2454     PORT_Memcpy(nick, data, len);
2455     nick[len] = 0;
2456     return nick;
2457 }
2458 
2459 /*
2460  * dump a PK11_MergeTokens error log to the console
2461  */
2462 void
2463 DumpMergeLog(const char *progname, PK11MergeLog *log)
2464 {
2465     PK11MergeLogNode *node;
2466 
2467     for (node = log->head; node; node = node->next) {
2468         SECItem attrItem;
2469         char *nickname = NULL;
2470         const char *objectClass = NULL;
2471         SECStatus rv;
2472 
2473         attrItem.data = NULL;
2474         rv = PK11_ReadRawAttribute(PK11_TypeGeneric, node->object,
2475                                    CKA_LABEL, &attrItem);
2476         if (rv == SECSuccess) {
2477             nickname = mkNickname(attrItem.data, attrItem.len);
2478             PORT_Free(attrItem.data);
2479         }
2480         attrItem.data = NULL;
2481         rv = PK11_ReadRawAttribute(PK11_TypeGeneric, node->object,
2482                                    CKA_CLASS, &attrItem);
2483         if (rv == SECSuccess) {
2484             if (attrItem.len == sizeof(CK_ULONG)) {
2485                 objectClass = getObjectClass(*(CK_ULONG *)attrItem.data);
2486             }
2487             PORT_Free(attrItem.data);
2488         }
2489 
2490         fprintf(stderr, "%s: Could not merge object %s (type %s): %s\n",
2491                 progName,
2492                 nickname ? nickname : "unnamed",
2493                 objectClass ? objectClass : "unknown",
2494                 SECU_Strerror(node->error));
2495 
2496         if (nickname) {
2497             PORT_Free(nickname);
2498         }
2499     }
2500 }
2501 
2502 /*  Certutil commands  */
2503 enum {
2504     cmd_AddCert = 0,
2505     cmd_CreateNewCert,
2506     cmd_DeleteCert,
2507     cmd_AddEmailCert,
2508     cmd_DeleteKey,
2509     cmd_GenKeyPair,
2510     cmd_PrintHelp,
2511     cmd_PrintSyntax,
2512     cmd_ListKeys,
2513     cmd_ListCerts,
2514     cmd_ModifyCertTrust,
2515     cmd_NewDBs,
2516     cmd_DumpChain,
2517     cmd_CertReq,
2518     cmd_CreateAndAddCert,
2519     cmd_TokenReset,
2520     cmd_ListModules,
2521     cmd_CheckCertValidity,
2522     cmd_ChangePassword,
2523     cmd_Version,
2524     cmd_Batch,
2525     cmd_Merge,
2526     cmd_UpgradeMerge, /* test only */
2527     cmd_Rename,
2528     cmd_BuildFlags,
2529     max_cmd
2530 };
2531 
2532 /*  Certutil options */
2533 enum certutilOpts {
2534     opt_SSOPass = 0,
2535     opt_AddKeyUsageExt,
2536     opt_AddBasicConstraintExt,
2537     opt_AddAuthorityKeyIDExt,
2538     opt_AddCRLDistPtsExt,
2539     opt_AddNSCertTypeExt,
2540     opt_AddExtKeyUsageExt,
2541     opt_ExtendedEmailAddrs,
2542     opt_ExtendedDNSNames,
2543     opt_ASCIIForIO,
2544     opt_ValidityTime,
2545     opt_IssuerName,
2546     opt_CertDir,
2547     opt_VerifySig,
2548     opt_PasswordFile,
2549     opt_KeySize,
2550     opt_TokenName,
2551     opt_InputFile,
2552     opt_Emailaddress,
2553     opt_KeyIndex,
2554     opt_KeyType,
2555     opt_DetailedInfo,
2556     opt_SerialNumber,
2557     opt_Nickname,
2558     opt_OutputFile,
2559     opt_PhoneNumber,
2560     opt_DBPrefix,
2561     opt_PQGFile,
2562     opt_BinaryDER,
2563     opt_Subject,
2564     opt_Trust,
2565     opt_Usage,
2566     opt_Validity,
2567     opt_OffsetMonths,
2568     opt_SelfSign,
2569     opt_RW,
2570     opt_Exponent,
2571     opt_NoiseFile,
2572     opt_Hash,
2573     opt_NewPasswordFile,
2574     opt_AddAuthInfoAccExt,
2575     opt_AddSubjInfoAccExt,
2576     opt_AddCertPoliciesExt,
2577     opt_AddPolicyMapExt,
2578     opt_AddPolicyConstrExt,
2579     opt_AddInhibAnyExt,
2580     opt_AddNameConstraintsExt,
2581     opt_AddSubjectKeyIDExt,
2582     opt_AddCmdKeyUsageExt,
2583     opt_AddCmdNSCertTypeExt,
2584     opt_AddCmdExtKeyUsageExt,
2585     opt_SourceDir,
2586     opt_SourcePrefix,
2587     opt_UpgradeID,
2588     opt_UpgradeTokenName,
2589     opt_KeyOpFlagsOn,
2590     opt_KeyOpFlagsOff,
2591     opt_KeyAttrFlags,
2592     opt_EmptyPassword,
2593     opt_CertVersion,
2594     opt_AddSubjectAltNameExt,
2595     opt_DumpExtensionValue,
2596     opt_GenericExtensions,
2597     opt_NewNickname,
2598     opt_Pss,
2599     opt_PssSign,
2600     opt_SimpleSelfSigned,
2601     opt_Help
2602 };
2603 
2604 static const secuCommandFlag commands_init[] =
2605     {
2606       { /* cmd_AddCert             */ 'A', PR_FALSE, 0, PR_FALSE },
2607       { /* cmd_CreateNewCert       */ 'C', PR_FALSE, 0, PR_FALSE },
2608       { /* cmd_DeleteCert          */ 'D', PR_FALSE, 0, PR_FALSE },
2609       { /* cmd_AddEmailCert        */ 'E', PR_FALSE, 0, PR_FALSE },
2610       { /* cmd_DeleteKey           */ 'F', PR_FALSE, 0, PR_FALSE },
2611       { /* cmd_GenKeyPair          */ 'G', PR_FALSE, 0, PR_FALSE },
2612       { /* cmd_PrintHelp           */ 'H', PR_FALSE, 0, PR_FALSE, "help" },
2613       { /* cmd_PrintSyntax         */ 0, PR_FALSE, 0, PR_FALSE,
2614         "syntax" },
2615       { /* cmd_ListKeys            */ 'K', PR_FALSE, 0, PR_FALSE },
2616       { /* cmd_ListCerts           */ 'L', PR_FALSE, 0, PR_FALSE },
2617       { /* cmd_ModifyCertTrust     */ 'M', PR_FALSE, 0, PR_FALSE },
2618       { /* cmd_NewDBs              */ 'N', PR_FALSE, 0, PR_FALSE },
2619       { /* cmd_DumpChain           */ 'O', PR_FALSE, 0, PR_FALSE },
2620       { /* cmd_CertReq             */ 'R', PR_FALSE, 0, PR_FALSE },
2621       { /* cmd_CreateAndAddCert    */ 'S', PR_FALSE, 0, PR_FALSE },
2622       { /* cmd_TokenReset          */ 'T', PR_FALSE, 0, PR_FALSE },
2623       { /* cmd_ListModules         */ 'U', PR_FALSE, 0, PR_FALSE },
2624       { /* cmd_CheckCertValidity   */ 'V', PR_FALSE, 0, PR_FALSE },
2625       { /* cmd_ChangePassword      */ 'W', PR_FALSE, 0, PR_FALSE },
2626       { /* cmd_Version             */ 'Y', PR_FALSE, 0, PR_FALSE },
2627       { /* cmd_Batch               */ 'B', PR_FALSE, 0, PR_FALSE },
2628       { /* cmd_Merge               */ 0, PR_FALSE, 0, PR_FALSE, "merge" },
2629       { /* cmd_UpgradeMerge        */ 0, PR_FALSE, 0, PR_FALSE,
2630         "upgrade-merge" },
2631       { /* cmd_Rename              */ 0, PR_FALSE, 0, PR_FALSE,
2632         "rename" },
2633       { /* cmd_BuildFlags          */ 0, PR_FALSE, 0, PR_FALSE,
2634         "build-flags" }
2635     };
2636 #define NUM_COMMANDS ((sizeof commands_init) / (sizeof commands_init[0]))
2637 
2638 static const secuCommandFlag options_init[] =
2639     {
2640       { /* opt_SSOPass             */ '0', PR_TRUE, 0, PR_FALSE },
2641       { /* opt_AddKeyUsageExt      */ '1', PR_FALSE, 0, PR_FALSE },
2642       { /* opt_AddBasicConstraintExt*/ '2', PR_FALSE, 0, PR_FALSE },
2643       { /* opt_AddAuthorityKeyIDExt*/ '3', PR_FALSE, 0, PR_FALSE },
2644       { /* opt_AddCRLDistPtsExt    */ '4', PR_FALSE, 0, PR_FALSE },
2645       { /* opt_AddNSCertTypeExt    */ '5', PR_FALSE, 0, PR_FALSE },
2646       { /* opt_AddExtKeyUsageExt   */ '6', PR_FALSE, 0, PR_FALSE },
2647       { /* opt_ExtendedEmailAddrs  */ '7', PR_TRUE, 0, PR_FALSE },
2648       { /* opt_ExtendedDNSNames    */ '8', PR_TRUE, 0, PR_FALSE },
2649       { /* opt_ASCIIForIO          */ 'a', PR_FALSE, 0, PR_FALSE },
2650       { /* opt_ValidityTime        */ 'b', PR_TRUE, 0, PR_FALSE },
2651       { /* opt_IssuerName          */ 'c', PR_TRUE, 0, PR_FALSE },
2652       { /* opt_CertDir             */ 'd', PR_TRUE, 0, PR_FALSE },
2653       { /* opt_VerifySig           */ 'e', PR_FALSE, 0, PR_FALSE },
2654       { /* opt_PasswordFile        */ 'f', PR_TRUE, 0, PR_FALSE },
2655       { /* opt_KeySize             */ 'g', PR_TRUE, 0, PR_FALSE },
2656       { /* opt_TokenName           */ 'h', PR_TRUE, 0, PR_FALSE },
2657       { /* opt_InputFile           */ 'i', PR_TRUE, 0, PR_FALSE },
2658       { /* opt_Emailaddress        */ 0, PR_TRUE, 0, PR_FALSE, "email" },
2659       { /* opt_KeyIndex            */ 'j', PR_TRUE, 0, PR_FALSE },
2660       { /* opt_KeyType             */ 'k', PR_TRUE, 0, PR_FALSE },
2661       { /* opt_DetailedInfo        */ 'l', PR_FALSE, 0, PR_FALSE },
2662       { /* opt_SerialNumber        */ 'm', PR_TRUE, 0, PR_FALSE },
2663       { /* opt_Nickname            */ 'n', PR_TRUE, 0, PR_FALSE },
2664       { /* opt_OutputFile          */ 'o', PR_TRUE, 0, PR_FALSE },
2665       { /* opt_PhoneNumber         */ 'p', PR_TRUE, 0, PR_FALSE },
2666       { /* opt_DBPrefix            */ 'P', PR_TRUE, 0, PR_FALSE },
2667       { /* opt_PQGFile             */ 'q', PR_TRUE, 0, PR_FALSE },
2668       { /* opt_BinaryDER           */ 'r', PR_FALSE, 0, PR_FALSE },
2669       { /* opt_Subject             */ 's', PR_TRUE, 0, PR_FALSE },
2670       { /* opt_Trust               */ 't', PR_TRUE, 0, PR_FALSE },
2671       { /* opt_Usage               */ 'u', PR_TRUE, 0, PR_FALSE },
2672       { /* opt_Validity            */ 'v', PR_TRUE, 0, PR_FALSE },
2673       { /* opt_OffsetMonths        */ 'w', PR_TRUE, 0, PR_FALSE },
2674       { /* opt_SelfSign            */ 'x', PR_FALSE, 0, PR_FALSE },
2675       { /* opt_RW                  */ 'X', PR_FALSE, 0, PR_FALSE },
2676       { /* opt_Exponent            */ 'y', PR_TRUE, 0, PR_FALSE },
2677       { /* opt_NoiseFile           */ 'z', PR_TRUE, 0, PR_FALSE },
2678       { /* opt_Hash                */ 'Z', PR_TRUE, 0, PR_FALSE },
2679       { /* opt_NewPasswordFile     */ '@', PR_TRUE, 0, PR_FALSE },
2680       { /* opt_AddAuthInfoAccExt   */ 0, PR_FALSE, 0, PR_FALSE, "extAIA" },
2681       { /* opt_AddSubjInfoAccExt   */ 0, PR_FALSE, 0, PR_FALSE, "extSIA" },
2682       { /* opt_AddCertPoliciesExt  */ 0, PR_FALSE, 0, PR_FALSE, "extCP" },
2683       { /* opt_AddPolicyMapExt     */ 0, PR_FALSE, 0, PR_FALSE, "extPM" },
2684       { /* opt_AddPolicyConstrExt  */ 0, PR_FALSE, 0, PR_FALSE, "extPC" },
2685       { /* opt_AddInhibAnyExt      */ 0, PR_FALSE, 0, PR_FALSE, "extIA" },
2686       { /* opt_AddNameConstraintsExt*/ 0, PR_FALSE, 0, PR_FALSE, "extNC" },
2687       { /* opt_AddSubjectKeyIDExt  */ 0, PR_FALSE, 0, PR_FALSE,
2688         "extSKID" },
2689       { /* opt_AddCmdKeyUsageExt   */ 0, PR_TRUE, 0, PR_FALSE,
2690         "keyUsage" },
2691       { /* opt_AddCmdNSCertTypeExt */ 0, PR_TRUE, 0, PR_FALSE,
2692         "nsCertType" },
2693       { /* opt_AddCmdExtKeyUsageExt*/ 0, PR_TRUE, 0, PR_FALSE,
2694         "extKeyUsage" },
2695 
2696       { /* opt_SourceDir           */ 0, PR_TRUE, 0, PR_FALSE,
2697         "source-dir" },
2698       { /* opt_SourcePrefix        */ 0, PR_TRUE, 0, PR_FALSE,
2699         "source-prefix" },
2700       { /* opt_UpgradeID           */ 0, PR_TRUE, 0, PR_FALSE,
2701         "upgrade-id" },
2702       { /* opt_UpgradeTokenName    */ 0, PR_TRUE, 0, PR_FALSE,
2703         "upgrade-token-name" },
2704       { /* opt_KeyOpFlagsOn        */ 0, PR_TRUE, 0, PR_FALSE,
2705         "keyOpFlagsOn" },
2706       { /* opt_KeyOpFlagsOff       */ 0, PR_TRUE, 0, PR_FALSE,
2707         "keyOpFlagsOff" },
2708       { /* opt_KeyAttrFlags        */ 0, PR_TRUE, 0, PR_FALSE,
2709         "keyAttrFlags" },
2710       { /* opt_EmptyPassword       */ 0, PR_FALSE, 0, PR_FALSE,
2711         "empty-password" },
2712       { /* opt_CertVersion         */ 0, PR_TRUE, 0, PR_FALSE,
2713         "certVersion" },
2714       { /* opt_AddSubjectAltExt    */ 0, PR_TRUE, 0, PR_FALSE, "extSAN" },
2715       { /* opt_DumpExtensionValue  */ 0, PR_TRUE, 0, PR_FALSE,
2716         "dump-ext-val" },
2717       { /* opt_GenericExtensions   */ 0, PR_TRUE, 0, PR_FALSE,
2718         "extGeneric" },
2719       { /* opt_NewNickname         */ 0, PR_TRUE, 0, PR_FALSE,
2720         "new-n" },
2721       { /* opt_Pss                 */ 0, PR_FALSE, 0, PR_FALSE,
2722         "pss" },
2723       { /* opt_PssSign             */ 0, PR_FALSE, 0, PR_FALSE,
2724         "pss-sign" },
2725       { /* opt_SimpleSelfSigned    */ 0, PR_FALSE, 0, PR_FALSE,
2726         "simple-self-signed" },
2727     };
2728 #define NUM_OPTIONS ((sizeof options_init) / (sizeof options_init[0]))
2729 
2730 static secuCommandFlag certutil_commands[NUM_COMMANDS];
2731 static secuCommandFlag certutil_options[NUM_OPTIONS];
2732 
2733 static const secuCommand certutil = {
2734     NUM_COMMANDS,
2735     NUM_OPTIONS,
2736     certutil_commands,
2737     certutil_options
2738 };
2739 
2740 static certutilExtnList certutil_extns;
2741 
2742 static int
2743 certutil_main(int argc, char **argv, PRBool initialize)
2744 {
2745     CERTCertDBHandle *certHandle;
2746     PK11SlotInfo *slot = NULL;
2747     CERTName *subject = 0;
2748     PRFileDesc *inFile = PR_STDIN;
2749     PRFileDesc *outFile = PR_STDOUT;
2750     SECItem certReqDER = { siBuffer, NULL, 0 };
2751     SECItem certDER = { siBuffer, NULL, 0 };
2752     const char *slotname = "internal";
2753     const char *certPrefix = "";
2754     char *sourceDir = "";
2755     const char *srcCertPrefix = "";
2756     char *upgradeID = "";
2757     char *upgradeTokenName = "";
2758     KeyType keytype = rsaKey;
2759     char *name = NULL;
2760     char *newName = NULL;
2761     char *email = NULL;
2762     char *keysource = NULL;
2763     SECOidTag hashAlgTag = SEC_OID_UNKNOWN;
2764     int keysize = DEFAULT_KEY_BITS;
2765     int publicExponent = 0x010001;
2766     int certVersion = SEC_CERTIFICATE_VERSION_3;
2767     unsigned int serialNumber = 0;
2768     int warpmonths = 0;
2769     int validityMonths = 3;
2770     int commandsEntered = 0;
2771     char commandToRun = '\0';
2772     secuPWData pwdata = { PW_NONE, 0 };
2773     secuPWData pwdata2 = { PW_NONE, 0 };
2774     PRBool readOnly = PR_FALSE;
2775     PRBool initialized = PR_FALSE;
2776     CK_FLAGS keyOpFlagsOn = 0;
2777     CK_FLAGS keyOpFlagsOff = 0;
2778     PK11AttrFlags keyAttrFlags =
2779         PK11_ATTR_TOKEN | PK11_ATTR_SENSITIVE | PK11_ATTR_PRIVATE;
2780 
2781     SECKEYPrivateKey *privkey = NULL;
2782     SECKEYPublicKey *pubkey = NULL;
2783 
2784     int i;
2785     SECStatus rv;
2786 
2787     progName = PORT_Strrchr(argv[0], '/');
2788     progName = progName ? progName + 1 : argv[0];
2789     memcpy(certutil_commands, commands_init, sizeof commands_init);
2790     memcpy(certutil_options, options_init, sizeof options_init);
2791 
2792     rv = SECU_ParseCommandLine(argc, argv, progName, &certutil);
2793 
2794     if (rv != SECSuccess)
2795         Usage();
2796 
2797     if (certutil.commands[cmd_PrintSyntax].activated) {
2798         PrintSyntax();
2799     }
2800 
2801     if (certutil.commands[cmd_PrintHelp].activated) {
2802         char buf[2];
2803         const char *command = NULL;
2804         for (i = 0; i < max_cmd; i++) {
2805             if (i == cmd_PrintHelp)
2806                 continue;
2807             if (certutil.commands[i].activated) {
2808                 if (certutil.commands[i].flag) {
2809                     buf[0] = certutil.commands[i].flag;
2810                     buf[1] = 0;
2811                     command = buf;
2812                 } else {
2813                     command = certutil.commands[i].longform;
2814                 }
2815                 break;
2816             }
2817         }
2818         LongUsage((command ? usage_selected : usage_all), command);
2819         exit(1);
2820     }
2821 
2822     if (certutil.commands[cmd_BuildFlags].activated) {
2823         PrintBuildFlags();
2824     }
2825 
2826     if (certutil.options[opt_PasswordFile].arg) {
2827         pwdata.source = PW_FROMFILE;
2828         pwdata.data = certutil.options[opt_PasswordFile].arg;
2829     }
2830     if (certutil.options[opt_NewPasswordFile].arg) {
2831         pwdata2.source = PW_FROMFILE;
2832         pwdata2.data = certutil.options[opt_NewPasswordFile].arg;
2833     }
2834 
2835     if (certutil.options[opt_CertDir].activated)
2836         SECU_ConfigDirectory(certutil.options[opt_CertDir].arg);
2837 
2838     if (certutil.options[opt_SourceDir].activated)
2839         sourceDir = certutil.options[opt_SourceDir].arg;
2840 
2841     if (certutil.options[opt_UpgradeID].activated)
2842         upgradeID = certutil.options[opt_UpgradeID].arg;
2843 
2844     if (certutil.options[opt_UpgradeTokenName].activated)
2845         upgradeTokenName = certutil.options[opt_UpgradeTokenName].arg;
2846 
2847     if (certutil.options[opt_KeySize].activated) {
2848         keysize = PORT_Atoi(certutil.options[opt_KeySize].arg);
2849         if ((keysize < MIN_KEY_BITS) || (keysize > MAX_KEY_BITS)) {
2850             PR_fprintf(PR_STDERR,
2851                        "%s -g:  Keysize must be between %d and %d.\n",
2852                        progName, MIN_KEY_BITS, MAX_KEY_BITS);
2853             return 255;
2854         }
2855         if (keytype == ecKey) {
2856             PR_fprintf(PR_STDERR, "%s -g:  Not for ec keys.\n", progName);
2857             return 255;
2858         }
2859     }
2860 
2861     /*  -h specify token name  */
2862     if (certutil.options[opt_TokenName].activated) {
2863         if (PL_strcmp(certutil.options[opt_TokenName].arg, "all") == 0)
2864             slotname = NULL;
2865         else
2866             slotname = certutil.options[opt_TokenName].arg;
2867     }
2868 
2869     /*  -Z hash type  */
2870     if (certutil.options[opt_Hash].activated) {
2871         char *arg = certutil.options[opt_Hash].arg;
2872         hashAlgTag = SECU_StringToSignatureAlgTag(arg);
2873         if (hashAlgTag == SEC_OID_UNKNOWN) {
2874             PR_fprintf(PR_STDERR, "%s -Z:  %s is not a recognized type.\n",
2875                        progName, arg);
2876             return 255;
2877         }
2878     }
2879 
2880     /*  -k key type  */
2881     if (certutil.options[opt_KeyType].activated) {
2882         char *arg = certutil.options[opt_KeyType].arg;
2883         if (PL_strcmp(arg, "rsa") == 0) {
2884             keytype = rsaKey;
2885         } else if (PL_strcmp(arg, "dsa") == 0) {
2886             keytype = dsaKey;
2887         } else if (PL_strcmp(arg, "ec") == 0) {
2888             keytype = ecKey;
2889         } else if (PL_strcmp(arg, "all") == 0) {
2890             keytype = nullKey;
2891         } else {
2892             /* use an existing private/public key pair */
2893             keysource = arg;
2894         }
2895     } else if (certutil.commands[cmd_ListKeys].activated) {
2896         keytype = nullKey;
2897     }
2898 
2899     if (certutil.options[opt_KeyOpFlagsOn].activated) {
2900         keyOpFlagsOn = GetOpFlags(certutil.options[opt_KeyOpFlagsOn].arg);
2901     }
2902     if (certutil.options[opt_KeyOpFlagsOff].activated) {
2903         keyOpFlagsOff = GetOpFlags(certutil.options[opt_KeyOpFlagsOff].arg);
2904         keyOpFlagsOn &= ~keyOpFlagsOff; /* make off override on */
2905     }
2906     if (certutil.options[opt_KeyAttrFlags].activated) {
2907         keyAttrFlags = GetAttrFlags(certutil.options[opt_KeyAttrFlags].arg);
2908     }
2909 
2910     /*  -m serial number */
2911     if (certutil.options[opt_SerialNumber].activated) {
2912         int sn = PORT_Atoi(certutil.options[opt_SerialNumber].arg);
2913         if (sn < 0) {
2914             PR_fprintf(PR_STDERR, "%s -m:  %s is not a valid serial number.\n",
2915                        progName, certutil.options[opt_SerialNumber].arg);
2916             return 255;
2917         }
2918         serialNumber = sn;
2919     }
2920 
2921     /*  -P certdb name prefix */
2922     if (certutil.options[opt_DBPrefix].activated) {
2923         if (certutil.options[opt_DBPrefix].arg) {
2924             certPrefix = certutil.options[opt_DBPrefix].arg;
2925         } else {
2926             Usage();
2927         }
2928     }
2929 
2930     /*  --source-prefix certdb name prefix */
2931     if (certutil.options[opt_SourcePrefix].activated) {
2932         if (certutil.options[opt_SourcePrefix].arg) {
2933             srcCertPrefix = certutil.options[opt_SourcePrefix].arg;
2934         } else {
2935             Usage();
2936         }
2937     }
2938 
2939     /*  -q PQG file or curve name */
2940     if (certutil.options[opt_PQGFile].activated) {
2941         if ((keytype != dsaKey) && (keytype != ecKey)) {
2942             PR_fprintf(PR_STDERR, "%s -q: specifies a PQG file for DSA keys"
2943                                   " (-k dsa) or a named curve for EC keys (-k ec)\n)",
2944                        progName);
2945             return 255;
2946         }
2947     }
2948 
2949     /*  -s subject name  */
2950     if (certutil.options[opt_Subject].activated) {
2951         subject = CERT_AsciiToName(certutil.options[opt_Subject].arg);
2952         if (!subject) {
2953             PR_fprintf(PR_STDERR, "%s -s: improperly formatted name: \"%s\"\n",
2954                        progName, certutil.options[opt_Subject].arg);
2955             return 255;
2956         }
2957     }
2958 
2959     /*  -v validity period  */
2960     if (certutil.options[opt_Validity].activated) {
2961         validityMonths = PORT_Atoi(certutil.options[opt_Validity].arg);
2962         if (validityMonths < 0) {
2963             PR_fprintf(PR_STDERR, "%s -v: incorrect validity period: \"%s\"\n",
2964                        progName, certutil.options[opt_Validity].arg);
2965             return 255;
2966         }
2967     }
2968 
2969     /*  -w warp months  */
2970     if (certutil.options[opt_OffsetMonths].activated)
2971         warpmonths = PORT_Atoi(certutil.options[opt_OffsetMonths].arg);
2972 
2973     /*  -y public exponent (for RSA)  */
2974     if (certutil.options[opt_Exponent].activated) {
2975         publicExponent = PORT_Atoi(certutil.options[opt_Exponent].arg);
2976         if ((publicExponent != 3) &&
2977             (publicExponent != 17) &&
2978             (publicExponent != 65537)) {
2979             PR_fprintf(PR_STDERR, "%s -y: incorrect public exponent %d.",
2980                        progName, publicExponent);
2981             PR_fprintf(PR_STDERR, "Must be 3, 17, or 65537.\n");
2982             return 255;
2983         }
2984     }
2985 
2986     /*  --certVersion */
2987     if (certutil.options[opt_CertVersion].activated) {
2988         certVersion = PORT_Atoi(certutil.options[opt_CertVersion].arg);
2989         if (certVersion < 1 || certVersion > 4) {
2990             PR_fprintf(PR_STDERR, "%s -certVersion: incorrect certificate version %d.",
2991                        progName, certVersion);
2992             PR_fprintf(PR_STDERR, "Must be 1, 2, 3 or 4.\n");
2993             return 255;
2994         }
2995         certVersion = certVersion - 1;
2996     }
2997 
2998     /*  Check number of commands entered.  */
2999     commandsEntered = 0;
3000     for (i = 0; i < certutil.numCommands; i++) {
3001         if (certutil.commands[i].activated) {
3002             commandToRun = certutil.commands[i].flag;
3003             commandsEntered++;
3004         }
3005         if (commandsEntered > 1)
3006             break;
3007     }
3008     if (commandsEntered > 1) {
3009         PR_fprintf(PR_STDERR, "%s: only one command at a time!\n", progName);
3010         PR_fprintf(PR_STDERR, "You entered: ");
3011         for (i = 0; i < certutil.numCommands; i++) {
3012             if (certutil.commands[i].activated)
3013                 PR_fprintf(PR_STDERR, " -%c", certutil.commands[i].flag);
3014         }
3015         PR_fprintf(PR_STDERR, "\n");
3016         return 255;
3017     }
3018     if (commandsEntered == 0) {
3019         Usage();
3020     }
3021 
3022     if (certutil.commands[cmd_ListCerts].activated ||
3023         certutil.commands[cmd_PrintHelp].activated ||
3024         certutil.commands[cmd_ListKeys].activated ||
3025         certutil.commands[cmd_ListModules].activated ||
3026         certutil.commands[cmd_CheckCertValidity].activated ||
3027         certutil.commands[cmd_Version].activated) {
3028         readOnly = !certutil.options[opt_RW].activated;
3029     }
3030 
3031     /*  -A, -D, -M, -S, -V, and all require -n  */
3032     if ((certutil.commands[cmd_AddCert].activated ||
3033          certutil.commands[cmd_DeleteCert].activated ||
3034          certutil.commands[cmd_DumpChain].activated ||
3035          certutil.commands[cmd_ModifyCertTrust].activated ||
3036          certutil.commands[cmd_CreateAndAddCert].activated ||
3037          certutil.commands[cmd_CheckCertValidity].activated) &&
3038         !certutil.options[opt_Nickname].activated) {
3039         PR_fprintf(PR_STDERR,
3040                    "%s -%c: nickname is required for this command (-n).\n",
3041                    progName, commandToRun);
3042         return 255;
3043     }
3044 
3045     /*  -A, -E, -M, -S require trust  */
3046     if ((certutil.commands[cmd_AddCert].activated ||
3047          certutil.commands[cmd_AddEmailCert].activated ||
3048          certutil.commands[cmd_ModifyCertTrust].activated ||
3049          certutil.commands[cmd_CreateAndAddCert].activated) &&
3050         !certutil.options[opt_Trust].activated) {
3051         PR_fprintf(PR_STDERR,
3052                    "%s -%c: trust is required for this command (-t).\n",
3053                    progName, commandToRun);
3054         return 255;
3055     }
3056 
3057     /*  if -L is given raw, ascii or dump mode, it must be for only one cert. */
3058     if (certutil.commands[cmd_ListCerts].activated &&
3059         (certutil.options[opt_ASCIIForIO].activated ||
3060          certutil.options[opt_DumpExtensionValue].activated ||
3061          certutil.options[opt_BinaryDER].activated) &&
3062         !certutil.options[opt_Nickname].activated) {
3063         PR_fprintf(PR_STDERR,
3064                    "%s: nickname is required to dump cert in raw or ascii mode.\n",
3065                    progName);
3066         return 255;
3067     }
3068 
3069     /*  -L can only be in (raw || ascii).  */
3070     if (certutil.commands[cmd_ListCerts].activated &&
3071         certutil.options[opt_ASCIIForIO].activated &&
3072         certutil.options[opt_BinaryDER].activated) {
3073         PR_fprintf(PR_STDERR,
3074                    "%s: cannot specify both -r and -a when dumping cert.\n",
3075                    progName);
3076         return 255;
3077     }
3078 
3079     /*  If making a cert request, need a subject.  */
3080     if ((certutil.commands[cmd_CertReq].activated ||
3081          certutil.commands[cmd_CreateAndAddCert].activated) &&
3082         !(certutil.options[opt_Subject].activated || keysource)) {
3083         PR_fprintf(PR_STDERR,
3084                    "%s -%c: subject is required to create a cert request.\n",
3085                    progName, commandToRun);
3086         return 255;
3087     }
3088 
3089     /*  If making a cert, need a serial number.  */
3090     if ((certutil.commands[cmd_CreateNewCert].activated ||
3091          certutil.commands[cmd_CreateAndAddCert].activated) &&
3092         !certutil.options[opt_SerialNumber].activated) {
3093         /*  Make a default serial number from the current time.  */
3094         PRTime now = PR_Now();
3095         LL_USHR(now, now, 19);
3096         LL_L2UI(serialNumber, now);
3097     }
3098 
3099     /*  Validation needs the usage to validate for.  */
3100     if (certutil.commands[cmd_CheckCertValidity].activated &&
3101         !certutil.options[opt_Usage].activated) {
3102         PR_fprintf(PR_STDERR,
3103                    "%s -V: specify a usage to validate the cert for (-u).\n",
3104                    progName);
3105         return 255;
3106     }
3107 
3108     /* Rename needs an old and a new nickname */
3109     if (certutil.commands[cmd_Rename].activated &&
3110         !(certutil.options[opt_Nickname].activated &&
3111           certutil.options[opt_NewNickname].activated)) {
3112 
3113         PR_fprintf(PR_STDERR,
3114                    "%s --rename: specify an old nickname (-n) and\n"
3115                    "   a new nickname (--new-n).\n",
3116                    progName);
3117         return 255;
3118     }
3119 
3120     /* Delete needs a nickname or a key ID */
3121     if (certutil.commands[cmd_DeleteKey].activated &&
3122         !(certutil.options[opt_Nickname].activated || keysource)) {
3123         PR_fprintf(PR_STDERR,
3124                    "%s -%c: specify a nickname (-n) or\n"
3125                    "   a key ID (-k).\n",
3126                    progName, commandToRun);
3127         return 255;
3128     }
3129 
3130     /* Upgrade/Merge needs a source database and a upgrade id. */
3131     if (certutil.commands[cmd_UpgradeMerge].activated &&
3132         !(certutil.options[opt_SourceDir].activated &&
3133           certutil.options[opt_UpgradeID].activated)) {
3134 
3135         PR_fprintf(PR_STDERR,
3136                    "%s --upgrade-merge: specify an upgrade database directory "
3137                    "(--source-dir) and\n"
3138                    "   an upgrade ID (--upgrade-id).\n",
3139                    progName);
3140         return 255;
3141     }
3142 
3143     /* Merge needs a source database */
3144     if (certutil.commands[cmd_Merge].activated &&
3145         !certutil.options[opt_SourceDir].activated) {
3146 
3147         PR_fprintf(PR_STDERR,
3148                    "%s --merge: specify an source database directory "
3149                    "(--source-dir)\n",
3150                    progName);
3151         return 255;
3152     }
3153 
3154     /*  To make a cert, need either a issuer or to self-sign it.  */
3155     if (certutil.commands[cmd_CreateAndAddCert].activated &&
3156         !(certutil.options[opt_IssuerName].activated ||
3157           certutil.options[opt_SelfSign].activated)) {
3158         PR_fprintf(PR_STDERR,
3159                    "%s -S: must specify issuer (-c) or self-sign (-x).\n",
3160                    progName);
3161         return 255;
3162     }
3163 
3164     /*  Using slotname == NULL for listing keys and certs on all slots,
3165      *  but only that. */
3166     if (!(certutil.commands[cmd_ListKeys].activated ||
3167           certutil.commands[cmd_DumpChain].activated ||
3168           certutil.commands[cmd_ListCerts].activated) &&
3169         slotname == NULL) {
3170         PR_fprintf(PR_STDERR,
3171                    "%s -%c: cannot use \"-h all\" for this command.\n",
3172                    progName, commandToRun);
3173         return 255;
3174     }
3175 
3176     /*  Using keytype == nullKey for list all key types, but only that.  */
3177     if (!certutil.commands[cmd_ListKeys].activated && keytype == nullKey) {
3178         PR_fprintf(PR_STDERR,
3179                    "%s -%c: cannot use \"-k all\" for this command.\n",
3180                    progName, commandToRun);
3181         return 255;
3182     }
3183 
3184     /*  Open the input file.  */
3185     if (certutil.options[opt_InputFile].activated) {
3186         inFile = PR_Open(certutil.options[opt_InputFile].arg, PR_RDONLY, 0);
3187         if (!inFile) {
3188             PR_fprintf(PR_STDERR,
3189                        "%s:  unable to open \"%s\" for reading (%ld, %ld).\n",
3190                        progName, certutil.options[opt_InputFile].arg,
3191                        PR_GetError(), PR_GetOSError());
3192             return 255;
3193         }
3194     }
3195 
3196     /*  Open the output file.  */
3197     if (certutil.options[opt_OutputFile].activated) {
3198         outFile = PR_Open(certutil.options[opt_OutputFile].arg,
3199                           PR_CREATE_FILE | PR_RDWR | PR_TRUNCATE, 00660);
3200         if (!outFile) {
3201             PR_fprintf(PR_STDERR,
3202                        "%s:  unable to open \"%s\" for writing (%ld, %ld).\n",
3203                        progName, certutil.options[opt_OutputFile].arg,
3204                        PR_GetError(), PR_GetOSError());
3205             return 255;
3206         }
3207     }
3208 
3209     name = SECU_GetOptionArg(&certutil, opt_Nickname);
3210     newName = SECU_GetOptionArg(&certutil, opt_NewNickname);
3211     email = SECU_GetOptionArg(&certutil, opt_Emailaddress);
3212 
3213     PK11_SetPasswordFunc(SECU_GetModulePassword);
3214 
3215     if (PR_TRUE == initialize) {
3216         /*  Initialize NSPR and NSS.  */
3217         PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
3218         if (!certutil.commands[cmd_UpgradeMerge].activated) {
3219             rv = NSS_Initialize(SECU_ConfigDirectory(NULL),
3220                                 certPrefix, certPrefix,
3221                                 "secmod.db", readOnly ? NSS_INIT_READONLY : 0);
3222         } else {
3223             rv = NSS_InitWithMerge(SECU_ConfigDirectory(NULL),
3224                                    certPrefix, certPrefix, "secmod.db",
3225                                    sourceDir, srcCertPrefix, srcCertPrefix,
3226                                    upgradeID, upgradeTokenName,
3227                                    readOnly ? NSS_INIT_READONLY : 0);
3228         }
3229         if (rv != SECSuccess) {
3230             SECU_PrintPRandOSError(progName);
3231             rv = SECFailure;
3232             goto shutdown;
3233         }
3234         initialized = PR_TRUE;
3235         SECU_RegisterDynamicOids();
3236         /* Ensure the SSL error code table has been registered. Bug 1460284. */
3237         SSL_OptionSetDefault(-1, 0);
3238     }
3239     certHandle = CERT_GetDefaultCertDB();
3240 
3241     if (certutil.commands[cmd_Version].activated) {
3242         printf("Certificate database content version: command not implemented.\n");
3243     }
3244 
3245     if (PL_strcmp(slotname, "internal") == 0)
3246         slot = PK11_GetInternalKeySlot();
3247     else if (slotname != NULL)
3248         slot = PK11_FindSlotByName(slotname);
3249 
3250     if (!slot && (certutil.commands[cmd_NewDBs].activated ||
3251                   certutil.commands[cmd_ModifyCertTrust].activated ||
3252                   certutil.commands[cmd_ChangePassword].activated ||
3253                   certutil.commands[cmd_TokenReset].activated ||
3254                   certutil.commands[cmd_CreateAndAddCert].activated ||
3255                   certutil.commands[cmd_AddCert].activated ||
3256                   certutil.commands[cmd_Merge].activated ||
3257                   certutil.commands[cmd_UpgradeMerge].activated ||
3258                   certutil.commands[cmd_AddEmailCert].activated)) {
3259 
3260         SECU_PrintError(progName, "could not find the slot %s", slotname);
3261         rv = SECFailure;
3262         goto shutdown;
3263     }
3264 
3265     /*  If creating new database, initialize the password.  */
3266     if (certutil.commands[cmd_NewDBs].activated) {
3267         if (certutil.options[opt_EmptyPassword].activated && (PK11_NeedUserInit(slot))) {
3268             rv = PK11_InitPin(slot, (char *)NULL, "");
3269         } else {
3270             rv = SECU_ChangePW2(slot, 0, 0, certutil.options[opt_PasswordFile].arg,
3271                                 certutil.options[opt_NewPasswordFile].arg);
3272         }
3273         if (rv != SECSuccess) {
3274             SECU_PrintError(progName, "Could not set password for the slot");
3275             goto shutdown;
3276         }
3277     }
3278 
3279     /* if we are going to modify the cert database,
3280      * make sure it's initialized */
3281     if (certutil.commands[cmd_ModifyCertTrust].activated ||
3282         certutil.commands[cmd_CreateAndAddCert].activated ||
3283         certutil.commands[cmd_AddCert].activated ||
3284         certutil.commands[cmd_AddEmailCert].activated) {
3285         if (PK11_NeedLogin(slot) && PK11_NeedUserInit(slot)) {
3286             char *password = NULL;
3287             /* fetch the password from the command line or the file
3288              * if no password is supplied, initialize the password to NULL */
3289             if (pwdata.source == PW_FROMFILE) {
3290                 password = SECU_FilePasswd(slot, PR_FALSE, pwdata.data);
3291             } else if (pwdata.source == PW_PLAINTEXT) {
3292                 password = PL_strdup(pwdata.data);
3293             }
3294             rv = PK11_InitPin(slot, (char *)NULL, password ? password : "");
3295             if (password) {
3296                 PORT_Memset(password, 0, PL_strlen(password));
3297                 PORT_Free(password);
3298             }
3299             if (rv != SECSuccess) {
3300                 SECU_PrintError(progName, "Could not set password for the slot");
3301                 goto shutdown;
3302             }
3303         }
3304     }
3305 
3306     /* walk through the upgrade merge if necessary.
3307      * This option is more to test what some applications will want to do
3308      * to do an automatic upgrade. The --merge command is more useful for
3309      * the general case where 2 database need to be merged together.
3310      */
3311     if (certutil.commands[cmd_UpgradeMerge].activated) {
3312         if (*upgradeTokenName == 0) {
3313             upgradeTokenName = upgradeID;
3314         }
3315         if (!PK11_IsInternal(slot)) {
3316             fprintf(stderr, "Only internal DB's can be upgraded\n");
3317             rv = SECSuccess;
3318             goto shutdown;
3319         }
3320         if (!PK11_IsRemovable(slot)) {
3321             printf("database already upgraded.\n");
3322             rv = SECSuccess;
3323             goto shutdown;
3324         }
3325         if (!PK11_NeedLogin(slot)) {
3326             printf("upgrade complete!\n");
3327             rv = SECSuccess;
3328             goto shutdown;
3329         }
3330         /* authenticate to the old DB if necessary */
3331         if (PORT_Strcmp(PK11_GetTokenName(slot), upgradeTokenName) == 0) {
3332             /* if we need a password, supply it. This will be the password
3333              * for the old database */
3334             rv = PK11_Authenticate(slot, PR_FALSE, &pwdata2);
3335             if (rv != SECSuccess) {
3336                 SECU_PrintError(progName, "Could not get password for %s",
3337                                 upgradeTokenName);
3338                 goto shutdown;
3339             }
3340             /*
3341              * if we succeeded above, but still aren't logged in, that means
3342              * we just supplied the password for the old database. We may
3343              * need the password for the new database. NSS will automatically
3344              * change the token names at this point
3345              */
3346             if (PK11_IsLoggedIn(slot, &pwdata)) {
3347                 printf("upgrade complete!\n");
3348                 rv = SECSuccess;
3349                 goto shutdown;
3350             }
3351         }
3352 
3353         /* call PK11_IsPresent to update our cached token information */
3354         if (!PK11_IsPresent(slot)) {
3355             /* this shouldn't happen. We call isPresent to force a token
3356              * info update */
3357             fprintf(stderr, "upgrade/merge internal error\n");
3358             rv = SECFailure;
3359             goto shutdown;
3360         }
3361 
3362         /* the token is now set to the state of the source database,
3363          * if we need a password for it, PK11_Authenticate will
3364          * automatically prompt us */
3365         rv = PK11_Authenticate(slot, PR_FALSE, &pwdata);
3366         if (rv == SECSuccess) {
3367             printf("upgrade complete!\n");
3368         } else {
3369             SECU_PrintError(progName, "Could not get password for %s",
3370                             PK11_GetTokenName(slot));
3371         }
3372         goto shutdown;
3373     }
3374 
3375     /*
3376      * merge 2 databases.
3377      */
3378     if (certutil.commands[cmd_Merge].activated) {
3379         PK11SlotInfo *sourceSlot = NULL;
3380         PK11MergeLog *log;
3381         char *modspec = PR_smprintf(
3382             "configDir='%s' certPrefix='%s' tokenDescription='%s'",
3383             sourceDir, srcCertPrefix,
3384             *upgradeTokenName ? upgradeTokenName : "Source Database");
3385 
3386         if (!modspec) {
3387             rv = SECFailure;
3388             goto shutdown;
3389         }
3390 
3391         sourceSlot = SECMOD_OpenUserDB(modspec);
3392         PR_smprintf_free(modspec);
3393         if (!sourceSlot) {
3394             SECU_PrintError(progName, "couldn't open source database");
3395             rv = SECFailure;
3396             goto shutdown;
3397         }
3398 
3399         rv = PK11_Authenticate(slot, PR_FALSE, &pwdata);
3400         if (rv != SECSuccess) {
3401             SECU_PrintError(progName, "Couldn't get password for %s",
3402                             PK11_GetTokenName(slot));
3403             goto merge_fail;
3404         }
3405 
3406         rv = PK11_Authenticate(sourceSlot, PR_FALSE, &pwdata2);
3407         if (rv != SECSuccess) {
3408             SECU_PrintError(progName, "Couldn't get password for %s",
3409                             PK11_GetTokenName(sourceSlot));
3410             goto merge_fail;
3411         }
3412 
3413         log = PK11_CreateMergeLog();
3414         if (!log) {
3415             rv = SECFailure;
3416             SECU_PrintError(progName, "couldn't create error log");
3417             goto merge_fail;
3418         }
3419 
3420         rv = PK11_MergeTokens(slot, sourceSlot, log, &pwdata, &pwdata2);
3421         if (rv != SECSuccess) {
3422             DumpMergeLog(progName, log);
3423         }
3424         PK11_DestroyMergeLog(log);
3425 
3426     merge_fail:
3427         SECMOD_CloseUserDB(sourceSlot);
3428         PK11_FreeSlot(sourceSlot);
3429         goto shutdown;
3430     }
3431 
3432     /* The following 8 options are mutually exclusive with all others. */
3433 
3434     /*  List certs (-L)  */
3435     if (certutil.commands[cmd_ListCerts].activated) {
3436         if (certutil.options[opt_DumpExtensionValue].activated) {
3437             const char *oid_str;
3438             SECItem oid_item;
3439             SECStatus srv;
3440             oid_item.data = NULL;
3441             oid_item.len = 0;
3442             oid_str = certutil.options[opt_DumpExtensionValue].arg;
3443             srv = GetOidFromString(NULL, &oid_item, oid_str, strlen(oid_str));
3444             if (srv != SECSuccess) {
3445                 SECU_PrintError(progName, "malformed extension OID %s",
3446                                 oid_str);
3447                 goto shutdown;
3448             }
3449             rv = ListCerts(certHandle, name, email, slot,
3450                            PR_TRUE /*binary*/, PR_FALSE /*ascii*/,
3451                            &oid_item,
3452                            outFile, &pwdata);
3453             SECITEM_FreeItem(&oid_item, PR_FALSE);
3454         } else {
3455             rv = ListCerts(certHandle, name, email, slot,
3456                            certutil.options[opt_BinaryDER].activated,
3457                            certutil.options[opt_ASCIIForIO].activated,
3458                            NULL, outFile, &pwdata);
3459         }
3460         goto shutdown;
3461     }
3462     if (certutil.commands[cmd_DumpChain].activated) {
3463         rv = DumpChain(certHandle, name,
3464                        certutil.options[opt_ASCIIForIO].activated,
3465                        certutil.options[opt_SimpleSelfSigned].activated);
3466         goto shutdown;
3467     }
3468     /*  XXX needs work  */
3469     /*  List keys (-K)  */
3470     if (certutil.commands[cmd_ListKeys].activated) {
3471         rv = ListKeys(slot, name, 0 /*keyindex*/, keytype, PR_FALSE /*dopriv*/,
3472                       &pwdata);
3473         goto shutdown;
3474     }
3475     /*  List modules (-U)  */
3476     if (certutil.commands[cmd_ListModules].activated) {
3477         rv = ListModules();
3478         goto shutdown;
3479     }
3480     /*  Delete cert (-D)  */
3481     if (certutil.commands[cmd_DeleteCert].activated) {
3482         rv = DeleteCert(certHandle, name, &pwdata);
3483         goto shutdown;
3484     }
3485     /*  Rename cert (--rename)  */
3486     if (certutil.commands[cmd_Rename].activated) {
3487         rv = RenameCert(certHandle, name, newName, &pwdata);
3488         goto shutdown;
3489     }
3490     /*  Delete key (-F)  */
3491     if (certutil.commands[cmd_DeleteKey].activated) {
3492         if (certutil.options[opt_Nickname].activated) {
3493             rv = DeleteCertAndKey(name, &pwdata);
3494         } else {
3495             privkey = findPrivateKeyByID(slot, keysource, &pwdata);
3496             if (!privkey) {
3497                 SECU_PrintError(progName, "%s is not a key-id", keysource);
3498                 rv = SECFailure;
3499             } else {
3500                 rv = DeleteKey(privkey, &pwdata);
3501                 /* already destroyed by PK11_DeleteTokenPrivateKey */
3502                 privkey = NULL;
3503             }
3504         }
3505         goto shutdown;
3506     }
3507     /*  Modify trust attribute for cert (-M)  */
3508     if (certutil.commands[cmd_ModifyCertTrust].activated) {
3509         rv = ChangeTrustAttributes(certHandle, slot, name,
3510                                    certutil.options[opt_Trust].arg, &pwdata);
3511         goto shutdown;
3512     }
3513     /*  Change key db password (-W) (future - change pw to slot?)  */
3514     if (certutil.commands[cmd_ChangePassword].activated) {
3515         rv = SECU_ChangePW2(slot, 0, 0, certutil.options[opt_PasswordFile].arg,
3516                             certutil.options[opt_NewPasswordFile].arg);
3517         if (rv != SECSuccess) {
3518             SECU_PrintError(progName, "Could not set password for the slot");
3519             goto shutdown;
3520         }
3521     }
3522     /*  Reset the a token */
3523     if (certutil.commands[cmd_TokenReset].activated) {
3524         char *sso_pass = "";
3525 
3526         if (certutil.options[opt_SSOPass].activated) {
3527             sso_pass = certutil.options[opt_SSOPass].arg;
3528         }
3529         rv = PK11_ResetToken(slot, sso_pass);
3530 
3531         goto shutdown;
3532     }
3533     /*  Check cert validity against current time (-V)  */
3534     if (certutil.commands[cmd_CheckCertValidity].activated) {
3535         /* XXX temporary hack for fips - must log in to get priv key */
3536         if (certutil.options[opt_VerifySig].activated) {
3537             if (slot && PK11_NeedLogin(slot)) {
3538                 SECStatus newrv = PK11_Authenticate(slot, PR_TRUE, &pwdata);
3539                 if (newrv != SECSuccess) {
3540                     SECU_PrintError(progName, "could not authenticate to token %s.",
3541                                     PK11_GetTokenName(slot));
3542                     goto shutdown;
3543                 }
3544             }
3545         }
3546         rv = ValidateCert(certHandle, name,
3547                           certutil.options[opt_ValidityTime].arg,
3548                           certutil.options[opt_Usage].arg,
3549                           certutil.options[opt_VerifySig].activated,
3550                           certutil.options[opt_DetailedInfo].activated,
3551                           certutil.options[opt_ASCIIForIO].activated,
3552                           &pwdata);
3553         if (rv != SECSuccess && PR_GetError() == SEC_ERROR_INVALID_ARGS)
3554             SECU_PrintError(progName, "validation failed");
3555         goto shutdown;
3556     }
3557 
3558     /*
3559      *  Key generation
3560      */
3561 
3562     /*  These commands may require keygen.  */
3563     if (certutil.commands[cmd_CertReq].activated ||
3564         certutil.commands[cmd_CreateAndAddCert].activated ||
3565         certutil.commands[cmd_GenKeyPair].activated) {
3566         if (keysource) {
3567             CERTCertificate *keycert;
3568             keycert = CERT_FindCertByNicknameOrEmailAddr(certHandle, keysource);
3569             if (!keycert) {
3570                 keycert = PK11_FindCertFromNickname(keysource, NULL);
3571             }
3572 
3573             if (keycert) {
3574                 privkey = PK11_FindKeyByDERCert(slot, keycert, &pwdata);
3575             } else {
3576                 /* Interpret keysource as CKA_ID */
3577                 privkey = findPrivateKeyByID(slot, keysource, &pwdata);
3578             }
3579 
3580             if (!privkey) {
3581                 SECU_PrintError(
3582                     progName,
3583                     "%s is neither a key-type nor a nickname nor a key-id", keysource);
3584                 return SECFailure;
3585             }
3586 
3587             pubkey = SECKEY_ConvertToPublicKey(privkey);
3588             if (!pubkey) {
3589                 SECU_PrintError(progName,
3590                                 "Could not get keys from cert %s", keysource);
3591                 if (keycert) {
3592                     CERT_DestroyCertificate(keycert);
3593                 }
3594                 rv = SECFailure;
3595                 goto shutdown;
3596             }
3597             keytype = privkey->keyType;
3598 
3599             /* On CertReq for renewal if no subject has been
3600              * specified obtain it from the certificate.
3601              */
3602             if (certutil.commands[cmd_CertReq].activated && !subject) {
3603                 if (keycert) {
3604                     subject = CERT_AsciiToName(keycert->subjectName);
3605                     if (!subject) {
3606                         SECU_PrintError(
3607                             progName,
3608                             "Could not get subject from certificate %s",
3609                             keysource);
3610                         CERT_DestroyCertificate(keycert);
3611                         rv = SECFailure;
3612                         goto shutdown;
3613                     }
3614                 } else {
3615                     SECU_PrintError(progName, "Subject name not provided");
3616                     rv = SECFailure;
3617                     goto shutdown;
3618                 }
3619             }
3620             if (keycert) {
3621                 CERT_DestroyCertificate(keycert);
3622             }
3623         } else {
3624             privkey =
3625                 CERTUTIL_GeneratePrivateKey(keytype, slot, keysize,
3626                                             publicExponent,
3627                                             certutil.options[opt_NoiseFile].arg,
3628                                             &pubkey,
3629                                             certutil.options[opt_PQGFile].arg,
3630                                             keyAttrFlags,
3631                                             keyOpFlagsOn,
3632                                             keyOpFlagsOff,
3633                                             &pwdata);
3634             if (privkey == NULL) {
3635                 SECU_PrintError(progName, "unable to generate key(s)\n");
3636                 rv = SECFailure;
3637                 goto shutdown;
3638             }
3639         }
3640         privkey->wincx = &pwdata;
3641         PORT_Assert(pubkey != NULL);
3642 
3643         /*  If all that was needed was keygen, exit.  */
3644         if (certutil.commands[cmd_GenKeyPair].activated) {
3645             rv = SECSuccess;
3646             goto shutdown;
3647         }
3648     }
3649 
3650     if (certutil.options[opt_Pss].activated) {
3651         if (!certutil.commands[cmd_CertReq].activated &&
3652             !certutil.commands[cmd_CreateAndAddCert].activated) {
3653             PR_fprintf(PR_STDERR,
3654                        "%s -%c: --pss only works with -R or -S.\n",
3655                        progName, commandToRun);
3656             return 255;
3657         }
3658         if (keytype != rsaKey) {
3659             PR_fprintf(PR_STDERR,
3660                        "%s -%c: --pss only works with RSA keys.\n",
3661                        progName, commandToRun);
3662             return 255;
3663         }
3664     }
3665 
3666     /* --pss-sign is to sign a certificate with RSA-PSS, even if the
3667      * issuer's key is an RSA key.  If the key is an RSA-PSS key, the
3668      * generated signature is always RSA-PSS. */
3669     if (certutil.options[opt_PssSign].activated) {
3670         if (!certutil.commands[cmd_CreateNewCert].activated &&
3671             !certutil.commands[cmd_CreateAndAddCert].activated) {
3672             PR_fprintf(PR_STDERR,
3673                        "%s -%c: --pss-sign only works with -C or -S.\n",
3674                        progName, commandToRun);
3675             return 255;
3676         }
3677         if (keytype != rsaKey) {
3678             PR_fprintf(PR_STDERR,
3679                        "%s -%c: --pss-sign only works with RSA keys.\n",
3680                        progName, commandToRun);
3681             return 255;
3682         }
3683     }
3684 
3685     if (certutil.options[opt_SimpleSelfSigned].activated &&
3686         !certutil.commands[cmd_DumpChain].activated) {
3687         PR_fprintf(PR_STDERR,
3688                    "%s -%c: --simple-self-signed only works with -O.\n",
3689                    progName, commandToRun);
3690         return 255;
3691     }
3692 
3693     /* If we need a list of extensions convert the flags into list format */
3694     if (certutil.commands[cmd_CertReq].activated ||
3695         certutil.commands[cmd_CreateAndAddCert].activated ||
3696         certutil.commands[cmd_CreateNewCert].activated) {
3697         certutil_extns[ext_keyUsage].activated =
3698             certutil.options[opt_AddCmdKeyUsageExt].activated;
3699         if (!certutil_extns[ext_keyUsage].activated) {
3700             certutil_extns[ext_keyUsage].activated =
3701                 certutil.options[opt_AddKeyUsageExt].activated;
3702         } else {
3703             certutil_extns[ext_keyUsage].arg =
3704                 certutil.options[opt_AddCmdKeyUsageExt].arg;
3705         }
3706         certutil_extns[ext_basicConstraint].activated =
3707             certutil.options[opt_AddBasicConstraintExt].activated;
3708         certutil_extns[ext_nameConstraints].activated =
3709             certutil.options[opt_AddNameConstraintsExt].activated;
3710         certutil_extns[ext_authorityKeyID].activated =
3711             certutil.options[opt_AddAuthorityKeyIDExt].activated;
3712         certutil_extns[ext_subjectKeyID].activated =
3713             certutil.options[opt_AddSubjectKeyIDExt].activated;
3714         certutil_extns[ext_CRLDistPts].activated =
3715             certutil.options[opt_AddCRLDistPtsExt].activated;
3716         certutil_extns[ext_NSCertType].activated =
3717             certutil.options[opt_AddCmdNSCertTypeExt].activated;
3718         if (!certutil_extns[ext_NSCertType].activated) {
3719             certutil_extns[ext_NSCertType].activated =
3720                 certutil.options[opt_AddNSCertTypeExt].activated;
3721         } else {
3722             certutil_extns[ext_NSCertType].arg =
3723                 certutil.options[opt_AddCmdNSCertTypeExt].arg;
3724         }
3725 
3726         certutil_extns[ext_extKeyUsage].activated =
3727             certutil.options[opt_AddCmdExtKeyUsageExt].activated;
3728         if (!certutil_extns[ext_extKeyUsage].activated) {
3729             certutil_extns[ext_extKeyUsage].activated =
3730                 certutil.options[opt_AddExtKeyUsageExt].activated;
3731         } else {
3732             certutil_extns[ext_extKeyUsage].arg =
3733                 certutil.options[opt_AddCmdExtKeyUsageExt].arg;
3734         }
3735         certutil_extns[ext_subjectAltName].activated =
3736             certutil.options[opt_AddSubjectAltNameExt].activated;
3737         if (certutil_extns[ext_subjectAltName].activated) {
3738             certutil_extns[ext_subjectAltName].arg =
3739                 certutil.options[opt_AddSubjectAltNameExt].arg;
3740         }
3741 
3742         certutil_extns[ext_authInfoAcc].activated =
3743             certutil.options[opt_AddAuthInfoAccExt].activated;
3744         certutil_extns[ext_subjInfoAcc].activated =
3745             certutil.options[opt_AddSubjInfoAccExt].activated;
3746         certutil_extns[ext_certPolicies].activated =
3747             certutil.options[opt_AddCertPoliciesExt].activated;
3748         certutil_extns[ext_policyMappings].activated =
3749             certutil.options[opt_AddPolicyMapExt].activated;
3750         certutil_extns[ext_policyConstr].activated =
3751             certutil.options[opt_AddPolicyConstrExt].activated;
3752         certutil_extns[ext_inhibitAnyPolicy].activated =
3753             certutil.options[opt_AddInhibAnyExt].activated;
3754     }
3755 
3756     /* -A -C or -E    Read inFile */
3757     if (certutil.commands[cmd_CreateNewCert].activated ||
3758         certutil.commands[cmd_AddCert].activated ||
3759         certutil.commands[cmd_AddEmailCert].activated) {
3760         PRBool isCreate = certutil.commands[cmd_CreateNewCert].activated;
3761         rv = SECU_ReadDERFromFile(isCreate ? &certReqDER : &certDER, inFile,
3762                                   certutil.options[opt_ASCIIForIO].activated,
3763                                   PR_TRUE);
3764         if (rv)
3765             goto shutdown;
3766     }
3767 
3768     /*
3769      *  Certificate request
3770      */
3771 
3772     /*  Make a cert request (-R).  */
3773     if (certutil.commands[cmd_CertReq].activated) {
3774         rv = CertReq(privkey, pubkey, keytype, hashAlgTag, subject,
3775                      certutil.options[opt_PhoneNumber].arg,
3776                      certutil.options[opt_ASCIIForIO].activated,
3777                      certutil.options[opt_ExtendedEmailAddrs].arg,
3778                      certutil.options[opt_ExtendedDNSNames].arg,
3779                      certutil_extns,
3780                      (certutil.options[opt_GenericExtensions].activated ? certutil.options[opt_GenericExtensions].arg
3781                                                                         : NULL),
3782                      certutil.options[opt_Pss].activated,
3783                      &certReqDER);
3784         if (rv)
3785             goto shutdown;
3786         privkey->wincx = &pwdata;
3787     }
3788 
3789     /*
3790      *  Certificate creation
3791      */
3792 
3793     /*  If making and adding a cert, create a cert request file first without
3794      *  any extensions, then load it with the command line extensions
3795      *  and output the cert to another file.
3796      */
3797     if (certutil.commands[cmd_CreateAndAddCert].activated) {
3798         static certutilExtnList nullextnlist = { { PR_FALSE, NULL } };
3799         rv = CertReq(privkey, pubkey, keytype, hashAlgTag, subject,
3800                      certutil.options[opt_PhoneNumber].arg,
3801                      PR_FALSE, /* do not BASE64-encode regardless of -a option */
3802                      NULL,
3803                      NULL,
3804                      nullextnlist,
3805                      (certutil.options[opt_GenericExtensions].activated ? certutil.options[opt_GenericExtensions].arg
3806                                                                         : NULL),
3807                      certutil.options[opt_Pss].activated,
3808                      &certReqDER);
3809         if (rv)
3810             goto shutdown;
3811         privkey->wincx = &pwdata;
3812     }
3813 
3814     /*  Create a certificate (-C or -S).  */
3815     if (certutil.commands[cmd_CreateAndAddCert].activated ||
3816         certutil.commands[cmd_CreateNewCert].activated) {
3817         rv = CreateCert(certHandle, slot,
3818                         certutil.options[opt_IssuerName].arg,
3819                         &certReqDER, &privkey, &pwdata, hashAlgTag,
3820                         serialNumber, warpmonths, validityMonths,
3821                         certutil.options[opt_ExtendedEmailAddrs].arg,
3822                         certutil.options[opt_ExtendedDNSNames].arg,
3823                         certutil.options[opt_ASCIIForIO].activated &&
3824                             certutil.commands[cmd_CreateNewCert].activated,
3825                         certutil.options[opt_SelfSign].activated,
3826                         certutil_extns,
3827                         (certutil.options[opt_GenericExtensions].activated ? certutil.options[opt_GenericExtensions].arg
3828                                                                            : NULL),
3829                         certVersion,
3830                         certutil.options[opt_PssSign].activated,
3831                         &certDER);
3832         if (rv)
3833             goto shutdown;
3834     }
3835 
3836     /*
3837      * Adding a cert to the database (or slot)
3838      */
3839 
3840     /* -A -E or -S    Add the cert to the DB */
3841     if (certutil.commands[cmd_CreateAndAddCert].activated ||
3842         certutil.commands[cmd_AddCert].activated ||
3843         certutil.commands[cmd_AddEmailCert].activated) {
3844         if (strstr(certutil.options[opt_Trust].arg, "u")) {
3845             fprintf(stderr, "Notice: Trust flag u is set automatically if the "
3846                             "private key is present.\n");
3847         }
3848         rv = AddCert(slot, certHandle, name,
3849                      certutil.options[opt_Trust].arg,
3850                      &certDER,
3851                      certutil.commands[cmd_AddEmailCert].activated, &pwdata);
3852         if (rv)
3853             goto shutdown;
3854     }
3855 
3856     if (certutil.commands[cmd_CertReq].activated ||
3857         certutil.commands[cmd_CreateNewCert].activated) {
3858         SECItem *item = certutil.commands[cmd_CertReq].activated ? &certReqDER
3859                                                                  : &certDER;
3860         PRInt32 written = PR_Write(outFile, item->data, item->len);
3861         if (written < 0 || (PRUint32)written != item->len) {
3862             rv = SECFailure;
3863         }
3864     }
3865 
3866 shutdown:
3867     if (slot) {
3868         PK11_FreeSlot(slot);
3869     }
3870     if (privkey) {
3871         SECKEY_DestroyPrivateKey(privkey);
3872     }
3873     if (pubkey) {
3874         SECKEY_DestroyPublicKey(pubkey);
3875     }
3876     if (subject) {
3877         CERT_DestroyName(subject);
3878     }
3879     if (name) {
3880         PL_strfree(name);
3881     }
3882     if (newName) {
3883         PL_strfree(newName);
3884     }
3885     if (inFile && inFile != PR_STDIN) {
3886         PR_Close(inFile);
3887     }
3888     if (outFile && outFile != PR_STDOUT) {
3889         PR_Close(outFile);
3890     }
3891     SECITEM_FreeItem(&certReqDER, PR_FALSE);
3892     SECITEM_FreeItem(&certDER, PR_FALSE);
3893     if (pwdata.data && pwdata.source == PW_PLAINTEXT) {
3894         /* Allocated by a PL_strdup call in SECU_GetModulePassword. */
3895         PL_strfree(pwdata.data);
3896     }
3897     if (email) {
3898         PL_strfree(email);
3899     }
3900 
3901     /* Open the batch command file.
3902      *
3903      * - If -B <command line> option is specified, the contents in the
3904      * command file will be interpreted as subsequent certutil
3905      * commands to be executed in the current certutil process
3906      * context after the current certutil command has been executed.
3907      * - Each line in the command file consists of the command
3908      * line arguments for certutil.
3909      * - The -d <configdir> option will be ignored if specified in the
3910      * command file.
3911      * - Quoting with double quote characters ("...") is supported
3912      * to allow white space in a command line argument.  The
3913      * double quote character cannot be escaped and quoting cannot
3914      * be nested in this version.
3915      * - each line in the batch file is limited to 512 characters
3916     */
3917 
3918     if ((SECSuccess == rv) && certutil.commands[cmd_Batch].activated) {
3919         FILE *batchFile = NULL;
3920         char *nextcommand = NULL;
3921         PRInt32 cmd_len = 0, buf_size = 0;
3922         static const int increment = 512;
3923 
3924         if (!certutil.options[opt_InputFile].activated ||
3925             !certutil.options[opt_InputFile].arg) {
3926             PR_fprintf(PR_STDERR,
3927                        "%s:  no batch input file specified.\n",
3928                        progName);
3929             return 255;
3930         }
3931         batchFile = fopen(certutil.options[opt_InputFile].arg, "r");
3932         if (!batchFile) {
3933             PR_fprintf(PR_STDERR,
3934                        "%s:  unable to open \"%s\" for reading (%ld, %ld).\n",
3935                        progName, certutil.options[opt_InputFile].arg,
3936                        PR_GetError(), PR_GetOSError());
3937             return 255;
3938         }
3939         /* read and execute command-lines in a loop */
3940         while (SECSuccess == rv) {
3941             PRBool invalid = PR_FALSE;
3942             int newargc = 2;
3943             char *space = NULL;
3944             char *nextarg = NULL;
3945             char **newargv = NULL;
3946             char *crlf;
3947 
3948             if (cmd_len + increment > buf_size) {
3949                 char *new_buf;
3950                 buf_size += increment;
3951                 new_buf = PORT_Realloc(nextcommand, buf_size);
3952                 if (!new_buf) {
3953                     PR_fprintf(PR_STDERR, "%s: PORT_Realloc(%ld) failed\n",
3954                                progName, buf_size);
3955                     break;
3956                 }
3957                 nextcommand = new_buf;
3958                 nextcommand[cmd_len] = '\0';
3959             }
3960             if (!fgets(nextcommand + cmd_len, buf_size - cmd_len, batchFile)) {
3961                 break;
3962             }
3963             crlf = PORT_Strrchr(nextcommand, '\n');
3964             if (crlf) {
3965                 *crlf = '\0';
3966             }
3967             cmd_len = strlen(nextcommand);
3968             if (cmd_len && nextcommand[cmd_len - 1] == '\\') {
3969                 nextcommand[--cmd_len] = '\0';
3970                 continue;
3971             }
3972 
3973             /* we now need to split the command into argc / argv format */
3974 
3975             newargv = PORT_Alloc(sizeof(char *) * (newargc + 1));
3976             newargv[0] = progName;
3977             newargv[1] = nextcommand;
3978             nextarg = nextcommand;
3979             while ((space = PORT_Strpbrk(nextarg, " \f\n\r\t\v"))) {
3980                 while (isspace(*space)) {
3981                     *space = '\0';
3982                     space++;
3983                 }
3984                 if (*space == '\0') {
3985                     break;
3986                 } else if (*space != '\"') {
3987                     nextarg = space;
3988                 } else {
3989                     char *closingquote = strchr(space + 1, '\"');
3990                     if (closingquote) {
3991                         *closingquote = '\0';
3992                         space++;
3993                         nextarg = closingquote + 1;
3994                     } else {
3995                         invalid = PR_TRUE;
3996                         nextarg = space;
3997                     }
3998                 }
3999                 newargc++;
4000                 newargv = PORT_Realloc(newargv, sizeof(char *) * (newargc + 1));
4001                 newargv[newargc - 1] = space;
4002             }
4003             newargv[newargc] = NULL;
4004 
4005             /* invoke next command */
4006             if (PR_TRUE == invalid) {
4007                 PR_fprintf(PR_STDERR, "Missing closing quote in batch command :\n%s\nNot executed.\n",
4008                            nextcommand);
4009                 rv = SECFailure;
4010             } else {
4011                 if (0 != certutil_main(newargc, newargv, PR_FALSE))
4012                     rv = SECFailure;
4013             }
4014             PORT_Free(newargv);
4015             cmd_len = 0;
4016             nextcommand[0] = '\0';
4017         }
4018         PORT_Free(nextcommand);
4019         fclose(batchFile);
4020     }
4021 
4022     if ((initialized == PR_TRUE) && NSS_Shutdown() != SECSuccess) {
4023         exit(1);
4024     }
4025     if (rv == SECSuccess) {
4026         return 0;
4027     } else {
4028         return 255;
4029     }
4030 }
4031 
4032 int
4033 main(int argc, char **argv)
4034 {
4035     int rv = certutil_main(argc, argv, PR_TRUE);
4036     PL_ArenaFinish();
4037     PR_Cleanup();
4038     return rv;
4039 }
4040