/* * Parse an encoded NSS_P12_AuthenticatedSafe */ static int authSafeParse( const CSSM_DATA authSafeBlob, P12ParseInfo &pinfo, unsigned depth) // print indent depth { NSS_P12_AuthenticatedSafe authSafe; memset(&authSafe, 0, sizeof(authSafe)); if(pinfo.mCoder.decodeItem(authSafeBlob, NSS_P12_AuthenticatedSafeTemplate, &authSafe)) { printf("***Error decoding authSafe\n"); return 1; } unsigned numInfos = nssArraySize((const void **)authSafe.info); doIndent(depth); printf("authSafe numInfos %u\n", numInfos); int rtn = 0; for(unsigned dex=0; dex<numInfos; dex++) { NSS_P7_DecodedContentInfo *info = authSafe.info[dex]; doIndent(depth); printf("AuthSafe.info[%u] {\n", dex); rtn = authSafeElementParse(info, pinfo, depth+3); if(rtn) { break; } doIndent(depth); printf("}\n"); } return rtn; }
/* print a CFData as an X509 Name (i.e., subject or issuer) */ void printCfName( CFDataRef nameData, OidParser &parser) { SecAsn1CoderRef coder = NULL; OSStatus ortn; ortn = SecAsn1CoderCreate(&coder); if(ortn) { cssmPerror("SecAsn1CoderCreate", ortn); return; } /* subsequent errors to errOut: */ NSS_Name nssName = {NULL}; unsigned numRdns; ortn = SecAsn1Decode(coder, CFDataGetBytePtr(nameData), CFDataGetLength(nameData), kSecAsn1NameTemplate, &nssName); if(ortn) { printf("***Error decoding NSS_Name\n"); goto errOut; } numRdns = nssArraySize((const void **)nssName.rdns); for(unsigned dex=0; dex<numRdns; dex++) { printRdn(nssName.rdns[dex], parser); } errOut: if(coder) { SecAsn1CoderRelease(coder); } }
/* * Parse an encoded NSS_P12_SafeContents. This could be either * present as plaintext in an AuthSafe or decrypted. */ static int safeContentsParse(pkcs12_context * context, const SecAsn1Item *contentsBlob) { p12DecodeLog("safeContentsParse"); NSS_P12_SafeContents sc; memset(&sc, 0, sizeof(sc)); require_noerr(decode_item(context, contentsBlob, NSS_P12_SafeContentsTemplate, &sc), out); unsigned numBags = nssArraySize((const void **)sc.bags); unsigned int dex; for(dex=0; dex<numBags; dex++) { NSS_P12_SafeBag *bag = sc.bags[dex]; assert(bag != NULL); /* ensure that *something* is there */ require(bag->bagValue.keyBag != NULL, out); /* * Break out to individual bag type */ switch(bag->type) { case BT_ShroudedKeyBag: require_noerr(shroudedKeyBagParse(context, bag), out); break; case BT_CertBag: require_noerr(certBagParse(context, bag), out); break; case BT_KeyBag: /* keyBagParse(bag); */ p12DecodeLog("Unhandled BT_KeyBag"); break; case BT_CrlBag: /* crlBagParse(bag); */ p12DecodeLog("Unhandled BT_CrlBag"); break; case BT_SecretBag: /* secretBagParse(bag); */ p12DecodeLog("Unhandled BT_SecretBag"); break; case BT_SafeContentsBag: /* safeContentsBagParse(bag); */ p12DecodeLog("Unhandled BT_SafeContentsBag"); break; default: p12DecodeLog("Unknown bag type"); goto out; break; } } return 0; out: return -1; }
/* * Parse an encoded NSS_P12_SafeContents. This could be either * present as plaintext in an AuthSafe or decrypted. */ void P12Coder::safeContentsParse( const CSSM_DATA &contentsBlob, SecNssCoder &localCdr) { p12DecodeLog("safeContentsParse"); NSS_P12_SafeContents sc; memset(&sc, 0, sizeof(sc)); if(localCdr.decodeItem(contentsBlob, NSS_P12_SafeContentsTemplate, &sc)) { p12ErrorLog("Error decoding SafeContents\n"); P12_THROW_DECODE; } unsigned numBags = nssArraySize((const void **)sc.bags); for(unsigned dex=0; dex<numBags; dex++) { NSS_P12_SafeBag *bag = sc.bags[dex]; assert(bag != NULL); /* ensure that *something* is there */ if(bag->bagValue.keyBag == NULL) { p12ErrorLog("safeContentsParse: Empty SafeBag\n"); P12_THROW_DECODE; } /* * Break out to individual bag type */ switch(bag->type) { case BT_KeyBag: keyBagParse(*bag, localCdr); break; case BT_ShroudedKeyBag: shroudedKeyBagParse(*bag, localCdr); break; case BT_CertBag: certBagParse(*bag, localCdr); break; case BT_CrlBag: crlBagParse(*bag, localCdr); break; case BT_SecretBag: secretBagParse(*bag ,localCdr); break; case BT_SafeContentsBag: safeContentsBagParse(*bag, localCdr); break; default: p12ErrorLog("unknown p12 BagType (%u)\n", (unsigned)bag->type); P12_THROW_DECODE; } } }
static void printRdn(const NSS_RDN *rdn, OidParser &parser) { unsigned numAtvs = nssArraySize((const void **)rdn->atvs); char *fieldName; for(unsigned dex=0; dex<numAtvs; dex++) { const NSS_ATV *atv = rdn->atvs[dex]; if(compareOids(&atv->type, &CSSMOID_CountryName)) { fieldName = "Country "; } else if(compareOids(&atv->type, &CSSMOID_OrganizationName)) { fieldName = "Org "; } else if(compareOids(&atv->type, &CSSMOID_LocalityName)) { fieldName = "Locality "; } else if(compareOids(&atv->type, &CSSMOID_OrganizationalUnitName)) { fieldName = "OrgUnit "; } else if(compareOids(&atv->type, &CSSMOID_CommonName)) { fieldName = "Common Name "; } else if(compareOids(&atv->type, &CSSMOID_Surname)) { fieldName = "Surname "; } else if(compareOids(&atv->type, &CSSMOID_Title)) { fieldName = "Title "; } else if(compareOids(&atv->type, &CSSMOID_Surname)) { fieldName = "Surname "; } else if(compareOids(&atv->type, &CSSMOID_StateProvinceName)) { fieldName = "State "; } else if(compareOids(&atv->type, &CSSMOID_CollectiveStateProvinceName)) { fieldName = "Coll. State "; } else if(compareOids(&atv->type, &CSSMOID_EmailAddress)) { /* deprecated, used by Thawte */ fieldName = "Email addrs "; } else { fieldName = "Other name "; } indent(); printf("%s : ", fieldName); /* Not strictly true here, but we'll just assume we can print everything */ printAscii((char *)atv->value.item.Data, atv->value.item.Length, atv->value.item.Length); putchar('\n'); } }
void P12BagAttrs::copyAttr( const NSS_Attribute &src, NSS_Attribute &dst) { mCoder.allocCopyItem(src.attrType, dst.attrType); unsigned numVals = nssArraySize((const void **)src.attrValue); dst.attrValue = (CSSM_DATA **)p12NssNullArray(numVals, mCoder); for(unsigned dex=0; dex<numVals; dex++) { CSSM_DATA *dstVal = mCoder.mallocn<CSSM_DATA>(); memset(dstVal, 0, sizeof(CSSM_DATA)); dst.attrValue[dex] = dstVal; mCoder.allocCopyItem(*src.attrValue[dex], *dstVal); } }
static int attrParse( const NSS_Attribute *attr, P12ParseInfo &pinfo, unsigned depth) { doIndent(depth); printf("attrType : %s\n", oidStr(attr->attrType, pinfo.mParser)); unsigned numVals = nssArraySize((const void **)attr->attrValue); doIndent(depth); printf("numValues = %u\n", numVals); for(unsigned dex=0; dex<numVals; dex++) { doIndent(depth); printf("val[%u] : ", dex); /* * Note: these two enumerated types should only have one att value * per PKCS9. Leave that to real apps, we want to see what's there * in any case. */ if(nssCompareCssmData(&attr->attrType, &CSSMOID_PKCS9_FriendlyName)) { /* BMP string (UniCode) */ CSSM_DATA ustr; if(pinfo.mCoder.decodeItem(*attr->attrValue[dex], kSecAsn1BMPStringTemplate, &ustr)) { printf("***Error decoding BMP string\n"); continue; } printDataAsUnichars(ustr); } else if(nssCompareCssmData(&attr->attrType, &CSSMOID_PKCS9_LocalKeyId)) { /* Octet string */ CSSM_DATA ostr; if(pinfo.mCoder.decodeItem(*attr->attrValue[dex], kSecAsn1ObjectIDTemplate, &ostr)) { printf("***Error decoding LocalKeyId string\n"); continue; } printDataAsHex(&ostr, 16); } else { printDataAsHex(attr->attrValue[dex], 8); } } return 0; }
/* * Parse an encoded NSS_P12_AuthenticatedSafe */ static int authSafeParse(pkcs12_context * context, const SecAsn1Item *authSafeBlob) { p12DecodeLog("authSafeParse"); NSS_P12_AuthenticatedSafe authSafe; memset(&authSafe, 0, sizeof(authSafe)); require_noerr(decode_item(context, authSafeBlob, NSS_P12_AuthenticatedSafeTemplate, &authSafe), out); unsigned numInfos = nssArraySize((const void **)authSafe.info); unsigned int dex; for (dex=0; dex<numInfos; dex++) { NSS_P7_DecodedContentInfo *info = authSafe.info[dex]; require_noerr_quiet(authSafeElementParse(context, info), out); } return 0; out: return -1; }
/* * Parse an encoded NSS_P12_AuthenticatedSafe */ void P12Coder::authSafeParse( const CSSM_DATA &authSafeBlob, SecNssCoder &localCdr) { p12DecodeLog("authSafeParse"); NSS_P12_AuthenticatedSafe authSafe; memset(&authSafe, 0, sizeof(authSafe)); if(localCdr.decodeItem(authSafeBlob, NSS_P12_AuthenticatedSafeTemplate, &authSafe)) { p12ErrorLog("Error decoding authSafe\n"); P12_THROW_DECODE; } unsigned numInfos = nssArraySize((const void **)authSafe.info); for(unsigned dex=0; dex<numInfos; dex++) { NSS_P7_DecodedContentInfo *info = authSafe.info[dex]; authSafeElementParse(info, localCdr); } }
/* * getter, public API version */ void P12BagAttrs::getAttr( unsigned attrNum, CFDataRef *attrOid, // RETURNED CFArrayRef *attrValues) // RETURNED { if(attrNum >= numAttrs()) { MacOSError::throwMe(paramErr); } NSS_Attribute *attr = mAttrs[attrNum]; *attrOid = p12CssmDataToCf(attr->attrType); unsigned numVals = nssArraySize((const void **)attr->attrValue); if(numVals == 0) { /* maybe should return empty array...? */ *attrValues = NULL; return; } CFMutableArrayRef vals = CFArrayCreateMutable(NULL, numVals, NULL); for(unsigned dex=0; dex<numVals; dex++) { CFDataRef val = p12CssmDataToCf(*attr->attrValue[dex]); CFArrayAppendValue(vals, val); } *attrValues = vals; }
unsigned P12BagAttrs::numAttrs() const { return nssArraySize((const void **)mAttrs); }
static int emit_item(pkcs12_context * context, NSS_Attribute **attrs, CFStringRef item_key, CFTypeRef item_value) { int result = -1; /* parse attrs into friendlyName, localKeyId; ignoring generic attrs */ CFMutableDictionaryRef attr_dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); require(attr_dict, out); unsigned numAttrs = nssArraySize((const void **)attrs); unsigned int dex; for(dex = 0; dex < numAttrs; dex++) { NSS_Attribute *attr = attrs[dex]; unsigned numValues = nssArraySize((const void**)attr->attrValue); DERItem type = { attr->attrType.Data, attr->attrType.Length }; if(DEROidCompare(&type, &oidFriendlyName)) { /* * BMP string (UniCode). Spec says only one legal value. */ require(numValues == 1, out); SecAsn1Item friendly_name_asn1; require_noerr(decode_item(context, attr->attrValue[0], kSecAsn1BMPStringTemplate, &friendly_name_asn1), out); CFStringRef friendly_name = CFStringCreateWithBytes(kCFAllocatorDefault, friendly_name_asn1.Data, friendly_name_asn1.Length, kCFStringEncodingUnicode, true); if (friendly_name) { CFDictionarySetValue(attr_dict, kSecImportItemLabel, friendly_name); CFRelease(friendly_name); } } else if(DEROidCompare(&type, &oidLocalKeyId)) { /* * Octet string. Spec says only one legal value. */ require(numValues == 1, out); SecAsn1Item local_key_id; require_noerr(decode_item(context, attr->attrValue[0], kSecAsn1OctetStringTemplate, &local_key_id), out); CFDataRef keyid = CFDataCreate(kCFAllocatorDefault, local_key_id.Data, local_key_id.Length); if (keyid) { CFDictionarySetValue(attr_dict, kSecImportItemKeyID, keyid); CFRelease(keyid); } } } CFTypeRef key = CFDictionaryGetValue(attr_dict, kSecImportItemKeyID); if (!key) key = CFDictionaryGetValue(attr_dict, kSecImportItemLabel); if (!key) key = item_value; CFMutableDictionaryRef item = (CFMutableDictionaryRef)CFDictionaryGetValue(context->items, key); if (item) { CFDictionarySetValue(item, item_key, item_value); } else { CFDictionarySetValue(attr_dict, item_key, item_value); CFDictionarySetValue(context->items, key, attr_dict); } result = 0; out: CFReleaseSafe(attr_dict); return result; }
/* * Parse an encoded NSS_P12_SafeContents. This could be either * present as plaintext in an AuthSafe or decrypted. */ static int safeContentsParse( const CSSM_DATA &contentsBlob, P12ParseInfo &pinfo, unsigned depth) // print indent depth { NSS_P12_SafeContents sc; memset(&sc, 0, sizeof(sc)); if(pinfo.mCoder.decodeItem(contentsBlob, NSS_P12_SafeContentsTemplate, &sc)) { printf("***Error decoding SafeContents\n"); return 1; } unsigned numBags = nssArraySize((const void **)sc.bags); doIndent(depth); printf("SafeContents num bags %u\n", numBags); int rtn = 0; for(unsigned dex=0; dex<numBags; dex++) { NSS_P12_SafeBag *bag = sc.bags[dex]; doIndent(depth); printf("Bag %u:\n", dex); /* common stuff here */ doIndent(depth+3); printf("bagId = %s\n", oidStr(bag->bagId, pinfo.mParser)); doIndent(depth+3); printf("type = %s\n", p12BagTypeStr(bag->type)); unsigned numAttrs = nssArraySize((const void**)bag->bagAttrs); if(numAttrs) { doIndent(depth+3); printf("numAttrs = %u\n", numAttrs); for(unsigned i=0; i<numAttrs; i++) { doIndent(depth+3); printf("attr[%u]:\n", i); attrParse(bag->bagAttrs[i], pinfo, depth+6); } } /* * Now break out to individual bag type * * This hacked line breaks when we have a real key bag defined */ unsigned defaultLen = (unsigned)bag->bagValue.keyBag->Length; switch(bag->type) { case BT_KeyBag: doIndent(depth+3); printf("KeyBag: size %u\n", defaultLen); break; case BT_ShroudedKeyBag: doIndent(depth+3); printf("ShroudedKeyBag:\n"); rtn = shroudedKeyBagParse(bag->bagValue.shroudedKeyBag, pinfo, depth+6); break; case BT_CertBag: doIndent(depth+3); printf("CertBag:\n"); rtn = certBagParse(bag->bagValue.certBag, pinfo, depth+6); break; case BT_CrlBag: doIndent(depth+3); printf("CrlBag:\n"); rtn = crlBagParse(bag->bagValue.crlBag, pinfo, depth+6); break; case BT_SecretBag: doIndent(depth+3); printf("SecretBag: size %u\n", defaultLen); break; case BT_SafeContentsBag: doIndent(depth+3); printf("SafeContentsBag: size %u\n", defaultLen); break; default: doIndent(depth+3); printf("===Warning: unknownBagType (%u)\n", (unsigned)bag->type); break; } if(rtn) { break; } } return rtn; }
/* * ShroudedKeyBag parser w/decrypt */ static int shroudedKeyBagParse( const NSS_P12_ShroudedKeyBag *keyBag, P12ParseInfo &pinfo, unsigned depth) { const CSSM_X509_ALGORITHM_IDENTIFIER &algId = keyBag->algorithm; NSS_P12_PBE_Params pbep; if(p12AlgIdParse(algId, &pbep, pinfo, depth)) { return 1; } if(pinfo.mPwd.Data == NULL) { doIndent(depth); printf("=== Key not decrypted (no passphrase)===\n"); return 0; } /* * Prepare for decryption */ CSSM_ALGORITHMS keyAlg; // e.g., CSSM_ALGID_DES CSSM_ALGORITHMS encrAlg; // e.g., CSSM_ALGID_3DES_3KEY_EDE CSSM_ALGORITHMS pbeHashAlg; // SHA1 or MD5 uint32 keySizeInBits; uint32 blockSizeInBytes; // for IV, optional CSSM_PADDING padding; // CSSM_PADDING_PKCS7, etc. CSSM_ENCRYPT_MODE mode; // CSSM_ALGMODE_CBCPadIV8, etc. #if IMPORT_EXPORT_COMPLETE PKCS_Which pkcs; bool found = pkcsOidToParams(&algId.algorithm, keyAlg, encrAlg, pbeHashAlg, keySizeInBits, blockSizeInBytes, padding, mode, pkcs); #else bool found = pkcsOidToParams(&algId.algorithm, keyAlg, encrAlg, pbeHashAlg, keySizeInBits, blockSizeInBytes, padding, mode); #endif if(!found) { printf("***ShroudedKeyBag encrAlg not understood\n"); return 1; } unsigned iterCount = dataToInt(pbep.iterations); CSSM_DATA berPrivKey; /* decrypt, result is BER encoded private key */ CSSM_RETURN crtn = p12Decrypt_app(pinfo.mCspHand, keyBag->encryptedData, keyAlg, encrAlg, pbeHashAlg, keySizeInBits, blockSizeInBytes, padding, mode, iterCount, pbep.salt, pinfo.mPwd, pinfo.mCoder, berPrivKey); if(crtn) { doIndent(depth); printf("***Error decrypting private key\n"); return 1; } /* decode */ NSS_PrivateKeyInfo privKey; memset(&privKey, 0, sizeof(privKey)); if(pinfo.mCoder.decodeItem(berPrivKey, kSecAsn1PrivateKeyInfoTemplate, &privKey)) { doIndent(depth); printf("***Error decoding decrypted private key\n"); return 1; } /* * in P12 library, we'd convert the result into a CSSM_KEY * or a SecItem... */ CSSM_X509_ALGORITHM_IDENTIFIER &privAlg = privKey.algorithm; doIndent(depth); printf("Priv Key Alg : %s\n", oidStr(privAlg.algorithm, pinfo.mParser)); doIndent(depth); printf("Priv Key Blob : "); printDataAsHex(&privKey.privateKey, 16); unsigned numAttrs = nssArraySize((const void**)privKey.attributes); if(numAttrs) { doIndent(depth+3); printf("numAttrs = %u\n", numAttrs); for(unsigned i=0; i<numAttrs; i++) { doIndent(depth+3); printf("attr[%u]:\n", i); attrParse(privKey.attributes[i], pinfo, depth+6); } } return 0; }