void CL_nssDistPointsToCssm( const NSS_CRLDistributionPoints &nssObj, CE_CRLDistPointsSyntax &cdsaObj, SecNssCoder &coder, // for temp decoding Allocator &alloc) { memset(&cdsaObj, 0, sizeof(cdsaObj)); unsigned numPoints = clNssArraySize((const void **)nssObj.distPoints); if(numPoints == 0) { return; } unsigned len = sizeof(CE_CRLDistributionPoint) * numPoints; cdsaObj.distPoints = (CE_CRLDistributionPoint *)alloc.malloc(len); memset(cdsaObj.distPoints, 0, len); cdsaObj.numDistPoints = numPoints; for(unsigned dex=0; dex<numPoints; dex++) { CE_CRLDistributionPoint &cpoint = cdsaObj.distPoints[dex]; NSS_DistributionPoint &npoint = *(nssObj.distPoints[dex]); /* All three fields are optional */ if(npoint.distPointName != NULL) { /* Drop in a CE_DistributionPointName */ CE_DistributionPointName *cname = (CE_DistributionPointName *)alloc.malloc( sizeof(CE_DistributionPointName)); memset(cname, 0, sizeof(*cname)); cpoint.distPointName = cname; /* * This one is currently still encoded; we have to peek * at its tag and decode accordingly. */ CL_decodeDistributionPointName(*npoint.distPointName, *cname, coder, alloc); } if(npoint.reasons.Data != NULL) { /* careful, it's a bit string */ if(npoint.reasons.Length > 8) { clErrorLog("***CL_nssDistPointsToCssm: Malformed reasons\n"); CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT); } cpoint.reasonsPresent = CSSM_TRUE; if(npoint.reasons.Length != 0) { cpoint.reasons = npoint.reasons.Data[0]; } } if(npoint.crlIssuer.names != NULL) { /* Cook up a new CE_GeneralNames */ cpoint.crlIssuer = (CE_GeneralNames *)alloc.malloc(sizeof(CE_GeneralNames)); CL_nssGeneralNamesToCssm(npoint.crlIssuer, *cpoint.crlIssuer, coder, alloc); } } }
/* * Given a fully encoded BER object, create a CSSM_X509EXT_TAGandVALUE * representing it. We malloc the CSSM_X509EXT_TAGandVALUE itself using * specified allocator, but the referent (in CSSM_X509EXT_TAGandVALUE.value) * merely points to data inside the berValue. */ CSSM_X509EXT_TAGandVALUE *DecodedExten::createTagAndValue( const CSSM_DATA &berValue, Allocator &alloc) const { if((berValue.Data == NULL) || (berValue.Length == 0)) { return NULL; } CSSM_X509EXT_TAGandVALUE *tv = (CSSM_X509EXT_TAGandVALUE *) alloc.malloc(sizeof(CSSM_X509EXT_TAGandVALUE)); // Important: by the time we get called, the extension data // has already been deconstructed, and the raw value we are // handed in berValue does not include ASN.1 type or length. // Since createTagAndValue is only called in the case where // the contents are unknown (and thus opaque), always treat // as an octet string. tv->type = SEC_ASN1_OCTET_STRING; tv->value.Length = berValue.Length; tv->value.Data = berValue.Data; return tv; #if 0 tv->type = berValue.Data[0]; /* * length of length is variable; ASN spec says it can actually be up to * 127 bytes, but we only have room for 32 bits! */ const uint8 *lp = berValue.Data + 1; uint8 len1 = *lp; if((len1 & 0x80) == 0) { /* short form */ tv->value.Length = len1; tv->value.Data = const_cast<uint8 *>(lp + 1); return tv; } unsigned numLenBytes = len1 & 0x7f; if(numLenBytes > 4) { clErrorLog("createTagAndValue: impossible length of length (%u)\n", numLenBytes); alloc.free(tv); CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT); } uint32 len = 0; lp++; // points to first length byte for(uint32 dex=0; dex<numLenBytes; dex++) { len <<= 8; len += *lp; lp++; } tv->value.Length = len; tv->value.Data = const_cast<uint8 *>(lp); return tv; #endif }
CSSM_ALGORITHMS CL_oidToAlg( const CSSM_OID &oid) { CSSM_ALGORITHMS alg; bool found = cssmOidToAlg(&oid, &alg); if(!found) { clErrorLog("CL_oidToAlg: unknown alg\n"); CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT); } return alg; }
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); } } }
/* * GIven a CSSM_DATA containing a decoded BIT_STRING, * convert to a KeyUsage. */ CE_KeyUsage clBitStringToKeyUsage( const CSSM_DATA &cdata) { unsigned toCopy = (cdata.Length + 7) / 8; if(toCopy > 2) { /* I hope I never see this... */ clErrorLog("clBitStringToKeyUsage: KeyUsage larger than 2 bytes!"); toCopy = 2; } unsigned char bits[2] = {0, 0}; memmove(bits, cdata.Data, toCopy); CE_KeyUsage usage = (((unsigned)bits[0]) << 8) | bits[1]; return usage; }
/* * Encode into a NSS-style Extensions. * * Each extension object, currently stored as some AsnType subclass, * is BER-encoded and the result is stored as an octet string * (AsnOcts) in a new Extension object in the TBS. * * Called from {Crl,Cert}CreateTemplate via encode{Tbs,Cts}(). */ void DecodedExtensions::encodeToNss( NSS_CertExtension **&extensions) { assert(extensions == NULL); if(mNumExtensions == 0) { /* no extensions, no error */ return; } /* malloc a NULL_terminated array of NSS_CertExtension pointers */ unsigned len = (mNumExtensions + 1) * sizeof(NSS_CertExtension *); extensions = (NSS_CertExtension **)mCoder.malloc(len); memset(extensions, 0, len); /* grind thru our DecodedExtens, creating an NSS_CertExtension for * each one */ for(unsigned extenDex=0; extenDex<mNumExtensions; extenDex++) { NSS_CertExtension *thisNssExten = (NSS_CertExtension *)mCoder.malloc(sizeof(NSS_CertExtension)); memset(thisNssExten, 0, sizeof(NSS_CertExtension)); extensions[extenDex] = thisNssExten; const DecodedExten *decodedExt = getExtension(extenDex); /* BER-encode the extension object if appropriate */ if(decodedExt->berEncoded()) { /* unknown extension type, it's already encoded */ const CSSM_DATA *srcBer = (const CSSM_DATA *)decodedExt->rawExtn(); assert(srcBer != NULL); mCoder.allocCopyItem(*srcBer, thisNssExten->value); } else { PRErrorCode prtn; prtn = mCoder.encodeItem(decodedExt->nssObj(), decodedExt->templ(), thisNssExten->value); if(prtn) { clErrorLog("encodeToNss: extension encode error"); CssmError::throwMe(CSSMERR_CL_INTERNAL_ERROR); } } ArenaAllocator arenaAlloc(mCoder); if(decodedExt->critical()) { /* optional, default false */ clCssmBoolToNss(CSSM_TRUE, thisNssExten->critical, arenaAlloc); } mCoder.allocCopyItem(decodedExt->extnId(), thisNssExten->extnId); } }
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); } }
/* map an OID to an oidToFieldFuncs */ static const oidToFieldFuncs *oidToFields( const CssmOid &fieldId) { const oidToFieldFuncs *fieldTable = fieldFuncTable; for(unsigned i=0; i<NUM_KNOWN_FIELDS; i++) { if(fieldId == CssmData::overlay(*fieldTable->fieldId)) { return fieldTable; } fieldTable++; } #ifndef NDEBUG clErrorLog("oidToFields: unknown OID (len=%d): %s\n", (int)fieldId.length(), fieldId.toHex().c_str()); #endif CssmError::throwMe(CSSMERR_CL_UNKNOWN_TAG); }
/* * Obtain the index'th occurrence of field specified by fieldId in specified cert. * Format of the returned field depends on fieldId. * Returns total number of fieldId fields in the cert if index is 0. * FieldValue assumed to be empty on entry. * Returns true if specified field was found, else returns false. */ bool DecodedCert::getCertFieldData( const CssmOid &fieldId, // which field unsigned index, // which occurrence (0 = first) uint32 &numFields, // RETURNED CssmOwnedData &fieldValue) // RETURNED { switch(mState) { case IS_Empty: case IS_Building: clErrorLog("DecodedCert::getCertField: can't parse undecoded cert!"); CssmError::throwMe(CSSMERR_CL_INTERNAL_ERROR); case IS_DecodedAll: case IS_DecodedTBS: break; } const oidToFieldFuncs *fieldFuncs = oidToFields(fieldId); return fieldFuncs->getFcn(*this, index, numFields, fieldValue); }
/* * Given a fully encoded BER object, create a CSSM_X509EXT_TAGandVALUE * representing it. We malloc the CSSM_X509EXT_TAGandVALUE itself using * specified allocator, but the referent (in CSSM_X509EXT_TAGandVALUE.value) * merely points to data inside the berValue. */ CSSM_X509EXT_TAGandVALUE *DecodedExten::createTagAndValue( const CSSM_DATA &berValue, Allocator &alloc) const { if((berValue.Data == NULL) || (berValue.Length == 0)) { return NULL; } CSSM_X509EXT_TAGandVALUE *tv = (CSSM_X509EXT_TAGandVALUE *) alloc.malloc(sizeof(CSSM_X509EXT_TAGandVALUE)); tv->type = berValue.Data[0]; /* * length of length is variable; ASN spec says it can actually be up to * 127 bytes, but we only have room for 32 bits! */ const uint8 *lp = berValue.Data + 1; uint8 len1 = *lp; if((len1 & 0x80) == 0) { /* short form */ tv->value.Length = len1; tv->value.Data = const_cast<uint8 *>(lp + 1); return tv; } unsigned numLenBytes = len1 & 0x7f; if(numLenBytes > 4) { clErrorLog("createTagAndValue: impossible length of length (%u)\n", numLenBytes); alloc.free(tv); CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT); } uint32 len = 0; lp++; // points to first length byte for(uint32 dex=0; dex<numLenBytes; dex++) { len <<= 8; len += *lp; lp++; } tv->value.Length = len; tv->value.Data = const_cast<uint8 *>(lp); return tv; }
bool getFieldKeyUsage( DecodedItem &cert, unsigned index, // which occurrence (0 = first) uint32 &numFields, // RETURNED CssmOwnedData &fieldValue) { const DecodedExten *decodedExt; CSSM_DATA *nssObj; CE_KeyUsage *cdsaObj; bool brtn; brtn = cert.GetExtenTop<CSSM_DATA, CE_KeyUsage>( index, numFields, fieldValue.allocator, CSSMOID_KeyUsage, nssObj, cdsaObj, decodedExt); if(!brtn) { return false; } /* make a copy - can't modify length in place */ CSSM_DATA bitString = *nssObj; clNssBitStringToCssm(bitString); size_t toCopy = bitString.Length; if(toCopy > 2) { /* I hope I never see this... */ clErrorLog("getFieldKeyUsage: KeyUsage larger than 2 bytes!"); toCopy = 2; } unsigned char bits[2] = {0, 0}; memmove(bits, bitString.Data, toCopy); *cdsaObj = (((unsigned)bits[0]) << 8) | bits[1]; /* pass back to caller */ getFieldExtenCommon(cdsaObj, *decodedExt, fieldValue); return true; }
/* * Common routime to free a CSSM_X509_EXTENSIONS. Used to free * CSSM_X509_TBS_CERTLIST.extensions and * CSSM_X509_REVOKED_CERT_ENTRY.extensions. * We just cook up a CssmOid and a CssmOwnedData for each extension * and pass to CL_freeCrlFieldData(). */ static void CL_freeCssmExtensions( CSSM_X509_EXTENSIONS &extens, Allocator &alloc) { for(uint32 dex=0; dex<extens.numberOfExtensions; dex++) { CSSM_X509_EXTENSION_PTR exten = &extens.extensions[dex]; const CSSM_OID *fieldOid; /* * The field OID is either the same as the extension's OID (if we parsed * it) or CSSMOID_X509V3CertificateExtensionCStruct (if we didn't). */ switch(exten->format) { case CSSM_X509_DATAFORMAT_ENCODED: fieldOid = &CSSMOID_X509V3CertificateExtensionCStruct; break; case CSSM_X509_DATAFORMAT_PARSED: case CSSM_X509_DATAFORMAT_PAIR: fieldOid = &exten->extnId; break; default: clErrorLog("CL_freeCssmExtensions: bad exten->format (%d)", (int)exten->format); CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER); } const CssmOid &fieldId = CssmOid::overlay(*fieldOid); if (exten->extnId.Data != NULL) // if this is null, something threw when it was instantiated { CssmData cData((uint8 *)exten, sizeof(CSSM_X509_EXTENSION)); CssmRemoteData fieldValue(alloc, cData); CL_freeCrlFieldData(fieldId, fieldValue, false); fieldValue.release(); // but no free (via reset() */ } } alloc.free(extens.extensions); memset(&extens, 0, sizeof(CSSM_X509_EXTENSIONS)); }
/* * Set the field specified by fieldId in the specified Cert. * Note no index - individual field routines either append (for extensions) * or if field already set ::throwMe(for all others) */ void DecodedCert::setCertField( const CssmOid &fieldId, // which field const CssmData &fieldValue) { switch(mState) { case IS_Empty: // first time thru mState = IS_Building; break; case IS_Building: // subsequent passes break; case IS_DecodedAll: case IS_DecodedTBS: clErrorLog("DecodedCert::setCertField: can't build on a decoded cert!"); CssmError::throwMe(CSSMERR_CL_INTERNAL_ERROR); } if((fieldValue.data() == NULL) || (fieldValue.length() == 0)) { CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER); } const oidToFieldFuncs *fieldFuncs = oidToFields(fieldId); const CssmData &value = CssmData::overlay(fieldValue); fieldFuncs->setFcn(*this, value); }
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); } }
bool AppleX509CLSession::CrlGetNextFieldValue( CSSM_HANDLE ResultsHandle, CSSM_DATA_PTR &Value) { /* fetch & validate the query */ CLQuery *query = queryMap.lookupEntry(ResultsHandle); if(query == NULL) { CssmError::throwMe(CSSMERR_CL_INVALID_RESULTS_HANDLE); } if(query->queryType() != CLQ_CRL) { clErrorLog("CrlGetNextFieldValue: bad queryType (%d)", (int)query->queryType()); CssmError::throwMe(CSSMERR_CL_INVALID_RESULTS_HANDLE); } if(query->nextIndex() >= query->numFields()) { return false; } /* fetch the associated cached CRL */ CLCachedCRL *cachedCrl = lookupCachedCRL(query->cachedObject()); uint32 dummy; CssmAutoData aData(*this); if(!cachedCrl->crl().getCrlFieldData(query->fieldId(), query->nextIndex(), dummy, aData)) { return false; } /* success - copy field data to outgoing Value */ Value = (CSSM_DATA_PTR)malloc(sizeof(CSSM_DATA)); *Value = aData.release(); query->incrementIndex(); return true; }
/* encode TBS component; only called from CertCreateTemplate */ void DecodedCert::encodeTbs( CssmOwnedData &encodedTbs) { encodeExtensions(); assert(mState == IS_Building); /* enforce required fields - could go deeper, maybe we should */ NSS_TBSCertificate &tbs = mCert.tbs; if((tbs.signature.algorithm.Data == NULL) || (tbs.issuer.rdns == NULL) || (tbs.subject.rdns == NULL) || (tbs.subjectPublicKeyInfo.subjectPublicKey.Data == NULL)) { clErrorLog("DecodedCert::encodeTbs: incomplete TBS"); /* an odd, undocumented error return */ CssmError::throwMe(CSSMERR_CL_NO_FIELD_VALUES); } PRErrorCode prtn; prtn = SecNssEncodeItemOdata(&tbs, kSecAsn1TBSCertificateTemplate, encodedTbs); if(prtn) { CssmError::throwMe(CSSMERR_CL_MEMORY_ERROR); } }
/* * Obtain a CSSM_KEY from a CSSM_X509_SUBJECT_PUBLIC_KEY_INFO, * inferring as much as we can from required fields * (CSSM_X509_SUBJECT_PUBLIC_KEY_INFO) and extensions (for * KeyUse, obtained from the optional DecodedCert). */ CSSM_KEY_PTR CL_extractCSSMKeyNSS( const CSSM_X509_SUBJECT_PUBLIC_KEY_INFO &keyInfo, Allocator &alloc, const DecodedCert *decodedCert) // optional { CSSM_KEY_PTR cssmKey = (CSSM_KEY_PTR) alloc.malloc(sizeof(CSSM_KEY)); memset(cssmKey, 0, sizeof(CSSM_KEY)); CSSM_KEYHEADER &hdr = cssmKey->KeyHeader; CssmRemoteData keyData(alloc, cssmKey->KeyData); hdr.HeaderVersion = CSSM_KEYHEADER_VERSION; /* CspId blank */ hdr.BlobType = CSSM_KEYBLOB_RAW; hdr.AlgorithmId = CL_oidToAlg(keyInfo.algorithm.algorithm); hdr.KeyAttr = CSSM_KEYATTR_MODIFIABLE | CSSM_KEYATTR_EXTRACTABLE; /* * Format inferred from AlgorithmId. I have never seen these defined * anywhere, e.g., what's the format of an RSA public key in a cert? * X509 certainly doesn't say. However. the following two cases are * known to be correct. */ switch(hdr.AlgorithmId) { case CSSM_ALGID_RSA: hdr.Format = CSSM_KEYBLOB_RAW_FORMAT_PKCS1; break; case CSSM_ALGID_DSA: case CSSM_ALGID_ECDSA: case CSSM_ALGID_DH: case CSSM_ALGMODE_PKCS1_EME_OAEP: hdr.Format = CSSM_KEYBLOB_RAW_FORMAT_X509; break; case CSSM_ALGID_FEE: /* CSSM_KEYBLOB_RAW_FORMAT_NONE --> DER encoded */ hdr.Format = CSSM_KEYBLOB_RAW_FORMAT_NONE; break; default: /* punt */ hdr.Format = CSSM_KEYBLOB_RAW_FORMAT_NONE; } hdr.KeyClass = CSSM_KEYCLASS_PUBLIC_KEY; /* KeyUsage inferred from extensions */ if(decodedCert) { hdr.KeyUsage = decodedCert->inferKeyUsage(); } else { hdr.KeyUsage = CSSM_KEYUSE_ANY; } /* start/end date unknown, leave zero */ hdr.WrapAlgorithmId = CSSM_ALGID_NONE; hdr.WrapMode = CSSM_ALGMODE_NONE; switch(hdr.AlgorithmId) { case CSSM_ALGID_DSA: case CSSM_ALGID_ECDSA: case CSSM_ALGID_DH: case CSSM_ALGMODE_PKCS1_EME_OAEP: { /* * Just encode the whole subject public key info blob. * NOTE we're assuming that the keyInfo.subjectPublicKey * field is in the NSS_native BITSTRING format, i.e., * its Length field is in bits and we don't have to adjust. */ PRErrorCode prtn = SecNssEncodeItemOdata(&keyInfo, kSecAsn1SubjectPublicKeyInfoTemplate, keyData); if(prtn) { clErrorLog("extractCSSMKey: error on reencode\n"); CssmError::throwMe(CSSMERR_CL_MEMORY_ERROR); } break; } default: /* * RSA, FEE for now. * keyInfo.subjectPublicKey (in BITS) ==> KeyData */ keyData.copy(keyInfo.subjectPublicKey.Data, (keyInfo.subjectPublicKey.Length + 7) / 8); } /* * LogicalKeySizeInBits - ask the CSP */ CSSM_CSP_HANDLE cspHand = getGlobalCspHand(true); CSSM_KEY_SIZE keySize; CSSM_RETURN crtn; crtn = CSSM_QueryKeySizeInBits(cspHand, CSSM_INVALID_HANDLE, cssmKey, &keySize); switch(crtn) { default: CssmError::throwMe(crtn); case CSSMERR_CSP_APPLE_PUBLIC_KEY_INCOMPLETE: /* * This is how the CSP indicates a "partial" public key, * with a valid public key value but no alg-specific * parameters (currently, DSA only). */ hdr.KeyAttr |= CSSM_KEYATTR_PARTIAL; /* and drop thru */ case CSSM_OK: cssmKey->KeyHeader.LogicalKeySizeInBits = keySize.LogicalKeySizeInBits; break; } keyData.release(); return cssmKey; }
void setFieldCertPolicies( DecodedItem &cert, const CssmData &fieldValue) { CSSM_X509_EXTENSION_PTR cssmExt = verifySetFreeExtension(fieldValue, false); SecNssCoder &coder = cert.coder(); NSS_CertPolicies *nssObj = (NSS_CertPolicies *)coder.malloc(sizeof(NSS_CertPolicies)); memset(nssObj, 0, sizeof(NSS_CertPolicies)); CE_CertPolicies *cdsaObj = (CE_CertPolicies *)cssmExt->value.parsedValue; if(cdsaObj->numPolicies) { nssObj->policies = (NSS_PolicyInformation **)clNssNullArray( cdsaObj->numPolicies, coder); } for(unsigned polDex=0; polDex<cdsaObj->numPolicies; polDex++) { CE_PolicyInformation *cPolInfo = &cdsaObj->policies[polDex]; NSS_PolicyInformation *nPolInfo = (NSS_PolicyInformation *) coder.malloc(sizeof(NSS_PolicyInformation)); memset(nPolInfo, 0, sizeof(*nPolInfo)); nssObj->policies[polDex] = nPolInfo; coder.allocCopyItem(cPolInfo->certPolicyId, nPolInfo->certPolicyId); unsigned numQual = cPolInfo->numPolicyQualifiers; if(numQual != 0) { nPolInfo->policyQualifiers = (NSS_PolicyQualifierInfo **)clNssNullArray(numQual, coder); } for(unsigned qualDex=0; qualDex<numQual; qualDex++) { CE_PolicyQualifierInfo *cQualInfo = &cPolInfo->policyQualifiers[qualDex]; NSS_PolicyQualifierInfo *nQualInfo = (NSS_PolicyQualifierInfo *)coder.malloc( sizeof(NSS_PolicyQualifierInfo)); memset(nQualInfo, 0, sizeof(NSS_PolicyQualifierInfo)); nPolInfo->policyQualifiers[qualDex] = nQualInfo; /* * OK we're at the lowest level. * policyQualifierId == id_qt_cps: qualifier is * an IA5 string, incoming data is its contents. * Else incoming data is an encoded blob we pass on directly. */ coder.allocCopyItem(cQualInfo->policyQualifierId, nQualInfo->policyQualifierId); if(clCompareCssmData(&cQualInfo->policyQualifierId, &CSSMOID_QT_CPS)) { if(coder.encodeItem(&cQualInfo->qualifier, kSecAsn1IA5StringTemplate, nQualInfo->qualifier)) { clErrorLog("setFieldCertPOlicies: IA5 encode error\n"); CssmError::throwMe(CSSMERR_CL_MEMORY_ERROR); } } else { /* uninterpreted, copy over directly */ coder.allocCopyItem(cQualInfo->qualifier, nQualInfo->qualifier); } } /* for each qualifier */ } /* for each policy */ /* add to mExtensions */ cert.addExtension(nssObj, cssmExt->extnId, cssmExt->critical, false, kSecAsn1CertPoliciesTemplate); }
bool getFieldCertPolicies( DecodedItem &cert, unsigned index, // which occurrence (0 = first) uint32 &numFields, // RETURNED CssmOwnedData &fieldValue) { const DecodedExten *decodedExt; NSS_CertPolicies *nssObj; CE_CertPolicies *cdsaObj; bool brtn; Allocator &alloc = fieldValue.allocator; brtn = cert.GetExtenTop<NSS_CertPolicies, CE_CertPolicies>( index, numFields, fieldValue.allocator, CSSMOID_CertificatePolicies, nssObj, cdsaObj, decodedExt); if(!brtn) { return false; } assert(nssObj != NULL); memset(cdsaObj, 0, sizeof(*cdsaObj)); cdsaObj->numPolicies = clNssArraySize((const void **)nssObj->policies); unsigned sz = cdsaObj->numPolicies * sizeof(CE_PolicyInformation); if(sz) { cdsaObj->policies = (CE_PolicyInformation *)alloc.malloc(sz); memset(cdsaObj->policies, 0, sz); } for(unsigned polDex=0; polDex<cdsaObj->numPolicies; polDex++) { CE_PolicyInformation *cPolInfo = &cdsaObj->policies[polDex]; NSS_PolicyInformation *nPolInfo = nssObj->policies[polDex]; clAllocCopyData(alloc, nPolInfo->certPolicyId, cPolInfo->certPolicyId); if(nPolInfo->policyQualifiers == NULL) { continue; } cPolInfo->numPolicyQualifiers = clNssArraySize((const void **)nPolInfo->policyQualifiers); sz = cPolInfo->numPolicyQualifiers * sizeof(CE_PolicyQualifierInfo); cPolInfo->policyQualifiers = (CE_PolicyQualifierInfo *) alloc.malloc(sz); memset(cPolInfo->policyQualifiers, 0, sz); for(unsigned qualDex=0; qualDex<cPolInfo->numPolicyQualifiers; qualDex++) { NSS_PolicyQualifierInfo *nQualInfo = nPolInfo->policyQualifiers[qualDex]; CE_PolicyQualifierInfo *cQualInfo = &cPolInfo->policyQualifiers[qualDex]; /* * leaf. * policyQualifierId == CSSMOID_QT_CPS : * IA5String - decode and return contents. * Else return whole thing. */ clAllocCopyData(alloc, nQualInfo->policyQualifierId, cQualInfo->policyQualifierId); CSSM_DATA toCopy = nQualInfo->qualifier; if(clCompareCssmData(&nQualInfo->policyQualifierId, &CSSMOID_QT_CPS)) { /* decode as IA5String to temp memory */ toCopy.Data = NULL; toCopy.Length = 0; if(cert.coder().decodeItem(nQualInfo->qualifier, kSecAsn1IA5StringTemplate, &toCopy)) { clErrorLog("***getCertPolicies: bad IA5String!\n"); CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT); } } /* else copy out nQualInfo->qualifier */ clAllocCopyData(alloc, toCopy, cQualInfo->qualifier); } /* for each qualifier */ } /* for each policy info */ getFieldExtenCommon(cdsaObj, *decodedExt, fieldValue); return true; }
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); } } } }
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); } }
/* * Initialize by decoding a NSS-style NSS_CertExtension array. * This involves figuring out what kind of object is represented in the * octet string in the extension, decoding it, and appending the resulting * NSS object to mExtensions in the form of a DecodedExten. * * Called when decoding either a cert or a CRL (for caching it or * getting its fields) or a cert template (only via * CertGetAllTemplateFields()). */ void DecodedExtensions::decodeFromNss( NSS_CertExtension **extensions) { if(extensions == NULL) { /* OK, no extensions present */ return; } unsigned numExtens = clNssArraySize((const void **)extensions); /* traverse extension list */ for(unsigned dex=0; dex<numExtens; dex++) { NSS_CertExtension *nssExten = extensions[dex]; /* * For this extension->extnId, cook up an appropriate * NSS-specific type (NSS_KeyUsage, etc.); */ CSSM_DATA &rawExtn = nssExten->value; bool berEncoded = false; bool found; // we understand this OID unsigned nssObjLen; // size of associated NSS object const SecAsn1Template *templ = NULL; // template for decoding void *nssObj = NULL; // decode destination found = clOidToNssInfo(nssExten->extnId, nssObjLen, templ); if(!found) { /* * We don't know how to deal with this. */ berEncoded = true; } else { /* * Create NSS-style object specific to this extension, just * by knowing its length and ASN template. * Decode the extensions's extnValue into that object. We don't * have to know what kind of object it is anymore. */ assert(templ != NULL); nssObj = mCoder.malloc(nssObjLen); memset(nssObj, 0, nssObjLen); PRErrorCode prtn; prtn = mCoder.decodeItem(rawExtn, templ, nssObj); if(prtn) { /* * FIXME - what do we do here? For now flag it * as an non-understood extension... */ clErrorLog("decodeExtensions: extension decode error\n"); nssObj = NULL; berEncoded = true; } } if((nssObj != NULL) || berEncoded) { /* append if the decode was successful */ addExtension(nssExten->extnId, clNssBoolToCssm(nssExten->critical), nssObj, berEncoded, templ, &rawExtn); } } }
/* * Common means to get all fields from a decoded cert. Used in * CertGetAllTemplateFields and CertGetAllFields. */ void DecodedCert::getAllParsedCertFields( uint32 &NumberOfFields, // RETURNED CSSM_FIELD_PTR &CertFields) // RETURNED { /* this is the max - some might be missing */ uint32 maxFields = NUM_STD_CERT_FIELDS + mDecodedExtensions.numExtensions(); CSSM_FIELD_PTR outFields = (CSSM_FIELD_PTR)mAlloc.malloc(maxFields * sizeof(CSSM_FIELD)); /* * We'll be copying oids and values for fields we find into * outFields; current number of valid fields found in numOutFields. */ memset(outFields, 0, maxFields * sizeof(CSSM_FIELD)); uint32 numOutFields = 0; CSSM_FIELD_PTR currOutField; uint32 currOidDex; const CSSM_OID *currOid; CssmAutoData aData(mAlloc); // for malloc/copy of outgoing data /* query for each OID we know about */ for(currOidDex=0; currOidDex<NUM_KNOWN_FIELDS; currOidDex++) { const oidToFieldFuncs *fieldFuncs = &fieldFuncTable[currOidDex]; currOid = fieldFuncs->fieldId; uint32 numFields; // for THIS oid /* * Return false if field not there, which is not an error here. * Actual exceptions are fatal. */ if(!fieldFuncs->getFcn(*this, 0, // index - looking for first one numFields, aData)) { continue; } /* got some data for this oid - copy it and oid to outgoing CertFields */ assert(numOutFields < maxFields); currOutField = &outFields[numOutFields]; currOutField->FieldValue = aData.release(); aData.copy(*currOid); currOutField->FieldOid = aData.release(); numOutFields++; /* if more fields are available for this OID, snag them too */ for(uint32 fieldDex=1; fieldDex<numFields; fieldDex++) { /* note this should always succeed */ bool brtn = fieldFuncs->getFcn(*this, fieldDex, numFields, // shouldn't change aData); if(!brtn) { clErrorLog("getAllParsedCertFields: index screwup"); CssmError::throwMe(CSSMERR_CL_INTERNAL_ERROR); } assert(numOutFields < maxFields); currOutField = &outFields[numOutFields]; currOutField->FieldValue = aData.release(); aData.copy(*currOid); currOutField->FieldOid = aData.release(); numOutFields++; } /* multiple fields for currOid */ } /* for each known OID */ NumberOfFields = numOutFields; CertFields = outFields; }
void CL_cssmGeneralNameToNss( CE_GeneralName &cdsaObj, NSS_GeneralName &nssObj, // actually an NSSTaggedItem SecNssCoder &coder) // for temp decoding { memset(&nssObj, 0, sizeof(nssObj)); /* * The default here is just to use the app-supplied data as is... */ nssObj.item = cdsaObj.name; unsigned char itemTag; // for nssObj.tag bool doCopy = false; // unless we have to modify tag byte unsigned char overrideTag; // to force context-specific tag for // an ASN_ANY PRErrorCode prtn; switch(cdsaObj.nameType) { case GNT_OtherName: /* * Caller supplies an CE_OtherName. Encode it. */ if((cdsaObj.name.Length != sizeof(CE_OtherName)) || (cdsaObj.name.Data == NULL)) { clErrorLog("CL_cssmGeneralNameToNss: OtherName.Length" " error\n"); CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT); } prtn = coder.encodeItem(cdsaObj.name.Data, kSecAsn1OtherNameTemplate, nssObj.item); if(prtn) { clErrorLog("CL_cssmGeneralNameToNss: OtherName encode" " error\n"); CssmError::throwMe(CSSMERR_CL_MEMORY_ERROR); } itemTag = NGT_OtherName; break; case GNT_RFC822Name: // IA5String itemTag = NGT_RFC822Name; break; case GNT_DNSName: // IA5String itemTag = NGT_DNSName; break; case GNT_X400Address: // caller's resposibility /* * Encoded as ASN_ANY, the only thing we do is to * force the correct context-specific tag */ itemTag = GNT_X400Address; if(!cdsaObj.berEncoded) { clErrorLog("CL_cssmGeneralNameToNss: X400Address must" " be BER-encoded\n"); CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT); } overrideTag = SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | NGT_X400Address; doCopy = true; break; case GNT_DirectoryName: { /* * Caller supplies an CSSM_X509_NAME. Convert to NSS * format and encode it. */ if((cdsaObj.name.Length != sizeof(CSSM_X509_NAME)) || (cdsaObj.name.Data == NULL)) { clErrorLog("CL_cssmGeneralNameToNss: DirectoryName.Length" " error\n"); CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT); } NSS_Name nssName; CSSM_X509_NAME_PTR cdsaName = (CSSM_X509_NAME_PTR)cdsaObj.name.Data; CL_cssmNameToNss(*cdsaName, nssName, coder); prtn = coder.encodeItem(&nssName, kSecAsn1NameTemplate, nssObj.item); if(prtn) { clErrorLog("CL_cssmGeneralNameToNss: X509Name encode" " error\n"); CssmError::throwMe(CSSMERR_CL_MEMORY_ERROR); } itemTag = GNT_DirectoryName; /* * AND, munge the tag to make it a context-specific * sequence * no, not needed, this is wrapped in an explicit... */ //nssObj.item.Data[0] = SEC_ASN1_CONTEXT_SPECIFIC | // SEC_ASN1_CONSTRUCTED | GNT_DirectoryName; break; } case GNT_EdiPartyName: // caller's resposibility /* * Encoded as ASN_ANY, the only thing we do is to * force the correct context-specific tag */ itemTag = GNT_EdiPartyName; if(!cdsaObj.berEncoded) { clErrorLog("CL_cssmGeneralNameToNss: EdiPartyName must" " be BER-encoded\n"); CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT); } overrideTag = SEC_ASN1_CONTEXT_SPECIFIC | NGT_X400Address; doCopy = true; break; case GNT_URI: // IA5String itemTag = GNT_URI; break; case GNT_IPAddress: // OCTET_STRING itemTag = NGT_IPAddress; break; case GNT_RegisteredID: // OID itemTag = NGT_RegisteredID; break; default: clErrorLog("CL_cssmGeneralNameToNss: bad name tag\n"); CssmError::throwMe(CSSMERR_CL_UNKNOWN_TAG); } if(doCopy) { coder.allocCopyItem(cdsaObj.name, nssObj.item); nssObj.item.Data[0] = overrideTag; } nssObj.tag = itemTag; }