2 * Copyright (c) 2002,2011-2012,2014 Apple Inc. All Rights Reserved.
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
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.
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).
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>
36 #define MIN_EXTENSIONS 4 // initial size of *mExtensions
38 DecodedExten::DecodedExten(
39 const CSSM_OID
&extnId
, // copied
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
50 : mCritical(critical
),
52 mBerEncoded(berEncoded
),
57 coder
.allocCopyItem(extnId
, mExtnId
);
59 mRawExtn
= (CSSM_DATA
*)coder
.malloc(sizeof(CSSM_DATA
));
60 coder
.allocCopyItem(*rawExtn
, *mRawExtn
);
64 DecodedExten::~DecodedExten()
66 /* the only stuff we allocated was in the coder pool and will be freed
67 * when coder is freed */
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.
76 CSSM_X509EXT_TAGandVALUE
*DecodedExten::createTagAndValue(
77 const CSSM_DATA
&berValue
,
78 Allocator
&alloc
) const
80 if((berValue
.Data
== NULL
) || (berValue
.Length
== 0)) {
83 CSSM_X509EXT_TAGandVALUE
*tv
= (CSSM_X509EXT_TAGandVALUE
*)
84 alloc
.malloc(sizeof(CSSM_X509EXT_TAGandVALUE
));
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.
93 tv
->type
= SEC_ASN1_OCTET_STRING
;
94 tv
->value
.Length
= berValue
.Length
;
95 tv
->value
.Data
= berValue
.Data
;
99 tv
->type
= berValue
.Data
[0];
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!
105 const uint8
*lp
= berValue
.Data
+ 1;
107 if((len1
& 0x80) == 0) {
109 tv
->value
.Length
= len1
;
110 tv
->value
.Data
= const_cast<uint8
*>(lp
+ 1);
114 unsigned numLenBytes
= len1
& 0x7f;
115 if(numLenBytes
> 4) {
116 clErrorLog("createTagAndValue: impossible length of length (%u)\n", numLenBytes
);
118 CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT
);
122 lp
++; // points to first length byte
123 for(uint32 dex
=0; dex
<numLenBytes
; dex
++) {
128 tv
->value
.Length
= len
;
129 tv
->value
.Data
= const_cast<uint8
*>(lp
);
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.).
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
145 clAllocCopyData(alloc
, mExtnId
, cssmExt
->extnId
);
146 cssmExt
->critical
= mCritical
? CSSM_TRUE
: CSSM_FALSE
;
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).
153 clAllocCopyData(alloc
, *mRawExtn
, cssmExt
->BERvalue
);
156 cssmExt
->BERvalue
.Data
= NULL
;
157 cssmExt
->BERvalue
.Length
= 0;
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
);
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
;
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.
182 * Currently only used when decoding a CRL and converting it en masse
185 template<class NssType
, class CdsaType
>
187 const DecodedExten
&decodedExt
,
188 NssType
*&nssObj
, // RETURNED
189 CdsaType
*&cdsaObj
, // mallocd and RETURNED
192 nssObj
= (NssType
*)(decodedExt
.nssObj());
193 assert(nssObj
!= NULL
);
194 cdsaObj
= (CdsaType
*)alloc
.malloc(sizeof(CdsaType
));
195 memset(cdsaObj
, 0, sizeof(CdsaType
));
198 void DecodedExten::parse(
199 CSSM_X509_EXTENSION_PTR cssmExt
, // mallocd by caller, RETURNED
200 Allocator
&alloc
) const
202 void *vCdsaObj
= NULL
;
204 /* non-understood extension */
205 convertToCdsa(NULL
, cssmExt
, alloc
);
208 if(clCompareCssmData(&mExtnId
, &CSSMOID_AuthorityKeyIdentifier
)) {
209 CE_AuthorityKeyID
*cdsaObj
;
210 NSS_AuthorityKeyId
*nssObj
;
211 nssToCssm
<NSS_AuthorityKeyId
, CE_AuthorityKeyID
>(
216 CL_nssAuthorityKeyIdToCssm(*nssObj
, *cdsaObj
, mCoder
, alloc
);
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
;
225 nssToCssm
<CSSM_DATA
, CE_CrlNumber
>(
231 if(clCompareCssmData(&mExtnId
, &CSSMOID_CrlReason
)) {
232 toThrow
= CSSMERR_CL_INVALID_CRL_POINTER
;
235 /* tolerate crlNumber > 4 bytes */
238 *cdsaObj
= clDataToInt(*nssObj
, toThrow
);
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
>(
252 CL_nssGeneralNamesToCssm(*nssObj
, *cdsaObj
, mCoder
, alloc
);
255 else if(clCompareCssmData(&mExtnId
, &CSSMOID_IssuingDistributionPoint
)) {
256 CE_IssuingDistributionPoint
*cdsaObj
;
257 NSS_IssuingDistributionPoint
*nssObj
;
258 nssToCssm
<NSS_IssuingDistributionPoint
, CE_IssuingDistributionPoint
>(
263 CL_nssIssuingDistPointToCssm(nssObj
, cdsaObj
, mCoder
, alloc
);
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.
271 else if(clCompareCssmData(&mExtnId
, &CSSMOID_CrlDistributionPoints
)) {
272 CE_CRLDistPointsSyntax
*cdsaObj
;
273 NSS_CRLDistributionPoints
*nssObj
;
274 nssToCssm
<NSS_CRLDistributionPoints
, CE_CRLDistPointsSyntax
>(
279 CL_nssDistPointsToCssm((const NSS_CRLDistributionPoints
&)*nssObj
, *cdsaObj
, mCoder
, alloc
);
283 * cert entry extensions
285 else if(clCompareCssmData(&mExtnId
, &CSSMOID_HoldInstructionCode
)) {
286 /* value is just an OID */
289 nssToCssm
<CSSM_DATA
, CSSM_OID
>(
294 clAllocCopyData(alloc
, *nssObj
, *cdsaObj
);
297 else if(clCompareCssmData(&mExtnId
, &CSSMOID_InvalidityDate
)) {
298 /* GeneralizedTime */
301 nssToCssm
<CSSM_DATA
, CSSM_DATA
>(
306 clAllocCopyData(alloc
, *nssObj
, *cdsaObj
);
310 /* if we get here, this routine is not keeping up with
311 * clOidToNssInfo() */
313 CssmError::throwMe(CSSMERR_CL_INTERNAL_ERROR
);
315 convertToCdsa(vCdsaObj
, cssmExt
, alloc
);
319 #pragma mark ------ DecodedExtensions ------
322 * A variable-size array of DecodedExtens.
323 * Used for storing cert and CRL extensions as well as per-CRL-entry
326 DecodedExtensions::DecodedExtensions(
338 DecodedExtensions::~DecodedExtensions()
340 for(unsigned i
=0; i
<mNumExtensions
; i
++) {
341 assert(mExtensions
[i
] != NULL
);
342 delete mExtensions
[i
];
344 mAlloc
.free(mExtensions
);
347 mSizeofExtensions
= 0;
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.
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()).
361 void DecodedExtensions::decodeFromNss(
362 NSS_CertExtension
**extensions
)
364 if(extensions
== NULL
) {
365 /* OK, no extensions present */
368 unsigned numExtens
= clNssArraySize((const void **)extensions
);
370 /* traverse extension list */
371 for(unsigned dex
=0; dex
<numExtens
; dex
++) {
372 NSS_CertExtension
*nssExten
= extensions
[dex
];
375 * For this extension->extnId, cook up an appropriate
376 * NSS-specific type (NSS_KeyUsage, etc.);
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
);
387 * We don't know how to deal with this.
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.
398 assert(templ
!= NULL
);
399 nssObj
= mCoder
.malloc(nssObjLen
);
400 memset(nssObj
, 0, nssObjLen
);
402 prtn
= mCoder
.decodeItem(rawExtn
, templ
, nssObj
);
405 * FIXME - what do we do here? For now flag it
406 * as an non-understood extension...
408 clErrorLog("decodeExtensions: extension decode error\n");
413 if((nssObj
!= NULL
) || berEncoded
) {
414 /* append if the decode was successful */
415 addExtension(nssExten
->extnId
,
416 clNssBoolToCssm(nssExten
->critical
),
426 * Encode into a NSS-style Extensions.
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.
432 * Called from {Crl,Cert}CreateTemplate via encode{Tbs,Cts}().
434 void DecodedExtensions::encodeToNss(
435 NSS_CertExtension
**&extensions
)
437 assert(extensions
== NULL
);
439 if(mNumExtensions
== 0) {
440 /* no extensions, no error */
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
);
449 /* grind thru our DecodedExtens, creating an NSS_CertExtension for
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
;
457 const DecodedExten
*decodedExt
= getExtension(extenDex
);
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
);
468 prtn
= mCoder
.encodeItem(decodedExt
->nssObj(),
469 decodedExt
->templ(), thisNssExten
->value
);
471 clErrorLog("encodeToNss: extension encode error");
472 CssmError::throwMe(CSSMERR_CL_INTERNAL_ERROR
);
475 ArenaAllocator
arenaAlloc(mCoder
);
476 if(decodedExt
->critical()) {
477 /* optional, default false */
478 clCssmBoolToNss(CSSM_TRUE
, thisNssExten
->critical
, arenaAlloc
);
480 mCoder
.allocCopyItem(decodedExt
->extnId(), thisNssExten
->extnId
);
484 /* add/retrieve entries */
485 void DecodedExtensions::addExtension(
486 const CSSM_OID
&extnId
, // copied
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
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
*));
505 mExtensions
[mNumExtensions
++] = new DecodedExten(extnId
,
506 critical
, nssObj
, berEncoded
, templ
, mCoder
, rawExtn
);
509 const DecodedExten
*DecodedExtensions::getExtension(
510 unsigned extenDex
) const
512 assert(extenDex
< mNumExtensions
);
513 return mExtensions
[extenDex
];
516 /* Convert to CSSM_X509_EXTENSIONS */
517 /* Currently only used when decoding a CRL and converting it en masse
519 void DecodedExtensions::convertToCdsa(
520 CSSM_X509_EXTENSIONS
&cssmExtens
,
521 Allocator
&alloc
) const
523 memset(&cssmExtens
, 0, sizeof(cssmExtens
));
524 if(mNumExtensions
== 0) {
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
++) {
534 getExtension(dex
)->parse(&cssmExtens
.extensions
[dex
], alloc
);
537 /* FIXME - what now? */
538 clFieldLog("DecodedExtensions:convertToCdsa: extension "