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();
274 DirectoryString
*dirStr
= NULL
;
276 buf
.InstallData(cbuf
->Access(), len
);
277 if ((val
= setjmp (env
)) == 0) {
278 tag
= BDecTag (buf
, len
, env
);
279 elmtLen
= BDecLen (buf
, len
, env
);
282 errorLog0("getField_RDN: malformed DirectoryString (1)\n");
283 /* FIXME - throw? Discard the whole cert? What? */
285 currRdn
->numberOfPairs
--;
289 /* current buf ptr is at the string value's contents. */
290 if((tag
== MAKE_TAG_ID (UNIV
, PRIM
, IA5STRING_TAG_CODE
)) ||
291 (tag
== MAKE_TAG_ID (UNIV
, CONS
, IA5STRING_TAG_CODE
))) {
292 /* any other printable types not handled by DirectoryString here */
293 valData
= buf
.DataPtr();
294 valLength
= buf
.DataLen();
300 /* from sm_x520sa.h */
302 dirStr
= new DirectoryString
;
303 if((val
= setjmp (env
)) == 0) {
304 dirStr
->BDecContent(buf
, tag
, elmtLen
, dec
, env
);
307 errorLog0("getField_RDN: malformed DirectoryString (1)\n");
308 /* FIXME - throw? Discard the whole cert? What? */
310 currRdn
->numberOfPairs
--;
313 AsnOcts
*octs
= NULL
;
314 switch(dirStr
->choiceId
) {
315 case DirectoryString::printableStringCid
:
316 octs
= dirStr
->printableString
;
318 case DirectoryString::teletexStringCid
:
319 octs
= dirStr
->teletexString
;
321 case DirectoryString::universalStringCid
:
322 octs
= dirStr
->universalString
;
324 case DirectoryString::bmpStringCid
:
325 octs
= dirStr
->bmpString
;
327 case DirectoryString::utf8StringCid
:
328 octs
= dirStr
->utf8String
;
331 /* should never happen unless DirectoryString changes */
332 errorLog1("getField_RDN: Bad DirectoryString::choiceId (%d)\n",
333 (int)dirStr
->choiceId
);
334 CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER
);
337 valLength
= octs
->Len();
338 } /* normal DirectoryString */
340 /* OK, set up outgoing CSSM_X509_TYPE_VALUE_PAIR */
341 CssmOid
&oid
= CssmOid::overlay(currAttr
->type
);
342 CL_snaccOidToCssm(att
->type
, oid
, alloc
);
343 currAttr
->valueType
= tag
>> 24;
344 currAttr
->value
.Data
= (uint8
*)alloc
.malloc(valLength
);
345 currAttr
->value
.Length
= valLength
;
346 memcpy(currAttr
->value
.Data
, valData
, valLength
);
348 rdn
->GoNext(); // snacc format
349 currAttr
++; // CDSA format
351 } /* for eact attr in rdn */
353 rdns
->GoNext(); // snacc format
354 currRdn
++; // CDSA format
355 } /* for each rdn in rdns */
360 static void setField_RDN (
362 const CssmData
&fieldValue
)
365 * The main job here is extracting attr/value pairs in CSSM format
366 * from fieldData, and converting them into arguments for NameBuilder.addATDV.
367 * Note that we're taking the default for primaryDistinguished,
368 * because the CDSA CSSM_X509_TYPE_VALUE_PAIR struct doesn't allow for
371 CSSM_X509_NAME_PTR x509Name
= (CSSM_X509_NAME_PTR
)fieldValue
.data();
372 for(unsigned rdnDex
=0; rdnDex
<x509Name
->numberOfRDNs
; rdnDex
++) {
373 CSSM_X509_RDN_PTR rdn
= &x509Name
->RelativeDistinguishedName
[rdnDex
];
374 if(rdn
->numberOfPairs
!= 1) {
375 errorLog0("setField_RDN: only one a/v pair per RDN supported\n");
376 CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER
);
379 CSSM_X509_TYPE_VALUE_PAIR_PTR atv
= rdn
->AttributeTypeAndValue
;
381 oid
.Set(reinterpret_cast<char *>(atv
->type
.Data
), atv
->type
.Length
);
383 DirectoryString::ChoiceIdEnum stringType
;
384 switch(atv
->valueType
) {
385 case BER_TAG_T61_STRING
:
386 stringType
= DirectoryString::teletexStringCid
;
388 case BER_TAG_PRINTABLE_STRING
:
389 stringType
= DirectoryString::printableStringCid
;
391 case BER_TAG_PKIX_UNIVERSAL_STRING
:
392 stringType
= DirectoryString::universalStringCid
;
394 case BER_TAG_PKIX_BMP_STRING
:
395 stringType
= DirectoryString::bmpStringCid
;
397 case BER_TAG_PKIX_UTF8_STRING
:
398 stringType
= DirectoryString::utf8StringCid
;
401 errorLog1("setField_RDN: illegal tag(%d)\n", atv
->valueType
);
402 CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER
);
405 reinterpret_cast<char *>(atv
->value
.Data
),
412 /* common for issuer and subject */
413 static void freeField_RDN (
414 CssmOwnedData
&fieldValue
)
416 if(fieldValue
.data() == NULL
) {
419 if(fieldValue
.length() != sizeof(CSSM_X509_NAME
)) {
420 CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER
);
422 CssmAllocator
&alloc
= fieldValue
.allocator
;
423 CSSM_X509_NAME_PTR x509Name
= (CSSM_X509_NAME_PTR
)fieldValue
.data();
424 for(unsigned rdnDex
=0; rdnDex
<x509Name
->numberOfRDNs
; rdnDex
++) {
425 CSSM_X509_RDN_PTR rdn
= &x509Name
->RelativeDistinguishedName
[rdnDex
];
426 for(unsigned atvDex
=0; atvDex
<rdn
->numberOfPairs
; atvDex
++) {
427 CSSM_X509_TYPE_VALUE_PAIR_PTR atv
= &rdn
->AttributeTypeAndValue
[atvDex
];
428 alloc
.free(atv
->type
.Data
);
429 alloc
.free(atv
->value
.Data
);
430 memset(atv
, 0, sizeof(CSSM_X509_TYPE_VALUE_PAIR
));
432 alloc
.free(rdn
->AttributeTypeAndValue
);
433 memset(rdn
, 0, sizeof(CSSM_X509_RDN
));
435 alloc
.free(x509Name
->RelativeDistinguishedName
);
436 memset(x509Name
, 0, sizeof(CSSM_X509_NAME
));
438 /* top-level x509Name pointer freed by freeCertFieldData() */
442 static bool getField_Issuer (
443 const DecodedCert
&cert
,
444 unsigned index
, // which occurrence (0 = first)
445 uint32
&numFields
, // RETURNED
446 CssmOwnedData
&fieldValue
) // RETURNED
450 if(!tbsGetCheck(cert
.certificateToSign
->issuer
, index
)) {
454 brtn
= getField_RDN(*cert
.certificateToSign
->issuer
, numFields
, fieldValue
);
457 freeField_RDN(fieldValue
);
463 static void setField_Issuer (
465 const CssmData
&fieldValue
)
467 tbsSetCheck(cert
.certificateToSign
->issuer
, fieldValue
, sizeof(CSSM_X509_NAME
),
469 NameBuilder
*issuer
= new NameBuilder
;
470 cert
.certificateToSign
->issuer
= issuer
;
471 setField_RDN(*issuer
, fieldValue
);
475 static bool getField_Subject (
476 const DecodedCert
&cert
,
477 unsigned index
, // which occurrence (0 = first)
478 uint32
&numFields
, // RETURNED
479 CssmOwnedData
&fieldValue
) // RETURNED
481 if(!tbsGetCheck(cert
.certificateToSign
->subject
, index
)) {
486 brtn
= getField_RDN(*cert
.certificateToSign
->subject
, numFields
, fieldValue
);
489 freeField_RDN(fieldValue
);
495 static void setField_Subject (
497 const CssmData
&fieldValue
)
499 tbsSetCheck(cert
.certificateToSign
->subject
, fieldValue
, sizeof(CSSM_X509_NAME
),
501 NameBuilder
*subject
= new NameBuilder
;
502 cert
.certificateToSign
->subject
= subject
;
503 setField_RDN(*subject
, fieldValue
);
507 *** Issuer Name, Subject Name (normalized and encoded version)
508 *** Format = CSSM_DATA containing the DER encoding of the normalized name
509 *** class Name from sm_x501if
512 /* first, the common code */
513 static bool getField_normRDN (
515 uint32
&numFields
, // RETURNED (if successful, 0 or 1)
516 CssmOwnedData
&fieldValue
) // RETURNED
519 * First step is to make a copy of the existing name. The easiest way to do
520 * this is to encode and decode.
522 CssmAllocator
&alloc
= fieldValue
.allocator
;
523 CssmAutoData
encodedName1(alloc
);
524 /* FIXME - should SC_encodeAsnObj() take a const AsnType & ? */
525 SC_encodeAsnObj(const_cast<Name
&>(name
), encodedName1
, MAX_RDN_SIZE
);
527 SC_decodeAsnObj(encodedName1
, decodedName
);
530 CL_normalizeX509Name(decodedName
, alloc
);
533 SC_encodeAsnObj(decodedName
, fieldValue
, MAX_RDN_SIZE
);
538 static bool getFieldSubjectNorm(
539 const DecodedCert
&cert
,
540 unsigned index
, // which occurrence (0 = first)
541 uint32
&numFields
, // RETURNED
542 CssmOwnedData
&fieldValue
) // RETURNED
544 if(!tbsGetCheck(cert
.certificateToSign
->subject
, index
)) {
547 return getField_normRDN(*cert
.certificateToSign
->subject
, numFields
, fieldValue
);
550 static bool getFieldIssuerNorm(
551 const DecodedCert
&cert
,
552 unsigned index
, // which occurrence (0 = first)
553 uint32
&numFields
, // RETURNED
554 CssmOwnedData
&fieldValue
) // RETURNED
556 if(!tbsGetCheck(cert
.certificateToSign
->issuer
, index
)) {
559 return getField_normRDN(*cert
.certificateToSign
->issuer
, numFields
, fieldValue
);
564 *** TBS AlgId, Signature AlgId
565 *** Format = CSSM_X509_ALGORITHM_IDENTIFIER
569 static void getField_AlgId (
570 const AlgorithmIdentifier
*snaccAlgId
,
571 CssmOwnedData
&fieldValue
) // RETURNED
573 CssmAllocator
&alloc
= fieldValue
.allocator
;
574 fieldValue
.malloc(sizeof(CSSM_X509_ALGORITHM_IDENTIFIER
));
575 CSSM_X509_ALGORITHM_IDENTIFIER
*cssmAlgId
=
576 (CSSM_X509_ALGORITHM_IDENTIFIER
*)fieldValue
.data();
577 CL_snaccAlgIdToCssm (*snaccAlgId
, *cssmAlgId
, alloc
);
580 static void setField_AlgId (
581 AlgorithmIdentifier
*snaccAlgId
,
582 const CssmData
&fieldValue
)
584 CSSM_X509_ALGORITHM_IDENTIFIER
*cssmAlgId
=
585 (CSSM_X509_ALGORITHM_IDENTIFIER
*)fieldValue
.data();
586 if(cssmAlgId
->algorithm
.Data
== NULL
) {
587 CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER
);
589 CL_cssmAlgIdToSnacc(*cssmAlgId
, *snaccAlgId
);
592 static void freeField_AlgId (
593 CssmOwnedData
&fieldValue
)
595 CSSM_X509_ALGORITHM_IDENTIFIER
*cssmAlgId
=
596 (CSSM_X509_ALGORITHM_IDENTIFIER
*)fieldValue
.data();
597 if(cssmAlgId
== NULL
) {
600 if(fieldValue
.length() != sizeof(CSSM_X509_ALGORITHM_IDENTIFIER
)) {
601 CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER
);
603 CssmAllocator
&alloc
= fieldValue
.allocator
;
604 alloc
.free(cssmAlgId
->algorithm
.Data
);
605 alloc
.free(cssmAlgId
->parameters
.Data
);
606 memset(cssmAlgId
, 0, sizeof(CSSM_X509_ALGORITHM_IDENTIFIER
));
611 static bool getField_TbsAlgId (
612 const DecodedCert
&cert
,
613 unsigned index
, // which occurrence (0 = first)
614 uint32
&numFields
, // RETURNED
615 CssmOwnedData
&fieldValue
) // RETURNED
617 AlgorithmIdentifier
*snaccAlgId
= cert
.certificateToSign
->signature
;
618 if(!tbsGetCheck(snaccAlgId
, index
)) {
621 getField_AlgId(snaccAlgId
, fieldValue
);
626 static void setField_TbsAlgId (
628 const CssmData
&fieldValue
)
630 tbsSetCheck(cert
.certificateToSign
->signature
, fieldValue
,
631 sizeof(CSSM_X509_ALGORITHM_IDENTIFIER
), "TBS_AlgId");
632 AlgorithmIdentifier
*snaccAlgId
= new AlgorithmIdentifier
;
633 cert
.certificateToSign
->signature
= snaccAlgId
;
634 setField_AlgId(snaccAlgId
, fieldValue
);
637 /* Cert AlgId - read only */
638 static bool getField_CertAlgId (
639 const DecodedCert
&cert
,
640 unsigned index
, // which occurrence (0 = first)
641 uint32
&numFields
, // RETURNED
642 CssmOwnedData
&fieldValue
) // RETURNED
644 AlgorithmIdentifier
*snaccAlgId
= cert
.algorithmIdentifier
;
645 if(!tbsGetCheck(snaccAlgId
, index
)) {
648 getField_AlgId(snaccAlgId
, fieldValue
);
654 *** Validity not before, not after
655 *** Format: CSSM_X509_TIME
658 /*** common code ***/
659 static void getField_Time (
660 const Time
*snaccTime
,
661 CssmOwnedData
&fieldValue
) // RETURNED
663 CssmAllocator
&alloc
= fieldValue
.allocator
;
664 fieldValue
.malloc(sizeof(CSSM_X509_TIME
));
665 CSSM_X509_TIME
*cssmTime
=
666 (CSSM_X509_TIME
*)fieldValue
.data();
667 memset(cssmTime
, 0, sizeof(CSSM_X509_TIME
));
669 char *timeStr
= NULL
;
671 switch(snaccTime
->choiceId
) {
672 case Time::utcTimeCid
:
673 cssmTime
->timeType
= BER_TAG_UTC_TIME
;
674 timeStr
= *snaccTime
->utcTime
; // an AsnOct
675 timeStrLen
= snaccTime
->utcTime
->Len();
677 case Time::generalizedTimeCid
:
678 timeStr
= *snaccTime
->generalizedTime
; // an AsnOct
679 timeStrLen
= snaccTime
->generalizedTime
->Len();
680 cssmTime
->timeType
= BER_TAG_GENERALIZED_TIME
;
683 /* snacc error, should never happen */
684 cssmTime
->timeType
= BER_TAG_OCTET_STRING
;
685 timeStr
= *snaccTime
->generalizedTime
; // an AsnOct
686 timeStrLen
= snaccTime
->generalizedTime
->Len();
690 cssmTime
->time
.Data
= reinterpret_cast<uint8
*>(alloc
.malloc(timeStrLen
));
691 cssmTime
->time
.Length
= timeStrLen
;
692 memcpy(cssmTime
->time
.Data
, timeStr
, timeStrLen
);
695 static void setField_Time (
697 const CssmData
&fieldValue
)
699 CSSM_X509_TIME
*cssmTime
=
700 (CSSM_X509_TIME
*)fieldValue
.data();
701 const char *tStr
= reinterpret_cast<const char *>(cssmTime
->time
.Data
);
702 size_t tLen
= cssmTime
->time
.Length
;
704 switch(cssmTime
->timeType
) {
705 case BER_TAG_GENERALIZED_TIME
:
706 snaccTime
->choiceId
= Time::generalizedTimeCid
;
707 snaccTime
->generalizedTime
= new GeneralizedTime(tStr
, tLen
);
709 case BER_TAG_UTC_TIME
:
710 snaccTime
->choiceId
= Time::utcTimeCid
;
711 snaccTime
->utcTime
= new UTCTime(tStr
, tLen
);
714 errorLog1("setField_Time: bad time tag (%d)\n", cssmTime
->timeType
);
715 CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER
);
719 static void freeField_Time (
720 CssmOwnedData
&fieldValue
)
722 CSSM_X509_TIME
*cssmTime
= (CSSM_X509_TIME
*)fieldValue
.data();
723 if(cssmTime
== NULL
) {
726 if(fieldValue
.length() != sizeof(CSSM_X509_TIME
)) {
727 CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER
);
729 fieldValue
.allocator
.free(cssmTime
->time
.Data
);
730 memset(cssmTime
, 0, sizeof(CSSM_X509_TIME
));
734 static bool getField_NotBefore (
735 const DecodedCert
&cert
,
736 unsigned index
, // which occurrence (0 = first)
737 uint32
&numFields
, // RETURNED
738 CssmOwnedData
&fieldValue
) // RETURNED
740 if(!tbsGetCheck(cert
.certificateToSign
->validity
, index
)) {
743 if(cert
.certificateToSign
->validity
->notBefore
== NULL
) {
746 getField_Time(cert
.certificateToSign
->validity
->notBefore
, fieldValue
);
751 static void setField_NotBefore (
753 const CssmData
&fieldValue
)
755 /* anything could need mallocing except TBS */
756 if(cert
.certificateToSign
->validity
== NULL
) {
757 cert
.certificateToSign
->validity
= new Validity
;
759 tbsSetCheck(cert
.certificateToSign
->validity
->notBefore
, fieldValue
,
760 sizeof(CSSM_X509_TIME
), "NotBefore");
761 cert
.certificateToSign
->validity
->notBefore
= new Time
;
762 setField_Time(cert
.certificateToSign
->validity
->notBefore
, fieldValue
);
766 static bool getField_NotAfter (
767 const DecodedCert
&cert
,
768 unsigned index
, // which occurrence (0 = first)
769 uint32
&numFields
, // RETURNED
770 CssmOwnedData
&fieldValue
) // RETURNED
772 if(!tbsGetCheck(cert
.certificateToSign
->validity
, index
)) {
775 if(cert
.certificateToSign
->validity
->notAfter
== NULL
) {
778 getField_Time(cert
.certificateToSign
->validity
->notAfter
, fieldValue
);
783 static void setField_NotAfter (
785 const CssmData
&fieldValue
)
787 /* anything could need mallocing except TBS */
788 if(cert
.certificateToSign
->validity
== NULL
) {
789 cert
.certificateToSign
->validity
= new Validity
;
791 tbsSetCheck(cert
.certificateToSign
->validity
->notAfter
, fieldValue
,
792 sizeof(CSSM_X509_TIME
), "NotAfter");
793 cert
.certificateToSign
->validity
->notAfter
= new Time
;
794 setField_Time(cert
.certificateToSign
->validity
->notAfter
, fieldValue
);
798 *** Subject/issuer unique ID
799 *** Format: Raw bytes. It's stored in the cert as an ASN bit string; the decoded
800 *** bytes are present at this level (i.e., not tag and length in the bytes).
801 *** NOTE: this is not quite accurate in that we only provide byte-aligned size,
802 *** not bit-aligned. This field is rarely if ever used so I think it's O, but
805 static bool getField_SubjectUniqueId (
806 const DecodedCert
&cert
,
807 unsigned index
, // which occurrence (0 = first)
808 uint32
&numFields
, // RETURNED
809 CssmOwnedData
&fieldValue
) // RETURNED
811 UniqueIdentifier
*id
= cert
.certificateToSign
->subjectUniqueIdentifier
;
812 if(!tbsGetCheck(id
, index
)) {
815 SC_asnBitsToCssmData(*id
, fieldValue
);
820 static void setField_SubjectUniqueId (
822 const CssmData
&fieldValue
)
824 tbsSetCheck(cert
.certificateToSign
->subjectUniqueIdentifier
, fieldValue
, 0,
826 cert
.certificateToSign
->subjectUniqueIdentifier
= new UniqueIdentifier(
827 reinterpret_cast<char * const>(fieldValue
.Data
), fieldValue
.Length
* 8);
830 static bool getField_IssuerUniqueId (
831 const DecodedCert
&cert
,
832 unsigned index
, // which occurrence (0 = first)
833 uint32
&numFields
, // RETURNED
834 CssmOwnedData
&fieldValue
) // RETURNED
836 UniqueIdentifier
*id
= cert
.certificateToSign
->issuerUniqueIdentifier
;
837 if(!tbsGetCheck(id
, index
)) {
840 SC_asnBitsToCssmData(*id
, fieldValue
);
845 static void setField_IssuerUniqueId (
847 const CssmData
&fieldValue
)
849 tbsSetCheck(cert
.certificateToSign
->issuerUniqueIdentifier
, fieldValue
, 0,
851 cert
.certificateToSign
->issuerUniqueIdentifier
= new UniqueIdentifier(
852 reinterpret_cast<char * const>(fieldValue
.Data
), fieldValue
.Length
* 8);
857 *** Format = CSSM_X509_SUBJECT_PUBLIC_KEY_INFO
859 static bool getField_PublicKeyInfo (
860 const DecodedCert
&cert
,
861 unsigned index
, // which occurrence (0 = first)
862 uint32
&numFields
, // RETURNED
863 CssmOwnedData
&fieldValue
) // RETURNED
865 if(!tbsGetCheck(cert
.certificateToSign
->subjectPublicKeyInfo
, index
)) {
868 SubjectPublicKeyInfo
*snaccKeyInfo
= cert
.certificateToSign
->subjectPublicKeyInfo
;
869 AlgorithmIdentifier
*snaccAlgId
= snaccKeyInfo
->algorithm
;
870 if(snaccAlgId
== NULL
) {
871 errorLog0("getField_PublicKeyInfo: cert has pubKeyInfo but no algorithm!\n");
874 CssmAllocator
&alloc
= fieldValue
.allocator
;
875 fieldValue
.malloc(sizeof(CSSM_X509_SUBJECT_PUBLIC_KEY_INFO
));
876 CSSM_X509_SUBJECT_PUBLIC_KEY_INFO
*cssmKeyInfo
=
877 (CSSM_X509_SUBJECT_PUBLIC_KEY_INFO
*)fieldValue
.data();
878 memset(cssmKeyInfo
, 0, sizeof(CSSM_X509_SUBJECT_PUBLIC_KEY_INFO
));
879 CL_snaccAlgIdToCssm(*snaccAlgId
, cssmKeyInfo
->algorithm
, alloc
);
882 * key info - the actual public key blob - is stored in the cert as a bit string;
883 * snacc will give us the actual bits which are invariably yet another DER
884 * encoding (e.g., PKCS1 for RSA public keys).
886 size_t keyLen
= (snaccKeyInfo
->subjectPublicKey
.BitLen() + 7) / 8;
887 cssmKeyInfo
->subjectPublicKey
.Data
= (uint8
*)alloc
.malloc(keyLen
);
888 cssmKeyInfo
->subjectPublicKey
.Length
= keyLen
;
889 memcpy(cssmKeyInfo
->subjectPublicKey
.Data
,
890 snaccKeyInfo
->subjectPublicKey
.BitOcts(),
896 static void setField_PublicKeyInfo (
898 const CssmData
&fieldValue
)
900 /* This fails if setField_PublicKeyStruct has already been called */
901 tbsSetCheck(cert
.certificateToSign
->subjectPublicKeyInfo
, fieldValue
,
902 sizeof(CSSM_X509_SUBJECT_PUBLIC_KEY_INFO
), "PubKeyInfo");
903 CSSM_X509_SUBJECT_PUBLIC_KEY_INFO
*cssmKeyInfo
=
904 (CSSM_X509_SUBJECT_PUBLIC_KEY_INFO
*)fieldValue
.Data
;
905 if((cssmKeyInfo
->subjectPublicKey
.Data
== NULL
) ||
906 (cssmKeyInfo
->subjectPublicKey
.Length
== 0)) {
907 CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER
);
910 SubjectPublicKeyInfo
*snaccKeyInfo
= new SubjectPublicKeyInfo
;
911 cert
.certificateToSign
->subjectPublicKeyInfo
= snaccKeyInfo
;
912 snaccKeyInfo
->algorithm
= new AlgorithmIdentifier
;
914 /* common code to convert algorithm info (algID and parameters) */
915 const CSSM_X509_ALGORITHM_IDENTIFIER
*cssmAlgId
= &cssmKeyInfo
->algorithm
;
916 CL_cssmAlgIdToSnacc(*cssmAlgId
, *snaccKeyInfo
->algorithm
);
918 /* actual public key blob - AsnBits */
919 snaccKeyInfo
->subjectPublicKey
.Set(reinterpret_cast<char *>
920 (cssmKeyInfo
->subjectPublicKey
.Data
),
921 cssmKeyInfo
->subjectPublicKey
.Length
);
924 static void freeField_PublicKeyInfo (
925 CssmOwnedData
&fieldValue
)
927 CSSM_X509_SUBJECT_PUBLIC_KEY_INFO
*cssmKeyInfo
=
928 (CSSM_X509_SUBJECT_PUBLIC_KEY_INFO
*)fieldValue
.data();
929 if(cssmKeyInfo
== NULL
) {
932 CssmAllocator
&alloc
= fieldValue
.allocator
;
933 CSSM_X509_ALGORITHM_IDENTIFIER
*algId
= &cssmKeyInfo
->algorithm
;
934 alloc
.free(algId
->algorithm
.Data
);
935 alloc
.free(algId
->parameters
.Data
);
936 alloc
.free(cssmKeyInfo
->subjectPublicKey
.Data
);
937 memset(cssmKeyInfo
, 0, sizeof(CSSM_X509_SUBJECT_PUBLIC_KEY_INFO
));}
940 *** key info from CSSM_KEY
941 *** Format = CSSM_KEY
943 static bool getField_PublicKeyStruct (
944 const DecodedCert
&cert
,
945 unsigned index
, // which occurrence (0 = first)
946 uint32
&numFields
, // RETURNED
947 CssmOwnedData
&fieldValue
) // RETURNED
949 if(!tbsGetCheck(cert
.certificateToSign
->subjectPublicKeyInfo
, index
)) {
952 CSSM_KEY_PTR cssmKey
= cert
.extractCSSMKey(fieldValue
.allocator
);
953 fieldValue
.set(reinterpret_cast<uint8
*>(cssmKey
), sizeof(CSSM_KEY
));
958 static void setField_PublicKeyStruct (
960 const CssmData
&fieldValue
)
962 /* This fails if setField_PublicKeyInfo has already been called */
963 tbsSetCheck(cert
.certificateToSign
->subjectPublicKeyInfo
, fieldValue
,
964 sizeof(CSSM_KEY
), "PubKey");
965 CSSM_KEY_PTR cssmKey
= (CSSM_KEY_PTR
)fieldValue
.data();
966 if((cssmKey
->KeyData
.Data
== NULL
) ||
967 (cssmKey
->KeyData
.Data
== 0)) {
968 CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER
);
971 SubjectPublicKeyInfo
*snaccKeyInfo
= new SubjectPublicKeyInfo
;
972 cert
.certificateToSign
->subjectPublicKeyInfo
= snaccKeyInfo
;
973 snaccKeyInfo
->algorithm
= new AlgorithmIdentifier
;
974 CL_cssmAlgToSnaccOid(cssmKey
->KeyHeader
.AlgorithmId
,
975 snaccKeyInfo
->algorithm
->algorithm
);
977 /* NULL algorithm paramneters, always in this case */
978 CL_nullAlgParams(*snaccKeyInfo
->algorithm
);
980 /* actual public key blob - AsnBits */
982 *** TBD FIXME if this key is a ref key, null wrap it to a raw key
984 if(cssmKey
->KeyHeader
.BlobType
!= CSSM_KEYBLOB_RAW
) {
985 errorLog0("CL SetField: must specify RAW key blob\n");
986 CssmError::throwMe(CSSM_ERRCODE_INVALID_FIELD_POINTER
);
988 snaccKeyInfo
->subjectPublicKey
.Set(reinterpret_cast<char *>
989 (cssmKey
->KeyData
.Data
), cssmKey
->KeyData
.Length
* 8);
992 static void freeField_PublicKeyStruct (
993 CssmOwnedData
&fieldValue
)
995 CSSM_KEY_PTR cssmKey
= (CSSM_KEY_PTR
)fieldValue
.data();
996 DecodedCert::freeCSSMKey(cssmKey
, fieldValue
.allocator
, false);
1001 *** Format = raw bytes
1004 static bool getField_Signature (
1005 const DecodedCert
&cert
,
1006 unsigned index
, // which occurrence (0 = first)
1007 uint32
&numFields
, // RETURNED
1008 CssmOwnedData
&fieldValue
) // RETURNED
1010 if((index
> 0) || // max of one sig
1011 (cert
.signatureValue
.BitLen() == 0)) { // no sig - must be TBS only
1014 SC_asnBitsToCssmData(cert
.signatureValue
, fieldValue
);
1020 *** end of field-specific triplets
1023 /* setField for read-only OIDs (i.e., the ones in cert, not TBS) */
1024 static void setField_ReadOnly (
1026 const CssmData
&fieldValue
)
1028 errorLog0("Attempt to set a read-only field\n");
1029 CssmError::throwMe(CSSMERR_CL_UNKNOWN_TAG
);
1033 * Table to map OID to {get,set,free}field
1036 const CSSM_OID
*fieldId
;
1037 getFieldFcn
*getFcn
;
1038 setFieldFcn
*setFcn
;
1039 freeFieldFcn
*freeFcn
; // OPTIONAL - NULL means just free the
1043 static const oidToFieldFuncs fieldFuncTable
[] = {
1044 { &CSSMOID_X509V1Version
,
1045 &getField_Version
, &setField_Version
, NULL
},
1046 { &CSSMOID_X509V1SerialNumber
,
1047 &getField_SerialNumber
, &setField_SerialNumber
, NULL
},
1048 { &CSSMOID_X509V1IssuerNameCStruct
,
1049 &getField_Issuer
, &setField_Issuer
, &freeField_RDN
},
1050 { &CSSMOID_X509V1SubjectNameCStruct
,
1051 &getField_Subject
, &setField_Subject
, &freeField_RDN
},
1052 { &CSSMOID_X509V1SignatureAlgorithmTBS
,
1053 &getField_TbsAlgId
, &setField_TbsAlgId
, &freeField_AlgId
},
1054 { &CSSMOID_X509V1SignatureAlgorithm
,
1055 &getField_CertAlgId
, &setField_ReadOnly
, &freeField_AlgId
},
1056 { &CSSMOID_X509V1ValidityNotBefore
,
1057 &getField_NotBefore
, &setField_NotBefore
, &freeField_Time
},
1058 { &CSSMOID_X509V1ValidityNotAfter
,
1059 &getField_NotAfter
, &setField_NotAfter
, &freeField_Time
},
1060 { &CSSMOID_X509V1CertificateIssuerUniqueId
,
1061 &getField_IssuerUniqueId
, &setField_IssuerUniqueId
, NULL
},
1062 { &CSSMOID_X509V1CertificateSubjectUniqueId
,
1063 &getField_SubjectUniqueId
, &setField_SubjectUniqueId
, NULL
},
1064 { &CSSMOID_X509V1SubjectPublicKeyCStruct
,
1065 &getField_PublicKeyInfo
, &setField_PublicKeyInfo
, &freeField_PublicKeyInfo
},
1066 { &CSSMOID_CSSMKeyStruct
,
1067 &getField_PublicKeyStruct
, &setField_PublicKeyStruct
,
1068 &freeField_PublicKeyStruct
},
1069 { &CSSMOID_X509V1Signature
,
1070 &getField_Signature
, &setField_ReadOnly
, NULL
},
1071 { &CSSMOID_X509V1IssuerName
,
1072 getFieldIssuerNorm
, &setField_ReadOnly
, NULL
},
1073 { &CSSMOID_X509V1SubjectName
,
1074 getFieldSubjectNorm
, &setField_ReadOnly
, NULL
},
1077 * Extensions, implemented in CertExtensions.cpp
1078 * When adding new ones, also add to:
1079 * -- oidToSnaccObj() in CertExtensions.cpp
1080 * -- get/set/free functions in CertExtensions.{cpp,h}
1082 { &CSSMOID_KeyUsage
, &getFieldKeyUsage
, &setFieldKeyUsage
,
1083 &freeFieldSimpleExtension
},
1084 { &CSSMOID_BasicConstraints
, &getFieldBasicConstraints
,
1085 &setFieldBasicConstraints
, &freeFieldSimpleExtension
},
1086 { &CSSMOID_ExtendedKeyUsage
, &getFieldExtKeyUsage
,
1087 &setFieldExtKeyUsage
, &freeFieldExtKeyUsage
} ,
1088 { &CSSMOID_SubjectKeyIdentifier
, &getFieldSubjectKeyId
,
1089 &setFieldSubjectKeyId
, &freeFieldSubjectKeyId
} ,
1090 { &CSSMOID_AuthorityKeyIdentifier
, &getFieldAuthorityKeyId
,
1091 &setFieldAuthorityKeyId
, &freeFieldAuthorityKeyId
} ,
1092 { &CSSMOID_SubjectAltName
, &getFieldSubjAltName
,
1093 &setFieldSubjAltName
, &freeFieldSubjAltName
} ,
1094 { &CSSMOID_CertificatePolicies
, &getFieldCertPolicies
,
1095 &setFieldCertPolicies
, &freeFieldCertPolicies
} ,
1096 { &CSSMOID_NetscapeCertType
, &getFieldNetscapeCertType
,
1097 &setFieldNetscapeCertType
, &freeFieldSimpleExtension
} ,
1098 { &CSSMOID_X509V3CertificateExtensionCStruct
, &getFieldUnknownExt
,
1099 &setFieldUnknownExt
, &freeFieldUnknownExt
}
1102 #define NUM_KNOWN_FIELDS (sizeof(fieldFuncTable) / sizeof(oidToFieldFuncs))
1103 #define NUM_STD_CERT_FIELDS 13 /* not including extensions */
1106 /* map an OID to an oidToFieldFuncs */
1107 static const oidToFieldFuncs
*oidToFields(
1108 const CssmOid
&fieldId
)
1110 const oidToFieldFuncs
*funcPtr
= fieldFuncTable
;
1112 for(unsigned i
=0; i
<NUM_KNOWN_FIELDS
; i
++) {
1113 if(fieldId
== CssmData::overlay(*funcPtr
->fieldId
)) {
1118 CssmError::throwMe(CSSMERR_CL_UNKNOWN_TAG
);
1123 *** Public functions
1127 * Obtain the index'th occurrence of field specified by fieldId in specified cert.
1128 * Format of the returned field depends on fieldId.
1129 * Returns total number of fieldId fields in the cert if index is 0.
1130 * FieldValue assumed to be empty on entry.
1131 * Returns true if specified field was found, else returns false.
1133 bool DecodedCert::getCertFieldData(
1134 const CssmOid
&fieldId
, // which field
1135 unsigned index
, // which occurrence (0 = first)
1136 uint32
&numFields
, // RETURNED
1137 CssmOwnedData
&fieldValue
) const // RETURNED
1139 CASSERT(certificateToSign
!= NULL
);
1143 errorLog0("DecodedCert::getCertField: can't parse undecoded cert!\n");
1144 CssmError::throwMe(CSSMERR_CL_INTERNAL_ERROR
);
1145 case CS_DecodedCert
:
1149 const oidToFieldFuncs
*fieldFuncs
= oidToFields(fieldId
);
1150 return fieldFuncs
->getFcn(*this, index
, numFields
, fieldValue
);
1154 * Set the field specified by fieldId in the specified Cert.
1155 * Note no index - individual field routines either append (for extensions)
1156 * or if field already set ::throwMe(for all others)
1158 void DecodedCert::setCertField(
1159 const CssmOid
&fieldId
, // which field
1160 const CssmData
&fieldValue
)
1162 CASSERT(certificateToSign
!= NULL
);
1164 case CS_Empty
: // first time thru
1165 mState
= CS_Building
;
1167 case CS_Building
: // subsequent passes
1169 case CS_DecodedCert
:
1171 errorLog0("DecodedCert::setCertField: can't build on a decoded cert!\n");
1172 CssmError::throwMe(CSSMERR_CL_INTERNAL_ERROR
);
1174 if((fieldValue
.data() == NULL
) || (fieldValue
.length() == 0)) {
1175 CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER
);
1177 const oidToFieldFuncs
*fieldFuncs
= oidToFields(fieldId
);
1178 const CssmData
&value
= CssmData::overlay(fieldValue
);
1179 fieldFuncs
->setFcn(*this, value
);
1183 * Free the fieldId-specific data referred to by fieldValue->Data.
1185 void DecodedCert::freeCertFieldData(
1186 const CssmOid
&fieldId
,
1187 CssmOwnedData
&fieldValue
)
1189 if((fieldValue
.data() == NULL
) || (fieldValue
.length() == 0)) {
1190 CssmError::throwMe(CSSM_ERRCODE_INVALID_FIELD_POINTER
);
1192 const oidToFieldFuncs
*fieldFuncs
= oidToFields(fieldId
);
1193 if(fieldFuncs
->freeFcn
!= NULL
) {
1194 /* optional - simple cases handled below */
1195 fieldFuncs
->freeFcn(fieldValue
);
1198 fieldValue
.release();
1204 * Common means to get all fields from a decoded cert. Used in
1205 * CertGetAllTemplateFields and CertGetAllFields.
1207 void DecodedCert::getAllParsedCertFields(
1208 uint32
&NumberOfFields
, // RETURNED
1209 CSSM_FIELD_PTR
&CertFields
) // RETURNED
1211 /* this is the max - some might be missing */
1212 uint32 maxFields
= NUM_STD_CERT_FIELDS
+ mNumExtensions
;
1213 CSSM_FIELD_PTR outFields
= (CSSM_FIELD_PTR
)malloc(maxFields
* sizeof(CSSM_FIELD
));
1216 * We'll be copying oids and values for fields we find into
1217 * outFields; current number of valid fields found in numOutFields.
1219 memset(outFields
, 0, maxFields
* sizeof(CSSM_FIELD
));
1220 uint32 numOutFields
= 0;
1221 CSSM_FIELD_PTR currOutField
;
1223 const CSSM_OID
*currOid
;
1224 CssmAutoData
aData(alloc
); // for malloc/copy of outgoing data
1226 /* query for each OID we know about */
1227 for(currOidDex
=0; currOidDex
<NUM_KNOWN_FIELDS
; currOidDex
++) {
1228 const oidToFieldFuncs
*fieldFuncs
= &fieldFuncTable
[currOidDex
];
1229 currOid
= fieldFuncs
->fieldId
;
1230 uint32 numFields
; // for THIS oid
1233 * Return false if field not there, which is not an error here.
1234 * Actual exceptions are fatal.
1236 if(!fieldFuncs
->getFcn(*this,
1237 0, // index - looking for first one
1243 /* got some data for this oid - copy it and oid to outgoing CertFields */
1244 CASSERT(numOutFields
< maxFields
);
1245 currOutField
= &outFields
[numOutFields
];
1246 currOutField
->FieldValue
= aData
.release();
1247 aData
.copy(*currOid
);
1248 currOutField
->FieldOid
= aData
.release();
1251 /* if more fields are available for this OID, snag them too */
1252 for(uint32 fieldDex
=1; fieldDex
<numFields
; fieldDex
++) {
1253 /* note this should always succeed */
1254 bool brtn
= fieldFuncs
->getFcn(*this,
1256 numFields
, // shouldn't change
1259 errorLog0("getAllParsedCertFields: index screwup\n");
1260 CssmError::throwMe(CSSMERR_CL_INTERNAL_ERROR
);
1262 CASSERT(numOutFields
< maxFields
);
1263 currOutField
= &outFields
[numOutFields
];
1264 currOutField
->FieldValue
= aData
.release();
1265 aData
.copy(*currOid
);
1266 currOutField
->FieldOid
= aData
.release();
1268 } /* multiple fields for currOid */
1269 } /* for each known OID */
1271 NumberOfFields
= numOutFields
;
1272 CertFields
= outFields
;
1276 DecodedCert::describeFormat(
1277 CssmAllocator
&alloc
,
1278 uint32
&NumberOfFields
,
1279 CSSM_OID_PTR
&OidList
)
1281 /* malloc in app's space, do deep copy (including ->Data) */
1282 CSSM_OID_PTR oidList
= (CSSM_OID_PTR
)alloc
.malloc(
1283 NUM_KNOWN_FIELDS
* sizeof(CSSM_OID
));
1284 memset(oidList
, 0, NUM_KNOWN_FIELDS
* sizeof(CSSM_OID
));
1285 for(unsigned i
=0; i
<NUM_KNOWN_FIELDS
; i
++) {
1286 CssmAutoData
oidCopy(alloc
, *fieldFuncTable
[i
].fieldId
);
1287 oidList
[i
] = oidCopy
.release();
1289 NumberOfFields
= NUM_KNOWN_FIELDS
;