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