1/*
2 * Copyright (c) 2003 Apple Computer, Inc. All Rights Reserved.
3 *
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
8 * using this file.
9 *
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
16 */
17
18/*
19 * clNameUtils.cpp - support for Name, GeneralizedName, all sorts of names
20 */
21
22#include "clNameUtils.h"
23#include "clNssUtils.h"
24#include "cldebugging.h"
25#include <security_utilities/utilities.h>
26
27#pragma mark ----- NSS_Name <--> CSSM_X509_NAME -----
28
29/*
30 * NSS_ATV --> CSSM_X509_TYPE_VALUE_PAIR
31 */
32static
33void CL_nssAtvToCssm(
34	const NSS_ATV				&nssObj,
35	CSSM_X509_TYPE_VALUE_PAIR	&cssmObj,
36	Allocator				&alloc)
37{
38	/* tag and decoded data */
39	cssmObj.valueType = nssObj.value.tag;
40	clAllocCopyData(alloc, nssObj.value.item, cssmObj.value);
41	/* the OID */
42	clAllocCopyData(alloc, nssObj.type, cssmObj.type);
43}
44
45/* NSS_RDN --> CSSM_X509_RDN */
46void CL_nssRdnToCssm(
47	const NSS_RDN	&nssObj,
48	CSSM_X509_RDN	&cssmObj,
49	Allocator	&alloc,
50	SecNssCoder		&coder)		// conversion requires further decoding
51{
52	memset(&cssmObj, 0, sizeof(cssmObj));
53	unsigned numAtvs = clNssArraySize((const void **)nssObj.atvs);
54	if(numAtvs == 0) {
55		return;
56	}
57
58	size_t len = numAtvs * sizeof(CSSM_X509_TYPE_VALUE_PAIR);
59	cssmObj.AttributeTypeAndValue =
60			(CSSM_X509_TYPE_VALUE_PAIR_PTR)alloc.malloc(len);
61	cssmObj.numberOfPairs = numAtvs;
62	CSSM_X509_TYPE_VALUE_PAIR_PTR cssmAtvs = cssmObj.AttributeTypeAndValue;
63	memset(cssmAtvs, 0, len);
64
65	for(unsigned dex=0; dex<numAtvs; dex++) {
66		CL_nssAtvToCssm(*(nssObj.atvs[dex]), cssmAtvs[dex], alloc);
67	}
68	return;
69}
70
71/* NSS_Name --> CSSM_X509_NAME */
72void CL_nssNameToCssm(
73	const NSS_Name	&nssObj,
74	CSSM_X509_NAME	&cssmObj,
75	Allocator	&alloc)
76{
77	memset(&cssmObj, 0, sizeof(cssmObj));
78	unsigned numRdns = clNssArraySize((const void **)nssObj.rdns);
79	if(numRdns == 0) {
80		/* not technically an error */
81		return;
82	}
83
84	size_t len = numRdns * sizeof(CSSM_X509_RDN);
85	cssmObj.RelativeDistinguishedName = (CSSM_X509_RDN_PTR)alloc.malloc(len);
86	cssmObj.numberOfRDNs = numRdns;
87	CSSM_X509_RDN_PTR cssmRdns = cssmObj.RelativeDistinguishedName;
88	memset(cssmRdns, 0, len);
89
90	SecNssCoder	coder;		// conversion requires further decoding
91
92	for(unsigned dex=0; dex<numRdns; dex++) {
93		CL_nssRdnToCssm(*(nssObj.rdns[dex]), cssmRdns[dex], alloc, coder);
94	}
95	return;
96}
97
98/*
99 * CSSM_X509_TYPE_VALUE_PAIR --> NSS_ATV
100 */
101void CL_cssmAtvToNss(
102	const CSSM_X509_TYPE_VALUE_PAIR	&cssmObj,
103	NSS_ATV							&nssObj,
104	SecNssCoder						&coder)
105{
106	memset(&nssObj, 0, sizeof(nssObj));
107
108	/* copy the OID */
109	coder.allocCopyItem(cssmObj.type, nssObj.type);
110
111	/* tag and value */
112	nssObj.value.tag = cssmObj.valueType;
113	coder.allocCopyItem(cssmObj.value, nssObj.value.item);
114}
115
116/* CSSM_X509_RDN --> NSS_RDN */
117void CL_cssmRdnToNss(
118	const CSSM_X509_RDN	&cssmObj,
119	NSS_RDN				&nssObj,
120	SecNssCoder			&coder)
121{
122	memset(&nssObj, 0, sizeof(nssObj));
123
124	/* alloc NULL-terminated array of ATV pointers */
125	unsigned numAtvs = cssmObj.numberOfPairs;
126	unsigned size = (numAtvs + 1) * sizeof(void *);
127	nssObj.atvs = (NSS_ATV **)coder.malloc(size);
128	memset(nssObj.atvs, 0, size);
129
130	/* grind thru the elements */
131	for(unsigned atvDex=0; atvDex<numAtvs; atvDex++) {
132		nssObj.atvs[atvDex] = (NSS_ATV *)coder.malloc(sizeof(NSS_ATV));
133		CL_cssmAtvToNss(cssmObj.AttributeTypeAndValue[atvDex],
134			*nssObj.atvs[atvDex], coder);
135	}
136}
137
138/* CSSM_X509_NAME --> NSS_Name */
139void CL_cssmNameToNss(
140	const CSSM_X509_NAME	&cssmObj,
141	NSS_Name				&nssObj,
142	SecNssCoder				&coder)
143{
144	memset(&nssObj, 0, sizeof(nssObj));
145
146	/* alloc NULL-terminated array of RDN pointers */
147	unsigned numRdns = cssmObj.numberOfRDNs;
148	nssObj.rdns = (NSS_RDN **)clNssNullArray(numRdns, coder);
149
150	/* grind thru the elements */
151	for(unsigned rdnDex=0; rdnDex<numRdns; rdnDex++) {
152		nssObj.rdns[rdnDex] = (NSS_RDN *)coder.malloc(sizeof(NSS_RDN));
153		CL_cssmRdnToNss(cssmObj.RelativeDistinguishedName[rdnDex],
154			*nssObj.rdns[rdnDex], coder);
155	}
156}
157
158#pragma mark ----- Name Normalization -----
159
160void CL_normalizeString(
161	char *strPtr,
162	int &strLen)					// IN/OUT
163{
164	char *pCh = strPtr;				// working ptr
165	char *pD = pCh;					// start of good string chars
166	char *pEos = pCh + strLen - 1;
167
168	if(strLen == 0) {
169		return;
170	}
171
172	/* adjust if Length included NULL terminator */
173	while(*pEos == 0) {
174		pEos--;
175	}
176
177	/* Remove trailing spaces */
178	while(isspace(*pEos)) {
179		pEos--;
180	}
181
182	/* Point to one past last non-space character */
183	pEos++;
184
185	/* upper case */
186	while(pCh < pEos) {
187		*pCh = toupper(*pCh);
188		pCh++;
189	}
190
191	/* clean out whitespace */
192	/*
193	 * 1. skip all leading whitespace
194	 */
195	pCh = pD;
196	while(isspace(*pCh) && (pCh < pEos)) {
197		pCh++;
198	}
199
200	/*
201	 * 2. eliminate multiple whitespace.
202	 *    pCh points to first non-white char.
203	 *	  pD still points to start of string
204	 */
205	char ch;
206	while(pCh < pEos) {
207		ch = *pCh++;
208		*pD++ = ch;		// normal case
209		if( isspace(ch) ){
210			/* skip 'til next nonwhite */
211			while(isspace(*pCh) && (pCh < pEos)) {
212				pCh++;
213			}
214		}
215	};
216
217	strLen = (int)(pD - strPtr);
218}
219
220/*
221 * Normalize an RDN. Per RFC2459 (4.1.2.4), printable strings are case
222 * insensitive and we're supposed to ignore leading and trailing
223 * whitespace, and collapse multiple whitespace characters into one.
224 *
225 * Incoming NSS_Name is assumed to be entirely within specifed coder's
226 * address space; we'll be munging some of that and possibly replacing
227 * some pointers with others allocated from the same space.
228 */
229void CL_normalizeX509NameNSS(
230	NSS_Name &nssName,
231	SecNssCoder &coder)
232{
233	unsigned numRdns = clNssArraySize((const void **)nssName.rdns);
234	if(numRdns == 0) {
235		/* not technically an error */
236		return;
237	}
238
239	for(unsigned rdnDex=0; rdnDex<numRdns; rdnDex++) {
240		NSS_RDN *rdn = nssName.rdns[rdnDex];
241		assert(rdn != NULL);
242		unsigned numAttrs = clNssArraySize((const void **)rdn->atvs);
243		if(numAttrs == 0) {
244			clFieldLog("clNormalizeX509Name: zero numAttrs at index %d", rdnDex);
245			continue;
246		}
247
248		/* descend into array of attribute/values */
249		for(unsigned attrDex=0; attrDex<numAttrs; attrDex++) {
250			NSS_ATV *attr = rdn->atvs[attrDex];
251			assert(attr != NULL);
252
253			/*
254			 * attr->value is an ASN_ANY containing an encoded
255			 * string. We only normalize Prinatable String types.
256			 * If we find one, decode it, normalize it, encode the
257			 * result, and put the encoding back in attr->value.
258			 * We temporarily "leak" the original string, which only
259			 * has a lifetime of the incoming SecNssCoder.
260			 */
261			NSS_TaggedItem &attrVal = attr->value;
262			if(attrVal.tag != SEC_ASN1_PRINTABLE_STRING) {
263				/* skip it */
264				continue;
265			}
266
267			/* normalize */
268			char *strPtr = (char *)attrVal.item.Data;
269			int newLen = (int)attrVal.item.Length;
270			CL_normalizeString(strPtr, newLen);
271
272			/* possible length adjustment */
273			attrVal.item.Length = newLen;
274		}	/* for each attribute/value */
275	}		/* for each RDN */
276}
277
278#pragma mark ----- CE_GeneralNames <--> NSS_GeneralNames -----
279
280void CL_nssGeneralNameToCssm(
281	NSS_GeneralName &nssObj,
282	CE_GeneralName &cdsaObj,
283	SecNssCoder &coder,				// for temp decoding
284	Allocator &alloc)			// destination
285{
286	memset(&cdsaObj, 0, sizeof(cdsaObj));
287	PRErrorCode prtn;
288
289	/* for caller's CE_GeneralName */
290	CSSM_BOOL berEncoded = CSSM_FALSE;
291	CE_GeneralNameType cdsaTag;
292
293	/*
294	 * At this point, depending on the decoded object's tag, we either
295	 * have the final bytes to copy out, or we need to decode further.
296	 * After this switch, if doCopy is true, give the caller a copy
297	 * of nssObj.item.
298	 */
299	bool doCopy = true;
300	switch(nssObj.tag) {
301		case NGT_OtherName:		// ASN_ANY -> CE_OtherName
302		{
303			cdsaTag = GNT_OtherName;
304
305			/* decode to coder memory */
306			CE_OtherName *nssOther =
307				(CE_OtherName *)coder.malloc(sizeof(CE_OtherName));
308			memset(nssOther, 0, sizeof(CE_OtherName));
309			prtn = coder.decodeItem(nssObj.item,
310				kSecAsn1GenNameOtherNameTemplate,
311				nssOther);
312			if(prtn) {
313				clErrorLog("CL_nssGeneralNameToCssm: error decoding "
314						"OtherName\n");
315				CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
316			}
317
318			/* copy out to caller */
319			clAllocData(alloc, cdsaObj.name, sizeof(CE_OtherName));
320			clCopyOtherName(*nssOther, *((CE_OtherName *)cdsaObj.name.Data),
321				alloc);
322			doCopy = false;
323			break;
324		}
325		case NGT_RFC822Name:	// IA5String, done
326			cdsaTag = GNT_RFC822Name;
327			break;
328		case NGT_DNSName:		// IA5String
329			cdsaTag = GNT_DNSName;
330			break;
331		case NGT_X400Address:	// ASY_ANY, leave alone
332			cdsaTag = GNT_X400Address;
333			berEncoded = CSSM_TRUE;
334			break;
335		case NGT_DirectoryName:	// ASN_ANY --> NSS_Name
336		{
337			cdsaTag = GNT_DirectoryName;
338
339			/* Decode to coder memory */
340			NSS_Name *nssName = (NSS_Name *)coder.malloc(sizeof(NSS_Name));
341			memset(nssName, 0, sizeof(NSS_Name));
342			prtn = coder.decodeItem(nssObj.item, kSecAsn1NameTemplate, nssName);
343			if(prtn) {
344				clErrorLog("CL_nssGeneralNameToCssm: error decoding "
345						"NSS_Name\n");
346				CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
347			}
348
349			/* convert & copy out to caller */
350			clAllocData(alloc, cdsaObj.name, sizeof(CSSM_X509_NAME));
351			CL_nssNameToCssm(*nssName,
352				*((CSSM_X509_NAME *)cdsaObj.name.Data), alloc);
353			doCopy = false;
354			break;
355		}
356		case NGT_EdiPartyName:	// ASN_ANY, leave alone
357			cdsaTag = GNT_EdiPartyName;
358			berEncoded = CSSM_TRUE;
359			break;
360		case NGT_URI:			// IA5String
361			cdsaTag = GNT_URI;
362			break;
363		case NGT_IPAddress:		// OCTET_STRING
364			cdsaTag = GNT_IPAddress;
365			break;
366		case NGT_RegisteredID:	// OID
367			cdsaTag = GNT_RegisteredID;
368			break;
369		default:
370			clErrorLog("CL_nssGeneralNameToCssm: bad name tag\n");
371			CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
372	}
373
374	cdsaObj.nameType = cdsaTag;
375	cdsaObj.berEncoded = berEncoded;
376	if(doCopy) {
377		clAllocCopyData(alloc, nssObj.item, cdsaObj.name);
378	}
379}
380
381void CL_nssGeneralNamesToCssm(
382	const NSS_GeneralNames &nssObj,
383	CE_GeneralNames &cdsaObj,
384	SecNssCoder &coder,				// for temp decoding
385	Allocator &alloc)			// destination
386{
387	memset(&cdsaObj, 0, sizeof(cdsaObj));
388	unsigned numNames = clNssArraySize((const void **)nssObj.names);
389	if(numNames == 0) {
390		return;
391	}
392
393	/*
394	 * Decode each name element, currently a raw ASN_ANY blob.
395	 * Then convert each result into CDSA form.
396	 * This array of (NSS_GeneralName)s is temporary, it doesn't
397	 * persist outside of this routine other than the fact that it's
398	 * mallocd by the coder arena pool.
399	 */
400	NSS_GeneralName *names =
401		(NSS_GeneralName *)coder.malloc(sizeof(NSS_GeneralName) * numNames);
402	memset(names, 0, sizeof(NSS_GeneralName) * numNames);
403	cdsaObj.generalName = (CE_GeneralName *)alloc.malloc(
404		sizeof(CE_GeneralName) * numNames);
405	cdsaObj.numNames = numNames;
406
407	for(unsigned dex=0; dex<numNames; dex++) {
408		if(coder.decodeItem(*nssObj.names[dex], kSecAsn1GeneralNameTemplate,
409				&names[dex])) {
410			clErrorLog("***CL_nssGeneralNamesToCssm: Error decoding "
411				"General.name\n");
412			CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
413		}
414
415		CL_nssGeneralNameToCssm(names[dex],
416			cdsaObj.generalName[dex],
417			coder, alloc);
418	}
419}
420
421void CL_cssmGeneralNameToNss(
422	CE_GeneralName &cdsaObj,
423	NSS_GeneralName &nssObj,		// actually an NSSTaggedItem
424	SecNssCoder &coder)				// for temp decoding
425{
426	memset(&nssObj, 0, sizeof(nssObj));
427
428	/*
429	 * The default here is just to use the app-supplied data as is...
430	 */
431	nssObj.item = cdsaObj.name;
432	unsigned char itemTag;			// for nssObj.tag
433	bool doCopy = false;			// unless we have to modify tag byte
434	unsigned char overrideTag;		// to force context-specific tag for
435									//   an ASN_ANY
436	PRErrorCode prtn;
437
438	switch(cdsaObj.nameType) {
439		case GNT_OtherName:
440			/*
441			 * Caller supplies an CE_OtherName. Encode it.
442			 */
443			if((cdsaObj.name.Length != sizeof(CE_OtherName)) ||
444			   (cdsaObj.name.Data == NULL)) {
445				clErrorLog("CL_cssmGeneralNameToNss: OtherName.Length"
446					" error\n");
447				CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
448			}
449			prtn = coder.encodeItem(cdsaObj.name.Data,
450				kSecAsn1OtherNameTemplate, nssObj.item);
451			if(prtn) {
452				clErrorLog("CL_cssmGeneralNameToNss: OtherName encode"
453					" error\n");
454				CssmError::throwMe(CSSMERR_CL_MEMORY_ERROR);
455			}
456			itemTag = NGT_OtherName;
457			break;
458		case GNT_RFC822Name:		// IA5String
459			itemTag = NGT_RFC822Name;
460			break;
461		case GNT_DNSName:			// IA5String
462			itemTag = NGT_DNSName;
463			break;
464		case GNT_X400Address:		// caller's resposibility
465			/*
466			 * Encoded as ASN_ANY, the only thing we do is to
467			 * force the correct context-specific tag
468			 */
469			itemTag = GNT_X400Address;
470			if(!cdsaObj.berEncoded) {
471				clErrorLog("CL_cssmGeneralNameToNss: X400Address must"
472					" be BER-encoded\n");
473				CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
474			}
475			overrideTag = SEC_ASN1_CONTEXT_SPECIFIC |
476				SEC_ASN1_CONSTRUCTED | NGT_X400Address;
477			doCopy = true;
478			break;
479		case GNT_DirectoryName:
480		{
481			/*
482			 * Caller supplies an CSSM_X509_NAME. Convert to NSS
483			 * format and encode it.
484			 */
485			if((cdsaObj.name.Length != sizeof(CSSM_X509_NAME)) ||
486			   (cdsaObj.name.Data == NULL)) {
487				clErrorLog("CL_cssmGeneralNameToNss: DirectoryName.Length"
488					" error\n");
489				CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
490			}
491			NSS_Name nssName;
492			CSSM_X509_NAME_PTR cdsaName =
493				(CSSM_X509_NAME_PTR)cdsaObj.name.Data;
494			CL_cssmNameToNss(*cdsaName, nssName, coder);
495			prtn = coder.encodeItem(&nssName,
496				kSecAsn1NameTemplate, nssObj.item);
497			if(prtn) {
498				clErrorLog("CL_cssmGeneralNameToNss: X509Name encode"
499					" error\n");
500				CssmError::throwMe(CSSMERR_CL_MEMORY_ERROR);
501			}
502			itemTag = GNT_DirectoryName;
503
504			/*
505			 * AND, munge the tag to make it a context-specific
506			 * sequence
507			 * no, not needed, this is wrapped in an explicit...
508			 */
509			//nssObj.item.Data[0] = SEC_ASN1_CONTEXT_SPECIFIC |
510			//	SEC_ASN1_CONSTRUCTED | GNT_DirectoryName;
511
512			break;
513		}
514		case GNT_EdiPartyName:		// caller's resposibility
515			/*
516			 * Encoded as ASN_ANY, the only thing we do is to
517			 * force the correct context-specific tag
518			 */
519			itemTag = GNT_EdiPartyName;
520			if(!cdsaObj.berEncoded) {
521				clErrorLog("CL_cssmGeneralNameToNss: EdiPartyName must"
522					" be BER-encoded\n");
523				CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
524			}
525			overrideTag = SEC_ASN1_CONTEXT_SPECIFIC |  NGT_X400Address;
526			doCopy = true;
527			break;
528		case GNT_URI:				// IA5String
529			itemTag = GNT_URI;
530			break;
531		case GNT_IPAddress:			// OCTET_STRING
532			itemTag = NGT_IPAddress;
533			break;
534		case GNT_RegisteredID:		// OID
535			itemTag = NGT_RegisteredID;
536			break;
537		default:
538			clErrorLog("CL_cssmGeneralNameToNss: bad name tag\n");
539			CssmError::throwMe(CSSMERR_CL_UNKNOWN_TAG);
540	}
541	if(doCopy) {
542		coder.allocCopyItem(cdsaObj.name, nssObj.item);
543		nssObj.item.Data[0] = overrideTag;
544	}
545	nssObj.tag = itemTag;
546}
547
548void CL_cssmGeneralNamesToNss(
549	const CE_GeneralNames &cdsaObj,
550	NSS_GeneralNames &nssObj,
551	SecNssCoder &coder)
552{
553	uint32 numNames = cdsaObj.numNames;
554	nssObj.names = (CSSM_DATA **)clNssNullArray(numNames, coder);
555
556	/*
557	 * Convert each element in cdsaObj to NSS form, encode, drop into
558	 * the ASN_ANY array.
559	 *
560	 * This array of (NSS_GeneralName)s is temporary, it doesn't
561	 * persist outside of this routine other than the fact that it's
562	 * mallocd by the coder arena pool.
563	 */
564	NSS_GeneralName *names =
565		(NSS_GeneralName *)coder.malloc(sizeof(NSS_GeneralName) * numNames);
566	memset(names, 0, sizeof(NSS_GeneralName) * numNames);
567	for(unsigned dex=0; dex<cdsaObj.numNames; dex++) {
568		nssObj.names[dex] = (CSSM_DATA_PTR)coder.malloc(sizeof(CSSM_DATA));
569		memset(nssObj.names[dex], 0, sizeof(CSSM_DATA));
570		CL_cssmGeneralNameToNss(cdsaObj.generalName[dex],
571			names[dex], coder);
572		if(coder.encodeItem(&names[dex], kSecAsn1GeneralNameTemplate,
573				*nssObj.names[dex])) {
574			clErrorLog("***Error encoding General.name\n");
575			CssmError::throwMe(CSSMERR_CL_MEMORY_ERROR);
576		}
577	}
578}
579
580/* Copy a CE_OtherName */
581void clCopyOtherName(
582	const CE_OtherName &src,
583	CE_OtherName &dst,
584	Allocator &alloc)
585{
586	clAllocCopyData(alloc, src.typeId, dst.typeId);
587	clAllocCopyData(alloc, src.value, dst.value);
588}
589
590#pragma mark ----- Name-related Free -----
591
592void CL_freeAuthorityKeyId(
593	CE_AuthorityKeyID 				&cdsaObj,
594	Allocator					&alloc)
595{
596	alloc.free(cdsaObj.keyIdentifier.Data);
597	CL_freeCssmGeneralNames(cdsaObj.generalNames, alloc);
598	alloc.free(cdsaObj.generalNames);
599	alloc.free(cdsaObj.serialNumber.Data);
600	memset(&cdsaObj, 0, sizeof(CE_AuthorityKeyID));
601}
602
603void CL_freeCssmGeneralName(
604	CE_GeneralName 		&genName,
605	Allocator 			&alloc)
606{
607	switch(genName.nameType) {
608		/*
609		 * Two special cases here.
610		 */
611		case GNT_DirectoryName:
612			if((!genName.berEncoded) &&					// we're flexible
613					(genName.name.Length ==
614						sizeof(CSSM_X509_NAME))) {		// paranoia
615				CL_freeX509Name((CSSM_X509_NAME_PTR)genName.name.Data, alloc);
616			}
617			break;
618
619		case GNT_OtherName:
620			if((!genName.berEncoded) &&					// we're flexible
621					(genName.name.Length ==
622						sizeof(CE_OtherName))) {		// paranoia
623				CE_OtherName *con = (CE_OtherName *)genName.name.Data;
624				CL_freeOtherName(con, alloc);
625			}
626			break;
627		default:
628			break;
629	}
630	/* and always free this */
631	alloc.free(genName.name.Data);
632}
633
634void CL_freeCssmGeneralNames(
635	CE_GeneralNames 		*cdsaObj,
636	Allocator 				&alloc)
637{
638	if(cdsaObj == NULL) {
639		return;
640	}
641	for(unsigned i=0; i<cdsaObj->numNames; i++) {
642		CL_freeCssmGeneralName(cdsaObj->generalName[i], alloc);
643	}
644	if(cdsaObj->numNames) {
645		memset(cdsaObj->generalName, 0, cdsaObj->numNames * sizeof(CE_GeneralName));
646		alloc.free(cdsaObj->generalName);
647	}
648	memset(cdsaObj, 0, sizeof(CE_GeneralNames));
649}
650
651void CL_freeCssmDistPointName(
652	CE_DistributionPointName	*cssmDpn,
653	Allocator				&alloc)
654{
655	if(cssmDpn == NULL) {
656		return;
657	}
658	switch(cssmDpn->nameType) {
659		case CE_CDNT_FullName:
660			CL_freeCssmGeneralNames(cssmDpn->dpn.fullName, alloc);
661			alloc.free(cssmDpn->dpn.fullName);
662			break;
663		case CE_CDNT_NameRelativeToCrlIssuer:
664			CL_freeX509Rdn(cssmDpn->dpn.rdn, alloc);
665			alloc.free(cssmDpn->dpn.rdn);
666			break;
667	}
668	memset(cssmDpn, 0, sizeof(*cssmDpn));
669}
670
671void CL_freeCssmDistPoints(
672	CE_CRLDistPointsSyntax	*cssmDps,
673	Allocator			&alloc)
674{
675	if(cssmDps == NULL) {
676		return;
677	}
678	for(unsigned dex=0; dex<cssmDps->numDistPoints; dex++) {
679		CE_CRLDistributionPoint *cssmDp = &cssmDps->distPoints[dex];
680		if(cssmDp->distPointName) {
681			CL_freeCssmDistPointName(cssmDp->distPointName, alloc);
682			alloc.free(cssmDp->distPointName);
683		}
684		if(cssmDp->crlIssuer) {
685			CL_freeCssmGeneralNames(cssmDp->crlIssuer, alloc);
686			alloc.free(cssmDp->crlIssuer);
687		}
688	}
689	memset(cssmDps->distPoints, 0,
690		cssmDps->numDistPoints * sizeof(CE_CRLDistributionPoint));
691	alloc.free(cssmDps->distPoints);
692	memset(cssmDps, 0, sizeof(*cssmDps));
693}
694
695/* free contents of an CSSM_X509_NAME */
696void CL_freeX509Name(
697	CSSM_X509_NAME_PTR	x509Name,
698	Allocator		&alloc)
699{
700	if(x509Name == NULL) {
701		return;
702	}
703	for(unsigned rdnDex=0; rdnDex<x509Name->numberOfRDNs; rdnDex++) {
704		CSSM_X509_RDN_PTR rdn = &x509Name->RelativeDistinguishedName[rdnDex];
705		CL_freeX509Rdn(rdn, alloc);
706	}
707	alloc.free(x509Name->RelativeDistinguishedName);
708	memset(x509Name, 0, sizeof(CSSM_X509_NAME));
709}
710
711void CL_freeX509Rdn(
712	CSSM_X509_RDN_PTR	rdn,
713	Allocator		&alloc)
714{
715	if(rdn == NULL) {
716		return;
717	}
718	for(unsigned atvDex=0; atvDex<rdn->numberOfPairs; atvDex++) {
719		CSSM_X509_TYPE_VALUE_PAIR_PTR atv =
720			&rdn->AttributeTypeAndValue[atvDex];
721		alloc.free(atv->type.Data);
722		alloc.free(atv->value.Data);
723		memset(atv, 0, sizeof(CSSM_X509_TYPE_VALUE_PAIR));
724	}
725	alloc.free(rdn->AttributeTypeAndValue);
726	memset(rdn, 0, sizeof(CSSM_X509_RDN));
727}
728
729void CL_freeOtherName(
730	CE_OtherName		*cssmOther,
731	Allocator		&alloc)
732{
733	if(cssmOther == NULL) {
734		return;
735	}
736	alloc.free(cssmOther->typeId.Data);
737	alloc.free(cssmOther->value.Data);
738	memset(cssmOther, 0, sizeof(*cssmOther));
739}
740
741void CL_freeCssmIssuingDistPoint(
742	CE_IssuingDistributionPoint	*cssmIdp,
743	Allocator				&alloc)
744{
745	CL_freeCssmDistPointName(cssmIdp->distPointName, alloc);
746}
747
748