2 * Copyright (c) 2000-2001 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 * CLCertExtensions.cpp - extensions support. A major component of DecodedCert.
22 * Created 9/8/2000 by Doug Mitchell.
23 * Copyright (c) 2000 by Apple Computer.
27 #include "DecodedCert.h"
28 #include "cldebugging.h"
29 #include "CertBuilder.h"
30 #include "CLCertExtensions.h"
31 #include "SnaccUtils.h"
32 #include <Security/utilities.h>
33 #include <Security/oidscert.h>
34 #include <Security/cssmerr.h>
35 #include <Security/x509defs.h>
36 #include <Security/certextensions.h>
37 #include <Security/cdsaUtils.h>
38 #include <Security/sm_x509ce.h>
39 #include <Security/globalizer.h>
41 static AsnType
*oidToSnaccObj(
42 const AsnOid
&extnId
);
44 #define MIN_EXTENSIONS 4 // initial size of *mExtensions
47 * AsnOid "constants" which we construct and cache on demand to avoid the
48 * somewhat expensive op of constructing them every time we test for equality
55 mId_ce_keyUsage(id_ce_keyUsage_arc
),
56 mId_ce_basicConstraints(id_ce_basicConstraints_arc
),
57 mId_ce_extKeyUsage(id_ce_extKeyUsage_arc
),
58 mId_ce_subjectKeyIdentifier(id_ce_subjectKeyIdentifier_arc
),
59 mId_ce_authorityKeyIdentifier(id_ce_authorityKeyIdentifier_arc
),
60 mId_ce_subjectAltName(id_ce_subjectAltName_arc
),
61 mId_ce_certificatePolicies(id_ce_certificatePolicies_arc
),
62 mId_netscape_cert_type(id_netscape_cert_type_arc
)
65 AsnOid mId_ce_keyUsage
;
66 AsnOid mId_ce_basicConstraints
;
67 AsnOid mId_ce_extKeyUsage
;
68 AsnOid mId_ce_subjectKeyIdentifier
;
69 AsnOid mId_ce_authorityKeyIdentifier
;
70 AsnOid mId_ce_subjectAltName
;
71 AsnOid mId_ce_certificatePolicies
;
72 AsnOid mId_netscape_cert_type
;
75 static ModuleNexus
<ExtOidCache
> extOidCache
;
78 * Decode tbs->Extensions into mExtensions. This involves figuring out
79 * what kind of object is represented in the octet string in the
80 * extension, decoding it, and placing the resulting AsnType in a
81 * new DecodedExten struct.
83 * Called when decoding either a cert (for caching it or getting its fields)
84 * or a template (only via CertGetAllTemplateFields()).
86 void DecodedCert::decodeExtensions()
88 CASSERT(certificateToSign
!= NULL
);
89 Extensions
*extensions
= certificateToSign
->extensions
;
90 if(extensions
== NULL
) {
91 /* OK, no extensions present */
95 Extension
*snaccExten
= extensions
->First();
96 extensions
->SetCurrToFirst();
98 /* traverse extension list */
99 while(snaccExten
!= 0) {
101 * For this extension->extnId, cook up an approppriate
102 * AsnType (KeyUsage, etc.);
104 AsnOid
&extnId
= snaccExten
->extnId
;
105 bool berEncoded
= false;
106 AsnType
*snaccObj
= oidToSnaccObj(extnId
);
107 if(snaccObj
== NULL
) {
109 * We don't know how to deal with this, just take the
110 * raw bytes, copied from snaccExte.
112 snaccObj
= new AsnOcts(snaccExten
->extnValue
);
117 * We have a snacc-style object specific to this extension.
118 * Decode the extensions's extnValue into that object. We don't
119 * have to know what kind of object it is anymore.
121 CssmData
cData(snaccExten
->extnValue
, snaccExten
->extnValue
.Len());
123 SC_decodeAsnObj(cData
, *snaccObj
);
127 * FIXME - what do we do here? Is it safe to just ignore this
128 * extension, or is the whole cert invalid?
130 errorLog0("decodeExtensions: extension decode error\n");
135 if(snaccObj
!= NULL
) {
136 /* add to mExtensions if the decode was successful */
137 bool critical
= false; // default
138 if(snaccExten
->critical
!= NULL
) {
139 critical
= *snaccExten
->critical
;
141 addExtension(snaccObj
,
146 extensions
->GoNext();
147 snaccExten
= extensions
->Curr();
152 * Encode mExtensions into tbs->Extensions.
154 * Each extension object, currently stored as some AsnType subclass,
155 * is BER-encoded and the reesult is stored as an octet string
156 * (AsnOcts) in a new Extension object in the TBS.
158 * Only called from CertCreateTemplate via encodeTbs().
160 #define MAX_EXTEN_SIZE (4 * 1024) /* SWAG for max encoded size */
162 void DecodedCert::encodeExtensions()
164 CertificateToSign
*tbs
= certificateToSign
;
165 CASSERT(mState
== CS_Building
);
166 CASSERT((tbs
!= NULL
) && (tbs
->extensions
== NULL
));
168 if(mNumExtensions
== 0) {
169 /* no extensions, no error */
172 tbs
->extensions
= new Extensions
;
173 Extensions
*extns
= tbs
->extensions
;
175 /* for each of our DecodedExtens, append an Extension object to
178 for(extenDex
=0; extenDex
<mNumExtensions
; extenDex
++) {
179 Extension
*snaccExt
= extns
->Append();
180 DecodedExten
*decodedExt
= &mExtensions
[extenDex
];
182 /* BER-encode the extension object if appropriate */
183 if(decodedExt
->berEncoded
) {
184 /* unknown extension type, it's already encoded */
185 /* A failure of this dynamic cast is a fata internal error */
186 AsnOcts
*rawOcts
= dynamic_cast<AsnOcts
*>(decodedExt
->snaccObj
);
187 if(rawOcts
== NULL
) {
188 errorLog0("encodeExtensions: dynamic_cast failure!\n");
189 CssmError::throwMe(CSSMERR_CL_INTERNAL_ERROR
);
191 snaccExt
->extnValue
.Set(*rawOcts
);
194 CssmAutoData
aData(alloc
);
196 SC_encodeAsnObj(*decodedExt
->snaccObj
, aData
, MAX_EXTEN_SIZE
);
199 errorLog0("encodeExtensions: extension encode error\n");
202 CssmData
&cData
= aData
.get();
203 snaccExt
->extnValue
.Set((char *)cData
.data(), cData
.length());
205 snaccExt
->critical
= new AsnBool(decodedExt
->critical
);
206 snaccExt
->extnId
.Set(*decodedExt
->extnId
);
212 * Add a new DecodedExten to mExtensions.
213 * Called from decodeExtensions and setField*.
214 * At this point, the actual extenmsion data is represented by some subclass
215 * of AsnType - either a specific extension type (e.g. KeyUsage), or as an
216 * octet string (AsnOcts) for extension types we don't understand (and which
217 * are encoded by the app).
219 void DecodedCert::addExtension(
220 AsnType
*snaccObj
, // e.g. KeyUsage
221 const AsnOid
&extnId
,
223 bool berEncoded
) // i.e., we don't know how to parse
225 /* cook up a new DecodedExten, reallocing mExtensions is necessary */
226 if(mNumExtensions
== mSizeofExtensions
) {
227 /* expand by doubling, or initial malloc */
228 mSizeofExtensions
= mNumExtensions
?
229 (2 * mNumExtensions
) : MIN_EXTENSIONS
;
230 mExtensions
= (DecodedExten
*)alloc
.realloc(
231 mExtensions
, mSizeofExtensions
* sizeof(DecodedExten
));
233 DecodedExten
*decodedExt
= &mExtensions
[mNumExtensions
++];
234 decodedExt
->extnId
= new AsnOid(extnId
);
235 decodedExt
->critical
= critical
;
236 decodedExt
->snaccObj
= snaccObj
;
237 decodedExt
->berEncoded
= berEncoded
;
241 * Search for DecodedExten by AsnOid or "any unknown extension".
242 * Called from getField*() and inferKeyUsage.
243 * Returns NULL if specified extension not found.
245 DecodedExten
*DecodedCert::findDecodedExt(
246 const AsnOid
&extnId
, // for known extensions
247 bool unknown
, // otherwise
249 uint32
&numFields
) const
252 DecodedExten
*decodedExt
;
253 DecodedExten
*rtnExt
= NULL
;
256 for(dex
=0; dex
<mNumExtensions
; dex
++) {
257 CASSERT(mExtensions
!= NULL
);
258 decodedExt
= &mExtensions
[dex
];
260 * known extensions: OID match
261 * unknown extensions: just know that we didn't decode it
263 if( (!unknown
&& (*decodedExt
->extnId
== extnId
)) ||
264 (unknown
&& decodedExt
->berEncoded
)) {
266 if(found
++ == index
) {
267 /* the one we want */
270 if((rtnExt
!= NULL
) && (index
!= 0)) {
271 /* only determine numFields on search for first one */
277 /* sucessful return */
289 * Common code to pass info from a DecodedExten back to app.
290 * Called from getField*().
292 static void getFieldExtenCommon(
293 void *cdsaObj
, // e.g. CE_KeyUsage
294 // CSSM_DATA_PTR for berEncoded
295 const DecodedExten
&decodedExt
,
296 CssmOwnedData
&fieldValue
)
298 CSSM_X509_EXTENSION_PTR cssmExt
;
299 CssmAllocator
&alloc
= fieldValue
.allocator
;
300 CssmData
&fdata
= fieldValue
.get();
302 cssmExt
= (CSSM_X509_EXTENSION_PTR
)alloc
.malloc(sizeof(CSSM_X509_EXTENSION
));
303 fdata
.Data
= (uint8
*)cssmExt
;
304 fdata
.Length
= sizeof(CSSM_X509_EXTENSION
);
305 CL_snaccOidToCssm(*decodedExt
.extnId
,
306 CssmOid::overlay(cssmExt
->extnId
),
308 if(decodedExt
.critical
!= NULL
) {
309 cssmExt
->critical
= decodedExt
.critical
? CSSM_TRUE
: CSSM_FALSE
;
313 cssmExt
->critical
= false;
315 if(decodedExt
.berEncoded
) {
316 /* an extension we never parsed or understood */
317 cssmExt
->format
= CSSM_X509_DATAFORMAT_ENCODED
;
318 cssmExt
->value
.parsedValue
= NULL
;
319 cssmExt
->BERvalue
= *(reinterpret_cast<CSSM_DATA_PTR
>(cdsaObj
));
322 cssmExt
->format
= CSSM_X509_DATAFORMAT_PARSED
;
323 cssmExt
->value
.parsedValue
= cdsaObj
;
324 cssmExt
->BERvalue
.Data
= NULL
;
325 cssmExt
->BERvalue
.Length
= 0;
330 * Common code for top of setField* and freeField*().
332 static CSSM_X509_EXTENSION_PTR
verifySetFreeExtension(
333 const CssmData
&fieldValue
,
334 bool berEncoded
) // false: value in value.parsedValue
335 // true : value in BERValue
337 if(fieldValue
.length() != sizeof(CSSM_X509_EXTENSION
)) {
338 errorLog2("Set/FreeExtension: bad length : exp %d got %d\n",
339 (int)sizeof(CSSM_X509_EXTENSION
), (int)fieldValue
.length());
340 CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER
);
342 CSSM_X509_EXTENSION_PTR cssmExt
=
343 reinterpret_cast<CSSM_X509_EXTENSION_PTR
>(fieldValue
.data());
345 if((cssmExt
->value
.parsedValue
!= NULL
) || (cssmExt
->BERvalue
.Data
== NULL
)) {
346 CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER
);
350 if((cssmExt
->value
.parsedValue
== NULL
) || (cssmExt
->BERvalue
.Data
!= NULL
)) {
351 CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER
);
358 * Common free code for all extensions. Extension-specific code must
359 * free anything beyond cdsaExt->Value.parsedValue, then we free everything
360 * else (except the extension struct itself, which is freed by
361 * DecodedCert::freeCertFieldData()).
363 static void freeFieldExtenCommon(
364 CSSM_X509_EXTENSION_PTR exten
,
365 CssmAllocator
&alloc
)
367 alloc
.free(exten
->extnId
.Data
);
368 alloc
.free(exten
->BERvalue
.Data
); // may be NULL
369 alloc
.free(exten
->value
.parsedValue
); // may be NULL
374 * Cook up an AsnType associated with specified extnId
375 * When adding oid/type pairs here, also add to:
376 * -- fieldFuncs[] in CertFields.cpp
377 * -- and the get/set/free functions in this file.
379 static AsnType
*oidToSnaccObj(
380 const AsnOid
&extnId
)
382 ExtOidCache
&oc
= extOidCache();
384 if(extnId
== oc
.mId_ce_keyUsage
) {
387 else if(extnId
== oc
.mId_ce_basicConstraints
) {
388 return new BasicConstraintsSyntax
;
390 else if(extnId
== oc
.mId_ce_extKeyUsage
) {
391 return new ExtKeyUsageSyntax
;
393 else if(extnId
== oc
.mId_ce_subjectKeyIdentifier
) {
396 else if(extnId
== oc
.mId_ce_authorityKeyIdentifier
) {
397 return new AuthorityKeyIdentifier
;
399 else if(extnId
== oc
.mId_ce_subjectAltName
) {
400 return new GeneralNames
;
402 else if(extnId
== oc
.mId_ce_certificatePolicies
) {
403 return new CertificatePoliciesSyntax
;
405 else if(extnId
== oc
.mId_netscape_cert_type
) {
413 /* common code for top of getField* */
414 template<class SnaccType
, class CdsaType
>
416 const DecodedCert
&cert
,
417 unsigned index
, // which occurrence (0 = first)
418 uint32
&numFields
, // RETURNED
419 CssmAllocator
&alloc
,
420 const AsnOid
&fieldId
,
421 SnaccType
*&snaccObj
,
423 DecodedExten
*&decodedExt
)
425 /* See if we have one of these in our list of DecodedExtens */
426 decodedExt
= cert
.findDecodedExt(fieldId
, false, index
, numFields
);
427 if(decodedExt
== NULL
) {
431 /* failure of this dynamic_cast is fatal */
432 snaccObj
= dynamic_cast<SnaccType
*>(decodedExt
->snaccObj
);
433 if(snaccObj
== NULL
) {
434 errorLog0("GetFieldTop: dynamic_cast failure\n");
435 CssmError::throwMe(CSSMERR_CL_INTERNAL_ERROR
);
437 cdsaObj
= (CdsaType
*)alloc
.malloc(sizeof(CdsaType
));
438 memset(cdsaObj
, 0, sizeof(CdsaType
));
443 *** get/set/free functions called out from CertFields.cpp
447 * One common free for extensions whose parsed value doesn't go any deeper
448 * than cssmExt->value.parsedValue.
450 void freeFieldSimpleExtension (
451 CssmOwnedData
&fieldValue
)
453 CSSM_X509_EXTENSION_PTR cssmExt
= verifySetFreeExtension(fieldValue
, false);
454 freeFieldExtenCommon(cssmExt
, fieldValue
.allocator
);
459 *** CDSA format CE_KeyUsage
460 *** SNACC format KeyUsage
461 *** OID CSSMOID_KeyUsage
464 void setFieldKeyUsage(
466 const CssmData
&fieldValue
)
468 CSSM_X509_EXTENSION_PTR cssmExt
= verifySetFreeExtension(fieldValue
, false);
469 CE_KeyUsage
*cdsaObj
= (CE_KeyUsage
*)cssmExt
->value
.parsedValue
;
471 /* brute-force cdsaObj --> snaccObj */
472 char bits
[sizeof(CE_KeyUsage
)];
473 bits
[0] = static_cast<char>((*cdsaObj
) >> 8);
474 bits
[1] = static_cast<char>(*cdsaObj
);
475 memmove(bits
, cdsaObj
, sizeof(CE_KeyUsage
));
476 KeyUsage
*snaccObj
= new KeyUsage(bits
, sizeof(CE_KeyUsage
) * 8);
478 /* add to mExtensions */
479 cert
.addExtension(snaccObj
, cssmExt
->extnId
, cssmExt
->critical
, false);
483 bool getFieldKeyUsage(
484 const DecodedCert
&cert
,
485 unsigned index
, // which occurrence (0 = first)
486 uint32
&numFields
, // RETURNED
487 CssmOwnedData
&fieldValue
)
489 DecodedExten
*decodedExt
;
491 CE_KeyUsage
*cdsaObj
;
494 brtn
= GetFieldTop
<KeyUsage
, CE_KeyUsage
>(
498 fieldValue
.allocator
,
507 unsigned toCopy
= (snaccObj
->BitLen() + 7) / 8;
509 /* I hope I never see this... */
510 errorLog0("getFieldKeyUsage: KeyUsage larger than 2 bytes!\n");
513 unsigned char bits
[2] = {0, 0};
514 memmove(bits
, snaccObj
->BitOcts(), toCopy
);
515 *cdsaObj
= (((unsigned)bits
[0]) << 8) | bits
[1];
517 /* pass back to caller */
518 getFieldExtenCommon(cdsaObj
, *decodedExt
, fieldValue
);
523 *** Basic Constraints
524 *** CDSA format: CE_BasicConstraints
525 *** SNACC format BasicConstraintsSyntax
526 *** OID CSSMOID_BasicConstraints
529 void setFieldBasicConstraints(
531 const CssmData
&fieldValue
)
533 CSSM_X509_EXTENSION_PTR cssmExt
= verifySetFreeExtension(fieldValue
, false);
534 BasicConstraintsSyntax
*snaccObj
= new BasicConstraintsSyntax
;
535 CE_BasicConstraints
*cdsaObj
= (CE_BasicConstraints
*)cssmExt
->value
.parsedValue
;
537 /* brute-force cdsaObj --> snaccObj */
538 snaccObj
->cA
= new AsnBool(cdsaObj
->cA
? true : false);
539 if(cdsaObj
->pathLenConstraintPresent
) {
540 AsnIntType val
= cdsaObj
->pathLenConstraint
;
541 snaccObj
->pathLenConstraint
= new AsnInt(val
);
544 /* add to mExtensions */
545 cert
.addExtension(snaccObj
, cssmExt
->extnId
, cssmExt
->critical
, false);
549 bool getFieldBasicConstraints(
550 const DecodedCert
&cert
,
551 unsigned index
, // which occurrence (0 = first)
552 uint32
&numFields
, // RETURNED
553 CssmOwnedData
&fieldValue
)
555 DecodedExten
*decodedExt
;
556 BasicConstraintsSyntax
*snaccObj
;
557 CE_BasicConstraints
*cdsaObj
;
560 brtn
= GetFieldTop
<BasicConstraintsSyntax
, CE_BasicConstraints
>(
564 fieldValue
.allocator
,
565 id_ce_basicConstraints
,
573 if(snaccObj
->cA
== NULL
) {
575 cdsaObj
->cA
= CSSM_FALSE
;
578 bool val
= *snaccObj
->cA
;
579 cdsaObj
->cA
= val
? CSSM_TRUE
: CSSM_FALSE
;
581 if(snaccObj
->pathLenConstraint
== NULL
) {
582 cdsaObj
->pathLenConstraintPresent
= CSSM_FALSE
;
583 cdsaObj
->pathLenConstraint
= 0;
586 cdsaObj
->pathLenConstraintPresent
= CSSM_TRUE
;
587 AsnIntType val
= *snaccObj
->pathLenConstraint
;
588 cdsaObj
->pathLenConstraint
= val
;
591 /* pass back to caller */
592 getFieldExtenCommon(cdsaObj
, *decodedExt
, fieldValue
);
597 *** Extended Key Usage
598 *** CDSA format: CE_ExtendedKeyUsage
599 *** SNACC format ExtKeyUsageSyntax
600 *** OID CSSMOID_ExtendedKeyUsage
602 void setFieldExtKeyUsage(
604 const CssmData
&fieldValue
)
606 CSSM_X509_EXTENSION_PTR cssmExt
= verifySetFreeExtension(fieldValue
, false);
607 ExtKeyUsageSyntax
*snaccObj
= new ExtKeyUsageSyntax
;
608 CE_ExtendedKeyUsage
*cdsaObj
= (CE_ExtendedKeyUsage
*)cssmExt
->value
.parsedValue
;
610 /* brute-force cdsaObj --> snaccObj, one 'purpose' (OID) at a time */
612 for(oidDex
=0; oidDex
<cdsaObj
->numPurposes
; oidDex
++) {
613 KeyPurposeId
*snaccPurp
= snaccObj
->Append();
614 CSSM_OID_PTR cdsaPurp
= &cdsaObj
->purposes
[oidDex
];
615 snaccPurp
->Set(reinterpret_cast<char *>(cdsaPurp
->Data
), cdsaPurp
->Length
);
618 /* add to mExtensions */
619 cert
.addExtension(snaccObj
, cssmExt
->extnId
, cssmExt
->critical
, false);
622 bool getFieldExtKeyUsage(
623 const DecodedCert
&cert
,
624 unsigned index
, // which occurrence (0 = first)
625 uint32
&numFields
, // RETURNED
626 CssmOwnedData
&fieldValue
)
628 DecodedExten
*decodedExt
;
629 ExtKeyUsageSyntax
*snaccObj
;
630 CE_ExtendedKeyUsage
*cdsaObj
;
633 brtn
= GetFieldTop
<ExtKeyUsageSyntax
, CE_ExtendedKeyUsage
>(
637 fieldValue
.allocator
,
646 /* brute force snaccObj --> cdsaObj, one purpose at a time */
647 CssmAllocator
&alloc
= fieldValue
.allocator
;
648 cdsaObj
->numPurposes
= snaccObj
->Count();
649 cdsaObj
->purposes
= (CSSM_OID_PTR
)alloc
.malloc(cdsaObj
->numPurposes
*
651 snaccObj
->SetCurrToFirst();
653 for(oidDex
=0; oidDex
<cdsaObj
->numPurposes
; oidDex
++) {
654 CL_snaccOidToCssm(*snaccObj
->Curr(),
655 CssmOid::overlay(cdsaObj
->purposes
[oidDex
]),
659 getFieldExtenCommon(cdsaObj
, *decodedExt
, fieldValue
);
663 void freeFieldExtKeyUsage(
664 CssmOwnedData
&fieldValue
)
666 CSSM_X509_EXTENSION_PTR cssmExt
= verifySetFreeExtension(fieldValue
, false);
667 CssmAllocator
&alloc
= fieldValue
.allocator
;
668 CE_ExtendedKeyUsage
*cdsaObj
=
669 (CE_ExtendedKeyUsage
*)cssmExt
->value
.parsedValue
;
671 for(oidDex
=0; oidDex
<cdsaObj
->numPurposes
; oidDex
++) {
672 alloc
.free(cdsaObj
->purposes
[oidDex
].Data
);
674 alloc
.free(cdsaObj
->purposes
);
675 freeFieldExtenCommon(cssmExt
, alloc
); // frees extnId, parsedValue, BERvalue
679 *** Subject Key Identifier
680 *** CDSA format: CE_SubjectKeyID, which is just a CSSM_DATA
681 *** SNACC format AsnOcts
682 *** OID CSSMOID_SubjectKeyIdentifier
685 void setFieldSubjectKeyId(
687 const CssmData
&fieldValue
)
689 CSSM_X509_EXTENSION_PTR cssmExt
= verifySetFreeExtension(fieldValue
, false);
690 CE_SubjectKeyID
*cdsaObj
= (CE_SubjectKeyID
*)cssmExt
->value
.parsedValue
;
691 AsnOcts
*snaccObj
= new AsnOcts((char *)cdsaObj
->Data
, cdsaObj
->Length
);
692 cert
.addExtension(snaccObj
, cssmExt
->extnId
, cssmExt
->critical
, false);
695 bool getFieldSubjectKeyId(
696 const DecodedCert
&cert
,
697 unsigned index
, // which occurrence (0 = first)
698 uint32
&numFields
, // RETURNED
699 CssmOwnedData
&fieldValue
)
701 DecodedExten
*decodedExt
;
703 CE_SubjectKeyID
*cdsaObj
;
706 brtn
= GetFieldTop
<AsnOcts
, CE_SubjectKeyID
>(
710 fieldValue
.allocator
,
711 id_ce_subjectKeyIdentifier
,
718 CL_AsnOctsToCssmData(*snaccObj
, *cdsaObj
, fieldValue
.allocator
);
719 getFieldExtenCommon(cdsaObj
, *decodedExt
, fieldValue
);
723 void freeFieldSubjectKeyId (
724 CssmOwnedData
&fieldValue
)
726 CSSM_X509_EXTENSION_PTR cssmExt
= verifySetFreeExtension(fieldValue
, false);
727 CssmAllocator
&alloc
= fieldValue
.allocator
;
728 CE_SubjectKeyID
*cdsaObj
= (CE_SubjectKeyID
*)cssmExt
->value
.parsedValue
;
729 alloc
.free(cdsaObj
->Data
);
730 freeFieldExtenCommon(cssmExt
, alloc
); // frees extnId, parsedValue, BERvalue
734 *** Authority Key Identifier
735 *** CDSA format: CE_AuthorityKeyID
736 *** SNACC format AuthorityKeyIdentifier
737 *** OID CSSMOID_AuthorityKeyIdentifier
740 void setFieldAuthorityKeyId(
742 const CssmData
&fieldValue
)
744 CSSM_X509_EXTENSION_PTR cssmExt
= verifySetFreeExtension(fieldValue
, false);
745 CE_AuthorityKeyID
*cdsaObj
= (CE_AuthorityKeyID
*)cssmExt
->value
.parsedValue
;
746 AuthorityKeyIdentifier
*snaccObj
= new AuthorityKeyIdentifier
;
749 * brute-force a CDSA-style CE_AuthorityKeyID into snacc-style
750 * AuthorityKeyIdentifier
752 if(cdsaObj
->keyIdentifierPresent
) {
753 /* Just an AsnOcts */
754 snaccObj
->keyIdentifier
= new AsnOcts((char *)cdsaObj
->keyIdentifier
.Data
,
755 cdsaObj
->keyIdentifier
.Length
);
757 if(cdsaObj
->generalNamesPresent
) {
758 /* GeneralNames, the hard one */
759 snaccObj
->authorityCertIssuer
= CL_cdsaGeneralNamesToSnacc(
760 *cdsaObj
->generalNames
);
762 if(cdsaObj
->serialNumberPresent
) {
763 /* boils down to BigIntegerStr, or AsnOcts */
764 snaccObj
->authorityCertSerialNumber
=
765 new CertificateSerialNumber((char *)cdsaObj
->serialNumber
.Data
,
766 cdsaObj
->serialNumber
.Length
);
769 cert
.addExtension(snaccObj
, cssmExt
->extnId
, cssmExt
->critical
, false);
772 bool getFieldAuthorityKeyId(
773 const DecodedCert
&cert
,
774 unsigned index
, // which occurrence (0 = first)
775 uint32
&numFields
, // RETURNED
776 CssmOwnedData
&fieldValue
)
778 DecodedExten
*decodedExt
;
779 AuthorityKeyIdentifier
*snaccObj
;
780 CE_AuthorityKeyID
*cdsaObj
;
782 CssmAllocator
&alloc
= fieldValue
.allocator
;
784 brtn
= GetFieldTop
<AuthorityKeyIdentifier
, CE_AuthorityKeyID
>(
789 id_ce_authorityKeyIdentifier
,
797 /* brute-force a snacc-style AuthorityKeyIdentifier into CDSA format */
798 if(snaccObj
->keyIdentifier
!= NULL
) {
799 /* Just an AsnOcts */
800 cdsaObj
->keyIdentifierPresent
= CSSM_TRUE
;
801 CL_AsnOctsToCssmData(*snaccObj
->keyIdentifier
,
802 cdsaObj
->keyIdentifier
,
805 if(snaccObj
->authorityCertIssuer
!= NULL
) {
806 /* GeneralNames, the hard one */
807 cdsaObj
->generalNamesPresent
= CSSM_TRUE
;
808 cdsaObj
->generalNames
= (CE_GeneralNames
*)alloc
.malloc(sizeof(CE_GeneralNames
));
809 CL_snaccGeneralNamesToCdsa(*snaccObj
->authorityCertIssuer
,
810 *cdsaObj
->generalNames
,
813 if(snaccObj
->authorityCertSerialNumber
!= NULL
) {
814 /* boils down to BigIntegerStr, or AsnOcts */
815 cdsaObj
->serialNumberPresent
= CSSM_TRUE
;
816 CL_AsnOctsToCssmData(*snaccObj
->authorityCertSerialNumber
,
817 cdsaObj
->serialNumber
,
820 getFieldExtenCommon(cdsaObj
, *decodedExt
, fieldValue
);
824 static void freeFieldGeneralNames(
825 CE_GeneralNames
*cdsaObj
,
826 CssmAllocator
&alloc
)
828 if(cdsaObj
== NULL
) {
831 for(unsigned i
=0; i
<cdsaObj
->numNames
; i
++) {
832 alloc
.free(cdsaObj
->generalName
[i
].name
.Data
);
834 if(cdsaObj
->numNames
) {
835 memset(cdsaObj
->generalName
, 0, cdsaObj
->numNames
* sizeof(CE_GeneralName
));
836 alloc
.free(cdsaObj
->generalName
);
838 memset(cdsaObj
, 0, sizeof(CE_GeneralNames
));
841 void freeFieldAuthorityKeyId (
842 CssmOwnedData
&fieldValue
)
844 CSSM_X509_EXTENSION_PTR cssmExt
= verifySetFreeExtension(fieldValue
, false);
845 CssmAllocator
&alloc
= fieldValue
.allocator
;
846 CE_AuthorityKeyID
*cdsaObj
= (CE_AuthorityKeyID
*)cssmExt
->value
.parsedValue
;
847 alloc
.free(cdsaObj
->keyIdentifier
.Data
);
848 freeFieldGeneralNames(cdsaObj
->generalNames
, alloc
);
849 alloc
.free(cdsaObj
->generalNames
);
850 alloc
.free(cdsaObj
->serialNumber
.Data
);
851 memset(cdsaObj
, 0, sizeof(CE_AuthorityKeyID
));
852 freeFieldExtenCommon(cssmExt
, alloc
); // frees extnId, parsedValue, BERvalue
856 *** Subject alternate name
857 *** CDSA Format: CE_GeneralNames
858 *** SNACC format: GeneralNames
859 *** OID: CSSMOID_SubjectAltName
861 void setFieldSubjAltName(
863 const CssmData
&fieldValue
)
865 CSSM_X509_EXTENSION_PTR cssmExt
= verifySetFreeExtension(fieldValue
, false);
866 CE_GeneralNames
*cdsaObj
= (CE_GeneralNames
*)cssmExt
->value
.parsedValue
;
867 GeneralNames
*snaccObj
= CL_cdsaGeneralNamesToSnacc(*cdsaObj
);
868 cert
.addExtension(snaccObj
, cssmExt
->extnId
, cssmExt
->critical
, false);
871 bool getFieldSubjAltName(
872 const DecodedCert
&cert
,
873 unsigned index
, // which occurrence (0 = first)
874 uint32
&numFields
, // RETURNED
875 CssmOwnedData
&fieldValue
)
877 DecodedExten
*decodedExt
;
878 GeneralNames
*snaccObj
;
879 CE_GeneralNames
*cdsaObj
;
882 brtn
= GetFieldTop
<GeneralNames
, CE_GeneralNames
>(
886 fieldValue
.allocator
,
887 id_ce_subjectAltName
,
894 CL_snaccGeneralNamesToCdsa(*snaccObj
, *cdsaObj
, fieldValue
.allocator
);
895 getFieldExtenCommon(cdsaObj
, *decodedExt
, fieldValue
);
899 void freeFieldSubjAltName (
900 CssmOwnedData
&fieldValue
)
902 CSSM_X509_EXTENSION_PTR cssmExt
= verifySetFreeExtension(fieldValue
, false);
903 CssmAllocator
&alloc
= fieldValue
.allocator
;
904 CE_GeneralNames
*cdsaObj
= (CE_GeneralNames
*)cssmExt
->value
.parsedValue
;
905 freeFieldGeneralNames(cdsaObj
, alloc
);
906 freeFieldExtenCommon(cssmExt
, alloc
); // frees extnId, parsedValue, BERvalue
910 *** Certificate Policies
911 *** CDSA Format: CE_CertPolicies
912 *** SNACC format: CertificatePoliciesSyntax
913 *** OID: CSSMOID_CertificatePolicies
916 #define MAX_IA5_NAME_SIZE 1024
918 void setFieldCertPolicies(
920 const CssmData
&fieldValue
)
922 CssmAllocator
&alloc
= CssmAllocator::standard();
923 CSSM_X509_EXTENSION_PTR cssmExt
= verifySetFreeExtension(fieldValue
, false);
924 CertificatePoliciesSyntax
*snaccObj
= new CertificatePoliciesSyntax
;
925 CE_CertPolicies
*cdsaObj
= (CE_CertPolicies
*)cssmExt
->value
.parsedValue
;
927 /* brute-force cdsaObj --> snaccObj */
928 for(unsigned polDex
=0; polDex
<cdsaObj
->numPolicies
; polDex
++) {
929 CE_PolicyInformation
*cPolInfo
= &cdsaObj
->policies
[polDex
];
930 PolicyInformation
*sPolInfo
= snaccObj
->Append();
931 sPolInfo
->policyIdentifier
.Set((char *)cPolInfo
->certPolicyId
.Data
,
932 cPolInfo
->certPolicyId
.Length
);
933 if(cPolInfo
->numPolicyQualifiers
!= 0) {
934 sPolInfo
->policyQualifiers
= new PolicyInformationSeqOf
;
936 for(unsigned qualDex
=0; qualDex
<cPolInfo
->numPolicyQualifiers
; qualDex
++) {
937 CE_PolicyQualifierInfo
*cQualInfo
= &cPolInfo
->policyQualifiers
[qualDex
];
938 PolicyQualifierInfo
*sQualInfo
= sPolInfo
->policyQualifiers
->Append();
940 /* OK we're at the lowest level.
941 * policyQualifierId == id_qt_cps: qualifier is an IA5 string,
942 * incoming data is its contents. Else incoming data is an encoded
943 * blob we pass on directly.
945 sQualInfo
->policyQualifierId
.Set(
946 (char *)cQualInfo
->policyQualifierId
.Data
,
947 cQualInfo
->policyQualifierId
.Length
);
949 /* we'll convert this incoming ptr/len.... */
950 uint8
*rawData
= cQualInfo
->qualifier
.Data
;
951 unsigned rawDataLen
= cQualInfo
->qualifier
.Length
;
952 /* to this, somehow; it'll be used to build the required AsnAny. */
953 CssmAutoData
aData(alloc
);
955 if(sQualInfo
->policyQualifierId
== id_qt_cps
) {
956 /* build & encode an IA5String */
957 IA5String
*ia5
= new IA5String((char *)rawData
, rawDataLen
);
958 SC_encodeAsnObj(*ia5
, aData
, MAX_IA5_NAME_SIZE
);
962 /* copy over directly */
963 aData
.copy(rawData
, rawDataLen
);
966 /* install the result into CSM_Buffer, which mallocs & copies */
967 sQualInfo
->qualifier
= new AsnAny
;
969 sQualInfo
->qualifier
->value
= new CSM_Buffer(cp
, aData
.length());
971 } /* for each qualifier */
972 } /* for each policy */
974 /* add to mExtensions */
975 cert
.addExtension(snaccObj
, cssmExt
->extnId
, cssmExt
->critical
, false);
978 bool getFieldCertPolicies(
979 const DecodedCert
&cert
,
980 unsigned index
, // which occurrence (0 = first)
981 uint32
&numFields
, // RETURNED
982 CssmOwnedData
&fieldValue
)
984 DecodedExten
*decodedExt
;
985 CertificatePoliciesSyntax
*snaccObj
;
986 CE_CertPolicies
*cdsaObj
;
988 CssmAllocator
&alloc
= fieldValue
.allocator
;
989 brtn
= GetFieldTop
<CertificatePoliciesSyntax
, CE_CertPolicies
>(
993 fieldValue
.allocator
,
994 id_ce_certificatePolicies
,
1002 /* brute force CertificatePoliciesSyntax --> CE_CertPolicies */
1003 cdsaObj
->numPolicies
= snaccObj
->Count();
1004 unsigned sz
= cdsaObj
->numPolicies
* sizeof(CE_PolicyInformation
);
1005 cdsaObj
->policies
= (CE_PolicyInformation
*)alloc
.malloc(sz
);
1006 memset(cdsaObj
->policies
, 0, sz
);
1007 snaccObj
->SetCurrToFirst();
1008 for(unsigned polDex
=0; polDex
<cdsaObj
->numPolicies
; polDex
++) {
1009 CE_PolicyInformation
*cPolInfo
= &cdsaObj
->policies
[polDex
];
1010 PolicyInformation
*sPolInfo
= snaccObj
->Curr();
1011 CssmOid
&cOid
= CssmOid::overlay(cPolInfo
->certPolicyId
);
1012 CL_snaccOidToCssm(sPolInfo
->policyIdentifier
, cOid
, alloc
);
1013 if(sPolInfo
->policyQualifiers
== NULL
) {
1016 cPolInfo
->numPolicyQualifiers
= sPolInfo
->policyQualifiers
->Count();
1017 cPolInfo
->policyQualifiers
= (CE_PolicyQualifierInfo
*)
1018 alloc
.malloc(cPolInfo
->numPolicyQualifiers
*
1019 sizeof(CE_PolicyQualifierInfo
));
1020 sPolInfo
->policyQualifiers
->SetCurrToFirst();
1021 for(unsigned qualDex
=0; qualDex
<cPolInfo
->numPolicyQualifiers
; qualDex
++) {
1022 PolicyQualifierInfo
*sQualInfo
= sPolInfo
->policyQualifiers
->Curr();
1023 CE_PolicyQualifierInfo
*cQualInfo
= &cPolInfo
->policyQualifiers
[qualDex
];
1027 * policyQualifierId == id_qt_cps : IA5String - decode and return
1028 * contents. Else return whole thing.
1030 CssmOid
&cOid2
= CssmOid::overlay(cQualInfo
->policyQualifierId
);
1031 CL_snaccOidToCssm(sQualInfo
->policyQualifierId
, cOid2
, alloc
);
1033 CSM_Buffer
*cbuf
= sQualInfo
->qualifier
->value
;
1035 CssmRemoteData
outData(alloc
, cQualInfo
->qualifier
);
1036 if(sQualInfo
->policyQualifierId
== id_qt_cps
) {
1038 CssmAutoData
berData(alloc
, cbuf
->Access(), cbuf
->Length());
1039 /* error is fatal, punt the whole kit'n'kaboodle and leak */
1040 SC_decodeAsnObj(berData
, ia5
);
1042 outData
.copy(src
, ia5
.Len());
1045 outData
.copy(cbuf
->Access(), cbuf
->Length());
1048 sPolInfo
->policyQualifiers
->GoNext();
1052 getFieldExtenCommon(cdsaObj
, *decodedExt
, fieldValue
);
1056 void freeFieldCertPolicies (
1057 CssmOwnedData
&fieldValue
)
1059 CSSM_X509_EXTENSION_PTR cssmExt
= verifySetFreeExtension(fieldValue
, false);
1060 CssmAllocator
&alloc
= fieldValue
.allocator
;
1061 CE_CertPolicies
*cdsaObj
= (CE_CertPolicies
*)cssmExt
->value
.parsedValue
;
1062 for(unsigned polDex
=0; polDex
<cdsaObj
->numPolicies
; polDex
++) {
1063 CE_PolicyInformation
*cPolInfo
= &cdsaObj
->policies
[polDex
];
1064 alloc
.free(cPolInfo
->certPolicyId
.Data
);
1065 for(unsigned qualDex
=0; qualDex
<cPolInfo
->numPolicyQualifiers
; qualDex
++) {
1066 CE_PolicyQualifierInfo
*cQualInfo
= &cPolInfo
->policyQualifiers
[qualDex
];
1067 alloc
.free(cQualInfo
->policyQualifierId
.Data
);
1068 alloc
.free(cQualInfo
->qualifier
.Data
);
1070 alloc
.free(cPolInfo
->policyQualifiers
);
1072 alloc
.free(cdsaObj
->policies
);
1073 freeFieldExtenCommon(cssmExt
, alloc
); // frees extnId, parsedValue, BERvalue
1077 *** Netscape cert type
1078 *** CDSA Format: CE_NetscapeCertType (a uint16)
1079 *** SNACC format: AsnBits
1080 *** OID: CSSMOID_NetscapeCertType
1082 void setFieldNetscapeCertType(
1084 const CssmData
&fieldValue
)
1086 CSSM_X509_EXTENSION_PTR cssmExt
= verifySetFreeExtension(fieldValue
, false);
1087 CE_NetscapeCertType
*cdsaObj
= (CE_NetscapeCertType
*)cssmExt
->value
.parsedValue
;
1089 char bits
[sizeof(CE_NetscapeCertType
)];
1090 bits
[0] = static_cast<char>((*cdsaObj
) >> 8);
1091 bits
[1] = static_cast<char>(*cdsaObj
);
1092 memmove(bits
, cdsaObj
, sizeof(CE_NetscapeCertType
));
1093 AsnBits
*snaccObj
= new AsnBits(bits
, sizeof(CE_NetscapeCertType
) * 8);
1095 /* add to mExtensions */
1096 cert
.addExtension(snaccObj
, cssmExt
->extnId
, cssmExt
->critical
, false);
1099 bool getFieldNetscapeCertType(
1100 const DecodedCert
&cert
,
1101 unsigned index
, // which occurrence (0 = first)
1102 uint32
&numFields
, // RETURNED
1103 CssmOwnedData
&fieldValue
)
1105 DecodedExten
*decodedExt
;
1107 CE_NetscapeCertType
*cdsaObj
;
1110 brtn
= GetFieldTop
<AsnBits
, CE_NetscapeCertType
>(
1114 fieldValue
.allocator
,
1115 id_netscape_cert_type
,
1123 unsigned toCopy
= (snaccObj
->BitLen() + 7) / 8;
1125 /* I hope I never see this... */
1126 errorLog0("getFieldNetscapeCertType: bitstring larger than 2 bytes!\n");
1129 unsigned char bits
[2] = {0, 0};
1130 memmove(bits
, snaccObj
->BitOcts(), toCopy
);
1131 *cdsaObj
= (((unsigned)bits
[0]) << 8) | bits
[1];
1132 getFieldExtenCommon(cdsaObj
, *decodedExt
, fieldValue
);
1137 *** unknown extensions
1138 *** CDSA format: raw bytes in a CSSM_DATA. This data is the BER-encoding of
1139 *** some extension struct we don't know about.
1140 *** SNACC format AsnOcts
1141 *** OID CSSMOID_X509V3CertificateExtensionCStruct
1144 void setFieldUnknownExt(
1146 const CssmData
&fieldValue
)
1148 CSSM_X509_EXTENSION_PTR cssmExt
= verifySetFreeExtension(fieldValue
, true);
1149 AsnOcts
*snaccObj
= new AsnOcts(
1150 reinterpret_cast<char *>(cssmExt
->BERvalue
.Data
),
1151 cssmExt
->BERvalue
.Length
);
1152 cert
.addExtension(snaccObj
, cssmExt
->extnId
, cssmExt
->critical
, true);
1155 bool getFieldUnknownExt(
1156 const DecodedCert
&cert
,
1157 unsigned index
, // which occurrence (0 = first)
1158 uint32
&numFields
, // RETURNED
1159 CssmOwnedData
&fieldValue
)
1161 AsnOid
noOidLikeThis (1, 2); // a dummy argument
1162 DecodedExten
*decodedExt
= cert
.findDecodedExt(noOidLikeThis
,
1163 true, index
, numFields
);
1164 if(decodedExt
== NULL
) {
1167 /* failure of this dynamic_cast is fatal */
1168 AsnOcts
*snaccObj
= dynamic_cast<AsnOcts
*>(decodedExt
->snaccObj
);
1169 if(snaccObj
== NULL
) {
1170 errorLog0("getFieldUnknownExt: dynamic_cast failure\n");
1171 CssmError::throwMe(CSSMERR_CL_INTERNAL_ERROR
);
1173 char *octData
= *snaccObj
;
1174 CssmAutoData
encodedBytes(fieldValue
.allocator
, octData
, snaccObj
->Len());
1175 /* easier way to do this...? */
1176 CssmData cData
= encodedBytes
.release();
1177 getFieldExtenCommon(&cData
, *decodedExt
, fieldValue
);
1181 void freeFieldUnknownExt (
1182 CssmOwnedData
&fieldValue
)
1184 CSSM_X509_EXTENSION_PTR cssmExt
= verifySetFreeExtension(fieldValue
, true);
1185 CssmAllocator
&alloc
= fieldValue
.allocator
;
1186 freeFieldExtenCommon(cssmExt
, alloc
); // frees extnId, parsedValue, BERvalue
1194 *** Subject alternate name
1195 *** CDSA Format: CE_GeneralNames
1196 *** SNACC format: GeneralNames
1197 *** OID: CSSMOID_SubjectAltName
1199 void setFieldSomeExt(
1201 const CssmData
&fieldValue
)
1203 CSSM_X509_EXTENSION_PTR cssmExt
= verifySetFreeExtension(fieldValue
, false);
1204 new an approppriate AsnType
snaccObj (KeyUsage
, etc
.);
1205 extension
-specific e
.g
. CE_KeyUsage
*cdsaObj
= cssmExt
->value
.parsedValue
;
1206 /* brute-force cdsaObj --> snaccObj */
1208 /* add to mExtensions */
1209 cert
.addExtension(snaccObj
, cssmExt
->extnId
, cssmExt
->critical
, false);
1212 bool getFieldSomeExt(
1213 const DecodedCert
&cert
,
1214 unsigned index
, // which occurrence (0 = first)
1215 uint32
&numFields
, // RETURNED
1216 CssmOwnedData
&fieldValue
)
1218 DecodedExten
*decodedExt
;
1219 e
.g
. ExtKeyUsageSyntax
*snaccObj
;
1220 e
.g
. CE_ExtendedKeyUsage
*cdsaObj
;
1223 brtn
= GetFieldTop
<ExtKeyUsageSyntax
, CE_ExtendedKeyUsage
>(
1227 fieldValue
.allocator
,
1228 e
.g
. id_ce_extKeyUsage
,
1236 brute force snaccObj
--> cdsaObj
;
1237 getFieldExtenCommon(cdsaObj
, *decodedExt
, fieldValue
);
1241 /* only used if complex structs below cssmExt->value.parsedValue */
1242 void freeFieldSomeExt (
1243 CssmOwnedData
&fieldValue
)
1245 CSSM_X509_EXTENSION_PTR cssmExt
= verifySetFreeExtension(fieldValue
, false);
1246 CssmAllocator
&alloc
= fieldValue
.allocator
;
1247 free the stuff in cssmExt
->value
.parsedValue
;
1248 freeFieldExtenCommon(cssmExt
, alloc
); // frees extnId, parsedValue, BERvalue