]> git.saurik.com Git - apple/security.git/blob - SecurityTests/clxutils/p12/p12Parse.cpp
Security-57031.10.10.tar.gz
[apple/security.git] / SecurityTests / clxutils / p12 / 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 "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 */
29 class P12ParseInfo
30 {
31 public:
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
62 void 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
83 static 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 */
91 static char oidStrBuf[OID_PARSER_STRING_SIZE];
92
93 static 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
101 static 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
125 static 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 }
156 errOut:
157 free(uc);
158 if(outStr) {
159 free(outStr);
160 }
161 CFRelease(cstr);
162 return;
163 }
164
165 uint32 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
186 static 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
241 static int ctr = 0;
242 #endif
243
244 #define IMPORT_EXPORT_COMPLETE 1
245
246 static 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 */
308 static 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 &param = algId.parameters;
317 if(pbeParams == NULL) {
318 /* alg params are uninterpreted */
319 doIndent(depth);
320 printf("Alg Params : ");
321 printDataAsHex(&param);
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 */
359 static 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
386 static 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 */
437 static 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 */
536 static 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 */
562 static 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 */
590 static 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 */
685 static 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 */
759 static 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
792 static 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
819 static 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
877 int 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 }