2 * Copyright (c) 2002 Apple Computer, 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/cssmapple.h>
33 #include <Security/oidscert.h>
35 #define MIN_EXTENSIONS 4 // initial size of *mExtensions
37 DecodedExten::DecodedExten(
38 const CSSM_OID
&extnId
, // copied
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
49 : mCritical(critical
),
51 mBerEncoded(berEncoded
),
56 coder
.allocCopyItem(extnId
, mExtnId
);
58 mRawExtn
= (CSSM_DATA
*)coder
.malloc(sizeof(CSSM_DATA
));
59 coder
.allocCopyItem(*rawExtn
, *mRawExtn
);
63 DecodedExten::~DecodedExten()
65 /* the only stuff we allocated was in the coder pool and will be freed
66 * when coder is freed */
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.
75 CSSM_X509EXT_TAGandVALUE
*DecodedExten::createTagAndValue(
76 const CSSM_DATA
&berValue
,
77 Allocator
&alloc
) const
79 if((berValue
.Data
== NULL
) || (berValue
.Length
== 0)) {
82 CSSM_X509EXT_TAGandVALUE
*tv
= (CSSM_X509EXT_TAGandVALUE
*)
83 alloc
.malloc(sizeof(CSSM_X509EXT_TAGandVALUE
));
84 tv
->type
= berValue
.Data
[0];
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!
90 const uint8
*lp
= berValue
.Data
+ 1;
92 if((len1
& 0x80) == 0) {
94 tv
->value
.Length
= len1
;
95 tv
->value
.Data
= const_cast<uint8
*>(lp
+ 1);
99 unsigned numLenBytes
= len1
& 0x7f;
100 if(numLenBytes
> 4) {
101 clErrorLog("createTagAndValue: impossible length of length (%u)\n", numLenBytes
);
103 CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT
);
107 lp
++; // points to first length byte
108 for(uint32 dex
=0; dex
<numLenBytes
; dex
++) {
113 tv
->value
.Length
= len
;
114 tv
->value
.Data
= const_cast<uint8
*>(lp
);
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.).
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
129 clAllocCopyData(alloc
, mExtnId
, cssmExt
->extnId
);
130 cssmExt
->critical
= mCritical
? CSSM_TRUE
: CSSM_FALSE
;
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).
137 clAllocCopyData(alloc
, *mRawExtn
, cssmExt
->BERvalue
);
140 cssmExt
->BERvalue
.Data
= NULL
;
141 cssmExt
->BERvalue
.Length
= 0;
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
);
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
;
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.
166 * Currently only used when decoding a CRL and converting it en masse
169 template<class NssType
, class CdsaType
>
171 const DecodedExten
&decodedExt
,
172 NssType
*&nssObj
, // RETURNED
173 CdsaType
*&cdsaObj
, // mallocd and RETURNED
176 nssObj
= (NssType
*)(decodedExt
.nssObj());
177 assert(nssObj
!= NULL
);
178 cdsaObj
= (CdsaType
*)alloc
.malloc(sizeof(CdsaType
));
179 memset(cdsaObj
, 0, sizeof(CdsaType
));
182 void DecodedExten::parse(
183 CSSM_X509_EXTENSION_PTR cssmExt
, // mallocd by caller, RETURNED
184 Allocator
&alloc
) const
186 void *vCdsaObj
= NULL
;
188 /* non-understood extension */
189 convertToCdsa(NULL
, cssmExt
, alloc
);
192 if(clCompareCssmData(&mExtnId
, &CSSMOID_AuthorityKeyIdentifier
)) {
193 CE_AuthorityKeyID
*cdsaObj
;
194 NSS_AuthorityKeyId
*nssObj
;
195 nssToCssm
<NSS_AuthorityKeyId
, CE_AuthorityKeyID
>(
200 CL_nssAuthorityKeyIdToCssm(*nssObj
, *cdsaObj
, mCoder
, alloc
);
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
;
209 nssToCssm
<CSSM_DATA
, CE_CrlNumber
>(
215 if(clCompareCssmData(&mExtnId
, &CSSMOID_CrlReason
)) {
216 toThrow
= CSSMERR_CL_INVALID_CRL_POINTER
;
219 /* tolerate crlNumber > 4 bytes */
222 *cdsaObj
= clDataToInt(*nssObj
, toThrow
);
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
>(
236 CL_nssGeneralNamesToCssm(*nssObj
, *cdsaObj
, mCoder
, alloc
);
239 else if(clCompareCssmData(&mExtnId
, &CSSMOID_IssuingDistributionPoint
)) {
240 CE_IssuingDistributionPoint
*cdsaObj
;
241 NSS_IssuingDistributionPoint
*nssObj
;
242 nssToCssm
<NSS_IssuingDistributionPoint
, CE_IssuingDistributionPoint
>(
247 CL_nssIssuingDistPointToCssm(nssObj
, cdsaObj
, mCoder
, alloc
);
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.
255 else if(clCompareCssmData(&mExtnId
, &CSSMOID_CrlDistributionPoints
)) {
256 CE_CRLDistPointsSyntax
*cdsaObj
;
257 NSS_CRLDistributionPoints
*nssObj
;
258 nssToCssm
<NSS_CRLDistributionPoints
, CE_CRLDistPointsSyntax
>(
263 CL_nssDistPointsToCssm((const NSS_CRLDistributionPoints
&)*nssObj
, *cdsaObj
, mCoder
, alloc
);
267 * cert entry extensions
269 else if(clCompareCssmData(&mExtnId
, &CSSMOID_HoldInstructionCode
)) {
270 /* value is just an OID */
273 nssToCssm
<CSSM_DATA
, CSSM_OID
>(
278 clAllocCopyData(alloc
, *nssObj
, *cdsaObj
);
281 else if(clCompareCssmData(&mExtnId
, &CSSMOID_InvalidityDate
)) {
282 /* GeneralizedTime */
285 nssToCssm
<CSSM_DATA
, CSSM_DATA
>(
290 clAllocCopyData(alloc
, *nssObj
, *cdsaObj
);
294 /* if we get here, this routine is not keeping up with
295 * clOidToNssInfo() */
297 CssmError::throwMe(CSSMERR_CL_INTERNAL_ERROR
);
299 convertToCdsa(vCdsaObj
, cssmExt
, alloc
);
303 #pragma mark ------ DecodedExtensions ------
306 * A variable-size array of DecodedExtens.
307 * Used for storing cert and CRL extensions as well as per-CRL-entry
310 DecodedExtensions::DecodedExtensions(
322 DecodedExtensions::~DecodedExtensions()
324 for(unsigned i
=0; i
<mNumExtensions
; i
++) {
325 assert(mExtensions
[i
] != NULL
);
326 delete mExtensions
[i
];
328 mAlloc
.free(mExtensions
);
331 mSizeofExtensions
= 0;
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.
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()).
345 void DecodedExtensions::decodeFromNss(
346 NSS_CertExtension
**extensions
)
348 if(extensions
== NULL
) {
349 /* OK, no extensions present */
352 unsigned numExtens
= clNssArraySize((const void **)extensions
);
354 /* traverse extension list */
355 for(unsigned dex
=0; dex
<numExtens
; dex
++) {
356 NSS_CertExtension
*nssExten
= extensions
[dex
];
359 * For this extension->extnId, cook up an appropriate
360 * NSS-specific type (NSS_KeyUsage, etc.);
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
);
371 * We don't know how to deal with this.
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.
382 assert(templ
!= NULL
);
383 nssObj
= mCoder
.malloc(nssObjLen
);
384 memset(nssObj
, 0, nssObjLen
);
386 prtn
= mCoder
.decodeItem(rawExtn
, templ
, nssObj
);
389 * FIXME - what do we do here? For now flag it
390 * as an non-understood extension...
392 clErrorLog("decodeExtensions: extension decode error\n");
397 if((nssObj
!= NULL
) || berEncoded
) {
398 /* append if the decode was successful */
399 addExtension(nssExten
->extnId
,
400 clNssBoolToCssm(nssExten
->critical
),
410 * Encode into a NSS-style Extensions.
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.
416 * Called from {Crl,Cert}CreateTemplate via encode{Tbs,Cts}().
418 void DecodedExtensions::encodeToNss(
419 NSS_CertExtension
**&extensions
)
421 assert(extensions
== NULL
);
423 if(mNumExtensions
== 0) {
424 /* no extensions, no error */
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
);
433 /* grind thru our DecodedExtens, creating an NSS_CertExtension for
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
;
441 const DecodedExten
*decodedExt
= getExtension(extenDex
);
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
);
452 prtn
= mCoder
.encodeItem(decodedExt
->nssObj(),
453 decodedExt
->templ(), thisNssExten
->value
);
455 clErrorLog("encodeToNss: extension encode error");
456 CssmError::throwMe(CSSMERR_CL_INTERNAL_ERROR
);
459 ArenaAllocator
arenaAlloc(mCoder
);
460 if(decodedExt
->critical()) {
461 /* optional, default false */
462 clCssmBoolToNss(CSSM_TRUE
, thisNssExten
->critical
, arenaAlloc
);
464 mCoder
.allocCopyItem(decodedExt
->extnId(), thisNssExten
->extnId
);
468 /* add/retrieve entries */
469 void DecodedExtensions::addExtension(
470 const CSSM_OID
&extnId
, // copied
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
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
));
489 mExtensions
[mNumExtensions
++] = new DecodedExten(extnId
,
490 critical
, nssObj
, berEncoded
, templ
, mCoder
, rawExtn
);
493 const DecodedExten
*DecodedExtensions::getExtension(
494 unsigned extenDex
) const
496 assert(extenDex
< mNumExtensions
);
497 return mExtensions
[extenDex
];
500 /* Convert to CSSM_X509_EXTENSIONS */
501 /* Currently only used when decoding a CRL and converting it en masse
503 void DecodedExtensions::convertToCdsa(
504 CSSM_X509_EXTENSIONS
&cssmExtens
,
505 Allocator
&alloc
) const
507 memset(&cssmExtens
, 0, sizeof(cssmExtens
));
508 if(mNumExtensions
== 0) {
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
++) {
518 getExtension(dex
)->parse(&cssmExtens
.extensions
[dex
], alloc
);
521 /* FIXME - what now? */
522 clFieldLog("DecodedExtensions:convertToCdsa: extension "