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 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
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 * 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.).
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
80 clAllocCopyData(alloc
, mExtnId
, cssmExt
->extnId
);
81 cssmExt
->critical
= mCritical
? CSSM_TRUE
: CSSM_FALSE
;
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).
88 clAllocCopyData(alloc
, *mRawExtn
, cssmExt
->BERvalue
);
91 cssmExt
->BERvalue
.Data
= NULL
;
92 cssmExt
->BERvalue
.Length
= 0;
95 /* an extension we never parsed or understood */
96 assert(cdsaObj
== NULL
);
97 cssmExt
->format
= CSSM_X509_DATAFORMAT_ENCODED
;
98 cssmExt
->value
.parsedValue
= NULL
;
101 /* caller sees parsed version plus raw BER-encoded bytes */
102 assert(cdsaObj
!= NULL
);
104 /* normal decode & parse case */
105 cssmExt
->format
= CSSM_X509_DATAFORMAT_PAIR
;
109 cssmExt
->format
= CSSM_X509_DATAFORMAT_PARSED
;
111 /* in app alloc's space, mallocd by getField*() */
112 cssmExt
->value
.parsedValue
= cdsaObj
;
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.
124 * Currently only used when decoding a CRL and converting it en masse
127 template<class NssType
, class CdsaType
>
129 const DecodedExten
&decodedExt
,
130 NssType
*&nssObj
, // RETURNED
131 CdsaType
*&cdsaObj
, // mallocd and RETURNED
132 CssmAllocator
&alloc
)
134 nssObj
= (NssType
*)(decodedExt
.nssObj());
135 assert(nssObj
!= NULL
);
136 cdsaObj
= (CdsaType
*)alloc
.malloc(sizeof(CdsaType
));
137 memset(cdsaObj
, 0, sizeof(CdsaType
));
140 void DecodedExten::parse(
141 CSSM_X509_EXTENSION_PTR cssmExt
, // mallocd by caller, RETURNED
142 CssmAllocator
&alloc
) const
144 void *vCdsaObj
= NULL
;
146 /* non-understood extension */
147 convertToCdsa(NULL
, cssmExt
, alloc
);
150 if(clCompareCssmData(&mExtnId
, &CSSMOID_AuthorityKeyIdentifier
)) {
151 CE_AuthorityKeyID
*cdsaObj
;
152 NSS_AuthorityKeyId
*nssObj
;
153 nssToCssm
<NSS_AuthorityKeyId
, CE_AuthorityKeyID
>(
158 CL_nssAuthorityKeyIdToCssm(*nssObj
, *cdsaObj
, mCoder
, alloc
);
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
;
167 nssToCssm
<CSSM_DATA
, CE_CrlNumber
>(
172 *cdsaObj
= clDataToInt(*nssObj
);
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
>(
186 CL_nssGeneralNamesToCssm(*nssObj
, *cdsaObj
, mCoder
, alloc
);
189 else if(clCompareCssmData(&mExtnId
, &CSSMOID_IssuingDistributionPoint
)) {
190 CE_IssuingDistributionPoint
*cdsaObj
;
191 NSS_IssuingDistributionPoint
*nssObj
;
192 nssToCssm
<NSS_IssuingDistributionPoint
, CE_IssuingDistributionPoint
>(
197 CL_nssIssuingDistPointToCssm(nssObj
, cdsaObj
, mCoder
, alloc
);
202 * cert entry extensions
204 else if(clCompareCssmData(&mExtnId
, &CSSMOID_HoldInstructionCode
)) {
205 /* value is just an OID */
208 nssToCssm
<CSSM_DATA
, CSSM_OID
>(
213 clAllocCopyData(alloc
, *nssObj
, *cdsaObj
);
216 else if(clCompareCssmData(&mExtnId
, &CSSMOID_InvalidityDate
)) {
217 /* GeneralizedTime */
220 nssToCssm
<CSSM_DATA
, CSSM_DATA
>(
225 clAllocCopyData(alloc
, *nssObj
, *cdsaObj
);
229 /* if we get here, this routine is not keeping up with
230 * clOidToNssInfo() */
232 CssmError::throwMe(CSSMERR_CL_INTERNAL_ERROR
);
234 convertToCdsa(vCdsaObj
, cssmExt
, alloc
);
238 #pragma mark ------ DecodedExtensions ------
241 * A variable-size array of DecodedExtens.
242 * Used for storing cert and CRL extensions as well as per-CRL-entry
245 DecodedExtensions::DecodedExtensions(
247 CssmAllocator
&alloc
)
257 DecodedExtensions::~DecodedExtensions()
259 for(unsigned i
=0; i
<mNumExtensions
; i
++) {
260 assert(mExtensions
[i
] != NULL
);
261 delete mExtensions
[i
];
263 mAlloc
.free(mExtensions
);
266 mSizeofExtensions
= 0;
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.
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()).
280 void DecodedExtensions::decodeFromNss(
281 NSS_CertExtension
**extensions
)
283 if(extensions
== NULL
) {
284 /* OK, no extensions present */
287 unsigned numExtens
= clNssArraySize((const void **)extensions
);
289 /* traverse extension list */
290 for(unsigned dex
=0; dex
<numExtens
; dex
++) {
291 NSS_CertExtension
*nssExten
= extensions
[dex
];
294 * For this extension->extnId, cook up an approppriate
295 * NSS-specific type (NSS_KeyUsage, etc.);
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
);
306 * We don't know how to deal with this.
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.
317 assert(templ
!= NULL
);
318 nssObj
= mCoder
.malloc(nssObjLen
);
319 memset(nssObj
, 0, nssObjLen
);
321 prtn
= mCoder
.decodeItem(rawExtn
, templ
, nssObj
);
324 * FIXME - what do we do here? For now flag it
325 * as an non-understood extension...
327 clErrorLog("decodeExtensions: extension decode error\n");
332 if((nssObj
!= NULL
) || berEncoded
) {
333 /* append if the decode was successful */
334 addExtension(nssExten
->extnId
,
335 clNssBoolToCssm(nssExten
->critical
),
345 * Encode into a NSS-style Extensions.
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.
351 * Called from {Crl,Cert}CreateTemplate via encode{Tbs,Cts}().
353 void DecodedExtensions::encodeToNss(
354 NSS_CertExtension
**&extensions
)
356 assert(extensions
== NULL
);
358 if(mNumExtensions
== 0) {
359 /* no extensions, no error */
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
);
368 /* grind thru our DecodedExtens, creating an NSS_CertExtension for
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
;
376 const DecodedExten
*decodedExt
= getExtension(extenDex
);
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
);
387 prtn
= mCoder
.encodeItem(decodedExt
->nssObj(),
388 decodedExt
->templ(), thisNssExten
->value
);
390 clErrorLog("encodeToNss: extension encode error");
391 CssmError::throwMe(CSSMERR_CL_INTERNAL_ERROR
);
394 ArenaAllocator
arenaAlloc(mCoder
);
395 if(decodedExt
->critical()) {
396 /* optional, default false */
397 clCssmBoolToNss(CSSM_TRUE
, thisNssExten
->critical
, arenaAlloc
);
399 mCoder
.allocCopyItem(decodedExt
->extnId(), thisNssExten
->extnId
);
403 /* add/retrieve entries */
404 void DecodedExtensions::addExtension(
405 const CSSM_OID
&extnId
, // copied
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
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
));
424 mExtensions
[mNumExtensions
++] = new DecodedExten(extnId
,
425 critical
, nssObj
, berEncoded
, templ
, mCoder
, rawExtn
);
428 const DecodedExten
*DecodedExtensions::getExtension(
429 unsigned extenDex
) const
431 assert(extenDex
< mNumExtensions
);
432 return mExtensions
[extenDex
];
435 /* Convert to CSSM_X509_EXTENSIONS */
436 /* Currently only used when decoding a CRL and converting it en masse
438 void DecodedExtensions::convertToCdsa(
439 CSSM_X509_EXTENSIONS
&cssmExtens
,
440 CssmAllocator
&alloc
) const
442 memset(&cssmExtens
, 0, sizeof(cssmExtens
));
443 if(mNumExtensions
== NULL
) {
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
++) {
453 getExtension(dex
)->parse(&cssmExtens
.extensions
[dex
], alloc
);
456 /* FIXME - what now? */
457 clFieldLog("DecodedExtensions:convertToCdsa: extension "