1/*
2 * Copyright (c) 2002 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 * DecodedItem.cpp - class representing the common portions of
21 * NSS-format decoded certs and CRLs, with extensions parsed and
22 * decoded (still in NSS format).
23 */
24
25#include "DecodedItem.h"
26#include "cldebugging.h"
27#include "AppleX509CLSession.h"
28#include "CSPAttacher.h"
29#include "CLFieldsCommon.h"
30#include "clNssUtils.h"
31#include "clNameUtils.h"
32#include <security_asn1/SecAsn1Types.h>
33#include <Security/cssmapple.h>
34#include <Security/oidscert.h>
35
36#define MIN_EXTENSIONS		4		// initial size of *mExtensions
37
38DecodedExten::DecodedExten(
39	const CSSM_OID 	&extnId,	// copied
40	bool			critical,
41	void			*nssObj,	// NSS_KeyUsage, NSS_BasicConstraints,
42								//   etc. NOT COPIED, exists in same
43								//   memory space as coder
44	bool			berEncoded,	// indicates unknown extension which we
45								// do not BER-decode when parsing a cert
46	const SecAsn1Template *templ,	// to decode/encode if !berEncoded
47	SecNssCoder		&coder,			// all local allocs from here
48	const CSSM_DATA	*rawExtn)	// NSS_CertExtension.value, copied to
49								//   mRawExtn
50	: mCritical(critical),
51	  mNssObj(nssObj),
52	  mBerEncoded(berEncoded),
53	  mTempl(templ),
54	  mCoder(coder),
55	  mRawExtn(NULL)
56{
57	coder.allocCopyItem(extnId, mExtnId);
58	if(rawExtn) {
59		mRawExtn = (CSSM_DATA *)coder.malloc(sizeof(CSSM_DATA));
60		coder.allocCopyItem(*rawExtn, *mRawExtn);
61	}
62}
63
64DecodedExten::~DecodedExten()
65{
66	/* the only stuff we allocated was in the coder pool and will be freed
67	 * when coder is freed */
68}
69
70/*
71 * Given a fully encoded BER object, create a CSSM_X509EXT_TAGandVALUE
72 * representing it. We malloc the CSSM_X509EXT_TAGandVALUE itself using
73 * specified allocator, but the referent (in CSSM_X509EXT_TAGandVALUE.value)
74 * merely points to data inside the berValue.
75 */
76CSSM_X509EXT_TAGandVALUE *DecodedExten::createTagAndValue(
77	const CSSM_DATA &berValue,
78	Allocator &alloc) const
79{
80	if((berValue.Data == NULL) || (berValue.Length == 0)) {
81		return NULL;
82	}
83	CSSM_X509EXT_TAGandVALUE *tv = (CSSM_X509EXT_TAGandVALUE *)
84		alloc.malloc(sizeof(CSSM_X509EXT_TAGandVALUE));
85
86	// Important: by the time we get called, the extension data
87	// has already been deconstructed, and the raw value we are
88	// handed in berValue does not include ASN.1 type or length.
89	// Since createTagAndValue is only called in the case where
90	// the contents are unknown (and thus opaque), always treat
91	// as an octet string.
92
93	tv->type = SEC_ASN1_OCTET_STRING;
94	tv->value.Length = berValue.Length;
95	tv->value.Data = berValue.Data;
96	return tv;
97
98#if 0
99	tv->type = berValue.Data[0];
100
101	/*
102	 * length of length is variable; ASN spec says it can actually be up to
103	 * 127 bytes, but we only have room for 32 bits!
104	 */
105	const uint8 *lp = berValue.Data + 1;
106	uint8 len1 = *lp;
107	if((len1 & 0x80) == 0) {
108		/* short form */
109		tv->value.Length = len1;
110		tv->value.Data = const_cast<uint8 *>(lp + 1);
111		return tv;
112	}
113
114	unsigned numLenBytes = len1 & 0x7f;
115	if(numLenBytes > 4) {
116		clErrorLog("createTagAndValue: impossible length of length (%u)\n", numLenBytes);
117		alloc.free(tv);
118		CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
119	}
120
121	uint32 len = 0;
122	lp++;			// points to first length byte
123	for(uint32 dex=0; dex<numLenBytes; dex++) {
124		len <<= 8;
125		len += *lp;
126		lp++;
127	}
128	tv->value.Length = len;
129	tv->value.Data = const_cast<uint8 *>(lp);
130	return tv;
131#endif
132}
133
134/*
135 * Convert this extension to a CSSM_X509_EXTENSION, in the specified
136 * (app-level) alloc space, after its contents have
137 * been converted to a native CDSA object (CE_KeyUsage, etc.).
138 */
139void DecodedExten::convertToCdsa(
140	void 					*cdsaObj,		// e.g. CE_KeyUsage
141											// CSSM_DATA_PTR for berEncoded
142	CSSM_X509_EXTENSION_PTR	cssmExt,		// contents RETURNED
143	Allocator			&alloc) const
144{
145	clAllocCopyData(alloc, mExtnId, cssmExt->extnId);
146	cssmExt->critical = mCritical ? CSSM_TRUE : CSSM_FALSE;
147
148	/*
149	 * in either case copy the raw extension data if we have it (we may not
150	 * have it if this was created via setField).
151	 */
152	if(mRawExtn) {
153		clAllocCopyData(alloc, *mRawExtn, cssmExt->BERvalue);
154	}
155	else {
156		cssmExt->BERvalue.Data = NULL;
157		cssmExt->BERvalue.Length = 0;
158	}
159	if(mBerEncoded) {
160		/* an extension we never parsed or understood */
161		assert(cdsaObj == NULL);
162		cssmExt->format = CSSM_X509_DATAFORMAT_ENCODED;
163		cssmExt->value.tagAndValue = createTagAndValue(cssmExt->BERvalue, alloc);
164	}
165	else {
166		/* caller sees parsed version plus raw BER-encoded bytes */
167		assert(cdsaObj != NULL);
168		cssmExt->format = CSSM_X509_DATAFORMAT_PARSED;
169		/* in app alloc's space, mallocd by getField*() */
170		cssmExt->value.parsedValue = cdsaObj;
171	}
172}
173
174/*
175 * Convert a DecodedExten to a CSSM_X509_EXTENSION. This includes
176 * the mapping of the extnId to a known CDSA type and type and doing the
177 * actual NSS-to-CDSA conversion. At the time this function is
178 * called, the DecodedExten either has a valid mNssObj, or it's an
179 * unknown extension type in which case mNssObj is an AsnOcts containing
180 * the opaquely DER-encoded extension value.
181 *
182 * Currently only used when decoding a CRL and converting it en masse
183 * to CDSA.
184 */
185template<class NssType, class CdsaType>
186void nssToCssm(
187	const DecodedExten	&decodedExt,
188	NssType				*&nssObj,		// RETURNED
189	CdsaType			*&cdsaObj,		// mallocd and RETURNED
190	Allocator		&alloc)
191{
192	nssObj = (NssType *)(decodedExt.nssObj());
193	assert(nssObj != NULL);
194	cdsaObj = (CdsaType *)alloc.malloc(sizeof(CdsaType));
195	memset(cdsaObj, 0, sizeof(CdsaType));
196}
197
198void DecodedExten::parse(
199	CSSM_X509_EXTENSION_PTR	cssmExt,		// mallocd by caller, RETURNED
200	Allocator			&alloc) const
201{
202	void *vCdsaObj = NULL;
203	if(mBerEncoded) {
204		/* non-understood extension */
205		convertToCdsa(NULL, cssmExt, alloc);
206		return;
207	}
208	if(clCompareCssmData(&mExtnId, &CSSMOID_AuthorityKeyIdentifier)) {
209		CE_AuthorityKeyID *cdsaObj;
210		NSS_AuthorityKeyId *nssObj;
211		nssToCssm<NSS_AuthorityKeyId, CE_AuthorityKeyID>(
212			*this,
213			nssObj,
214			cdsaObj,
215			alloc);
216		CL_nssAuthorityKeyIdToCssm(*nssObj, *cdsaObj, mCoder, alloc);
217		vCdsaObj = cdsaObj;
218	}
219	/* same encoding (uint32) for all of these: */
220	else if(clCompareCssmData(&mExtnId, &CSSMOID_CrlNumber) ||
221	        clCompareCssmData(&mExtnId, &CSSMOID_DeltaCrlIndicator) ||
222			clCompareCssmData(&mExtnId, &CSSMOID_CrlReason)) {
223		CE_CrlNumber *cdsaObj;
224		CSSM_DATA *nssObj;
225		nssToCssm<CSSM_DATA, CE_CrlNumber>(
226			*this,
227			nssObj,
228			cdsaObj,
229			alloc);
230		CSSM_RETURN toThrow;
231		if(clCompareCssmData(&mExtnId, &CSSMOID_CrlReason)) {
232			toThrow = CSSMERR_CL_INVALID_CRL_POINTER;
233		}
234		else {
235			/* tolerate crlNumber > 4 bytes */
236			toThrow = CSSM_OK;
237		}
238		*cdsaObj = clDataToInt(*nssObj, toThrow);
239		vCdsaObj = cdsaObj;
240	}
241	/* same encoding (GeneralNames) for all of these: */
242	else if(clCompareCssmData(&mExtnId, &CSSMOID_IssuerAltName) ||
243	   clCompareCssmData(&mExtnId, &CSSMOID_SubjectAltName) ||
244	   clCompareCssmData(&mExtnId, &CSSMOID_CertIssuer)) {
245		CE_GeneralNames *cdsaObj;
246		NSS_GeneralNames *nssObj;
247		nssToCssm<NSS_GeneralNames, CE_GeneralNames>(
248			*this,
249			nssObj,
250			cdsaObj,
251			alloc);
252		CL_nssGeneralNamesToCssm(*nssObj, *cdsaObj, mCoder, alloc);
253		vCdsaObj = cdsaObj;
254	}
255	else if(clCompareCssmData(&mExtnId, &CSSMOID_IssuingDistributionPoint)) {
256		CE_IssuingDistributionPoint *cdsaObj;
257		NSS_IssuingDistributionPoint *nssObj;
258		nssToCssm<NSS_IssuingDistributionPoint, CE_IssuingDistributionPoint>(
259			*this,
260			nssObj,
261			cdsaObj,
262			alloc);
263		CL_nssIssuingDistPointToCssm(nssObj, cdsaObj, mCoder, alloc);
264		vCdsaObj = cdsaObj;
265	}
266    /*
267        <rdar://problem/9580989> CrashTracer: [USER] 48 crashes in WebProcess at ...
268        This code should not normally be executed, since it seems from RFC5280 that
269        CSSMOID_IssuingDistributionPoint is the correct extension to use.
270    */
271	else if(clCompareCssmData(&mExtnId, &CSSMOID_CrlDistributionPoints)) {
272		CE_CRLDistPointsSyntax *cdsaObj;
273		NSS_CRLDistributionPoints *nssObj;
274		nssToCssm<NSS_CRLDistributionPoints, CE_CRLDistPointsSyntax>(
275			*this,
276			nssObj,
277			cdsaObj,
278			alloc);
279		CL_nssDistPointsToCssm((const NSS_CRLDistributionPoints&)*nssObj, *cdsaObj, mCoder, alloc);
280		vCdsaObj = cdsaObj;
281	}
282	/*
283	 * cert entry extensions
284	 */
285	else if(clCompareCssmData(&mExtnId, &CSSMOID_HoldInstructionCode)) {
286		/* value is just an OID */
287		CSSM_OID *cdsaObj;
288		CSSM_DATA *nssObj;
289		nssToCssm<CSSM_DATA, CSSM_OID>(
290			*this,
291			nssObj,
292			cdsaObj,
293			alloc);
294		clAllocCopyData(alloc, *nssObj, *cdsaObj);
295		vCdsaObj = cdsaObj;
296	}
297	else if(clCompareCssmData(&mExtnId, &CSSMOID_InvalidityDate)) {
298		/* GeneralizedTime */
299		CSSM_DATA *cdsaObj;
300		CSSM_DATA *nssObj;
301		nssToCssm<CSSM_DATA, CSSM_DATA>(
302			*this,
303			nssObj,
304			cdsaObj,
305			alloc);
306		clAllocCopyData(alloc, *nssObj, *cdsaObj);
307		vCdsaObj = cdsaObj;
308	}
309	else {
310		/* if we get here, this routine is not keeping up with
311		 * clOidToNssInfo()  */
312		// assert(0);
313		CssmError::throwMe(CSSMERR_CL_INTERNAL_ERROR);
314	}
315	convertToCdsa(vCdsaObj, cssmExt, alloc);
316}
317
318
319#pragma mark ------ DecodedExtensions ------
320
321/*
322 * A variable-size array of DecodedExtens.
323 * Used for storing cert and CRL extensions as well as per-CRL-entry
324 * extensions.
325 */
326DecodedExtensions::DecodedExtensions(
327	SecNssCoder		&coder,
328	Allocator	&alloc)
329	:	mCoder(coder),
330		mAlloc(alloc),
331		mExtensions(NULL),
332		mNumExtensions(0),
333		mSizeofExtensions(0)
334{
335
336}
337
338DecodedExtensions::~DecodedExtensions()
339{
340	for(unsigned i=0; i<mNumExtensions; i++) {
341		assert(mExtensions[i] != NULL);
342		delete mExtensions[i];
343	}
344	mAlloc.free(mExtensions);
345	mExtensions = NULL;
346	mNumExtensions = 0;
347	mSizeofExtensions = 0;
348}
349
350
351/*
352 * Initialize by decoding a NSS-style NSS_CertExtension array.
353 * This involves figuring out what kind of object is represented in the
354 * octet string in the  extension, decoding it, and appending the resulting
355 * NSS object to mExtensions in the form of a DecodedExten.
356 *
357 * Called when decoding either a cert or a CRL (for caching it or
358 * getting its fields) or a cert template (only via
359 * CertGetAllTemplateFields()).
360 */
361void DecodedExtensions::decodeFromNss(
362	NSS_CertExtension 	**extensions)
363{
364	if(extensions == NULL) {
365		/* OK, no extensions present */
366		return;
367	}
368	unsigned numExtens = clNssArraySize((const void **)extensions);
369
370	/* traverse extension list */
371	for(unsigned dex=0; dex<numExtens; dex++) {
372		NSS_CertExtension *nssExten = extensions[dex];
373
374		/*
375		 * For this extension->extnId, cook up an appropriate
376		 * NSS-specific type (NSS_KeyUsage, etc.);
377		 */
378		CSSM_DATA &rawExtn = nssExten->value;
379		bool berEncoded = false;
380		bool found;								// we understand this OID
381		unsigned nssObjLen;						// size of associated NSS object
382		const SecAsn1Template *templ = NULL;	// template for decoding
383		void *nssObj = NULL;					// decode destination
384		found = clOidToNssInfo(nssExten->extnId, nssObjLen, templ);
385		if(!found) {
386			/*
387			 * We don't know how to deal with this.
388			 */
389			berEncoded = true;
390		}
391		else {
392			/*
393			 * Create NSS-style object specific to this extension, just
394			 * by knowing its length and ASN template.
395			 * Decode the extensions's extnValue into that object. We don't
396			 * have to know what kind of object it is anymore.
397			 */
398			assert(templ != NULL);
399			nssObj = mCoder.malloc(nssObjLen);
400			memset(nssObj, 0, nssObjLen);
401			PRErrorCode prtn;
402			prtn = mCoder.decodeItem(rawExtn, templ, nssObj);
403			if(prtn) {
404				/*
405				 * FIXME - what do we do here? For now flag it
406				 * as an non-understood extension...
407				 */
408				clErrorLog("decodeExtensions: extension decode error\n");
409				nssObj = NULL;
410				berEncoded = true;
411			}
412		}
413		if((nssObj != NULL) || berEncoded) {
414			/* append if the decode was successful */
415			addExtension(nssExten->extnId,
416				clNssBoolToCssm(nssExten->critical),
417				nssObj,
418				berEncoded,
419				templ,
420				&rawExtn);
421		}
422	}
423}
424
425/*
426 * Encode into a NSS-style Extensions.
427 *
428 * Each extension object, currently stored as some AsnType subclass,
429 * is BER-encoded and the result is stored as an octet string
430 * (AsnOcts) in a new Extension object in the TBS.
431 *
432 * Called from {Crl,Cert}CreateTemplate via encode{Tbs,Cts}().
433 */
434void DecodedExtensions::encodeToNss(
435	NSS_CertExtension 	**&extensions)
436{
437	assert(extensions == NULL);
438
439	if(mNumExtensions == 0) {
440		/* no extensions, no error */
441		return;
442	}
443
444	/* malloc a NULL_terminated array of NSS_CertExtension pointers */
445	unsigned len = (mNumExtensions + 1) * sizeof(NSS_CertExtension *);
446	extensions = (NSS_CertExtension **)mCoder.malloc(len);
447	memset(extensions, 0, len);
448
449	/* grind thru our DecodedExtens, creating an NSS_CertExtension for
450	 * each one */
451	for(unsigned extenDex=0; extenDex<mNumExtensions; extenDex++) {
452		NSS_CertExtension *thisNssExten =
453			(NSS_CertExtension *)mCoder.malloc(sizeof(NSS_CertExtension));
454		memset(thisNssExten, 0, sizeof(NSS_CertExtension));
455		extensions[extenDex] = thisNssExten;
456
457		const DecodedExten *decodedExt = getExtension(extenDex);
458
459		/* BER-encode the extension object if appropriate */
460		if(decodedExt->berEncoded()) {
461			/* unknown extension type, it's already encoded */
462			const CSSM_DATA *srcBer = (const CSSM_DATA *)decodedExt->rawExtn();
463			assert(srcBer != NULL);
464			mCoder.allocCopyItem(*srcBer, thisNssExten->value);
465		}
466		else {
467			PRErrorCode prtn;
468			prtn = mCoder.encodeItem(decodedExt->nssObj(),
469				decodedExt->templ(), thisNssExten->value);
470			if(prtn) {
471				clErrorLog("encodeToNss: extension encode error");
472				CssmError::throwMe(CSSMERR_CL_INTERNAL_ERROR);
473			}
474		}
475		ArenaAllocator arenaAlloc(mCoder);
476		if(decodedExt->critical()) {
477			/* optional, default false */
478			clCssmBoolToNss(CSSM_TRUE, thisNssExten->critical, arenaAlloc);
479		}
480		mCoder.allocCopyItem(decodedExt->extnId(), thisNssExten->extnId);
481	}
482}
483
484/* add/retrieve entries */
485void DecodedExtensions::addExtension(
486	const CSSM_OID 	&extnId,	// copied
487	bool			critical,
488	void			*nssObj,	// NSS_KeyUsage, NSS_BasicConstraints,
489								//   etc. NOT COPIED, exists in same
490								//   memory space as coder
491	bool			berEncoded,	// indicates unknown extension which we
492								// do not BER-decode when parsing a cert
493	const SecAsn1Template *templ, // required if !berEncoded
494	const CSSM_DATA	*rawExtn) 	// NSS_CertExtension.value, copied,
495								//   optional (not present during a
496								//   SetField op)
497{
498	if(mNumExtensions == mSizeofExtensions) {
499		/* expand by doubling, or initial malloc */
500		mSizeofExtensions = mNumExtensions ?
501			(2 * mNumExtensions) : MIN_EXTENSIONS;
502		mExtensions = (DecodedExten **)mAlloc.realloc(
503			mExtensions, mSizeofExtensions * sizeof(DecodedExten));
504	}
505	mExtensions[mNumExtensions++] = new DecodedExten(extnId,
506		critical, nssObj, berEncoded, templ, mCoder, rawExtn);
507}
508
509const DecodedExten *DecodedExtensions::getExtension(
510	unsigned extenDex) const
511{
512	assert(extenDex < mNumExtensions);
513	return mExtensions[extenDex];
514}
515
516/* Convert to CSSM_X509_EXTENSIONS */
517/* Currently only used when decoding a CRL and converting it en masse
518 * to CDSA */
519void DecodedExtensions::convertToCdsa(
520	CSSM_X509_EXTENSIONS		&cssmExtens,
521	Allocator				&alloc) const
522{
523	memset(&cssmExtens, 0, sizeof(cssmExtens));
524	if(mNumExtensions == 0) {
525		return;
526	}
527	cssmExtens.extensions = (CSSM_X509_EXTENSION_PTR)alloc.malloc(
528		sizeof(CSSM_X509_EXTENSION) * mNumExtensions);
529	memset(cssmExtens.extensions, 0,
530		sizeof(CSSM_X509_EXTENSION) * mNumExtensions);
531	cssmExtens.numberOfExtensions = mNumExtensions;
532	for(unsigned dex=0; dex<mNumExtensions; dex++) {
533		try {
534			getExtension(dex)->parse(&cssmExtens.extensions[dex], alloc);
535		}
536		catch(...) {
537			/* FIXME - what now? */
538			clFieldLog("DecodedExtensions:convertToCdsa: extension "
539				"decode error");
540		}
541	}
542}
543
544