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