1/*
2 * Copyright (c) 2000-2001 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/*
20 * CrlFields.cpp - convert between NSS-based NSS_Crl components and CDSA-style
21 *                  fields. A major component of DecodedCrl.
22 *
23 * Created 8/29/2002 by Doug Mitchell.
24 * Copyright (c) 2002 by Apple Computer.
25 */
26
27#include "DecodedCrl.h"
28#include <security_utilities/debugging.h>
29#include "cldebugging.h"
30#include "CLCrlExtensions.h"
31#include "CLCertExtensions.h"
32#include "CLFieldsCommon.h"
33#include "clNssUtils.h"
34#include "clNameUtils.h"
35#include <security_utilities/utilities.h>
36#include <Security/oidscrl.h>
37#include <Security/oidscert.h>
38#include <Security/cssmerr.h>
39#include <Security/x509defs.h>
40
41static void CL_freeCssmExtensions(
42	CSSM_X509_EXTENSIONS	&extens,
43	Allocator			&alloc);
44
45/***
46 *** Version
47 *** Format = DER-encoded int (max of four bytes in this case)
48 ***/
49static bool getField_Version (
50	DecodedItem		 	&item,
51	unsigned			index,			// which occurrence (0 = first)
52	uint32				&numFields,		// RETURNED
53	CssmOwnedData		&fieldValue)	// RETURNED
54{
55	const DecodedCrl &crl = dynamic_cast<const DecodedCrl &>(item);
56	const CSSM_DATA &vers = crl.mCrl.tbs.version;
57	if(!tbsGetCheck(vers.Data, index)) {
58		/* not present, optional */
59		return false;
60	}
61	fieldValue.copy(vers.Data, vers.Length);
62	numFields = 1;
63	return true;
64}
65
66static void setField_Version (
67	DecodedItem 		&item,
68	const CssmData		&fieldValue)
69{
70	DecodedCrl &crl = dynamic_cast<DecodedCrl &>(item);
71	CSSM_DATA &vers = crl.mCrl.tbs.version;
72	tbsSetCheck(vers.Data, fieldValue, 0, "version");
73	crl.coder().allocCopyItem(fieldValue, vers);
74}
75
76/*** issuer
77 *** Format = CSSM_X509_NAME
78 *** class Name from sm_x501if
79 ***/
80static bool getField_Issuer (
81	DecodedItem			&item,
82	unsigned			index,			// which occurrence (0 = first)
83	uint32				&numFields,		// RETURNED
84	CssmOwnedData		&fieldValue)	// RETURNED
85{
86	if(index != 0) {
87		return false;
88	}
89
90	bool brtn;
91
92	const DecodedCrl &crl = dynamic_cast<const DecodedCrl &>(item);
93	try {
94		brtn = getField_RDN_NSS(crl.mCrl.tbs.issuer, fieldValue);
95		if(brtn) {
96			numFields = 1;
97		}
98	}
99	catch (...) {
100		freeField_RDN(fieldValue);
101		throw;
102	}
103	return brtn;
104}
105
106static void setField_Issuer  (
107	DecodedItem 		&item,
108	const CssmData		&fieldValue)
109{
110	DecodedCrl &crl = dynamic_cast<DecodedCrl &>(item);
111	const CSSM_X509_NAME *cssmName = (const CSSM_X509_NAME *)fieldValue.Data;
112	NSS_Name &nssName = crl.mCrl.tbs.issuer;
113	tbsSetCheck(nssName.rdns, fieldValue, sizeof(CSSM_X509_NAME),
114		"IssuerName");
115	CL_cssmNameToNss(*cssmName, nssName, crl.coder());
116}
117
118/***
119 *** This/Next update
120 *** Format: CSSM_X509_TIME
121 ***/
122static bool getField_ThisUpdate (
123	DecodedItem		 	&item,
124	unsigned			index,			// which occurrence (0 = first)
125	uint32				&numFields,		// RETURNED
126	CssmOwnedData		&fieldValue)	// RETURNED
127{
128	const DecodedCrl &crl = dynamic_cast<const DecodedCrl &>(item);
129	const NSS_Time &srcTime = crl.mCrl.tbs.thisUpdate;
130	return getField_TimeNSS(srcTime, index, numFields, fieldValue);
131}
132
133static void setField_ThisUpdate (
134	DecodedItem 		&item,
135	const CssmData		&fieldValue)
136{
137	DecodedCrl &crl = dynamic_cast<DecodedCrl &>(item);
138	NSS_Time &dstTime = crl.mCrl.tbs.thisUpdate;
139	tbsSetCheck(dstTime.item.Data, fieldValue,
140		sizeof(CSSM_X509_TIME), "NotBefore");
141	setField_TimeNSS(fieldValue, dstTime, crl.coder());
142}
143
144static bool getField_NextUpdate (
145	DecodedItem		 	&item,
146	unsigned			index,			// which occurrence (0 = first)
147	uint32				&numFields,		// RETURNED
148	CssmOwnedData		&fieldValue)	// RETURNED
149{
150	const DecodedCrl &crl = dynamic_cast<const DecodedCrl &>(item);
151	const NSS_Time &srcTime = crl.mCrl.tbs.nextUpdate;
152	return getField_TimeNSS(srcTime, index, numFields, fieldValue);
153}
154
155static void setField_NextUpdate (
156	DecodedItem 		&item,
157	const CssmData		&fieldValue)
158{
159	DecodedCrl &crl = dynamic_cast<DecodedCrl &>(item);
160	NSS_Time &dstTime = crl.mCrl.tbs.nextUpdate;
161	tbsSetCheck(dstTime.item.Data, fieldValue,
162		sizeof(CSSM_X509_TIME), "NotBefore");
163	setField_TimeNSS(fieldValue, dstTime, crl.coder());
164}
165
166/***
167 *** Issuer Name (normalized and encoded version)
168 *** Format = CSSM_DATA containing the DER encoding of the normalized name
169 ***/
170static bool getFieldIssuerNorm(
171	DecodedItem		 	&item,
172	unsigned			index,			// which occurrence (0 = first)
173	uint32				&numFields,		// RETURNED
174	CssmOwnedData		&fieldValue)	// RETURNED
175{
176	if(index != 0) {
177		return false;
178	}
179	const DecodedCrl &crl = dynamic_cast<const DecodedCrl &>(item);
180	return getField_normRDN_NSS(crl.mCrl.tbs.derIssuer, numFields,
181		fieldValue);
182}
183
184/***
185 *** TBS AlgId
186 *** Format = CSSM_X509_ALGORITHM_IDENTIFIER
187 ***/
188static bool getField_CrlTbsAlgId (
189	DecodedItem		 	&item,
190	unsigned			index,			// which occurrence (0 = first)
191	uint32				&numFields,		// RETURNED
192	CssmOwnedData		&fieldValue)	// RETURNED
193{
194	const DecodedCrl &crl = dynamic_cast<const DecodedCrl &>(item);
195	const CSSM_X509_ALGORITHM_IDENTIFIER &srcAlgId =
196		crl.mCrl.signatureAlgorithm;
197	if(!tbsGetCheck(srcAlgId.algorithm.Data, index)) {
198		return false;
199	}
200	getField_AlgIdNSS(srcAlgId, fieldValue);
201	numFields = 1;
202	return true;
203}
204
205/*
206 * Support for entries in revocation list
207 */
208static void nssRevokedEntryToCssm(
209	NSS_RevokedCert						&nssEntry,
210	CSSM_X509_REVOKED_CERT_ENTRY 		&cssmEntry,
211	Allocator						&alloc)
212{
213	clAllocCopyData(alloc, nssEntry.userCertificate, cssmEntry.certificateSerialNumber);
214	CL_nssTimeToCssm(nssEntry.revocationDate, cssmEntry.revocationDate, alloc);
215
216	/* CSSM_X509_EXTENSIONS extensions */
217	NSS_CertExtension 	**nssExtens = nssEntry.extensions;
218	if(nssExtens == NULL) {
219		/* done */
220		return;
221	}
222
223	/*
224	 * First we have to decode the NSS-style Extensions into a
225	 * DecodedExtensions object. For cert- and CRL-wide extensions, this
226	 * is done at the construction of Decoded{Cert,Crl}. However for
227	 * per-CRL-entry entensions, this is (currently) the only place
228	 * this decoding is done.
229	 */
230	SecNssCoder coder;
231	DecodedExtensions decodedExtens(coder, alloc);
232	decodedExtens.decodeFromNss(nssExtens);
233
234	/* convert to CDSA style */
235	decodedExtens.convertToCdsa(cssmEntry.extensions, alloc);
236}
237
238static void freeCssmEntry(
239	CSSM_X509_REVOKED_CERT_ENTRY_PTR 	cssmEntry,
240	Allocator						&alloc)
241{
242	if(cssmEntry == NULL) {
243		return;
244	}
245	if(cssmEntry->certificateSerialNumber.Data) {
246		alloc.free(cssmEntry->certificateSerialNumber.Data);
247		cssmEntry->certificateSerialNumber.Data = NULL;
248		cssmEntry->certificateSerialNumber.Length = 0;
249	}
250	CL_freeCssmTime(&cssmEntry->revocationDate, alloc);
251
252	/* CSSM_X509_EXTENSIONS extensions */
253	CL_freeCssmExtensions(cssmEntry->extensions, alloc);
254
255	memset(cssmEntry, 0, sizeof(CSSM_X509_REVOKED_CERT_ENTRY));
256}
257
258static void nssRevokedListToCssm(
259	NSS_RevokedCert					**nssList,		// may be NULL
260	CSSM_X509_REVOKED_CERT_LIST_PTR	cssmList,
261	Allocator					&alloc)
262{
263	unsigned numEntries = clNssArraySize((const void **)nssList);
264	cssmList->numberOfRevokedCertEntries = numEntries;
265	if(numEntries == 0) {
266		cssmList->revokedCertEntry = NULL;
267		return;
268	}
269	cssmList->revokedCertEntry = (CSSM_X509_REVOKED_CERT_ENTRY_PTR)alloc.malloc(
270		sizeof(CSSM_X509_REVOKED_CERT_ENTRY) * numEntries);
271	memset(cssmList->revokedCertEntry, 0,
272		sizeof(CSSM_X509_REVOKED_CERT_ENTRY) * numEntries);
273	for(unsigned dex=0; dex<numEntries; dex++) {
274		NSS_RevokedCert *nssEntry = nssList[dex];
275		assert(nssEntry != NULL);
276		CSSM_X509_REVOKED_CERT_ENTRY_PTR cssmEntry =
277			&cssmList->revokedCertEntry[dex];
278		nssRevokedEntryToCssm(*nssEntry, *cssmEntry, alloc);
279	}
280}
281
282
283static void freeCssmRevokedList(
284	CSSM_X509_REVOKED_CERT_LIST_PTR 	cssmList,
285	Allocator						&alloc)
286{
287	if(cssmList == NULL) {
288		return;
289	}
290	for(unsigned dex=0; dex<cssmList->numberOfRevokedCertEntries; dex++) {
291		CSSM_X509_REVOKED_CERT_ENTRY_PTR cssmEntry =
292			&cssmList->revokedCertEntry[dex];
293		freeCssmEntry(cssmEntry, alloc);
294	}
295	if(cssmList->revokedCertEntry) {
296		alloc.free(cssmList->revokedCertEntry);
297	}
298	memset(cssmList, 0, sizeof(CSSM_X509_REVOKED_CERT_LIST));
299}
300
301/***
302 *** SignedCRL
303 *** Format: CSSM_X509_SIGNED_CRL (the whole enchilada, parsed)
304 ***/
305static bool getField_SignedCrl (
306	DecodedItem		 	&item,
307	unsigned			index,			// which occurrence (0 = first)
308	uint32				&numFields,		// RETURNED
309	CssmOwnedData		&fieldValue)	// RETURNED
310{
311	Allocator 			&alloc = fieldValue.allocator;
312
313	const DecodedCrl &nssCrl = dynamic_cast<const DecodedCrl &>(item);
314	const NSS_TBSCrl &nssTbs = nssCrl.mCrl.tbs;
315	fieldValue.malloc(sizeof(CSSM_X509_SIGNED_CRL));
316	CSSM_X509_SIGNED_CRL	&cssmCrl = *((CSSM_X509_SIGNED_CRL *)fieldValue.data());
317
318	memset(&cssmCrl, 0, sizeof(CSSM_X509_SIGNED_CRL));
319	CSSM_X509_TBS_CERTLIST &cssmTbs = cssmCrl.tbsCertList;
320
321	/* version */
322	clAllocCopyData(alloc, nssTbs.version, cssmTbs.version);
323
324	/* CSSM_X509_ALGORITHM_IDENTIFIER signature - in TBS and CRL */
325	CL_copyAlgId(nssTbs.signature, cssmTbs.signature, alloc);
326	CL_copyAlgId(nssCrl.mCrl.signatureAlgorithm,
327			cssmCrl.signature.algorithmIdentifier, alloc);
328
329	/* CSSM_X509_NAME issuer */
330	CL_nssNameToCssm(nssTbs.issuer, cssmTbs.issuer, alloc);
331
332	/* CSSM_X509_TIME thisUpdate, nextUpdate */
333	CL_nssTimeToCssm(nssTbs.thisUpdate, cssmTbs.thisUpdate, alloc);
334	CL_nssTimeToCssm(nssTbs.nextUpdate, cssmTbs.nextUpdate, alloc);
335
336	/* CSSM_X509_REVOKED_CERT_LIST_PTR revokedCertificates */
337	if(nssTbs.revokedCerts != NULL) {
338		cssmTbs.revokedCertificates = (CSSM_X509_REVOKED_CERT_LIST_PTR)
339			alloc.malloc(sizeof(CSSM_X509_REVOKED_CERT_LIST));
340		memset(cssmTbs.revokedCertificates, 0, sizeof(CSSM_X509_REVOKED_CERT_LIST));
341		nssRevokedListToCssm(nssTbs.revokedCerts,
342			cssmTbs.revokedCertificates, alloc);
343	}
344
345	/* CSSM_X509_EXTENSIONS extensions */
346	const DecodedExtensions &decodedExtens = nssCrl.decodedExtens();
347	decodedExtens.convertToCdsa(cssmTbs.extensions, alloc);
348
349	/* raw signature - stored in bits - note signature.algId set above */
350	CSSM_DATA nssSig = nssCrl.mCrl.signature;
351	nssSig.Length = (nssSig.Length + 7) / 8;
352	clAllocCopyData(alloc, nssSig, cssmCrl.signature.encrypted);
353	numFields = 1;
354	return true;
355}
356
357static void setField_SignedCrl (
358	DecodedItem 		&item,
359	const CssmData		&fieldValue)
360{
361	/* TBD - writing CRLs not supported now */
362	CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
363}
364
365static void freeField_SignedCrl (
366	CssmOwnedData		&fieldValue)
367{
368	CSSM_X509_SIGNED_CRL *cssmCrl =
369		(CSSM_X509_SIGNED_CRL *)fieldValue.data();
370
371	if(cssmCrl == NULL) {
372		return;
373	}
374	if(fieldValue.length() != sizeof(CSSM_X509_SIGNED_CRL)) {
375		CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER);
376	}
377	Allocator &alloc = fieldValue.allocator;
378	CSSM_X509_TBS_CERTLIST_PTR cssmTbs = &cssmCrl->tbsCertList;
379	if(cssmTbs == NULL) {
380		CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER);
381	}
382
383	/* run down the fields */
384	if(cssmTbs->version.Data) {
385		alloc.free(cssmTbs->version.Data);
386	}
387
388	/* CSSM_X509_ALGORITHM_IDENTIFIER signature - in TBS and CRL */
389	CL_freeCssmAlgId(&cssmTbs->signature, alloc);
390	CL_freeCssmAlgId(&cssmCrl->signature.algorithmIdentifier, alloc);
391
392	/* issuer, thisUpdate, nextUpdate */
393	CL_freeX509Name(&cssmTbs->issuer, alloc);
394	CL_freeCssmTime(&cssmTbs->thisUpdate, alloc);
395	CL_freeCssmTime(&cssmTbs->nextUpdate, alloc);
396
397	/* CSSM_X509_REVOKED_CERT_LIST_PTR revokedCertificates */
398	freeCssmRevokedList(cssmTbs->revokedCertificates, alloc);
399	alloc.free(cssmTbs->revokedCertificates);
400
401	/* CSSM_X509_EXTENSIONS extensions */
402	CL_freeCssmExtensions(cssmTbs->extensions, alloc);
403
404	/* raw signature - note signature.algId freed above */
405	alloc.free(cssmCrl->signature.encrypted.Data);
406
407	memset(cssmCrl, 0, sizeof(CSSM_X509_SIGNED_CRL));
408}
409
410/*
411 * Table to map OID to {get,set,free}field
412 */
413typedef struct {
414	const CSSM_OID		*fieldId;
415	getItemFieldFcn		*getFcn;
416	setItemFieldFcn		*setFcn;
417	freeFieldFcn		*freeFcn;		// OPTIONAL - NULL means just free the
418										// top-level data
419} oidToFieldFuncs;
420
421
422static const oidToFieldFuncs crlFieldTable[] = {
423	/* this first one, which returns everything in a parsed format,
424	 * is intended to be normally the only field used */
425	{ 	&CSSMOID_X509V2CRLSignedCrlCStruct,
426		&getField_SignedCrl, &setField_SignedCrl, &freeField_SignedCrl },
427	{ 	&CSSMOID_X509V2CRLVersion,
428		&getField_Version, &setField_Version, NULL },
429	{ 	&CSSMOID_X509V1CRLIssuerNameCStruct,
430		&getField_Issuer, &setField_Issuer, &freeField_RDN },
431	{ 	&CSSMOID_X509V1CRLThisUpdate,
432		&getField_ThisUpdate, &setField_ThisUpdate, &freeField_Time },
433	{ 	&CSSMOID_X509V1CRLNextUpdate,
434		&getField_NextUpdate, &setField_NextUpdate, &freeField_Time },
435	{   &CSSMOID_X509V1IssuerName,
436		getFieldIssuerNorm, &setField_ReadOnly, NULL },
437	{	&CSSMOID_X509V1SignatureAlgorithmTBS,
438		&getField_CrlTbsAlgId, &setField_ReadOnly, &freeField_AlgId },
439		// ...etc..
440	/*
441	 * Extensions, implemented in CrlExtensions.cpp
442	 * When adding new ones, also add to:
443	 *   -- clOidToNssInfo() in CLFieldsCommon.cpp
444	 *   -- get/set/free functions in CrlExtensions.{cpp,h}
445	 *   -- DecodedExten::parse in DecodedExtensions.cpp
446	 */
447	{	&CSSMOID_CrlNumber,
448		&getFieldCrlNumber, &setFieldCrlNumber, freeFieldSimpleExtension },
449	{	&CSSMOID_DeltaCrlIndicator,
450		&getFieldDeltaCrl, &setFieldCrlNumber, freeFieldSimpleExtension },
451	{	&CSSMOID_CertIssuer,				// get/set not implemented
452		&getField_Unimplemented, &setField_ReadOnly,
453		&freeFieldSubjIssuerAltName},
454	{	&CSSMOID_CrlReason,					// get/set not implemented
455		&getField_Unimplemented, &setField_ReadOnly,
456		freeFieldSimpleExtension},
457	{	&CSSMOID_IssuingDistributionPoint,	// get/set not implemented
458		&getField_Unimplemented, &setField_ReadOnly,
459		&freeFieldIssuingDistPoint},
460	{	&CSSMOID_HoldInstructionCode,		// get/set not implemented
461		&getField_Unimplemented, &setField_ReadOnly,
462		&freeFieldOidOrData},
463	{	&CSSMOID_InvalidityDate,			// get/set not implemented
464		&getField_Unimplemented, &setField_ReadOnly,
465		&freeFieldOidOrData},
466
467	/* in common with CertExtensions */
468	{	&CSSMOID_AuthorityKeyIdentifier, &getFieldAuthorityKeyId,
469		&setFieldAuthorityKeyId, &freeFieldAuthorityKeyId } ,
470	{   &CSSMOID_X509V3CertificateExtensionCStruct, &getFieldUnknownExt,
471		&setFieldUnknownExt, &freeFieldUnknownExt },
472	{	&CSSMOID_SubjectAltName, &getFieldSubjAltName,
473		&setFieldSubjIssuerAltName, &freeFieldSubjIssuerAltName } ,
474	{	&CSSMOID_IssuerAltName, &getFieldIssuerAltName,
475		&setFieldSubjIssuerAltName, &freeFieldSubjIssuerAltName } ,
476
477	{	&CSSMOID_CrlDistributionPoints,	// get/set not implemented
478		&getField_Unimplemented, &setField_ReadOnly,
479		&freeFieldCrlDistributionPoints},
480	// etc..
481};
482
483#define NUM_KNOWN_FIELDS		(sizeof(crlFieldTable) / sizeof(oidToFieldFuncs))
484#define NUM_STD_CRL_FIELDS		2		/* TBD not including extensions */
485
486/* map an OID to an oidToFieldFuncs */
487static const oidToFieldFuncs *oidToFields(
488	const CssmOid			&fieldId)
489{
490	const oidToFieldFuncs *fieldTable = crlFieldTable;
491	for(unsigned i=0; i<NUM_KNOWN_FIELDS; i++) {
492		if(fieldId == CssmData::overlay(*fieldTable->fieldId)) {
493			return fieldTable;
494		}
495		fieldTable++;
496	}
497	CssmError::throwMe(CSSMERR_CL_UNKNOWN_TAG);
498}
499
500/*
501 * Common routine to free OID-specific field data. Used in the
502 * public DecodedCrl::freeCrlFieldData and when freeing
503 * extensions in a CSSM_X509_TBS_CERTLIST.
504 */
505static void CL_freeCrlFieldData(
506	const CssmOid		&fieldId,
507	CssmOwnedData		&fieldValue,
508	bool				reset = true)
509{
510	if((fieldValue.data() == NULL) || (fieldValue.length() == 0)) {
511		CssmError::throwMe(CSSM_ERRCODE_INVALID_FIELD_POINTER);
512	}
513	const oidToFieldFuncs *fieldFuncs = oidToFields(fieldId);
514	if(fieldFuncs->freeFcn != NULL) {
515		/* optional - simple cases handled below */
516		fieldFuncs->freeFcn(fieldValue);
517	}
518	if(reset) {
519		fieldValue.reset();
520		fieldValue.release();
521	}
522}
523
524/*
525 * Common routime to free a CSSM_X509_EXTENSIONS. Used to free
526 * CSSM_X509_TBS_CERTLIST.extensions and
527 * CSSM_X509_REVOKED_CERT_ENTRY.extensions.
528 * We just cook up a CssmOid and a CssmOwnedData for each extension
529 * and pass to CL_freeCrlFieldData().
530 */
531static void CL_freeCssmExtensions(
532	CSSM_X509_EXTENSIONS	&extens,
533	Allocator			&alloc)
534{
535	for(uint32 dex=0; dex<extens.numberOfExtensions; dex++) {
536		CSSM_X509_EXTENSION_PTR exten = &extens.extensions[dex];
537		const CSSM_OID *fieldOid;
538
539		/*
540		 * The field OID is either the same as the extension's OID (if we parsed
541		 * it) or CSSMOID_X509V3CertificateExtensionCStruct (if we didn't).
542		 */
543		switch(exten->format) {
544			case CSSM_X509_DATAFORMAT_ENCODED:
545				fieldOid = &CSSMOID_X509V3CertificateExtensionCStruct;
546				break;
547			case CSSM_X509_DATAFORMAT_PARSED:
548			case CSSM_X509_DATAFORMAT_PAIR:
549				fieldOid = &exten->extnId;
550				break;
551			default:
552				clErrorLog("CL_freeCssmExtensions: bad exten->format (%d)",
553					(int)exten->format);
554				CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER);
555		}
556
557		const CssmOid &fieldId = CssmOid::overlay(*fieldOid);
558
559        if (exten->extnId.Data != NULL)  // if this is null, something threw when it was instantiated
560        {
561            CssmData cData((uint8 *)exten, sizeof(CSSM_X509_EXTENSION));
562            CssmRemoteData fieldValue(alloc, cData);
563            CL_freeCrlFieldData(fieldId, fieldValue, false);
564            fieldValue.release();			// but no free (via reset() */
565        }
566	}
567	alloc.free(extens.extensions);
568	memset(&extens, 0, sizeof(CSSM_X509_EXTENSIONS));
569}
570
571
572
573/***
574 *** Public functions
575 ***/
576
577/*
578 * Obtain the index'th occurrence of field specified by fieldId in specified cert.
579 * Format of the returned field depends on fieldId.
580 * Returns total number of fieldId fields in the cert if index is 0.
581 * FieldValue assumed to be empty on entry.
582 * Returns true if specified field was found, else returns false.
583 */
584bool DecodedCrl::getCrlFieldData(
585	const CssmOid		&fieldId,		// which field
586	unsigned			index,			// which occurrence (0 = first)
587	uint32				&numFields,		// RETURNED
588	CssmOwnedData		&fieldValue) 	// RETURNED
589{
590	switch(mState) {
591		case IS_Empty:
592		case IS_Building:
593			clErrorLog("DecodedCrl::getCrlField: can't parse undecoded CRL!");
594			CssmError::throwMe(CSSMERR_CL_INTERNAL_ERROR);
595		case IS_DecodedAll:
596		case IS_DecodedTBS:
597			break;
598	}
599	const oidToFieldFuncs *fieldFuncs = oidToFields(fieldId);
600	return fieldFuncs->getFcn(*this, index, numFields, fieldValue);
601}
602
603/*
604 * Set the field specified by fieldId in the specified Cert.
605 * Note no index - individual field routines either append (for extensions)
606 * or if field already set ::throwMe(for all others)
607 */
608void DecodedCrl::setCrlField(
609	const CssmOid		&fieldId,		// which field
610	const CssmData		&fieldValue)
611{
612	switch(mState) {
613		case IS_Empty:			// first time thru
614			mState = IS_Building;
615			break;
616		case IS_Building:		// subsequent passes
617			break;
618		case IS_DecodedAll:
619		case IS_DecodedTBS:
620			clErrorLog("DecodedCrl::setCrlField: can't build on a decoded CRL!");
621			CssmError::throwMe(CSSMERR_CL_INTERNAL_ERROR);
622	}
623	if((fieldValue.data() == NULL) || (fieldValue.length() == 0)) {
624		CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER);
625	}
626	const oidToFieldFuncs *fieldFuncs = oidToFields(fieldId);
627	const CssmData &value = CssmData::overlay(fieldValue);
628	fieldFuncs->setFcn(*this, value);
629}
630
631/*
632 * Free the fieldId-specific data referred to by fieldValue->Data.
633 * No state from DecodedCrl needed; use the routine shared with
634 * CL_freeCssmExtensions().
635 */
636void DecodedCrl::freeCrlFieldData(
637	const CssmOid		&fieldId,
638	CssmOwnedData		&fieldValue)
639{
640	CL_freeCrlFieldData(fieldId, fieldValue);
641}
642
643
644/*
645 * Common means to get all fields from a decoded CRL. Used in
646 * CrlGetAllTemplateFields and CrlGetAllFields.
647 */
648void DecodedCrl::getAllParsedCrlFields(
649	uint32 				&NumberOfFields,		// RETURNED
650	CSSM_FIELD_PTR 		&CrlFields)				// RETURNED
651{
652	/* this is the max - some might be missing */
653	uint32 maxFields = NUM_STD_CRL_FIELDS + mDecodedExtensions.numExtensions();
654	CSSM_FIELD_PTR outFields = (CSSM_FIELD_PTR)mAlloc.malloc(
655		maxFields * sizeof(CSSM_FIELD));
656
657	/*
658	 * We'll be copying oids and values for fields we find into
659	 * outFields; current number of valid fields found in numOutFields.
660	 */
661	memset(outFields, 0, maxFields * sizeof(CSSM_FIELD));
662	uint32 			numOutFields = 0;
663	CSSM_FIELD_PTR 	currOutField;
664	uint32 			currOidDex;
665	const CSSM_OID 	*currOid;
666	CssmAutoData 	aData(mAlloc);		// for malloc/copy of outgoing data
667
668	/* query for each OID we know about */
669	for(currOidDex=0; currOidDex<NUM_KNOWN_FIELDS; currOidDex++) {
670		const oidToFieldFuncs *fieldFuncs = &crlFieldTable[currOidDex];
671		currOid = fieldFuncs->fieldId;
672		uint32 numFields;				// for THIS oid
673
674		/*
675		 * Return false if field not there, which is not an error here.
676		 * Actual exceptions are fatal.
677		 */
678		if(!fieldFuncs->getFcn(*this,
679				0, 				// index - looking for first one
680				numFields,
681				aData)) {
682			continue;
683		}
684
685		/* got some data for this oid - copy it and oid to outgoing CrlFields */
686		assert(numOutFields < maxFields);
687		currOutField = &outFields[numOutFields];
688		currOutField->FieldValue = aData.release();
689		aData.copy(*currOid);
690		currOutField->FieldOid = aData.release();
691		numOutFields++;
692
693		/* if more fields are available for this OID, snag them too */
694		for(uint32 fieldDex=1; fieldDex<numFields; fieldDex++) {
695			/* note this should always succeed */
696			bool brtn = fieldFuncs->getFcn(*this,
697				fieldDex,
698				numFields, 			// shouldn't change
699				aData);
700			if(!brtn) {
701				clErrorLog("getAllParsedCrlFields: index screwup");
702				CssmError::throwMe(CSSMERR_CL_INTERNAL_ERROR);
703			}
704			assert(numOutFields < maxFields);
705			currOutField = &outFields[numOutFields];
706			currOutField->FieldValue = aData.release();
707			aData.copy(*currOid);
708			currOutField->FieldOid = aData.release();
709			numOutFields++;
710		}	/* multiple fields for currOid */
711	}		/* for each known OID */
712
713	NumberOfFields = numOutFields;
714	CrlFields = outFields;
715}
716
717void
718DecodedCrl::describeFormat(
719	Allocator &alloc,
720	uint32 &NumberOfFields,
721	CSSM_OID_PTR &OidList)
722{
723	/* malloc in app's space, do deep copy (including ->Data) */
724	CSSM_OID_PTR oidList = (CSSM_OID_PTR)alloc.malloc(
725		NUM_KNOWN_FIELDS * sizeof(CSSM_OID));
726	memset(oidList, 0, NUM_KNOWN_FIELDS * sizeof(CSSM_OID));
727	for(unsigned i=0; i<NUM_KNOWN_FIELDS; i++) {
728		CssmAutoData oidCopy(alloc, *crlFieldTable[i].fieldId);
729		oidList[i] = oidCopy.release();
730	}
731	NumberOfFields = NUM_KNOWN_FIELDS;
732	OidList = oidList;
733}
734