DecodedExten::DecodedExten( const CSSM_OID &extnId, // copied bool critical, void *nssObj, // NSS_KeyUsage, NSS_BasicConstraints, // etc. NOT COPIED, exists in same // memory space as coder bool berEncoded, // indicates unknown extension which we // do not BER-decode when parsing a cert const SecAsn1Template *templ, // to decode/encode if !berEncoded SecNssCoder &coder, // all local allocs from here const CSSM_DATA *rawExtn) // NSS_CertExtension.value, copied to // mRawExtn : mCritical(critical), mNssObj(nssObj), mBerEncoded(berEncoded), mTempl(templ), mCoder(coder), mRawExtn(NULL) { coder.allocCopyItem(extnId, mExtnId); if(rawExtn) { mRawExtn = (CSSM_DATA *)coder.malloc(sizeof(CSSM_DATA)); coder.allocCopyItem(*rawExtn, *mRawExtn); } }
void CL_cssmInfoAccessToNss( const CE_AuthorityInfoAccess &cdsaObj, NSS_AuthorityInfoAccess &nssObj, SecNssCoder &coder) { memset(&nssObj, 0, sizeof(nssObj)); uint32 numDescs = cdsaObj.numAccessDescriptions; nssObj.accessDescriptions = (NSS_AccessDescription **)clNssNullArray(numDescs, coder); for(unsigned dex=0; dex<numDescs; dex++) { nssObj.accessDescriptions[dex] = coder.mallocn<NSS_AccessDescription>(); CE_AccessDescription *src = &cdsaObj.accessDescriptions[dex]; NSS_AccessDescription *dst = nssObj.accessDescriptions[dex]; coder.allocCopyItem(src->accessMethod, dst->accessMethod); /* Convert general name, then encode it into destination */ NSS_GeneralName nssGenName; CL_cssmGeneralNameToNss(src->accessLocation, nssGenName, coder); PRErrorCode prtn = coder.encodeItem(&nssGenName, kSecAsn1GeneralNameTemplate, dst->encodedAccessLocation); if(prtn) { clErrorLog("CL_cssmInfoAccessToNss: encode error\n"); CssmError::throwMe(CSSMERR_CL_MEMORY_ERROR); } } }
void CL_certCrlDecodeComponents( const CssmData &signedItem, // DER-encoded cert or CRL CssmOwnedData &tbsBlob, // still DER-encoded CssmOwnedData &algId, // ditto CssmOwnedData &rawSig) // raw bits (not an encoded AsnBits) { /* BER-decode into temp memory */ NSS_SignedCertOrCRL nssObj; SecNssCoder coder; PRErrorCode prtn; memset(&nssObj, 0, sizeof(nssObj)); prtn = coder.decode(signedItem.data(), signedItem.length(), kSecAsn1SignedCertOrCRLTemplate, &nssObj); if(prtn) { CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT); } /* tbsBlob and algId are raw ASN_ANY including tags, which we pass * back to caller intact */ tbsBlob.copy(nssObj.tbsBlob.Data, nssObj.tbsBlob.Length); algId.copy(nssObj.signatureAlgorithm.Data, nssObj.signatureAlgorithm.Length); /* signature is a bit string which we do in fact decode */ rawSig.copy(nssObj.signature.Data, (nssObj.signature.Length + 7) / 8); }
void CL_cssmGeneralNamesToNss( const CE_GeneralNames &cdsaObj, NSS_GeneralNames &nssObj, SecNssCoder &coder) { uint32 numNames = cdsaObj.numNames; nssObj.names = (CSSM_DATA **)clNssNullArray(numNames, coder); /* * Convert each element in cdsaObj to NSS form, encode, drop into * the ASN_ANY array. * * This array of (NSS_GeneralName)s is temporary, it doesn't * persist outside of this routine other than the fact that it's * mallocd by the coder arena pool. */ NSS_GeneralName *names = (NSS_GeneralName *)coder.malloc(sizeof(NSS_GeneralName) * numNames); memset(names, 0, sizeof(NSS_GeneralName) * numNames); for(unsigned dex=0; dex<cdsaObj.numNames; dex++) { nssObj.names[dex] = (CSSM_DATA_PTR)coder.malloc(sizeof(CSSM_DATA)); memset(nssObj.names[dex], 0, sizeof(CSSM_DATA)); CL_cssmGeneralNameToNss(cdsaObj.generalName[dex], names[dex], coder); if(coder.encodeItem(&names[dex], kSecAsn1GeneralNameTemplate, *nssObj.names[dex])) { clErrorLog("***Error encoding General.name\n"); CssmError::throwMe(CSSMERR_CL_MEMORY_ERROR); } } }
/* * Convert a CSSM_KEY to a CSSM_X509_SUBJECT_PUBLIC_KEY_INFO. The * CSSM key must be in raw format and with a specific blob format. * -- RSA keys have to be CSSM_KEYBLOB_RAW_FORMAT_PKCS1 * -- DSA keys have to be CSSM_KEYBLOB_RAW_FORMAT_X509 * -- ECDSA keys have to be CSSM_KEYBLOB_RAW_FORMAT_X509 */ void CL_CSSMKeyToSubjPubKeyInfoNSS( const CSSM_KEY &cssmKey, CSSM_X509_SUBJECT_PUBLIC_KEY_INFO &nssKeyInfo, SecNssCoder &coder) { const CSSM_KEYHEADER &hdr = cssmKey.KeyHeader; if(hdr.BlobType != CSSM_KEYBLOB_RAW) { clErrorLog("CL SetField: must specify RAW key blob\n"); CssmError::throwMe(CSSMERR_CSP_KEY_BLOB_TYPE_INCORRECT); } memset(&nssKeyInfo, 0, sizeof(nssKeyInfo)); /* algorithm and format dependent from here... */ switch(hdr.AlgorithmId) { case CSSM_ALGID_RSA: if(hdr.Format != CSSM_KEYBLOB_RAW_FORMAT_PKCS1) { clErrorLog("CL SetField: RSA key must be in PKCS1 format\n"); CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_FORMAT); } /* and fall thru */ default: { /* Key header's algorithm --> OID */ const CSSM_OID *oid = cssmAlgToOid(hdr.AlgorithmId); if(oid == NULL) { clErrorLog("CL SetField: Unknown key algorithm\n"); CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM); } CSSM_X509_ALGORITHM_IDENTIFIER &algId = nssKeyInfo.algorithm; coder.allocCopyItem(*oid, algId.algorithm); /* NULL algorithm parameters, always in this case */ CL_nullAlgParams(algId); /* Copy key bits, destination is a BIT STRING */ coder.allocCopyItem(cssmKey.KeyData, nssKeyInfo.subjectPublicKey); nssKeyInfo.subjectPublicKey.Length *= 8; break; } case CSSM_ALGID_DSA: case CSSM_ALGID_ECDSA: if(hdr.Format != CSSM_KEYBLOB_RAW_FORMAT_X509) { clErrorLog("CL SetField: DSA/ECDSA key must be in X509 format\n"); CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_FORMAT); } /* * All we do is decode the whole key blob into the * SubjectPublicKeyInfo. */ if(coder.decodeItem(cssmKey.KeyData, kSecAsn1SubjectPublicKeyInfoTemplate, &nssKeyInfo)) { clErrorLog("CL SetField: Error decoding DSA public key\n"); CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_FORMAT); } break; } }
/* This is always a DER-encoded blob at the NSS level */ void CL_decodeDistributionPointName( const CSSM_DATA &nssBlob, CE_DistributionPointName &cssmDpn, SecNssCoder &coder, Allocator &alloc) { memset(&cssmDpn, 0, sizeof(CE_DistributionPointName)); if(nssBlob.Length == 0) { clErrorLog("***CL_decodeDistributionPointName: bad PointName\n"); CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT); } unsigned char tag = nssBlob.Data[0] & SEC_ASN1_TAGNUM_MASK; switch(tag) { case NSS_DIST_POINT_FULL_NAME_TAG: { /* decode to temp coder memory */ NSS_GeneralNames gnames; gnames.names = NULL; if(coder.decodeItem(nssBlob, kSecAsn1DistPointFullNameTemplate, &gnames)) { clErrorLog("***Error decoding DistPointFullName\n"); CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT); } cssmDpn.nameType = CE_CDNT_FullName; cssmDpn.dpn.fullName = (CE_GeneralNames *)alloc.malloc( sizeof(CE_GeneralNames)); /* copy out to caller */ CL_nssGeneralNamesToCssm(gnames, *cssmDpn.dpn.fullName, coder, alloc); break; } case NSS_DIST_POINT_RDN_TAG: { /* decode to temp coder memory */ NSS_RDN rdn; memset(&rdn, 0, sizeof(rdn)); if(coder.decodeItem(nssBlob, kSecAsn1DistPointRDNTemplate, &rdn)) { clErrorLog("***Error decoding DistPointRDN\n"); CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT); } cssmDpn.nameType = CE_CDNT_NameRelativeToCrlIssuer; cssmDpn.dpn.rdn = (CSSM_X509_RDN_PTR)alloc.malloc( sizeof(CSSM_X509_RDN)); /* copy out to caller */ CL_nssRdnToCssm(rdn, *cssmDpn.dpn.rdn, alloc, coder); break; } default: clErrorLog("***Bad CE_DistributionPointName tag\n"); CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT); } }
/* top-level PKCS12 PFX decoder */ void P12Coder::decode( CFDataRef cdpfx) { SecNssCoder localCdr; NSS_P12_DecodedPFX pfx; p12DecodeLog("decode"); memset(&pfx, 0, sizeof(pfx)); const CSSM_DATA rawBlob = {int_cast<CFIndex, CSSM_SIZE>(CFDataGetLength(cdpfx)), (uint8 *)CFDataGetBytePtr(cdpfx)}; if(localCdr.decodeItem(rawBlob, NSS_P12_DecodedPFXTemplate, &pfx)) { p12ErrorLog("Error on top-level decode of NSS_P12_DecodedPFX\n"); P12_THROW_DECODE; } NSS_P7_DecodedContentInfo &dci = pfx.authSafe; if(dci.type != CT_Data) { /* no other types supported yet */ p12ErrorLog("bad top-level contentType\n"); P12_THROW_DECODE; } mIntegrityMode = kSecPkcs12ModePassword; if(pfx.macData == NULL) { /* not present is an error in kSecPkcs12ModePassword */ p12ErrorLog("no MAC in PFX\n"); P12_THROW_DECODE; } macParse(*pfx.macData, localCdr); const CSSM_DATA *macPhrase = getMacPassPhrase(); const CSSM_KEY *macPassKey = getMacPassKey(); if((macPhrase == NULL) && (macPassKey == NULL)) { p12ErrorLog("no passphrase set\n"); CssmError::throwMe(CSSMERR_CSP_MISSING_ATTR_PASSPHRASE); } CSSM_RETURN crtn = p12VerifyMac(pfx, mCspHand, macPhrase, macPassKey, localCdr); if(crtn) { p12LogCssmError("p12VerifyMac", crtn); CssmError::throwMe(errSecPkcs12VerifyFailure); } authSafeParse(*dci.content.data, localCdr); /* * On success, if we have a keychain, store certs and CRLs there */ if(mKeychain != NULL) { storeDecodeResults(); } }
/* * CSSM_X509_TYPE_VALUE_PAIR --> NSS_ATV */ void CL_cssmAtvToNss( const CSSM_X509_TYPE_VALUE_PAIR &cssmObj, NSS_ATV &nssObj, SecNssCoder &coder) { memset(&nssObj, 0, sizeof(nssObj)); /* copy the OID */ coder.allocCopyItem(cssmObj.type, nssObj.type); /* tag and value */ nssObj.value.tag = cssmObj.valueType; coder.allocCopyItem(cssmObj.value, nssObj.value.item); }
static int writeAuthSafeContent( const CSSM_DATA &rawBlob, const char *outFile, SecNssCoder &coder, OidParser &parser) { NSS_P12_RawPFX pfx; memset(&pfx, 0, sizeof(pfx)); if(coder.decodeItem(rawBlob, NSS_P12_RawPFXTemplate, &pfx)) { printf("***Error on top-level decode of NSS_P12_RawPFX\n"); return 1; } printf("...version = %u\n", (unsigned)dataToInt(pfx.version)); NSS_P7_RawContentInfo &rci = pfx.authSafe; printf("...contentType = %s\n", oidStr(rci.contentType, parser)); /* parse content per OID the only special case is PKCS7_Data, * which we unwrap from an octet string before writing it */ CSSM_DATA toWrite; if(nssCompareCssmData(&rci.contentType, &CSSMOID_PKCS7_Data)) { if(coder.decodeItem(rci.content, SEC_OctetStringTemplate, &toWrite)) { printf("***Error decoding PKCS7_Data Octet string; writing" " raw contents\n"); toWrite = rci.content; } } else if(nssCompareCssmData(&rci.contentType, &CSSMOID_PKCS7_SignedData)) { /* the only other legal content type here */ /* This is encoded SignedData which I am not even close * to worrying about - Panther p12 won't do this */ toWrite = rci.content; } else { printf("***writeAuthSafeContent: bad contentType\n"); return 1; } if(writeFile(outFile, toWrite.Data, toWrite.Length)) { printf("***Error writing to %s\n", outFile); return 1; } else { printf("...%u bytes written to %s\n", (unsigned)toWrite.Length, outFile); return 0; } }
void CL_infoAccessToCssm( const NSS_AuthorityInfoAccess &nssObj, CE_AuthorityInfoAccess &cdsaObj, SecNssCoder &coder, // for temp decoding Allocator &alloc) { memset(&cdsaObj, 0, sizeof(cdsaObj)); unsigned numDescs = clNssArraySize((const void **)nssObj.accessDescriptions); if(numDescs == 0) { return; } cdsaObj.accessDescriptions = (CE_AccessDescription *)alloc.malloc( numDescs * sizeof(CE_AccessDescription)); cdsaObj.numAccessDescriptions = numDescs; for(unsigned dex=0; dex<numDescs; dex++) { CE_AccessDescription *dst = &cdsaObj.accessDescriptions[dex]; NSS_AccessDescription *src = nssObj.accessDescriptions[dex]; clAllocCopyData(alloc, src->accessMethod, dst->accessMethod); /* decode the general name */ NSS_GeneralName nssGenName; memset(&nssGenName, 0, sizeof(nssGenName)); PRErrorCode prtn = coder.decodeItem(src->encodedAccessLocation, kSecAsn1GeneralNameTemplate, &nssGenName); if(prtn) { clErrorLog("***Error decoding NSS_AuthorityInfoAccess.accessLocation\n"); CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT); } /* then convert the result to CSSM */ CL_nssGeneralNameToCssm(nssGenName, dst->accessLocation, coder, alloc); } }
/* * Some implementations use a two-OID mechanism to specify ECDSA signature * algorithm with a digest of other than SHA1. This is really not necessary; * we use the single-OID method (e.g. CSSMOID_ECDSA_WithSHA512) when * encoding, but we have to accomodate externally generated items with * the two-OID method. This routine decodes the digest OID and infers a * CSSM_ALGORITHMS from it. * Throws CSSMERR_CL_UNKNOWN_FORMAT on any error. */ CSSM_ALGORITHMS CL_nssDecodeECDSASigAlgParams( const CSSM_DATA &encParams, SecNssCoder &coder) { CSSM_X509_ALGORITHM_IDENTIFIER algParams; memset(&algParams, 0, sizeof(algParams)); PRErrorCode prtn = coder.decodeItem(encParams, kSecAsn1AlgorithmIDTemplate, &algParams); if(prtn) { clErrorLog("CL_nssDecodeECDSASigAlgParams: error decoding CSSM_X509_ALGORITHM_IDENTIFIER\n"); CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT); } /* get the digest algorithm, convert to ECDSA w/digest OID */ CSSM_ALGORITHMS digestAlg = CL_oidToAlg(algParams.algorithm); switch(digestAlg) { case CSSM_ALGID_SHA1: return CSSM_ALGID_SHA1WithECDSA; case CSSM_ALGID_SHA224: return CSSM_ALGID_SHA224WithECDSA; case CSSM_ALGID_SHA256: return CSSM_ALGID_SHA256WithECDSA; case CSSM_ALGID_SHA384: return CSSM_ALGID_SHA384WithECDSA; case CSSM_ALGID_SHA512: return CSSM_ALGID_SHA512WithECDSA; default: clErrorLog("CL_nssDecodeECDSASigAlgParams: unknown digest algorithm\n"); CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT); } }
/* * Parse an CSSM_X509_ALGORITHM_IDENTIFIER specific to P12. * Decode the alg params as a NSS_P12_PBE_Params and parse and * return the result if the pbeParams is non-NULL. */ void P12Coder::algIdParse( const CSSM_X509_ALGORITHM_IDENTIFIER &algId, NSS_P12_PBE_Params *pbeParams, // optional SecNssCoder &localCdr) { p12DecodeLog("algIdParse"); const CSSM_DATA ¶m = algId.parameters; if(pbeParams == NULL) { /* alg params are uninterpreted */ return; } if(param.Length == 0) { p12ErrorLog("algIdParse: no alg parameters\n"); P12_THROW_DECODE; } memset(pbeParams, 0, sizeof(*pbeParams)); if(localCdr.decodeItem(param, NSS_P12_PBE_ParamsTemplate, pbeParams)) { p12ErrorLog("Error decoding NSS_P12_PBE_Params\n"); P12_THROW_DECODE; } }
/* uint32 --> CSSM_DATA */ void p12IntToData( uint32 num, CSSM_DATA &cdata, SecNssCoder &coder) { uint32 len = 0; if(num < 0x100) { len = 1; } else if(num < 0x10000) { len = 2; } else if(num < 0x1000000) { len = 3; } else { len = 4; } coder.allocItem(cdata, len); uint8 *cp = &cdata.Data[len - 1]; for(unsigned i=0; i<len; i++) { *cp-- = num & 0xff; num >>= 8; } }
/* * Calculate the MAC for a PFX. Caller is either going compare * the result against an existing PFX's MAC or drop the result into * a newly created PFX. */ CSSM_RETURN p12GenMac( CSSM_CSP_HANDLE cspHand, const CSSM_DATA &ptext, // e.g., NSS_P12_DecodedPFX.derAuthSaafe CSSM_ALGORITHMS alg, // better be SHA1! unsigned iterCount, const CSSM_DATA &salt, /* exactly one of the following two must be valid */ const CSSM_DATA *pwd, // unicode external representation const CSSM_KEY *passKey, SecNssCoder &coder, // for mallocing macData CSSM_DATA &macData) // RETURNED { CSSM_RETURN crtn; CSSM_CC_HANDLE ccHand = 0; /* P12 style key derivation */ unsigned keySizeInBits; CSSM_ALGORITHMS hmacAlg; switch(alg) { case CSSM_ALGID_SHA1: keySizeInBits = 160; hmacAlg = CSSM_ALGID_SHA1HMAC; break; case CSSM_ALGID_MD5: /* not even sure if this is legal in p12 world... */ keySizeInBits = 128; hmacAlg = CSSM_ALGID_MD5HMAC; break; default: return CSSMERR_CSP_INVALID_ALGORITHM; } CSSM_KEY macKey; CSSM_DATA iv = {0, NULL}; crtn = p12KeyGen(cspHand, macKey, false, hmacAlg, alg, keySizeInBits, iterCount, salt, pwd, passKey, iv); if(crtn) { return crtn; } /* subsequent errors to errOut: */ /* prealloc the mac data */ coder.allocItem(macData, keySizeInBits / 8); crtn = CSSM_CSP_CreateMacContext(cspHand, hmacAlg, &macKey, &ccHand); if(crtn) { cuPrintError("CSSM_CSP_CreateMacContext", crtn); goto errOut; } crtn = CSSM_GenerateMac (ccHand, &ptext, 1, &macData); if(crtn) { cuPrintError("CSSM_GenerateMac", crtn); } errOut: if(ccHand) { CSSM_DeleteContext(ccHand); } CSSM_FreeKey(cspHand, NULL, &macKey, CSSM_FALSE); return crtn; }
/* * CSSM time to NSS time. */ void CL_cssmTimeToNss( const CSSM_X509_TIME &cssmTime, NSS_TaggedItem &nssTime, SecNssCoder &coder) { nssTime.tag = cssmTime.timeType; coder.allocCopyItem(cssmTime.time, nssTime.item); }
void p12CfDataToCssm( CFDataRef cf, CSSM_DATA &c, SecNssCoder &coder) { coder.allocCopyItem(CFDataGetBytePtr(cf), CFDataGetLength(cf), c); }
void p12GenSalt( CSSM_DATA &salt, SecNssCoder &coder) { DevRandomGenerator rng; coder.allocItem(salt, P12_SALT_LEN); rng.random(salt.Data, P12_SALT_LEN); }
void CL_cssmAuthorityKeyIdToNss( const CE_AuthorityKeyID &cdsaObj, NSS_AuthorityKeyId &nssObj, SecNssCoder &coder) { memset(&nssObj, 0, sizeof(nssObj)); if(cdsaObj.keyIdentifierPresent) { nssObj.keyIdentifier = (CSSM_DATA_PTR)coder.malloc(sizeof(CSSM_DATA)); coder.allocCopyItem(cdsaObj.keyIdentifier, *nssObj.keyIdentifier); } if(cdsaObj.generalNamesPresent ) { /* GeneralNames, the hard one */ CL_cssmGeneralNamesToNss(*cdsaObj.generalNames, nssObj.genNames, coder); } if(cdsaObj.serialNumberPresent) { coder.allocCopyItem(cdsaObj.serialNumber,nssObj.serialNumber); } }
void CL_cssmDistPointsToNss( const CE_CRLDistPointsSyntax &cdsaObj, NSS_CRLDistributionPoints &nssObj, SecNssCoder &coder) { memset(&nssObj, 0, sizeof(nssObj)); unsigned numPoints = cdsaObj.numDistPoints; if(numPoints == 0) { return; } nssObj.distPoints = (NSS_DistributionPoint **)clNssNullArray(numPoints, coder); for(unsigned dex=0; dex<numPoints; dex++) { nssObj.distPoints[dex] = (NSS_DistributionPoint *) coder.malloc(sizeof(NSS_DistributionPoint)); NSS_DistributionPoint *npoint = nssObj.distPoints[dex]; memset(npoint, 0, sizeof(NSS_DistributionPoint)); CE_CRLDistributionPoint *cpoint = &cdsaObj.distPoints[dex]; /* all fields are optional */ if(cpoint->distPointName) { /* encode and drop into ASN_ANY slot */ npoint->distPointName = (CSSM_DATA *) coder.malloc(sizeof(CSSM_DATA)); CL_encodeDistributionPointName(*cpoint->distPointName, *npoint->distPointName, coder); } if(cpoint->reasonsPresent) { /* bit string, presumed max length 8 bits */ coder.allocItem(npoint->reasons, 1); npoint->reasons.Data[0] = cpoint->reasons; /* adjust for bit string length */ npoint->reasons.Length = 8; } if(cpoint->crlIssuer) { CL_cssmGeneralNamesToNss(*cpoint->crlIssuer, npoint->crlIssuer, coder); } } }
/* CSSM_X509_RDN --> NSS_RDN */ void CL_cssmRdnToNss( const CSSM_X509_RDN &cssmObj, NSS_RDN &nssObj, SecNssCoder &coder) { memset(&nssObj, 0, sizeof(nssObj)); /* alloc NULL-terminated array of ATV pointers */ unsigned numAtvs = cssmObj.numberOfPairs; unsigned size = (numAtvs + 1) * sizeof(void *); nssObj.atvs = (NSS_ATV **)coder.malloc(size); memset(nssObj.atvs, 0, size); /* grind thru the elements */ for(unsigned atvDex=0; atvDex<numAtvs; atvDex++) { nssObj.atvs[atvDex] = (NSS_ATV *)coder.malloc(sizeof(NSS_ATV)); CL_cssmAtvToNss(cssmObj.AttributeTypeAndValue[atvDex], *nssObj.atvs[atvDex], coder); } }
/* * 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; } } }
void CL_nssGeneralNamesToCssm( const NSS_GeneralNames &nssObj, CE_GeneralNames &cdsaObj, SecNssCoder &coder, // for temp decoding Allocator &alloc) // destination { memset(&cdsaObj, 0, sizeof(cdsaObj)); unsigned numNames = clNssArraySize((const void **)nssObj.names); if(numNames == 0) { return; } /* * Decode each name element, currently a raw ASN_ANY blob. * Then convert each result into CDSA form. * This array of (NSS_GeneralName)s is temporary, it doesn't * persist outside of this routine other than the fact that it's * mallocd by the coder arena pool. */ NSS_GeneralName *names = (NSS_GeneralName *)coder.malloc(sizeof(NSS_GeneralName) * numNames); memset(names, 0, sizeof(NSS_GeneralName) * numNames); cdsaObj.generalName = (CE_GeneralName *)alloc.malloc( sizeof(CE_GeneralName) * numNames); cdsaObj.numNames = numNames; for(unsigned dex=0; dex<numNames; dex++) { if(coder.decodeItem(*nssObj.names[dex], kSecAsn1GeneralNameTemplate, &names[dex])) { clErrorLog("***CL_nssGeneralNamesToCssm: Error decoding " "General.name\n"); CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT); } CL_nssGeneralNameToCssm(names[dex], cdsaObj.generalName[dex], coder, alloc); } }
void CL_cssmQualCertStatementsToNss( const CE_QC_Statements &cdsaObj, NSS_QC_Statements &nssObj, SecNssCoder &coder) { memset(&nssObj, 0, sizeof(nssObj)); uint32 numQcs = cdsaObj.numQCStatements; nssObj.qcStatements = (NSS_QC_Statement **)clNssNullArray(numQcs, coder); for(uint32 dex=0; dex<numQcs; dex++) { nssObj.qcStatements[dex] = (NSS_QC_Statement *) coder.malloc(sizeof(NSS_QC_Statement)); NSS_QC_Statement *dst = nssObj.qcStatements[dex]; CE_QC_Statement *src = &cdsaObj.qcStatements[dex]; memset(dst, 0, sizeof(*dst)); coder.allocCopyItem(src->statementId, dst->statementId); if(src->semanticsInfo) { if(src->otherInfo) { /* this is either/or, not both */ CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER); } /* encode this CE_SemanticsInformation */ CE_SemanticsInformation *srcSI = src->semanticsInfo; NSS_SemanticsInformation dstSI; memset(&dstSI, 0, sizeof(dstSI)); if(srcSI->semanticsIdentifier) { dstSI.semanticsIdentifier = (CSSM_DATA_PTR)coder.malloc(sizeof(CSSM_DATA)); coder.allocCopyItem(*srcSI->semanticsIdentifier, *dstSI.semanticsIdentifier); } if(srcSI->nameRegistrationAuthorities) { dstSI.nameRegistrationAuthorities = (NSS_GeneralNames *)coder.malloc(sizeof(NSS_GeneralNames)); CL_cssmGeneralNamesToNss(*srcSI->nameRegistrationAuthorities, *dstSI.nameRegistrationAuthorities, coder); } PRErrorCode prtn = coder.encodeItem(&dstSI, kSecAsn1SemanticsInformationTemplate, dst->info); if(prtn) { clErrorLog("CL_cssmQualCertStatementsToNss: encode error\n"); CssmError::throwMe(CSSMERR_CL_MEMORY_ERROR); } } if(src->otherInfo) { /* drop in as ASN_ANY */ coder.allocCopyItem(*src->otherInfo, dst->info); } } }
/* convert App passphrase to array of chars used in P12 PBE */ void p12ImportPassPhrase( CFStringRef inPhrase, SecNssCoder &coder, CSSM_DATA &outPhrase) { CFDataRef cfData = CFStringCreateExternalRepresentation(NULL, inPhrase, kCFStringEncodingUTF8, 0); if(cfData == NULL) { p12ErrorLog("***p12ImportPassPhrase: can't convert passphrase to UTF8\n"); MacOSError::throwMe(errSecParam); } CFIndex keyLen = CFDataGetLength(cfData); coder.allocItem(outPhrase, keyLen); memmove(outPhrase.Data, CFDataGetBytePtr(cfData), keyLen); CFRelease(cfData); }
/* * Generate random label string to allow associating an imported private * key with a cert. */ void p12GenLabel( CSSM_DATA &label, SecNssCoder &coder) { /* first a random uint32 */ uint8 d[4]; DevRandomGenerator rng; rng.random(d, 4); CSSM_DATA cd = {4, d}; uint32 i; p12DataToInt(cd, i); /* sprintf that into a real string */ coder.allocItem(label, 9); memset(label.Data, 0, 9); sprintf((char *)label.Data, "%08X", (unsigned)i); }
/* CSSM_X509_NAME --> NSS_Name */ void CL_cssmNameToNss( const CSSM_X509_NAME &cssmObj, NSS_Name &nssObj, SecNssCoder &coder) { memset(&nssObj, 0, sizeof(nssObj)); /* alloc NULL-terminated array of RDN pointers */ unsigned numRdns = cssmObj.numberOfRDNs; nssObj.rdns = (NSS_RDN **)clNssNullArray(numRdns, coder); /* grind thru the elements */ for(unsigned rdnDex=0; rdnDex<numRdns; rdnDex++) { nssObj.rdns[rdnDex] = (NSS_RDN *)coder.malloc(sizeof(NSS_RDN)); CL_cssmRdnToNss(cssmObj.RelativeDistinguishedName[rdnDex], *nssObj.rdns[rdnDex], coder); } }
/* * Attempt to convert a CFStringRef, which represents a SafeBag's * FriendlyName, to a UTF8-encoded CSSM_DATA. The CSSM_DATA and its * referent are allocated in the specified SecNssCoder's memory. * No guarantee that this conversion works. If it doesn't we return * NULL and caller must be prepared to deal with that. */ CSSM_DATA_PTR p12StringToUtf8( CFStringRef cfStr, SecNssCoder &coder) { if(cfStr == NULL) { return NULL; } CFIndex strLen = CFStringGetLength(cfStr); if(strLen == 0) { return NULL; } CSSM_DATA_PTR rtn = coder.mallocn<CSSM_DATA>(); coder.allocItem(*rtn, strLen + 1); if(!CFStringGetCString(cfStr, (char *)rtn->Data,strLen + 1, kCFStringEncodingUTF8)) { /* not convertible from native Unicode to UTF8 */ return NULL; } return rtn; }
/* * 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); } }
void CL_encodeDistributionPointName( CE_DistributionPointName &cpoint, CSSM_DATA &npoint, SecNssCoder &coder) { const SecAsn1Template *templ = NULL; NSS_GeneralNames gnames; NSS_RDN rdn; void *encodeSrc = NULL; /* * Our job is to convert one of two incoming aggregate types * into NSS format, then encode the result into npoint. */ switch(cpoint.nameType) { case CE_CDNT_FullName: CL_cssmGeneralNamesToNss(*cpoint.dpn.fullName, gnames, coder); encodeSrc = &gnames; templ = kSecAsn1DistPointFullNameTemplate; break; case CE_CDNT_NameRelativeToCrlIssuer: CL_cssmRdnToNss(*cpoint.dpn.rdn, rdn, coder); encodeSrc = &rdn; templ = kSecAsn1DistPointRDNTemplate; break; default: clErrorLog("CL_encodeDistributionPointName: bad nameType\n"); CssmError::throwMe(CSSMERR_CL_UNKNOWN_TAG); } if(coder.encodeItem(encodeSrc, templ, npoint)) { clErrorLog("CL_encodeDistributionPointName: encode error\n"); CssmError::throwMe(CSSMERR_CL_MEMORY_ERROR); } }
/* * Given an array of PEM parameter lines, infer parameters for key derivation and * encryption. */ static OSStatus opensslPbeParams( CFArrayRef paramLines, // elements are CFStrings SecNssCoder &coder, // IV allocd with this /* remaining arguments RETURNED */ CSSM_ALGORITHMS &pbeAlg, CSSM_ALGORITHMS &keyAlg, CSSM_ALGORITHMS &encrAlg, CSSM_ENCRYPT_MODE &encrMode, CSSM_PADDING &encrPad, uint32 &keySizeInBits, unsigned &blockSizeInBytes, CSSM_DATA &iv) { /* * This format requires PEM parameter lines. We could have gotten here * without them if caller specified wrong format. */ if(paramLines == NULL) { SecImpExpDbg("importWrappedKeyOpenssl: no PEM parameter lines"); return errSecUnknownFormat; } CFStringRef dekInfo = NULL; CFIndex numLines = CFArrayGetCount(paramLines); for(CFIndex dex=0; dex<numLines; dex++) { CFStringRef str = (CFStringRef)CFArrayGetValueAtIndex(paramLines, dex); CFRange range; range = CFStringFind(str, CFSTR("DEK-Info: "), 0); if(range.length != 0) { dekInfo = str; break; } } if(dekInfo == NULL) { SecImpExpDbg("importWrappedKeyOpenssl: no DEK-Info lines"); return errSecUnknownFormat; } /* drop down to C strings for low level grunging */ char cstr[1024]; if(!CFStringGetCString(dekInfo, cstr, sizeof(cstr), kCFStringEncodingASCII)) { SecImpExpDbg("importWrappedKeyOpenssl: bad DEK-Info line (1)"); return errSecUnknownFormat; } /* * This line looks like this: * DEK-Info: DES-CBC,A22977A0A6A6F696 * * Now parse, getting the cipher spec and the IV. */ char *cp = strchr(cstr, ':'); if(cp == NULL) { SecImpExpDbg("importWrappedKeyOpenssl: bad DEK-Info line (2)"); return errSecUnknownFormat; } if((cp[1] == ' ') && (cp[2] != '\0')) { /* as it normally does... */ cp += 2; } /* We only support DES and 3DES here */ if(!strncmp(cp, "DES-EDE3-CBC", 12)) { keyAlg = CSSM_ALGID_3DES_3KEY; encrAlg = CSSM_ALGID_3DES_3KEY_EDE; keySizeInBits = 64 * 3; blockSizeInBytes = 8; } else if(!strncmp(cp, "DES-CBC", 7)) { keyAlg = CSSM_ALGID_DES; encrAlg = CSSM_ALGID_DES; keySizeInBits = 64; blockSizeInBytes = 8; } else { SecImpExpDbg("importWrappedKeyOpenssl: unrecognized wrap alg (%s)", cp); return errSecUnknownFormat; } /* these are more or less fixed */ pbeAlg = CSSM_ALGID_PBE_OPENSSL_MD5; encrMode = CSSM_ALGMODE_CBCPadIV8; encrPad = CSSM_PADDING_PKCS7; /* now get the ASCII hex version of the IV */ cp = strchr(cp, ','); if(cp == NULL) { SecImpExpDbg("importWrappedKeyOpenssl: No IV in DEK-Info line"); return errSecUnknownFormat; } if(cp[1] != '\0') { cp++; } /* remainder should be just the IV */ if(strlen(cp) != (blockSizeInBytes * 2)) { SecImpExpDbg("importWrappedKeyOpenssl: bad IV in DEK-Info line (1)"); return errSecUnknownFormat; } coder.allocItem(iv, blockSizeInBytes); for(unsigned dex=0; dex<blockSizeInBytes; dex++) { if(hexToUchar(cp + (dex * 2), &iv.Data[dex])) { SecImpExpDbg("importWrappedKeyOpenssl: bad IV in DEK-Info line (2)"); return errSecUnknownFormat; } } return errSecSuccess; }