]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_apple_x509_cl/lib/DecodedExtensions.cpp
Security-58286.1.32.tar.gz
[apple/security.git] / OSX / libsecurity_apple_x509_cl / lib / DecodedExtensions.cpp
1 /*
2 * Copyright (c) 2002,2011-2012,2014 Apple 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
38 DecodedExten::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
64 DecodedExten::~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 */
76 CSSM_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 */
139 void 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 */
185 template<class NssType, class CdsaType>
186 void 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
198 void 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 */
326 DecodedExtensions::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
338 DecodedExtensions::~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 */
361 void 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 */
434 void 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 */
485 void 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
509 const 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 */
519 void 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