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