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 * CertFields.cpp - convert between snacc-based Certificate components and CDSA-style
21 * fields. A major component of DecodedCert.
23 * Created 9/1/2000 by Doug Mitchell.
24 * Copyright (c) 2000 by Apple Computer.
26 * The code in this file is dreadfully gross. There is no practical way to do this
27 * work (converting between C++ snacc types and C CSDA types) without the kind
28 * of brute force code you see here.
31 #include "DecodedCert.h"
32 #include "cldebugging.h"
33 #include "CertBuilder.h"
34 #include "CLCertExtensions.h"
35 #include "SnaccUtils.h"
36 #include <Security/utilities.h>
37 #include <Security/oidscert.h>
38 #include <Security/cssmerr.h>
39 #include <Security/x509defs.h>
40 #include <Security/cdsaUtils.h>
43 * Routines for common validity checking for certificateToSign fields.
45 * Call from setField*: verify field isn't already set, optionally validate
48 static void tbsSetCheck(
50 const CssmData
&fieldValue
,
54 if(fieldToSet
!= NULL
) {
55 /* can't add another */
56 errorLog1("setField(%s): field already set\n", op
);
57 CssmError::throwMe(CSSMERR_CL_INVALID_NUMBER_OF_FIELDS
);
59 if((expLength
!= 0) && (fieldValue
.length() != expLength
)) {
60 errorLog3("setField(%s): bad length : exp %d got %d\n",
61 op
, (int)expLength
, (int)fieldValue
.length());
62 CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER
);
67 * Call from getField* for unique fields - detect missing field or index out of bounds.
69 static bool tbsGetCheck(
73 if((requiredField
== NULL
) || (reqIndex
!= 0)) {
83 *** Format = DER-encoded int (max of four bytes in this case)
85 static bool getField_Version (
86 const DecodedCert
&cert
,
87 unsigned index
, // which occurrence (0 = first)
88 uint32
&numFields
, // RETURNED
89 CssmOwnedData
&fieldValue
) // RETURNED
91 if(!tbsGetCheck(cert
.certificateToSign
->version
, index
)) {
95 /* cook up big-endian char array representation */
96 int ivers
= *cert
.certificateToSign
->version
;
97 uint32 uvers
= static_cast<uint32
>(ivers
);
98 uint8 chars
[sizeof(uint32
)];
99 for(uint32 i
=0; i
<sizeof(uint32
); i
++) {
100 chars
[sizeof(uint32
) - 1 -i
] = (uint8
)uvers
;
103 fieldValue
.copy(chars
, sizeof(uint32
));
108 static void setField_Version (
110 const CssmData
&fieldValue
)
112 tbsSetCheck(cert
.certificateToSign
->version
, fieldValue
, 0, "version");
114 /* get big-endian int from *fieldValue.Data */
115 if(fieldValue
.length() > sizeof(unsigned)) {
116 CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER
);
119 uint8
*cp
= fieldValue
;
120 for(unsigned i
=0; i
<fieldValue
.length(); i
++) {
124 cert
.certificateToSign
->version
= new Version((int)vers
);
125 cert
.certificateToSign
->version
->Set((int)vers
);
129 #if this_is_a_template
132 *** Format = DER-encoded int (always four bytes in this case)
134 static bool getField_Version (
135 const DecodedCert
&cert
,
136 unsigned index
, // which occurrence (0 = first)
137 uint32
&numFields
, // RETURNED
138 CssmOwnedData
&fieldValue
) // RETURNED
140 tbsGetCheck(cert
.certificateToSign
->version
, index
);
142 static void setField_Version (
144 const CssmData
&fieldValue
)
146 tbsSetCheck(cert
.certificateToSign
->version
, fieldValue
, sizeof(uint32
),
150 static void freeField_Version (
151 CssmOwnedData
&fieldValue
)
158 *** Format = DER-encoded int, variable length
160 static bool getField_SerialNumber (
161 const DecodedCert
&cert
,
162 unsigned index
, // which occurrence (0 = first)
163 uint32
&numFields
, // RETURNED
164 CssmOwnedData
&fieldValue
) // RETURNED
170 char *cp
= cert
.certificateToSign
->serialNumber
;
171 uint32 len
= cert
.certificateToSign
->serialNumber
.Len();
172 fieldValue
.copy(cp
, len
);
177 static void setField_SerialNumber (
179 const CssmData
&fieldValue
)
181 cert
.certificateToSign
->serialNumber
.Set(fieldValue
, fieldValue
.Length
);
185 *** Issuer Name, Subject Name (C struct version)
186 *** Format = CSSM_X509_NAME
187 *** class Name from sm_x501if
190 /* first, the common code */
191 static bool getField_RDN (
193 uint32
&numFields
, // RETURNED (if successful, 0 or 1)
194 CssmOwnedData
&fieldValue
) // RETURNED
196 RDNSequence
*rdns
= name
.rDNSequence
;
197 int numRdns
= rdns
->Count();
198 if((rdns
== NULL
) || (numRdns
== 0)) {
199 /* not technically an error */
203 /* alloc top-level CSSM_X509_NAME and its RelativeDistinguishedName array */
204 CssmAllocator
&alloc
= fieldValue
.allocator
;
205 fieldValue
.malloc(sizeof(CSSM_X509_NAME
));
206 CSSM_X509_NAME_PTR x509Name
= (CSSM_X509_NAME_PTR
)fieldValue
.data();
207 memset(x509Name
, 0, sizeof(CSSM_X509_NAME
));
208 x509Name
->numberOfRDNs
= numRdns
;
209 x509Name
->RelativeDistinguishedName
=
210 (CSSM_X509_RDN_PTR
)alloc
.malloc(sizeof(CSSM_X509_RDN
) * numRdns
);
211 CSSM_X509_RDN_PTR currRdn
= x509Name
->RelativeDistinguishedName
;
212 memset(currRdn
, 0, sizeof(CSSM_X509_RDN
) * numRdns
);
214 rdns
->SetCurrElmt(0);
215 for(int rdnDex
=0; rdnDex
<numRdns
; rdnDex
++) {
217 RelativeDistinguishedName
*rdn
= rdns
->Curr();
219 /* not sure how this can happen... */
220 dprintf1("getField_RDN: NULL rdn at index %d\n", rdnDex
);
222 /* next snacc RDN but keep CDSA position unchanged */
223 rdns
->GoNext(); // snacc format
224 x509Name
->numberOfRDNs
--; // since we're skipping one
227 int numAttrs
= rdn
->Count();
229 dprintf1("getField_RDN: zero numAttrs at index %d\n", rdnDex
);
231 x509Name
->numberOfRDNs
--; // since we're skipping one
235 /* alloc CSSM_X509_TYPE_VALUE_PAIR array for this rdn */
236 currRdn
->numberOfPairs
= numAttrs
;
237 currRdn
->AttributeTypeAndValue
= (CSSM_X509_TYPE_VALUE_PAIR_PTR
)
238 alloc
.malloc(sizeof(CSSM_X509_TYPE_VALUE_PAIR
) * numAttrs
);
239 CSSM_X509_TYPE_VALUE_PAIR_PTR currAttr
= currRdn
->AttributeTypeAndValue
;
240 memset(currAttr
, 0, sizeof(CSSM_X509_TYPE_VALUE_PAIR
) * numAttrs
);
242 /* descend into array of attribute/values */
244 for(int attrDex
=0; attrDex
<numAttrs
; attrDex
++) {
246 AttributeTypeAndDistinguishedValue
*att
= rdn
->Curr();
248 /* not sure how this can happen... */
249 dprintf1("getField_RDN: NULL att at index %d\n", attrDex
);
251 currRdn
->numberOfPairs
--;
256 * Convert snacc-style AttributeTypeAndDistinguishedValue to
257 * CSSM-style CSSM_X509_TYPE_VALUE_PAIR
259 * Hopefully 'value' is one of the types defined in DirectoryString,
260 * defined in sm_x520sa. Some certs use IA5String, which is not
261 * technically legal and is not handled by DirectoryString, so
262 * we have to handle that ourself. See e.g. the Thawte serverbasic
263 * cert, which has an email address in IA5String format.
265 CSM_Buffer
*cbuf
= att
->value
.value
;
267 AsnLen len
= cbuf
->Length();
273 DirectoryString
*dirStr
= NULL
;
275 buf
.InstallData(cbuf
->Access(), len
);
277 tag
= BDecTag (buf
, len
, env
);
278 elmtLen
= BDecLen (buf
, len
, env
);
281 errorLog0("getField_RDN: malformed DirectoryString (1)\n");
282 /* FIXME - throw? Discard the whole cert? What? */
284 currRdn
->numberOfPairs
--;
288 /* current buf ptr is at the string value's contents. */
289 if((tag
== MAKE_TAG_ID (UNIV
, PRIM
, IA5STRING_TAG_CODE
)) ||
290 (tag
== MAKE_TAG_ID (UNIV
, CONS
, IA5STRING_TAG_CODE
))) {
291 /* any other printable types not handled by DirectoryString here */
292 valData
= buf
.DataPtr();
293 valLength
= buf
.DataLen();
299 /* from sm_x520sa.h */
301 dirStr
= new DirectoryString
;
303 dirStr
->BDecContent(buf
, tag
, elmtLen
, dec
, env
);
306 errorLog0("getField_RDN: malformed DirectoryString (1)\n");
307 /* FIXME - throw? Discard the whole cert? What? */
309 currRdn
->numberOfPairs
--;
312 AsnOcts
*octs
= NULL
;
313 switch(dirStr
->choiceId
) {
314 case DirectoryString::printableStringCid
:
315 octs
= dirStr
->printableString
;
317 case DirectoryString::teletexStringCid
:
318 octs
= dirStr
->teletexString
;
320 case DirectoryString::universalStringCid
:
321 octs
= dirStr
->universalString
;
323 case DirectoryString::bmpStringCid
:
324 octs
= dirStr
->bmpString
;
326 case DirectoryString::utf8StringCid
:
327 octs
= dirStr
->utf8String
;
330 /* should never happen unless DirectoryString changes */
331 errorLog1("getField_RDN: Bad DirectoryString::choiceId (%d)\n",
332 (int)dirStr
->choiceId
);
333 CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER
);
336 valLength
= octs
->Len();
337 } /* normal DirectoryString */
339 /* OK, set up outgoing CSSM_X509_TYPE_VALUE_PAIR */
340 CssmOid
&oid
= CssmOid::overlay(currAttr
->type
);
341 CL_snaccOidToCssm(att
->type
, oid
, alloc
);
342 currAttr
->valueType
= tag
>> 24;
343 currAttr
->value
.Data
= (uint8
*)alloc
.malloc(valLength
);
344 currAttr
->value
.Length
= valLength
;
345 memcpy(currAttr
->value
.Data
, valData
, valLength
);
347 rdn
->GoNext(); // snacc format
348 currAttr
++; // CDSA format
350 } /* for eact attr in rdn */
352 rdns
->GoNext(); // snacc format
353 currRdn
++; // CDSA format
354 } /* for each rdn in rdns */
359 /* common for issuer and subject */
360 static void freeField_RDN (
361 CssmOwnedData
&fieldValue
)
363 if(fieldValue
.data() == NULL
) {
366 if(fieldValue
.length() != sizeof(CSSM_X509_NAME
)) {
367 CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER
);
369 CssmAllocator
&alloc
= fieldValue
.allocator
;
370 CSSM_X509_NAME_PTR x509Name
= (CSSM_X509_NAME_PTR
)fieldValue
.data();
371 for(unsigned rdnDex
=0; rdnDex
<x509Name
->numberOfRDNs
; rdnDex
++) {
372 CSSM_X509_RDN_PTR rdn
= &x509Name
->RelativeDistinguishedName
[rdnDex
];
373 for(unsigned atvDex
=0; atvDex
<rdn
->numberOfPairs
; atvDex
++) {
374 CSSM_X509_TYPE_VALUE_PAIR_PTR atv
= &rdn
->AttributeTypeAndValue
[atvDex
];
375 alloc
.free(atv
->type
.Data
);
376 alloc
.free(atv
->value
.Data
);
377 memset(atv
, 0, sizeof(CSSM_X509_TYPE_VALUE_PAIR
));
379 alloc
.free(rdn
->AttributeTypeAndValue
);
380 memset(rdn
, 0, sizeof(CSSM_X509_RDN
));
382 alloc
.free(x509Name
->RelativeDistinguishedName
);
383 memset(x509Name
, 0, sizeof(CSSM_X509_NAME
));
385 /* top-level x509Name pointer freed by freeCertFieldData() */
389 static bool getField_Issuer (
390 const DecodedCert
&cert
,
391 unsigned index
, // which occurrence (0 = first)
392 uint32
&numFields
, // RETURNED
393 CssmOwnedData
&fieldValue
) // RETURNED
397 if(!tbsGetCheck(cert
.certificateToSign
->issuer
, index
)) {
401 brtn
= getField_RDN(*cert
.certificateToSign
->issuer
, numFields
, fieldValue
);
404 freeField_RDN(fieldValue
);
410 static void setField_Issuer (
412 const CssmData
&fieldValue
)
414 tbsSetCheck(cert
.certificateToSign
->issuer
, fieldValue
, sizeof(CSSM_X509_NAME
),
416 NameBuilder
*issuer
= new NameBuilder
;
417 cert
.certificateToSign
->issuer
= issuer
;
418 const CSSM_X509_NAME
*x509Name
= (const CSSM_X509_NAME
*)fieldValue
.Data
;
419 issuer
->addX509Name(x509Name
);
423 static bool getField_Subject (
424 const DecodedCert
&cert
,
425 unsigned index
, // which occurrence (0 = first)
426 uint32
&numFields
, // RETURNED
427 CssmOwnedData
&fieldValue
) // RETURNED
429 if(!tbsGetCheck(cert
.certificateToSign
->subject
, index
)) {
434 brtn
= getField_RDN(*cert
.certificateToSign
->subject
, numFields
, fieldValue
);
437 freeField_RDN(fieldValue
);
443 static void setField_Subject (
445 const CssmData
&fieldValue
)
447 tbsSetCheck(cert
.certificateToSign
->subject
, fieldValue
, sizeof(CSSM_X509_NAME
),
449 NameBuilder
*subject
= new NameBuilder
;
450 cert
.certificateToSign
->subject
= subject
;
451 const CSSM_X509_NAME
*x509Name
= (const CSSM_X509_NAME
*)fieldValue
.Data
;
452 subject
->addX509Name(x509Name
);
456 *** Issuer Name, Subject Name (normalized and encoded version)
457 *** Format = CSSM_DATA containing the DER encoding of the normalized name
458 *** class Name from sm_x501if
461 /* first, the common code */
462 static bool getField_normRDN (
464 uint32
&numFields
, // RETURNED (if successful, 0 or 1)
465 CssmOwnedData
&fieldValue
) // RETURNED
468 * First step is to make a copy of the existing name. The easiest way to do
469 * this is to encode and decode.
471 CssmAllocator
&alloc
= fieldValue
.allocator
;
472 CssmAutoData
encodedName1(alloc
);
473 /* FIXME - should SC_encodeAsnObj() take a const AsnType & ? */
474 SC_encodeAsnObj(const_cast<Name
&>(name
), encodedName1
, MAX_RDN_SIZE
);
476 SC_decodeAsnObj(encodedName1
, decodedName
);
479 CL_normalizeX509Name(decodedName
, alloc
);
482 SC_encodeAsnObj(decodedName
, fieldValue
, MAX_RDN_SIZE
);
487 static bool getFieldSubjectNorm(
488 const DecodedCert
&cert
,
489 unsigned index
, // which occurrence (0 = first)
490 uint32
&numFields
, // RETURNED
491 CssmOwnedData
&fieldValue
) // RETURNED
493 if(!tbsGetCheck(cert
.certificateToSign
->subject
, index
)) {
496 return getField_normRDN(*cert
.certificateToSign
->subject
, numFields
, fieldValue
);
499 static bool getFieldIssuerNorm(
500 const DecodedCert
&cert
,
501 unsigned index
, // which occurrence (0 = first)
502 uint32
&numFields
, // RETURNED
503 CssmOwnedData
&fieldValue
) // RETURNED
505 if(!tbsGetCheck(cert
.certificateToSign
->issuer
, index
)) {
508 return getField_normRDN(*cert
.certificateToSign
->issuer
, numFields
, fieldValue
);
513 *** TBS AlgId, Signature AlgId
514 *** Format = CSSM_X509_ALGORITHM_IDENTIFIER
518 static void getField_AlgId (
519 const AlgorithmIdentifier
*snaccAlgId
,
520 CssmOwnedData
&fieldValue
) // RETURNED
522 CssmAllocator
&alloc
= fieldValue
.allocator
;
523 fieldValue
.malloc(sizeof(CSSM_X509_ALGORITHM_IDENTIFIER
));
524 CSSM_X509_ALGORITHM_IDENTIFIER
*cssmAlgId
=
525 (CSSM_X509_ALGORITHM_IDENTIFIER
*)fieldValue
.data();
526 CL_snaccAlgIdToCssm (*snaccAlgId
, *cssmAlgId
, alloc
);
529 static void setField_AlgId (
530 AlgorithmIdentifier
*snaccAlgId
,
531 const CssmData
&fieldValue
)
533 CSSM_X509_ALGORITHM_IDENTIFIER
*cssmAlgId
=
534 (CSSM_X509_ALGORITHM_IDENTIFIER
*)fieldValue
.data();
535 if(cssmAlgId
->algorithm
.Data
== NULL
) {
536 CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER
);
538 CL_cssmAlgIdToSnacc(*cssmAlgId
, *snaccAlgId
);
541 static void freeField_AlgId (
542 CssmOwnedData
&fieldValue
)
544 CSSM_X509_ALGORITHM_IDENTIFIER
*cssmAlgId
=
545 (CSSM_X509_ALGORITHM_IDENTIFIER
*)fieldValue
.data();
546 if(cssmAlgId
== NULL
) {
549 if(fieldValue
.length() != sizeof(CSSM_X509_ALGORITHM_IDENTIFIER
)) {
550 CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER
);
552 CssmAllocator
&alloc
= fieldValue
.allocator
;
553 alloc
.free(cssmAlgId
->algorithm
.Data
);
554 alloc
.free(cssmAlgId
->parameters
.Data
);
555 memset(cssmAlgId
, 0, sizeof(CSSM_X509_ALGORITHM_IDENTIFIER
));
560 static bool getField_TbsAlgId (
561 const DecodedCert
&cert
,
562 unsigned index
, // which occurrence (0 = first)
563 uint32
&numFields
, // RETURNED
564 CssmOwnedData
&fieldValue
) // RETURNED
566 AlgorithmIdentifier
*snaccAlgId
= cert
.certificateToSign
->signature
;
567 if(!tbsGetCheck(snaccAlgId
, index
)) {
570 getField_AlgId(snaccAlgId
, fieldValue
);
575 static void setField_TbsAlgId (
577 const CssmData
&fieldValue
)
579 tbsSetCheck(cert
.certificateToSign
->signature
, fieldValue
,
580 sizeof(CSSM_X509_ALGORITHM_IDENTIFIER
), "TBS_AlgId");
581 AlgorithmIdentifier
*snaccAlgId
= new AlgorithmIdentifier
;
582 cert
.certificateToSign
->signature
= snaccAlgId
;
583 setField_AlgId(snaccAlgId
, fieldValue
);
586 /* Cert AlgId - read only */
587 static bool getField_CertAlgId (
588 const DecodedCert
&cert
,
589 unsigned index
, // which occurrence (0 = first)
590 uint32
&numFields
, // RETURNED
591 CssmOwnedData
&fieldValue
) // RETURNED
593 AlgorithmIdentifier
*snaccAlgId
= cert
.algorithmIdentifier
;
594 if(!tbsGetCheck(snaccAlgId
, index
)) {
597 getField_AlgId(snaccAlgId
, fieldValue
);
603 *** Validity not before, not after
604 *** Format: CSSM_X509_TIME
607 /*** common code ***/
608 static void getField_Time (
609 const Time
*snaccTime
,
610 CssmOwnedData
&fieldValue
) // RETURNED
612 CssmAllocator
&alloc
= fieldValue
.allocator
;
613 fieldValue
.malloc(sizeof(CSSM_X509_TIME
));
614 CSSM_X509_TIME
*cssmTime
=
615 (CSSM_X509_TIME
*)fieldValue
.data();
616 memset(cssmTime
, 0, sizeof(CSSM_X509_TIME
));
618 char *timeStr
= NULL
;
620 switch(snaccTime
->choiceId
) {
621 case Time::utcTimeCid
:
622 cssmTime
->timeType
= BER_TAG_UTC_TIME
;
623 timeStr
= *snaccTime
->utcTime
; // an AsnOct
624 timeStrLen
= snaccTime
->utcTime
->Len();
626 case Time::generalizedTimeCid
:
627 timeStr
= *snaccTime
->generalizedTime
; // an AsnOct
628 timeStrLen
= snaccTime
->generalizedTime
->Len();
629 cssmTime
->timeType
= BER_TAG_GENERALIZED_TIME
;
632 /* snacc error, should never happen */
633 cssmTime
->timeType
= BER_TAG_OCTET_STRING
;
634 timeStr
= *snaccTime
->generalizedTime
; // an AsnOct
635 timeStrLen
= snaccTime
->generalizedTime
->Len();
639 cssmTime
->time
.Data
= reinterpret_cast<uint8
*>(alloc
.malloc(timeStrLen
));
640 cssmTime
->time
.Length
= timeStrLen
;
641 memcpy(cssmTime
->time
.Data
, timeStr
, timeStrLen
);
644 static void setField_Time (
646 const CssmData
&fieldValue
)
648 CSSM_X509_TIME
*cssmTime
=
649 (CSSM_X509_TIME
*)fieldValue
.data();
650 const char *tStr
= reinterpret_cast<const char *>(cssmTime
->time
.Data
);
651 size_t tLen
= cssmTime
->time
.Length
;
653 switch(cssmTime
->timeType
) {
654 case BER_TAG_GENERALIZED_TIME
:
655 snaccTime
->choiceId
= Time::generalizedTimeCid
;
656 snaccTime
->generalizedTime
= new GeneralizedTime(tStr
, tLen
);
658 case BER_TAG_UTC_TIME
:
659 snaccTime
->choiceId
= Time::utcTimeCid
;
660 snaccTime
->utcTime
= new UTCTime(tStr
, tLen
);
663 errorLog1("setField_Time: bad time tag (%d)\n", cssmTime
->timeType
);
664 CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER
);
668 static void freeField_Time (
669 CssmOwnedData
&fieldValue
)
671 CSSM_X509_TIME
*cssmTime
= (CSSM_X509_TIME
*)fieldValue
.data();
672 if(cssmTime
== NULL
) {
675 if(fieldValue
.length() != sizeof(CSSM_X509_TIME
)) {
676 CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER
);
678 fieldValue
.allocator
.free(cssmTime
->time
.Data
);
679 memset(cssmTime
, 0, sizeof(CSSM_X509_TIME
));
683 static bool getField_NotBefore (
684 const DecodedCert
&cert
,
685 unsigned index
, // which occurrence (0 = first)
686 uint32
&numFields
, // RETURNED
687 CssmOwnedData
&fieldValue
) // RETURNED
689 if(!tbsGetCheck(cert
.certificateToSign
->validity
, index
)) {
692 if(cert
.certificateToSign
->validity
->notBefore
== NULL
) {
695 getField_Time(cert
.certificateToSign
->validity
->notBefore
, fieldValue
);
700 static void setField_NotBefore (
702 const CssmData
&fieldValue
)
704 /* anything could need mallocing except TBS */
705 if(cert
.certificateToSign
->validity
== NULL
) {
706 cert
.certificateToSign
->validity
= new Validity
;
708 tbsSetCheck(cert
.certificateToSign
->validity
->notBefore
, fieldValue
,
709 sizeof(CSSM_X509_TIME
), "NotBefore");
710 cert
.certificateToSign
->validity
->notBefore
= new Time
;
711 setField_Time(cert
.certificateToSign
->validity
->notBefore
, fieldValue
);
715 static bool getField_NotAfter (
716 const DecodedCert
&cert
,
717 unsigned index
, // which occurrence (0 = first)
718 uint32
&numFields
, // RETURNED
719 CssmOwnedData
&fieldValue
) // RETURNED
721 if(!tbsGetCheck(cert
.certificateToSign
->validity
, index
)) {
724 if(cert
.certificateToSign
->validity
->notAfter
== NULL
) {
727 getField_Time(cert
.certificateToSign
->validity
->notAfter
, fieldValue
);
732 static void setField_NotAfter (
734 const CssmData
&fieldValue
)
736 /* anything could need mallocing except TBS */
737 if(cert
.certificateToSign
->validity
== NULL
) {
738 cert
.certificateToSign
->validity
= new Validity
;
740 tbsSetCheck(cert
.certificateToSign
->validity
->notAfter
, fieldValue
,
741 sizeof(CSSM_X509_TIME
), "NotAfter");
742 cert
.certificateToSign
->validity
->notAfter
= new Time
;
743 setField_Time(cert
.certificateToSign
->validity
->notAfter
, fieldValue
);
747 *** Subject/issuer unique ID
748 *** Format: Raw bytes. It's stored in the cert as an ASN bit string; the decoded
749 *** bytes are present at this level (i.e., not tag and length in the bytes).
750 *** NOTE: this is not quite accurate in that we only provide byte-aligned size,
751 *** not bit-aligned. This field is rarely if ever used so I think it's O, but
754 static bool getField_SubjectUniqueId (
755 const DecodedCert
&cert
,
756 unsigned index
, // which occurrence (0 = first)
757 uint32
&numFields
, // RETURNED
758 CssmOwnedData
&fieldValue
) // RETURNED
760 UniqueIdentifier
*id
= cert
.certificateToSign
->subjectUniqueIdentifier
;
761 if(!tbsGetCheck(id
, index
)) {
764 SC_asnBitsToCssmData(*id
, fieldValue
);
769 static void setField_SubjectUniqueId (
771 const CssmData
&fieldValue
)
773 tbsSetCheck(cert
.certificateToSign
->subjectUniqueIdentifier
, fieldValue
, 0,
775 cert
.certificateToSign
->subjectUniqueIdentifier
= new UniqueIdentifier(
776 reinterpret_cast<char * const>(fieldValue
.Data
), fieldValue
.Length
* 8);
779 static bool getField_IssuerUniqueId (
780 const DecodedCert
&cert
,
781 unsigned index
, // which occurrence (0 = first)
782 uint32
&numFields
, // RETURNED
783 CssmOwnedData
&fieldValue
) // RETURNED
785 UniqueIdentifier
*id
= cert
.certificateToSign
->issuerUniqueIdentifier
;
786 if(!tbsGetCheck(id
, index
)) {
789 SC_asnBitsToCssmData(*id
, fieldValue
);
794 static void setField_IssuerUniqueId (
796 const CssmData
&fieldValue
)
798 tbsSetCheck(cert
.certificateToSign
->issuerUniqueIdentifier
, fieldValue
, 0,
800 cert
.certificateToSign
->issuerUniqueIdentifier
= new UniqueIdentifier(
801 reinterpret_cast<char * const>(fieldValue
.Data
), fieldValue
.Length
* 8);
806 *** Format = CSSM_X509_SUBJECT_PUBLIC_KEY_INFO
808 static bool getField_PublicKeyInfo (
809 const DecodedCert
&cert
,
810 unsigned index
, // which occurrence (0 = first)
811 uint32
&numFields
, // RETURNED
812 CssmOwnedData
&fieldValue
) // RETURNED
814 if(!tbsGetCheck(cert
.certificateToSign
->subjectPublicKeyInfo
, index
)) {
817 SubjectPublicKeyInfo
*snaccKeyInfo
= cert
.certificateToSign
->subjectPublicKeyInfo
;
818 AlgorithmIdentifier
*snaccAlgId
= snaccKeyInfo
->algorithm
;
819 if(snaccAlgId
== NULL
) {
820 errorLog0("getField_PublicKeyInfo: cert has pubKeyInfo but no algorithm!\n");
823 CssmAllocator
&alloc
= fieldValue
.allocator
;
824 fieldValue
.malloc(sizeof(CSSM_X509_SUBJECT_PUBLIC_KEY_INFO
));
825 CSSM_X509_SUBJECT_PUBLIC_KEY_INFO
*cssmKeyInfo
=
826 (CSSM_X509_SUBJECT_PUBLIC_KEY_INFO
*)fieldValue
.data();
827 memset(cssmKeyInfo
, 0, sizeof(CSSM_X509_SUBJECT_PUBLIC_KEY_INFO
));
828 CL_snaccAlgIdToCssm(*snaccAlgId
, cssmKeyInfo
->algorithm
, alloc
);
831 * key info - the actual public key blob - is stored in the cert as a bit string;
832 * snacc will give us the actual bits which are invariably yet another DER
833 * encoding (e.g., PKCS1 for RSA public keys).
835 size_t keyLen
= (snaccKeyInfo
->subjectPublicKey
.BitLen() + 7) / 8;
836 cssmKeyInfo
->subjectPublicKey
.Data
= (uint8
*)alloc
.malloc(keyLen
);
837 cssmKeyInfo
->subjectPublicKey
.Length
= keyLen
;
838 memcpy(cssmKeyInfo
->subjectPublicKey
.Data
,
839 snaccKeyInfo
->subjectPublicKey
.BitOcts(),
845 static void setField_PublicKeyInfo (
847 const CssmData
&fieldValue
)
849 /* This fails if setField_PublicKeyStruct has already been called */
850 tbsSetCheck(cert
.certificateToSign
->subjectPublicKeyInfo
, fieldValue
,
851 sizeof(CSSM_X509_SUBJECT_PUBLIC_KEY_INFO
), "PubKeyInfo");
852 CSSM_X509_SUBJECT_PUBLIC_KEY_INFO
*cssmKeyInfo
=
853 (CSSM_X509_SUBJECT_PUBLIC_KEY_INFO
*)fieldValue
.Data
;
854 if((cssmKeyInfo
->subjectPublicKey
.Data
== NULL
) ||
855 (cssmKeyInfo
->subjectPublicKey
.Length
== 0)) {
856 CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER
);
859 SubjectPublicKeyInfo
*snaccKeyInfo
= new SubjectPublicKeyInfo
;
860 cert
.certificateToSign
->subjectPublicKeyInfo
= snaccKeyInfo
;
861 snaccKeyInfo
->algorithm
= new AlgorithmIdentifier
;
863 /* common code to convert algorithm info (algID and parameters) */
864 const CSSM_X509_ALGORITHM_IDENTIFIER
*cssmAlgId
= &cssmKeyInfo
->algorithm
;
865 CL_cssmAlgIdToSnacc(*cssmAlgId
, *snaccKeyInfo
->algorithm
);
867 /* actual public key blob - AsnBits */
868 snaccKeyInfo
->subjectPublicKey
.Set(reinterpret_cast<char *>
869 (cssmKeyInfo
->subjectPublicKey
.Data
),
870 cssmKeyInfo
->subjectPublicKey
.Length
* 8);
873 static void freeField_PublicKeyInfo (
874 CssmOwnedData
&fieldValue
)
876 CSSM_X509_SUBJECT_PUBLIC_KEY_INFO
*cssmKeyInfo
=
877 (CSSM_X509_SUBJECT_PUBLIC_KEY_INFO
*)fieldValue
.data();
878 if(cssmKeyInfo
== NULL
) {
881 CssmAllocator
&alloc
= fieldValue
.allocator
;
882 CSSM_X509_ALGORITHM_IDENTIFIER
*algId
= &cssmKeyInfo
->algorithm
;
883 alloc
.free(algId
->algorithm
.Data
);
884 alloc
.free(algId
->parameters
.Data
);
885 alloc
.free(cssmKeyInfo
->subjectPublicKey
.Data
);
886 memset(cssmKeyInfo
, 0, sizeof(CSSM_X509_SUBJECT_PUBLIC_KEY_INFO
));}
889 *** key info from CSSM_KEY
890 *** Format = CSSM_KEY
892 static bool getField_PublicKeyStruct (
893 const DecodedCert
&cert
,
894 unsigned index
, // which occurrence (0 = first)
895 uint32
&numFields
, // RETURNED
896 CssmOwnedData
&fieldValue
) // RETURNED
898 if(!tbsGetCheck(cert
.certificateToSign
->subjectPublicKeyInfo
, index
)) {
901 CSSM_KEY_PTR cssmKey
= cert
.extractCSSMKey(fieldValue
.allocator
);
902 fieldValue
.set(reinterpret_cast<uint8
*>(cssmKey
), sizeof(CSSM_KEY
));
907 static void setField_PublicKeyStruct (
909 const CssmData
&fieldValue
)
911 /* This fails if setField_PublicKeyInfo has already been called */
912 tbsSetCheck(cert
.certificateToSign
->subjectPublicKeyInfo
, fieldValue
,
913 sizeof(CSSM_KEY
), "PubKey");
914 CSSM_KEY_PTR cssmKey
= (CSSM_KEY_PTR
)fieldValue
.data();
915 if((cssmKey
->KeyData
.Data
== NULL
) ||
916 (cssmKey
->KeyData
.Data
== 0)) {
917 CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER
);
920 SubjectPublicKeyInfo
*snaccKeyInfo
= new SubjectPublicKeyInfo
;
921 cert
.certificateToSign
->subjectPublicKeyInfo
= snaccKeyInfo
;
922 snaccKeyInfo
->algorithm
= new AlgorithmIdentifier
;
923 CL_cssmAlgToSnaccOid(cssmKey
->KeyHeader
.AlgorithmId
,
924 snaccKeyInfo
->algorithm
->algorithm
);
926 /* NULL algorithm paramneters, always in this case */
927 CL_nullAlgParams(*snaccKeyInfo
->algorithm
);
929 /* actual public key blob - AsnBits */
931 *** Note: ideally we'd like to just convert an incoming ref key to a raw
932 *** key here if necessary, but this occurs during CertCreateTemplate,
933 *** when we don't have a CSP handle. This conversion is the caller's
936 if(cssmKey
->KeyHeader
.BlobType
!= CSSM_KEYBLOB_RAW
) {
937 errorLog0("CL SetField: must specify RAW key blob\n");
938 CssmError::throwMe(CSSM_ERRCODE_INVALID_FIELD_POINTER
);
940 snaccKeyInfo
->subjectPublicKey
.Set(reinterpret_cast<char *>
941 (cssmKey
->KeyData
.Data
), cssmKey
->KeyData
.Length
* 8);
944 static void freeField_PublicKeyStruct (
945 CssmOwnedData
&fieldValue
)
947 CSSM_KEY_PTR cssmKey
= (CSSM_KEY_PTR
)fieldValue
.data();
948 CL_freeCSSMKey(cssmKey
, fieldValue
.allocator
, false);
953 *** Format = raw bytes
956 static bool getField_Signature (
957 const DecodedCert
&cert
,
958 unsigned index
, // which occurrence (0 = first)
959 uint32
&numFields
, // RETURNED
960 CssmOwnedData
&fieldValue
) // RETURNED
962 if((index
> 0) || // max of one sig
963 (cert
.signatureValue
.BitLen() == 0)) { // no sig - must be TBS only
966 SC_asnBitsToCssmData(cert
.signatureValue
, fieldValue
);
972 *** end of field-specific triplets
975 /* setField for read-only OIDs (i.e., the ones in cert, not TBS) */
976 static void setField_ReadOnly (
978 const CssmData
&fieldValue
)
980 errorLog0("Attempt to set a read-only field\n");
981 CssmError::throwMe(CSSMERR_CL_UNKNOWN_TAG
);
985 * Table to map OID to {get,set,free}field
988 const CSSM_OID
*fieldId
;
991 freeFieldFcn
*freeFcn
; // OPTIONAL - NULL means just free the
995 static const oidToFieldFuncs fieldFuncTable
[] = {
996 { &CSSMOID_X509V1Version
,
997 &getField_Version
, &setField_Version
, NULL
},
998 { &CSSMOID_X509V1SerialNumber
,
999 &getField_SerialNumber
, &setField_SerialNumber
, NULL
},
1000 { &CSSMOID_X509V1IssuerNameCStruct
,
1001 &getField_Issuer
, &setField_Issuer
, &freeField_RDN
},
1002 { &CSSMOID_X509V1SubjectNameCStruct
,
1003 &getField_Subject
, &setField_Subject
, &freeField_RDN
},
1004 { &CSSMOID_X509V1SignatureAlgorithmTBS
,
1005 &getField_TbsAlgId
, &setField_TbsAlgId
, &freeField_AlgId
},
1006 { &CSSMOID_X509V1SignatureAlgorithm
,
1007 &getField_CertAlgId
, &setField_ReadOnly
, &freeField_AlgId
},
1008 { &CSSMOID_X509V1ValidityNotBefore
,
1009 &getField_NotBefore
, &setField_NotBefore
, &freeField_Time
},
1010 { &CSSMOID_X509V1ValidityNotAfter
,
1011 &getField_NotAfter
, &setField_NotAfter
, &freeField_Time
},
1012 { &CSSMOID_X509V1CertificateIssuerUniqueId
,
1013 &getField_IssuerUniqueId
, &setField_IssuerUniqueId
, NULL
},
1014 { &CSSMOID_X509V1CertificateSubjectUniqueId
,
1015 &getField_SubjectUniqueId
, &setField_SubjectUniqueId
, NULL
},
1016 { &CSSMOID_X509V1SubjectPublicKeyCStruct
,
1017 &getField_PublicKeyInfo
, &setField_PublicKeyInfo
, &freeField_PublicKeyInfo
},
1018 { &CSSMOID_CSSMKeyStruct
,
1019 &getField_PublicKeyStruct
, &setField_PublicKeyStruct
,
1020 &freeField_PublicKeyStruct
},
1021 { &CSSMOID_X509V1Signature
,
1022 &getField_Signature
, &setField_ReadOnly
, NULL
},
1023 { &CSSMOID_X509V1IssuerName
,
1024 getFieldIssuerNorm
, &setField_ReadOnly
, NULL
},
1025 { &CSSMOID_X509V1SubjectName
,
1026 getFieldSubjectNorm
, &setField_ReadOnly
, NULL
},
1029 * Extensions, implemented in CertExtensions.cpp
1030 * When adding new ones, also add to:
1031 * -- oidToSnaccObj() in CertExtensions.cpp
1032 * -- get/set/free functions in CertExtensions.{cpp,h}
1034 { &CSSMOID_KeyUsage
, &getFieldKeyUsage
, &setFieldKeyUsage
,
1035 &freeFieldSimpleExtension
},
1036 { &CSSMOID_BasicConstraints
, &getFieldBasicConstraints
,
1037 &setFieldBasicConstraints
, &freeFieldSimpleExtension
},
1038 { &CSSMOID_ExtendedKeyUsage
, &getFieldExtKeyUsage
,
1039 &setFieldExtKeyUsage
, &freeFieldExtKeyUsage
} ,
1040 { &CSSMOID_SubjectKeyIdentifier
, &getFieldSubjectKeyId
,
1041 &setFieldSubjectKeyId
, &freeFieldSubjectKeyId
} ,
1042 { &CSSMOID_AuthorityKeyIdentifier
, &getFieldAuthorityKeyId
,
1043 &setFieldAuthorityKeyId
, &freeFieldAuthorityKeyId
} ,
1044 { &CSSMOID_SubjectAltName
, &getFieldSubjAltName
,
1045 &setFieldSubjAltName
, &freeFieldSubjAltName
} ,
1046 { &CSSMOID_CertificatePolicies
, &getFieldCertPolicies
,
1047 &setFieldCertPolicies
, &freeFieldCertPolicies
} ,
1048 { &CSSMOID_NetscapeCertType
, &getFieldNetscapeCertType
,
1049 &setFieldNetscapeCertType
, &freeFieldSimpleExtension
} ,
1050 { &CSSMOID_X509V3CertificateExtensionCStruct
, &getFieldUnknownExt
,
1051 &setFieldUnknownExt
, &freeFieldUnknownExt
}
1054 #define NUM_KNOWN_FIELDS (sizeof(fieldFuncTable) / sizeof(oidToFieldFuncs))
1055 #define NUM_STD_CERT_FIELDS 13 /* not including extensions */
1058 /* map an OID to an oidToFieldFuncs */
1059 static const oidToFieldFuncs
*oidToFields(
1060 const CssmOid
&fieldId
)
1062 const oidToFieldFuncs
*funcPtr
= fieldFuncTable
;
1064 for(unsigned i
=0; i
<NUM_KNOWN_FIELDS
; i
++) {
1065 if(fieldId
== CssmData::overlay(*funcPtr
->fieldId
)) {
1070 CssmError::throwMe(CSSMERR_CL_UNKNOWN_TAG
);
1075 *** Public functions
1079 * Obtain the index'th occurrence of field specified by fieldId in specified cert.
1080 * Format of the returned field depends on fieldId.
1081 * Returns total number of fieldId fields in the cert if index is 0.
1082 * FieldValue assumed to be empty on entry.
1083 * Returns true if specified field was found, else returns false.
1085 bool DecodedCert::getCertFieldData(
1086 const CssmOid
&fieldId
, // which field
1087 unsigned index
, // which occurrence (0 = first)
1088 uint32
&numFields
, // RETURNED
1089 CssmOwnedData
&fieldValue
) const // RETURNED
1091 CASSERT(certificateToSign
!= NULL
);
1095 errorLog0("DecodedCert::getCertField: can't parse undecoded cert!\n");
1096 CssmError::throwMe(CSSMERR_CL_INTERNAL_ERROR
);
1097 case CS_DecodedCert
:
1101 const oidToFieldFuncs
*fieldFuncs
= oidToFields(fieldId
);
1102 return fieldFuncs
->getFcn(*this, index
, numFields
, fieldValue
);
1106 * Set the field specified by fieldId in the specified Cert.
1107 * Note no index - individual field routines either append (for extensions)
1108 * or if field already set ::throwMe(for all others)
1110 void DecodedCert::setCertField(
1111 const CssmOid
&fieldId
, // which field
1112 const CssmData
&fieldValue
)
1114 CASSERT(certificateToSign
!= NULL
);
1116 case CS_Empty
: // first time thru
1117 mState
= CS_Building
;
1119 case CS_Building
: // subsequent passes
1121 case CS_DecodedCert
:
1123 errorLog0("DecodedCert::setCertField: can't build on a decoded cert!\n");
1124 CssmError::throwMe(CSSMERR_CL_INTERNAL_ERROR
);
1126 if((fieldValue
.data() == NULL
) || (fieldValue
.length() == 0)) {
1127 CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER
);
1129 const oidToFieldFuncs
*fieldFuncs
= oidToFields(fieldId
);
1130 const CssmData
&value
= CssmData::overlay(fieldValue
);
1131 fieldFuncs
->setFcn(*this, value
);
1135 * Free the fieldId-specific data referred to by fieldValue->Data.
1137 void DecodedCert::freeCertFieldData(
1138 const CssmOid
&fieldId
,
1139 CssmOwnedData
&fieldValue
)
1141 if((fieldValue
.data() == NULL
) || (fieldValue
.length() == 0)) {
1142 CssmError::throwMe(CSSM_ERRCODE_INVALID_FIELD_POINTER
);
1144 const oidToFieldFuncs
*fieldFuncs
= oidToFields(fieldId
);
1145 if(fieldFuncs
->freeFcn
!= NULL
) {
1146 /* optional - simple cases handled below */
1147 fieldFuncs
->freeFcn(fieldValue
);
1150 fieldValue
.release();
1156 * Common means to get all fields from a decoded cert. Used in
1157 * CertGetAllTemplateFields and CertGetAllFields.
1159 void DecodedCert::getAllParsedCertFields(
1160 uint32
&NumberOfFields
, // RETURNED
1161 CSSM_FIELD_PTR
&CertFields
) // RETURNED
1163 /* this is the max - some might be missing */
1164 uint32 maxFields
= NUM_STD_CERT_FIELDS
+ mNumExtensions
;
1165 CSSM_FIELD_PTR outFields
= (CSSM_FIELD_PTR
)alloc
.malloc(maxFields
* sizeof(CSSM_FIELD
));
1168 * We'll be copying oids and values for fields we find into
1169 * outFields; current number of valid fields found in numOutFields.
1171 memset(outFields
, 0, maxFields
* sizeof(CSSM_FIELD
));
1172 uint32 numOutFields
= 0;
1173 CSSM_FIELD_PTR currOutField
;
1175 const CSSM_OID
*currOid
;
1176 CssmAutoData
aData(alloc
); // for malloc/copy of outgoing data
1178 /* query for each OID we know about */
1179 for(currOidDex
=0; currOidDex
<NUM_KNOWN_FIELDS
; currOidDex
++) {
1180 const oidToFieldFuncs
*fieldFuncs
= &fieldFuncTable
[currOidDex
];
1181 currOid
= fieldFuncs
->fieldId
;
1182 uint32 numFields
; // for THIS oid
1185 * Return false if field not there, which is not an error here.
1186 * Actual exceptions are fatal.
1188 if(!fieldFuncs
->getFcn(*this,
1189 0, // index - looking for first one
1195 /* got some data for this oid - copy it and oid to outgoing CertFields */
1196 CASSERT(numOutFields
< maxFields
);
1197 currOutField
= &outFields
[numOutFields
];
1198 currOutField
->FieldValue
= aData
.release();
1199 aData
.copy(*currOid
);
1200 currOutField
->FieldOid
= aData
.release();
1203 /* if more fields are available for this OID, snag them too */
1204 for(uint32 fieldDex
=1; fieldDex
<numFields
; fieldDex
++) {
1205 /* note this should always succeed */
1206 bool brtn
= fieldFuncs
->getFcn(*this,
1208 numFields
, // shouldn't change
1211 errorLog0("getAllParsedCertFields: index screwup\n");
1212 CssmError::throwMe(CSSMERR_CL_INTERNAL_ERROR
);
1214 CASSERT(numOutFields
< maxFields
);
1215 currOutField
= &outFields
[numOutFields
];
1216 currOutField
->FieldValue
= aData
.release();
1217 aData
.copy(*currOid
);
1218 currOutField
->FieldOid
= aData
.release();
1220 } /* multiple fields for currOid */
1221 } /* for each known OID */
1223 NumberOfFields
= numOutFields
;
1224 CertFields
= outFields
;
1228 DecodedCert::describeFormat(
1229 CssmAllocator
&alloc
,
1230 uint32
&NumberOfFields
,
1231 CSSM_OID_PTR
&OidList
)
1233 /* malloc in app's space, do deep copy (including ->Data) */
1234 CSSM_OID_PTR oidList
= (CSSM_OID_PTR
)alloc
.malloc(
1235 NUM_KNOWN_FIELDS
* sizeof(CSSM_OID
));
1236 memset(oidList
, 0, NUM_KNOWN_FIELDS
* sizeof(CSSM_OID
));
1237 for(unsigned i
=0; i
<NUM_KNOWN_FIELDS
; i
++) {
1238 CssmAutoData
oidCopy(alloc
, *fieldFuncTable
[i
].fieldId
);
1239 oidList
[i
] = oidCopy
.release();
1241 NumberOfFields
= NUM_KNOWN_FIELDS
;