/* * Copyright (c) 2002 Apple Computer, 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. */ /* * DecodedItem.cpp - class representing the common portions of * NSS-format decoded certs and CRLs, with extensions parsed and * decoded (still in NSS format). */ #include "DecodedItem.h" #include "cldebugging.h" #include "AppleX509CLSession.h" #include "CSPAttacher.h" #include "CLFieldsCommon.h" #include "clNssUtils.h" #include "clNameUtils.h" #include #include #define MIN_EXTENSIONS 4 // initial size of *mExtensions 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 SEC_ASN1Template *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); } } DecodedExten::~DecodedExten() { /* the only stuff we allocated was in the coder pool and will be freed * when coder is freed */ } /* * Convert this extension to a CSSM_X509_EXTENSION, in the specified * (app-level) alloc space, after its contents have * been converted to a native CDSA object (CE_KeyUsage, etc.). */ void DecodedExten::convertToCdsa( void *cdsaObj, // e.g. CE_KeyUsage // CSSM_DATA_PTR for berEncoded CSSM_X509_EXTENSION_PTR cssmExt, // contents RETURNED CssmAllocator &alloc) const { clAllocCopyData(alloc, mExtnId, cssmExt->extnId); cssmExt->critical = mCritical ? CSSM_TRUE : CSSM_FALSE; /* * in either case copy the raw extension data if we have it (we may not * have it if this was created via setField). */ if(mRawExtn) { clAllocCopyData(alloc, *mRawExtn, cssmExt->BERvalue); } else { cssmExt->BERvalue.Data = NULL; cssmExt->BERvalue.Length = 0; } if(mBerEncoded) { /* an extension we never parsed or understood */ assert(cdsaObj == NULL); cssmExt->format = CSSM_X509_DATAFORMAT_ENCODED; cssmExt->value.parsedValue = NULL; } else { /* caller sees parsed version plus raw BER-encoded bytes */ assert(cdsaObj != NULL); if(mRawExtn) { /* normal decode & parse case */ cssmExt->format = CSSM_X509_DATAFORMAT_PAIR; } else { /* setField */ cssmExt->format = CSSM_X509_DATAFORMAT_PARSED; } /* in app alloc's space, mallocd by getField*() */ cssmExt->value.parsedValue = cdsaObj; } } /* * Convert a DecodedExten to a CSSM_X509_EXTENSION. This includes * the mapping of the extnId to a known CDSA type and type and doing the * actual NSS-to-CDSA conversion. At the time this function is * called, the DecodedExten either has a valid mNssObj, or it's an * unknown extension type in which case mNssObj is an AsnOcts containing * the opaquely DER-encoded extension value. * * Currently only used when decoding a CRL and converting it en masse * to CDSA. */ template void nssToCssm( const DecodedExten &decodedExt, NssType *&nssObj, // RETURNED CdsaType *&cdsaObj, // mallocd and RETURNED CssmAllocator &alloc) { nssObj = (NssType *)(decodedExt.nssObj()); assert(nssObj != NULL); cdsaObj = (CdsaType *)alloc.malloc(sizeof(CdsaType)); memset(cdsaObj, 0, sizeof(CdsaType)); } void DecodedExten::parse( CSSM_X509_EXTENSION_PTR cssmExt, // mallocd by caller, RETURNED CssmAllocator &alloc) const { void *vCdsaObj = NULL; if(mBerEncoded) { /* non-understood extension */ convertToCdsa(NULL, cssmExt, alloc); return; } if(clCompareCssmData(&mExtnId, &CSSMOID_AuthorityKeyIdentifier)) { CE_AuthorityKeyID *cdsaObj; NSS_AuthorityKeyId *nssObj; nssToCssm( *this, nssObj, cdsaObj, alloc); CL_nssAuthorityKeyIdToCssm(*nssObj, *cdsaObj, mCoder, alloc); vCdsaObj = cdsaObj; } /* same encoding (uint32) for all of these: */ else if(clCompareCssmData(&mExtnId, &CSSMOID_CrlNumber) || clCompareCssmData(&mExtnId, &CSSMOID_DeltaCrlIndicator) || clCompareCssmData(&mExtnId, &CSSMOID_CrlReason)) { CE_CrlNumber *cdsaObj; CSSM_DATA *nssObj; nssToCssm( *this, nssObj, cdsaObj, alloc); *cdsaObj = clDataToInt(*nssObj); vCdsaObj = cdsaObj; } /* same encoding (GeneralNames) for all of these: */ else if(clCompareCssmData(&mExtnId, &CSSMOID_IssuerAltName) || clCompareCssmData(&mExtnId, &CSSMOID_SubjectAltName) || clCompareCssmData(&mExtnId, &CSSMOID_CertIssuer)) { CE_GeneralNames *cdsaObj; NSS_GeneralNames *nssObj; nssToCssm( *this, nssObj, cdsaObj, alloc); CL_nssGeneralNamesToCssm(*nssObj, *cdsaObj, mCoder, alloc); vCdsaObj = cdsaObj; } else if(clCompareCssmData(&mExtnId, &CSSMOID_IssuingDistributionPoint)) { CE_IssuingDistributionPoint *cdsaObj; NSS_IssuingDistributionPoint *nssObj; nssToCssm( *this, nssObj, cdsaObj, alloc); CL_nssIssuingDistPointToCssm(nssObj, cdsaObj, mCoder, alloc); vCdsaObj = cdsaObj; } /* * cert entry extensions */ else if(clCompareCssmData(&mExtnId, &CSSMOID_HoldInstructionCode)) { /* value is just an OID */ CSSM_OID *cdsaObj; CSSM_DATA *nssObj; nssToCssm( *this, nssObj, cdsaObj, alloc); clAllocCopyData(alloc, *nssObj, *cdsaObj); vCdsaObj = cdsaObj; } else if(clCompareCssmData(&mExtnId, &CSSMOID_InvalidityDate)) { /* GeneralizedTime */ CSSM_DATA *cdsaObj; CSSM_DATA *nssObj; nssToCssm( *this, nssObj, cdsaObj, alloc); clAllocCopyData(alloc, *nssObj, *cdsaObj); vCdsaObj = cdsaObj; } else { /* if we get here, this routine is not keeping up with * clOidToNssInfo() */ assert(0); CssmError::throwMe(CSSMERR_CL_INTERNAL_ERROR); } convertToCdsa(vCdsaObj, cssmExt, alloc); } #pragma mark ------ DecodedExtensions ------ /* * A variable-size array of DecodedExtens. * Used for storing cert and CRL extensions as well as per-CRL-entry * extensions. */ DecodedExtensions::DecodedExtensions( SecNssCoder &coder, CssmAllocator &alloc) : mCoder(coder), mAlloc(alloc), mExtensions(NULL), mNumExtensions(0), mSizeofExtensions(0) { } DecodedExtensions::~DecodedExtensions() { for(unsigned i=0; iextnId, cook up an approppriate * 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 SEC_ASN1Template *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); } } } /* * 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; extenDexberEncoded()) { /* 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); } } /* add/retrieve entries */ void DecodedExtensions::addExtension( 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 SEC_ASN1Template *templ, // required if !berEncoded const CSSM_DATA *rawExtn) // NSS_CertExtension.value, copied, // optional (not present during a // SetField op) { if(mNumExtensions == mSizeofExtensions) { /* expand by doubling, or initial malloc */ mSizeofExtensions = mNumExtensions ? (2 * mNumExtensions) : MIN_EXTENSIONS; mExtensions = (DecodedExten **)mAlloc.realloc( mExtensions, mSizeofExtensions * sizeof(DecodedExten)); } mExtensions[mNumExtensions++] = new DecodedExten(extnId, critical, nssObj, berEncoded, templ, mCoder, rawExtn); } const DecodedExten *DecodedExtensions::getExtension( unsigned extenDex) const { assert(extenDex < mNumExtensions); return mExtensions[extenDex]; } /* Convert to CSSM_X509_EXTENSIONS */ /* Currently only used when decoding a CRL and converting it en masse * to CDSA */ void DecodedExtensions::convertToCdsa( CSSM_X509_EXTENSIONS &cssmExtens, CssmAllocator &alloc) const { memset(&cssmExtens, 0, sizeof(cssmExtens)); if(mNumExtensions == NULL) { return; } cssmExtens.extensions = (CSSM_X509_EXTENSION_PTR)alloc.malloc( sizeof(CSSM_X509_EXTENSION) * mNumExtensions); memset(cssmExtens.extensions, 0, sizeof(CSSM_X509_EXTENSION) * mNumExtensions); cssmExtens.numberOfExtensions = mNumExtensions; for(unsigned dex=0; dexparse(&cssmExtens.extensions[dex], alloc); } catch(...) { /* FIXME - what now? */ clFieldLog("DecodedExtensions:convertToCdsa: extension " "decode error"); } } }