DecodedExtensions.cpp [plain text]
#include "DecodedItem.h"
#include "cldebugging.h"
#include "AppleX509CLSession.h"
#include "CSPAttacher.h"
#include "CLFieldsCommon.h"
#include "clNssUtils.h"
#include "clNameUtils.h"
#include <security_asn1/SecAsn1Types.h>
#include <Security/cssmapple.h>
#include <Security/oidscert.h>
#define MIN_EXTENSIONS 4 // initial size of *mExtensions
DecodedExten::DecodedExten(
const CSSM_OID &extnId, bool critical,
void *nssObj, bool berEncoded, const SecAsn1Template *templ, SecNssCoder &coder, const CSSM_DATA *rawExtn) : 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()
{
}
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 = SEC_ASN1_OCTET_STRING;
tv->value.Length = berValue.Length;
tv->value.Data = berValue.Data;
return tv;
#if 0
tv->type = berValue.Data[0];
const uint8 *lp = berValue.Data + 1;
uint8 len1 = *lp;
if((len1 & 0x80) == 0) {
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++; 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
}
void DecodedExten::convertToCdsa(
void *cdsaObj, CSSM_X509_EXTENSION_PTR cssmExt, Allocator &alloc) const
{
clAllocCopyData(alloc, mExtnId, cssmExt->extnId);
cssmExt->critical = mCritical ? CSSM_TRUE : CSSM_FALSE;
if(mRawExtn) {
clAllocCopyData(alloc, *mRawExtn, cssmExt->BERvalue);
}
else {
cssmExt->BERvalue.Data = NULL;
cssmExt->BERvalue.Length = 0;
}
if(mBerEncoded) {
assert(cdsaObj == NULL);
cssmExt->format = CSSM_X509_DATAFORMAT_ENCODED;
cssmExt->value.tagAndValue = createTagAndValue(cssmExt->BERvalue, alloc);
}
else {
assert(cdsaObj != NULL);
cssmExt->format = CSSM_X509_DATAFORMAT_PARSED;
cssmExt->value.parsedValue = cdsaObj;
}
}
template<class NssType, class CdsaType>
void nssToCssm(
const DecodedExten &decodedExt,
NssType *&nssObj, CdsaType *&cdsaObj, Allocator &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, Allocator &alloc) const
{
void *vCdsaObj = NULL;
if(mBerEncoded) {
convertToCdsa(NULL, cssmExt, alloc);
return;
}
if(clCompareCssmData(&mExtnId, &CSSMOID_AuthorityKeyIdentifier)) {
CE_AuthorityKeyID *cdsaObj;
NSS_AuthorityKeyId *nssObj;
nssToCssm<NSS_AuthorityKeyId, CE_AuthorityKeyID>(
*this,
nssObj,
cdsaObj,
alloc);
CL_nssAuthorityKeyIdToCssm(*nssObj, *cdsaObj, mCoder, alloc);
vCdsaObj = cdsaObj;
}
else if(clCompareCssmData(&mExtnId, &CSSMOID_CrlNumber) ||
clCompareCssmData(&mExtnId, &CSSMOID_DeltaCrlIndicator) ||
clCompareCssmData(&mExtnId, &CSSMOID_CrlReason)) {
CE_CrlNumber *cdsaObj;
CSSM_DATA *nssObj;
nssToCssm<CSSM_DATA, CE_CrlNumber>(
*this,
nssObj,
cdsaObj,
alloc);
CSSM_RETURN toThrow;
if(clCompareCssmData(&mExtnId, &CSSMOID_CrlReason)) {
toThrow = CSSMERR_CL_INVALID_CRL_POINTER;
}
else {
toThrow = CSSM_OK;
}
*cdsaObj = clDataToInt(*nssObj, toThrow);
vCdsaObj = cdsaObj;
}
else if(clCompareCssmData(&mExtnId, &CSSMOID_IssuerAltName) ||
clCompareCssmData(&mExtnId, &CSSMOID_SubjectAltName) ||
clCompareCssmData(&mExtnId, &CSSMOID_CertIssuer)) {
CE_GeneralNames *cdsaObj;
NSS_GeneralNames *nssObj;
nssToCssm<NSS_GeneralNames, CE_GeneralNames>(
*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<NSS_IssuingDistributionPoint, CE_IssuingDistributionPoint>(
*this,
nssObj,
cdsaObj,
alloc);
CL_nssIssuingDistPointToCssm(nssObj, cdsaObj, mCoder, alloc);
vCdsaObj = cdsaObj;
}
else if(clCompareCssmData(&mExtnId, &CSSMOID_CrlDistributionPoints)) {
CE_CRLDistPointsSyntax *cdsaObj;
NSS_CRLDistributionPoints *nssObj;
nssToCssm<NSS_CRLDistributionPoints, CE_CRLDistPointsSyntax>(
*this,
nssObj,
cdsaObj,
alloc);
CL_nssDistPointsToCssm((const NSS_CRLDistributionPoints&)*nssObj, *cdsaObj, mCoder, alloc);
vCdsaObj = cdsaObj;
}
else if(clCompareCssmData(&mExtnId, &CSSMOID_HoldInstructionCode)) {
CSSM_OID *cdsaObj;
CSSM_DATA *nssObj;
nssToCssm<CSSM_DATA, CSSM_OID>(
*this,
nssObj,
cdsaObj,
alloc);
clAllocCopyData(alloc, *nssObj, *cdsaObj);
vCdsaObj = cdsaObj;
}
else if(clCompareCssmData(&mExtnId, &CSSMOID_InvalidityDate)) {
CSSM_DATA *cdsaObj;
CSSM_DATA *nssObj;
nssToCssm<CSSM_DATA, CSSM_DATA>(
*this,
nssObj,
cdsaObj,
alloc);
clAllocCopyData(alloc, *nssObj, *cdsaObj);
vCdsaObj = cdsaObj;
}
else {
CssmError::throwMe(CSSMERR_CL_INTERNAL_ERROR);
}
convertToCdsa(vCdsaObj, cssmExt, alloc);
}
#pragma mark ------ DecodedExtensions ------
DecodedExtensions::DecodedExtensions(
SecNssCoder &coder,
Allocator &alloc)
: mCoder(coder),
mAlloc(alloc),
mExtensions(NULL),
mNumExtensions(0),
mSizeofExtensions(0)
{
}
DecodedExtensions::~DecodedExtensions()
{
for(unsigned i=0; i<mNumExtensions; i++) {
assert(mExtensions[i] != NULL);
delete mExtensions[i];
}
mAlloc.free(mExtensions);
mExtensions = NULL;
mNumExtensions = 0;
mSizeofExtensions = 0;
}
void DecodedExtensions::decodeFromNss(
NSS_CertExtension **extensions)
{
if(extensions == NULL) {
return;
}
unsigned numExtens = clNssArraySize((const void **)extensions);
for(unsigned dex=0; dex<numExtens; dex++) {
NSS_CertExtension *nssExten = extensions[dex];
CSSM_DATA &rawExtn = nssExten->value;
bool berEncoded = false;
bool found; unsigned nssObjLen; const SecAsn1Template *templ = NULL; void *nssObj = NULL; found = clOidToNssInfo(nssExten->extnId, nssObjLen, templ);
if(!found) {
berEncoded = true;
}
else {
assert(templ != NULL);
nssObj = mCoder.malloc(nssObjLen);
memset(nssObj, 0, nssObjLen);
PRErrorCode prtn;
prtn = mCoder.decodeItem(rawExtn, templ, nssObj);
if(prtn) {
clErrorLog("decodeExtensions: extension decode error\n");
nssObj = NULL;
berEncoded = true;
}
}
if((nssObj != NULL) || berEncoded) {
addExtension(nssExten->extnId,
clNssBoolToCssm(nssExten->critical),
nssObj,
berEncoded,
templ,
&rawExtn);
}
}
}
void DecodedExtensions::encodeToNss(
NSS_CertExtension **&extensions)
{
assert(extensions == NULL);
if(mNumExtensions == 0) {
return;
}
unsigned len = (mNumExtensions + 1) * sizeof(NSS_CertExtension *);
extensions = (NSS_CertExtension **)mCoder.malloc(len);
memset(extensions, 0, len);
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);
if(decodedExt->berEncoded()) {
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()) {
clCssmBoolToNss(CSSM_TRUE, thisNssExten->critical, arenaAlloc);
}
mCoder.allocCopyItem(decodedExt->extnId(), thisNssExten->extnId);
}
}
void DecodedExtensions::addExtension(
const CSSM_OID &extnId, bool critical,
void *nssObj, bool berEncoded, const SecAsn1Template *templ, const CSSM_DATA *rawExtn) {
if(mNumExtensions == mSizeofExtensions) {
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];
}
void DecodedExtensions::convertToCdsa(
CSSM_X509_EXTENSIONS &cssmExtens,
Allocator &alloc) const
{
memset(&cssmExtens, 0, sizeof(cssmExtens));
if(mNumExtensions == 0) {
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; dex<mNumExtensions; dex++) {
try {
getExtension(dex)->parse(&cssmExtens.extensions[dex], alloc);
}
catch(...) {
clFieldLog("DecodedExtensions:convertToCdsa: extension "
"decode error");
}
}
}