]> git.saurik.com Git - apple/security.git/blob - SecurityTests/clxutils/p12Parse/p12Parse.cpp
Security-57336.1.9.tar.gz
[apple/security.git] / SecurityTests / clxutils / p12Parse / p12Parse.cpp
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 */
31 class P12ParseInfo
32 {
33 public:
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
64 void 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
85 static 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 */
93 static char oidStrBuf[OID_PARSER_STRING_SIZE];
94
95 static 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
103 static 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
128 static 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 }
159 errOut:
160 free(uc);
161 if(outStr) {
162 free(outStr);
163 }
164 CFRelease(cstr);
165 return;
166 }
167
168 uint32 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
189 static 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
244 static int ctr = 0;
245 #endif
246
247 #define IMPORT_EXPORT_COMPLETE 1
248
249 static 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 */
311 static 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 &param = algId.parameters;
320 if(pbeParams == NULL) {
321 /* alg params are uninterpreted */
322 doIndent(depth);
323 printf("Alg Params : ");
324 printDataAsHex(&param);
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 */
362 static 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
389 static 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 */
440 static 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 */
539 static 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 */
565 static 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 */
593 static 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 */
688 static 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 */
762 static 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
795 static 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
822 static 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
880 int 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 }