]>
Commit | Line | Data |
---|---|---|
b1ab9ed8 A |
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 */ | |
141 | typedef 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 | ||
149 | class AppleX509CLSession; | |
150 | ||
151 | class DecodedItem | |
152 | { | |
153 | public: | |
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 | ||
166 | public: | |
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 | ||
221 | protected: | |
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_ */ |