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