2  * grunt-quality p12 parse tool. 
   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.  
   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" 
  22 #include <CoreFoundation/CoreFoundation.h> 
  23 #include <security_cdsa_utils/cuCdsaUtils.h> 
  24 #include <Security/oidsattr.h> 
  27  * The stuff which gets passed around to all parse modules 
  32         P12ParseInfo(SecNssCoder 
&coder
, 
  33                 CSSM_CSP_HANDLE cspHand
, 
  35                 /* NULL means don't verify MAC, don't decrypt */ 
  37                 /* if this second pwd is absent, use macPwd for both */ 
  39                 P12Parsed 
&parsed
)                      // destination 
  45                         pwdToUcode(macPwd
, mPwd
); 
  46                         pwdToUcode(encrPwd
, mEncrPwd
); 
  51         void pwdToUcode(CFStringRef str
, CSSM_DATA 
&pwd
); 
  54         CSSM_CSP_HANDLE         mCspHand
; 
  56         CSSM_DATA                       mPwd
;           // unicode, double null terminated 
  58         P12Parsed                       
&mParsed
;       // destination 
  62 void P12ParseInfo::pwdToUcode( 
  71         CFIndex len 
= CFStringGetLength(str
); 
  72         mCoder
.allocItem(pwd
, (len 
* sizeof(UniChar
)) + 2); 
  74         for(CFIndex dex
=0; dex
<len
; dex
++) { 
  75                 UniChar uc 
= CFStringGetCharacterAtIndex(str
, dex
); 
  83 static void doIndent(unsigned depth
) 
  85         for(unsigned i
=0; i
<depth
; i
++) { 
  90 /* thread-unsafe oid-to-string converter */ 
  91 static char oidStrBuf
[OID_PARSER_STRING_SIZE
]; 
  93 static const char *oidStr( 
  97         parser
.oidParse(oid
.Data
, oid
.Length
, oidStrBuf
); 
 101 static void printDataAsHex( 
 103         unsigned maxToPrint 
= 0)                // optional, 0 means print it all 
 107         uint32 len 
= d
->Length
; 
 110         if((maxToPrint 
!= 0) && (len 
> maxToPrint
)) { 
 114         for(i
=0; i
<len
; i
++) { 
 115                 printf("%02X ", ((unsigned char *)cp
)[i
]); 
 125 static void printDataAsUnichars( 
 126         const CSSM_DATA 
&data
) 
 128         if(data
.Length 
& 1) { 
 129                 printf("Unicode can not have odd number of bytes\n"); 
 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
; 
 137         while(inp 
< (data
.Data 
+ data
.Length
)) { 
 138                 *outp 
= (((unsigned)inp
[0]) << 8) | inp
[1]; 
 143         CFStringRef cstr 
= CFStringCreateWithCharacters(NULL
, uc
, strLen
); 
 145                 printf("***Error creating CFString from unichars\n"); 
 149         outStr 
= (char *)malloc(strLen 
+ 1); 
 150         if(CFStringGetCString(cstr
, outStr
, strLen 
+ 1, kCFStringEncodingASCII
)) { 
 151                 printf("%s\n", outStr
); 
 154                 printf("***Error converting from unicode to ASCII\n"); 
 166         const CSSM_DATA 
&cdata
) 
 168         if((cdata
.Length 
== 0) || (cdata
.Data 
== NULL
)) { 
 171         uint32 len 
= cdata
.Length
; 
 172         if(len 
> sizeof(uint32
)) { 
 173                 printf("***Bad formatting for DER integer\n"); 
 174                 len 
= sizeof(uint32
); 
 178         uint8 
*cp 
= cdata
.Data
; 
 179         for(uint32 i
=0; i
<len
; i
++) { 
 180                 rtn 
= (rtn 
<< 8) | *cp
++; 
 185 #ifdef old_and_in_the_way 
 186 static int writeAuthSafeContent( 
 187         const CSSM_DATA 
&rawBlob
,  
 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"); 
 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
)); 
 202         /* parse content per OID the only special case is PKCS7_Data, 
 203          * which we unwrap from an octet string before writing it */ 
 205         if(nssCompareCssmData(&rci
.contentType
, &CSSMOID_PKCS7_Data
)) { 
 206                 if(coder
.decodeItem(rci
.content
, SEC_OctetStringTemplate
, 
 208                         printf("***Error decoding PKCS7_Data Octet string; writing" 
 210                         toWrite 
= rci
.content
; 
 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
; 
 221                 printf("***writeAuthSafeContent: bad contentType\n"); 
 224         if(writeFile(outFile
, toWrite
.Data
, toWrite
.Length
)) { 
 225                 printf("***Error writing to %s\n", outFile
); 
 229                 printf("...%u bytes written to %s\n",  
 230                         (unsigned)toWrite
.Length
, outFile
); 
 234 #endif  /* old_and_in_the_way */ 
 237  * Decrypt the contents of a NSS_P7_EncryptedData 
 239 #define WRITE_DECRYPT_TEXT      0 
 240 #if     WRITE_DECRYPT_TEXT 
 244 #define IMPORT_EXPORT_COMPLETE  1 
 246 static int encryptedDataDecrypt( 
 247         const NSS_P7_EncryptedData 
&edata
, 
 249         NSS_P12_PBE_Params 
*pbep
,       // preparsed 
 250         CSSM_DATA 
&ptext
)                       // result goes here in pinfo.coder space 
 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 
 263         bool found 
= pkcsOidToParams(&edata
.contentInfo
.encrAlg
.algorithm
, 
 264                 keyAlg
, encrAlg
, pbeHashAlg
, keySizeInBits
, blockSizeInBytes
, 
 265                 padding
, mode
, pkcs
); 
 267         bool found 
= pkcsOidToParams(&edata
.contentInfo
.encrAlg
.algorithm
, 
 268                 keyAlg
, encrAlg
, pbeHashAlg
, keySizeInBits
, blockSizeInBytes
, 
 270         #endif  /* IMPORT_EXPORT_COMPLETE */ 
 273                 printf("***EncryptedData encrAlg not understood\n"); 
 277         unsigned iterCount 
= dataToInt(pbep
->iterations
); 
 280         CSSM_RETURN crtn 
= p12Decrypt_app(pinfo
.mCspHand
, 
 281                 edata
.contentInfo
.encrContent
, 
 282                 keyAlg
, encrAlg
, pbeHashAlg
, 
 283                 keySizeInBits
, blockSizeInBytes
, 
 285                 iterCount
, pbep
->salt
, 
 289         #if WRITE_DECRYPT_TEXT 
 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
); 
 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. 
 308 static int p12AlgIdParse( 
 309         const CSSM_X509_ALGORITHM_IDENTIFIER 
&algId
, 
 310         NSS_P12_PBE_Params 
*pbeParams
,          // optional 
 312         unsigned depth
)                                         // print indent 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 */ 
 320                 printf("Alg Params : "); 
 321                 printDataAsHex(¶m
); 
 325         if(param
.Length 
== 0) { 
 326                 printf("===warning: no alg parameters, this is not optional\n"); 
 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"); 
 338         printDataAsHex(&pbeParams
->salt
); 
 340         if(pbeParams
->iterations
.Length 
> 4) { 
 341                 printf("warning: iterations greater than max int\n"); 
 343                 printf("Iterations : "); 
 344                 printDataAsHex(&pbeParams
->iterations
); 
 347                 printf("Iterations : %u\n",  
 348                         (unsigned)dataToInt(pbeParams
->iterations
)); 
 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 
 359 static int encryptedDataParse( 
 360         const NSS_P7_EncryptedData 
&edata
, 
 362         NSS_P12_PBE_Params 
*pbep
,               // optional, RETURNED 
 363         unsigned depth
)                                 // print indent depth 
 366         printf("version = %u\n", (unsigned)dataToInt(edata
.version
)); 
 367         const NSS_P7_EncrContentInfo 
&ci 
= edata
.contentInfo
; 
 369         printf("contentType = %s\n", oidStr(ci
.contentType
, pinfo
.mParser
)); 
 372          * Parse the alg ID, safe PBE params for when we do the  
 375         const CSSM_X509_ALGORITHM_IDENTIFIER 
&algId 
= ci
.encrAlg
; 
 376         if(p12AlgIdParse(algId
, pbep
, pinfo
, depth
)) { 
 381         printf("encrContent : "); 
 382         printDataAsHex(&ci
.encrContent
, 12); 
 386 static int attrParse( 
 387         const NSS_Attribute 
*attr
, 
 392         printf("attrType : %s\n", oidStr(attr
->attrType
, pinfo
.mParser
)); 
 393         unsigned numVals 
= nssArraySize((const void **)attr
->attrValue
); 
 395         printf("numValues = %u\n", numVals
); 
 397         for(unsigned dex
=0; dex
<numVals
; dex
++) { 
 399                 printf("val[%u] : ", dex
); 
 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 
 406                 if(nssCompareCssmData(&attr
->attrType
, &CSSMOID_PKCS9_FriendlyName
)) { 
 407                         /* BMP string (UniCode) */ 
 409                         if(pinfo
.mCoder
.decodeItem(*attr
->attrValue
[dex
], 
 410                                         kSecAsn1BMPStringTemplate
, &ustr
)) { 
 411                                 printf("***Error decoding BMP string\n"); 
 414                         printDataAsUnichars(ustr
); 
 416                 else if(nssCompareCssmData(&attr
->attrType
,  
 417                                         &CSSMOID_PKCS9_LocalKeyId
)) { 
 420                         if(pinfo
.mCoder
.decodeItem(*attr
->attrValue
[dex
], 
 421                                         kSecAsn1ObjectIDTemplate
, &ostr
)) { 
 422                                 printf("***Error decoding LocalKeyId string\n"); 
 425                         printDataAsHex(&ostr
, 16); 
 428                         printDataAsHex(attr
->attrValue
[dex
], 8); 
 435  * ShroudedKeyBag parser w/decrypt 
 437 static int shroudedKeyBagParse( 
 438         const NSS_P12_ShroudedKeyBag 
*keyBag
, 
 442         const CSSM_X509_ALGORITHM_IDENTIFIER 
&algId 
= keyBag
->algorithm
; 
 443         NSS_P12_PBE_Params pbep
; 
 444         if(p12AlgIdParse(algId
, &pbep
, pinfo
, depth
)) { 
 447         if(pinfo
.mPwd
.Data 
== NULL
) { 
 449                 printf("=== Key not decrypted (no passphrase)===\n"); 
 454          * Prepare for decryption 
 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 
 466         bool found 
= pkcsOidToParams(&algId
.algorithm
, 
 467                 keyAlg
, encrAlg
, pbeHashAlg
, keySizeInBits
, blockSizeInBytes
, 
 468                 padding
, mode
, pkcs
); 
 470         bool found 
= pkcsOidToParams(&algId
.algorithm
, 
 471                 keyAlg
, encrAlg
, pbeHashAlg
, keySizeInBits
, blockSizeInBytes
, 
 476                 printf("***ShroudedKeyBag encrAlg not understood\n"); 
 480         unsigned iterCount 
= dataToInt(pbep
.iterations
); 
 481         CSSM_DATA berPrivKey
; 
 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
, 
 489                 iterCount
, pbep
.salt
, 
 495                 printf("***Error decrypting private key\n"); 
 500         NSS_PrivateKeyInfo privKey
; 
 501         memset(&privKey
, 0, sizeof(privKey
)); 
 502         if(pinfo
.mCoder
.decodeItem(berPrivKey
, 
 503                         kSecAsn1PrivateKeyInfoTemplate
, &privKey
)) { 
 505                 printf("***Error decoding decrypted private key\n"); 
 510          * in P12 library, we'd convert the result into a CSSM_KEY 
 513         CSSM_X509_ALGORITHM_IDENTIFIER 
&privAlg 
= privKey
.algorithm
; 
 515         printf("Priv Key Alg  : %s\n", oidStr(privAlg
.algorithm
, pinfo
.mParser
)); 
 517         printf("Priv Key Blob : "); 
 518         printDataAsHex(&privKey
.privateKey
, 16); 
 520         unsigned numAttrs 
= nssArraySize((const void**)privKey
.attributes
); 
 523                 printf("numAttrs = %u\n", numAttrs
); 
 524                 for(unsigned i
=0; i
<numAttrs
; i
++) { 
 526                         printf("attr[%u]:\n", i
); 
 527                         attrParse(privKey
.attributes
[i
], pinfo
, depth
+6); 
 536 static int certBagParse( 
 537         const NSS_P12_CertBag 
*certBag
, 
 541         /* fixe - we really need to store the attrs along with the cert here! */ 
 542         switch(certBag
->type
) { 
 545                         printf("X509 cert found, size %u\n",  
 546                                 (unsigned)certBag
->certValue
.Length
); 
 547                         pinfo
.mParsed
.mCerts
.addBlob(certBag
->certValue
); 
 551                         printf("Unknown cert type found\n"); 
 552                         P12UnknownBlob 
*uk 
= new P12UnknownBlob(certBag
->certValue
, 
 554                         pinfo
.mParsed
.mUnknown
.addBlob(uk
); 
 562 static int crlBagParse( 
 563         const NSS_P12_CrlBag 
*crlBag
, 
 567         /* fixe - we really need to store the attrs along with the crl here! */ 
 568         switch(crlBag
->type
) { 
 571                         printf("X509 CRL found, size %u\n",  
 572                                 (unsigned)crlBag
->crlValue
.Length
); 
 573                         pinfo
.mParsed
.mCrls
.addBlob(crlBag
->crlValue
); 
 577                         printf("Unknown CRL type found\n"); 
 578                         P12UnknownBlob 
*uk 
= new P12UnknownBlob(crlBag
->crlValue
, 
 580                         pinfo
.mParsed
.mUnknown
.addBlob(uk
); 
 587  * Parse an encoded NSS_P12_SafeContents. This could be either  
 588  * present as plaintext in an AuthSafe or decrypted.  
 590 static int safeContentsParse( 
 591         const CSSM_DATA 
&contentsBlob
, 
 593         unsigned depth
)         // print indent depth 
 595         NSS_P12_SafeContents sc
; 
 596         memset(&sc
, 0, sizeof(sc
)); 
 597         if(pinfo
.mCoder
.decodeItem(contentsBlob
, NSS_P12_SafeContentsTemplate
, 
 599                 printf("***Error decoding SafeContents\n"); 
 602         unsigned numBags 
= nssArraySize((const void **)sc
.bags
); 
 604         printf("SafeContents num bags %u\n", numBags
); 
 607         for(unsigned dex
=0; dex
<numBags
; dex
++) { 
 608                 NSS_P12_SafeBag 
*bag 
= sc
.bags
[dex
]; 
 610                 printf("Bag %u:\n", dex
); 
 612                 /* common stuff here */ 
 614                 printf("bagId = %s\n", oidStr(bag
->bagId
, pinfo
.mParser
)); 
 616                 printf("type = %s\n", p12BagTypeStr(bag
->type
)); 
 617                 unsigned numAttrs 
= nssArraySize((const void**)bag
->bagAttrs
); 
 620                         printf("numAttrs = %u\n", numAttrs
); 
 621                         for(unsigned i
=0; i
<numAttrs
; i
++) { 
 623                                 printf("attr[%u]:\n", i
); 
 624                                 attrParse(bag
->bagAttrs
[i
], pinfo
, depth
+6); 
 629                  * Now break out to individual bag type 
 631                  * This hacked line breaks when we have a real key bag defined 
 633                 unsigned defaultLen 
= (unsigned)bag
->bagValue
.keyBag
->Length
; 
 637                                 printf("KeyBag: size %u\n", defaultLen
); 
 639                         case BT_ShroudedKeyBag
: 
 641                                 printf("ShroudedKeyBag:\n"); 
 642                                 rtn 
= shroudedKeyBagParse(bag
->bagValue
.shroudedKeyBag
, 
 648                                 printf("CertBag:\n"); 
 649                                 rtn 
= certBagParse(bag
->bagValue
.certBag
, 
 656                                 rtn 
= crlBagParse(bag
->bagValue
.crlBag
, 
 662                                 printf("SecretBag: size %u\n", defaultLen
); 
 664                         case BT_SafeContentsBag
: 
 666                                 printf("SafeContentsBag: size %u\n", defaultLen
); 
 670                                 printf("===Warning: unknownBagType (%u)\n", 
 671                                         (unsigned)bag
->type
); 
 682  * Parse a ContentInfo in the context of (i.e., as an element of) 
 683  * an element in a AuthenticatedSafe 
 685 static int authSafeElementParse( 
 686         const NSS_P7_DecodedContentInfo 
*info
, 
 688         unsigned depth
)         // print indent depth 
 690         char oidStr
[OID_PARSER_STRING_SIZE
]; 
 691         pinfo
.mParser
.oidParse(info
->contentType
.Data
,  
 692                 info
->contentType
.Length
, oidStr
); 
 695         printf("contentType = %s\n", oidStr
); 
 697         printf("type = %s\n", p7ContentInfoTypeStr(info
->type
)); 
 701                         /* unencrypted SafeContents */ 
 703                         printf("raw size: %u\n",  
 704                                 (unsigned)info
->content
.data
->Length
); 
 706                         printf("Plaintext SafeContents:\n"); 
 707                         rtn 
= safeContentsParse(*info
->content
.data
, 
 711                 case CT_EncryptedData
: 
 714                         printf("EncryptedData:\n"); 
 715                         NSS_P12_PBE_Params pbep
; 
 716                         rtn 
= encryptedDataParse(*info
->content
.encryptData
, 
 717                                 pinfo
, &pbep
, depth
+3); 
 721                         if(pinfo
.mPwd
.Data 
== NULL
) { 
 723                                 printf("=== Contents not decrypted (no passphrase)===\n"); 
 727                                 * Decrypt contents to get a SafeContents and 
 730                                 CSSM_DATA ptext 
= {0, NULL
}; 
 731                                 rtn 
= encryptedDataDecrypt(*info
->content
.encryptData
, 
 732                                         pinfo
, &pbep
, ptext
); 
 735                                         printf("***Error decrypting CT_EncryptedData\n"); 
 738                                 printf("Decrypted SafeContents {\n"); 
 739                                 rtn 
= safeContentsParse(ptext
, pinfo
, depth
+3); 
 746                         /* the rest map to an ASN_ANY/CSSM_DATA for now */ 
 748                         printf("size of %u is all we know today\n", 
 749                                 (unsigned)info
->content
.data
->Length
); 
 757  * Parse an encoded NSS_P12_AuthenticatedSafe 
 759 static int authSafeParse( 
 760         const CSSM_DATA authSafeBlob
, 
 762         unsigned depth
)         // print indent depth 
 764         NSS_P12_AuthenticatedSafe authSafe
; 
 766         memset(&authSafe
, 0, sizeof(authSafe
)); 
 767         if(pinfo
.mCoder
.decodeItem(authSafeBlob
, 
 768                         NSS_P12_AuthenticatedSafeTemplate
, 
 770                 printf("***Error decoding authSafe\n"); 
 773         unsigned numInfos 
= nssArraySize((const void **)authSafe
.info
); 
 775         printf("authSafe numInfos %u\n", numInfos
); 
 778         for(unsigned dex
=0; dex
<numInfos
; dex
++) { 
 779                 NSS_P7_DecodedContentInfo 
*info 
= authSafe
.info
[dex
]; 
 781                 printf("AuthSafe.info[%u] {\n", dex
); 
 782                 rtn 
= authSafeElementParse(info
, pinfo
, depth
+3); 
 792 static int p12MacParse( 
 793         const NSS_P12_MacData 
&macData
,  
 795         unsigned depth
)         // print indent depth 
 797         if(p12AlgIdParse(macData
.mac
.digestAlgorithm
, NULL
, pinfo
, depth
)) { 
 802         printDataAsHex(&macData
.mac
.digest
, 20); 
 805         printDataAsHex(&macData
.macSalt
, 16); 
 806         const CSSM_DATA 
&iter 
= macData
.iterations
; 
 808         if(iter
.Length 
> 4) { 
 810                 printf("***Warning: malformed iteraton length (%u)\n", 
 811                         (unsigned)iter
.Length
); 
 813         unsigned i 
= dataToInt(iter
); 
 815         printf("Iterations = %u\n", i
); 
 820         const CSSM_DATA 
&rawBlob
,  
 822         unsigned depth
)         // print indent depth 
 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"); 
 831         printf("version = %u\n", (unsigned)dataToInt(pfx
.version
)); 
 832         NSS_P7_DecodedContentInfo 
&dci 
= pfx
.authSafe
; 
 835         printf("contentType = %s\n", oidStr(dci
.contentType
, pinfo
.mParser
)); 
 837         printf("type = %s\n", p7ContentInfoTypeStr(dci
.type
)); 
 839         if(nssCompareCssmData(&dci
.contentType
, &CSSMOID_PKCS7_Data
)) { 
 841                 printf("AuthenticatedSafe Length %u {\n",  
 842                         (unsigned)dci
.content
.data
->Length
); 
 843                 rtn 
= authSafeParse(*dci
.content
.data
, pinfo
, depth
+3); 
 848                 printf("Not parsing any other content type today.\n"); 
 852                 printf("Mac Data {\n"); 
 853                 p12MacParse(*pfx
.macData
, pinfo
, depth
+3); 
 856                 if(pinfo
.mPwd
.Data 
== NULL
) { 
 858                         printf("=== MAC not verified (no passphrase)===\n"); 
 861                         CSSM_RETURN crtn 
= p12VerifyMac_app(pfx
, pinfo
.mCspHand
,  
 862                                 pinfo
.mPwd
, pinfo
.mCoder
); 
 865                                 cssmPerror("p12VerifyMac", crtn
); 
 867                                 printf("***MAC verify failure.\n"); 
 870                                 printf("MAC verifies OK.\n"); 
 879         CSSM_CSP_HANDLE cspHand
, 
 885         P12Parsed 
parsed(coder
); 
 886         P12ParseInfo 
pinfo(coder
, 
 890                 NULL
,                   // no separate pwd 
 893         printf("PKCS12 PFX:\n"); 
 894         int rtn 
= p12Parse(rawBlob
, pinfo
, 3); 
 898                 P12KnownBlobs 
&certs 
= pinfo
.mParsed
.mCerts
; 
 899                 if(certs
.mNumBlobs
) { 
 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
); 
 908                 P12KnownBlobs 
&crls 
= pinfo
.mParsed
.mCrls
; 
 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
);