X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/5dd5f9ec28f304ca377c42fd7f711d6cf12b90e1..5c19dc3ae3bd8e40a9c028b0deddd50ff337692c:/Security/libsecurity_apple_x509_cl/lib/clNssUtils.cpp diff --git a/Security/libsecurity_apple_x509_cl/lib/clNssUtils.cpp b/Security/libsecurity_apple_x509_cl/lib/clNssUtils.cpp deleted file mode 100644 index bad0ce39..00000000 --- a/Security/libsecurity_apple_x509_cl/lib/clNssUtils.cpp +++ /dev/null @@ -1,1386 +0,0 @@ -/* - * Copyright (c) 2003,2011-2012,2014 Apple Inc. All Rights Reserved. - * - * The contents of this file constitute Original Code as defined in and are - * subject to the Apple Public Source License Version 1.2 (the 'License'). - * You may not use this file except in compliance with the License. Please obtain - * a copy of the License at http://www.apple.com/publicsource and read it before - * using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS - * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT - * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR - * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the - * specific language governing rights and limitations under the License. - */ - -/* - * clNssUtils.cpp - support for libnssasn1-based ASN1 encode/decode - */ - -#include "clNssUtils.h" -#include "clNameUtils.h" -#include "CSPAttacher.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#pragma mark ----- ArenaAllocator ----- - -/* - * Avoid inlining this for debuggability - */ -void *ArenaAllocator::malloc(size_t len) throw(std::bad_alloc) -{ - try { - return mCoder.malloc(len); - } - catch (...) { - throw std::bad_alloc(); - } -} - -/* intentionally not implemented, should never be called */ -void ArenaAllocator::free(void *p) throw() -{ - throw std::bad_alloc(); -} - -void *ArenaAllocator::realloc(void *p, size_t len) throw(std::bad_alloc) -{ - throw std::bad_alloc(); -} - -#pragma mark ----- Malloc/Copy/Compare CSSM_DATA ----- - -/* - * Misc. alloc/copy with arbitrary Allocator - */ -/* malloc d.Data, set d.Length */ -void clAllocData( - Allocator &alloc, - CSSM_DATA &dst, - size_t len) -{ - if(len == 0) { - dst.Data = NULL; - } - else { - dst.Data = (uint8 *)alloc.malloc(len); - } - dst.Length = len; -} - -/* malloc and copy */ -void clAllocCopyData( - Allocator &alloc, - const CSSM_DATA &src, - CSSM_DATA &dst) -{ - clAllocData(alloc, dst, src.Length); - if(dst.Length != 0) { - memmove(dst.Data, src.Data, src.Length); - } -} - -/* - * Compare two CSSM_DATAs (or two CSSM_OIDs), return true if identical. - */ -bool clCompareCssmData( - const CSSM_DATA *data1, - const CSSM_DATA *data2) -{ - if((data1 == NULL) || (data1->Data == NULL) || - (data2 == NULL) || (data2->Data == NULL) || - (data1->Length != data2->Length)) { - return false; - } - if(data1->Length != data2->Length) { - return false; - } - if(memcmp(data1->Data, data2->Data, data1->Length) == 0) { - return true; - } - else { - return false; - } -} - -#pragma mark ----- CSSM_DATA <--> uint32 ----- - -uint32 clDataToInt( - const CSSM_DATA &cdata, - CSSM_RETURN toThrow) /* = CSSMERR_CL_INVALID_CERT_POINTER */ -{ - if((cdata.Length == 0) || (cdata.Data == NULL)) { - return 0; - } - size_t len = cdata.Length; - if(len > sizeof(uint32)) { - if(toThrow == 0) { - /* tolerate this */ - len = sizeof(uint32); - } - else { - CssmError::throwMe(toThrow); - } - } - - uint32 rtn = 0; - uint8 *cp = cdata.Data; - for(size_t i=0; i>= 8; - } -} - -#pragma mark ----- CSSM_BOOL <--> CSSM_DATA ----- -/* - * A Bool is encoded as one byte of either 0 or 0xff - * Default of NSS boolean not present is false - */ -CSSM_BOOL clNssBoolToCssm( - const CSSM_DATA &nssBool) -{ - if((nssBool.Data != NULL) && (nssBool.Data[0] == 0xff)) { - return CSSM_TRUE; - } - else { - return CSSM_FALSE; - } -} - -void clCssmBoolToNss( - CSSM_BOOL cBool, - CSSM_DATA &nssBool, - Allocator &alloc) -{ - uint32 num = cBool ? 0xff : 0; - clIntToData(num, nssBool, alloc); -} - -#pragma mark ----- Bit String manipulation ----- - -/* - * Adjust the length of a CSSM_DATA representing a pre-encoded - * bit string. On entry the length field is the number of bytes - * of data; en exit, the number if bits. Trailing zero bits - * are counted as unused (which is how KeyUsage and NetscapeCertType - * extensions are encoded). - */ -void clCssmBitStringToNss( - CSSM_DATA &b) -{ - size_t numBits = b.Length * 8; - - /* start at end of bit array, scanning backwards looking - * for the first set bit */ - bool foundSet = false; - for(ptrdiff_t dex=b.Length-1; dex>=0; dex--) { - unsigned bitMask = 0x01; - uint8 byte = b.Data[dex]; - for(unsigned bdex=0; bdex<8; bdex++) { - if(byte & bitMask) { - foundSet = true; - break; - } - else { - bitMask <<= 1; - numBits--; - } - } - if(foundSet) { - break; - } - } - /* !foundSet --> numBits = 0 */ - assert(((numBits > 0) & foundSet) || ((numBits == 0) && !foundSet)); - b.Length = numBits; -} - -/* - * On entry, Length is bit count; on exit, a byte count. - * The job here is to ensure that bits marked as "unused" in the - * BER encoding are cleared. Encoding rules say they are undefined in - * the actual encoding. - */ -void clNssBitStringToCssm( - CSSM_DATA &b) -{ - CSSM_SIZE byteCount = (b.Length + 7) / 8; - unsigned partialBits = b.Length & 0x7; - b.Length = byteCount; - if(partialBits == 0) { - return; - } - - /* mask off unused bits */ - unsigned unusedBits = 8 - partialBits; - uint8 *bp = b.Data + b.Length - 1; - /* mask = (2 ** unusedBits) - 1 */ - unsigned mask = (1 << unusedBits) - 1; - *bp &= ~mask; -} - -#pragma mark ----- NSS array manipulation ----- -/* - * How many items in a NULL-terminated array of pointers? - */ -unsigned clNssArraySize( - const void **array) -{ - unsigned count = 0; - if (array) { - while (*array++) { - count++; - } - } - return count; -} - -/* malloc a NULL-ed array of pointers of size num+1 */ -void **clNssNullArray( - uint32 num, - SecNssCoder &coder) -{ - unsigned len = (num + 1) * sizeof(void *); - void **p = (void **)coder.malloc(len); - memset(p, 0, len); - return p; -} - -/* - * GIven a CSSM_DATA containing a decoded BIT_STRING, - * convert to a KeyUsage. - */ -CE_KeyUsage clBitStringToKeyUsage( - const CSSM_DATA &cdata) -{ - size_t 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; -} - -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; -} - -#pragma mark ----- copy CSSM_X509_ALGORITHM_IDENTIFIER ----- - -/* - * Copy CSSM_X509_ALGORITHM_IDENTIFIER, same format (NSS and CSSM). - */ -void CL_copyAlgId( - const CSSM_X509_ALGORITHM_IDENTIFIER &srcAlgId, - CSSM_X509_ALGORITHM_IDENTIFIER &dstAlgId, - Allocator &alloc) -{ - clAllocCopyData(alloc, srcAlgId.algorithm, dstAlgId.algorithm); - clAllocCopyData(alloc, srcAlgId.parameters, dstAlgId.parameters); -} - -void CL_freeCssmAlgId( - CSSM_X509_ALGORITHM_IDENTIFIER *cdsaObj, // optional - Allocator &alloc) -{ - if(cdsaObj == NULL) { - return; - } - alloc.free(cdsaObj->algorithm.Data); - alloc.free(cdsaObj->parameters.Data); - memset(cdsaObj, 0, sizeof(CSSM_X509_ALGORITHM_IDENTIFIER)); -} - - -#pragma mark ----- CSSM_X509_TIME <--> NSS format ----- - -/* - * Map the tag associated with a choice of DirectoryString elements to - * a template array for encoding/decoding that string type. - * Contrary to RFC2459, we allow the IA5String type, which is actually - * used in the real world (cf. the email address in Thawte's serverbasic - * cert). - */ - -/* The template chooser does the work here */ - -bool CL_nssTimeToCssm( - const NSS_TaggedItem &nssTime, - CSSM_X509_TIME &cssmObj, - Allocator &alloc) -{ - cssmObj.timeType = nssTime.tag; - clAllocCopyData(alloc, nssTime.item, cssmObj.time); - return true; -} - -/* - * 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 CL_freeCssmTime( - CSSM_X509_TIME *cssmTime, - Allocator &alloc) -{ - if(cssmTime == NULL) { - return; - } - if(cssmTime->time.Data) { - alloc.free(cssmTime->time.Data); - } - memset(cssmTime, 0, sizeof(CSSM_X509_TIME)); -} - - -#pragma mark ----- CSSM_X509_SUBJECT_PUBLIC_KEY_INFO <--> CSSM_KEY ----- - -/* - * Copy a CSSM_X509_SUBJECT_PUBLIC_KEY_INFO. - * - * Same format (NSS and CSSM), EXCEPT: - * - * Objects which have just been NSS decoded or are about to be - * NSS encoded have the subjectPublicKey.Length field in BITS - * since this field is wrapped in a BIT STRING upon encoding. - * - * Caller tells us which format (bits or bytes) - * to use for each of {src, dst}. - */ -void CL_copySubjPubKeyInfo( - const CSSM_X509_SUBJECT_PUBLIC_KEY_INFO &srcInfo, - bool srcInBits, - CSSM_X509_SUBJECT_PUBLIC_KEY_INFO &dstInfo, - bool dstInBits, - Allocator &alloc) -{ - CL_copyAlgId(srcInfo.algorithm, dstInfo.algorithm, alloc); - - CSSM_DATA srcKey = srcInfo.subjectPublicKey; - if(srcInBits) { - srcKey.Length = (srcKey.Length + 7) / 8; - } - clAllocCopyData(alloc, srcKey, dstInfo.subjectPublicKey); - if(dstInBits) { - dstInfo.subjectPublicKey.Length *= 8; - } -} - -/* - * 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; -} - -/* - * Set up a encoded NULL for CSSM_X509_ALGORITHM_IDENTIFIER.parameters. - */ -void CL_nullAlgParams( - CSSM_X509_ALGORITHM_IDENTIFIER &algId) -{ - static const uint8 encNull[2] = { SEC_ASN1_NULL, 0 }; - CSSM_DATA encNullData; - encNullData.Data = (uint8 *)encNull; - encNullData.Length = 2; - - algId.parameters = encNullData; -} - -/* - * 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; - } -} - -void CL_freeCSSMKey( - CSSM_KEY_PTR cssmKey, - Allocator &alloc, - bool freeTop) -{ - if(cssmKey == NULL) { - return; - } - alloc.free(cssmKey->KeyData.Data); - memset(cssmKey, 0, sizeof(CSSM_KEY)); - if(freeTop) { - alloc.free(cssmKey); - } -} - -#pragma mark ----- CE_AuthorityKeyID <--> NSS_AuthorityKeyId ----- - -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_nssAuthorityKeyIdToCssm( - const NSS_AuthorityKeyId &nssObj, - CE_AuthorityKeyID &cdsaObj, - SecNssCoder &coder, // for temp decoding - Allocator &alloc) -{ - if(nssObj.keyIdentifier != NULL) { - cdsaObj.keyIdentifierPresent = CSSM_TRUE; - clAllocCopyData(alloc, *nssObj.keyIdentifier, cdsaObj.keyIdentifier); - } - if(nssObj.genNames.names != NULL) { - /* GeneralNames, the hard one */ - cdsaObj.generalNamesPresent = CSSM_TRUE; - cdsaObj.generalNames = - (CE_GeneralNames *)alloc.malloc(sizeof(CE_GeneralNames)); - CL_nssGeneralNamesToCssm(nssObj.genNames, - *cdsaObj.generalNames, - coder, - alloc); - } - if(nssObj.serialNumber.Data != NULL) { - cdsaObj.serialNumberPresent = CSSM_TRUE; - clAllocCopyData(alloc, nssObj.serialNumber, cdsaObj.serialNumber); - } -} - -#pragma mark ----- CE_AuthorityInfoAccess <--> NSS_AuthorityInfoAccess ----- - -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(); - 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_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; dexaccessMethod, 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); - } -} - -void CL_freeInfoAccess( - CE_AuthorityInfoAccess &cssmInfo, - Allocator &alloc) -{ - uint32 numDescs = cssmInfo.numAccessDescriptions; - for(unsigned dex=0; dexaccessMethod.Data); - CL_freeCssmGeneralName(dst->accessLocation, alloc); - } - alloc.free(cssmInfo.accessDescriptions); -} - - -#pragma mark ----- CE_QC_Statements <--> NSS_QC_Statements ----- - -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; dexstatementId, 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); - } - } -} - -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; dexstatementId, 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_freeQualCertStatements( - CE_QC_Statements &cssmQCs, - Allocator &alloc) -{ - uint32 numQCs = cssmQCs.numQCStatements; - for(unsigned dex=0; dexstatementId.Data); - if(dst->semanticsInfo) { - CE_SemanticsInformation *si = dst->semanticsInfo; - if(si->semanticsIdentifier) { - alloc.free(si->semanticsIdentifier->Data); - alloc.free(si->semanticsIdentifier); - } - if(si->nameRegistrationAuthorities) { - CL_freeCssmGeneralNames(si->nameRegistrationAuthorities, alloc); - alloc.free(si->nameRegistrationAuthorities); - } - alloc.free(si); - } - if(dst->otherInfo) { - alloc.free(dst->otherInfo->Data); - alloc.free(dst->otherInfo); - } - } - alloc.free(cssmQCs.qcStatements); -} - -#pragma mark ----- decode/encode CE_DistributionPointName ----- - -/* 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); - } -} - -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); - } -} - - -#pragma mark --- CE_CRLDistPointsSyntax <--> NSS_CRLDistributionPoints --- - -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; dexdistPointName) { - /* 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); - } - } -} - -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 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); - } - } -} - -#pragma mark ----- IssuingDistributionPoint ----- - -void CL_nssIssuingDistPointToCssm( - NSS_IssuingDistributionPoint *nssIdp, - CE_IssuingDistributionPoint *cssmIdp, - SecNssCoder &coder, - Allocator &alloc) -{ - /* All fields optional */ - memset(cssmIdp, 0, sizeof(*cssmIdp)); - if(nssIdp->distPointName) { - CE_DistributionPointName *cssmDp = (CE_DistributionPointName *) - alloc.malloc(sizeof(CE_DistributionPointName)); - - /* - * This one is currently still encoded; we have to peek - * at its tag and decode accordingly. - */ - CL_decodeDistributionPointName(*nssIdp->distPointName, - *cssmDp, coder, alloc); - cssmIdp->distPointName = cssmDp; - } - if(nssIdp->onlyUserCerts) { - cssmIdp->onlyUserCertsPresent = CSSM_TRUE; - cssmIdp->onlyUserCerts = clNssBoolToCssm(*nssIdp->onlyUserCerts); - } - if(nssIdp->onlyCACerts) { - cssmIdp->onlyCACertsPresent = CSSM_TRUE; - cssmIdp->onlyCACerts = clNssBoolToCssm(*nssIdp->onlyCACerts); - } - if(nssIdp->onlySomeReasons) { - cssmIdp->onlySomeReasonsPresent = CSSM_TRUE; - if(nssIdp->onlySomeReasons->Length > 0) { - cssmIdp->onlySomeReasons = *nssIdp->onlySomeReasons->Data; - } - else { - cssmIdp->onlySomeReasons = 0; - } - } - if(nssIdp->indirectCRL) { - cssmIdp->indirectCrlPresent = CSSM_TRUE; - cssmIdp->indirectCrl = clNssBoolToCssm(*nssIdp->indirectCRL); - } -} - -#pragma mark --- CE_NameConstraints <--> NSS_NameConstraints --- - -void CL_cssmNameConstraintsToNss( - const CE_NameConstraints &cdsaObj, - NSS_NameConstraints &nssObj, - SecNssCoder &coder) -{ - //%%%FIXME tba -} - -void CL_nssNameConstraintsToCssm( - const NSS_NameConstraints &nssObj, - CE_NameConstraints &cdsaObj, - SecNssCoder &coder, // for temp decoding - Allocator &alloc) -{ - //%%%FIXME tba -} - -void CL_freeCssmNameConstraints( - CE_NameConstraints *cssmNcs, - Allocator &alloc) -{ - if(cssmNcs == NULL) { - return; - } -//%%%FIXME need to add a CL_freeCssmGeneralSubtrees function to clNameUtils{.h,.cpp} -#if 0 - switch(cssmDpn->nameType) { - case CE_CDNT_FullName: - CL_freeCssmGeneralNames(cssmDpn->dpn.fullName, alloc); - alloc.free(cssmDpn->dpn.fullName); - break; - case CE_CDNT_NameRelativeToCrlIssuer: - CL_freeX509Rdn(cssmDpn->dpn.rdn, alloc); - alloc.free(cssmDpn->dpn.rdn); - break; - } -#endif - memset(cssmNcs, 0, sizeof(*cssmNcs)); -} - -#pragma mark --- CE_PolicyMappings <--> NSS_PolicyMappings --- - -void CL_cssmPolicyMappingsToNss( - const CE_PolicyMappings &cdsaObj, - NSS_PolicyMappings &nssObj, - SecNssCoder &coder) -{ - //%%%FIXME tba -} - -void CL_nssPolicyMappingsToCssm( - const NSS_PolicyMappings &nssObj, - CE_PolicyMappings &cdsaObj, - SecNssCoder &coder, // for temp decoding - Allocator &alloc) -{ - //%%%FIXME tba -} - -void CL_freeCssmPolicyMappings( - CE_PolicyMappings *cssmPms, - Allocator &alloc) -{ - if(cssmPms == NULL) { - return; - } - //%%%FIXME tba - - memset(cssmPms, 0, sizeof(*cssmPms)); -} - -#pragma mark --- CE_PolicyConstraints <--> NSS_PolicyConstraints --- - -void CL_cssmPolicyConstraintsToNss( - const CE_PolicyConstraints *cdsaObj, - NSS_PolicyConstraints *nssObj, - SecNssCoder &coder) -{ - //%%%FIXME tba -} - -void CL_nssPolicyConstraintsToCssm( - const NSS_PolicyConstraints *nssObj, - CE_PolicyConstraints *cdsaObj, - SecNssCoder &coder, // for temp decoding - Allocator &alloc) -{ - memset(cdsaObj, 0, sizeof(*cdsaObj)); - if(nssObj->requireExplicitPolicy.Data) { - cdsaObj->requireExplicitPolicyPresent = CSSM_TRUE; - cdsaObj->inhibitPolicyMapping = clDataToInt( - nssObj->requireExplicitPolicy, 0); - } - if(nssObj->inhibitPolicyMapping.Data) { - cdsaObj->inhibitPolicyMappingPresent = CSSM_TRUE; - cdsaObj->inhibitPolicyMapping = clDataToInt( - nssObj->inhibitPolicyMapping, 0); - } -} - -void CL_freeCssmPolicyConstraints( - CE_PolicyConstraints *cssmPcs, - Allocator &alloc) -{ - if(cssmPcs == NULL) { - return; - } - - memset(cssmPcs, 0, sizeof(*cssmPcs)); -} - - -#pragma mark ----- ECDSA_SigAlgParams support ----- - -/* - * 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); - } -} - -#pragma mark ----- Top-level Cert/CRL encode and decode ----- - -/* - * To ensure a secure means of signing and verifying TBSCert blobs, we - * provide these functions to encode and decode just the top-level - * elements of a certificate. Unfortunately there is no guarantee - * that when you decode and re-encode a TBSCert blob, you get the - * same thing you started with (although with DER rules, as opposed - * to BER rules, you should). Thus when signing, we sign the TBSCert - * and encode the signed cert here without ever decoding the TBSCert (or, - * at least, without using the decoded version to get the encoded TBS blob). - */ - -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); -} - - -/* - * Given pre-DER-encoded blobs, do the final encode step for a signed cert. - */ -void -CL_certEncodeComponents( - const CssmData &TBSCert, // DER-encoded - const CssmData &algId, // ditto - const CssmData &rawSig, // raw bits, not encoded - CssmOwnedData &signedCert) // DER-encoded -{ - NSS_SignedCertOrCRL nssObj; - nssObj.tbsBlob.Data = TBSCert.Data; - nssObj.tbsBlob.Length = TBSCert.Length; - nssObj.signatureAlgorithm.Data = algId.Data; - nssObj.signatureAlgorithm.Length = algId.Length; - nssObj.signature.Data = rawSig.Data; - nssObj.signature.Length = rawSig.Length * 8; // BIT STRING - - PRErrorCode prtn; - - prtn = SecNssEncodeItemOdata(&nssObj, - kSecAsn1SignedCertOrCRLTemplate,signedCert); - if(prtn) { - CssmError::throwMe(CSSMERR_CL_MEMORY_ERROR); - } - -}