/* 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); } }
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; } }
/* * 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; } }
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); } }
/* * 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; } }
/* * 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; } } }
/* 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(); } }
/* * 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_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_nssGeneralNameToCssm( NSS_GeneralName &nssObj, CE_GeneralName &cdsaObj, SecNssCoder &coder, // for temp decoding Allocator &alloc) // destination { memset(&cdsaObj, 0, sizeof(cdsaObj)); PRErrorCode prtn; /* for caller's CE_GeneralName */ CSSM_BOOL berEncoded = CSSM_FALSE; CE_GeneralNameType cdsaTag; /* * At this point, depending on the decoded object's tag, we either * have the final bytes to copy out, or we need to decode further. * After this switch, if doCopy is true, give the caller a copy * of nssObj.item. */ bool doCopy = true; switch(nssObj.tag) { case NGT_OtherName: // ASN_ANY -> CE_OtherName { cdsaTag = GNT_OtherName; /* decode to coder memory */ CE_OtherName *nssOther = (CE_OtherName *)coder.malloc(sizeof(CE_OtherName)); memset(nssOther, 0, sizeof(CE_OtherName)); prtn = coder.decodeItem(nssObj.item, kSecAsn1GenNameOtherNameTemplate, nssOther); if(prtn) { clErrorLog("CL_nssGeneralNameToCssm: error decoding " "OtherName\n"); CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT); } /* copy out to caller */ clAllocData(alloc, cdsaObj.name, sizeof(CE_OtherName)); clCopyOtherName(*nssOther, *((CE_OtherName *)cdsaObj.name.Data), alloc); doCopy = false; break; } case NGT_RFC822Name: // IA5String, done cdsaTag = GNT_RFC822Name; break; case NGT_DNSName: // IA5String cdsaTag = GNT_DNSName; break; case NGT_X400Address: // ASY_ANY, leave alone cdsaTag = GNT_X400Address; berEncoded = CSSM_TRUE; break; case NGT_DirectoryName: // ASN_ANY --> NSS_Name { cdsaTag = GNT_DirectoryName; /* Decode to coder memory */ NSS_Name *nssName = (NSS_Name *)coder.malloc(sizeof(NSS_Name)); memset(nssName, 0, sizeof(NSS_Name)); prtn = coder.decodeItem(nssObj.item, kSecAsn1NameTemplate, nssName); if(prtn) { clErrorLog("CL_nssGeneralNameToCssm: error decoding " "NSS_Name\n"); CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT); } /* convert & copy out to caller */ clAllocData(alloc, cdsaObj.name, sizeof(CSSM_X509_NAME)); CL_nssNameToCssm(*nssName, *((CSSM_X509_NAME *)cdsaObj.name.Data), alloc); doCopy = false; break; } case NGT_EdiPartyName: // ASN_ANY, leave alone cdsaTag = GNT_EdiPartyName; berEncoded = CSSM_TRUE; break; case NGT_URI: // IA5String cdsaTag = GNT_URI; break; case NGT_IPAddress: // OCTET_STRING cdsaTag = GNT_IPAddress; break; case NGT_RegisteredID: // OID cdsaTag = GNT_RegisteredID; break; default: clErrorLog("CL_nssGeneralNameToCssm: bad name tag\n"); CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT); } cdsaObj.nameType = cdsaTag; cdsaObj.berEncoded = berEncoded; if(doCopy) { clAllocCopyData(alloc, nssObj.item, cdsaObj.name); } }
void CL_qualCertStatementsToCssm( const NSS_QC_Statements &nssObj, CE_QC_Statements &cdsaObj, SecNssCoder &coder, // for temp decoding Allocator &alloc) { memset(&cdsaObj, 0, sizeof(cdsaObj)); unsigned numQcs = clNssArraySize((const void **)nssObj.qcStatements); if(numQcs == 0) { return; } cdsaObj.qcStatements = (CE_QC_Statement *)alloc.malloc( numQcs * sizeof(CE_AccessDescription)); cdsaObj.numQCStatements = numQcs; for(unsigned dex=0; dex<numQcs; dex++) { CE_QC_Statement *dst = &cdsaObj.qcStatements[dex]; NSS_QC_Statement *src = nssObj.qcStatements[dex]; memset(dst, 0, sizeof(*dst)); clAllocCopyData(alloc, src->statementId, dst->statementId); /* * Whether the optional info is a SemanticsInformation or is uninterpreted * DER data depends on statementId. */ if(src->info.Data) { if(clCompareCssmData(&src->statementId, &CSSMOID_OID_QCS_SYNTAX_V2)) { NSS_SemanticsInformation srcSI; memset(&srcSI, 0, sizeof(srcSI)); /* decode info as a NSS_SemanticsInformation */ PRErrorCode prtn = coder.decodeItem(src->info, kSecAsn1SemanticsInformationTemplate, &srcSI); if(prtn) { clErrorLog("***Error decoding CE_SemanticsInformation\n"); CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT); } /* NSS_SemanticsInformation --> CE_SemanticsInformation */ dst->semanticsInfo = (CE_SemanticsInformation *)alloc.malloc(sizeof(CE_SemanticsInformation)); CE_SemanticsInformation *dstSI = dst->semanticsInfo; memset(dstSI, 0, sizeof(*dstSI)); if(srcSI.semanticsIdentifier) { dstSI->semanticsIdentifier = (CSSM_OID *)alloc.malloc(sizeof(CSSM_OID)); clAllocCopyData(alloc, *srcSI.semanticsIdentifier, *dstSI->semanticsIdentifier); } if(srcSI.nameRegistrationAuthorities) { dstSI->nameRegistrationAuthorities = (CE_NameRegistrationAuthorities *)alloc.malloc( sizeof(CE_NameRegistrationAuthorities)); CL_nssGeneralNamesToCssm(*srcSI.nameRegistrationAuthorities, *dstSI->nameRegistrationAuthorities, coder, alloc); } } else { dst->otherInfo = (CSSM_DATA_PTR)alloc.malloc(sizeof(CSSM_DATA)); clAllocCopyData(alloc, src->info, *dst->otherInfo); } } } }