#include "clNssUtils.h"
#include "clNameUtils.h"
#include "CSPAttacher.h"
#include <security_asn1/secasn1.h>
#include <security_asn1/SecNssCoder.h>
#include <security_asn1/nssUtils.h>
#include <Security/keyTemplates.h>
#include <Security/certExtensionTemplates.h>
#include <Security/oidsalg.h>
#include <Security/oidsattr.h>
#include <Security/cssmapple.h>
#include <string.h>
#pragma mark ----- ArenaAllocator -----
void *ArenaAllocator::malloc(size_t len) throw(std::bad_alloc)
{
try {
return mCoder.malloc(len);
}
catch (...) {
throw std::bad_alloc();
}
}
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 -----
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;
}
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);
}
}
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)
{
if((cdata.Length == 0) || (cdata.Data == NULL)) {
return 0;
}
uint32 len = cdata.Length;
if(len > sizeof(uint32)) {
if(toThrow == 0) {
len = sizeof(uint32);
}
else {
CssmError::throwMe(toThrow);
}
}
uint32 rtn = 0;
uint8 *cp = cdata.Data;
for(uint32 i=0; i<len; i++) {
rtn = (rtn << 8) | *cp++;
}
return rtn;
}
void clIntToData(
uint32 num,
CSSM_DATA &cdata,
Allocator &alloc)
{
uint32 len = 0;
if(num < 0x100) {
len = 1;
}
else if(num < 0x10000) {
len = 2;
}
else if(num < 0x1000000) {
len = 3;
}
else {
len = 4;
}
clAllocData(alloc, cdata, len);
uint8 *cp = &cdata.Data[len - 1];
for(unsigned i=0; i<len; i++) {
*cp-- = num & 0xff;
num >>= 8;
}
}
#pragma mark ----- CSSM_BOOL <--> CSSM_DATA -----
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 -----
void clCssmBitStringToNss(
CSSM_DATA &b)
{
int numBits = b.Length * 8;
bool foundSet = false;
for(int 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;
}
}
assert(((numBits > 0) & foundSet) || ((numBits == 0) && !foundSet));
b.Length = (uint32)numBits;
}
void clNssBitStringToCssm(
CSSM_DATA &b)
{
uint32 byteCount = (b.Length + 7) / 8;
unsigned partialBits = b.Length & 0x7;
b.Length = byteCount;
if(partialBits == 0) {
return;
}
unsigned unusedBits = 8 - partialBits;
uint8 *bp = b.Data + b.Length - 1;
unsigned mask = (1 << unusedBits) - 1;
*bp &= ~mask;
}
#pragma mark ----- NSS array manipulation -----
unsigned clNssArraySize(
const void **array)
{
unsigned count = 0;
if (array) {
while (*array++) {
count++;
}
}
return count;
}
void **clNssNullArray(
uint32 num,
SecNssCoder &coder)
{
unsigned len = (num + 1) * sizeof(void *);
void **p = (void **)coder.malloc(len);
memset(p, 0, len);
return p;
}
CE_KeyUsage clBitStringToKeyUsage(
const CSSM_DATA &cdata)
{
unsigned toCopy = (cdata.Length + 7) / 8;
if(toCopy > 2) {
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 -----
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, 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 -----
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;
}
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 -----
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;
}
}
CSSM_KEY_PTR CL_extractCSSMKeyNSS(
const CSSM_X509_SUBJECT_PUBLIC_KEY_INFO &keyInfo,
Allocator &alloc,
const DecodedCert *decodedCert) {
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;
hdr.BlobType = CSSM_KEYBLOB_RAW;
hdr.AlgorithmId = CL_oidToAlg(keyInfo.algorithm.algorithm);
hdr.KeyAttr = CSSM_KEYATTR_MODIFIABLE | CSSM_KEYATTR_EXTRACTABLE;
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:
hdr.Format = CSSM_KEYBLOB_RAW_FORMAT_NONE;
break;
default:
hdr.Format = CSSM_KEYBLOB_RAW_FORMAT_NONE;
}
hdr.KeyClass = CSSM_KEYCLASS_PUBLIC_KEY;
if(decodedCert) {
hdr.KeyUsage = decodedCert->inferKeyUsage();
}
else {
hdr.KeyUsage = CSSM_KEYUSE_ANY;
}
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:
{
PRErrorCode prtn = SecNssEncodeItemOdata(&keyInfo,
kSecAsn1SubjectPublicKeyInfoTemplate, keyData);
if(prtn) {
clErrorLog("extractCSSMKey: error on reencode\n");
CssmError::throwMe(CSSMERR_CL_MEMORY_ERROR);
}
break;
}
default:
keyData.copy(keyInfo.subjectPublicKey.Data,
(keyInfo.subjectPublicKey.Length + 7) / 8);
}
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:
hdr.KeyAttr |= CSSM_KEYATTR_PARTIAL;
case CSSM_OK:
cssmKey->KeyHeader.LogicalKeySizeInBits =
keySize.LogicalKeySizeInBits;
break;
}
keyData.release();
return cssmKey;
}
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;
}
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));
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);
}
default:
{
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);
CL_nullAlgParams(algId);
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);
}
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 ) {
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, Allocator &alloc)
{
if(nssObj.keyIdentifier != NULL) {
cdsaObj.keyIdentifierPresent = CSSM_TRUE;
clAllocCopyData(alloc, *nssObj.keyIdentifier, cdsaObj.keyIdentifier);
}
if(nssObj.genNames.names != NULL) {
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<numDescs; dex++) {
nssObj.accessDescriptions[dex] = coder.mallocn<NSS_AccessDescription>();
CE_AccessDescription *src = &cdsaObj.accessDescriptions[dex];
NSS_AccessDescription *dst = nssObj.accessDescriptions[dex];
coder.allocCopyItem(src->accessMethod, dst->accessMethod);
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, 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; dex<numDescs; dex++) {
CE_AccessDescription *dst = &cdsaObj.accessDescriptions[dex];
NSS_AccessDescription *src = nssObj.accessDescriptions[dex];
clAllocCopyData(alloc, src->accessMethod, dst->accessMethod);
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);
}
CL_nssGeneralNameToCssm(nssGenName, dst->accessLocation, coder, alloc);
}
}
void CL_freeInfoAccess(
CE_AuthorityInfoAccess &cssmInfo,
Allocator &alloc)
{
uint32 numDescs = cssmInfo.numAccessDescriptions;
for(unsigned dex=0; dex<numDescs; dex++) {
CE_AccessDescription *dst = &cssmInfo.accessDescriptions[dex];
alloc.free(dst->accessMethod.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; dex<numQcs; dex++) {
nssObj.qcStatements[dex] = (NSS_QC_Statement *)
coder.malloc(sizeof(NSS_QC_Statement));
NSS_QC_Statement *dst = nssObj.qcStatements[dex];
CE_QC_Statement *src = &cdsaObj.qcStatements[dex];
memset(dst, 0, sizeof(*dst));
coder.allocCopyItem(src->statementId, dst->statementId);
if(src->semanticsInfo) {
if(src->otherInfo) {
CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER);
}
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) {
coder.allocCopyItem(*src->otherInfo, dst->info);
}
}
}
void CL_qualCertStatementsToCssm(
const NSS_QC_Statements &nssObj,
CE_QC_Statements &cdsaObj,
SecNssCoder &coder, 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; dex<numQcs; dex++) {
CE_QC_Statement *dst = &cdsaObj.qcStatements[dex];
NSS_QC_Statement *src = nssObj.qcStatements[dex];
memset(dst, 0, sizeof(*dst));
clAllocCopyData(alloc, src->statementId, dst->statementId);
if(src->info.Data) {
if(clCompareCssmData(&src->statementId, &CSSMOID_OID_QCS_SYNTAX_V2)) {
NSS_SemanticsInformation srcSI;
memset(&srcSI, 0, sizeof(srcSI));
PRErrorCode prtn = coder.decodeItem(src->info,
kSecAsn1SemanticsInformationTemplate, &srcSI);
if(prtn) {
clErrorLog("***Error decoding CE_SemanticsInformation\n");
CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
}
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; dex<numQCs; dex++) {
CE_QC_Statement *dst = &cssmQCs.qcStatements[dex];
alloc.free(dst->statementId.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 -----
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:
{
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));
CL_nssGeneralNamesToCssm(gnames,
*cssmDpn.dpn.fullName, coder, alloc);
break;
}
case NSS_DIST_POINT_RDN_TAG:
{
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));
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;
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; dex<numPoints; dex++) {
nssObj.distPoints[dex] = (NSS_DistributionPoint *)
coder.malloc(sizeof(NSS_DistributionPoint));
NSS_DistributionPoint *npoint = nssObj.distPoints[dex];
memset(npoint, 0, sizeof(NSS_DistributionPoint));
CE_CRLDistributionPoint *cpoint = &cdsaObj.distPoints[dex];
if(cpoint->distPointName) {
npoint->distPointName = (CSSM_DATA *)
coder.malloc(sizeof(CSSM_DATA));
CL_encodeDistributionPointName(*cpoint->distPointName,
*npoint->distPointName, coder);
}
if(cpoint->reasonsPresent) {
coder.allocItem(npoint->reasons, 1);
npoint->reasons.Data[0] = cpoint->reasons;
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, 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<numPoints; dex++) {
CE_CRLDistributionPoint &cpoint = cdsaObj.distPoints[dex];
NSS_DistributionPoint &npoint = *(nssObj.distPoints[dex]);
if(npoint.distPointName != NULL) {
CE_DistributionPointName *cname =
(CE_DistributionPointName *)alloc.malloc(
sizeof(CE_DistributionPointName));
memset(cname, 0, sizeof(*cname));
cpoint.distPointName = cname;
CL_decodeDistributionPointName(*npoint.distPointName,
*cname, coder, alloc);
}
if(npoint.reasons.Data != NULL) {
if(npoint.reasons.Length > 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) {
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)
{
memset(cssmIdp, 0, sizeof(*cssmIdp));
if(nssIdp->distPointName) {
CE_DistributionPointName *cssmDp = (CE_DistributionPointName *)
alloc.malloc(sizeof(CE_DistributionPointName));
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)
{
}
void CL_nssNameConstraintsToCssm(
const NSS_NameConstraints &nssObj,
CE_NameConstraints &cdsaObj,
SecNssCoder &coder, Allocator &alloc)
{
}
void CL_freeCssmNameConstraints(
CE_NameConstraints *cssmNcs,
Allocator &alloc)
{
if(cssmNcs == NULL) {
return;
}
#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)
{
}
void CL_nssPolicyMappingsToCssm(
const NSS_PolicyMappings &nssObj,
CE_PolicyMappings &cdsaObj,
SecNssCoder &coder, Allocator &alloc)
{
}
void CL_freeCssmPolicyMappings(
CE_PolicyMappings *cssmPms,
Allocator &alloc)
{
if(cssmPms == NULL) {
return;
}
memset(cssmPms, 0, sizeof(*cssmPms));
}
#pragma mark --- CE_PolicyConstraints <--> NSS_PolicyConstraints ---
void CL_cssmPolicyConstraintsToNss(
const CE_PolicyConstraints *cdsaObj,
NSS_PolicyConstraints *nssObj,
SecNssCoder &coder)
{
}
void CL_nssPolicyConstraintsToCssm(
const NSS_PolicyConstraints *nssObj,
CE_PolicyConstraints *cdsaObj,
SecNssCoder &coder, 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 -----
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);
}
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 -----
void CL_certCrlDecodeComponents(
const CssmData &signedItem, CssmOwnedData &tbsBlob, CssmOwnedData &algId, CssmOwnedData &rawSig) {
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.copy(nssObj.tbsBlob.Data, nssObj.tbsBlob.Length);
algId.copy(nssObj.signatureAlgorithm.Data,
nssObj.signatureAlgorithm.Length);
rawSig.copy(nssObj.signature.Data,
(nssObj.signature.Length + 7) / 8);
}
void
CL_certEncodeComponents(
const CssmData &TBSCert, const CssmData &algId, const CssmData &rawSig, CssmOwnedData &signedCert) {
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;
PRErrorCode prtn;
prtn = SecNssEncodeItemOdata(&nssObj,
kSecAsn1SignedCertOrCRLTemplate,signedCert);
if(prtn) {
CssmError::throwMe(CSSMERR_CL_MEMORY_ERROR);
}
}