#include <Security/cssmtype.h>
#include <Security/cssmapi.h>
#include <utilLib/common.h>
#include <clAppUtils/timeStr.h>
#include <clAppUtils/crlUtils.h>
#include <Security/oidsattr.h>
#include <Security/oidscert.h>
#include <Security/oidscrl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <security_cdsa_utilities/Schema.h>
#define CRL_ADD_TO_DB 0
#if CRL_ADD_TO_DB
#include <Security/SecCertificatePriv.h>
static CSSM_RETURN crlAddCrlSchema(
CSSM_DL_DB_HANDLE dlDbHand)
{
return CSSM_DL_CreateRelation(dlDbHand,
CSSM_DL_DB_RECORD_X509_CRL,
"CSSM_DL_DB_RECORD_X509_CRL",
Security::KeychainCore::Schema::X509CrlSchemaAttributeCount,
Security::KeychainCore::Schema::X509CrlSchemaAttributeList,
Security::KeychainCore::Schema::X509CrlSchemaIndexCount,
Security::KeychainCore::Schema::X509CrlSchemaIndexList);
}
static void crlInferCrlLabel(
const CSSM_X509_NAME *x509Name,
CSSM_DATA *label) {
const CSSM_DATA *printValue = SecInferLabelFromX509Name(x509Name);
if(printValue == NULL) {
label->Data = (uint8 *)"X509 CRL";
label->Length = 8;
}
else {
*label = *printValue;
}
}
static bool crlSearchNumericExtension(
const CSSM_X509_EXTENSIONS *extens,
const CSSM_OID *oid,
uint32 *val)
{
for(uint32 dex=0; dex<extens->numberOfExtensions; dex++) {
const CSSM_X509_EXTENSION *exten = &extens->extensions[dex];
if(!appCompareCssmData(&exten->extnId, oid)) {
continue;
}
if(exten->format != CSSM_X509_DATAFORMAT_PARSED) {
printf("***Malformed extension\n");
continue;
}
*val = *((uint32 *)exten->value.parsedValue);
return true;
}
return false;
}
#define MAX_CRL_ATTRS 8
CSSM_RETURN crlAddCrlToDb(
CSSM_DL_DB_HANDLE dlDbHand,
CSSM_CL_HANDLE clHand,
const CSSM_DATA *crl)
{
CSSM_DB_ATTRIBUTE_DATA attrs[MAX_CRL_ATTRS];
CSSM_DB_RECORD_ATTRIBUTE_DATA recordAttrs;
CSSM_DB_ATTRIBUTE_DATA_PTR attr = &attrs[0];
CSSM_DATA crlTypeData;
CSSM_DATA crlEncData;
CSSM_DATA printNameData;
CSSM_RETURN crtn;
CSSM_DB_UNIQUE_RECORD_PTR recordPtr;
CSSM_DATA_PTR issuer; CSSM_DATA_PTR crlValue; uint32 numFields;
CSSM_HANDLE result;
CSSM_CRL_ENCODING crlEnc = CSSM_CRL_ENCODING_DER;
const CSSM_X509_SIGNED_CRL *signedCrl;
const CSSM_X509_TBS_CERTLIST *tbsCrl;
CSSM_CRL_TYPE crlType;
CSSM_DATA thisUpdateData = {0, NULL};
CSSM_DATA nextUpdateData = {0, NULL};
char *thisUpdate, *nextUpdate;
unsigned timeLen;
uint32 crlNumber;
uint32 deltaCrlNumber;
CSSM_DATA crlNumberData;
CSSM_DATA deltaCrlNumberData;
bool crlNumberPresent = false;
bool deltaCrlPresent = false;
crtn = CSSM_CL_CrlGetFirstFieldValue(clHand,
crl,
&CSSMOID_X509V1IssuerName,
&result,
&numFields,
&issuer);
if(crtn) {
printError("CSSM_CL_CrlGetFirstFieldValue(Issuer)", crtn);
return crtn;
}
CSSM_CL_CrlAbortQuery(clHand, result);
crtn = CSSM_CL_CrlGetFirstFieldValue(clHand,
crl,
&CSSMOID_X509V2CRLSignedCrlCStruct,
&result,
&numFields,
&crlValue);
if(crtn) {
printError("CSSM_CL_CrlGetFirstFieldValue(Issuer)", crtn);
return crtn;
}
CSSM_CL_CrlAbortQuery(clHand, result);
if(crlValue == NULL) {
printf("***CSSM_CL_CrlGetFirstFieldValue: value error (1)\n");
return CSSMERR_CL_INVALID_CRL_POINTER;
}
if((crlValue->Data == NULL) ||
(crlValue->Length != sizeof(CSSM_X509_SIGNED_CRL))) {
printf("***CSSM_CL_CrlGetFirstFieldValue: value error (2)\n");
return CSSMERR_CL_INVALID_CRL_POINTER;
}
signedCrl = (const CSSM_X509_SIGNED_CRL *)crlValue->Data;
tbsCrl = &signedCrl->tbsCertList;
if(tbsCrl->version.Length == 0) {
crlType = CSSM_CRL_TYPE_X_509v1;
}
else {
uint8 vers = tbsCrl->version.Data[tbsCrl->version.Length - 1];
switch(vers) {
case 0:
crlType = CSSM_CRL_TYPE_X_509v1;
break;
case 1:
crlType = CSSM_CRL_TYPE_X_509v2;
break;
default:
printf("***Unknown version in CRL (%u)\n", vers);
crlType = CSSM_CRL_TYPE_X_509v1;
break;
}
}
crlTypeData.Data = (uint8 *)&crlType;
crlTypeData.Length = sizeof(CSSM_CRL_TYPE);
crlEncData.Data = (uint8 *)&crlEnc;
crlEncData.Length = sizeof(CSSM_CRL_ENCODING);
crlInferCrlLabel(&tbsCrl->issuer, &printNameData);
thisUpdate = x509TimeToCssmTimestring(&tbsCrl->thisUpdate, &timeLen);
if(thisUpdate == NULL) {
printf("***Badly formatted thisUpdate\n");
}
else {
thisUpdateData.Data = (uint8 *)thisUpdate;
thisUpdateData.Length = timeLen;
}
nextUpdate = x509TimeToCssmTimestring(&tbsCrl->nextUpdate, &timeLen);
if(nextUpdate == NULL) {
printf("***Badly formatted nextUpdate\n");
}
else {
nextUpdateData.Data = (uint8 *)nextUpdate;
nextUpdateData.Length = timeLen;
}
if(crlSearchNumericExtension(&tbsCrl->extensions,
&CSSMOID_CrlNumber,
&crlNumber)) {
crlNumberData.Data = (uint8 *)&crlNumber;
crlNumberData.Length = sizeof(uint32);
crlNumberPresent = true;
}
if(crlSearchNumericExtension(&tbsCrl->extensions,
&CSSMOID_DeltaCrlIndicator,
&deltaCrlNumber)) {
deltaCrlNumberData.Data = (uint8 *)&deltaCrlNumber;
deltaCrlNumberData.Length = sizeof(uint32);
deltaCrlPresent = true;
}
attr->Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_STRING;
attr->Info.Label.AttributeName = "CrlType";
attr->Info.AttributeFormat = CSSM_DB_ATTRIBUTE_FORMAT_UINT32;
attr->NumberOfValues = 1;
attr->Value = &crlTypeData;
attr++;
attr->Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_STRING;
attr->Info.Label.AttributeName = "CrlEncoding";
attr->Info.AttributeFormat = CSSM_DB_ATTRIBUTE_FORMAT_UINT32;
attr->NumberOfValues = 1;
attr->Value = &crlEncData;
attr++;
attr->Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_STRING;
attr->Info.Label.AttributeName = "PrintName";
attr->Info.AttributeFormat = CSSM_DB_ATTRIBUTE_FORMAT_BLOB;
attr->NumberOfValues = 1;
attr->Value = &printNameData;
attr++;
attr->Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_STRING;
attr->Info.Label.AttributeName = "Issuer";
attr->Info.AttributeFormat = CSSM_DB_ATTRIBUTE_FORMAT_BLOB;
attr->NumberOfValues = 1;
attr->Value = issuer;
attr++;
attr->Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_STRING;
attr->Info.Label.AttributeName = "ThisUpdate";
attr->Info.AttributeFormat = CSSM_DB_ATTRIBUTE_FORMAT_BLOB;
attr->NumberOfValues = 1;
attr->Value = &thisUpdateData;
attr++;
attr->Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_STRING;
attr->Info.Label.AttributeName = "NextUpdate";
attr->Info.AttributeFormat = CSSM_DB_ATTRIBUTE_FORMAT_BLOB;
attr->NumberOfValues = 1;
attr->Value = &nextUpdateData;
attr++;
if(crlNumberPresent) {
attr->Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_STRING;
attr->Info.Label.AttributeName = "CrlNumber";
attr->Info.AttributeFormat = CSSM_DB_ATTRIBUTE_FORMAT_UINT32;
attr->NumberOfValues = 1;
attr->Value = &crlNumberData;
attr++;
}
if(deltaCrlPresent) {
attr->Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_STRING;
attr->Info.Label.AttributeName = "DeltaCrlNumber";
attr->Info.AttributeFormat = CSSM_DB_ATTRIBUTE_FORMAT_UINT32;
attr->NumberOfValues = 1;
attr->Value = &deltaCrlNumberData;
attr++;
}
recordAttrs.DataRecordType = CSSM_DL_DB_RECORD_X509_CRL;
recordAttrs.SemanticInformation = 0;
recordAttrs.NumberOfAttributes = attr - attrs;
recordAttrs.AttributeData = attrs;
crtn = CSSM_DL_DataInsert(dlDbHand,
CSSM_DL_DB_RECORD_X509_CRL,
&recordAttrs,
crl,
&recordPtr);
if(crtn == CSSMERR_DL_INVALID_RECORDTYPE) {
crtn = crlAddCrlSchema(dlDbHand);
if(crtn == CSSM_OK) {
crtn = CSSM_DL_DataInsert(dlDbHand,
CSSM_DL_DB_RECORD_X509_CRL,
&recordAttrs,
crl,
&recordPtr);
}
}
if(crtn) {
printError("CSSM_DL_DataInsert", crtn);
}
else {
CSSM_DL_FreeUniqueRecord(dlDbHand, recordPtr);
}
CSSM_CL_FreeFieldValue(clHand, &CSSMOID_X509V1IssuerName, issuer);
CSSM_CL_FreeFieldValue(clHand, &CSSMOID_X509V2CRLSignedCrlCStruct,
crlValue);
free(thisUpdate);
free(nextUpdate);
return crtn;
}
#endif