--- /dev/null
+/*
+ * Copyright (c) 2003,2011-2012,2014 Apple 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.
+ */
+
+/*
+ * clNameUtils.cpp - support for Name, GeneralizedName, all sorts of names
+ */
+
+#include "clNameUtils.h"
+#include "clNssUtils.h"
+#include "cldebugging.h"
+#include <security_utilities/utilities.h>
+
+#pragma mark ----- NSS_Name <--> CSSM_X509_NAME -----
+
+/*
+ * NSS_ATV --> CSSM_X509_TYPE_VALUE_PAIR
+ */
+static
+void CL_nssAtvToCssm(
+ const NSS_ATV &nssObj,
+ CSSM_X509_TYPE_VALUE_PAIR &cssmObj,
+ Allocator &alloc)
+{
+ /* tag and decoded data */
+ cssmObj.valueType = nssObj.value.tag;
+ clAllocCopyData(alloc, nssObj.value.item, cssmObj.value);
+ /* the OID */
+ clAllocCopyData(alloc, nssObj.type, cssmObj.type);
+}
+
+/* NSS_RDN --> CSSM_X509_RDN */
+void CL_nssRdnToCssm(
+ const NSS_RDN &nssObj,
+ CSSM_X509_RDN &cssmObj,
+ Allocator &alloc,
+ SecNssCoder &coder) // conversion requires further decoding
+{
+ memset(&cssmObj, 0, sizeof(cssmObj));
+ unsigned numAtvs = clNssArraySize((const void **)nssObj.atvs);
+ if(numAtvs == 0) {
+ return;
+ }
+
+ size_t len = numAtvs * sizeof(CSSM_X509_TYPE_VALUE_PAIR);
+ cssmObj.AttributeTypeAndValue =
+ (CSSM_X509_TYPE_VALUE_PAIR_PTR)alloc.malloc(len);
+ cssmObj.numberOfPairs = numAtvs;
+ CSSM_X509_TYPE_VALUE_PAIR_PTR cssmAtvs = cssmObj.AttributeTypeAndValue;
+ memset(cssmAtvs, 0, len);
+
+ for(unsigned dex=0; dex<numAtvs; dex++) {
+ CL_nssAtvToCssm(*(nssObj.atvs[dex]), cssmAtvs[dex], alloc);
+ }
+ return;
+}
+
+/* NSS_Name --> CSSM_X509_NAME */
+void CL_nssNameToCssm(
+ const NSS_Name &nssObj,
+ CSSM_X509_NAME &cssmObj,
+ Allocator &alloc)
+{
+ memset(&cssmObj, 0, sizeof(cssmObj));
+ unsigned numRdns = clNssArraySize((const void **)nssObj.rdns);
+ if(numRdns == 0) {
+ /* not technically an error */
+ return;
+ }
+
+ size_t len = numRdns * sizeof(CSSM_X509_RDN);
+ cssmObj.RelativeDistinguishedName = (CSSM_X509_RDN_PTR)alloc.malloc(len);
+ cssmObj.numberOfRDNs = numRdns;
+ CSSM_X509_RDN_PTR cssmRdns = cssmObj.RelativeDistinguishedName;
+ memset(cssmRdns, 0, len);
+
+ SecNssCoder coder; // conversion requires further decoding
+
+ for(unsigned dex=0; dex<numRdns; dex++) {
+ CL_nssRdnToCssm(*(nssObj.rdns[dex]), cssmRdns[dex], alloc, coder);
+ }
+ return;
+}
+
+/*
+ * CSSM_X509_TYPE_VALUE_PAIR --> NSS_ATV
+ */
+void CL_cssmAtvToNss(
+ const CSSM_X509_TYPE_VALUE_PAIR &cssmObj,
+ NSS_ATV &nssObj,
+ SecNssCoder &coder)
+{
+ memset(&nssObj, 0, sizeof(nssObj));
+
+ /* copy the OID */
+ coder.allocCopyItem(cssmObj.type, nssObj.type);
+
+ /* tag and value */
+ nssObj.value.tag = cssmObj.valueType;
+ coder.allocCopyItem(cssmObj.value, nssObj.value.item);
+}
+
+/* CSSM_X509_RDN --> NSS_RDN */
+void CL_cssmRdnToNss(
+ const CSSM_X509_RDN &cssmObj,
+ NSS_RDN &nssObj,
+ SecNssCoder &coder)
+{
+ memset(&nssObj, 0, sizeof(nssObj));
+
+ /* alloc NULL-terminated array of ATV pointers */
+ unsigned numAtvs = cssmObj.numberOfPairs;
+ unsigned size = (numAtvs + 1) * sizeof(void *);
+ nssObj.atvs = (NSS_ATV **)coder.malloc(size);
+ memset(nssObj.atvs, 0, size);
+
+ /* grind thru the elements */
+ for(unsigned atvDex=0; atvDex<numAtvs; atvDex++) {
+ nssObj.atvs[atvDex] = (NSS_ATV *)coder.malloc(sizeof(NSS_ATV));
+ CL_cssmAtvToNss(cssmObj.AttributeTypeAndValue[atvDex],
+ *nssObj.atvs[atvDex], coder);
+ }
+}
+
+/* CSSM_X509_NAME --> NSS_Name */
+void CL_cssmNameToNss(
+ const CSSM_X509_NAME &cssmObj,
+ NSS_Name &nssObj,
+ SecNssCoder &coder)
+{
+ memset(&nssObj, 0, sizeof(nssObj));
+
+ /* alloc NULL-terminated array of RDN pointers */
+ unsigned numRdns = cssmObj.numberOfRDNs;
+ nssObj.rdns = (NSS_RDN **)clNssNullArray(numRdns, coder);
+
+ /* grind thru the elements */
+ for(unsigned rdnDex=0; rdnDex<numRdns; rdnDex++) {
+ nssObj.rdns[rdnDex] = (NSS_RDN *)coder.malloc(sizeof(NSS_RDN));
+ CL_cssmRdnToNss(cssmObj.RelativeDistinguishedName[rdnDex],
+ *nssObj.rdns[rdnDex], coder);
+ }
+}
+
+#pragma mark ----- Name Normalization -----
+
+void CL_normalizeString(
+ char *strPtr,
+ int &strLen) // IN/OUT
+{
+ char *pCh = strPtr; // working ptr
+ char *pD = pCh; // start of good string chars
+ char *pEos = pCh + strLen - 1;
+
+ if(strLen == 0) {
+ return;
+ }
+
+ /* adjust if Length included NULL terminator */
+ while(*pEos == 0) {
+ pEos--;
+ }
+
+ /* Remove trailing spaces */
+ while(isspace(*pEos)) {
+ pEos--;
+ }
+
+ /* Point to one past last non-space character */
+ pEos++;
+
+ /* upper case */
+ while(pCh < pEos) {
+ *pCh = toupper(*pCh);
+ pCh++;
+ }
+
+ /* clean out whitespace */
+ /*
+ * 1. skip all leading whitespace
+ */
+ pCh = pD;
+ while(isspace(*pCh) && (pCh < pEos)) {
+ pCh++;
+ }
+
+ /*
+ * 2. eliminate multiple whitespace.
+ * pCh points to first non-white char.
+ * pD still points to start of string
+ */
+ char ch;
+ while(pCh < pEos) {
+ ch = *pCh++;
+ *pD++ = ch; // normal case
+ if( isspace(ch) ){
+ /* skip 'til next nonwhite */
+ while(isspace(*pCh) && (pCh < pEos)) {
+ pCh++;
+ }
+ }
+ };
+
+ strLen = (int)(pD - strPtr);
+}
+
+/*
+ * Normalize an RDN. Per RFC2459 (4.1.2.4), printable strings are case
+ * insensitive and we're supposed to ignore leading and trailing
+ * whitespace, and collapse multiple whitespace characters into one.
+ *
+ * Incoming NSS_Name is assumed to be entirely within specifed coder's
+ * address space; we'll be munging some of that and possibly replacing
+ * some pointers with others allocated from the same space.
+ */
+void CL_normalizeX509NameNSS(
+ NSS_Name &nssName,
+ SecNssCoder &coder)
+{
+ unsigned numRdns = clNssArraySize((const void **)nssName.rdns);
+ if(numRdns == 0) {
+ /* not technically an error */
+ return;
+ }
+
+ for(unsigned rdnDex=0; rdnDex<numRdns; rdnDex++) {
+ NSS_RDN *rdn = nssName.rdns[rdnDex];
+ assert(rdn != NULL);
+ unsigned numAttrs = clNssArraySize((const void **)rdn->atvs);
+ if(numAttrs == 0) {
+ clFieldLog("clNormalizeX509Name: zero numAttrs at index %d", rdnDex);
+ continue;
+ }
+
+ /* descend into array of attribute/values */
+ for(unsigned attrDex=0; attrDex<numAttrs; attrDex++) {
+ NSS_ATV *attr = rdn->atvs[attrDex];
+ assert(attr != NULL);
+
+ /*
+ * attr->value is an ASN_ANY containing an encoded
+ * string. We only normalize Prinatable String types.
+ * If we find one, decode it, normalize it, encode the
+ * result, and put the encoding back in attr->value.
+ * We temporarily "leak" the original string, which only
+ * has a lifetime of the incoming SecNssCoder.
+ */
+ NSS_TaggedItem &attrVal = attr->value;
+ if(attrVal.tag != SEC_ASN1_PRINTABLE_STRING) {
+ /* skip it */
+ continue;
+ }
+
+ /* normalize */
+ char *strPtr = (char *)attrVal.item.Data;
+ int newLen = (int)attrVal.item.Length;
+ CL_normalizeString(strPtr, newLen);
+
+ /* possible length adjustment */
+ attrVal.item.Length = newLen;
+ } /* for each attribute/value */
+ } /* for each RDN */
+}
+
+#pragma mark ----- CE_GeneralNames <--> NSS_GeneralNames -----
+
+void CL_nssGeneralNameToCssm(
+ NSS_GeneralName &nssObj,
+ CE_GeneralName &cdsaObj,
+ SecNssCoder &coder, // for temp decoding
+ Allocator &alloc) // destination
+{
+ memset(&cdsaObj, 0, sizeof(cdsaObj));
+ PRErrorCode prtn;
+
+ /* for caller's CE_GeneralName */
+ CSSM_BOOL berEncoded = CSSM_FALSE;
+ CE_GeneralNameType cdsaTag;
+
+ /*
+ * At this point, depending on the decoded object's tag, we either
+ * have the final bytes to copy out, or we need to decode further.
+ * After this switch, if doCopy is true, give the caller a copy
+ * of nssObj.item.
+ */
+ bool doCopy = true;
+ switch(nssObj.tag) {
+ case NGT_OtherName: // ASN_ANY -> CE_OtherName
+ {
+ cdsaTag = GNT_OtherName;
+
+ /* decode to coder memory */
+ CE_OtherName *nssOther =
+ (CE_OtherName *)coder.malloc(sizeof(CE_OtherName));
+ memset(nssOther, 0, sizeof(CE_OtherName));
+ prtn = coder.decodeItem(nssObj.item,
+ kSecAsn1GenNameOtherNameTemplate,
+ nssOther);
+ if(prtn) {
+ clErrorLog("CL_nssGeneralNameToCssm: error decoding "
+ "OtherName\n");
+ CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
+ }
+
+ /* copy out to caller */
+ clAllocData(alloc, cdsaObj.name, sizeof(CE_OtherName));
+ clCopyOtherName(*nssOther, *((CE_OtherName *)cdsaObj.name.Data),
+ alloc);
+ doCopy = false;
+ break;
+ }
+ case NGT_RFC822Name: // IA5String, done
+ cdsaTag = GNT_RFC822Name;
+ break;
+ case NGT_DNSName: // IA5String
+ cdsaTag = GNT_DNSName;
+ break;
+ case NGT_X400Address: // ASY_ANY, leave alone
+ cdsaTag = GNT_X400Address;
+ berEncoded = CSSM_TRUE;
+ break;
+ case NGT_DirectoryName: // ASN_ANY --> NSS_Name
+ {
+ cdsaTag = GNT_DirectoryName;
+
+ /* Decode to coder memory */
+ NSS_Name *nssName = (NSS_Name *)coder.malloc(sizeof(NSS_Name));
+ memset(nssName, 0, sizeof(NSS_Name));
+ prtn = coder.decodeItem(nssObj.item, kSecAsn1NameTemplate, nssName);
+ if(prtn) {
+ clErrorLog("CL_nssGeneralNameToCssm: error decoding "
+ "NSS_Name\n");
+ CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
+ }
+
+ /* convert & copy out to caller */
+ clAllocData(alloc, cdsaObj.name, sizeof(CSSM_X509_NAME));
+ CL_nssNameToCssm(*nssName,
+ *((CSSM_X509_NAME *)cdsaObj.name.Data), alloc);
+ doCopy = false;
+ break;
+ }
+ case NGT_EdiPartyName: // ASN_ANY, leave alone
+ cdsaTag = GNT_EdiPartyName;
+ berEncoded = CSSM_TRUE;
+ break;
+ case NGT_URI: // IA5String
+ cdsaTag = GNT_URI;
+ break;
+ case NGT_IPAddress: // OCTET_STRING
+ cdsaTag = GNT_IPAddress;
+ break;
+ case NGT_RegisteredID: // OID
+ cdsaTag = GNT_RegisteredID;
+ break;
+ default:
+ clErrorLog("CL_nssGeneralNameToCssm: bad name tag\n");
+ CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
+ }
+
+ cdsaObj.nameType = cdsaTag;
+ cdsaObj.berEncoded = berEncoded;
+ if(doCopy) {
+ clAllocCopyData(alloc, nssObj.item, cdsaObj.name);
+ }
+}
+
+void CL_nssGeneralNamesToCssm(
+ const NSS_GeneralNames &nssObj,
+ CE_GeneralNames &cdsaObj,
+ SecNssCoder &coder, // for temp decoding
+ Allocator &alloc) // destination
+{
+ memset(&cdsaObj, 0, sizeof(cdsaObj));
+ unsigned numNames = clNssArraySize((const void **)nssObj.names);
+ if(numNames == 0) {
+ return;
+ }
+
+ /*
+ * Decode each name element, currently a raw ASN_ANY blob.
+ * Then convert each result into CDSA form.
+ * This array of (NSS_GeneralName)s is temporary, it doesn't
+ * persist outside of this routine other than the fact that it's
+ * mallocd by the coder arena pool.
+ */
+ NSS_GeneralName *names =
+ (NSS_GeneralName *)coder.malloc(sizeof(NSS_GeneralName) * numNames);
+ memset(names, 0, sizeof(NSS_GeneralName) * numNames);
+ cdsaObj.generalName = (CE_GeneralName *)alloc.malloc(
+ sizeof(CE_GeneralName) * numNames);
+ cdsaObj.numNames = numNames;
+
+ for(unsigned dex=0; dex<numNames; dex++) {
+ if(coder.decodeItem(*nssObj.names[dex], kSecAsn1GeneralNameTemplate,
+ &names[dex])) {
+ clErrorLog("***CL_nssGeneralNamesToCssm: Error decoding "
+ "General.name\n");
+ CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
+ }
+
+ CL_nssGeneralNameToCssm(names[dex],
+ cdsaObj.generalName[dex],
+ coder, alloc);
+ }
+}
+
+void CL_cssmGeneralNameToNss(
+ CE_GeneralName &cdsaObj,
+ NSS_GeneralName &nssObj, // actually an NSSTaggedItem
+ SecNssCoder &coder) // for temp decoding
+{
+ memset(&nssObj, 0, sizeof(nssObj));
+
+ /*
+ * The default here is just to use the app-supplied data as is...
+ */
+ nssObj.item = cdsaObj.name;
+ unsigned char itemTag; // for nssObj.tag
+ bool doCopy = false; // unless we have to modify tag byte
+ unsigned char overrideTag; // to force context-specific tag for
+ // an ASN_ANY
+ PRErrorCode prtn;
+
+ switch(cdsaObj.nameType) {
+ case GNT_OtherName:
+ /*
+ * Caller supplies an CE_OtherName. Encode it.
+ */
+ if((cdsaObj.name.Length != sizeof(CE_OtherName)) ||
+ (cdsaObj.name.Data == NULL)) {
+ clErrorLog("CL_cssmGeneralNameToNss: OtherName.Length"
+ " error\n");
+ CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
+ }
+ prtn = coder.encodeItem(cdsaObj.name.Data,
+ kSecAsn1OtherNameTemplate, nssObj.item);
+ if(prtn) {
+ clErrorLog("CL_cssmGeneralNameToNss: OtherName encode"
+ " error\n");
+ CssmError::throwMe(CSSMERR_CL_MEMORY_ERROR);
+ }
+ itemTag = NGT_OtherName;
+ break;
+ case GNT_RFC822Name: // IA5String
+ itemTag = NGT_RFC822Name;
+ break;
+ case GNT_DNSName: // IA5String
+ itemTag = NGT_DNSName;
+ break;
+ case GNT_X400Address: // caller's resposibility
+ /*
+ * Encoded as ASN_ANY, the only thing we do is to
+ * force the correct context-specific tag
+ */
+ itemTag = GNT_X400Address;
+ if(!cdsaObj.berEncoded) {
+ clErrorLog("CL_cssmGeneralNameToNss: X400Address must"
+ " be BER-encoded\n");
+ CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
+ }
+ overrideTag = SEC_ASN1_CONTEXT_SPECIFIC |
+ SEC_ASN1_CONSTRUCTED | NGT_X400Address;
+ doCopy = true;
+ break;
+ case GNT_DirectoryName:
+ {
+ /*
+ * Caller supplies an CSSM_X509_NAME. Convert to NSS
+ * format and encode it.
+ */
+ if((cdsaObj.name.Length != sizeof(CSSM_X509_NAME)) ||
+ (cdsaObj.name.Data == NULL)) {
+ clErrorLog("CL_cssmGeneralNameToNss: DirectoryName.Length"
+ " error\n");
+ CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
+ }
+ NSS_Name nssName;
+ CSSM_X509_NAME_PTR cdsaName =
+ (CSSM_X509_NAME_PTR)cdsaObj.name.Data;
+ CL_cssmNameToNss(*cdsaName, nssName, coder);
+ prtn = coder.encodeItem(&nssName,
+ kSecAsn1NameTemplate, nssObj.item);
+ if(prtn) {
+ clErrorLog("CL_cssmGeneralNameToNss: X509Name encode"
+ " error\n");
+ CssmError::throwMe(CSSMERR_CL_MEMORY_ERROR);
+ }
+ itemTag = GNT_DirectoryName;
+
+ /*
+ * AND, munge the tag to make it a context-specific
+ * sequence
+ * no, not needed, this is wrapped in an explicit...
+ */
+ //nssObj.item.Data[0] = SEC_ASN1_CONTEXT_SPECIFIC |
+ // SEC_ASN1_CONSTRUCTED | GNT_DirectoryName;
+
+ break;
+ }
+ case GNT_EdiPartyName: // caller's resposibility
+ /*
+ * Encoded as ASN_ANY, the only thing we do is to
+ * force the correct context-specific tag
+ */
+ itemTag = GNT_EdiPartyName;
+ if(!cdsaObj.berEncoded) {
+ clErrorLog("CL_cssmGeneralNameToNss: EdiPartyName must"
+ " be BER-encoded\n");
+ CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
+ }
+ overrideTag = SEC_ASN1_CONTEXT_SPECIFIC | NGT_X400Address;
+ doCopy = true;
+ break;
+ case GNT_URI: // IA5String
+ itemTag = GNT_URI;
+ break;
+ case GNT_IPAddress: // OCTET_STRING
+ itemTag = NGT_IPAddress;
+ break;
+ case GNT_RegisteredID: // OID
+ itemTag = NGT_RegisteredID;
+ break;
+ default:
+ clErrorLog("CL_cssmGeneralNameToNss: bad name tag\n");
+ CssmError::throwMe(CSSMERR_CL_UNKNOWN_TAG);
+ }
+ if(doCopy) {
+ coder.allocCopyItem(cdsaObj.name, nssObj.item);
+ nssObj.item.Data[0] = overrideTag;
+ }
+ nssObj.tag = itemTag;
+}
+
+void CL_cssmGeneralNamesToNss(
+ const CE_GeneralNames &cdsaObj,
+ NSS_GeneralNames &nssObj,
+ SecNssCoder &coder)
+{
+ uint32 numNames = cdsaObj.numNames;
+ nssObj.names = (CSSM_DATA **)clNssNullArray(numNames, coder);
+
+ /*
+ * Convert each element in cdsaObj to NSS form, encode, drop into
+ * the ASN_ANY array.
+ *
+ * This array of (NSS_GeneralName)s is temporary, it doesn't
+ * persist outside of this routine other than the fact that it's
+ * mallocd by the coder arena pool.
+ */
+ NSS_GeneralName *names =
+ (NSS_GeneralName *)coder.malloc(sizeof(NSS_GeneralName) * numNames);
+ memset(names, 0, sizeof(NSS_GeneralName) * numNames);
+ for(unsigned dex=0; dex<cdsaObj.numNames; dex++) {
+ nssObj.names[dex] = (CSSM_DATA_PTR)coder.malloc(sizeof(CSSM_DATA));
+ memset(nssObj.names[dex], 0, sizeof(CSSM_DATA));
+ CL_cssmGeneralNameToNss(cdsaObj.generalName[dex],
+ names[dex], coder);
+ if(coder.encodeItem(&names[dex], kSecAsn1GeneralNameTemplate,
+ *nssObj.names[dex])) {
+ clErrorLog("***Error encoding General.name\n");
+ CssmError::throwMe(CSSMERR_CL_MEMORY_ERROR);
+ }
+ }
+}
+
+/* Copy a CE_OtherName */
+void clCopyOtherName(
+ const CE_OtherName &src,
+ CE_OtherName &dst,
+ Allocator &alloc)
+{
+ clAllocCopyData(alloc, src.typeId, dst.typeId);
+ clAllocCopyData(alloc, src.value, dst.value);
+}
+
+#pragma mark ----- Name-related Free -----
+
+void CL_freeAuthorityKeyId(
+ CE_AuthorityKeyID &cdsaObj,
+ Allocator &alloc)
+{
+ alloc.free(cdsaObj.keyIdentifier.Data);
+ CL_freeCssmGeneralNames(cdsaObj.generalNames, alloc);
+ alloc.free(cdsaObj.generalNames);
+ alloc.free(cdsaObj.serialNumber.Data);
+ memset(&cdsaObj, 0, sizeof(CE_AuthorityKeyID));
+}
+
+void CL_freeCssmGeneralName(
+ CE_GeneralName &genName,
+ Allocator &alloc)
+{
+ switch(genName.nameType) {
+ /*
+ * Two special cases here.
+ */
+ case GNT_DirectoryName:
+ if((!genName.berEncoded) && // we're flexible
+ (genName.name.Length ==
+ sizeof(CSSM_X509_NAME))) { // paranoia
+ CL_freeX509Name((CSSM_X509_NAME_PTR)genName.name.Data, alloc);
+ }
+ break;
+
+ case GNT_OtherName:
+ if((!genName.berEncoded) && // we're flexible
+ (genName.name.Length ==
+ sizeof(CE_OtherName))) { // paranoia
+ CE_OtherName *con = (CE_OtherName *)genName.name.Data;
+ CL_freeOtherName(con, alloc);
+ }
+ break;
+ default:
+ break;
+ }
+ /* and always free this */
+ alloc.free(genName.name.Data);
+}
+
+void CL_freeCssmGeneralNames(
+ CE_GeneralNames *cdsaObj,
+ Allocator &alloc)
+{
+ if(cdsaObj == NULL) {
+ return;
+ }
+ for(unsigned i=0; i<cdsaObj->numNames; i++) {
+ CL_freeCssmGeneralName(cdsaObj->generalName[i], alloc);
+ }
+ if(cdsaObj->numNames) {
+ memset(cdsaObj->generalName, 0, cdsaObj->numNames * sizeof(CE_GeneralName));
+ alloc.free(cdsaObj->generalName);
+ }
+ memset(cdsaObj, 0, sizeof(CE_GeneralNames));
+}
+
+void CL_freeCssmDistPointName(
+ CE_DistributionPointName *cssmDpn,
+ Allocator &alloc)
+{
+ if(cssmDpn == NULL) {
+ return;
+ }
+ 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;
+ }
+ memset(cssmDpn, 0, sizeof(*cssmDpn));
+}
+
+void CL_freeCssmDistPoints(
+ CE_CRLDistPointsSyntax *cssmDps,
+ Allocator &alloc)
+{
+ if(cssmDps == NULL) {
+ return;
+ }
+ for(unsigned dex=0; dex<cssmDps->numDistPoints; dex++) {
+ CE_CRLDistributionPoint *cssmDp = &cssmDps->distPoints[dex];
+ if(cssmDp->distPointName) {
+ CL_freeCssmDistPointName(cssmDp->distPointName, alloc);
+ alloc.free(cssmDp->distPointName);
+ }
+ if(cssmDp->crlIssuer) {
+ CL_freeCssmGeneralNames(cssmDp->crlIssuer, alloc);
+ alloc.free(cssmDp->crlIssuer);
+ }
+ }
+ memset(cssmDps->distPoints, 0,
+ cssmDps->numDistPoints * sizeof(CE_CRLDistributionPoint));
+ alloc.free(cssmDps->distPoints);
+ memset(cssmDps, 0, sizeof(*cssmDps));
+}
+
+/* free contents of an CSSM_X509_NAME */
+void CL_freeX509Name(
+ CSSM_X509_NAME_PTR x509Name,
+ Allocator &alloc)
+{
+ if(x509Name == NULL) {
+ return;
+ }
+ for(unsigned rdnDex=0; rdnDex<x509Name->numberOfRDNs; rdnDex++) {
+ CSSM_X509_RDN_PTR rdn = &x509Name->RelativeDistinguishedName[rdnDex];
+ CL_freeX509Rdn(rdn, alloc);
+ }
+ alloc.free(x509Name->RelativeDistinguishedName);
+ memset(x509Name, 0, sizeof(CSSM_X509_NAME));
+}
+
+void CL_freeX509Rdn(
+ CSSM_X509_RDN_PTR rdn,
+ Allocator &alloc)
+{
+ if(rdn == NULL) {
+ return;
+ }
+ for(unsigned atvDex=0; atvDex<rdn->numberOfPairs; atvDex++) {
+ CSSM_X509_TYPE_VALUE_PAIR_PTR atv =
+ &rdn->AttributeTypeAndValue[atvDex];
+ alloc.free(atv->type.Data);
+ alloc.free(atv->value.Data);
+ memset(atv, 0, sizeof(CSSM_X509_TYPE_VALUE_PAIR));
+ }
+ alloc.free(rdn->AttributeTypeAndValue);
+ memset(rdn, 0, sizeof(CSSM_X509_RDN));
+}
+
+void CL_freeOtherName(
+ CE_OtherName *cssmOther,
+ Allocator &alloc)
+{
+ if(cssmOther == NULL) {
+ return;
+ }
+ alloc.free(cssmOther->typeId.Data);
+ alloc.free(cssmOther->value.Data);
+ memset(cssmOther, 0, sizeof(*cssmOther));
+}
+
+void CL_freeCssmIssuingDistPoint(
+ CE_IssuingDistributionPoint *cssmIdp,
+ Allocator &alloc)
+{
+ CL_freeCssmDistPointName(cssmIdp->distPointName, alloc);
+}
+