/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* ** dbtool.c ** ** tool to dump the underlying encoding of a database. This tool duplicates ** some private functions in softoken. It uses libsec and libutil, but no ** other portions of NSS. It currently only works on sqlite databases. For ** an even more primitive dump, use sqlite3 on the individual files. ** ** TODO: dump the meta data for the databases. ** optionally dump more PKCS5 information (KDF/salt/iterations) ** take a password and decode encrypted attributes/verify signed ** attributes. */ #include #include #if defined(WIN32) #include "fcntl.h" #include "io.h" #endif /*#include "secutil.h" */ /*#include "pk11pub.h" */ #if defined(XP_UNIX) #include #endif #include "nspr.h" #include "prtypes.h" #include "nss.h" #include "secasn1.h" #include "secder.h" #include "pk11table.h" #include "sftkdbt.h" #include "sdb.h" #include "secoid.h" #include "plgetopt.h" static char *progName; char *dbDir = NULL; static void Usage() { printf("Usage: %s [-c certprefix] [-k keyprefix] " "[-V certversion] [-v keyversion]\n" " [-d dbdir]\n", progName); printf("%-20s Directory with cert database (default is .)\n", "-d certdir"); printf("%-20s prefix for the cert database (default is \"\")\n", "-c certprefix"); printf("%-20s prefix for the key database (default is \"\")\n", "-k keyprefix"); printf("%-20s version of the cert database (default is 9)\n", "-V certversion"); printf("%-20s version of the key database (default is 4)\n", "-v keyversion"); exit(1); } #define SFTK_KEYDB_TYPE 0x40000000 #define SFTK_TOKEN_TYPE 0x80000000 /* * known attributes */ static const CK_ATTRIBUTE_TYPE known_attributes[] = { CKA_CLASS, CKA_TOKEN, CKA_PRIVATE, CKA_LABEL, CKA_APPLICATION, CKA_VALUE, CKA_OBJECT_ID, CKA_CERTIFICATE_TYPE, CKA_ISSUER, CKA_SERIAL_NUMBER, CKA_AC_ISSUER, CKA_OWNER, CKA_ATTR_TYPES, CKA_TRUSTED, CKA_CERTIFICATE_CATEGORY, CKA_JAVA_MIDP_SECURITY_DOMAIN, CKA_URL, CKA_HASH_OF_SUBJECT_PUBLIC_KEY, CKA_HASH_OF_ISSUER_PUBLIC_KEY, CKA_CHECK_VALUE, CKA_KEY_TYPE, CKA_SUBJECT, CKA_ID, CKA_SENSITIVE, CKA_ENCRYPT, CKA_DECRYPT, CKA_WRAP, CKA_UNWRAP, CKA_SIGN, CKA_SIGN_RECOVER, CKA_VERIFY, CKA_VERIFY_RECOVER, CKA_DERIVE, CKA_START_DATE, CKA_END_DATE, CKA_MODULUS, CKA_MODULUS_BITS, CKA_PUBLIC_EXPONENT, CKA_PRIVATE_EXPONENT, CKA_PRIME_1, CKA_PRIME_2, CKA_EXPONENT_1, CKA_EXPONENT_2, CKA_COEFFICIENT, CKA_PRIME, CKA_SUBPRIME, CKA_BASE, CKA_PRIME_BITS, CKA_SUB_PRIME_BITS, CKA_VALUE_BITS, CKA_VALUE_LEN, CKA_EXTRACTABLE, CKA_LOCAL, CKA_NEVER_EXTRACTABLE, CKA_ALWAYS_SENSITIVE, CKA_KEY_GEN_MECHANISM, CKA_MODIFIABLE, CKA_EC_PARAMS, CKA_EC_POINT, CKA_SECONDARY_AUTH, CKA_AUTH_PIN_FLAGS, CKA_ALWAYS_AUTHENTICATE, CKA_WRAP_WITH_TRUSTED, CKA_WRAP_TEMPLATE, CKA_UNWRAP_TEMPLATE, CKA_HW_FEATURE_TYPE, CKA_RESET_ON_INIT, CKA_HAS_RESET, CKA_PIXEL_X, CKA_PIXEL_Y, CKA_RESOLUTION, CKA_CHAR_ROWS, CKA_CHAR_COLUMNS, CKA_COLOR, CKA_BITS_PER_PIXEL, CKA_CHAR_SETS, CKA_ENCODING_METHODS, CKA_MIME_TYPES, CKA_MECHANISM_TYPE, CKA_REQUIRED_CMS_ATTRIBUTES, CKA_DEFAULT_CMS_ATTRIBUTES, CKA_SUPPORTED_CMS_ATTRIBUTES, CKA_NSS_URL, CKA_NSS_EMAIL, CKA_NSS_SMIME_INFO, CKA_NSS_SMIME_TIMESTAMP, CKA_NSS_PKCS8_SALT, CKA_NSS_PASSWORD_CHECK, CKA_NSS_EXPIRES, CKA_NSS_KRL, CKA_NSS_PQG_COUNTER, CKA_NSS_PQG_SEED, CKA_NSS_PQG_H, CKA_NSS_PQG_SEED_BITS, CKA_NSS_MODULE_SPEC, CKA_TRUST_DIGITAL_SIGNATURE, CKA_TRUST_NON_REPUDIATION, CKA_TRUST_KEY_ENCIPHERMENT, CKA_TRUST_DATA_ENCIPHERMENT, CKA_TRUST_KEY_AGREEMENT, CKA_TRUST_KEY_CERT_SIGN, CKA_TRUST_CRL_SIGN, CKA_TRUST_SERVER_AUTH, CKA_TRUST_CLIENT_AUTH, CKA_TRUST_CODE_SIGNING, CKA_TRUST_EMAIL_PROTECTION, CKA_TRUST_IPSEC_END_SYSTEM, CKA_TRUST_IPSEC_TUNNEL, CKA_TRUST_IPSEC_USER, CKA_TRUST_TIME_STAMPING, CKA_TRUST_STEP_UP_APPROVED, CKA_CERT_SHA1_HASH, CKA_CERT_MD5_HASH, CKA_NSS_DB, CKA_NSS_TRUST, CKA_NSS_OVERRIDE_EXTENSIONS, CKA_PUBLIC_KEY_INFO }; static unsigned int known_attributes_size = sizeof(known_attributes) / sizeof(known_attributes[0]); PRBool isULONGAttribute(CK_ATTRIBUTE_TYPE type) { switch (type) { case CKA_CERTIFICATE_CATEGORY: case CKA_CERTIFICATE_TYPE: case CKA_CLASS: case CKA_JAVA_MIDP_SECURITY_DOMAIN: case CKA_KEY_GEN_MECHANISM: case CKA_KEY_TYPE: case CKA_MECHANISM_TYPE: case CKA_MODULUS_BITS: case CKA_PRIME_BITS: case CKA_SUBPRIME_BITS: case CKA_VALUE_BITS: case CKA_VALUE_LEN: case CKA_TRUST_DIGITAL_SIGNATURE: case CKA_TRUST_NON_REPUDIATION: case CKA_TRUST_KEY_ENCIPHERMENT: case CKA_TRUST_DATA_ENCIPHERMENT: case CKA_TRUST_KEY_AGREEMENT: case CKA_TRUST_KEY_CERT_SIGN: case CKA_TRUST_CRL_SIGN: case CKA_TRUST_SERVER_AUTH: case CKA_TRUST_CLIENT_AUTH: case CKA_TRUST_CODE_SIGNING: case CKA_TRUST_EMAIL_PROTECTION: case CKA_TRUST_IPSEC_END_SYSTEM: case CKA_TRUST_IPSEC_TUNNEL: case CKA_TRUST_IPSEC_USER: case CKA_TRUST_TIME_STAMPING: case CKA_TRUST_STEP_UP_APPROVED: return PR_TRUE; default: break; } return PR_FALSE; } /* are the attributes private? */ static PRBool isPrivateAttribute(CK_ATTRIBUTE_TYPE type) { switch (type) { case CKA_VALUE: case CKA_PRIVATE_EXPONENT: case CKA_PRIME_1: case CKA_PRIME_2: case CKA_EXPONENT_1: case CKA_EXPONENT_2: case CKA_COEFFICIENT: return PR_TRUE; default: break; } return PR_FALSE; } /* These attributes must be authenticated with an hmac. */ static PRBool isAuthenticatedAttribute(CK_ATTRIBUTE_TYPE type) { switch (type) { case CKA_MODULUS: case CKA_PUBLIC_EXPONENT: case CKA_CERT_SHA1_HASH: case CKA_CERT_MD5_HASH: case CKA_TRUST_SERVER_AUTH: case CKA_TRUST_CLIENT_AUTH: case CKA_TRUST_EMAIL_PROTECTION: case CKA_TRUST_CODE_SIGNING: case CKA_TRUST_STEP_UP_APPROVED: case CKA_NSS_OVERRIDE_EXTENSIONS: return PR_TRUE; default: break; } return PR_FALSE; } /* * convert a database ulong back to a native ULONG. (reverse of the above * function. */ static CK_ULONG sdbULong2ULong(unsigned char *data) { int i; CK_ULONG value = 0; for (i = 0; i < SDB_ULONG_SIZE; i++) { value |= (((CK_ULONG)data[i]) << (SDB_ULONG_SIZE - 1 - i) * PR_BITS_PER_BYTE); } return value; } /* PBE defines and functions */ SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate) typedef struct EncryptedDataInfoStr { SECAlgorithmID algorithm; SECItem encryptedData; } EncryptedDataInfo; static const SEC_ASN1Template encryptedDataInfoTemplate[] = { { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(EncryptedDataInfo) }, { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(EncryptedDataInfo, algorithm), SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, { SEC_ASN1_OCTET_STRING, offsetof(EncryptedDataInfo, encryptedData) }, { 0 } }; typedef struct PBEParameterStr { SECAlgorithmID prfAlg; SECItem salt; SECItem iteration; SECItem keyLength; } PBEParameter; static const SEC_ASN1Template pkcs5V1PBEParameterTemplate[] = { { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(PBEParameter) }, { SEC_ASN1_OCTET_STRING, offsetof(PBEParameter, salt) }, { SEC_ASN1_INTEGER, offsetof(PBEParameter, iteration) }, { 0 } }; static const SEC_ASN1Template pkcs12V2PBEParameterTemplate[] = { { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(PBEParameter) }, { SEC_ASN1_OCTET_STRING, offsetof(PBEParameter, salt) }, { SEC_ASN1_INTEGER, offsetof(PBEParameter, iteration) }, { 0 } }; static const SEC_ASN1Template pkcs5V2PBEParameterTemplate[] = { { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(PBEParameter) }, /* this is really a choice, but since we don't understand any other * choice, just inline it. */ { SEC_ASN1_OCTET_STRING, offsetof(PBEParameter, salt) }, { SEC_ASN1_INTEGER, offsetof(PBEParameter, iteration) }, { SEC_ASN1_INTEGER, offsetof(PBEParameter, keyLength) }, { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(PBEParameter, prfAlg), SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, { 0 } }; typedef struct Pkcs5v2PBEParameterStr { SECAlgorithmID keyParams; /* parameters of the key generation */ SECAlgorithmID algParams; /* parameters for the encryption or mac op */ } Pkcs5v2PBEParameter; static const SEC_ASN1Template pkcs5v2PBES2ParameterTemplate[] = { { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(Pkcs5v2PBEParameter) }, { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(Pkcs5v2PBEParameter, keyParams), SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(Pkcs5v2PBEParameter, algParams), SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, { 0 } }; static inline PRBool isPKCS12PBE(SECOidTag alg) { switch (alg) { case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_2KEY_TRIPLE_DES_CBC: case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC: case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC2_CBC: case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC: case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC4: case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC4: return PR_TRUE; default: break; } return PR_FALSE; } /* helper functions */ /* output an NSS specific attribute or name that wasn't found in our * pkcs #11 table */ const char * makeNSSVendorName(CK_ATTRIBUTE_TYPE attribute, const char *nameType) { static char nss_name[256]; const char *name = NULL; if ((attribute >= CKA_NSS) && (attribute < 0xffffffffUL)) { sprintf(nss_name, "%s+%d", nameType, (int)(attribute - CKA_NSS)); name = nss_name; } return name; } /* turn and attribute into a name */ const char * AttributeName(CK_ATTRIBUTE_TYPE attribute) { const char *name = getNameFromAttribute(attribute); if (!name) { name = makeNSSVendorName(attribute, "CKA_NSS"); } return name ? name : "UNKNOWN_ATTRIBUTE_TYPE"; } /* turn and error code into a name */ const char * ErrorName(CK_RV crv) { const char *error = getName(crv, ConstResult); if (!error) { error = makeNSSVendorName(crv, "CKR_NSS"); } return error ? error : "UNKNOWN_ERROR"; } /* turn an oud tag into a string */ const char * oid2string(SECOidTag alg) { const char *oidstring = SECOID_FindOIDTagDescription(alg); const char *def = "Invalid oid tag"; /* future build a dotted oid string value here */ return oidstring ? oidstring : def; } /* dump an arbitary data blob. Dump it has hex with ascii on the side */ #define ASCCHAR(val) ((val) >= ' ' && (val) <= 0x7e ? (val) : '.') #define LINE_LENGTH 16 void dumpValue(const unsigned char *v, int len) { int i, next = 0; char string[LINE_LENGTH + 1]; char space[LINE_LENGTH * 2 + 1]; char *nl = ""; char *sp = ""; PORT_Memset(string, 0, sizeof(string)); for (i = 0; i < len; i++) { if ((i % LINE_LENGTH) == 0) { printf("%s%s%s ", sp, string, nl); PORT_Memset(string, 0, sizeof(string)); next = 0; nl = "\n"; sp = " "; } printf("%02x", v[i]); string[next++] = ASCCHAR(v[i]); } PORT_Memset(space, 0, sizeof(space)); i = LINE_LENGTH - (len % LINE_LENGTH); if (i != LINE_LENGTH) { int j; for (j = 0; j < i; j++) { space[j * 2] = ' '; space[j * 2 + 1] = ' '; } } printf("%s%s%s%s", space, sp, string, nl); } /* dump a PKCS5/12 PBE blob */ void dumpPKCS(unsigned char *val, CK_ULONG len, PRBool *hasSig) { EncryptedDataInfo edi; SECStatus rv; SECItem data; PLArenaPool *arena; SECOidTag alg, prfAlg; PBEParameter pbeParam; unsigned char zero = 0; const SEC_ASN1Template *template = pkcs5V1PBEParameterTemplate; int iter, keyLen, i; if (hasSig) { *hasSig = PR_FALSE; } data.data = val; data.len = len; arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); if (arena == NULL) { printf("Couldn't allocate arena\n"); return; } /* initialize default values */ PORT_Memset(&pbeParam, 0, sizeof(pbeParam)); pbeParam.keyLength.data = &zero; pbeParam.keyLength.len = sizeof(zero); SECOID_SetAlgorithmID(arena, &pbeParam.prfAlg, SEC_OID_SHA1, NULL); /* first crack the encrypted data from the PBE algorithm ID */ rv = SEC_QuickDERDecodeItem(arena, &edi, encryptedDataInfoTemplate, &data); if (rv != SECSuccess) { printf("Encrypted Data, failed to decode\n"); dumpValue(val, len); PORT_FreeArena(arena, PR_FALSE); return; } /* now use the pbe secalg to dump info on the pbe */ alg = SECOID_GetAlgorithmTag(&edi.algorithm); if ((alg == SEC_OID_PKCS5_PBES2) || (alg == SEC_OID_PKCS5_PBMAC1)) { Pkcs5v2PBEParameter param; SECOidTag palg; const char *typeName = (alg == SEC_OID_PKCS5_PBES2) ? "Encrypted Data PBES2" : "Mac Data PBMAC1"; rv = SEC_QuickDERDecodeItem(arena, ¶m, pkcs5v2PBES2ParameterTemplate, &edi.algorithm.parameters); if (rv != SECSuccess) { printf("%s, failed to decode\n", typeName); dumpValue(val, len); PORT_FreeArena(arena, PR_FALSE); return; } palg = SECOID_GetAlgorithmTag(¶m.algParams); printf("%s alg=%s ", typeName, oid2string(palg)); if (hasSig && palg == SEC_OID_AES_256_CBC) { *hasSig = PR_TRUE; } template = pkcs5V2PBEParameterTemplate; edi.algorithm.parameters = param.keyParams.parameters; } else { printf("Encrypted Data alg=%s ", oid2string(alg)); if (alg == SEC_OID_PKCS5_PBKDF2) { template = pkcs5V2PBEParameterTemplate; } else if (isPKCS12PBE(alg)) { template = pkcs12V2PBEParameterTemplate; } else { template = pkcs5V1PBEParameterTemplate; } } rv = SEC_QuickDERDecodeItem(arena, &pbeParam, template, &edi.algorithm.parameters); if (rv != SECSuccess) { printf("( failed to decode params)\n"); PORT_FreeArena(arena, PR_FALSE); return; } /* dump the pbe parmeters */ iter = DER_GetInteger(&pbeParam.iteration); keyLen = DER_GetInteger(&pbeParam.keyLength); prfAlg = SECOID_GetAlgorithmTag(&pbeParam.prfAlg); printf("(prf=%s iter=%d keyLen=%d salt=0x", oid2string(prfAlg), iter, keyLen); for (i = 0; i < pbeParam.salt.len; i++) printf("%02x", pbeParam.salt.data[i]); printf(")\n"); /* finally dump the raw encrypted data */ dumpValue(edi.encryptedData.data, edi.encryptedData.len); PORT_FreeArena(arena, PR_FALSE); } /* dump a long attribute, convert to an unsigned long. PKCS #11 Longs are * limited to 32 bits by the spec, even if the CK_ULONG is longer */ void dumpLongAttribute(CK_ATTRIBUTE_TYPE type, CK_ULONG value) { const char *nameType = "CK_NSS"; ConstType constType = ConstNone; const char *valueName = NULL; switch (type) { case CKA_CLASS: nameType = "CKO_NSS"; constType = ConstObject; break; case CKA_CERTIFICATE_TYPE: nameType = "CKC_NSS"; constType = ConstCertType; break; case CKA_KEY_TYPE: nameType = "CKK_NSS"; constType = ConstKeyType; break; case CKA_MECHANISM_TYPE: nameType = "CKM_NSS"; constType = ConstMechanism; break; case CKA_TRUST_SERVER_AUTH: case CKA_TRUST_CLIENT_AUTH: case CKA_TRUST_CODE_SIGNING: case CKA_TRUST_EMAIL_PROTECTION: case CKA_TRUST_IPSEC_END_SYSTEM: case CKA_TRUST_IPSEC_TUNNEL: case CKA_TRUST_IPSEC_USER: case CKA_TRUST_TIME_STAMPING: nameType = "CKT_NSS"; constType = ConstTrust; break; default: break; } /* if value has a symbolic name, use it */ if (constType != ConstNone) { valueName = getName(value, constType); } if (!valueName) { valueName = makeNSSVendorName(value, nameType); } if (!valueName) { printf("%d (0x%08x)\n", (int)value, (int)value); } else { printf("%s (0x%08x)\n", valueName, (int)value); } } /* dump a signature for an object */ static const char META_SIG_TEMPLATE[] = "sig_%s_%08x_%08x"; void dumpSignature(CK_ATTRIBUTE_TYPE attribute, SDB *keydb, PRBool isKey, CK_OBJECT_HANDLE objectID, PRBool force) { char id[30]; CK_RV crv; SECItem signText; unsigned char signData[SDB_MAX_META_DATA_LEN]; if (!force && !isAuthenticatedAttribute(attribute)) { return; } sprintf(id, META_SIG_TEMPLATE, isKey ? "key" : "cert", (unsigned int)objectID, (unsigned int)attribute); printf(" Signature %s:", id); signText.data = signData; signText.len = sizeof(signData); crv = (*keydb->sdb_GetMetaData)(keydb, id, &signText, NULL); if ((crv != CKR_OK) && isKey) { sprintf(id, META_SIG_TEMPLATE, isKey ? "key" : "cert", (unsigned int)(objectID | SFTK_KEYDB_TYPE | SFTK_TOKEN_TYPE), (unsigned int)attribute); crv = (*keydb->sdb_GetMetaData)(keydb, id, &signText, NULL); } if (crv != CKR_OK) { printf(" FAILED %s with %s (0x%08x)\n", id, ErrorName(crv), (int)crv); return; } dumpPKCS(signText.data, signText.len, NULL); return; } /* dump an attribute. use the helper functions above */ void dumpAttribute(CK_ATTRIBUTE *template, SDB *keydb, PRBool isKey, CK_OBJECT_HANDLE id) { CK_ATTRIBUTE_TYPE attribute = template->type; printf(" %s(0x%08x): ", AttributeName(attribute), (int)attribute); if (template->pValue == NULL) { printf("NULL (%d)\n", (int)template->ulValueLen); return; } if (template->ulValueLen == SDB_ULONG_SIZE && isULONGAttribute(attribute)) { CK_ULONG value = sdbULong2ULong(template->pValue); dumpLongAttribute(attribute, value); return; } if (template->ulValueLen == 1) { unsigned char val = *(unsigned char *)template->pValue; switch (val) { case 0: printf("CK_FALSE\n"); break; case 1: printf("CK_TRUE\n"); break; default: printf("%d 0x%02x %c\n", val, val, ASCCHAR(val)); break; } return; } if (isKey && isPrivateAttribute(attribute)) { PRBool hasSig = PR_FALSE; dumpPKCS(template->pValue, template->ulValueLen, &hasSig); if (hasSig) { dumpSignature(attribute, keydb, isKey, id, PR_TRUE); } return; } if (template->ulValueLen == 0) { printf("empty"); } printf("\n"); dumpValue(template->pValue, template->ulValueLen); } /* dump all the attributes in an object */ void dumpObject(CK_OBJECT_HANDLE id, SDB *db, SDB *keydb, PRBool isKey) { CK_RV crv; int i; CK_ATTRIBUTE template; char buffer[2048]; char *alloc = NULL; printf(" Object 0x%08x:\n", (int)id); for (i = 0; i < known_attributes_size; i++) { CK_ATTRIBUTE_TYPE attribute = known_attributes[i]; template.type = attribute; template.pValue = NULL; template.ulValueLen = 0; crv = (*db->sdb_GetAttributeValue)(db, id, &template, 1); if (crv != CKR_OK) { if (crv != CKR_ATTRIBUTE_TYPE_INVALID) { PR_fprintf(PR_STDERR, " " "Get Attribute %s (0x%08x):FAILED\"%s\"(0x%08x)\n", AttributeName(attribute), (int)attribute, ErrorName(crv), (int)crv); } continue; } if (template.ulValueLen < sizeof(buffer)) { template.pValue = buffer; } else { alloc = PORT_Alloc(template.ulValueLen); template.pValue = alloc; } if (template.pValue == NULL) { PR_fprintf(PR_STDERR, " " "Could allocate %d bytes for Attribute %s (0x%08x)\n", (int)template.ulValueLen, AttributeName(attribute), (int)attribute); continue; } crv = (*db->sdb_GetAttributeValue)(db, id, &template, 1); if (crv != CKR_OK) { if (crv != CKR_ATTRIBUTE_TYPE_INVALID) { PR_fprintf(PR_STDERR, " " "Get Attribute %s (0x%08x):FAILED\"%s\"(0x%08x)\n", AttributeName(attribute), (int)attribute, ErrorName(crv), (int)crv); } if (alloc) { PORT_Free(alloc); alloc = NULL; } continue; } dumpAttribute(&template, keydb, isKey, id); dumpSignature(template.type, keydb, isKey, id, PR_FALSE); if (alloc) { PORT_Free(alloc); alloc = NULL; } } } /* dump all the objects in a database */ void dumpDB(SDB *db, const char *name, SDB *keydb, PRBool isKey) { SDBFind *findHandle = NULL; CK_BBOOL isTrue = 1; CK_ATTRIBUTE allObjectTemplate = { CKA_TOKEN, NULL, 1 }; CK_ULONG allObjectTemplateCount = 1; PRBool recordFound = PR_FALSE; CK_RV crv = CKR_OK; CK_ULONG objectCount = 0; printf("%s:\n", name); allObjectTemplate.pValue = &isTrue; crv = (*db->sdb_FindObjectsInit)(db, &allObjectTemplate, allObjectTemplateCount, &findHandle); do { CK_OBJECT_HANDLE id; recordFound = PR_FALSE; crv = (*db->sdb_FindObjects)(db, findHandle, &id, 1, &objectCount); if ((crv == CKR_OK) && (objectCount == 1)) { recordFound = PR_TRUE; dumpObject(id, db, keydb, isKey); } } while (recordFound); if (crv != CKR_OK) { PR_fprintf(PR_STDERR, "Last record return PKCS #11 error = %s (0x%08x)\n", ErrorName(crv), (int)crv); } (*db->sdb_FindObjectsFinal)(db, findHandle); } static char * secu_ConfigDirectory(const char *base) { static PRBool initted = PR_FALSE; const char *dir = ".netscape"; char *home; static char buf[1000]; if (initted) return buf; if (base == NULL || *base == 0) { home = PR_GetEnvSecure("HOME"); if (!home) home = ""; if (*home && home[strlen(home) - 1] == '/') sprintf(buf, "%.900s%s", home, dir); else sprintf(buf, "%.900s/%s", home, dir); } else { sprintf(buf, "%.900s", base); if (buf[strlen(buf) - 1] == '/') buf[strlen(buf) - 1] = 0; } initted = PR_TRUE; return buf; } int main(int argc, char **argv) { PLOptState *optstate; PLOptStatus optstatus; char *certPrefix = "", *keyPrefix = ""; int cert_version = 9; int key_version = 4; SDB *certdb = NULL; SDB *keydb = NULL; PRBool isNew = PR_FALSE; CK_RV crv; progName = strrchr(argv[0], '/'); if (!progName) progName = strrchr(argv[0], '\\'); progName = progName ? progName + 1 : argv[0]; optstate = PL_CreateOptState(argc, argv, "d:c:k:v:V:h"); while ((optstatus = PL_GetNextOpt(optstate)) == PL_OPT_OK) { switch (optstate->option) { case 'h': default: Usage(); break; case 'd': dbDir = PORT_Strdup(optstate->value); break; case 'c': certPrefix = PORT_Strdup(optstate->value); break; case 'k': keyPrefix = PORT_Strdup(optstate->value); break; case 'v': key_version = atoi(optstate->value); break; case 'V': cert_version = atoi(optstate->value); break; } } PL_DestroyOptState(optstate); if (optstatus == PL_OPT_BAD) Usage(); if (dbDir) { char *tmp = dbDir; dbDir = secu_ConfigDirectory(tmp); PORT_Free(tmp); } else { dbDir = secu_ConfigDirectory(NULL); } PR_fprintf(PR_STDERR, "dbdir selected is %s\n\n", dbDir); if (dbDir[0] == '\0') { PR_fprintf(PR_STDERR, "ERROR: Directory \"%s\" does not exist.\n", dbDir); return 1; } PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); SECOID_Init(); crv = s_open(dbDir, certPrefix, keyPrefix, cert_version, key_version, SDB_RDONLY, &certdb, &keydb, &isNew); if (crv != CKR_OK) { PR_fprintf(PR_STDERR, "Couldn't open databased in %s, error=%s (0x%08x)\n", dbDir, ErrorName(crv), (int)crv); return 1; } /* now dump the objects in the cert database */ dumpDB(certdb, "CertDB", keydb, PR_FALSE); dumpDB(keydb, "KeyDB", keydb, PR_TRUE); return 0; }