1/*
2 * Copyright (c) 2000-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.h - class representing the common portions of NSS-format
21 * decoded certs and CRLs, with extensions parsed and decoded (still in
22 * NSS format).
23 *
24 * When a DecodedItem (cert or CRL) is quiescent and cached in the CL
25 * (either by an explicit cache call like CSSM_CL_CertCache or
26 * CSSM_CL_CrlCache(), or during a succession of GetFirst/GetNext field
27 * ops), the item is stored in the CL in what we call NSS form. NSS is
28 * the module we use to perform DER encoding and decoding; NSS form
29 * refers to structs defining Certs, CRLs, and extensions which are
30 * directly encodable and decodable by the NSS library. NSS structs are
31 * similar to their CDSA counterparts, sometimes identical, usually
32 * subtly different (due to requirements of the NSS module).
33 *
34 * Decoding a cert or a CRL:
35 * -------------------------
36 *
37 * When an app decodes a cert or CRL for any reason, the following phases
38 * are executed:
39 *
40 * PHASE I
41 * -------
42 *
43 * Basic BER-decode if the incoming CSSM_DATA blob. This happens in the
44 * constructors for DecodedCert and DecodedCrl. A modified/restricted
45 * version of this occurs in DecodedCert::decodeTbs(), which is used
46 * during a CSSM_CL_CertGetAllTemplateFields() call.
47 *
48 * PHASE II
49 * --------
50 *
51 * Extensions are converted from untyped blobs - which is how they look
52 * after PHASE I - to NSS-style C structs. This is done by examining
53 * the ExtnId of each cert's or CRL's extensions and doing a BER decode
54 * specific to that extension type. This is performed in
55 * DecodedExtensions.decodeFromNss() which is called immediately after
56 * the top-level decode performed in PHASE I.
57 *
58 * It is at this point that a cert or CRL can be cached in the CL's
59 * cacheMap or queryMap (see AppleX509CLSession.{h,cpp}. We call this
60 * state "NSS Form".
61 *
62 * PHASE III (CRLs only)
63 * --------------------
64 *
65 * This occurs when an app is actually fetching a full CRL in
66 * CDSA form. Individual entries in a CRL's revocation list also
67 * contain per-entry extension lists. These are converted from
68 * untyped blobs to meaningful NSS-style extension structs as
69 * in PHASE II prior to the conversion to CDSA form in PHASE IV.
70 *
71 * PHASE IV
72 * ---------
73 *
74 * This occurs when an app is actually fetching fields in CDSA form.
75 * This involves converting objects from NSS form to CDSA form
76 * (if necessary) and copying to the session allocator's memory space.
77 *
78 * The rationale behind this phased approach - in particular, the
79 * reason that in-memory items are stored in NSS form - is that this
80 * minimizes the number of copies between the intiial parse of a cert
81 * or CRL and the final GetField op. Since a GetField op inherently
82 * requires a copy (from internal memory to the session allocator's
83 * space), and conversion from NSS to CDSA form is basically a bunch of
84 * copies as well, we might as well just stop with the item in CRL
85 * format as soon as PHASE II is complete. Note that completion of
86 * PHASE II is in fact required before caching a cert since that enables
87 * us to have access to extension-specific info while a cert is
88 * cached. The KeyUsage and ExtendedKeyUsage extensions are used in
89 * this manner to get key info from a TBS cert.
90 *
91 *
92 * Creating and encoding a cert:
93 * -----------------------------
94 *
95 * Creating a cert (creating CRLs is not supported in this release)
96 * follows more or less the reverse procedure, as follows:
97 *
98 * PHASE I
99 * -------
100 *
101 * During a CSSM_CL_CertCreateTemplate() op, all fields which the
102 * app wishes to specify are passed into the CL in CDSA form. These
103 * fields are converted to NSS form in a temporary DecodedCert. This
104 * includes extensions (in NSS form).
105 *
106 * PHASE II
107 * --------
108 *
109 * Extensions in NSS form are encoded and bundled up into the final,
110 * BER-encode ready NSS_CertExtension array form. This occurs
111 * in DecodedCert::encodeExtensions(), called from the top of
112 * DecodedCert::encodeTbs(). We're still processing an app's
113 * CSSM_CL_CertCreateTemplate() call at this point.
114 *
115 * PHASE III
116 * ---------
117 *
118 * Final DER-encoding of a TBS cert is performed in
119 * DecodedCert::encodeTbs(). The resulting CSSM_DATA is
120 * passed back to the app as what CDSA calls a template.
121 * This completes the CSSM_CL_CertCreateTemplate() call.
122 *
123 * PHASE IV
124 * --------
125 *
126 * The TBS cert blob is signed and the resulting DER-encoded
127 * cert is passed back to the app.
128 */
129
130#ifndef	_DECODED_ITEM_H_
131#define _DECODED_ITEM_H_
132
133#include <Security/cssmtype.h>
134#include <security_cdsa_utilities/cssmdata.h>
135
136#include "cldebugging.h"
137#include "DecodedExtensions.h"
138#include <security_asn1/SecNssCoder.h>
139
140/* state of a DecodedItem */
141typedef enum {
142	IS_Empty,
143	IS_DecodedAll,		// can't set fields in this state
144	IS_DecodedTBS,		// ditto
145	IS_Building			// in the process of setting fields
146} ItemState;
147
148
149class AppleX509CLSession;
150
151class DecodedItem
152{
153public:
154	DecodedItem(
155		AppleX509CLSession	&session);
156
157	virtual ~DecodedItem();
158
159	SecNssCoder &coder() { return mCoder; }
160
161	static void describeFormat(
162		Allocator 		&alloc,
163		uint32 				&NumberOfFields,
164		CSSM_OID_PTR 		&OidList);
165
166public:
167	/***
168	 *** Extensions support
169	 ***/
170
171	/* called from decodeExtensions and setField* */
172	void addExtension(
173		void 				*nssThing,	// e.g. NSS_KeyUsage
174		const CSSM_OID		&extnId,
175		bool				critical,
176		bool				berEncoded,
177		const SecAsn1Template *templ,		// to decode/encode if !berEncoded
178		const CSSM_DATA		*rawExtn=NULL)	// Extension.extnValue, copied, only for
179											//   setField*()
180			{ mDecodedExtensions.addExtension(extnId, critical, nssThing,
181				berEncoded, templ, rawExtn);
182			}
183
184	const DecodedExten *findDecodedExt(
185		const CSSM_OID		&extnId,		// for known extensions
186		bool				unknown,		// otherwise
187		uint32				index,
188		uint32				&numFields) const;
189
190	const DecodedExtensions		&decodedExtens() const
191		{ return mDecodedExtensions; }
192
193	/*
194	 * Common code for get extension field routines.
195	 * Given an OID identifying an extension and an index, see if
196	 * we have the specified extension in mDecodedExtensions and
197	 * return the NSS and CDSA style objects as well as the
198	 * DecodedExten.
199	 */
200	template<class NssType, class CdsaType>
201	bool GetExtenTop(
202		unsigned			index,			// which occurrence (0 = first)
203		uint32				&numFields,		// RETURNED
204		Allocator			&alloc,
205		const CSSM_OID		&fieldId,		// identifies extension we seek
206		NssType				*&nssObj,		// RETURNED
207		CdsaType			*&cdsaObj,		// mallocd and RETURNED
208		const DecodedExten	*&decodedExt) const	// RETURNED
209	{
210		/* See if we have one of these in our list of DecodedExtens */
211		decodedExt = findDecodedExt(fieldId, false, index, numFields);
212		if(decodedExt == NULL) {
213			return false;
214		}
215		nssObj = (NssType *)decodedExt->nssObj();
216		cdsaObj = (CdsaType *)alloc.malloc(sizeof(CdsaType));
217		memset(cdsaObj, 0, sizeof(CdsaType));
218		return true;
219	}
220
221protected:
222	ItemState			mState;
223	Allocator		&mAlloc;
224	SecNssCoder			mCoder;			// from which all local allocs come
225	AppleX509CLSession	&mSession;
226	DecodedExtensions	mDecodedExtensions;
227
228};
229
230
231#endif	/* _DECODED_ITEM_H_ */
232