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