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 * CertFields.cpp - convert between NSS-based Certificate components and CDSA-style
21 *                  fields. A major component of DecodedCert.
22 *
23 * Created 9/1/2000 by Doug Mitchell.
24 * Copyright (c) 2000 by Apple Computer.
25 */
26
27#include "DecodedCert.h"
28#include "cldebugging.h"
29#include "CLCertExtensions.h"
30#include "clNssUtils.h"
31#include "clNameUtils.h"
32#include "CLFieldsCommon.h"
33#include <Security/oidscert.h>
34#include <Security/x509defs.h>
35#include <security_utilities/utilities.h>
36
37/***
38 *** Version
39 *** Format = DER-encoded int (max of four bytes in this case)
40 ***/
41static bool getField_Version (
42	DecodedItem		 	&item,
43	unsigned			index,			// which occurrence (0 = first)
44	uint32				&numFields,		// RETURNED
45	CssmOwnedData		&fieldValue)	// RETURNED
46{
47	const DecodedCert &cert = dynamic_cast<const DecodedCert &>(item);
48	const CSSM_DATA &vers = cert.mCert.tbs.version;
49	if(!tbsGetCheck(vers.Data, index)) {
50		/* not present, optional */
51		return false;
52	}
53	fieldValue.copy(vers.Data, vers.Length);
54	numFields = 1;
55	return true;
56}
57
58static void setField_Version (
59	DecodedItem			&item,
60	const CssmData		&fieldValue)
61{
62	DecodedCert &cert = dynamic_cast<DecodedCert &>(item);
63	CSSM_DATA &vers = cert.mCert.tbs.version;
64	tbsSetCheck(vers.Data, fieldValue, 0, "version");
65	cert.coder().allocCopyItem(fieldValue, vers);
66}
67
68
69#if	this_is_a_template
70/***
71 *** Version
72 *** Format = DER-encoded int (always four bytes in this case)
73 ***/
74static bool getField_Version (
75	DecodedItem		 	&item,
76	unsigned			index,			// which occurrence (0 = first)
77	uint32				&numFields,		// RETURNED
78	CssmOwnedData		&fieldValue)	// RETURNED
79{
80	const DecodedCert &cert = dynamic_cast<const DecodedCert &>(item);
81	tbsGetCheck(cert.certificateToSign->version, index);
82}
83static void setField_Version (
84	DecodedItem			&item,
85	const CssmData		&fieldValue)
86{
87	DecodedCert &cert = dynamic_cast<DecodedCert &>(item);
88	tbsSetCheck(cert.certificateToSign->version, fieldValue, sizeof(uint32),
89		"version");
90
91}
92static void freeField_Version (
93	CssmOwnedData		&fieldValue)
94{
95}
96#endif
97
98/***
99 *** Serial Number
100 *** Format = DER-encoded int, variable length
101 ***/
102static bool getField_SerialNumber (
103	DecodedItem		 	&item,
104	unsigned			index,			// which occurrence (0 = first)
105	uint32				&numFields,		// RETURNED
106	CssmOwnedData		&fieldValue)	// RETURNED
107{
108	const DecodedCert &cert = dynamic_cast<const DecodedCert &>(item);
109	const CSSM_DATA &sn = cert.mCert.tbs.serialNumber;
110	if(!tbsGetCheck(sn.Data, index)) {
111		return false;
112	}
113	fieldValue.copy(sn.Data, sn.Length);
114	numFields = 1;
115	return true;
116}
117
118static void setField_SerialNumber (
119	DecodedItem			&item,
120	const CssmData		&fieldValue)
121{
122	DecodedCert &cert = dynamic_cast<DecodedCert &>(item);
123	CSSM_DATA &sn = cert.mCert.tbs.serialNumber;
124	tbsSetCheck(sn.Data, fieldValue, 0, "SerialNumber");
125	cert.coder().allocCopyItem(fieldValue, sn);
126}
127
128/*** issuer/subject
129 *** Format = CSSM_X509_NAME
130 *** class Name from sm_x501if
131 ***/
132static bool getField_Issuer (
133	DecodedItem			&item,
134	unsigned			index,			// which occurrence (0 = first)
135	uint32				&numFields,		// RETURNED
136	CssmOwnedData		&fieldValue)	// RETURNED
137{
138	if(index != 0) {
139		return false;
140	}
141
142	bool brtn;
143
144	const DecodedCert &cert = dynamic_cast<const DecodedCert &>(item);
145	try {
146		brtn = getField_RDN_NSS(cert.mCert.tbs.issuer, fieldValue);
147		if(brtn) {
148			numFields = 1;
149		}
150	}
151	catch (...) {
152		freeField_RDN(fieldValue);
153		throw;
154	}
155	return brtn;
156}
157
158static void setField_Issuer  (
159	DecodedItem			&item,
160	const CssmData		&fieldValue)
161{
162	DecodedCert &cert = dynamic_cast<DecodedCert &>(item);
163	const CSSM_X509_NAME *cssmName = (const CSSM_X509_NAME *)fieldValue.Data;
164	NSS_Name &nssName = cert.mCert.tbs.issuer;
165	tbsSetCheck(nssName.rdns, fieldValue, sizeof(CSSM_X509_NAME),
166		"IssuerName");
167	CL_cssmNameToNss(*cssmName, nssName, cert.coder());
168}
169
170/*** subject ***/
171static bool getField_Subject (
172	DecodedItem		 	&item,
173	unsigned			index,			// which occurrence (0 = first)
174	uint32				&numFields,		// RETURNED
175	CssmOwnedData		&fieldValue)	// RETURNED
176{
177	if(index != 0) {
178		return false;
179	}
180
181	bool brtn;
182
183	const DecodedCert &cert = dynamic_cast<const DecodedCert &>(item);
184	try {
185		brtn = getField_RDN_NSS(cert.mCert.tbs.subject, fieldValue);
186		if(brtn) {
187			numFields = 1;
188		}
189	}
190	catch (...) {
191		freeField_RDN(fieldValue);
192		throw;
193	}
194	return brtn;
195}
196
197static void setField_Subject  (
198	DecodedItem			&item,
199	const CssmData		&fieldValue)
200{
201	DecodedCert &cert = dynamic_cast<DecodedCert &>(item);
202	const CSSM_X509_NAME *cssmName = (const CSSM_X509_NAME *)fieldValue.Data;
203	NSS_Name &nssName = cert.mCert.tbs.subject;
204	tbsSetCheck(nssName.rdns, fieldValue, sizeof(CSSM_X509_NAME),
205		"SubjectName");
206	CL_cssmNameToNss(*cssmName, nssName, cert.coder());
207}
208
209/***
210 *** Issuer Name, Subject Name (normalized and encoded version)
211 *** Format = CSSM_DATA containing the DER encoding of the normalized name
212 ***/
213static bool getFieldSubjectNorm(
214	DecodedItem		 	&item,
215	unsigned			index,			// which occurrence (0 = first)
216	uint32				&numFields,		// RETURNED
217	CssmOwnedData		&fieldValue)	// RETURNED
218{
219	if(index != 0) {
220		return false;
221	}
222	const DecodedCert &cert = dynamic_cast<const DecodedCert &>(item);
223	return getField_normRDN_NSS(cert.mCert.tbs.derSubject, numFields,
224		fieldValue);
225}
226
227static bool getFieldIssuerNorm(
228	DecodedItem		 	&item,
229	unsigned			index,			// which occurrence (0 = first)
230	uint32				&numFields,		// RETURNED
231	CssmOwnedData		&fieldValue)	// RETURNED
232{
233	if(index != 0) {
234		return false;
235	}
236	const DecodedCert &cert = dynamic_cast<const DecodedCert &>(item);
237	return getField_normRDN_NSS(cert.mCert.tbs.derIssuer, numFields, fieldValue);
238}
239
240/***
241 *** Issuer Name, Subject Name (encoded, NON-normalized version)
242 *** Format = CSSM_DATA containing the DER encoding of the name
243 ***/
244static bool getFieldSubjectStd(
245	DecodedItem		 	&item,
246	unsigned			index,			// which occurrence (0 = first)
247	uint32				&numFields,		// RETURNED
248	CssmOwnedData		&fieldValue)	// RETURNED
249{
250	if(index != 0) {
251		return false;
252	}
253	const DecodedCert &cert = dynamic_cast<const DecodedCert &>(item);
254	fieldValue.copy(cert.mCert.tbs.derSubject);
255	numFields = 1;
256	return true;
257}
258
259static bool getFieldIssuerStd(
260	DecodedItem		 	&item,
261	unsigned			index,			// which occurrence (0 = first)
262	uint32				&numFields,		// RETURNED
263	CssmOwnedData		&fieldValue)	// RETURNED
264{
265	if(index != 0) {
266		return false;
267	}
268	const DecodedCert &cert = dynamic_cast<const DecodedCert &>(item);
269	fieldValue.copy(cert.mCert.tbs.derIssuer);
270	numFields = 1;
271	return true;
272}
273
274/***
275 *** TBS AlgId, Signature AlgId
276 *** Format = CSSM_X509_ALGORITHM_IDENTIFIER
277 ***/
278/* TBS AlgId */
279static bool getField_TbsAlgId (
280	DecodedItem		 	&item,
281	unsigned			index,			// which occurrence (0 = first)
282	uint32				&numFields,		// RETURNED
283	CssmOwnedData		&fieldValue)	// RETURNED
284{
285	const DecodedCert &cert = dynamic_cast<const DecodedCert &>(item);
286	const CSSM_X509_ALGORITHM_IDENTIFIER &srcAlgId = cert.mCert.tbs.signature;
287	if(!tbsGetCheck(srcAlgId.algorithm.Data, index)) {
288		return false;
289	}
290	getField_AlgIdNSS(srcAlgId, fieldValue);
291	numFields = 1;
292	return true;
293}
294
295static void setField_TbsAlgId (
296	DecodedItem			&item,
297	const CssmData		&fieldValue)
298{
299	DecodedCert &cert = dynamic_cast<DecodedCert &>(item);
300	CSSM_X509_ALGORITHM_IDENTIFIER &dstAlgId = cert.mCert.tbs.signature;
301	tbsSetCheck(dstAlgId.algorithm.Data, fieldValue,
302		sizeof(CSSM_X509_ALGORITHM_IDENTIFIER), "TBS_AlgId");
303	setField_AlgIdNSS(fieldValue, dstAlgId, cert.coder());
304}
305
306/* Cert AlgId - read only */
307static bool getField_CertAlgId (
308	DecodedItem		 	&item,
309	unsigned			index,			// which occurrence (0 = first)
310	uint32				&numFields,		// RETURNED
311	CssmOwnedData		&fieldValue)	// RETURNED
312{
313	const DecodedCert &cert = dynamic_cast<const DecodedCert &>(item);
314	const CSSM_X509_ALGORITHM_IDENTIFIER &srcAlgId = cert.mCert.signatureAlgorithm;
315	if(!tbsGetCheck(srcAlgId.algorithm.Data, index)) {
316		return false;
317	}
318	getField_AlgIdNSS(srcAlgId, fieldValue);
319	numFields = 1;
320	return true;
321}
322
323/***
324 *** Validity not before, not after
325 *** Format: CSSM_X509_TIME
326 ***/
327
328/*** not before ***/
329static bool getField_NotBefore (
330	DecodedItem		 	&item,
331	unsigned			index,			// which occurrence (0 = first)
332	uint32				&numFields,		// RETURNED
333	CssmOwnedData		&fieldValue)	// RETURNED
334{
335	const DecodedCert &cert = dynamic_cast<const DecodedCert &>(item);
336	const NSS_Time &srcTime = cert.mCert.tbs.validity.notBefore;
337	return getField_TimeNSS(srcTime, index, numFields, fieldValue);
338}
339
340static void setField_NotBefore (
341	DecodedItem			&item,
342	const CssmData		&fieldValue)
343{
344	DecodedCert &cert = dynamic_cast<DecodedCert &>(item);
345	NSS_Time &dstTime = cert.mCert.tbs.validity.notBefore;
346	tbsSetCheck(dstTime.item.Data, fieldValue,
347		sizeof(CSSM_X509_TIME), "NotBefore");
348	setField_TimeNSS(fieldValue, dstTime, cert.coder());
349}
350
351/*** not after ***/
352static bool getField_NotAfter (
353	DecodedItem		 	&item,
354	unsigned			index,			// which occurrence (0 = first)
355	uint32				&numFields,		// RETURNED
356	CssmOwnedData		&fieldValue)	// RETURNED
357{
358	const DecodedCert &cert = dynamic_cast<const DecodedCert &>(item);
359	const NSS_Time &srcTime = cert.mCert.tbs.validity.notAfter;
360	return getField_TimeNSS(srcTime, index, numFields, fieldValue);
361}
362
363static void setField_NotAfter (
364	DecodedItem			&item,
365	const CssmData		&fieldValue)
366{
367	DecodedCert &cert = dynamic_cast<DecodedCert &>(item);
368	NSS_Time &dstTime = cert.mCert.tbs.validity.notAfter;
369	tbsSetCheck(dstTime.item.Data, fieldValue,
370		sizeof(CSSM_X509_TIME), "NotAfter");
371	setField_TimeNSS(fieldValue, dstTime, cert.coder());
372}
373
374/***
375 *** Subject/issuer unique ID
376 *** Format: Raw bytes. It's stored in the cert as an ASN bit string; the decoded
377 *** bytes are present at this level (i.e., not tag and length in the bytes).
378 *** NOTE: this is not quite accurate in that we only provide byte-aligned size,
379 *** not bit-aligned. This field is rarely if ever used so I think it's O, but
380 *** beware.
381 ***/
382static bool getField_SubjectUniqueId (
383	DecodedItem		 	&item,
384	unsigned			index,			// which occurrence (0 = first)
385	uint32				&numFields,		// RETURNED
386	CssmOwnedData		&fieldValue)	// RETURNED
387{
388	const DecodedCert &cert = dynamic_cast<const DecodedCert &>(item);
389	const CSSM_DATA &srcBits = cert.mCert.tbs.subjectID;
390	if(!tbsGetCheck(srcBits.Data, index)) {
391		return false;
392	}
393
394	/* That CSSM_DATA is a decoded BITSTRING; its length is in bits */
395	CSSM_DATA tmp = srcBits;
396	tmp.Length = (tmp.Length + 7) / 8;
397	fieldValue.copy(tmp.Data, tmp.Length);
398	numFields = 1;
399	return true;
400}
401
402static void setField_SubjectUniqueId (
403	DecodedItem			&item,
404	const CssmData		&fieldValue)
405{
406	DecodedCert &cert = dynamic_cast<DecodedCert &>(item);
407	CSSM_DATA &dstBits = cert.mCert.tbs.subjectID;
408	tbsSetCheck(dstBits.Data, fieldValue, 0, "SubjectUniqueID");
409	cert.coder().allocCopyItem(fieldValue, dstBits);
410	dstBits.Length *= 8;
411}
412
413static bool getField_IssuerUniqueId (
414	DecodedItem		 	&item,
415	unsigned			index,			// which occurrence (0 = first)
416	uint32				&numFields,		// RETURNED
417	CssmOwnedData		&fieldValue)	// RETURNED
418{
419	const DecodedCert &cert = dynamic_cast<const DecodedCert &>(item);
420	const CSSM_DATA &srcBits = cert.mCert.tbs.issuerID;
421	if(!tbsGetCheck(srcBits.Data, index)) {
422		return false;
423	}
424
425	/* That CSSM_DATA is a decoded BITSTRING; its length is in bits */
426	CSSM_DATA tmp = srcBits;
427	tmp.Length = (tmp.Length + 7) / 8;
428	fieldValue.copy(tmp.Data, tmp.Length);
429	numFields = 1;
430	return true;
431}
432
433static void setField_IssuerUniqueId (
434	DecodedItem			&item,
435	const CssmData		&fieldValue)
436{
437	DecodedCert &cert = dynamic_cast<DecodedCert &>(item);
438	CSSM_DATA &dstBits = cert.mCert.tbs.issuerID;
439	tbsSetCheck(dstBits.Data, fieldValue, 0, "IssuerUniqueID");
440	cert.coder().allocCopyItem(fieldValue, dstBits);
441	dstBits.Length *= 8;
442}
443
444/***
445 *** Public key info
446 *** Format = CSSM_X509_SUBJECT_PUBLIC_KEY_INFO
447 ***/
448static bool getField_PublicKeyInfo (
449	DecodedItem		 	&item,
450	unsigned			index,			// which occurrence (0 = first)
451	uint32				&numFields,		// RETURNED
452	CssmOwnedData		&fieldValue)	// RETURNED
453{
454	const DecodedCert &cert = dynamic_cast<const DecodedCert &>(item);
455	const CSSM_X509_SUBJECT_PUBLIC_KEY_INFO &srcInfo =
456		cert.mCert.tbs.subjectPublicKeyInfo;
457	if(!tbsGetCheck(srcInfo.subjectPublicKey.Data, index)) {
458		return false;
459	}
460
461	Allocator &alloc = fieldValue.allocator;
462	fieldValue.malloc(sizeof(CSSM_X509_SUBJECT_PUBLIC_KEY_INFO));
463	CSSM_X509_SUBJECT_PUBLIC_KEY_INFO *dstInfo =
464		(CSSM_X509_SUBJECT_PUBLIC_KEY_INFO *)fieldValue.data();
465
466	CL_copySubjPubKeyInfo(srcInfo, true,		// length in bits here
467		*dstInfo, false,						// length in bytes
468		alloc);
469
470	numFields = 1;
471	return true;
472}
473
474static void setField_PublicKeyInfo (
475	DecodedItem			&item,
476	const CssmData		&fieldValue)
477{
478	DecodedCert &cert = dynamic_cast<DecodedCert &>(item);
479	CSSM_X509_SUBJECT_PUBLIC_KEY_INFO &dstKeyInfo =
480		cert.mCert.tbs.subjectPublicKeyInfo;
481	tbsSetCheck(dstKeyInfo.subjectPublicKey.Data, fieldValue,
482		sizeof(CSSM_X509_SUBJECT_PUBLIC_KEY_INFO), "PubKeyInfo");
483
484	CSSM_X509_SUBJECT_PUBLIC_KEY_INFO *srcKeyInfo =
485		(CSSM_X509_SUBJECT_PUBLIC_KEY_INFO *)fieldValue.Data;
486	if((srcKeyInfo->subjectPublicKey.Data == NULL) ||
487	   (srcKeyInfo->subjectPublicKey.Length == 0)) {
488		CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER);
489	}
490
491	ArenaAllocator arenaAlloc(cert.coder());
492	CL_copySubjPubKeyInfo(*srcKeyInfo, false,	// length in bytes here
493		dstKeyInfo, true,						// length in bits
494		arenaAlloc);
495}
496
497static void freeField_PublicKeyInfo (
498	CssmOwnedData		&fieldValue)
499{
500	CSSM_X509_SUBJECT_PUBLIC_KEY_INFO *cssmKeyInfo =
501		(CSSM_X509_SUBJECT_PUBLIC_KEY_INFO *)fieldValue.data();
502	if(cssmKeyInfo == NULL) {
503		return;
504	}
505	Allocator &alloc = fieldValue.allocator;
506	CL_freeCssmAlgId(&cssmKeyInfo->algorithm, alloc);
507	alloc.free(cssmKeyInfo->subjectPublicKey.Data);
508	memset(cssmKeyInfo, 0, sizeof(CSSM_X509_SUBJECT_PUBLIC_KEY_INFO));}
509
510/***
511 *** key info from CSSM_KEY
512 *** Format = CSSM_KEY
513 ***/
514static bool getField_PublicKeyStruct (
515	DecodedItem		 	&item,
516	unsigned			index,			// which occurrence (0 = first)
517	uint32				&numFields,		// RETURNED
518	CssmOwnedData		&fieldValue)	// RETURNED
519{
520	const DecodedCert &cert = dynamic_cast<const DecodedCert &>(item);
521	if(!tbsGetCheck(cert.mCert.tbs.subjectPublicKeyInfo.subjectPublicKey.Data,
522			index)) {
523		return false;
524	}
525	CSSM_KEY_PTR cssmKey = cert.extractCSSMKey(fieldValue.allocator);
526	fieldValue.set(reinterpret_cast<uint8 *>(cssmKey), sizeof(CSSM_KEY));
527	numFields = 1;
528	return true;
529}
530
531static void setField_PublicKeyStruct (
532	DecodedItem			&item,
533	const CssmData		&fieldValue)
534{
535	DecodedCert &cert = dynamic_cast<DecodedCert &>(item);
536	CSSM_X509_SUBJECT_PUBLIC_KEY_INFO &dstKeyInfo =
537		cert.mCert.tbs.subjectPublicKeyInfo;
538	tbsSetCheck(dstKeyInfo.subjectPublicKey.Data, fieldValue,
539		sizeof(CSSM_KEY), "PubKeyStruct");
540
541	CSSM_KEY_PTR cssmKey = (CSSM_KEY_PTR)fieldValue.data();
542	if((cssmKey->KeyData.Data == NULL) ||
543	   (cssmKey->KeyData.Data == 0)) {
544		CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER);
545	}
546	CL_CSSMKeyToSubjPubKeyInfoNSS(*cssmKey, dstKeyInfo, cert.coder());
547}
548
549static void freeField_PublicKeyStruct (
550	CssmOwnedData		&fieldValue)
551{
552	CSSM_KEY_PTR cssmKey = (CSSM_KEY_PTR)fieldValue.data();
553	CL_freeCSSMKey(cssmKey, fieldValue.allocator, false);
554}
555
556/***
557 *** Signature
558 *** Format = raw bytes
559 *** read-only
560 ***/
561static bool getField_Signature (
562	DecodedItem		 	&item,
563	unsigned			index,			// which occurrence (0 = first)
564	uint32				&numFields,		// RETURNED
565	CssmOwnedData		&fieldValue)	// RETURNED
566{
567	const DecodedCert &cert = dynamic_cast<const DecodedCert &>(item);
568	const CSSM_DATA &sigBits = cert.mCert.signature;
569	if(!tbsGetCheck(sigBits.Data, index)) {
570		return false;
571	}
572	fieldValue.copy(sigBits.Data, (sigBits.Length + 7) / 8);
573	numFields = 1;
574	return true;
575}
576
577/***
578 *** end of field-specific triplets
579 ***/
580
581/*
582 * Table to map OID to {get,set,free}field
583 */
584typedef struct {
585	const CSSM_OID		*fieldId;
586	getItemFieldFcn		*getFcn;
587	setItemFieldFcn		*setFcn;
588	freeFieldFcn		*freeFcn;		// OPTIONAL - NULL means just free the
589										// top-level data
590} oidToFieldFuncs;
591
592static const oidToFieldFuncs fieldFuncTable[] = {
593	{ 	&CSSMOID_X509V1Version,
594		&getField_Version, &setField_Version, NULL },
595	{ 	&CSSMOID_X509V1SerialNumber,
596		&getField_SerialNumber, &setField_SerialNumber, NULL 	},
597	{ 	&CSSMOID_X509V1IssuerNameCStruct,
598		&getField_Issuer, &setField_Issuer, &freeField_RDN },
599	{ 	&CSSMOID_X509V1SubjectNameCStruct,
600		&getField_Subject, &setField_Subject, &freeField_RDN },
601	{	&CSSMOID_X509V1SignatureAlgorithmTBS,
602		&getField_TbsAlgId, &setField_TbsAlgId, &freeField_AlgId },
603	{	&CSSMOID_X509V1SignatureAlgorithm,
604		&getField_CertAlgId, &setField_ReadOnly, &freeField_AlgId	},
605	{	&CSSMOID_X509V1ValidityNotBefore,
606		&getField_NotBefore,	&setField_NotBefore,	&freeField_Time },
607	{	&CSSMOID_X509V1ValidityNotAfter,
608		&getField_NotAfter, &setField_NotAfter, &freeField_Time },
609	{	&CSSMOID_X509V1CertificateIssuerUniqueId,
610		&getField_IssuerUniqueId, &setField_IssuerUniqueId, NULL },
611	{	&CSSMOID_X509V1CertificateSubjectUniqueId,
612		&getField_SubjectUniqueId, &setField_SubjectUniqueId, NULL },
613	{	&CSSMOID_X509V1SubjectPublicKeyCStruct,
614		&getField_PublicKeyInfo, &setField_PublicKeyInfo, &freeField_PublicKeyInfo },
615	{	&CSSMOID_CSSMKeyStruct,
616		&getField_PublicKeyStruct, &setField_PublicKeyStruct,
617		&freeField_PublicKeyStruct },
618	{	&CSSMOID_X509V1Signature,
619		&getField_Signature, &setField_ReadOnly, NULL },
620	{   &CSSMOID_X509V1IssuerName,
621		getFieldIssuerNorm, &setField_ReadOnly, NULL },
622	{   &CSSMOID_X509V1SubjectName,
623		getFieldSubjectNorm, &setField_ReadOnly, NULL },
624	{   &CSSMOID_X509V1IssuerNameStd,
625		getFieldIssuerStd, &setField_ReadOnly, NULL },
626	{   &CSSMOID_X509V1SubjectNameStd,
627		getFieldSubjectStd, &setField_ReadOnly, NULL },
628
629	/*
630	 * Extensions, implemented in CLCertExtensions.cpp
631	 * When adding new ones, also add to:
632	 *   -- clOidToNssInfo() in CLFieldsCommon.cpp
633	 *   -- get/set/free functions in CLCertExtensions.{cpp,h}
634	 */
635	{	&CSSMOID_KeyUsage, &getFieldKeyUsage, &setFieldKeyUsage,
636	    &freeFieldSimpleExtension },
637	{   &CSSMOID_BasicConstraints, &getFieldBasicConstraints,
638	    &setFieldBasicConstraints, &freeFieldSimpleExtension },
639	{	&CSSMOID_ExtendedKeyUsage, &getFieldExtKeyUsage,
640		&setFieldExtKeyUsage, &freeFieldExtKeyUsage } ,
641	{	&CSSMOID_SubjectKeyIdentifier, &getFieldSubjectKeyId,
642		&setFieldSubjectKeyId, &freeFieldSubjectKeyId } ,
643	{	&CSSMOID_AuthorityKeyIdentifier, &getFieldAuthorityKeyId,
644		&setFieldAuthorityKeyId, &freeFieldAuthorityKeyId } ,
645	{	&CSSMOID_SubjectAltName, &getFieldSubjAltName,
646		&setFieldSubjIssuerAltName, &freeFieldSubjIssuerAltName } ,
647	{	&CSSMOID_IssuerAltName, &getFieldIssuerAltName,
648		&setFieldSubjIssuerAltName, &freeFieldSubjIssuerAltName } ,
649	{	&CSSMOID_CertificatePolicies, &getFieldCertPolicies,
650		&setFieldCertPolicies, &freeFieldCertPolicies } ,
651	{	&CSSMOID_NetscapeCertType, &getFieldNetscapeCertType,
652		&setFieldNetscapeCertType, &freeFieldSimpleExtension } ,
653	{	&CSSMOID_CrlDistributionPoints, &getFieldCrlDistPoints,
654		&setFieldCrlDistPoints, &freeFieldCrlDistPoints },
655	{   &CSSMOID_X509V3CertificateExtensionCStruct, &getFieldUnknownExt,
656		&setFieldUnknownExt, &freeFieldUnknownExt },
657	{   &CSSMOID_AuthorityInfoAccess, &getFieldAuthInfoAccess,
658		&setFieldAuthInfoAccess, &freeFieldInfoAccess },
659	{   &CSSMOID_SubjectInfoAccess, &getFieldSubjInfoAccess,
660		&setFieldAuthInfoAccess, &freeFieldInfoAccess },
661	{	&CSSMOID_QC_Statements, &getFieldQualCertStatements,
662		&setFieldQualCertStatements, &freeFieldQualCertStatements },
663
664	{   &CSSMOID_NameConstraints, &getFieldNameConstraints,
665		&setFieldNameConstraints, &freeFieldNameConstraints },
666	{   &CSSMOID_PolicyMappings, &getFieldPolicyMappings,
667		&setFieldPolicyMappings, &freeFieldPolicyMappings },
668	{   &CSSMOID_PolicyConstraints, &getFieldPolicyConstraints,
669		&setFieldPolicyConstraints, &freeFieldPolicyConstraints },
670	{   &CSSMOID_InhibitAnyPolicy, &getFieldInhibitAnyPolicy,
671		&setFieldInhibitAnyPolicy, &freeFieldSimpleExtension },
672
673};
674
675#define NUM_KNOWN_FIELDS		(sizeof(fieldFuncTable) / sizeof(oidToFieldFuncs))
676#define NUM_STD_CERT_FIELDS		17		/* not including extensions */
677
678/* map an OID to an oidToFieldFuncs */
679static const oidToFieldFuncs *oidToFields(
680	const CssmOid			&fieldId)
681{
682	const oidToFieldFuncs *fieldTable = fieldFuncTable;
683	for(unsigned i=0; i<NUM_KNOWN_FIELDS; i++) {
684		if(fieldId == CssmData::overlay(*fieldTable->fieldId)) {
685			return fieldTable;
686		}
687		fieldTable++;
688	}
689#ifndef	NDEBUG
690	clErrorLog("oidToFields: unknown OID (len=%d): %s\n",
691		(int)fieldId.length(), fieldId.toHex().c_str());
692#endif
693	CssmError::throwMe(CSSMERR_CL_UNKNOWN_TAG);
694}
695
696
697/***
698 *** Public functions
699 ***/
700
701/*
702 * Obtain the index'th occurrence of field specified by fieldId in specified cert.
703 * Format of the returned field depends on fieldId.
704 * Returns total number of fieldId fields in the cert if index is 0.
705 * FieldValue assumed to be empty on entry.
706 * Returns true if specified field was found, else returns false.
707 */
708bool DecodedCert::getCertFieldData(
709	const CssmOid		&fieldId,		// which field
710	unsigned			index,			// which occurrence (0 = first)
711	uint32				&numFields,		// RETURNED
712	CssmOwnedData		&fieldValue) 	// RETURNED
713{
714	switch(mState) {
715		case IS_Empty:
716		case IS_Building:
717			clErrorLog("DecodedCert::getCertField: can't parse undecoded cert!");
718			CssmError::throwMe(CSSMERR_CL_INTERNAL_ERROR);
719		case IS_DecodedAll:
720		case IS_DecodedTBS:
721			break;
722	}
723	const oidToFieldFuncs *fieldFuncs = oidToFields(fieldId);
724	return fieldFuncs->getFcn(*this, index, numFields, fieldValue);
725}
726
727/*
728 * Set the field specified by fieldId in the specified Cert.
729 * Note no index - individual field routines either append (for extensions)
730 * or if field already set ::throwMe(for all others)
731 */
732void DecodedCert::setCertField(
733	const CssmOid		&fieldId,		// which field
734	const CssmData		&fieldValue)
735{
736	switch(mState) {
737		case IS_Empty:			// first time thru
738			mState = IS_Building;
739			break;
740		case IS_Building:		// subsequent passes
741			break;
742		case IS_DecodedAll:
743		case IS_DecodedTBS:
744			clErrorLog("DecodedCert::setCertField: can't build on a decoded cert!");
745			CssmError::throwMe(CSSMERR_CL_INTERNAL_ERROR);
746	}
747	if((fieldValue.data() == NULL) || (fieldValue.length() == 0)) {
748		CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER);
749	}
750	const oidToFieldFuncs *fieldFuncs = oidToFields(fieldId);
751	const CssmData &value = CssmData::overlay(fieldValue);
752	fieldFuncs->setFcn(*this, value);
753}
754
755/*
756 * Free the fieldId-specific data referred to by fieldValue->Data.
757 */
758void DecodedCert::freeCertFieldData(
759	const CssmOid		&fieldId,
760	CssmOwnedData		&fieldValue)
761{
762	if((fieldValue.data() == NULL) || (fieldValue.length() == 0)) {
763		CssmError::throwMe(CSSM_ERRCODE_INVALID_FIELD_POINTER);
764	}
765	const oidToFieldFuncs *fieldFuncs = oidToFields(fieldId);
766	if(fieldFuncs->freeFcn != NULL) {
767		/* optional - simple cases handled below */
768		fieldFuncs->freeFcn(fieldValue);
769	}
770	fieldValue.reset();
771	fieldValue.release();
772
773}
774
775
776/*
777 * Common means to get all fields from a decoded cert. Used in
778 * CertGetAllTemplateFields and CertGetAllFields.
779 */
780void DecodedCert::getAllParsedCertFields(
781	uint32 				&NumberOfFields,		// RETURNED
782	CSSM_FIELD_PTR 		&CertFields)			// RETURNED
783{
784	/* this is the max - some might be missing */
785	uint32 maxFields = NUM_STD_CERT_FIELDS + mDecodedExtensions.numExtensions();
786	CSSM_FIELD_PTR outFields = (CSSM_FIELD_PTR)mAlloc.malloc(maxFields * sizeof(CSSM_FIELD));
787
788	/*
789	 * We'll be copying oids and values for fields we find into
790	 * outFields; current number of valid fields found in numOutFields.
791	 */
792	memset(outFields, 0, maxFields * sizeof(CSSM_FIELD));
793	uint32 			numOutFields = 0;
794	CSSM_FIELD_PTR 	currOutField;
795	uint32 			currOidDex;
796	const CSSM_OID 	*currOid;
797	CssmAutoData 	aData(mAlloc);		// for malloc/copy of outgoing data
798
799	/* query for each OID we know about */
800	for(currOidDex=0; currOidDex<NUM_KNOWN_FIELDS; currOidDex++) {
801		const oidToFieldFuncs *fieldFuncs = &fieldFuncTable[currOidDex];
802		currOid = fieldFuncs->fieldId;
803		uint32 numFields;				// for THIS oid
804
805		/*
806		 * Return false if field not there, which is not an error here.
807		 * Actual exceptions are fatal.
808		 */
809		if(!fieldFuncs->getFcn(*this,
810				0, 				// index - looking for first one
811				numFields,
812				aData)) {
813			continue;
814		}
815
816		/* got some data for this oid - copy it and oid to outgoing CertFields */
817		assert(numOutFields < maxFields);
818		currOutField = &outFields[numOutFields];
819		currOutField->FieldValue = aData.release();
820		aData.copy(*currOid);
821		currOutField->FieldOid = aData.release();
822		numOutFields++;
823
824		/* if more fields are available for this OID, snag them too */
825		for(uint32 fieldDex=1; fieldDex<numFields; fieldDex++) {
826			/* note this should always succeed */
827			bool brtn = fieldFuncs->getFcn(*this,
828				fieldDex,
829				numFields, 			// shouldn't change
830				aData);
831			if(!brtn) {
832				clErrorLog("getAllParsedCertFields: index screwup");
833				CssmError::throwMe(CSSMERR_CL_INTERNAL_ERROR);
834			}
835			assert(numOutFields < maxFields);
836			currOutField = &outFields[numOutFields];
837			currOutField->FieldValue = aData.release();
838			aData.copy(*currOid);
839			currOutField->FieldOid = aData.release();
840			numOutFields++;
841		}	/* multiple fields for currOid */
842	}		/* for each known OID */
843
844	NumberOfFields = numOutFields;
845	CertFields = outFields;
846}
847
848void
849DecodedCert::describeFormat(
850	Allocator &alloc,
851	uint32 &NumberOfFields,
852	CSSM_OID_PTR &OidList)
853{
854	/* malloc in app's space, do deep copy (including ->Data) */
855	CSSM_OID_PTR oidList = (CSSM_OID_PTR)alloc.malloc(
856		NUM_KNOWN_FIELDS * sizeof(CSSM_OID));
857	memset(oidList, 0, NUM_KNOWN_FIELDS * sizeof(CSSM_OID));
858	for(unsigned i=0; i<NUM_KNOWN_FIELDS; i++) {
859		CssmAutoData oidCopy(alloc, *fieldFuncTable[i].fieldId);
860		oidList[i] = oidCopy.release();
861	}
862	NumberOfFields = NUM_KNOWN_FIELDS;
863	OidList = oidList;
864}
865