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_GeneralName
));
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
));
837 memset(cdsaObj
, 0, sizeof(CE_GeneralNames
));
840 void freeFieldAuthorityKeyId (
841 CssmOwnedData
&fieldValue
)
843 CSSM_X509_EXTENSION_PTR cssmExt
= verifySetFreeExtension(fieldValue
, false);
844 CssmAllocator
&alloc
= fieldValue
.allocator
;
845 CE_AuthorityKeyID
*cdsaObj
= (CE_AuthorityKeyID
*)cssmExt
->value
.parsedValue
;
846 alloc
.free(cdsaObj
->keyIdentifier
.Data
);
847 freeFieldGeneralNames(cdsaObj
->generalNames
, alloc
);
848 alloc
.free(cdsaObj
->serialNumber
.Data
);
849 memset(cdsaObj
, 0, sizeof(CE_AuthorityKeyID
));
850 freeFieldExtenCommon(cssmExt
, alloc
); // frees extnId, parsedValue, BERvalue
854 *** Subject alternate name
855 *** CDSA Format: CE_GeneralNames
856 *** SNACC format: GeneralNames
857 *** OID: CSSMOID_SubjectAltName
859 void setFieldSubjAltName(
861 const CssmData
&fieldValue
)
863 CSSM_X509_EXTENSION_PTR cssmExt
= verifySetFreeExtension(fieldValue
, false);
864 CE_GeneralNames
*cdsaObj
= (CE_GeneralNames
*)cssmExt
->value
.parsedValue
;
865 GeneralNames
*snaccObj
= CL_cdsaGeneralNamesToSnacc(*cdsaObj
);
866 cert
.addExtension(snaccObj
, cssmExt
->extnId
, cssmExt
->critical
, false);
869 bool getFieldSubjAltName(
870 const DecodedCert
&cert
,
871 unsigned index
, // which occurrence (0 = first)
872 uint32
&numFields
, // RETURNED
873 CssmOwnedData
&fieldValue
)
875 DecodedExten
*decodedExt
;
876 GeneralNames
*snaccObj
;
877 CE_GeneralNames
*cdsaObj
;
880 brtn
= GetFieldTop
<GeneralNames
, CE_GeneralNames
>(
884 fieldValue
.allocator
,
885 id_ce_subjectAltName
,
892 CL_snaccGeneralNamesToCdsa(*snaccObj
, *cdsaObj
, fieldValue
.allocator
);
893 getFieldExtenCommon(cdsaObj
, *decodedExt
, fieldValue
);
897 void freeFieldSubjAltName (
898 CssmOwnedData
&fieldValue
)
900 CSSM_X509_EXTENSION_PTR cssmExt
= verifySetFreeExtension(fieldValue
, false);
901 CssmAllocator
&alloc
= fieldValue
.allocator
;
902 CE_GeneralNames
*cdsaObj
= (CE_GeneralNames
*)cssmExt
->value
.parsedValue
;
903 freeFieldGeneralNames(cdsaObj
, alloc
);
904 freeFieldExtenCommon(cssmExt
, alloc
); // frees extnId, parsedValue, BERvalue
908 *** Certificate Policies
909 *** CDSA Format: CE_CertPolicies
910 *** SNACC format: CertificatePoliciesSyntax
911 *** OID: CSSMOID_CertificatePolicies
914 #define MAX_IA5_NAME_SIZE 1024
916 void setFieldCertPolicies(
918 const CssmData
&fieldValue
)
920 CssmAllocator
&alloc
= CssmAllocator::standard();
921 CSSM_X509_EXTENSION_PTR cssmExt
= verifySetFreeExtension(fieldValue
, false);
922 CertificatePoliciesSyntax
*snaccObj
= new CertificatePoliciesSyntax
;
923 CE_CertPolicies
*cdsaObj
= (CE_CertPolicies
*)cssmExt
->value
.parsedValue
;
925 /* brute-force cdsaObj --> snaccObj */
926 for(unsigned polDex
=0; polDex
<cdsaObj
->numPolicies
; polDex
++) {
927 CE_PolicyInformation
*cPolInfo
= &cdsaObj
->policies
[polDex
];
928 PolicyInformation
*sPolInfo
= snaccObj
->Append();
929 sPolInfo
->policyIdentifier
.Set((char *)cPolInfo
->certPolicyId
.Data
,
930 cPolInfo
->certPolicyId
.Length
);
931 if(cPolInfo
->numPolicyQualifiers
!= 0) {
932 sPolInfo
->policyQualifiers
= new PolicyInformationSeqOf
;
934 for(unsigned qualDex
=0; qualDex
<cPolInfo
->numPolicyQualifiers
; qualDex
++) {
935 CE_PolicyQualifierInfo
*cQualInfo
= &cPolInfo
->policyQualifiers
[qualDex
];
936 PolicyQualifierInfo
*sQualInfo
= sPolInfo
->policyQualifiers
->Append();
938 /* OK we're at the lowest level.
939 * policyQualifierId == id_qt_cps: qualifier is an IA5 string,
940 * incoming data is its contents. Else incoming data is an encoded
941 * blob we pass on directly.
943 sQualInfo
->policyQualifierId
.Set(
944 (char *)cQualInfo
->policyQualifierId
.Data
,
945 cQualInfo
->policyQualifierId
.Length
);
947 /* we'll convert this incoming ptr/len.... */
948 uint8
*rawData
= cQualInfo
->qualifier
.Data
;
949 unsigned rawDataLen
= cQualInfo
->qualifier
.Length
;
950 /* to this, somehow; it'll be used to build the required AsnAny. */
951 CssmAutoData
aData(alloc
);
953 if(sQualInfo
->policyQualifierId
== id_qt_cps
) {
954 /* build & encode an IA5String */
955 IA5String
*ia5
= new IA5String((char *)rawData
, rawDataLen
);
956 SC_encodeAsnObj(*ia5
, aData
, MAX_IA5_NAME_SIZE
);
960 /* copy over directly */
961 aData
.copy(rawData
, rawDataLen
);
964 /* install the result into CSM_Buffer, which mallocs & copies */
965 sQualInfo
->qualifier
= new AsnAny
;
967 sQualInfo
->qualifier
->value
= new CSM_Buffer(cp
, aData
.length());
969 } /* for each qualifier */
970 } /* for each policy */
972 /* add to mExtensions */
973 cert
.addExtension(snaccObj
, cssmExt
->extnId
, cssmExt
->critical
, false);
976 bool getFieldCertPolicies(
977 const DecodedCert
&cert
,
978 unsigned index
, // which occurrence (0 = first)
979 uint32
&numFields
, // RETURNED
980 CssmOwnedData
&fieldValue
)
982 DecodedExten
*decodedExt
;
983 CertificatePoliciesSyntax
*snaccObj
;
984 CE_CertPolicies
*cdsaObj
;
986 CssmAllocator
&alloc
= fieldValue
.allocator
;
987 brtn
= GetFieldTop
<CertificatePoliciesSyntax
, CE_CertPolicies
>(
991 fieldValue
.allocator
,
992 id_ce_certificatePolicies
,
1000 /* brute force CertificatePoliciesSyntax --> CE_CertPolicies */
1001 cdsaObj
->numPolicies
= snaccObj
->Count();
1002 unsigned sz
= cdsaObj
->numPolicies
* sizeof(CE_PolicyInformation
);
1003 cdsaObj
->policies
= (CE_PolicyInformation
*)alloc
.malloc(sz
);
1004 memset(cdsaObj
->policies
, 0, sz
);
1005 snaccObj
->SetCurrToFirst();
1006 for(unsigned polDex
=0; polDex
<cdsaObj
->numPolicies
; polDex
++) {
1007 CE_PolicyInformation
*cPolInfo
= &cdsaObj
->policies
[polDex
];
1008 PolicyInformation
*sPolInfo
= snaccObj
->Curr();
1009 CssmOid
&cOid
= CssmOid::overlay(cPolInfo
->certPolicyId
);
1010 CL_snaccOidToCssm(sPolInfo
->policyIdentifier
, cOid
, alloc
);
1011 if(sPolInfo
->policyQualifiers
== NULL
) {
1014 cPolInfo
->numPolicyQualifiers
= sPolInfo
->policyQualifiers
->Count();
1015 cPolInfo
->policyQualifiers
= (CE_PolicyQualifierInfo
*)
1016 alloc
.malloc(cPolInfo
->numPolicyQualifiers
*
1017 sizeof(CE_PolicyQualifierInfo
));
1018 sPolInfo
->policyQualifiers
->SetCurrToFirst();
1019 for(unsigned qualDex
=0; qualDex
<cPolInfo
->numPolicyQualifiers
; qualDex
++) {
1020 PolicyQualifierInfo
*sQualInfo
= sPolInfo
->policyQualifiers
->Curr();
1021 CE_PolicyQualifierInfo
*cQualInfo
= &cPolInfo
->policyQualifiers
[qualDex
];
1025 * policyQualifierId == id_qt_cps : IA5String - decode and return
1026 * contents. Else return whole thing.
1028 CssmOid
&cOid2
= CssmOid::overlay(cQualInfo
->policyQualifierId
);
1029 CL_snaccOidToCssm(sQualInfo
->policyQualifierId
, cOid2
, alloc
);
1031 CSM_Buffer
*cbuf
= sQualInfo
->qualifier
->value
;
1033 CssmRemoteData
outData(alloc
, cQualInfo
->qualifier
);
1034 if(sQualInfo
->policyQualifierId
== id_qt_cps
) {
1036 CssmAutoData
berData(alloc
, cbuf
->Access(), cbuf
->Length());
1037 /* error is fatal, punt the whole kit'n'kaboodle and leak */
1038 SC_decodeAsnObj(berData
, ia5
);
1040 outData
.copy(src
, ia5
.Len());
1043 outData
.copy(cbuf
->Access(), cbuf
->Length());
1046 sPolInfo
->policyQualifiers
->GoNext();
1050 getFieldExtenCommon(cdsaObj
, *decodedExt
, fieldValue
);
1054 void freeFieldCertPolicies (
1055 CssmOwnedData
&fieldValue
)
1057 CSSM_X509_EXTENSION_PTR cssmExt
= verifySetFreeExtension(fieldValue
, false);
1058 CssmAllocator
&alloc
= fieldValue
.allocator
;
1059 CE_CertPolicies
*cdsaObj
= (CE_CertPolicies
*)cssmExt
->value
.parsedValue
;
1060 for(unsigned polDex
=0; polDex
<cdsaObj
->numPolicies
; polDex
++) {
1061 CE_PolicyInformation
*cPolInfo
= &cdsaObj
->policies
[polDex
];
1062 alloc
.free(cPolInfo
->certPolicyId
.Data
);
1063 for(unsigned qualDex
=0; qualDex
<cPolInfo
->numPolicyQualifiers
; qualDex
++) {
1064 CE_PolicyQualifierInfo
*cQualInfo
= &cPolInfo
->policyQualifiers
[qualDex
];
1065 alloc
.free(cQualInfo
->policyQualifierId
.Data
);
1066 alloc
.free(cQualInfo
->qualifier
.Data
);
1068 alloc
.free(cPolInfo
->policyQualifiers
);
1070 alloc
.free(cdsaObj
->policies
);
1071 freeFieldExtenCommon(cssmExt
, alloc
); // frees extnId, parsedValue, BERvalue
1075 *** Netscape cert type
1076 *** CDSA Format: CE_NetscapeCertType (a uint16)
1077 *** SNACC format: AsnBits
1078 *** OID: CSSMOID_NetscapeCertType
1080 void setFieldNetscapeCertType(
1082 const CssmData
&fieldValue
)
1084 CSSM_X509_EXTENSION_PTR cssmExt
= verifySetFreeExtension(fieldValue
, false);
1085 CE_NetscapeCertType
*cdsaObj
= (CE_NetscapeCertType
*)cssmExt
->value
.parsedValue
;
1087 char bits
[sizeof(CE_NetscapeCertType
)];
1088 bits
[0] = static_cast<char>((*cdsaObj
) >> 8);
1089 bits
[1] = static_cast<char>(*cdsaObj
);
1090 memmove(bits
, cdsaObj
, sizeof(CE_NetscapeCertType
));
1091 AsnBits
*snaccObj
= new AsnBits(bits
, sizeof(CE_NetscapeCertType
) * 8);
1093 /* add to mExtensions */
1094 cert
.addExtension(snaccObj
, cssmExt
->extnId
, cssmExt
->critical
, false);
1097 bool getFieldNetscapeCertType(
1098 const DecodedCert
&cert
,
1099 unsigned index
, // which occurrence (0 = first)
1100 uint32
&numFields
, // RETURNED
1101 CssmOwnedData
&fieldValue
)
1103 DecodedExten
*decodedExt
;
1105 CE_NetscapeCertType
*cdsaObj
;
1108 brtn
= GetFieldTop
<AsnBits
, CE_NetscapeCertType
>(
1112 fieldValue
.allocator
,
1113 id_netscape_cert_type
,
1121 unsigned toCopy
= (snaccObj
->BitLen() + 7) / 8;
1123 /* I hope I never see this... */
1124 errorLog0("getFieldNetscapeCertType: bitstring larger than 2 bytes!\n");
1127 unsigned char bits
[2] = {0, 0};
1128 memmove(bits
, snaccObj
->BitOcts(), toCopy
);
1129 *cdsaObj
= (((unsigned)bits
[0]) << 8) | bits
[1];
1130 getFieldExtenCommon(cdsaObj
, *decodedExt
, fieldValue
);
1135 *** unknown extensions
1136 *** CDSA format: raw bytes in a CSSM_DATA. This data is the BER-encoding of
1137 *** some extension struct we don't know about.
1138 *** SNACC format AsnOcts
1139 *** OID CSSMOID_X509V3CertificateExtensionCStruct
1142 void setFieldUnknownExt(
1144 const CssmData
&fieldValue
)
1146 CSSM_X509_EXTENSION_PTR cssmExt
= verifySetFreeExtension(fieldValue
, true);
1147 AsnOcts
*snaccObj
= new AsnOcts(
1148 reinterpret_cast<char *>(cssmExt
->BERvalue
.Data
),
1149 cssmExt
->BERvalue
.Length
);
1150 cert
.addExtension(snaccObj
, cssmExt
->extnId
, cssmExt
->critical
, true);
1153 bool getFieldUnknownExt(
1154 const DecodedCert
&cert
,
1155 unsigned index
, // which occurrence (0 = first)
1156 uint32
&numFields
, // RETURNED
1157 CssmOwnedData
&fieldValue
)
1159 AsnOid
noOidLikeThis (1, 2); // a dummy argument
1160 DecodedExten
*decodedExt
= cert
.findDecodedExt(noOidLikeThis
,
1161 true, index
, numFields
);
1162 if(decodedExt
== NULL
) {
1165 /* failure of this dynamic_cast is fatal */
1166 AsnOcts
*snaccObj
= dynamic_cast<AsnOcts
*>(decodedExt
->snaccObj
);
1167 if(snaccObj
== NULL
) {
1168 errorLog0("getFieldUnknownExt: dynamic_cast failure\n");
1169 CssmError::throwMe(CSSMERR_CL_INTERNAL_ERROR
);
1171 char *octData
= *snaccObj
;
1172 CssmAutoData
encodedBytes(fieldValue
.allocator
, octData
, snaccObj
->Len());
1173 /* easier way to do this...? */
1174 CssmData cData
= encodedBytes
.release();
1175 getFieldExtenCommon(&cData
, *decodedExt
, fieldValue
);
1179 void freeFieldUnknownExt (
1180 CssmOwnedData
&fieldValue
)
1182 CSSM_X509_EXTENSION_PTR cssmExt
= verifySetFreeExtension(fieldValue
, true);
1183 CssmAllocator
&alloc
= fieldValue
.allocator
;
1184 freeFieldExtenCommon(cssmExt
, alloc
); // frees extnId, parsedValue, BERvalue
1192 *** Subject alternate name
1193 *** CDSA Format: CE_GeneralNames
1194 *** SNACC format: GeneralNames
1195 *** OID: CSSMOID_SubjectAltName
1197 void setFieldSomeExt(
1199 const CssmData
&fieldValue
)
1201 CSSM_X509_EXTENSION_PTR cssmExt
= verifySetFreeExtension(fieldValue
, false);
1202 new an approppriate AsnType
snaccObj (KeyUsage
, etc
.);
1203 extension
-specific e
.g
. CE_KeyUsage
*cdsaObj
= cssmExt
->value
.parsedValue
;
1204 /* brute-force cdsaObj --> snaccObj */
1206 /* add to mExtensions */
1207 cert
.addExtension(snaccObj
, cssmExt
->extnId
, cssmExt
->critical
, false);
1210 bool getFieldSomeExt(
1211 const DecodedCert
&cert
,
1212 unsigned index
, // which occurrence (0 = first)
1213 uint32
&numFields
, // RETURNED
1214 CssmOwnedData
&fieldValue
)
1216 DecodedExten
*decodedExt
;
1217 e
.g
. ExtKeyUsageSyntax
*snaccObj
;
1218 e
.g
. CE_ExtendedKeyUsage
*cdsaObj
;
1221 brtn
= GetFieldTop
<ExtKeyUsageSyntax
, CE_ExtendedKeyUsage
>(
1225 fieldValue
.allocator
,
1226 e
.g
. id_ce_extKeyUsage
,
1234 brute force snaccObj
--> cdsaObj
;
1235 getFieldExtenCommon(cdsaObj
, *decodedExt
, fieldValue
);
1239 /* only used if complex structs below cssmExt->value.parsedValue */
1240 void freeFieldSomeExt (
1241 CssmOwnedData
&fieldValue
)
1243 CSSM_X509_EXTENSION_PTR cssmExt
= verifySetFreeExtension(fieldValue
, false);
1244 CssmAllocator
&alloc
= fieldValue
.allocator
;
1245 free the stuff in cssmExt
->value
.parsedValue
;
1246 freeFieldExtenCommon(cssmExt
, alloc
); // frees extnId, parsedValue, BERvalue