1/* 2 * grunt-quality p12 parse tool. 3 * 4 * The PFX ripper in this file uses, and always will use, the 5 * app-space reference PBE and crypto routines in p12Crypto.{h,cpp} 6 * and p12pbe.{h,cpp} in this directory. 7 */ 8#include "p12Parse.h" 9#include "p12Crypto.h" 10#include "pkcs12Parsed.h" 11#include "pkcs12Utils.h" 12#include <Security/asn1Templates.h> 13#include <security_asn1/nssUtils.h> 14#include <security_asn1/SecNssCoder.h> 15#include <security_cdsa_utils/cuOidParser.h> 16#include <security_cdsa_utils/cuPrintCert.h> 17#include <security_pkcs12/pkcs7Templates.h> 18#include <security_pkcs12/pkcs12Templates.h> 19#include <security_cdsa_utils/cuFileIo.h> 20#include <stdlib.h> 21#include <stdio.h> 22#include <string.h> 23#include <CoreFoundation/CoreFoundation.h> 24#include <security_cdsa_utils/cuCdsaUtils.h> 25#include <Security/oidsattr.h> 26#include <stdexcept> 27 28/* 29 * The stuff which gets passed around to all parse modules 30 */ 31class P12ParseInfo 32{ 33public: 34 P12ParseInfo(SecNssCoder &coder, 35 CSSM_CSP_HANDLE cspHand, 36 OidParser &parser, 37 /* NULL means don't verify MAC, don't decrypt */ 38 CFStringRef macPwd, 39 /* if this second pwd is absent, use macPwd for both */ 40 CFStringRef encrPwd, 41 P12Parsed &parsed) // destination 42 : mCoder(coder), 43 mCspHand(cspHand), 44 mParser(parser), 45 mParsed(parsed) 46 { 47 importPwd(macPwd, mPwd); 48 importPwd(encrPwd, mEncrPwd); 49 } 50 51 ~P12ParseInfo() {} 52 53 void importPwd(CFStringRef str, CSSM_DATA &pwd); 54 55 SecNssCoder &mCoder; 56 CSSM_CSP_HANDLE mCspHand; 57 OidParser &mParser; 58 CSSM_DATA mPwd; // unicode, double null terminated 59 CSSM_DATA mEncrPwd; 60 P12Parsed &mParsed; // destination 61 62}; 63 64void P12ParseInfo::importPwd( 65 CFStringRef str, 66 CSSM_DATA &pwd) 67{ 68 if(str == NULL) { 69 pwd.Data = NULL; 70 pwd.Length = 0; 71 return; 72 } 73 CFDataRef cfData = CFStringCreateExternalRepresentation(NULL, 74 str, kCFStringEncodingUTF8, 0); 75 if(cfData == NULL) { 76 printf("***p12ImportPassPhrase: can't convert passphrase to UTF8\n"); 77 throw std::invalid_argument("bad passphrase"); 78 } 79 unsigned keyLen = CFDataGetLength(cfData); 80 mCoder.allocItem(pwd, keyLen); 81 memmove(pwd.Data, CFDataGetBytePtr(cfData), keyLen); 82 CFRelease(cfData); 83} 84 85static void doIndent(unsigned depth) 86{ 87 for(unsigned i=0; i<depth; i++) { 88 putchar(' '); 89 } 90} 91 92/* thread-unsafe oid-to-string converter */ 93static char oidStrBuf[OID_PARSER_STRING_SIZE]; 94 95static const char *oidStr( 96 const CSSM_OID &oid, 97 OidParser &parser) 98{ 99 parser.oidParse(oid.Data, oid.Length, oidStrBuf); 100 return oidStrBuf; 101} 102 103static void printDataAsHex( 104 const CSSM_DATA *d, 105 unsigned maxToPrint = 0) // optional, 0 means print it all 106{ 107 unsigned i; 108 bool more = false; 109 uint32 len = d->Length; 110 uint8 *cp = d->Data; 111 112 if((maxToPrint != 0) && (len > maxToPrint)) { 113 len = maxToPrint; 114 more = true; 115 } 116 printf("len %lu : ", d->Length); 117 for(i=0; i<len; i++) { 118 printf("%02X ", ((unsigned char *)cp)[i]); 119 } 120 if(more) { 121 printf("...\n"); 122 } 123 else { 124 printf("\n"); 125 } 126} 127 128static void printDataAsUnichars( 129 const CSSM_DATA &data) 130{ 131 if(data.Length & 1) { 132 printf("Unicode can not have odd number of bytes\n"); 133 return; 134 } 135 /* don't assume anything endian... */ 136 unsigned strLen = data.Length / 2; 137 UniChar *uc = (UniChar *)malloc(strLen * sizeof(UniChar)); 138 const uint8 *inp = data.Data; 139 UniChar *outp = uc; 140 while(inp < (data.Data + data.Length)) { 141 *outp = (((unsigned)inp[0]) << 8) | inp[1]; 142 outp++; 143 inp += 2; 144 } 145 char *outStr = NULL; 146 CFStringRef cstr = CFStringCreateWithCharacters(NULL, uc, strLen); 147 if(cstr == NULL) { 148 printf("***Error creating CFString from unichars\n"); 149 goto errOut; 150 } 151 152 outStr = (char *)malloc(strLen + 1); 153 if(CFStringGetCString(cstr, outStr, strLen + 1, kCFStringEncodingASCII)) { 154 printf("%s\n", outStr); 155 } 156 else { 157 printf("***Error converting from unicode to ASCII\n"); 158 } 159errOut: 160 free(uc); 161 if(outStr) { 162 free(outStr); 163 } 164 CFRelease(cstr); 165 return; 166} 167 168uint32 dataToInt( 169 const CSSM_DATA &cdata) 170{ 171 if((cdata.Length == 0) || (cdata.Data == NULL)) { 172 return 0; 173 } 174 uint32 len = cdata.Length; 175 if(len > sizeof(uint32)) { 176 printf("***Bad formatting for DER integer\n"); 177 len = sizeof(uint32); 178 } 179 180 uint32 rtn = 0; 181 uint8 *cp = cdata.Data; 182 for(uint32 i=0; i<len; i++) { 183 rtn = (rtn << 8) | *cp++; 184 } 185 return rtn; 186} 187 188#ifdef old_and_in_the_way 189static int writeAuthSafeContent( 190 const CSSM_DATA &rawBlob, 191 const char *outFile, 192 SecNssCoder &coder, 193 OidParser &parser) 194{ 195 NSS_P12_RawPFX pfx; 196 memset(&pfx, 0, sizeof(pfx)); 197 if(coder.decodeItem(rawBlob, NSS_P12_RawPFXTemplate, &pfx)) { 198 printf("***Error on top-level decode of NSS_P12_RawPFX\n"); 199 return 1; 200 } 201 printf("...version = %u\n", (unsigned)dataToInt(pfx.version)); 202 NSS_P7_RawContentInfo &rci = pfx.authSafe; 203 printf("...contentType = %s\n", oidStr(rci.contentType, parser)); 204 205 /* parse content per OID the only special case is PKCS7_Data, 206 * which we unwrap from an octet string before writing it */ 207 CSSM_DATA toWrite; 208 if(nssCompareCssmData(&rci.contentType, &CSSMOID_PKCS7_Data)) { 209 if(coder.decodeItem(rci.content, SEC_OctetStringTemplate, 210 &toWrite)) { 211 printf("***Error decoding PKCS7_Data Octet string; writing" 212 " raw contents\n"); 213 toWrite = rci.content; 214 } 215 } 216 else if(nssCompareCssmData(&rci.contentType, 217 &CSSMOID_PKCS7_SignedData)) { 218 /* the only other legal content type here */ 219 /* This is encoded SignedData which I am not even close 220 * to worrying about - Panther p12 won't do this */ 221 toWrite = rci.content; 222 } 223 else { 224 printf("***writeAuthSafeContent: bad contentType\n"); 225 return 1; 226 } 227 if(writeFile(outFile, toWrite.Data, toWrite.Length)) { 228 printf("***Error writing to %s\n", outFile); 229 return 1; 230 } 231 else { 232 printf("...%u bytes written to %s\n", 233 (unsigned)toWrite.Length, outFile); 234 return 0; 235 } 236} 237#endif /* old_and_in_the_way */ 238 239/* 240 * Decrypt the contents of a NSS_P7_EncryptedData 241 */ 242#define WRITE_DECRYPT_TEXT 0 243#if WRITE_DECRYPT_TEXT 244static int ctr = 0; 245#endif 246 247#define IMPORT_EXPORT_COMPLETE 1 248 249static int encryptedDataDecrypt( 250 const NSS_P7_EncryptedData &edata, 251 P12ParseInfo &pinfo, 252 NSS_P12_PBE_Params *pbep, // preparsed 253 CSSM_DATA &ptext) // result goes here in pinfo.coder space 254{ 255 /* see if we can grok the encr alg */ 256 CSSM_ALGORITHMS keyAlg; // e.g., CSSM_ALGID_DES 257 CSSM_ALGORITHMS encrAlg; // e.g., CSSM_ALGID_3DES_3KEY_EDE 258 CSSM_ALGORITHMS pbeHashAlg; // SHA1 or MD5 259 uint32 keySizeInBits; 260 uint32 blockSizeInBytes; // for IV, optional 261 CSSM_PADDING padding; // CSSM_PADDING_PKCS7, etc. 262 CSSM_ENCRYPT_MODE mode; // CSSM_ALGMODE_CBCPadIV8, etc. 263 #if IMPORT_EXPORT_COMPLETE 264 PKCS_Which pkcs; 265 266 bool found = pkcsOidToParams(&edata.contentInfo.encrAlg.algorithm, 267 keyAlg, encrAlg, pbeHashAlg, keySizeInBits, blockSizeInBytes, 268 padding, mode, pkcs); 269 #else 270 bool found = pkcsOidToParams(&edata.contentInfo.encrAlg.algorithm, 271 keyAlg, encrAlg, pbeHashAlg, keySizeInBits, blockSizeInBytes, 272 padding, mode); 273 #endif /* IMPORT_EXPORT_COMPLETE */ 274 275 if(!found) { 276 printf("***EncryptedData encrAlg not understood\n"); 277 return 1; 278 } 279 280 unsigned iterCount = dataToInt(pbep->iterations); 281 282 /* go */ 283 CSSM_RETURN crtn = p12Decrypt_app(pinfo.mCspHand, 284 edata.contentInfo.encrContent, 285 keyAlg, encrAlg, pbeHashAlg, 286 keySizeInBits, blockSizeInBytes, 287 padding, mode, 288 iterCount, pbep->salt, 289 pinfo.mPwd, 290 pinfo.mCoder, 291 ptext); 292 #if WRITE_DECRYPT_TEXT 293 if(crtn == 0) { 294 char fname[100]; 295 sprintf(fname, "decrypt%d.der", ctr++); 296 writeFile(fname, ptext.Data, ptext.Length); 297 printf("...wrote %u bytes to %s\n", 298 (unsigned)ptext.Length, fname); 299 } 300 #endif 301 return crtn ? 1 : 0; 302 303} 304 305 306/* 307 * Parse an CSSM_X509_ALGORITHM_IDENTIFIER specific to P12. 308 * Decode the alg params as a NSS_P12_PBE_Params and parse and 309 * return the result if the pbeParams is non-NULL. 310 */ 311static int p12AlgIdParse( 312 const CSSM_X509_ALGORITHM_IDENTIFIER &algId, 313 NSS_P12_PBE_Params *pbeParams, // optional 314 P12ParseInfo &pinfo, 315 unsigned depth) // print indent depth 316{ 317 doIndent(depth); 318 printf("encrAlg = %s\n", oidStr(algId.algorithm, pinfo.mParser)); 319 const CSSM_DATA ¶m = algId.parameters; 320 if(pbeParams == NULL) { 321 /* alg params are uninterpreted */ 322 doIndent(depth); 323 printf("Alg Params : "); 324 printDataAsHex(¶m); 325 return 0; 326 } 327 328 if(param.Length == 0) { 329 printf("===warning: no alg parameters, this is not optional\n"); 330 return 0; 331 } 332 333 memset(pbeParams, 0, sizeof(*pbeParams)); 334 if(pinfo.mCoder.decodeItem(param, 335 NSS_P12_PBE_ParamsTemplate, pbeParams)) { 336 printf("***Error decoding NSS_P12_PBE_Params\n"); 337 return 1; 338 } 339 doIndent(depth); 340 printf("Salt : "); 341 printDataAsHex(&pbeParams->salt); 342 doIndent(depth); 343 if(pbeParams->iterations.Length > 4) { 344 printf("warning: iterations greater than max int\n"); 345 doIndent(depth); 346 printf("Iterations : "); 347 printDataAsHex(&pbeParams->iterations); 348 } 349 else { 350 printf("Iterations : %u\n", 351 (unsigned)dataToInt(pbeParams->iterations)); 352 } 353 return 0; 354} 355 356/* 357 * Parse a NSS_P7_EncryptedData - specifically in the context 358 * of a P12 in password privacy mode. (The latter assumption is 359 * to enable us to infer CSSM_X509_ALGORITHM_IDENTIFIER.parameters 360 * format). 361 */ 362static int encryptedDataParse( 363 const NSS_P7_EncryptedData &edata, 364 P12ParseInfo &pinfo, 365 NSS_P12_PBE_Params *pbep, // optional, RETURNED 366 unsigned depth) // print indent depth 367{ 368 doIndent(depth); 369 printf("version = %u\n", (unsigned)dataToInt(edata.version)); 370 const NSS_P7_EncrContentInfo &ci = edata.contentInfo; 371 doIndent(depth); 372 printf("contentType = %s\n", oidStr(ci.contentType, pinfo.mParser)); 373 374 /* 375 * Parse the alg ID, safe PBE params for when we do the 376 * key unwrap 377 */ 378 const CSSM_X509_ALGORITHM_IDENTIFIER &algId = ci.encrAlg; 379 if(p12AlgIdParse(algId, pbep, pinfo, depth)) { 380 return 1; 381 } 382 383 doIndent(depth); 384 printf("encrContent : "); 385 printDataAsHex(&ci.encrContent, 12); 386 return 0; 387} 388 389static int attrParse( 390 const NSS_Attribute *attr, 391 P12ParseInfo &pinfo, 392 unsigned depth) 393{ 394 doIndent(depth); 395 printf("attrType : %s\n", oidStr(attr->attrType, pinfo.mParser)); 396 unsigned numVals = nssArraySize((const void **)attr->attrValue); 397 doIndent(depth); 398 printf("numValues = %u\n", numVals); 399 400 for(unsigned dex=0; dex<numVals; dex++) { 401 doIndent(depth); 402 printf("val[%u] : ", dex); 403 404 /* 405 * Note: these two enumerated types should only have one att value 406 * per PKCS9. Leave that to real apps, we want to see what's there 407 * in any case. 408 */ 409 if(nssCompareCssmData(&attr->attrType, &CSSMOID_PKCS9_FriendlyName)) { 410 /* BMP string (UniCode) */ 411 CSSM_DATA ustr; 412 if(pinfo.mCoder.decodeItem(*attr->attrValue[dex], 413 kSecAsn1BMPStringTemplate, &ustr)) { 414 printf("***Error decoding BMP string\n"); 415 continue; 416 } 417 printDataAsUnichars(ustr); 418 } 419 else if(nssCompareCssmData(&attr->attrType, 420 &CSSMOID_PKCS9_LocalKeyId)) { 421 /* Octet string */ 422 CSSM_DATA ostr; 423 if(pinfo.mCoder.decodeItem(*attr->attrValue[dex], 424 kSecAsn1OctetStringTemplate, &ostr)) { 425 printf("***Error decoding LocalKeyId string\n"); 426 continue; 427 } 428 printDataAsHex(&ostr, 16); 429 } 430 else { 431 printDataAsHex(attr->attrValue[dex], 8); 432 } 433 } 434 return 0; 435} 436 437/* 438 * ShroudedKeyBag parser w/decrypt 439 */ 440static int shroudedKeyBagParse( 441 const NSS_P12_ShroudedKeyBag *keyBag, 442 P12ParseInfo &pinfo, 443 unsigned depth) 444{ 445 const CSSM_X509_ALGORITHM_IDENTIFIER &algId = keyBag->algorithm; 446 NSS_P12_PBE_Params pbep; 447 if(p12AlgIdParse(algId, &pbep, pinfo, depth)) { 448 return 1; 449 } 450 if(pinfo.mPwd.Data == NULL) { 451 doIndent(depth); 452 printf("=== Key not decrypted (no passphrase)===\n"); 453 return 0; 454 } 455 456 /* 457 * Prepare for decryption 458 */ 459 CSSM_ALGORITHMS keyAlg; // e.g., CSSM_ALGID_DES 460 CSSM_ALGORITHMS encrAlg; // e.g., CSSM_ALGID_3DES_3KEY_EDE 461 CSSM_ALGORITHMS pbeHashAlg; // SHA1 or MD5 462 uint32 keySizeInBits; 463 uint32 blockSizeInBytes; // for IV, optional 464 CSSM_PADDING padding; // CSSM_PADDING_PKCS7, etc. 465 CSSM_ENCRYPT_MODE mode; // CSSM_ALGMODE_CBCPadIV8, etc. 466 #if IMPORT_EXPORT_COMPLETE 467 PKCS_Which pkcs; 468 469 bool found = pkcsOidToParams(&algId.algorithm, 470 keyAlg, encrAlg, pbeHashAlg, keySizeInBits, blockSizeInBytes, 471 padding, mode, pkcs); 472 #else 473 bool found = pkcsOidToParams(&algId.algorithm, 474 keyAlg, encrAlg, pbeHashAlg, keySizeInBits, blockSizeInBytes, 475 padding, mode); 476 #endif 477 478 if(!found) { 479 printf("***ShroudedKeyBag encrAlg not understood\n"); 480 return 1; 481 } 482 483 unsigned iterCount = dataToInt(pbep.iterations); 484 CSSM_DATA berPrivKey; 485 486 /* decrypt, result is BER encoded private key */ 487 CSSM_RETURN crtn = p12Decrypt_app(pinfo.mCspHand, 488 keyBag->encryptedData, 489 keyAlg, encrAlg, pbeHashAlg, 490 keySizeInBits, blockSizeInBytes, 491 padding, mode, 492 iterCount, pbep.salt, 493 pinfo.mPwd, 494 pinfo.mCoder, 495 berPrivKey); 496 if(crtn) { 497 doIndent(depth); 498 printf("***Error decrypting private key\n"); 499 return 1; 500 } 501 502 /* decode */ 503 NSS_PrivateKeyInfo privKey; 504 memset(&privKey, 0, sizeof(privKey)); 505 if(pinfo.mCoder.decodeItem(berPrivKey, 506 kSecAsn1PrivateKeyInfoTemplate, &privKey)) { 507 doIndent(depth); 508 printf("***Error decoding decrypted private key\n"); 509 return 1; 510 } 511 512 /* 513 * in P12 library, we'd convert the result into a CSSM_KEY 514 * or a SecItem... 515 */ 516 CSSM_X509_ALGORITHM_IDENTIFIER &privAlg = privKey.algorithm; 517 doIndent(depth); 518 printf("Priv Key Alg : %s\n", oidStr(privAlg.algorithm, pinfo.mParser)); 519 doIndent(depth); 520 printf("Priv Key Blob : "); 521 printDataAsHex(&privKey.privateKey, 16); 522 523 unsigned numAttrs = nssArraySize((const void**)privKey.attributes); 524 if(numAttrs) { 525 doIndent(depth+3); 526 printf("numAttrs = %u\n", numAttrs); 527 for(unsigned i=0; i<numAttrs; i++) { 528 doIndent(depth+3); 529 printf("attr[%u]:\n", i); 530 attrParse(privKey.attributes[i], pinfo, depth+6); 531 } 532 } 533 return 0; 534} 535 536/* 537 * CertBag parser 538 */ 539static int certBagParse( 540 const NSS_P12_CertBag *certBag, 541 P12ParseInfo &pinfo, 542 unsigned depth) 543{ 544 /* fixe - we really need to store the attrs along with the cert here! */ 545 switch(certBag->type) { 546 case CT_X509: 547 doIndent(depth); 548 printf("X509 cert found, size %u\n", 549 (unsigned)certBag->certValue.Length); 550 pinfo.mParsed.mCerts.addBlob(certBag->certValue); 551 break; 552 default: 553 doIndent(depth); 554 printf("Unknown cert type found\n"); 555 P12UnknownBlob *uk = new P12UnknownBlob(certBag->certValue, 556 certBag->bagType); 557 pinfo.mParsed.mUnknown.addBlob(uk); 558 } 559 return 0; 560} 561 562/* 563 * CrlBag parser 564 */ 565static int crlBagParse( 566 const NSS_P12_CrlBag *crlBag, 567 P12ParseInfo &pinfo, 568 unsigned depth) 569{ 570 /* fixe - we really need to store the attrs along with the crl here! */ 571 switch(crlBag->type) { 572 case CRT_X509: 573 doIndent(depth); 574 printf("X509 CRL found, size %u\n", 575 (unsigned)crlBag->crlValue.Length); 576 pinfo.mParsed.mCrls.addBlob(crlBag->crlValue); 577 break; 578 default: 579 doIndent(depth); 580 printf("Unknown CRL type found\n"); 581 P12UnknownBlob *uk = new P12UnknownBlob(crlBag->crlValue, 582 crlBag->bagType); 583 pinfo.mParsed.mUnknown.addBlob(uk); 584 } 585 return 0; 586} 587 588 589/* 590 * Parse an encoded NSS_P12_SafeContents. This could be either 591 * present as plaintext in an AuthSafe or decrypted. 592 */ 593static int safeContentsParse( 594 const CSSM_DATA &contentsBlob, 595 P12ParseInfo &pinfo, 596 unsigned depth) // print indent depth 597{ 598 NSS_P12_SafeContents sc; 599 memset(&sc, 0, sizeof(sc)); 600 if(pinfo.mCoder.decodeItem(contentsBlob, NSS_P12_SafeContentsTemplate, 601 &sc)) { 602 printf("***Error decoding SafeContents\n"); 603 return 1; 604 } 605 unsigned numBags = nssArraySize((const void **)sc.bags); 606 doIndent(depth); 607 printf("SafeContents num bags %u\n", numBags); 608 int rtn = 0; 609 610 for(unsigned dex=0; dex<numBags; dex++) { 611 NSS_P12_SafeBag *bag = sc.bags[dex]; 612 doIndent(depth); 613 printf("Bag %u:\n", dex); 614 615 /* common stuff here */ 616 doIndent(depth+3); 617 printf("bagId = %s\n", oidStr(bag->bagId, pinfo.mParser)); 618 doIndent(depth+3); 619 printf("type = %s\n", p12BagTypeStr(bag->type)); 620 unsigned numAttrs = nssArraySize((const void**)bag->bagAttrs); 621 if(numAttrs) { 622 doIndent(depth+3); 623 printf("numAttrs = %u\n", numAttrs); 624 for(unsigned i=0; i<numAttrs; i++) { 625 doIndent(depth+3); 626 printf("attr[%u]:\n", i); 627 attrParse(bag->bagAttrs[i], pinfo, depth+6); 628 } 629 } 630 631 /* 632 * Now break out to individual bag type 633 * 634 * This hacked line breaks when we have a real key bag defined 635 */ 636 unsigned defaultLen = (unsigned)bag->bagValue.keyBag->Length; 637 switch(bag->type) { 638 case BT_KeyBag: 639 doIndent(depth+3); 640 printf("KeyBag: size %u\n", defaultLen); 641 break; 642 case BT_ShroudedKeyBag: 643 doIndent(depth+3); 644 printf("ShroudedKeyBag:\n"); 645 rtn = shroudedKeyBagParse(bag->bagValue.shroudedKeyBag, 646 pinfo, 647 depth+6); 648 break; 649 case BT_CertBag: 650 doIndent(depth+3); 651 printf("CertBag:\n"); 652 rtn = certBagParse(bag->bagValue.certBag, 653 pinfo, 654 depth+6); 655 break; 656 case BT_CrlBag: 657 doIndent(depth+3); 658 printf("CrlBag:\n"); 659 rtn = crlBagParse(bag->bagValue.crlBag, 660 pinfo, 661 depth+6); 662 break; 663 case BT_SecretBag: 664 doIndent(depth+3); 665 printf("SecretBag: size %u\n", defaultLen); 666 break; 667 case BT_SafeContentsBag: 668 doIndent(depth+3); 669 printf("SafeContentsBag: size %u\n", defaultLen); 670 break; 671 default: 672 doIndent(depth+3); 673 printf("===Warning: unknownBagType (%u)\n", 674 (unsigned)bag->type); 675 break; 676 } 677 if(rtn) { 678 break; 679 } 680 } 681 return rtn; 682} 683 684/* 685 * Parse a ContentInfo in the context of (i.e., as an element of) 686 * an element in a AuthenticatedSafe 687 */ 688static int authSafeElementParse( 689 const NSS_P7_DecodedContentInfo *info, 690 P12ParseInfo &pinfo, 691 unsigned depth) // print indent depth 692{ 693 char oidStr[OID_PARSER_STRING_SIZE]; 694 pinfo.mParser.oidParse(info->contentType.Data, 695 info->contentType.Length, oidStr); 696 697 doIndent(depth); 698 printf("contentType = %s\n", oidStr); 699 doIndent(depth); 700 printf("type = %s\n", p7ContentInfoTypeStr(info->type)); 701 int rtn = 0; 702 switch(info->type) { 703 case CT_Data: 704 /* unencrypted SafeContents */ 705 doIndent(depth); 706 printf("raw size: %u\n", 707 (unsigned)info->content.data->Length); 708 doIndent(depth); 709 printf("Plaintext SafeContents:\n"); 710 rtn = safeContentsParse(*info->content.data, 711 pinfo, depth+3); 712 break; 713 714 case CT_EncryptedData: 715 { 716 doIndent(depth); 717 printf("EncryptedData:\n"); 718 NSS_P12_PBE_Params pbep; 719 rtn = encryptedDataParse(*info->content.encryptData, 720 pinfo, &pbep, depth+3); 721 if(rtn) { 722 break; 723 } 724 if(pinfo.mPwd.Data == NULL) { 725 doIndent(depth+3); 726 printf("=== Contents not decrypted (no passphrase)===\n"); 727 } 728 else { 729 /* 730 * Decrypt contents to get a SafeContents and 731 * then parse that. 732 */ 733 CSSM_DATA ptext = {0, NULL}; 734 rtn = encryptedDataDecrypt(*info->content.encryptData, 735 pinfo, &pbep, ptext); 736 doIndent(depth); 737 if(rtn) { 738 printf("***Error decrypting CT_EncryptedData\n"); 739 break; 740 } 741 printf("Decrypted SafeContents {\n"); 742 rtn = safeContentsParse(ptext, pinfo, depth+3); 743 doIndent(depth); 744 printf("}\n"); 745 } 746 break; 747 } 748 default: 749 /* the rest map to an ASN_ANY/CSSM_DATA for now */ 750 doIndent(depth+3); 751 printf("size of %u is all we know today\n", 752 (unsigned)info->content.data->Length); 753 rtn = 0; 754 break; 755 } 756 return rtn; 757} 758 759/* 760 * Parse an encoded NSS_P12_AuthenticatedSafe 761 */ 762static int authSafeParse( 763 const CSSM_DATA authSafeBlob, 764 P12ParseInfo &pinfo, 765 unsigned depth) // print indent depth 766{ 767 NSS_P12_AuthenticatedSafe authSafe; 768 769 memset(&authSafe, 0, sizeof(authSafe)); 770 if(pinfo.mCoder.decodeItem(authSafeBlob, 771 NSS_P12_AuthenticatedSafeTemplate, 772 &authSafe)) { 773 printf("***Error decoding authSafe\n"); 774 return 1; 775 } 776 unsigned numInfos = nssArraySize((const void **)authSafe.info); 777 doIndent(depth); 778 printf("authSafe numInfos %u\n", numInfos); 779 780 int rtn = 0; 781 for(unsigned dex=0; dex<numInfos; dex++) { 782 NSS_P7_DecodedContentInfo *info = authSafe.info[dex]; 783 doIndent(depth); 784 printf("AuthSafe.info[%u] {\n", dex); 785 rtn = authSafeElementParse(info, pinfo, depth+3); 786 if(rtn) { 787 break; 788 } 789 doIndent(depth); 790 printf("}\n"); 791 } 792 return rtn; 793} 794 795static int p12MacParse( 796 const NSS_P12_MacData &macData, 797 P12ParseInfo &pinfo, 798 unsigned depth) // print indent depth 799{ 800 if(p12AlgIdParse(macData.mac.digestAlgorithm, NULL, pinfo, depth)) { 801 return 1; 802 } 803 doIndent(depth); 804 printf("Digest : "); 805 printDataAsHex(&macData.mac.digest, 20); 806 doIndent(depth); 807 printf("Salt : "); 808 printDataAsHex(&macData.macSalt, 16); 809 const CSSM_DATA &iter = macData.iterations; 810 811 if(iter.Length > 4) { 812 doIndent(depth); 813 printf("***Warning: malformed iteraton length (%u)\n", 814 (unsigned)iter.Length); 815 } 816 unsigned i = dataToInt(iter); 817 doIndent(depth); 818 printf("Iterations = %u\n", i); 819 return 0; 820} 821 822static int p12Parse( 823 const CSSM_DATA &rawBlob, 824 P12ParseInfo &pinfo, 825 unsigned depth) // print indent depth 826{ 827 NSS_P12_DecodedPFX pfx; 828 memset(&pfx, 0, sizeof(pfx)); 829 if(pinfo.mCoder.decodeItem(rawBlob, NSS_P12_DecodedPFXTemplate, &pfx)) { 830 printf("***Error on top-level decode of NSS_P12_DecodedPFX\n"); 831 return 1; 832 } 833 doIndent(depth); 834 printf("version = %u\n", (unsigned)dataToInt(pfx.version)); 835 NSS_P7_DecodedContentInfo &dci = pfx.authSafe; 836 837 doIndent(depth); 838 printf("contentType = %s\n", oidStr(dci.contentType, pinfo.mParser)); 839 doIndent(depth); 840 printf("type = %s\n", p7ContentInfoTypeStr(dci.type)); 841 int rtn = 0; 842 if(nssCompareCssmData(&dci.contentType, &CSSMOID_PKCS7_Data)) { 843 doIndent(depth); 844 printf("AuthenticatedSafe Length %u {\n", 845 (unsigned)dci.content.data->Length); 846 rtn = authSafeParse(*dci.content.data, pinfo, depth+3); 847 doIndent(depth); 848 printf("}\n"); 849 } 850 else { 851 printf("Not parsing any other content type today.\n"); 852 } 853 if(pfx.macData) { 854 doIndent(depth); 855 printf("Mac Data {\n"); 856 p12MacParse(*pfx.macData, pinfo, depth+3); 857 doIndent(depth); 858 printf("}\n"); 859 if(pinfo.mPwd.Data == NULL) { 860 doIndent(depth); 861 printf("=== MAC not verified (no passphrase)===\n"); 862 } 863 else { 864 CSSM_RETURN crtn = p12VerifyMac_app(pfx, pinfo.mCspHand, 865 pinfo.mPwd, pinfo.mCoder); 866 doIndent(depth); 867 if(crtn) { 868 cssmPerror("p12VerifyMac", crtn); 869 doIndent(depth); 870 printf("***MAC verify failure.\n"); 871 } 872 else { 873 printf("MAC verifies OK.\n"); 874 } 875 } 876 } 877 return 0; 878} 879 880int p12ParseTop( 881 CSSM_DATA &rawBlob, 882 CSSM_CSP_HANDLE cspHand, 883 CFStringRef pwd, 884 bool verbose) 885{ 886 SecNssCoder coder; 887 OidParser parser; 888 P12Parsed parsed(coder); 889 P12ParseInfo pinfo(coder, 890 cspHand, 891 parser, 892 pwd, 893 NULL, // no separate pwd 894 parsed); 895 896 printf("PKCS12 PFX:\n"); 897 int rtn = p12Parse(rawBlob, pinfo, 3); 898 899 /* find anything? */ 900 if(verbose) { 901 P12KnownBlobs &certs = pinfo.mParsed.mCerts; 902 if(certs.mNumBlobs) { 903 printf("\n\n"); 904 for(unsigned dex=0; dex<certs.mNumBlobs; dex++) { 905 printf("Cert %u:\n", dex); 906 printCert(certs.mBlobs[dex].Data, 907 certs.mBlobs[dex].Length, CSSM_FALSE); 908 printf("\n"); 909 } 910 } 911 P12KnownBlobs &crls = pinfo.mParsed.mCrls; 912 if(crls.mNumBlobs) { 913 printf("\n\n"); 914 for(unsigned dex=0; dex<crls.mNumBlobs; dex++) { 915 printf("CRL %u:\n", dex); 916 printCrl(crls.mBlobs[dex].Data, 917 crls.mBlobs[dex].Length, CSSM_FALSE); 918 } 919 } 920 } 921 return rtn; 922} 923