dbtool.c (25412B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 /* 6 ** dbtool.c 7 ** 8 ** tool to dump the underlying encoding of a database. This tool duplicates 9 ** some private functions in softoken. It uses libsec and libutil, but no 10 ** other portions of NSS. It currently only works on sqlite databases. For 11 ** an even more primitive dump, use sqlite3 on the individual files. 12 ** 13 ** TODO: dump the meta data for the databases. 14 ** optionally dump more PKCS5 information (KDF/salt/iterations) 15 ** take a password and decode encrypted attributes/verify signed 16 ** attributes. 17 */ 18 #include <stdio.h> 19 #include <string.h> 20 21 #if defined(WIN32) 22 #include "fcntl.h" 23 #include "io.h" 24 #endif 25 26 /*#include "secutil.h" */ 27 /*#include "pk11pub.h" */ 28 29 #if defined(XP_UNIX) 30 #include <unistd.h> 31 #endif 32 33 #include "nspr.h" 34 #include "prtypes.h" 35 #include "nss.h" 36 #include "secasn1.h" 37 #include "secder.h" 38 #include "pk11table.h" 39 #include "sftkdbt.h" 40 #include "sdb.h" 41 #include "secoid.h" 42 43 #include "plgetopt.h" 44 45 static char *progName; 46 47 char *dbDir = NULL; 48 49 static void 50 Usage() 51 { 52 printf("Usage: %s [-c certprefix] [-k keyprefix] " 53 "[-V certversion] [-v keyversion]\n" 54 " [-d dbdir]\n", 55 progName); 56 printf("%-20s Directory with cert database (default is .)\n", 57 "-d certdir"); 58 printf("%-20s prefix for the cert database (default is \"\")\n", 59 "-c certprefix"); 60 printf("%-20s prefix for the key database (default is \"\")\n", 61 "-k keyprefix"); 62 printf("%-20s version of the cert database (default is 9)\n", 63 "-V certversion"); 64 printf("%-20s version of the key database (default is 4)\n", 65 "-v keyversion"); 66 exit(1); 67 } 68 #define SFTK_KEYDB_TYPE 0x40000000 69 #define SFTK_TOKEN_TYPE 0x80000000 70 71 /* 72 * known attributes 73 */ 74 extern const CK_ATTRIBUTE_TYPE sftkdb_known_attributes[]; 75 extern size_t sftkdb_known_attributes_size; 76 77 PRBool 78 isULONGAttribute(CK_ATTRIBUTE_TYPE type) 79 { 80 switch (type) { 81 case CKA_CERTIFICATE_CATEGORY: 82 case CKA_CERTIFICATE_TYPE: 83 case CKA_CLASS: 84 case CKA_JAVA_MIDP_SECURITY_DOMAIN: 85 case CKA_KEY_GEN_MECHANISM: 86 case CKA_KEY_TYPE: 87 case CKA_MECHANISM_TYPE: 88 case CKA_MODULUS_BITS: 89 case CKA_PRIME_BITS: 90 case CKA_SUBPRIME_BITS: 91 case CKA_VALUE_BITS: 92 case CKA_VALUE_LEN: 93 94 case CKA_NSS_TRUST_DIGITAL_SIGNATURE: 95 case CKA_NSS_TRUST_NON_REPUDIATION: 96 case CKA_NSS_TRUST_KEY_ENCIPHERMENT: 97 case CKA_NSS_TRUST_DATA_ENCIPHERMENT: 98 case CKA_NSS_TRUST_KEY_AGREEMENT: 99 case CKA_NSS_TRUST_KEY_CERT_SIGN: 100 case CKA_NSS_TRUST_CRL_SIGN: 101 102 case CKA_NSS_TRUST_SERVER_AUTH: 103 case CKA_NSS_TRUST_CLIENT_AUTH: 104 case CKA_NSS_TRUST_CODE_SIGNING: 105 case CKA_NSS_TRUST_EMAIL_PROTECTION: 106 case CKA_NSS_TRUST_IPSEC_END_SYSTEM: 107 case CKA_NSS_TRUST_IPSEC_TUNNEL: 108 case CKA_NSS_TRUST_IPSEC_USER: 109 case CKA_NSS_TRUST_TIME_STAMPING: 110 case CKA_PKCS_TRUST_SERVER_AUTH: 111 case CKA_PKCS_TRUST_CLIENT_AUTH: 112 case CKA_PKCS_TRUST_CODE_SIGNING: 113 case CKA_PKCS_TRUST_EMAIL_PROTECTION: 114 case CKA_TRUST_IPSEC_IKE: 115 case CKA_PKCS_TRUST_TIME_STAMPING: 116 case CKA_NAME_HASH_ALGORITHM: 117 return PR_TRUE; 118 default: 119 break; 120 } 121 return PR_FALSE; 122 } 123 124 /* are the attributes private? */ 125 static PRBool 126 isPrivateAttribute(CK_ATTRIBUTE_TYPE type) 127 { 128 switch (type) { 129 case CKA_VALUE: 130 case CKA_PRIVATE_EXPONENT: 131 case CKA_PRIME_1: 132 case CKA_PRIME_2: 133 case CKA_EXPONENT_1: 134 case CKA_EXPONENT_2: 135 case CKA_COEFFICIENT: 136 return PR_TRUE; 137 default: 138 break; 139 } 140 return PR_FALSE; 141 } 142 143 /* These attributes must be authenticated with an hmac. */ 144 static PRBool 145 isAuthenticatedAttribute(CK_ATTRIBUTE_TYPE type) 146 { 147 switch (type) { 148 case CKA_MODULUS: 149 case CKA_PUBLIC_EXPONENT: 150 case CKA_NSS_CERT_SHA1_HASH: 151 case CKA_NSS_CERT_MD5_HASH: 152 case CKA_NSS_TRUST_SERVER_AUTH: 153 case CKA_NSS_TRUST_CLIENT_AUTH: 154 case CKA_NSS_TRUST_EMAIL_PROTECTION: 155 case CKA_NSS_TRUST_CODE_SIGNING: 156 case CKA_HASH_OF_CERTIFICATE: 157 case CKA_NAME_HASH_ALGORITHM: 158 case CKA_PKCS_TRUST_SERVER_AUTH: 159 case CKA_PKCS_TRUST_CLIENT_AUTH: 160 case CKA_PKCS_TRUST_EMAIL_PROTECTION: 161 case CKA_PKCS_TRUST_CODE_SIGNING: 162 case CKA_NSS_OVERRIDE_EXTENSIONS: 163 return PR_TRUE; 164 default: 165 break; 166 } 167 return PR_FALSE; 168 } 169 170 /* 171 * convert a database ulong back to a native ULONG. (reverse of the above 172 * function. 173 */ 174 static CK_ULONG 175 sdbULong2ULong(unsigned char *data) 176 { 177 int i; 178 CK_ULONG value = 0; 179 180 for (i = 0; i < SDB_ULONG_SIZE; i++) { 181 value |= (((CK_ULONG)data[i]) << (SDB_ULONG_SIZE - 1 - i) * PR_BITS_PER_BYTE); 182 } 183 return value; 184 } 185 186 /* PBE defines and functions */ 187 SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate) 188 189 typedef struct EncryptedDataInfoStr { 190 SECAlgorithmID algorithm; 191 SECItem encryptedData; 192 } EncryptedDataInfo; 193 194 static const SEC_ASN1Template encryptedDataInfoTemplate[] = { 195 { SEC_ASN1_SEQUENCE, 196 0, NULL, sizeof(EncryptedDataInfo) }, 197 { SEC_ASN1_INLINE | SEC_ASN1_XTRN, 198 offsetof(EncryptedDataInfo, algorithm), 199 SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, 200 { SEC_ASN1_OCTET_STRING, 201 offsetof(EncryptedDataInfo, encryptedData) }, 202 { 0 } 203 }; 204 205 typedef struct PBEParameterStr { 206 SECAlgorithmID prfAlg; 207 SECItem salt; 208 SECItem iteration; 209 SECItem keyLength; 210 } PBEParameter; 211 212 static const SEC_ASN1Template pkcs5V1PBEParameterTemplate[] = { 213 { SEC_ASN1_SEQUENCE, 214 0, NULL, sizeof(PBEParameter) }, 215 { SEC_ASN1_OCTET_STRING, 216 offsetof(PBEParameter, salt) }, 217 { SEC_ASN1_INTEGER, 218 offsetof(PBEParameter, iteration) }, 219 { 0 } 220 }; 221 222 static const SEC_ASN1Template pkcs12V2PBEParameterTemplate[] = { 223 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(PBEParameter) }, 224 { SEC_ASN1_OCTET_STRING, offsetof(PBEParameter, salt) }, 225 { SEC_ASN1_INTEGER, offsetof(PBEParameter, iteration) }, 226 { 0 } 227 }; 228 229 static const SEC_ASN1Template pkcs5V2PBEParameterTemplate[] = { 230 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(PBEParameter) }, 231 /* this is really a choice, but since we don't understand any other 232 * choice, just inline it. */ 233 { SEC_ASN1_OCTET_STRING, offsetof(PBEParameter, salt) }, 234 { SEC_ASN1_INTEGER, offsetof(PBEParameter, iteration) }, 235 { SEC_ASN1_INTEGER, offsetof(PBEParameter, keyLength) }, 236 { SEC_ASN1_INLINE | SEC_ASN1_XTRN, 237 offsetof(PBEParameter, prfAlg), 238 SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, 239 { 0 } 240 }; 241 242 typedef struct Pkcs5v2PBEParameterStr { 243 SECAlgorithmID keyParams; /* parameters of the key generation */ 244 SECAlgorithmID algParams; /* parameters for the encryption or mac op */ 245 } Pkcs5v2PBEParameter; 246 247 static const SEC_ASN1Template pkcs5v2PBES2ParameterTemplate[] = { 248 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(Pkcs5v2PBEParameter) }, 249 { SEC_ASN1_INLINE | SEC_ASN1_XTRN, 250 offsetof(Pkcs5v2PBEParameter, keyParams), 251 SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, 252 { SEC_ASN1_INLINE | SEC_ASN1_XTRN, 253 offsetof(Pkcs5v2PBEParameter, algParams), 254 SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, 255 { 0 } 256 }; 257 258 static inline PRBool 259 isPKCS12PBE(SECOidTag alg) 260 { 261 switch (alg) { 262 case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_2KEY_TRIPLE_DES_CBC: 263 case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC: 264 case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC2_CBC: 265 case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC: 266 case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC4: 267 case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC4: 268 return PR_TRUE; 269 default: 270 break; 271 } 272 return PR_FALSE; 273 } 274 275 /* helper functions */ 276 277 /* output an NSS specific attribute or name that wasn't found in our 278 * pkcs #11 table */ 279 const char * 280 makeNSSVendorName(CK_ATTRIBUTE_TYPE attribute, const char *nameType) 281 { 282 static char nss_name[256]; 283 const char *name = NULL; 284 if ((attribute >= CKA_NSS) && (attribute < 0xffffffffUL)) { 285 snprintf(nss_name, sizeof(nss_name), "%s+%d", nameType, (int)(attribute - CKA_NSS)); 286 name = nss_name; 287 } 288 return name; 289 } 290 291 /* turn and attribute into a name */ 292 const char * 293 AttributeName(CK_ATTRIBUTE_TYPE attribute) 294 { 295 const char *name = getNameFromAttribute(attribute); 296 if (!name) { 297 name = makeNSSVendorName(attribute, "CKA_NSS"); 298 } 299 300 return name ? name : "UNKNOWN_ATTRIBUTE_TYPE"; 301 } 302 303 /* turn and error code into a name */ 304 const char * 305 ErrorName(CK_RV crv) 306 { 307 const char *error = getName(crv, ConstResult); 308 if (!error) { 309 error = makeNSSVendorName(crv, "CKR_NSS"); 310 } 311 return error ? error : "UNKNOWN_ERROR"; 312 } 313 314 /* turn an oud tag into a string */ 315 const char * 316 oid2string(SECOidTag alg) 317 { 318 const char *oidstring = SECOID_FindOIDTagDescription(alg); 319 const char *def = "Invalid oid tag"; /* future build a dotted oid string value here */ 320 return oidstring ? oidstring : def; 321 } 322 323 /* dump an arbitary data blob. Dump it has hex with ascii on the side */ 324 #define ASCCHAR(val) ((val) >= ' ' && (val) <= 0x7e ? (val) : '.') 325 #define LINE_LENGTH 16 326 void 327 dumpValue(const unsigned char *v, int len) 328 { 329 int i, next = 0; 330 char string[LINE_LENGTH + 1]; 331 char space[LINE_LENGTH * 2 + 1]; 332 char *nl = ""; 333 char *sp = ""; 334 PORT_Memset(string, 0, sizeof(string)); 335 336 for (i = 0; i < len; i++) { 337 if ((i % LINE_LENGTH) == 0) { 338 printf("%s%s%s ", sp, string, nl); 339 PORT_Memset(string, 0, sizeof(string)); 340 next = 0; 341 nl = "\n"; 342 sp = " "; 343 } 344 printf("%02x", v[i]); 345 string[next++] = ASCCHAR(v[i]); 346 } 347 PORT_Memset(space, 0, sizeof(space)); 348 i = LINE_LENGTH - (len % LINE_LENGTH); 349 if (i != LINE_LENGTH) { 350 int j; 351 for (j = 0; j < i; j++) { 352 space[j * 2] = ' '; 353 space[j * 2 + 1] = ' '; 354 } 355 } 356 printf("%s%s%s%s", space, sp, string, nl); 357 } 358 359 /* dump a PKCS5/12 PBE blob */ 360 void 361 dumpPKCS(unsigned char *val, CK_ULONG len, PRBool *hasSig) 362 { 363 EncryptedDataInfo edi; 364 SECStatus rv; 365 SECItem data; 366 PLArenaPool *arena; 367 SECOidTag alg, prfAlg; 368 PBEParameter pbeParam; 369 unsigned char zero = 0; 370 const SEC_ASN1Template *template = pkcs5V1PBEParameterTemplate; 371 int iter, keyLen, i; 372 373 if (hasSig) { 374 *hasSig = PR_FALSE; 375 } 376 377 data.data = val; 378 data.len = len; 379 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); 380 if (arena == NULL) { 381 printf("Couldn't allocate arena\n"); 382 return; 383 } 384 385 /* initialize default values */ 386 PORT_Memset(&pbeParam, 0, sizeof(pbeParam)); 387 pbeParam.keyLength.data = &zero; 388 pbeParam.keyLength.len = sizeof(zero); 389 SECOID_SetAlgorithmID(arena, &pbeParam.prfAlg, SEC_OID_SHA1, NULL); 390 391 /* first crack the encrypted data from the PBE algorithm ID */ 392 rv = SEC_QuickDERDecodeItem(arena, &edi, encryptedDataInfoTemplate, &data); 393 if (rv != SECSuccess) { 394 printf("Encrypted Data, failed to decode\n"); 395 dumpValue(val, len); 396 PORT_FreeArena(arena, PR_FALSE); 397 return; 398 } 399 /* now use the pbe secalg to dump info on the pbe */ 400 alg = SECOID_GetAlgorithmTag(&edi.algorithm); 401 if ((alg == SEC_OID_PKCS5_PBES2) || (alg == SEC_OID_PKCS5_PBMAC1)) { 402 Pkcs5v2PBEParameter param; 403 SECOidTag palg; 404 const char *typeName = (alg == SEC_OID_PKCS5_PBES2) ? "Encrypted Data PBES2" : "Mac Data PBMAC1"; 405 406 rv = SEC_QuickDERDecodeItem(arena, ¶m, 407 pkcs5v2PBES2ParameterTemplate, 408 &edi.algorithm.parameters); 409 if (rv != SECSuccess) { 410 printf("%s, failed to decode\n", typeName); 411 dumpValue(val, len); 412 PORT_FreeArena(arena, PR_FALSE); 413 return; 414 } 415 palg = SECOID_GetAlgorithmTag(¶m.algParams); 416 printf("%s alg=%s ", typeName, oid2string(palg)); 417 if (hasSig && palg == SEC_OID_AES_256_CBC) { 418 *hasSig = PR_TRUE; 419 } 420 template = pkcs5V2PBEParameterTemplate; 421 edi.algorithm.parameters = param.keyParams.parameters; 422 } else { 423 printf("Encrypted Data alg=%s ", oid2string(alg)); 424 if (alg == SEC_OID_PKCS5_PBKDF2) { 425 template = pkcs5V2PBEParameterTemplate; 426 } else if (isPKCS12PBE(alg)) { 427 template = pkcs12V2PBEParameterTemplate; 428 } else { 429 template = pkcs5V1PBEParameterTemplate; 430 } 431 } 432 rv = SEC_QuickDERDecodeItem(arena, &pbeParam, 433 template, 434 &edi.algorithm.parameters); 435 if (rv != SECSuccess) { 436 printf("( failed to decode params)\n"); 437 PORT_FreeArena(arena, PR_FALSE); 438 return; 439 } 440 /* dump the pbe parmeters */ 441 iter = DER_GetInteger(&pbeParam.iteration); 442 keyLen = DER_GetInteger(&pbeParam.keyLength); 443 prfAlg = SECOID_GetAlgorithmTag(&pbeParam.prfAlg); 444 printf("(prf=%s iter=%d keyLen=%d salt=0x", 445 oid2string(prfAlg), iter, keyLen); 446 for (i = 0; i < pbeParam.salt.len; i++) 447 printf("%02x", pbeParam.salt.data[i]); 448 printf(")\n"); 449 /* finally dump the raw encrypted data */ 450 dumpValue(edi.encryptedData.data, edi.encryptedData.len); 451 PORT_FreeArena(arena, PR_FALSE); 452 } 453 454 /* dump a long attribute, convert to an unsigned long. PKCS #11 Longs are 455 * limited to 32 bits by the spec, even if the CK_ULONG is longer */ 456 void 457 dumpLongAttribute(CK_ATTRIBUTE_TYPE type, CK_ULONG value) 458 { 459 const char *nameType = "CK_NSS"; 460 ConstType constType = ConstNone; 461 const char *valueName = NULL; 462 463 switch (type) { 464 case CKA_CLASS: 465 nameType = "CKO_NSS"; 466 constType = ConstObject; 467 break; 468 case CKA_CERTIFICATE_TYPE: 469 nameType = "CKC_NSS"; 470 constType = ConstCertType; 471 break; 472 case CKA_KEY_TYPE: 473 nameType = "CKK_NSS"; 474 constType = ConstKeyType; 475 break; 476 case CKA_MECHANISM_TYPE: 477 case CKA_NAME_HASH_ALGORITHM: 478 nameType = "CKM_NSS"; 479 constType = ConstMechanism; 480 break; 481 case CKA_NSS_TRUST_SERVER_AUTH: 482 case CKA_NSS_TRUST_CLIENT_AUTH: 483 case CKA_NSS_TRUST_CODE_SIGNING: 484 case CKA_NSS_TRUST_EMAIL_PROTECTION: 485 case CKA_NSS_TRUST_IPSEC_END_SYSTEM: 486 case CKA_NSS_TRUST_IPSEC_TUNNEL: 487 case CKA_NSS_TRUST_IPSEC_USER: 488 case CKA_NSS_TRUST_TIME_STAMPING: 489 nameType = "CKT_NSS"; 490 constType = ConstTrust; 491 break; 492 case CKA_PKCS_TRUST_SERVER_AUTH: 493 case CKA_PKCS_TRUST_CLIENT_AUTH: 494 case CKA_PKCS_TRUST_CODE_SIGNING: 495 case CKA_PKCS_TRUST_EMAIL_PROTECTION: 496 case CKA_TRUST_IPSEC_IKE: 497 case CKA_PKCS_TRUST_TIME_STAMPING: 498 nameType = "CKT_"; 499 constType = ConstTrust; 500 break; 501 default: 502 break; 503 } 504 /* if value has a symbolic name, use it */ 505 if (constType != ConstNone) { 506 valueName = getName(value, constType); 507 } 508 if (!valueName) { 509 valueName = makeNSSVendorName(value, nameType); 510 } 511 if (!valueName) { 512 printf("%d (0x%08x)\n", (int)value, (int)value); 513 } else { 514 printf("%s (0x%08x)\n", valueName, (int)value); 515 } 516 } 517 518 /* dump a signature for an object */ 519 static const char META_SIG_TEMPLATE[] = "sig_%s_%08x_%08x"; 520 void 521 dumpSignature(CK_ATTRIBUTE_TYPE attribute, SDB *keydb, PRBool isKey, 522 CK_OBJECT_HANDLE objectID, PRBool force) 523 { 524 char id[30]; 525 CK_RV crv; 526 SECItem signText; 527 unsigned char signData[SDB_MAX_META_DATA_LEN]; 528 529 if (!force && !isAuthenticatedAttribute(attribute)) { 530 return; 531 } 532 snprintf(id, sizeof(id), META_SIG_TEMPLATE, 533 isKey ? "key" : "cert", 534 (unsigned int)objectID, (unsigned int)attribute); 535 printf(" Signature %s:", id); 536 signText.data = signData; 537 signText.len = sizeof(signData); 538 539 crv = (*keydb->sdb_GetMetaData)(keydb, id, &signText, NULL); 540 if ((crv != CKR_OK) && isKey) { 541 snprintf(id, sizeof(id), META_SIG_TEMPLATE, 542 isKey ? "key" : "cert", (unsigned int)(objectID | SFTK_KEYDB_TYPE | SFTK_TOKEN_TYPE), 543 (unsigned int)attribute); 544 crv = (*keydb->sdb_GetMetaData)(keydb, id, &signText, NULL); 545 } 546 if (crv != CKR_OK) { 547 printf(" FAILED %s with %s (0x%08x)\n", id, ErrorName(crv), (int)crv); 548 return; 549 } 550 dumpPKCS(signText.data, signText.len, NULL); 551 return; 552 } 553 554 /* dump an attribute. use the helper functions above */ 555 void 556 dumpAttribute(CK_ATTRIBUTE *template, SDB *keydb, PRBool isKey, 557 CK_OBJECT_HANDLE id) 558 { 559 CK_ATTRIBUTE_TYPE attribute = template->type; 560 printf(" %s(0x%08x): ", AttributeName(attribute), (int)attribute); 561 if (template->pValue == NULL) { 562 printf("NULL (%d)\n", (int)template->ulValueLen); 563 return; 564 } 565 if (template->ulValueLen == SDB_ULONG_SIZE && isULONGAttribute(attribute)) { 566 CK_ULONG value = sdbULong2ULong(template->pValue); 567 dumpLongAttribute(attribute, value); 568 return; 569 } 570 if (template->ulValueLen == 1) { 571 unsigned char val = *(unsigned char *)template->pValue; 572 switch (val) { 573 case 0: 574 printf("CK_FALSE\n"); 575 break; 576 case 1: 577 printf("CK_TRUE\n"); 578 break; 579 default: 580 printf("%d 0x%02x %c\n", val, val, ASCCHAR(val)); 581 break; 582 } 583 return; 584 } 585 if (isKey && isPrivateAttribute(attribute)) { 586 PRBool hasSig = PR_FALSE; 587 dumpPKCS(template->pValue, template->ulValueLen, &hasSig); 588 if (hasSig) { 589 dumpSignature(attribute, keydb, isKey, id, PR_TRUE); 590 } 591 return; 592 } 593 if (template->ulValueLen == 0) { 594 printf("empty"); 595 } 596 printf("\n"); 597 dumpValue(template->pValue, template->ulValueLen); 598 } 599 600 /* dump all the attributes in an object */ 601 void 602 dumpObject(CK_OBJECT_HANDLE id, SDB *db, SDB *keydb, PRBool isKey) 603 { 604 CK_RV crv; 605 size_t i; 606 CK_ATTRIBUTE template; 607 char buffer[2048]; 608 char *alloc = NULL; 609 610 printf(" Object 0x%08x:\n", (int)id); 611 for (i = 0; i < sftkdb_known_attributes_size; i++) { 612 CK_ATTRIBUTE_TYPE attribute = sftkdb_known_attributes[i]; 613 template.type = attribute; 614 template.pValue = NULL; 615 template.ulValueLen = 0; 616 crv = (*db->sdb_GetAttributeValue)(db, id, &template, 1); 617 618 if (crv != CKR_OK) { 619 if (crv != CKR_ATTRIBUTE_TYPE_INVALID) { 620 PR_fprintf(PR_STDERR, " " 621 "Get Attribute %s (0x%08x):FAILED\"%s\"(0x%08x)\n", 622 AttributeName(attribute), (int)attribute, 623 ErrorName(crv), (int)crv); 624 } 625 continue; 626 } 627 628 if (template.ulValueLen < sizeof(buffer)) { 629 template.pValue = buffer; 630 } else { 631 alloc = PORT_Alloc(template.ulValueLen); 632 template.pValue = alloc; 633 } 634 if (template.pValue == NULL) { 635 PR_fprintf(PR_STDERR, " " 636 "Could allocate %d bytes for Attribute %s (0x%08x)\n", 637 (int)template.ulValueLen, 638 AttributeName(attribute), (int)attribute); 639 continue; 640 } 641 crv = (*db->sdb_GetAttributeValue)(db, id, &template, 1); 642 643 if (crv != CKR_OK) { 644 if (crv != CKR_ATTRIBUTE_TYPE_INVALID) { 645 PR_fprintf(PR_STDERR, " " 646 "Get Attribute %s (0x%08x):FAILED\"%s\"(0x%08x)\n", 647 AttributeName(attribute), (int)attribute, 648 ErrorName(crv), (int)crv); 649 } 650 if (alloc) { 651 PORT_Free(alloc); 652 alloc = NULL; 653 } 654 continue; 655 } 656 657 dumpAttribute(&template, keydb, isKey, id); 658 dumpSignature(template.type, keydb, isKey, id, PR_FALSE); 659 if (alloc) { 660 PORT_Free(alloc); 661 alloc = NULL; 662 } 663 } 664 } 665 666 /* dump all the objects in a database */ 667 void 668 dumpDB(SDB *db, const char *name, SDB *keydb, PRBool isKey) 669 { 670 SDBFind *findHandle = NULL; 671 CK_BBOOL isTrue = 1; 672 CK_ATTRIBUTE allObjectTemplate = { CKA_TOKEN, NULL, 1 }; 673 CK_ULONG allObjectTemplateCount = 1; 674 PRBool recordFound = PR_FALSE; 675 CK_RV crv = CKR_OK; 676 CK_ULONG objectCount = 0; 677 printf("%s:\n", name); 678 679 allObjectTemplate.pValue = &isTrue; 680 crv = (*db->sdb_FindObjectsInit)(db, &allObjectTemplate, 681 allObjectTemplateCount, &findHandle); 682 do { 683 CK_OBJECT_HANDLE id; 684 recordFound = PR_FALSE; 685 crv = (*db->sdb_FindObjects)(db, findHandle, &id, 1, &objectCount); 686 if ((crv == CKR_OK) && (objectCount == 1)) { 687 recordFound = PR_TRUE; 688 dumpObject(id, db, keydb, isKey); 689 } 690 } while (recordFound); 691 if (crv != CKR_OK) { 692 PR_fprintf(PR_STDERR, 693 "Last record return PKCS #11 error = %s (0x%08x)\n", 694 ErrorName(crv), (int)crv); 695 } 696 (*db->sdb_FindObjectsFinal)(db, findHandle); 697 } 698 699 static char * 700 secu_ConfigDirectory(const char *base) 701 { 702 static PRBool initted = PR_FALSE; 703 const char *dir = ".netscape"; 704 char *home; 705 static char buf[1000]; 706 707 if (initted) 708 return buf; 709 710 if (base == NULL || *base == 0) { 711 home = PR_GetEnvSecure("HOME"); 712 if (!home) 713 home = ""; 714 715 if (*home && home[strlen(home) - 1] == '/') 716 snprintf(buf, sizeof(buf), "%.900s%s", home, dir); 717 else 718 snprintf(buf, sizeof(buf), "%.900s/%s", home, dir); 719 } else { 720 snprintf(buf, sizeof(buf), "%.900s", base); 721 if (buf[strlen(buf) - 1] == '/') 722 buf[strlen(buf) - 1] = 0; 723 } 724 725 initted = PR_TRUE; 726 return buf; 727 } 728 729 int 730 main(int argc, char **argv) 731 { 732 PLOptState *optstate; 733 PLOptStatus optstatus; 734 char *certPrefix = "", *keyPrefix = ""; 735 int cert_version = 9; 736 int key_version = 4; 737 SDB *certdb = NULL; 738 SDB *keydb = NULL; 739 PRBool isNew = PR_FALSE; 740 741 CK_RV crv; 742 743 progName = strrchr(argv[0], '/'); 744 if (!progName) 745 progName = strrchr(argv[0], '\\'); 746 progName = progName ? progName + 1 : argv[0]; 747 748 optstate = PL_CreateOptState(argc, argv, "d:c:k:v:V:h"); 749 750 while ((optstatus = PL_GetNextOpt(optstate)) == PL_OPT_OK) { 751 switch (optstate->option) { 752 case 'h': 753 default: 754 Usage(); 755 break; 756 757 case 'd': 758 dbDir = PORT_Strdup(optstate->value); 759 break; 760 761 case 'c': 762 certPrefix = PORT_Strdup(optstate->value); 763 break; 764 765 case 'k': 766 keyPrefix = PORT_Strdup(optstate->value); 767 break; 768 769 case 'v': 770 key_version = atoi(optstate->value); 771 break; 772 773 case 'V': 774 cert_version = atoi(optstate->value); 775 break; 776 } 777 } 778 PL_DestroyOptState(optstate); 779 if (optstatus == PL_OPT_BAD) 780 Usage(); 781 782 if (dbDir) { 783 char *tmp = dbDir; 784 dbDir = secu_ConfigDirectory(tmp); 785 PORT_Free(tmp); 786 } else { 787 dbDir = secu_ConfigDirectory(NULL); 788 } 789 PR_fprintf(PR_STDERR, "dbdir selected is %s\n\n", dbDir); 790 791 if (dbDir[0] == '\0') { 792 PR_fprintf(PR_STDERR, 793 "ERROR: Directory \"%s\" does not exist.\n", dbDir); 794 return 1; 795 } 796 797 PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); 798 SECOID_Init(); 799 800 crv = s_open(dbDir, certPrefix, keyPrefix, cert_version, key_version, 801 SDB_RDONLY, &certdb, &keydb, &isNew); 802 if (crv != CKR_OK) { 803 PR_fprintf(PR_STDERR, 804 "Couldn't open databased in %s, error=%s (0x%08x)\n", 805 dbDir, ErrorName(crv), (int)crv); 806 return 1; 807 } 808 809 /* now dump the objects in the cert database */ 810 dumpDB(certdb, "CertDB", keydb, PR_FALSE); 811 dumpDB(keydb, "KeyDB", keydb, PR_TRUE); 812 813 crv = sdb_Close(certdb); 814 if (crv != CKR_OK) { 815 PR_fprintf(PR_STDERR, 816 "Couldn't close cert database in %s, error=%s (0x%08x)\n", 817 dbDir, ErrorName(crv), (int)crv); 818 } 819 820 crv = sdb_Close(keydb); 821 if (crv != CKR_OK) { 822 PR_fprintf(PR_STDERR, 823 "Couldn't close key database in %s, error=%s (0x%08x)\n", 824 dbDir, ErrorName(crv), (int)crv); 825 } 826 827 crv = s_shutdown(); 828 if (crv != CKR_OK) { 829 PR_fprintf(PR_STDERR, 830 "Error in s_shutdown, error=%s (0x%08x)\n", 831 ErrorName(crv), (int)crv); 832 } 833 return 0; 834 }