#include "DecodedCrl.h"
#include <security_utilities/debugging.h>
#include "cldebugging.h"
#include "CLCrlExtensions.h"
#include "CLCertExtensions.h"
#include "CLFieldsCommon.h"
#include "clNssUtils.h"
#include "clNameUtils.h"
#include <security_utilities/utilities.h>
#include <Security/oidscrl.h>
#include <Security/oidscert.h>
#include <Security/cssmerr.h>
#include <Security/x509defs.h>
static void CL_freeCssmExtensions(
CSSM_X509_EXTENSIONS &extens,
Allocator &alloc);
static bool getField_Version (
DecodedItem &item,
unsigned index, uint32 &numFields, CssmOwnedData &fieldValue) {
const DecodedCrl &crl = dynamic_cast<const DecodedCrl &>(item);
const CSSM_DATA &vers = crl.mCrl.tbs.version;
if(!tbsGetCheck(vers.Data, index)) {
return false;
}
fieldValue.copy(vers.Data, vers.Length);
numFields = 1;
return true;
}
static void setField_Version (
DecodedItem &item,
const CssmData &fieldValue)
{
DecodedCrl &crl = dynamic_cast<DecodedCrl &>(item);
CSSM_DATA &vers = crl.mCrl.tbs.version;
tbsSetCheck(vers.Data, fieldValue, 0, "version");
crl.coder().allocCopyItem(fieldValue, vers);
}
static bool getField_Issuer (
DecodedItem &item,
unsigned index, uint32 &numFields, CssmOwnedData &fieldValue) {
if(index != 0) {
return false;
}
bool brtn;
const DecodedCrl &crl = dynamic_cast<const DecodedCrl &>(item);
try {
brtn = getField_RDN_NSS(crl.mCrl.tbs.issuer, fieldValue);
if(brtn) {
numFields = 1;
}
}
catch (...) {
freeField_RDN(fieldValue);
throw;
}
return brtn;
}
static void setField_Issuer (
DecodedItem &item,
const CssmData &fieldValue)
{
DecodedCrl &crl = dynamic_cast<DecodedCrl &>(item);
const CSSM_X509_NAME *cssmName = (const CSSM_X509_NAME *)fieldValue.Data;
NSS_Name &nssName = crl.mCrl.tbs.issuer;
tbsSetCheck(nssName.rdns, fieldValue, sizeof(CSSM_X509_NAME),
"IssuerName");
CL_cssmNameToNss(*cssmName, nssName, crl.coder());
}
static bool getField_ThisUpdate (
DecodedItem &item,
unsigned index, uint32 &numFields, CssmOwnedData &fieldValue) {
const DecodedCrl &crl = dynamic_cast<const DecodedCrl &>(item);
const NSS_Time &srcTime = crl.mCrl.tbs.thisUpdate;
return getField_TimeNSS(srcTime, index, numFields, fieldValue);
}
static void setField_ThisUpdate (
DecodedItem &item,
const CssmData &fieldValue)
{
DecodedCrl &crl = dynamic_cast<DecodedCrl &>(item);
NSS_Time &dstTime = crl.mCrl.tbs.thisUpdate;
tbsSetCheck(dstTime.item.Data, fieldValue,
sizeof(CSSM_X509_TIME), "NotBefore");
setField_TimeNSS(fieldValue, dstTime, crl.coder());
}
static bool getField_NextUpdate (
DecodedItem &item,
unsigned index, uint32 &numFields, CssmOwnedData &fieldValue) {
const DecodedCrl &crl = dynamic_cast<const DecodedCrl &>(item);
const NSS_Time &srcTime = crl.mCrl.tbs.nextUpdate;
return getField_TimeNSS(srcTime, index, numFields, fieldValue);
}
static void setField_NextUpdate (
DecodedItem &item,
const CssmData &fieldValue)
{
DecodedCrl &crl = dynamic_cast<DecodedCrl &>(item);
NSS_Time &dstTime = crl.mCrl.tbs.nextUpdate;
tbsSetCheck(dstTime.item.Data, fieldValue,
sizeof(CSSM_X509_TIME), "NotBefore");
setField_TimeNSS(fieldValue, dstTime, crl.coder());
}
static bool getFieldIssuerNorm(
DecodedItem &item,
unsigned index, uint32 &numFields, CssmOwnedData &fieldValue) {
if(index != 0) {
return false;
}
const DecodedCrl &crl = dynamic_cast<const DecodedCrl &>(item);
return getField_normRDN_NSS(crl.mCrl.tbs.derIssuer, numFields,
fieldValue);
}
static bool getField_CrlTbsAlgId (
DecodedItem &item,
unsigned index, uint32 &numFields, CssmOwnedData &fieldValue) {
const DecodedCrl &crl = dynamic_cast<const DecodedCrl &>(item);
const CSSM_X509_ALGORITHM_IDENTIFIER &srcAlgId =
crl.mCrl.signatureAlgorithm;
if(!tbsGetCheck(srcAlgId.algorithm.Data, index)) {
return false;
}
getField_AlgIdNSS(srcAlgId, fieldValue);
numFields = 1;
return true;
}
static void nssRevokedEntryToCssm(
NSS_RevokedCert &nssEntry,
CSSM_X509_REVOKED_CERT_ENTRY &cssmEntry,
Allocator &alloc)
{
clAllocCopyData(alloc, nssEntry.userCertificate, cssmEntry.certificateSerialNumber);
CL_nssTimeToCssm(nssEntry.revocationDate, cssmEntry.revocationDate, alloc);
NSS_CertExtension **nssExtens = nssEntry.extensions;
if(nssExtens == NULL) {
return;
}
SecNssCoder coder;
DecodedExtensions decodedExtens(coder, alloc);
decodedExtens.decodeFromNss(nssExtens);
decodedExtens.convertToCdsa(cssmEntry.extensions, alloc);
}
static void freeCssmEntry(
CSSM_X509_REVOKED_CERT_ENTRY_PTR cssmEntry,
Allocator &alloc)
{
if(cssmEntry == NULL) {
return;
}
if(cssmEntry->certificateSerialNumber.Data) {
alloc.free(cssmEntry->certificateSerialNumber.Data);
cssmEntry->certificateSerialNumber.Data = NULL;
cssmEntry->certificateSerialNumber.Length = 0;
}
CL_freeCssmTime(&cssmEntry->revocationDate, alloc);
CL_freeCssmExtensions(cssmEntry->extensions, alloc);
memset(cssmEntry, 0, sizeof(CSSM_X509_REVOKED_CERT_ENTRY));
}
static void nssRevokedListToCssm(
NSS_RevokedCert **nssList, CSSM_X509_REVOKED_CERT_LIST_PTR cssmList,
Allocator &alloc)
{
unsigned numEntries = clNssArraySize((const void **)nssList);
cssmList->numberOfRevokedCertEntries = numEntries;
if(numEntries == 0) {
cssmList->revokedCertEntry = NULL;
return;
}
cssmList->revokedCertEntry = (CSSM_X509_REVOKED_CERT_ENTRY_PTR)alloc.malloc(
sizeof(CSSM_X509_REVOKED_CERT_ENTRY) * numEntries);
memset(cssmList->revokedCertEntry, 0,
sizeof(CSSM_X509_REVOKED_CERT_ENTRY) * numEntries);
for(unsigned dex=0; dex<numEntries; dex++) {
NSS_RevokedCert *nssEntry = nssList[dex];
assert(nssEntry != NULL);
CSSM_X509_REVOKED_CERT_ENTRY_PTR cssmEntry =
&cssmList->revokedCertEntry[dex];
nssRevokedEntryToCssm(*nssEntry, *cssmEntry, alloc);
}
}
static void freeCssmRevokedList(
CSSM_X509_REVOKED_CERT_LIST_PTR cssmList,
Allocator &alloc)
{
if(cssmList == NULL) {
return;
}
for(unsigned dex=0; dex<cssmList->numberOfRevokedCertEntries; dex++) {
CSSM_X509_REVOKED_CERT_ENTRY_PTR cssmEntry =
&cssmList->revokedCertEntry[dex];
freeCssmEntry(cssmEntry, alloc);
}
if(cssmList->revokedCertEntry) {
alloc.free(cssmList->revokedCertEntry);
}
memset(cssmList, 0, sizeof(CSSM_X509_REVOKED_CERT_LIST));
}
static bool getField_SignedCrl (
DecodedItem &item,
unsigned index, uint32 &numFields, CssmOwnedData &fieldValue) {
Allocator &alloc = fieldValue.allocator;
const DecodedCrl &nssCrl = dynamic_cast<const DecodedCrl &>(item);
const NSS_TBSCrl &nssTbs = nssCrl.mCrl.tbs;
fieldValue.malloc(sizeof(CSSM_X509_SIGNED_CRL));
CSSM_X509_SIGNED_CRL &cssmCrl = *((CSSM_X509_SIGNED_CRL *)fieldValue.data());
memset(&cssmCrl, 0, sizeof(CSSM_X509_SIGNED_CRL));
CSSM_X509_TBS_CERTLIST &cssmTbs = cssmCrl.tbsCertList;
clAllocCopyData(alloc, nssTbs.version, cssmTbs.version);
CL_copyAlgId(nssTbs.signature, cssmTbs.signature, alloc);
CL_copyAlgId(nssCrl.mCrl.signatureAlgorithm,
cssmCrl.signature.algorithmIdentifier, alloc);
CL_nssNameToCssm(nssTbs.issuer, cssmTbs.issuer, alloc);
CL_nssTimeToCssm(nssTbs.thisUpdate, cssmTbs.thisUpdate, alloc);
CL_nssTimeToCssm(nssTbs.nextUpdate, cssmTbs.nextUpdate, alloc);
if(nssTbs.revokedCerts != NULL) {
cssmTbs.revokedCertificates = (CSSM_X509_REVOKED_CERT_LIST_PTR)
alloc.malloc(sizeof(CSSM_X509_REVOKED_CERT_LIST));
memset(cssmTbs.revokedCertificates, 0, sizeof(CSSM_X509_REVOKED_CERT_LIST));
nssRevokedListToCssm(nssTbs.revokedCerts,
cssmTbs.revokedCertificates, alloc);
}
const DecodedExtensions &decodedExtens = nssCrl.decodedExtens();
decodedExtens.convertToCdsa(cssmTbs.extensions, alloc);
CSSM_DATA nssSig = nssCrl.mCrl.signature;
nssSig.Length = (nssSig.Length + 7) / 8;
clAllocCopyData(alloc, nssSig, cssmCrl.signature.encrypted);
numFields = 1;
return true;
}
static void setField_SignedCrl (
DecodedItem &item,
const CssmData &fieldValue)
{
CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
}
static void freeField_SignedCrl (
CssmOwnedData &fieldValue)
{
CSSM_X509_SIGNED_CRL *cssmCrl =
(CSSM_X509_SIGNED_CRL *)fieldValue.data();
if(cssmCrl == NULL) {
return;
}
if(fieldValue.length() != sizeof(CSSM_X509_SIGNED_CRL)) {
CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER);
}
Allocator &alloc = fieldValue.allocator;
CSSM_X509_TBS_CERTLIST_PTR cssmTbs = &cssmCrl->tbsCertList;
if(cssmTbs == NULL) {
CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER);
}
if(cssmTbs->version.Data) {
alloc.free(cssmTbs->version.Data);
}
CL_freeCssmAlgId(&cssmTbs->signature, alloc);
CL_freeCssmAlgId(&cssmCrl->signature.algorithmIdentifier, alloc);
CL_freeX509Name(&cssmTbs->issuer, alloc);
CL_freeCssmTime(&cssmTbs->thisUpdate, alloc);
CL_freeCssmTime(&cssmTbs->nextUpdate, alloc);
freeCssmRevokedList(cssmTbs->revokedCertificates, alloc);
alloc.free(cssmTbs->revokedCertificates);
CL_freeCssmExtensions(cssmTbs->extensions, alloc);
alloc.free(cssmCrl->signature.encrypted.Data);
memset(cssmCrl, 0, sizeof(CSSM_X509_SIGNED_CRL));
}
typedef struct {
const CSSM_OID *fieldId;
getItemFieldFcn *getFcn;
setItemFieldFcn *setFcn;
freeFieldFcn *freeFcn; } oidToFieldFuncs;
static const oidToFieldFuncs crlFieldTable[] = {
{ &CSSMOID_X509V2CRLSignedCrlCStruct,
&getField_SignedCrl, &setField_SignedCrl, &freeField_SignedCrl },
{ &CSSMOID_X509V2CRLVersion,
&getField_Version, &setField_Version, NULL },
{ &CSSMOID_X509V1CRLIssuerNameCStruct,
&getField_Issuer, &setField_Issuer, &freeField_RDN },
{ &CSSMOID_X509V1CRLThisUpdate,
&getField_ThisUpdate, &setField_ThisUpdate, &freeField_Time },
{ &CSSMOID_X509V1CRLNextUpdate,
&getField_NextUpdate, &setField_NextUpdate, &freeField_Time },
{ &CSSMOID_X509V1IssuerName,
getFieldIssuerNorm, &setField_ReadOnly, NULL },
{ &CSSMOID_X509V1SignatureAlgorithmTBS,
&getField_CrlTbsAlgId, &setField_ReadOnly, &freeField_AlgId },
{ &CSSMOID_CrlNumber,
&getFieldCrlNumber, &setFieldCrlNumber, freeFieldSimpleExtension },
{ &CSSMOID_DeltaCrlIndicator,
&getFieldDeltaCrl, &setFieldCrlNumber, freeFieldSimpleExtension },
{ &CSSMOID_CertIssuer, &getField_Unimplemented, &setField_ReadOnly,
&freeFieldSubjIssuerAltName},
{ &CSSMOID_CrlReason, &getField_Unimplemented, &setField_ReadOnly,
freeFieldSimpleExtension},
{ &CSSMOID_IssuingDistributionPoint, &getField_Unimplemented, &setField_ReadOnly,
&freeFieldIssuingDistPoint},
{ &CSSMOID_HoldInstructionCode, &getField_Unimplemented, &setField_ReadOnly,
&freeFieldOidOrData},
{ &CSSMOID_InvalidityDate, &getField_Unimplemented, &setField_ReadOnly,
&freeFieldOidOrData},
{ &CSSMOID_AuthorityKeyIdentifier, &getFieldAuthorityKeyId,
&setFieldAuthorityKeyId, &freeFieldAuthorityKeyId } ,
{ &CSSMOID_X509V3CertificateExtensionCStruct, &getFieldUnknownExt,
&setFieldUnknownExt, &freeFieldUnknownExt },
{ &CSSMOID_SubjectAltName, &getFieldSubjAltName,
&setFieldSubjIssuerAltName, &freeFieldSubjIssuerAltName } ,
{ &CSSMOID_IssuerAltName, &getFieldIssuerAltName,
&setFieldSubjIssuerAltName, &freeFieldSubjIssuerAltName } ,
{ &CSSMOID_CrlDistributionPoints, &getField_Unimplemented, &setField_ReadOnly,
&freeFieldCrlDistributionPoints},
};
#define NUM_KNOWN_FIELDS (sizeof(crlFieldTable) / sizeof(oidToFieldFuncs))
#define NUM_STD_CRL_FIELDS 2
static const oidToFieldFuncs *oidToFields(
const CssmOid &fieldId)
{
const oidToFieldFuncs *fieldTable = crlFieldTable;
for(unsigned i=0; i<NUM_KNOWN_FIELDS; i++) {
if(fieldId == CssmData::overlay(*fieldTable->fieldId)) {
return fieldTable;
}
fieldTable++;
}
CssmError::throwMe(CSSMERR_CL_UNKNOWN_TAG);
}
static void CL_freeCrlFieldData(
const CssmOid &fieldId,
CssmOwnedData &fieldValue,
bool reset = true)
{
if((fieldValue.data() == NULL) || (fieldValue.length() == 0)) {
CssmError::throwMe(CSSM_ERRCODE_INVALID_FIELD_POINTER);
}
const oidToFieldFuncs *fieldFuncs = oidToFields(fieldId);
if(fieldFuncs->freeFcn != NULL) {
fieldFuncs->freeFcn(fieldValue);
}
if(reset) {
fieldValue.reset();
fieldValue.release();
}
}
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;
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) {
CssmData cData((uint8 *)exten, sizeof(CSSM_X509_EXTENSION));
CssmRemoteData fieldValue(alloc, cData);
CL_freeCrlFieldData(fieldId, fieldValue, false);
fieldValue.release(); }
}
alloc.free(extens.extensions);
memset(&extens, 0, sizeof(CSSM_X509_EXTENSIONS));
}
bool DecodedCrl::getCrlFieldData(
const CssmOid &fieldId, unsigned index, uint32 &numFields, CssmOwnedData &fieldValue) {
switch(mState) {
case IS_Empty:
case IS_Building:
clErrorLog("DecodedCrl::getCrlField: can't parse undecoded CRL!");
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);
}
void DecodedCrl::setCrlField(
const CssmOid &fieldId, const CssmData &fieldValue)
{
switch(mState) {
case IS_Empty: mState = IS_Building;
break;
case IS_Building: break;
case IS_DecodedAll:
case IS_DecodedTBS:
clErrorLog("DecodedCrl::setCrlField: can't build on a decoded CRL!");
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 DecodedCrl::freeCrlFieldData(
const CssmOid &fieldId,
CssmOwnedData &fieldValue)
{
CL_freeCrlFieldData(fieldId, fieldValue);
}
void DecodedCrl::getAllParsedCrlFields(
uint32 &NumberOfFields, CSSM_FIELD_PTR &CrlFields) {
uint32 maxFields = NUM_STD_CRL_FIELDS + mDecodedExtensions.numExtensions();
CSSM_FIELD_PTR outFields = (CSSM_FIELD_PTR)mAlloc.malloc(
maxFields * sizeof(CSSM_FIELD));
memset(outFields, 0, maxFields * sizeof(CSSM_FIELD));
uint32 numOutFields = 0;
CSSM_FIELD_PTR currOutField;
uint32 currOidDex;
const CSSM_OID *currOid;
CssmAutoData aData(mAlloc);
for(currOidDex=0; currOidDex<NUM_KNOWN_FIELDS; currOidDex++) {
const oidToFieldFuncs *fieldFuncs = &crlFieldTable[currOidDex];
currOid = fieldFuncs->fieldId;
uint32 numFields;
if(!fieldFuncs->getFcn(*this,
0, numFields,
aData)) {
continue;
}
assert(numOutFields < maxFields);
currOutField = &outFields[numOutFields];
currOutField->FieldValue = aData.release();
aData.copy(*currOid);
currOutField->FieldOid = aData.release();
numOutFields++;
for(uint32 fieldDex=1; fieldDex<numFields; fieldDex++) {
bool brtn = fieldFuncs->getFcn(*this,
fieldDex,
numFields, aData);
if(!brtn) {
clErrorLog("getAllParsedCrlFields: 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++;
}
}
NumberOfFields = numOutFields;
CrlFields = outFields;
}
void
DecodedCrl::describeFormat(
Allocator &alloc,
uint32 &NumberOfFields,
CSSM_OID_PTR &OidList)
{
CSSM_OID_PTR oidList = (CSSM_OID_PTR)alloc.malloc(
NUM_KNOWN_FIELDS * sizeof(CSSM_OID));
memset(oidList, 0, NUM_KNOWN_FIELDS * sizeof(CSSM_OID));
for(unsigned i=0; i<NUM_KNOWN_FIELDS; i++) {
CssmAutoData oidCopy(alloc, *crlFieldTable[i].fieldId);
oidList[i] = oidCopy.release();
}
NumberOfFields = NUM_KNOWN_FIELDS;
OidList = oidList;
}