security/nss/cmd/certutil/certutil.c

Wed, 31 Dec 2014 06:55:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:50 +0100
changeset 2
7e26c7da4463
permissions
-rw-r--r--

Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2

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

mercurial