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