]> git.saurik.com Git - apple/security.git/blob - AppleX509CL/DecodedExtensions.cpp
Security-177.tar.gz
[apple/security.git] / AppleX509CL / DecodedExtensions.cpp
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/cssmapple.h>
33 #include <Security/oidscert.h>
34
35 #define MIN_EXTENSIONS 4 // initial size of *mExtensions
36
37 DecodedExten::DecodedExten(
38 const CSSM_OID &extnId, // copied
39 bool critical,
40 void *nssObj, // NSS_KeyUsage, NSS_BasicConstraints,
41 // etc. NOT COPIED, exists in same
42 // memory space as coder
43 bool berEncoded, // indicates unknown extension which we
44 // do not BER-decode when parsing a cert
45 const SEC_ASN1Template *templ, // to decode/encode if !berEncoded
46 SecNssCoder &coder, // all local allocs from here
47 const CSSM_DATA *rawExtn) // NSS_CertExtension.value, copied to
48 // mRawExtn
49 : mCritical(critical),
50 mNssObj(nssObj),
51 mBerEncoded(berEncoded),
52 mTempl(templ),
53 mCoder(coder),
54 mRawExtn(NULL)
55 {
56 coder.allocCopyItem(extnId, mExtnId);
57 if(rawExtn) {
58 mRawExtn = (CSSM_DATA *)coder.malloc(sizeof(CSSM_DATA));
59 coder.allocCopyItem(*rawExtn, *mRawExtn);
60 }
61 }
62
63 DecodedExten::~DecodedExten()
64 {
65 /* the only stuff we allocated was in the coder pool and will be freed
66 * when coder is freed */
67 }
68
69 /*
70 * Convert this extension to a CSSM_X509_EXTENSION, in the specified
71 * (app-level) alloc space, after its contents have
72 * been converted to a native CDSA object (CE_KeyUsage, etc.).
73 */
74 void DecodedExten::convertToCdsa(
75 void *cdsaObj, // e.g. CE_KeyUsage
76 // CSSM_DATA_PTR for berEncoded
77 CSSM_X509_EXTENSION_PTR cssmExt, // contents RETURNED
78 CssmAllocator &alloc) const
79 {
80 clAllocCopyData(alloc, mExtnId, cssmExt->extnId);
81 cssmExt->critical = mCritical ? CSSM_TRUE : CSSM_FALSE;
82
83 /*
84 * in either case copy the raw extension data if we have it (we may not
85 * have it if this was created via setField).
86 */
87 if(mRawExtn) {
88 clAllocCopyData(alloc, *mRawExtn, cssmExt->BERvalue);
89 }
90 else {
91 cssmExt->BERvalue.Data = NULL;
92 cssmExt->BERvalue.Length = 0;
93 }
94 if(mBerEncoded) {
95 /* an extension we never parsed or understood */
96 assert(cdsaObj == NULL);
97 cssmExt->format = CSSM_X509_DATAFORMAT_ENCODED;
98 cssmExt->value.parsedValue = NULL;
99 }
100 else {
101 /* caller sees parsed version plus raw BER-encoded bytes */
102 assert(cdsaObj != NULL);
103 if(mRawExtn) {
104 /* normal decode & parse case */
105 cssmExt->format = CSSM_X509_DATAFORMAT_PAIR;
106 }
107 else {
108 /* setField */
109 cssmExt->format = CSSM_X509_DATAFORMAT_PARSED;
110 }
111 /* in app alloc's space, mallocd by getField*() */
112 cssmExt->value.parsedValue = cdsaObj;
113 }
114 }
115
116 /*
117 * Convert a DecodedExten to a CSSM_X509_EXTENSION. This includes
118 * the mapping of the extnId to a known CDSA type and type and doing the
119 * actual NSS-to-CDSA conversion. At the time this function is
120 * called, the DecodedExten either has a valid mNssObj, or it's an
121 * unknown extension type in which case mNssObj is an AsnOcts containing
122 * the opaquely DER-encoded extension value.
123 *
124 * Currently only used when decoding a CRL and converting it en masse
125 * to CDSA.
126 */
127 template<class NssType, class CdsaType>
128 void nssToCssm(
129 const DecodedExten &decodedExt,
130 NssType *&nssObj, // RETURNED
131 CdsaType *&cdsaObj, // mallocd and RETURNED
132 CssmAllocator &alloc)
133 {
134 nssObj = (NssType *)(decodedExt.nssObj());
135 assert(nssObj != NULL);
136 cdsaObj = (CdsaType *)alloc.malloc(sizeof(CdsaType));
137 memset(cdsaObj, 0, sizeof(CdsaType));
138 }
139
140 void DecodedExten::parse(
141 CSSM_X509_EXTENSION_PTR cssmExt, // mallocd by caller, RETURNED
142 CssmAllocator &alloc) const
143 {
144 void *vCdsaObj = NULL;
145 if(mBerEncoded) {
146 /* non-understood extension */
147 convertToCdsa(NULL, cssmExt, alloc);
148 return;
149 }
150 if(clCompareCssmData(&mExtnId, &CSSMOID_AuthorityKeyIdentifier)) {
151 CE_AuthorityKeyID *cdsaObj;
152 NSS_AuthorityKeyId *nssObj;
153 nssToCssm<NSS_AuthorityKeyId, CE_AuthorityKeyID>(
154 *this,
155 nssObj,
156 cdsaObj,
157 alloc);
158 CL_nssAuthorityKeyIdToCssm(*nssObj, *cdsaObj, mCoder, alloc);
159 vCdsaObj = cdsaObj;
160 }
161 /* same encoding (uint32) for all of these: */
162 else if(clCompareCssmData(&mExtnId, &CSSMOID_CrlNumber) ||
163 clCompareCssmData(&mExtnId, &CSSMOID_DeltaCrlIndicator) ||
164 clCompareCssmData(&mExtnId, &CSSMOID_CrlReason)) {
165 CE_CrlNumber *cdsaObj;
166 CSSM_DATA *nssObj;
167 nssToCssm<CSSM_DATA, CE_CrlNumber>(
168 *this,
169 nssObj,
170 cdsaObj,
171 alloc);
172 *cdsaObj = clDataToInt(*nssObj);
173 vCdsaObj = cdsaObj;
174 }
175 /* same encoding (GeneralNames) for all of these: */
176 else if(clCompareCssmData(&mExtnId, &CSSMOID_IssuerAltName) ||
177 clCompareCssmData(&mExtnId, &CSSMOID_SubjectAltName) ||
178 clCompareCssmData(&mExtnId, &CSSMOID_CertIssuer)) {
179 CE_GeneralNames *cdsaObj;
180 NSS_GeneralNames *nssObj;
181 nssToCssm<NSS_GeneralNames, CE_GeneralNames>(
182 *this,
183 nssObj,
184 cdsaObj,
185 alloc);
186 CL_nssGeneralNamesToCssm(*nssObj, *cdsaObj, mCoder, alloc);
187 vCdsaObj = cdsaObj;
188 }
189 else if(clCompareCssmData(&mExtnId, &CSSMOID_IssuingDistributionPoint)) {
190 CE_IssuingDistributionPoint *cdsaObj;
191 NSS_IssuingDistributionPoint *nssObj;
192 nssToCssm<NSS_IssuingDistributionPoint, CE_IssuingDistributionPoint>(
193 *this,
194 nssObj,
195 cdsaObj,
196 alloc);
197 CL_nssIssuingDistPointToCssm(nssObj, cdsaObj, mCoder, alloc);
198 vCdsaObj = cdsaObj;
199 }
200
201 /*
202 * cert entry extensions
203 */
204 else if(clCompareCssmData(&mExtnId, &CSSMOID_HoldInstructionCode)) {
205 /* value is just an OID */
206 CSSM_OID *cdsaObj;
207 CSSM_DATA *nssObj;
208 nssToCssm<CSSM_DATA, CSSM_OID>(
209 *this,
210 nssObj,
211 cdsaObj,
212 alloc);
213 clAllocCopyData(alloc, *nssObj, *cdsaObj);
214 vCdsaObj = cdsaObj;
215 }
216 else if(clCompareCssmData(&mExtnId, &CSSMOID_InvalidityDate)) {
217 /* GeneralizedTime */
218 CSSM_DATA *cdsaObj;
219 CSSM_DATA *nssObj;
220 nssToCssm<CSSM_DATA, CSSM_DATA>(
221 *this,
222 nssObj,
223 cdsaObj,
224 alloc);
225 clAllocCopyData(alloc, *nssObj, *cdsaObj);
226 vCdsaObj = cdsaObj;
227 }
228 else {
229 /* if we get here, this routine is not keeping up with
230 * clOidToNssInfo() */
231 assert(0);
232 CssmError::throwMe(CSSMERR_CL_INTERNAL_ERROR);
233 }
234 convertToCdsa(vCdsaObj, cssmExt, alloc);
235 }
236
237
238 #pragma mark ------ DecodedExtensions ------
239
240 /*
241 * A variable-size array of DecodedExtens.
242 * Used for storing cert and CRL extensions as well as per-CRL-entry
243 * extensions.
244 */
245 DecodedExtensions::DecodedExtensions(
246 SecNssCoder &coder,
247 CssmAllocator &alloc)
248 : mCoder(coder),
249 mAlloc(alloc),
250 mExtensions(NULL),
251 mNumExtensions(0),
252 mSizeofExtensions(0)
253 {
254
255 }
256
257 DecodedExtensions::~DecodedExtensions()
258 {
259 for(unsigned i=0; i<mNumExtensions; i++) {
260 assert(mExtensions[i] != NULL);
261 delete mExtensions[i];
262 }
263 mAlloc.free(mExtensions);
264 mExtensions = NULL;
265 mNumExtensions = 0;
266 mSizeofExtensions = 0;
267 }
268
269
270 /*
271 * Initialize by decoding a NSS-style NSS_CertExtension array.
272 * This involves figuring out what kind of object is represented in the
273 * octet string in the extension, decoding it, and appending the resulting
274 * NSS object to mExtensions in the form of a DecodedExten.
275 *
276 * Called when decoding either a cert or a CRL (for caching it or
277 * getting its fields) or a cert template (only via
278 * CertGetAllTemplateFields()).
279 */
280 void DecodedExtensions::decodeFromNss(
281 NSS_CertExtension **extensions)
282 {
283 if(extensions == NULL) {
284 /* OK, no extensions present */
285 return;
286 }
287 unsigned numExtens = clNssArraySize((const void **)extensions);
288
289 /* traverse extension list */
290 for(unsigned dex=0; dex<numExtens; dex++) {
291 NSS_CertExtension *nssExten = extensions[dex];
292
293 /*
294 * For this extension->extnId, cook up an approppriate
295 * NSS-specific type (NSS_KeyUsage, etc.);
296 */
297 CSSM_DATA &rawExtn = nssExten->value;
298 bool berEncoded = false;
299 bool found; // we understand this OID
300 unsigned nssObjLen; // size of associated NSS object
301 const SEC_ASN1Template *templ = NULL; // template for decoding
302 void *nssObj = NULL; // decode destination
303 found = clOidToNssInfo(nssExten->extnId, nssObjLen, templ);
304 if(!found) {
305 /*
306 * We don't know how to deal with this.
307 */
308 berEncoded = true;
309 }
310 else {
311 /*
312 * Create NSS-style object specific to this extension, just
313 * by knowing its length and ASN template.
314 * Decode the extensions's extnValue into that object. We don't
315 * have to know what kind of object it is anymore.
316 */
317 assert(templ != NULL);
318 nssObj = mCoder.malloc(nssObjLen);
319 memset(nssObj, 0, nssObjLen);
320 PRErrorCode prtn;
321 prtn = mCoder.decodeItem(rawExtn, templ, nssObj);
322 if(prtn) {
323 /*
324 * FIXME - what do we do here? For now flag it
325 * as an non-understood extension...
326 */
327 clErrorLog("decodeExtensions: extension decode error\n");
328 nssObj = NULL;
329 berEncoded = true;
330 }
331 }
332 if((nssObj != NULL) || berEncoded) {
333 /* append if the decode was successful */
334 addExtension(nssExten->extnId,
335 clNssBoolToCssm(nssExten->critical),
336 nssObj,
337 berEncoded,
338 templ,
339 &rawExtn);
340 }
341 }
342 }
343
344 /*
345 * Encode into a NSS-style Extensions.
346 *
347 * Each extension object, currently stored as some AsnType subclass,
348 * is BER-encoded and the result is stored as an octet string
349 * (AsnOcts) in a new Extension object in the TBS.
350 *
351 * Called from {Crl,Cert}CreateTemplate via encode{Tbs,Cts}().
352 */
353 void DecodedExtensions::encodeToNss(
354 NSS_CertExtension **&extensions)
355 {
356 assert(extensions == NULL);
357
358 if(mNumExtensions == 0) {
359 /* no extensions, no error */
360 return;
361 }
362
363 /* malloc a NULL_terminated array of NSS_CertExtension pointers */
364 unsigned len = (mNumExtensions + 1) * sizeof(NSS_CertExtension *);
365 extensions = (NSS_CertExtension **)mCoder.malloc(len);
366 memset(extensions, 0, len);
367
368 /* grind thru our DecodedExtens, creating an NSS_CertExtension for
369 * each one */
370 for(unsigned extenDex=0; extenDex<mNumExtensions; extenDex++) {
371 NSS_CertExtension *thisNssExten =
372 (NSS_CertExtension *)mCoder.malloc(sizeof(NSS_CertExtension));
373 memset(thisNssExten, 0, sizeof(NSS_CertExtension));
374 extensions[extenDex] = thisNssExten;
375
376 const DecodedExten *decodedExt = getExtension(extenDex);
377
378 /* BER-encode the extension object if appropriate */
379 if(decodedExt->berEncoded()) {
380 /* unknown extension type, it's already encoded */
381 const CSSM_DATA *srcBer = (const CSSM_DATA *)decodedExt->rawExtn();
382 assert(srcBer != NULL);
383 mCoder.allocCopyItem(*srcBer, thisNssExten->value);
384 }
385 else {
386 PRErrorCode prtn;
387 prtn = mCoder.encodeItem(decodedExt->nssObj(),
388 decodedExt->templ(), thisNssExten->value);
389 if(prtn) {
390 clErrorLog("encodeToNss: extension encode error");
391 CssmError::throwMe(CSSMERR_CL_INTERNAL_ERROR);
392 }
393 }
394 ArenaAllocator arenaAlloc(mCoder);
395 if(decodedExt->critical()) {
396 /* optional, default false */
397 clCssmBoolToNss(CSSM_TRUE, thisNssExten->critical, arenaAlloc);
398 }
399 mCoder.allocCopyItem(decodedExt->extnId(), thisNssExten->extnId);
400 }
401 }
402
403 /* add/retrieve entries */
404 void DecodedExtensions::addExtension(
405 const CSSM_OID &extnId, // copied
406 bool critical,
407 void *nssObj, // NSS_KeyUsage, NSS_BasicConstraints,
408 // etc. NOT COPIED, exists in same
409 // memory space as coder
410 bool berEncoded, // indicates unknown extension which we
411 // do not BER-decode when parsing a cert
412 const SEC_ASN1Template *templ, // required if !berEncoded
413 const CSSM_DATA *rawExtn) // NSS_CertExtension.value, copied,
414 // optional (not present during a
415 // SetField op)
416 {
417 if(mNumExtensions == mSizeofExtensions) {
418 /* expand by doubling, or initial malloc */
419 mSizeofExtensions = mNumExtensions ?
420 (2 * mNumExtensions) : MIN_EXTENSIONS;
421 mExtensions = (DecodedExten **)mAlloc.realloc(
422 mExtensions, mSizeofExtensions * sizeof(DecodedExten));
423 }
424 mExtensions[mNumExtensions++] = new DecodedExten(extnId,
425 critical, nssObj, berEncoded, templ, mCoder, rawExtn);
426 }
427
428 const DecodedExten *DecodedExtensions::getExtension(
429 unsigned extenDex) const
430 {
431 assert(extenDex < mNumExtensions);
432 return mExtensions[extenDex];
433 }
434
435 /* Convert to CSSM_X509_EXTENSIONS */
436 /* Currently only used when decoding a CRL and converting it en masse
437 * to CDSA */
438 void DecodedExtensions::convertToCdsa(
439 CSSM_X509_EXTENSIONS &cssmExtens,
440 CssmAllocator &alloc) const
441 {
442 memset(&cssmExtens, 0, sizeof(cssmExtens));
443 if(mNumExtensions == NULL) {
444 return;
445 }
446 cssmExtens.extensions = (CSSM_X509_EXTENSION_PTR)alloc.malloc(
447 sizeof(CSSM_X509_EXTENSION) * mNumExtensions);
448 memset(cssmExtens.extensions, 0,
449 sizeof(CSSM_X509_EXTENSION) * mNumExtensions);
450 cssmExtens.numberOfExtensions = mNumExtensions;
451 for(unsigned dex=0; dex<mNumExtensions; dex++) {
452 try {
453 getExtension(dex)->parse(&cssmExtens.extensions[dex], alloc);
454 }
455 catch(...) {
456 /* FIXME - what now? */
457 clFieldLog("DecodedExtensions:convertToCdsa: extension "
458 "decode error");
459 }
460 }
461 }
462