diff options
author | nelson%bolyard.com <devnull@localhost> | 2008-02-23 03:25:50 +0000 |
---|---|---|
committer | nelson%bolyard.com <devnull@localhost> | 2008-02-23 03:25:50 +0000 |
commit | 71e311fddd7f45fa1a9c28c6b4c7831d3bd32228 (patch) | |
tree | e83831a3239d5eb0090a07753f9330c3abf0e98f | |
parent | e005b31f6ce5193714a706a1f0e291dd860b2475 (diff) | |
download | nss-hg-71e311fddd7f45fa1a9c28c6b4c7831d3bd32228.tar.gz |
Bug 291384: certutil -K behavior doesn't match usage. r=alexei,rrelyea
-rw-r--r-- | security/nss/cmd/certutil/certutil.c | 161 |
1 files changed, 129 insertions, 32 deletions
diff --git a/security/nss/cmd/certutil/certutil.c b/security/nss/cmd/certutil/certutil.c index 387bd8722..c4fd5662f 100644 --- a/security/nss/cmd/certutil/certutil.c +++ b/security/nss/cmd/certutil/certutil.c @@ -700,7 +700,7 @@ listCerts(CERTCertDBHandle *handle, char *name, PK11SlotInfo *slot, } static SECStatus -ListCerts(CERTCertDBHandle *handle, char *name, PK11SlotInfo *slot, +ListCerts(CERTCertDBHandle *handle, char *nickname, PK11SlotInfo *slot, PRBool raw, PRBool ascii, PRFileDesc *outfile, secuPWData *pwdata) { SECStatus rv; @@ -718,7 +718,7 @@ ListCerts(CERTCertDBHandle *handle, char *name, PK11SlotInfo *slot, CERT_DestroyCertList(list); return SECSuccess; } else { - rv = listCerts(handle,name,slot,raw,ascii,outfile,pwdata); + rv = listCerts(handle,nickname,slot,raw,ascii,outfile,pwdata); } return rv; } @@ -869,67 +869,161 @@ printKeyCB(SECKEYPublicKey *key, SECItem *data, void *arg) return SECSuccess; } -/* callback for listing certs through pkcs11 */ -static SECStatus -secu_PrintKey(FILE *out, int count, SECKEYPrivateKey *key) +static PRBool +ItemIsPrintableASCII(const SECItem * item) { - char *name; + unsigned char *src = item->data; + unsigned int len = item->len; + while (len-- > 0) { + unsigned char uc = *src++; + if (uc < 0x20 || uc > 0x7e) + return PR_FALSE; + } + return PR_TRUE; +} - name = PK11_GetPrivateKeyNickname(key); - if (name == NULL) { - /* should look up associated cert */ - name = PORT_Strdup("< orphaned >"); +/* Caller ensures that dst is at least item->len*2+1 bytes long */ +static void +SECItemToHex(const SECItem * item, char * dst) +{ + if (dst && item && item->data) { + unsigned char * src = item->data; + unsigned int len = item->len; + for (; len > 0; --len, dst += 2) { + sprintf(dst, "%02x", *src++); + } + *dst = '\0'; } - fprintf(out, "<%d> %s\n", count, name); - PORT_Free(name); +} + +static const char * const keyTypeName[] = { + "null", "rsa", "dsa", "fortezza", "dh", "kea", "ec" }; + +#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) +{ + SECItem * ckaID; + char ckaIDbuf[MAX_CKA_ID_STR_LEN + 4]; + + pwarg = NULL; + ckaID = PK11_GetLowLevelKeyIDForPrivateKey(key); + if (!ckaID) { + strcpy(ckaIDbuf, "(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'; + } 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); + } + + PR_fprintf(out, "<%2d> %-8.8s %-42.42s %s\n", count, + keyTypeName[key->keyType], ckaIDbuf, nickName); + SECITEM_ZfreeItem(ckaID, PR_TRUE); return SECSuccess; } +/* returns SECSuccess if ANY keys are found, SECFailure otherwise. */ static SECStatus -listKeys(PK11SlotInfo *slot, KeyType keyType, void *pwarg) +ListKeysInSlot(PK11SlotInfo *slot, const char *nickName, KeyType keyType, + void *pwarg) { SECKEYPrivateKeyList *list; SECKEYPrivateKeyListNode *node; - int count; + int count = 0; if (PK11_NeedLogin(slot)) PK11_Authenticate(slot, PR_TRUE, pwarg); - list = PK11_ListPrivateKeysInSlot(slot); + if (nickName && nickName[0]) + list = PK11_ListPrivKeysInSlot(slot, (char *)nickName, pwarg); + else + list = PK11_ListPrivateKeysInSlot(slot); if (list == NULL) { SECU_PrintError(progName, "problem listing keys"); return SECFailure; } - for (count=0, node=PRIVKEY_LIST_HEAD(list) ; !PRIVKEY_LIST_END(node,list); - node= PRIVKEY_LIST_NEXT(node),count++) { - secu_PrintKey(stdout, count, node->key); + for (node=PRIVKEY_LIST_HEAD(list); + !PRIVKEY_LIST_END(node,list); + node=PRIVKEY_LIST_NEXT(node)) { + char * keyName; + static const char orphan[] = { "(orphan)" }; + + if (keyType != nullKey && keyType != node->key->keyType) + continue; + keyName = PK11_GetPrivateKeyNickname(node->key); + if (!keyName || !keyName[0]) { + /* Try extra hard to find nicknames for keys that lack them. */ + CERTCertificate * cert; + PORT_Free((void *)keyName); + keyName = NULL; + cert = PK11_GetCertFromPrivateKey(node->key); + if (cert) { + if (cert->nickname && !cert->nickname[0]) { + keyName = PORT_Strdup(cert->nickname); + } else if (cert->emailAddr && cert->emailAddr[0]) { + keyName = PORT_Strdup(cert->emailAddr); + } + CERT_DestroyCertificate(cert); + } + } + if (nickName) { + if (!keyName || PL_strcmp(keyName,nickName)) { + /* PKCS#11 module returned unwanted keys */ + PORT_Free((void *)keyName); + continue; + } + } + if (!keyName) + keyName = (char *)orphan; + + PrintKey(PR_STDOUT, keyName, count, node->key, pwarg); + + if (keyName != (char *)orphan) + PORT_Free((void *)keyName); + count++; } SECKEY_DestroyPrivateKeyList(list); if (count == 0) { - fprintf(stderr, "%s: no keys found\n", progName); + PR_fprintf(PR_STDOUT, "%s: no keys found\n", progName); return SECFailure; } return SECSuccess; } +/* returns SECSuccess if ANY keys are found, SECFailure otherwise. */ static SECStatus -ListKeys(PK11SlotInfo *slot, char *keyname, int index, +ListKeys(PK11SlotInfo *slot, const char *nickName, int index, KeyType keyType, PRBool dopriv, secuPWData *pwdata) { - SECStatus rv = SECSuccess; + SECStatus rv = SECFailure; if (slot == NULL) { PK11SlotList *list; PK11SlotListElement *le; list= PK11_GetAllTokens(CKM_INVALID_MECHANISM,PR_FALSE,PR_FALSE,pwdata); - if (list) for (le = list->head; le; le = le->next) { - rv = listKeys(le->slot,keyType,pwdata); + if (list) { + for (le = list->head; le; le = le->next) { + rv &= ListKeysInSlot(le->slot,nickName,keyType,pwdata); + } + PK11_FreeSlotList(list); } } else { - rv = listKeys(slot,keyType,pwdata); + rv = ListKeysInSlot(slot,nickName,keyType,pwdata); } return rv; } @@ -1188,18 +1282,19 @@ static void LongUsage(char *progName) " -X"); FPS "\n"); - FPS "%-15s List all keys\n", /*, or print out a single named key\n",*/ + FPS "%-15s List all private keys\n", "-K"); - FPS "%-20s Name of token in which to look for keys (default is internal," - " use \"all\" to list keys on all tokens)\n", + FPS "%-20s Name of token to search (\"all\" for all tokens)\n", " -h token-name "); + + FPS "%-20s Key type (\"all\" (default), \"dsa\"," #ifdef NSS_ENABLE_ECC - FPS "%-20s Type of key pair to list (\"all\", \"dsa\", \"ec\", \"rsa\" (default))\n", - " -k key-type"); -#else - FPS "%-20s Type of key pair to list (\"all\", \"dsa\", \"rsa\" (default))\n", - " -k key-type"); + " \"ec\"," #endif + " \"rsa\")\n", + " -k key-type"); + FPS "%-20s The nickname of the key or associated certificate\n", + " -n name"); FPS "%-20s Specify the password file\n", " -f password-file"); FPS "%-20s Key database directory (default is ~/.netscape)\n", @@ -2541,6 +2636,8 @@ secuCommandFlag certutil_options[] = progName, arg); return 255; } + } else if (certutil.commands[cmd_ListKeys].activated) { + keytype = nullKey; } /* -m serial number */ |