diff options
Diffstat (limited to 'security/nss/cmd/certutil/certutil.c')
-rw-r--r-- | security/nss/cmd/certutil/certutil.c | 280 |
1 files changed, 215 insertions, 65 deletions
diff --git a/security/nss/cmd/certutil/certutil.c b/security/nss/cmd/certutil/certutil.c index 20722ae78..df02e4439 100644 --- a/security/nss/cmd/certutil/certutil.c +++ b/security/nss/cmd/certutil/certutil.c @@ -36,9 +36,11 @@ #include "certdb.h" #include "nss.h" #include "certutil.h" +#include "basicutil.h" +#include "ssl.h" #define MIN_KEY_BITS 512 -/* MAX_KEY_BITS should agree with MAX_RSA_MODULUS in freebl */ +/* MAX_KEY_BITS should agree with RSA_MAX_MODULUS_BITS in freebl */ #define MAX_KEY_BITS 8192 #define DEFAULT_KEY_BITS 2048 @@ -447,7 +449,8 @@ ChangeTrustAttributes(CERTCertDBHandle *handle, PK11SlotInfo *slot, } static SECStatus -DumpChain(CERTCertDBHandle *handle, char *name, PRBool ascii) +DumpChain(CERTCertDBHandle *handle, char *name, PRBool ascii, + PRBool simpleSelfSigned) { CERTCertificate *the_cert; CERTCertificateList *chain; @@ -458,6 +461,14 @@ DumpChain(CERTCertDBHandle *handle, char *name, PRBool ascii) SECU_PrintError(progName, "Could not find: %s\n", name); return SECFailure; } + if (simpleSelfSigned && + SECEqual == SECITEM_CompareItem(&the_cert->derIssuer, + &the_cert->derSubject)) { + printf("\"%s\" [%s]\n\n", the_cert->nickname, the_cert->subjectName); + CERT_DestroyCertificate(the_cert); + return SECSuccess; + } + chain = CERT_CertChainFromCert(the_cert, 0, PR_TRUE); CERT_DestroyCertificate(the_cert); if (!chain) { @@ -730,6 +741,9 @@ ValidateCert(CERTCertDBHandle *handle, char *name, char *date, case 'V': usage = certificateUsageSSLServer; break; + case 'I': + usage = certificateUsageIPsec; + break; case 'S': usage = certificateUsageEmailSigner; break; @@ -782,17 +796,17 @@ ValidateCert(CERTCertDBHandle *handle, char *name, char *date, fprintf(stdout, "%s: certificate is valid\n", progName); GEN_BREAK(SECSuccess) } else { - char *name; + char *nick; CERTVerifyLogNode *node; node = log->head; while (node) { if (node->cert->nickname != NULL) { - name = node->cert->nickname; + nick = node->cert->nickname; } else { - name = node->cert->subjectName; + nick = node->cert->subjectName; } - fprintf(stderr, "%s : %s\n", name, + fprintf(stderr, "%s : %s\n", nick, SECU_Strerror(node->error)); CERT_DestroyCertificate(node->cert); node = node->next; @@ -845,41 +859,59 @@ SECItemToHex(const SECItem *item, char *dst) } static const char *const keyTypeName[] = { - "null", "rsa", "dsa", "fortezza", "dh", "kea", "ec" + "null", "rsa", "dsa", "fortezza", "dh", "kea", "ec", "rsaPss", "rsaOaep" }; #define MAX_CKA_ID_BIN_LEN 20 #define MAX_CKA_ID_STR_LEN 40 -/* print key number, key ID (in hex or ASCII), key label (nickname) */ -static SECStatus -PrintKey(PRFileDesc *out, const char *nickName, int count, - SECKEYPrivateKey *key, void *pwarg) +/* output human readable key ID in buffer, which should have at least + * MAX_CKA_ID_STR_LEN + 3 octets (quotations and a null terminator) */ +static void +formatPrivateKeyID(SECKEYPrivateKey *privkey, char *buffer) { SECItem *ckaID; - char ckaIDbuf[MAX_CKA_ID_STR_LEN + 4]; - pwarg = NULL; - ckaID = PK11_GetLowLevelKeyIDForPrivateKey(key); + ckaID = PK11_GetLowLevelKeyIDForPrivateKey(privkey); if (!ckaID) { - strcpy(ckaIDbuf, "(no CKA_ID)"); + strcpy(buffer, "(no CKA_ID)"); } else if (ItemIsPrintableASCII(ckaID)) { int len = PR_MIN(MAX_CKA_ID_STR_LEN, ckaID->len); - ckaIDbuf[0] = '"'; - memcpy(ckaIDbuf + 1, ckaID->data, len); - ckaIDbuf[1 + len] = '"'; - ckaIDbuf[2 + len] = '\0'; + buffer[0] = '"'; + memcpy(buffer + 1, ckaID->data, len); + buffer[1 + len] = '"'; + buffer[2 + len] = '\0'; } else { /* print ckaid in hex */ SECItem idItem = *ckaID; if (idItem.len > MAX_CKA_ID_BIN_LEN) idItem.len = MAX_CKA_ID_BIN_LEN; - SECItemToHex(&idItem, ckaIDbuf); + SECItemToHex(&idItem, buffer); } + SECITEM_ZfreeItem(ckaID, PR_TRUE); +} +/* print key number, key ID (in hex or ASCII), key label (nickname) */ +static SECStatus +PrintKey(PRFileDesc *out, const char *nickName, int count, + SECKEYPrivateKey *key, void *pwarg) +{ + char ckaIDbuf[MAX_CKA_ID_STR_LEN + 4]; + CERTCertificate *cert; + KeyType keyType; + + pwarg = NULL; + + formatPrivateKeyID(key, ckaIDbuf); + cert = PK11_GetCertFromPrivateKey(key); + if (cert) { + keyType = CERT_GetCertKeyType(&cert->subjectPublicKeyInfo); + CERT_DestroyCertificate(cert); + } else { + keyType = key->keyType; + } PR_fprintf(out, "<%2d> %-8.8s %-42.42s %s\n", count, - keyTypeName[key->keyType], ckaIDbuf, nickName); - SECITEM_ZfreeItem(ckaID, PR_TRUE); + keyTypeName[keyType], ckaIDbuf, nickName); return SECSuccess; } @@ -991,7 +1023,7 @@ ListKeys(PK11SlotInfo *slot, const char *nickName, int index, } static SECStatus -DeleteKey(char *nickname, secuPWData *pwdata) +DeleteCertAndKey(char *nickname, secuPWData *pwdata) { SECStatus rv; CERTCertificate *cert; @@ -999,7 +1031,7 @@ DeleteKey(char *nickname, secuPWData *pwdata) slot = PK11_GetInternalKeySlot(); if (PK11_NeedLogin(slot)) { - SECStatus rv = PK11_Authenticate(slot, PR_TRUE, pwdata); + rv = PK11_Authenticate(slot, PR_TRUE, pwdata); if (rv != SECSuccess) { SECU_PrintError(progName, "could not authenticate to token %s.", PK11_GetTokenName(slot)); @@ -1020,6 +1052,61 @@ DeleteKey(char *nickname, secuPWData *pwdata) return rv; } +static SECKEYPrivateKey * +findPrivateKeyByID(PK11SlotInfo *slot, const char *ckaID, secuPWData *pwarg) +{ + PORTCheapArenaPool arena; + SECItem ckaIDItem = { 0 }; + SECKEYPrivateKey *privkey = NULL; + SECStatus rv; + + if (PK11_NeedLogin(slot)) { + rv = PK11_Authenticate(slot, PR_TRUE, pwarg); + if (rv != SECSuccess) { + SECU_PrintError(progName, "could not authenticate to token %s.", + PK11_GetTokenName(slot)); + return NULL; + } + } + + if (0 == PL_strncasecmp("0x", ckaID, 2)) { + ckaID += 2; /* skip leading "0x" */ + } + PORT_InitCheapArena(&arena, DER_DEFAULT_CHUNKSIZE); + if (SECU_HexString2SECItem(&arena.arena, &ckaIDItem, ckaID)) { + privkey = PK11_FindKeyByKeyID(slot, &ckaIDItem, pwarg); + } + PORT_DestroyCheapArena(&arena); + return privkey; +} + +static SECStatus +DeleteKey(SECKEYPrivateKey *privkey, secuPWData *pwarg) +{ + SECStatus rv; + PK11SlotInfo *slot; + + slot = PK11_GetSlotFromPrivateKey(privkey); + if (PK11_NeedLogin(slot)) { + rv = PK11_Authenticate(slot, PR_TRUE, pwarg); + if (rv != SECSuccess) { + SECU_PrintError(progName, "could not authenticate to token %s.", + PK11_GetTokenName(slot)); + return SECFailure; + } + } + + rv = PK11_DeleteTokenPrivateKey(privkey, PR_TRUE); + if (rv != SECSuccess) { + char ckaIDbuf[MAX_CKA_ID_STR_LEN + 4]; + formatPrivateKeyID(privkey, ckaIDbuf); + SECU_PrintError("problem deleting private key \"%s\"\n", ckaIDbuf); + } + + PK11_FreeSlot(slot); + return rv; +} + /* * L i s t M o d u l e s * @@ -1066,7 +1153,7 @@ PrintBuildFlags() } static void -PrintSyntax(char *progName) +PrintSyntax() { #define FPS fprintf(stderr, FPS "Type %s -H for more detailed descriptions\n", progName); @@ -1089,7 +1176,9 @@ PrintSyntax(char *progName) "\t\t [-d certdir] [-P dbprefix]\n", progName); FPS "\t%s -E -n cert-name -t trustargs [-d certdir] [-P dbprefix] [-a] [-i input]\n", progName); - FPS "\t%s -F -n nickname [-d certdir] [-P dbprefix]\n", + FPS "\t%s -F -n cert-name [-d certdir] [-P dbprefix]\n", + progName); + FPS "\t%s -F -k key-id [-d certdir] [-P dbprefix]\n", progName); FPS "\t%s -G -n key-name [-h token-name] [-k rsa] [-g key-size] [-y exp]\n" "\t\t [-f pwfile] [-z noisefile] [-d certdir] [-P dbprefix]\n", progName); @@ -1115,7 +1204,9 @@ PrintSyntax(char *progName) FPS "\t%s --build-flags\n", progName); FPS "\t%s -M -n cert-name -t trustargs [-d certdir] [-P dbprefix]\n", progName); - FPS "\t%s -O -n cert-name [-X] [-d certdir] [-a] [-P dbprefix]\n", progName); + FPS "\t%s -O -n cert-name [-X] [-d certdir] [-a] [-P dbprefix]\n" + "\t\t [--simple-self-signed]\n", + progName); FPS "\t%s -R -s subj -o cert-request-file [-d certdir] [-P dbprefix] [-p phone] [-a]\n" "\t\t [-7 emailAddrs] [-k key-type-or-id] [-h token-name] [-f pwfile]\n" "\t\t [-g key-size] [-Z hashAlg]\n", @@ -1377,6 +1468,8 @@ luF(enum usage_level ul, const char *command) return; FPS "%-20s The nickname of the key to delete\n", " -n cert-name"); + FPS "%-20s The key id of the key to delete, obtained using -K\n", + " -k key-id"); FPS "%-20s Cert database directory (default is ~/.netscape)\n", " -d certdir"); FPS "%-20s Cert & Key database prefix\n", @@ -1542,6 +1635,8 @@ luO(enum usage_level ul, const char *command) " -P dbprefix"); FPS "%-20s force the database to open R/W\n", " -X"); + FPS "%-20s don't search for a chain if issuer name equals subject name\n", + " --simple-self-signed"); FPS "\n"); } @@ -1560,7 +1655,7 @@ luR(enum usage_level ul, const char *command) " -o output-req"); FPS "%-20s Type of key pair to generate (\"dsa\", \"ec\", \"rsa\" (default))\n", " -k key-type-or-id"); - FPS "%-20s or nickname of the cert key to use \n", + FPS "%-20s or nickname of the cert key to use, or key id obtained using -K\n", ""); FPS "%-20s Name of token in which to generate key (default is internal)\n", " -h token-name"); @@ -1614,6 +1709,7 @@ luV(enum usage_level ul, const char *command) FPS "%-20s Specify certificate usage:\n", " -u certusage"); FPS "%-25s C \t SSL Client\n", ""); FPS "%-25s V \t SSL Server\n", ""); + FPS "%-25s I \t IPsec\n", ""); FPS "%-25s L \t SSL CA\n", ""); FPS "%-25s A \t Any CA\n", ""); FPS "%-25s Y \t Verify CA\n", ""); @@ -1838,7 +1934,7 @@ luBuildFlags(enum usage_level ul, const char *command) } static void -LongUsage(char *progName, enum usage_level ul, const char *command) +LongUsage(enum usage_level ul, const char *command) { luA(ul, command); luB(ul, command); @@ -1866,14 +1962,14 @@ LongUsage(char *progName, enum usage_level ul, const char *command) } static void -Usage(char *progName) +Usage() { PR_fprintf(PR_STDERR, "%s - Utility to manipulate NSS certificate databases\n\n" "Usage: %s <command> -d <database-directory> <options>\n\n" "Valid commands:\n", progName, progName); - LongUsage(progName, usage_selected, NULL); + LongUsage(usage_selected, NULL); PR_fprintf(PR_STDERR, "\n" "%s -H <command> : Print available options for the given command\n" "%s -H : Print complete help output of all commands and options\n" @@ -2269,10 +2365,10 @@ flagArray opFlagsArray[] = { NAME_SIZE(verify_recover), CKF_VERIFY_RECOVER }, { NAME_SIZE(wrap), CKF_WRAP }, { NAME_SIZE(unwrap), CKF_UNWRAP }, - { NAME_SIZE(derive), CKF_DERIVE }, + { NAME_SIZE(derive), CKF_DERIVE } }; -int opFlagsCount = sizeof(opFlagsArray) / sizeof(flagArray); +int opFlagsCount = PR_ARRAY_SIZE(opFlagsArray); flagArray attrFlagsArray[] = { @@ -2286,14 +2382,13 @@ flagArray attrFlagsArray[] = { NAME_SIZE(insensitive), PK11_ATTR_INSENSITIVE }, { NAME_SIZE(extractable), PK11_ATTR_EXTRACTABLE }, { NAME_SIZE(unextractable), PK11_ATTR_UNEXTRACTABLE } - }; -int attrFlagsCount = sizeof(attrFlagsArray) / sizeof(flagArray); +int attrFlagsCount = PR_ARRAY_SIZE(attrFlagsArray); #define MAX_STRING 30 CK_ULONG -GetFlags(char *flagsString, flagArray *flagArray, int count) +GetFlags(char *flagsString, flagArray *flags, int count) { CK_ULONG flagsValue = strtol(flagsString, NULL, 0); int i; @@ -2303,10 +2398,10 @@ GetFlags(char *flagsString, flagArray *flagArray, int count) } while (*flagsString) { for (i = 0; i < count; i++) { - if (strncmp(flagsString, flagArray[i].name, flagArray[i].nameSize) == + if (strncmp(flagsString, flags[i].name, flags[i].nameSize) == 0) { - flagsValue |= flagArray[i].value; - flagsString += flagArray[i].nameSize; + flagsValue |= flags[i].value; + flagsString += flags[i].nameSize; if (*flagsString != 0) { flagsString++; } @@ -2499,6 +2594,7 @@ enum certutilOpts { opt_NewNickname, opt_Pss, opt_PssSign, + opt_SimpleSelfSigned, opt_Help }; @@ -2623,6 +2719,8 @@ static const secuCommandFlag options_init[] = "pss" }, { /* opt_PssSign */ 0, PR_FALSE, 0, PR_FALSE, "pss-sign" }, + { /* opt_SimpleSelfSigned */ 0, PR_FALSE, 0, PR_FALSE, + "simple-self-signed" }, }; #define NUM_OPTIONS ((sizeof options_init) / (sizeof options_init[0])) @@ -2691,14 +2789,13 @@ certutil_main(int argc, char **argv, PRBool initialize) rv = SECU_ParseCommandLine(argc, argv, progName, &certutil); if (rv != SECSuccess) - Usage(progName); + Usage(); if (certutil.commands[cmd_PrintSyntax].activated) { - PrintSyntax(progName); + PrintSyntax(); } if (certutil.commands[cmd_PrintHelp].activated) { - int i; char buf[2]; const char *command = NULL; for (i = 0; i < max_cmd; i++) { @@ -2715,7 +2812,7 @@ certutil_main(int argc, char **argv, PRBool initialize) break; } } - LongUsage(progName, (command ? usage_selected : usage_all), command); + LongUsage((command ? usage_selected : usage_all), command); exit(1); } @@ -2823,7 +2920,7 @@ certutil_main(int argc, char **argv, PRBool initialize) if (certutil.options[opt_DBPrefix].arg) { certPrefix = certutil.options[opt_DBPrefix].arg; } else { - Usage(progName); + Usage(); } } @@ -2832,7 +2929,7 @@ certutil_main(int argc, char **argv, PRBool initialize) if (certutil.options[opt_SourcePrefix].arg) { srcCertPrefix = certutil.options[opt_SourcePrefix].arg; } else { - Usage(progName); + Usage(); } } @@ -2916,7 +3013,7 @@ certutil_main(int argc, char **argv, PRBool initialize) return 255; } if (commandsEntered == 0) { - Usage(progName); + Usage(); } if (certutil.commands[cmd_ListCerts].activated || @@ -2928,10 +3025,9 @@ certutil_main(int argc, char **argv, PRBool initialize) readOnly = !certutil.options[opt_RW].activated; } - /* -A, -D, -F, -M, -S, -V, and all require -n */ + /* -A, -D, -M, -S, -V, and all require -n */ if ((certutil.commands[cmd_AddCert].activated || certutil.commands[cmd_DeleteCert].activated || - certutil.commands[cmd_DeleteKey].activated || certutil.commands[cmd_DumpChain].activated || certutil.commands[cmd_ModifyCertTrust].activated || certutil.commands[cmd_CreateAndAddCert].activated || @@ -3018,6 +3114,16 @@ certutil_main(int argc, char **argv, PRBool initialize) return 255; } + /* Delete needs a nickname or a key ID */ + if (certutil.commands[cmd_DeleteKey].activated && + !(certutil.options[opt_Nickname].activated || keysource)) { + PR_fprintf(PR_STDERR, + "%s -%c: specify a nickname (-n) or\n" + " a key ID (-k).\n", + commandToRun, progName); + return 255; + } + /* Upgrade/Merge needs a source database and a upgrade id. */ if (certutil.commands[cmd_UpgradeMerge].activated && !(certutil.options[opt_SourceDir].activated && @@ -3124,6 +3230,8 @@ certutil_main(int argc, char **argv, PRBool initialize) } initialized = PR_TRUE; SECU_RegisterDynamicOids(); + /* Ensure the SSL error code table has been registered. Bug 1460284. */ + SSL_OptionSetDefault(-1, 0); } certHandle = CERT_GetDefaultCertDB(); @@ -3350,7 +3458,8 @@ certutil_main(int argc, char **argv, PRBool initialize) } if (certutil.commands[cmd_DumpChain].activated) { rv = DumpChain(certHandle, name, - certutil.options[opt_ASCIIForIO].activated); + certutil.options[opt_ASCIIForIO].activated, + certutil.options[opt_SimpleSelfSigned].activated); goto shutdown; } /* XXX needs work */ @@ -3377,7 +3486,19 @@ certutil_main(int argc, char **argv, PRBool initialize) } /* Delete key (-F) */ if (certutil.commands[cmd_DeleteKey].activated) { - rv = DeleteKey(name, &pwdata); + if (certutil.options[opt_Nickname].activated) { + rv = DeleteCertAndKey(name, &pwdata); + } else { + privkey = findPrivateKeyByID(slot, keysource, &pwdata); + if (!privkey) { + SECU_PrintError(progName, "%s is not a key-id", keysource); + rv = SECFailure; + } else { + rv = DeleteKey(privkey, &pwdata); + /* already destroyed by PK11_DeleteTokenPrivateKey */ + privkey = NULL; + } + } goto shutdown; } /* Modify trust attribute for cert (-M) */ @@ -3444,37 +3565,58 @@ certutil_main(int argc, char **argv, PRBool initialize) keycert = CERT_FindCertByNicknameOrEmailAddr(certHandle, keysource); if (!keycert) { keycert = PK11_FindCertFromNickname(keysource, NULL); - if (!keycert) { - SECU_PrintError(progName, - "%s is neither a key-type nor a nickname", keysource); - return SECFailure; - } } - privkey = PK11_FindKeyByDERCert(slot, keycert, &pwdata); - if (privkey) - pubkey = CERT_ExtractPublicKey(keycert); + + if (keycert) { + privkey = PK11_FindKeyByDERCert(slot, keycert, &pwdata); + } else { + /* Interpret keysource as CKA_ID */ + privkey = findPrivateKeyByID(slot, keysource, &pwdata); + } + + if (!privkey) { + SECU_PrintError( + progName, + "%s is neither a key-type nor a nickname nor a key-id", keysource); + return SECFailure; + } + + pubkey = SECKEY_ConvertToPublicKey(privkey); if (!pubkey) { SECU_PrintError(progName, "Could not get keys from cert %s", keysource); + if (keycert) { + CERT_DestroyCertificate(keycert); + } rv = SECFailure; - CERT_DestroyCertificate(keycert); goto shutdown; } keytype = privkey->keyType; + /* On CertReq for renewal if no subject has been * specified obtain it from the certificate. */ if (certutil.commands[cmd_CertReq].activated && !subject) { - subject = CERT_AsciiToName(keycert->subjectName); - if (!subject) { - SECU_PrintError(progName, - "Could not get subject from certificate %s", keysource); - CERT_DestroyCertificate(keycert); + if (keycert) { + subject = CERT_AsciiToName(keycert->subjectName); + if (!subject) { + SECU_PrintError( + progName, + "Could not get subject from certificate %s", + keysource); + CERT_DestroyCertificate(keycert); + rv = SECFailure; + goto shutdown; + } + } else { + SECU_PrintError(progName, "Subject name not provided"); rv = SECFailure; goto shutdown; } } - CERT_DestroyCertificate(keycert); + if (keycert) { + CERT_DestroyCertificate(keycert); + } } else { privkey = CERTUTIL_GeneratePrivateKey(keytype, slot, keysize, @@ -3537,6 +3679,14 @@ certutil_main(int argc, char **argv, PRBool initialize) } } + if (certutil.options[opt_SimpleSelfSigned].activated && + !certutil.commands[cmd_DumpChain].activated) { + PR_fprintf(PR_STDERR, + "%s -%c: --simple-self-signed only works with -O.\n", + progName, commandToRun); + return 255; + } + /* If we need a list of extensions convert the flags into list format */ if (certutil.commands[cmd_CertReq].activated || certutil.commands[cmd_CreateAndAddCert].activated || |