]> git.saurik.com Git - apple/security.git/blob - AppleX509CL/CertFields.cpp
5d3f62274e5552faadd4a204c0308cd429cdd4d6
[apple/security.git] / AppleX509CL / CertFields.cpp
1 /*
2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
3 *
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
8 * using this file.
9 *
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.
16 */
17
18
19 /*
20 * CertFields.cpp - convert between snacc-based Certificate components and CDSA-style
21 * fields. A major component of DecodedCert.
22 *
23 * Created 9/1/2000 by Doug Mitchell.
24 * Copyright (c) 2000 by Apple Computer.
25 *
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.
29 */
30
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>
41
42 /*
43 * Routines for common validity checking for certificateToSign fields.
44 *
45 * Call from setField*: verify field isn't already set, optionally validate
46 * input length
47 */
48 static void tbsSetCheck(
49 void *fieldToSet,
50 const CssmData &fieldValue,
51 uint32 expLength,
52 const char *op)
53 {
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);
58 }
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);
63 }
64 }
65
66 /*
67 * Call from getField* for unique fields - detect missing field or index out of bounds.
68 */
69 static bool tbsGetCheck(
70 void *requiredField,
71 uint32 reqIndex)
72 {
73 if((requiredField == NULL) || (reqIndex != 0)) {
74 return false;
75 }
76 else {
77 return true;
78 }
79 }
80
81 /***
82 *** Version
83 *** Format = DER-encoded int (max of four bytes in this case)
84 ***/
85 static bool getField_Version (
86 const DecodedCert &cert,
87 unsigned index, // which occurrence (0 = first)
88 uint32 &numFields, // RETURNED
89 CssmOwnedData &fieldValue) // RETURNED
90 {
91 if(!tbsGetCheck(cert.certificateToSign->version, index)) {
92 return false;
93 }
94
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;
101 uvers >>= 8;
102 }
103 fieldValue.copy(chars, sizeof(uint32));
104 numFields = 1;
105 return true;
106 }
107
108 static void setField_Version (
109 DecodedCert &cert,
110 const CssmData &fieldValue)
111 {
112 tbsSetCheck(cert.certificateToSign->version, fieldValue, 0, "version");
113
114 /* get big-endian int from *fieldValue.Data */
115 if(fieldValue.length() > sizeof(unsigned)) {
116 CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER);
117 }
118 uint32 vers = 0;
119 uint8 *cp = fieldValue;
120 for(unsigned i=0; i<fieldValue.length(); i++) {
121 vers <<= 8;
122 vers |= cp[i];
123 }
124 cert.certificateToSign->version = new Version((int)vers);
125 cert.certificateToSign->version->Set((int)vers);
126 }
127
128
129 #if this_is_a_template
130 /***
131 *** Version
132 *** Format = DER-encoded int (always four bytes in this case)
133 ***/
134 static bool getField_Version (
135 const DecodedCert &cert,
136 unsigned index, // which occurrence (0 = first)
137 uint32 &numFields, // RETURNED
138 CssmOwnedData &fieldValue) // RETURNED
139 {
140 tbsGetCheck(cert.certificateToSign->version, index);
141 }
142 static void setField_Version (
143 DecodedCert &cert,
144 const CssmData &fieldValue)
145 {
146 tbsSetCheck(cert.certificateToSign->version, fieldValue, sizeof(uint32),
147 "version");
148
149 }
150 static void freeField_Version (
151 CssmOwnedData &fieldValue)
152 {
153 }
154 #endif
155
156 /***
157 *** Serial Number
158 *** Format = DER-encoded int, variable length
159 ***/
160 static bool getField_SerialNumber (
161 const DecodedCert &cert,
162 unsigned index, // which occurrence (0 = first)
163 uint32 &numFields, // RETURNED
164 CssmOwnedData &fieldValue) // RETURNED
165 {
166 if(index > 0) {
167 return false;
168 }
169
170 char *cp = cert.certificateToSign->serialNumber;
171 uint32 len = cert.certificateToSign->serialNumber.Len();
172 fieldValue.copy(cp, len);
173 numFields = 1;
174 return true;
175 }
176
177 static void setField_SerialNumber (
178 DecodedCert &cert,
179 const CssmData &fieldValue)
180 {
181 cert.certificateToSign->serialNumber.Set(fieldValue, fieldValue.Length);
182 }
183
184 /***
185 *** Issuer Name, Subject Name (C struct version)
186 *** Format = CSSM_X509_NAME
187 *** class Name from sm_x501if
188 ***/
189
190 /* first, the common code */
191 static bool getField_RDN (
192 const Name &name,
193 uint32 &numFields, // RETURNED (if successful, 0 or 1)
194 CssmOwnedData &fieldValue) // RETURNED
195 {
196 RDNSequence *rdns = name.rDNSequence;
197 int numRdns = rdns->Count();
198 if((rdns == NULL) || (numRdns == 0)) {
199 /* not technically an error */
200 return false;
201 }
202
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);
213
214 rdns->SetCurrElmt(0);
215 for(int rdnDex=0; rdnDex<numRdns; rdnDex++) {
216 /* from sm_x501if */
217 RelativeDistinguishedName *rdn = rdns->Curr();
218 if(rdn == NULL) {
219 /* not sure how this can happen... */
220 dprintf1("getField_RDN: NULL rdn at index %d\n", rdnDex);
221
222 /* next snacc RDN but keep CDSA position unchanged */
223 rdns->GoNext(); // snacc format
224 x509Name->numberOfRDNs--; // since we're skipping one
225 continue;
226 }
227 int numAttrs = rdn->Count();
228 if(numAttrs == 0) {
229 dprintf1("getField_RDN: zero numAttrs at index %d\n", rdnDex);
230 rdns->GoNext();
231 x509Name->numberOfRDNs--; // since we're skipping one
232 continue;
233 }
234
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);
241
242 /* descend into array of attribute/values */
243 rdn->SetCurrElmt(0);
244 for(int attrDex=0; attrDex<numAttrs; attrDex++) {
245 /* from sm_x501if */
246 AttributeTypeAndDistinguishedValue *att = rdn->Curr();
247 if(att == NULL) {
248 /* not sure how this can happen... */
249 dprintf1("getField_RDN: NULL att at index %d\n", attrDex);
250 rdn->GoNext();
251 currRdn->numberOfPairs--;
252 continue;
253 }
254
255 /*
256 * Convert snacc-style AttributeTypeAndDistinguishedValue to
257 * CSSM-style CSSM_X509_TYPE_VALUE_PAIR
258 *
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.
264 */
265 CSM_Buffer *cbuf = att->value.value;
266 AsnBuf buf;
267 AsnLen len = cbuf->Length();
268 AsnTag tag;
269 AsnLen elmtLen;
270 ENV_TYPE env;
271 char *valData;
272 int valLength;
273 DirectoryString *dirStr = NULL;
274
275 buf.InstallData(cbuf->Access(), len);
276 try {
277 tag = BDecTag (buf, len, env);
278 elmtLen = BDecLen (buf, len, env);
279 }
280 catch(...) {
281 errorLog0("getField_RDN: malformed DirectoryString (1)\n");
282 /* FIXME - throw? Discard the whole cert? What? */
283 rdn->GoNext();
284 currRdn->numberOfPairs--;
285 continue;
286 }
287
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();
294 // workaround
295 delete dirStr;
296 dirStr = NULL;
297 }
298 else {
299 /* from sm_x520sa.h */
300 AsnLen dec;
301 dirStr = new DirectoryString;
302 try {
303 dirStr->BDecContent(buf, tag, elmtLen, dec, env);
304 }
305 catch(...) {
306 errorLog0("getField_RDN: malformed DirectoryString (1)\n");
307 /* FIXME - throw? Discard the whole cert? What? */
308 rdn->GoNext();
309 currRdn->numberOfPairs--;
310 continue;
311 }
312 AsnOcts *octs = NULL;
313 switch(dirStr->choiceId) {
314 case DirectoryString::printableStringCid:
315 octs = dirStr->printableString;
316 break;
317 case DirectoryString::teletexStringCid:
318 octs = dirStr->teletexString;
319 break;
320 case DirectoryString::universalStringCid:
321 octs = dirStr->universalString;
322 break;
323 case DirectoryString::bmpStringCid:
324 octs = dirStr->bmpString;
325 break;
326 case DirectoryString::utf8StringCid:
327 octs = dirStr->utf8String;
328 break;
329 default:
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);
334 }
335 valData = *octs;
336 valLength = octs->Len();
337 } /* normal DirectoryString */
338
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);
346
347 rdn->GoNext(); // snacc format
348 currAttr++; // CDSA format
349 delete dirStr;
350 } /* for eact attr in rdn */
351
352 rdns->GoNext(); // snacc format
353 currRdn++; // CDSA format
354 } /* for each rdn in rdns */
355 numFields = 1;
356 return true;
357 }
358
359 /* common for issuer and subject */
360 static void freeField_RDN (
361 CssmOwnedData &fieldValue)
362 {
363 if(fieldValue.data() == NULL) {
364 return;
365 }
366 if(fieldValue.length() != sizeof(CSSM_X509_NAME)) {
367 CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER);
368 }
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));
378 }
379 alloc.free(rdn->AttributeTypeAndValue);
380 memset(rdn, 0, sizeof(CSSM_X509_RDN));
381 }
382 alloc.free(x509Name->RelativeDistinguishedName);
383 memset(x509Name, 0, sizeof(CSSM_X509_NAME));
384
385 /* top-level x509Name pointer freed by freeCertFieldData() */
386 }
387
388 /*** issuer ***/
389 static bool getField_Issuer (
390 const DecodedCert &cert,
391 unsigned index, // which occurrence (0 = first)
392 uint32 &numFields, // RETURNED
393 CssmOwnedData &fieldValue) // RETURNED
394 {
395 bool brtn;
396
397 if(!tbsGetCheck(cert.certificateToSign->issuer, index)) {
398 return false;
399 }
400 try {
401 brtn = getField_RDN(*cert.certificateToSign->issuer, numFields, fieldValue);
402 }
403 catch (...) {
404 freeField_RDN(fieldValue);
405 throw;
406 }
407 return brtn;
408 }
409
410 static void setField_Issuer (
411 DecodedCert &cert,
412 const CssmData &fieldValue)
413 {
414 tbsSetCheck(cert.certificateToSign->issuer, fieldValue, sizeof(CSSM_X509_NAME),
415 "IssuerName");
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);
420 }
421
422 /*** subject ***/
423 static bool getField_Subject (
424 const DecodedCert &cert,
425 unsigned index, // which occurrence (0 = first)
426 uint32 &numFields, // RETURNED
427 CssmOwnedData &fieldValue) // RETURNED
428 {
429 if(!tbsGetCheck(cert.certificateToSign->subject, index)) {
430 return false;
431 }
432 bool brtn;
433 try {
434 brtn = getField_RDN(*cert.certificateToSign->subject, numFields, fieldValue);
435 }
436 catch (...) {
437 freeField_RDN(fieldValue);
438 throw;
439 }
440 return brtn;
441 }
442
443 static void setField_Subject (
444 DecodedCert &cert,
445 const CssmData &fieldValue)
446 {
447 tbsSetCheck(cert.certificateToSign->subject, fieldValue, sizeof(CSSM_X509_NAME),
448 "SubjectName");
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);
453 }
454
455 /***
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
459 ***/
460
461 /* first, the common code */
462 static bool getField_normRDN (
463 const Name &name,
464 uint32 &numFields, // RETURNED (if successful, 0 or 1)
465 CssmOwnedData &fieldValue) // RETURNED
466 {
467 /*
468 * First step is to make a copy of the existing name. The easiest way to do
469 * this is to encode and decode.
470 */
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);
475 Name decodedName;
476 SC_decodeAsnObj(encodedName1, decodedName);
477
478 /* normalize */
479 CL_normalizeX509Name(decodedName, alloc);
480
481 /* encode result */
482 SC_encodeAsnObj(decodedName, fieldValue, MAX_RDN_SIZE);
483 numFields = 1;
484 return true;
485 }
486
487 static bool getFieldSubjectNorm(
488 const DecodedCert &cert,
489 unsigned index, // which occurrence (0 = first)
490 uint32 &numFields, // RETURNED
491 CssmOwnedData &fieldValue) // RETURNED
492 {
493 if(!tbsGetCheck(cert.certificateToSign->subject, index)) {
494 return false;
495 }
496 return getField_normRDN(*cert.certificateToSign->subject, numFields, fieldValue);
497 }
498
499 static bool getFieldIssuerNorm(
500 const DecodedCert &cert,
501 unsigned index, // which occurrence (0 = first)
502 uint32 &numFields, // RETURNED
503 CssmOwnedData &fieldValue) // RETURNED
504 {
505 if(!tbsGetCheck(cert.certificateToSign->issuer, index)) {
506 return false;
507 }
508 return getField_normRDN(*cert.certificateToSign->issuer, numFields, fieldValue);
509 }
510
511
512 /***
513 *** TBS AlgId, Signature AlgId
514 *** Format = CSSM_X509_ALGORITHM_IDENTIFIER
515 ***
516 *** common code:
517 ***/
518 static void getField_AlgId (
519 const AlgorithmIdentifier *snaccAlgId,
520 CssmOwnedData &fieldValue) // RETURNED
521 {
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);
527 }
528
529 static void setField_AlgId (
530 AlgorithmIdentifier *snaccAlgId,
531 const CssmData &fieldValue)
532 {
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);
537 }
538 CL_cssmAlgIdToSnacc(*cssmAlgId, *snaccAlgId);
539 }
540
541 static void freeField_AlgId (
542 CssmOwnedData &fieldValue)
543 {
544 CSSM_X509_ALGORITHM_IDENTIFIER *cssmAlgId =
545 (CSSM_X509_ALGORITHM_IDENTIFIER *)fieldValue.data();
546 if(cssmAlgId == NULL) {
547 return;
548 }
549 if(fieldValue.length() != sizeof(CSSM_X509_ALGORITHM_IDENTIFIER)) {
550 CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER);
551 }
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));
556 }
557
558
559 /* TBS AlgId */
560 static bool getField_TbsAlgId (
561 const DecodedCert &cert,
562 unsigned index, // which occurrence (0 = first)
563 uint32 &numFields, // RETURNED
564 CssmOwnedData &fieldValue) // RETURNED
565 {
566 AlgorithmIdentifier *snaccAlgId = cert.certificateToSign->signature;
567 if(!tbsGetCheck(snaccAlgId, index)) {
568 return false;
569 }
570 getField_AlgId(snaccAlgId, fieldValue);
571 numFields = 1;
572 return true;
573 }
574
575 static void setField_TbsAlgId (
576 DecodedCert &cert,
577 const CssmData &fieldValue)
578 {
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);
584 }
585
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
592 {
593 AlgorithmIdentifier *snaccAlgId = cert.algorithmIdentifier;
594 if(!tbsGetCheck(snaccAlgId, index)) {
595 return false;
596 }
597 getField_AlgId(snaccAlgId, fieldValue);
598 numFields = 1;
599 return true;
600 }
601
602 /***
603 *** Validity not before, not after
604 *** Format: CSSM_X509_TIME
605 ***/
606
607 /*** common code ***/
608 static void getField_Time (
609 const Time *snaccTime,
610 CssmOwnedData &fieldValue) // RETURNED
611 {
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));
617
618 char *timeStr = NULL;
619 int timeStrLen = 0;
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();
625 break;
626 case Time::generalizedTimeCid:
627 timeStr = *snaccTime->generalizedTime; // an AsnOct
628 timeStrLen = snaccTime->generalizedTime->Len();
629 cssmTime->timeType = BER_TAG_GENERALIZED_TIME;
630 break;
631 default:
632 /* snacc error, should never happen */
633 cssmTime->timeType = BER_TAG_OCTET_STRING;
634 timeStr = *snaccTime->generalizedTime; // an AsnOct
635 timeStrLen = snaccTime->generalizedTime->Len();
636 break;
637 }
638
639 cssmTime->time.Data = reinterpret_cast<uint8 *>(alloc.malloc(timeStrLen));
640 cssmTime->time.Length = timeStrLen;
641 memcpy(cssmTime->time.Data, timeStr, timeStrLen);
642 }
643
644 static void setField_Time (
645 Time *snaccTime,
646 const CssmData &fieldValue)
647 {
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;
652
653 switch(cssmTime->timeType) {
654 case BER_TAG_GENERALIZED_TIME:
655 snaccTime->choiceId = Time::generalizedTimeCid;
656 snaccTime->generalizedTime = new GeneralizedTime(tStr, tLen);
657 break;
658 case BER_TAG_UTC_TIME:
659 snaccTime->choiceId = Time::utcTimeCid;
660 snaccTime->utcTime = new UTCTime(tStr, tLen);
661 break;
662 default:
663 errorLog1("setField_Time: bad time tag (%d)\n", cssmTime->timeType);
664 CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER);
665 }
666 }
667
668 static void freeField_Time (
669 CssmOwnedData &fieldValue)
670 {
671 CSSM_X509_TIME *cssmTime = (CSSM_X509_TIME *)fieldValue.data();
672 if(cssmTime == NULL) {
673 return;
674 }
675 if(fieldValue.length() != sizeof(CSSM_X509_TIME)) {
676 CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER);
677 }
678 fieldValue.allocator.free(cssmTime->time.Data);
679 memset(cssmTime, 0, sizeof(CSSM_X509_TIME));
680 }
681
682 /*** not before ***/
683 static bool getField_NotBefore (
684 const DecodedCert &cert,
685 unsigned index, // which occurrence (0 = first)
686 uint32 &numFields, // RETURNED
687 CssmOwnedData &fieldValue) // RETURNED
688 {
689 if(!tbsGetCheck(cert.certificateToSign->validity, index)) {
690 return false;
691 }
692 if(cert.certificateToSign->validity->notBefore == NULL) {
693 return false;
694 }
695 getField_Time(cert.certificateToSign->validity->notBefore, fieldValue);
696 numFields = 1;
697 return true;
698 }
699
700 static void setField_NotBefore (
701 DecodedCert &cert,
702 const CssmData &fieldValue)
703 {
704 /* anything could need mallocing except TBS */
705 if(cert.certificateToSign->validity == NULL) {
706 cert.certificateToSign->validity = new Validity;
707 }
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);
712 }
713
714 /*** not after ***/
715 static bool getField_NotAfter (
716 const DecodedCert &cert,
717 unsigned index, // which occurrence (0 = first)
718 uint32 &numFields, // RETURNED
719 CssmOwnedData &fieldValue) // RETURNED
720 {
721 if(!tbsGetCheck(cert.certificateToSign->validity, index)) {
722 return false;
723 }
724 if(cert.certificateToSign->validity->notAfter == NULL) {
725 return false;
726 }
727 getField_Time(cert.certificateToSign->validity->notAfter, fieldValue);
728 numFields = 1;
729 return true;
730 }
731
732 static void setField_NotAfter (
733 DecodedCert &cert,
734 const CssmData &fieldValue)
735 {
736 /* anything could need mallocing except TBS */
737 if(cert.certificateToSign->validity == NULL) {
738 cert.certificateToSign->validity = new Validity;
739 }
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);
744 }
745
746 /***
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
752 *** beware.
753 ***/
754 static bool getField_SubjectUniqueId (
755 const DecodedCert &cert,
756 unsigned index, // which occurrence (0 = first)
757 uint32 &numFields, // RETURNED
758 CssmOwnedData &fieldValue) // RETURNED
759 {
760 UniqueIdentifier *id = cert.certificateToSign->subjectUniqueIdentifier;
761 if(!tbsGetCheck(id, index)) {
762 return false;
763 }
764 SC_asnBitsToCssmData(*id, fieldValue);
765 numFields = 1;
766 return true;
767 }
768
769 static void setField_SubjectUniqueId (
770 DecodedCert &cert,
771 const CssmData &fieldValue)
772 {
773 tbsSetCheck(cert.certificateToSign->subjectUniqueIdentifier, fieldValue, 0,
774 "SubjectUniqueID");
775 cert.certificateToSign->subjectUniqueIdentifier = new UniqueIdentifier(
776 reinterpret_cast<char * const>(fieldValue.Data), fieldValue.Length * 8);
777 }
778
779 static bool getField_IssuerUniqueId (
780 const DecodedCert &cert,
781 unsigned index, // which occurrence (0 = first)
782 uint32 &numFields, // RETURNED
783 CssmOwnedData &fieldValue) // RETURNED
784 {
785 UniqueIdentifier *id = cert.certificateToSign->issuerUniqueIdentifier;
786 if(!tbsGetCheck(id, index)) {
787 return false;
788 }
789 SC_asnBitsToCssmData(*id, fieldValue);
790 numFields = 1;
791 return true;
792 }
793
794 static void setField_IssuerUniqueId (
795 DecodedCert &cert,
796 const CssmData &fieldValue)
797 {
798 tbsSetCheck(cert.certificateToSign->issuerUniqueIdentifier, fieldValue, 0,
799 "IssuerniqueID");
800 cert.certificateToSign->issuerUniqueIdentifier = new UniqueIdentifier(
801 reinterpret_cast<char * const>(fieldValue.Data), fieldValue.Length * 8);
802 }
803
804 /***
805 *** Public key info
806 *** Format = CSSM_X509_SUBJECT_PUBLIC_KEY_INFO
807 ***/
808 static bool getField_PublicKeyInfo (
809 const DecodedCert &cert,
810 unsigned index, // which occurrence (0 = first)
811 uint32 &numFields, // RETURNED
812 CssmOwnedData &fieldValue) // RETURNED
813 {
814 if(!tbsGetCheck(cert.certificateToSign->subjectPublicKeyInfo, index)) {
815 return false;
816 }
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");
821 return false;
822 }
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);
829
830 /*
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).
834 */
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(),
840 keyLen);
841 numFields = 1;
842 return true;
843 }
844
845 static void setField_PublicKeyInfo (
846 DecodedCert &cert,
847 const CssmData &fieldValue)
848 {
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);
857 }
858
859 SubjectPublicKeyInfo *snaccKeyInfo = new SubjectPublicKeyInfo;
860 cert.certificateToSign->subjectPublicKeyInfo = snaccKeyInfo;
861 snaccKeyInfo->algorithm = new AlgorithmIdentifier;
862
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);
866
867 /* actual public key blob - AsnBits */
868 snaccKeyInfo->subjectPublicKey.Set(reinterpret_cast<char *>
869 (cssmKeyInfo->subjectPublicKey.Data),
870 cssmKeyInfo->subjectPublicKey.Length * 8);
871
872 }
873 static void freeField_PublicKeyInfo (
874 CssmOwnedData &fieldValue)
875 {
876 CSSM_X509_SUBJECT_PUBLIC_KEY_INFO *cssmKeyInfo =
877 (CSSM_X509_SUBJECT_PUBLIC_KEY_INFO *)fieldValue.data();
878 if(cssmKeyInfo == NULL) {
879 return;
880 }
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));}
887
888 /***
889 *** key info from CSSM_KEY
890 *** Format = CSSM_KEY
891 ***/
892 static bool getField_PublicKeyStruct (
893 const DecodedCert &cert,
894 unsigned index, // which occurrence (0 = first)
895 uint32 &numFields, // RETURNED
896 CssmOwnedData &fieldValue) // RETURNED
897 {
898 if(!tbsGetCheck(cert.certificateToSign->subjectPublicKeyInfo, index)) {
899 return false;
900 }
901 CSSM_KEY_PTR cssmKey = cert.extractCSSMKey(fieldValue.allocator);
902 fieldValue.set(reinterpret_cast<uint8 *>(cssmKey), sizeof(CSSM_KEY));
903 numFields = 1;
904 return true;
905 }
906
907 static void setField_PublicKeyStruct (
908 DecodedCert &cert,
909 const CssmData &fieldValue)
910 {
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);
918 }
919
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);
925
926 /* NULL algorithm paramneters, always in this case */
927 CL_nullAlgParams(*snaccKeyInfo->algorithm);
928
929 /* actual public key blob - AsnBits */
930 /***
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
934 *** responsibility.
935 ***/
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);
939 }
940 snaccKeyInfo->subjectPublicKey.Set(reinterpret_cast<char *>
941 (cssmKey->KeyData.Data), cssmKey->KeyData.Length * 8);
942 }
943
944 static void freeField_PublicKeyStruct (
945 CssmOwnedData &fieldValue)
946 {
947 CSSM_KEY_PTR cssmKey = (CSSM_KEY_PTR)fieldValue.data();
948 CL_freeCSSMKey(cssmKey, fieldValue.allocator, false);
949 }
950
951 /***
952 *** Signature
953 *** Format = raw bytes
954 *** read-only
955 ***/
956 static bool getField_Signature (
957 const DecodedCert &cert,
958 unsigned index, // which occurrence (0 = first)
959 uint32 &numFields, // RETURNED
960 CssmOwnedData &fieldValue) // RETURNED
961 {
962 if((index > 0) || // max of one sig
963 (cert.signatureValue.BitLen() == 0)) { // no sig - must be TBS only
964 return false;
965 }
966 SC_asnBitsToCssmData(cert.signatureValue, fieldValue);
967 numFields = 1;
968 return true;
969 }
970
971 /***
972 *** end of field-specific triplets
973 ***/
974
975 /* setField for read-only OIDs (i.e., the ones in cert, not TBS) */
976 static void setField_ReadOnly (
977 DecodedCert &cert,
978 const CssmData &fieldValue)
979 {
980 errorLog0("Attempt to set a read-only field\n");
981 CssmError::throwMe(CSSMERR_CL_UNKNOWN_TAG);
982 }
983
984 /*
985 * Table to map OID to {get,set,free}field
986 */
987 typedef struct {
988 const CSSM_OID *fieldId;
989 getFieldFcn *getFcn;
990 setFieldFcn *setFcn;
991 freeFieldFcn *freeFcn; // OPTIONAL - NULL means just free the
992 // top-level data
993 } oidToFieldFuncs;
994
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 },
1027
1028 /*
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}
1033 */
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 }
1052 };
1053
1054 #define NUM_KNOWN_FIELDS (sizeof(fieldFuncTable) / sizeof(oidToFieldFuncs))
1055 #define NUM_STD_CERT_FIELDS 13 /* not including extensions */
1056
1057
1058 /* map an OID to an oidToFieldFuncs */
1059 static const oidToFieldFuncs *oidToFields(
1060 const CssmOid &fieldId)
1061 {
1062 const oidToFieldFuncs *funcPtr = fieldFuncTable;
1063
1064 for(unsigned i=0; i<NUM_KNOWN_FIELDS; i++) {
1065 if(fieldId == CssmData::overlay(*funcPtr->fieldId)) {
1066 return funcPtr;
1067 }
1068 funcPtr++;
1069 }
1070 CssmError::throwMe(CSSMERR_CL_UNKNOWN_TAG);
1071 }
1072
1073
1074 /***
1075 *** Public functions
1076 ***/
1077
1078 /*
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.
1084 */
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
1090 {
1091 CASSERT(certificateToSign != NULL);
1092 switch(mState) {
1093 case CS_Empty:
1094 case CS_Building:
1095 errorLog0("DecodedCert::getCertField: can't parse undecoded cert!\n");
1096 CssmError::throwMe(CSSMERR_CL_INTERNAL_ERROR);
1097 case CS_DecodedCert:
1098 case CS_DecodedTBS:
1099 break;
1100 }
1101 const oidToFieldFuncs *fieldFuncs = oidToFields(fieldId);
1102 return fieldFuncs->getFcn(*this, index, numFields, fieldValue);
1103 }
1104
1105 /*
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)
1109 */
1110 void DecodedCert::setCertField(
1111 const CssmOid &fieldId, // which field
1112 const CssmData &fieldValue)
1113 {
1114 CASSERT(certificateToSign != NULL);
1115 switch(mState) {
1116 case CS_Empty: // first time thru
1117 mState = CS_Building;
1118 break;
1119 case CS_Building: // subsequent passes
1120 break;
1121 case CS_DecodedCert:
1122 case CS_DecodedTBS:
1123 errorLog0("DecodedCert::setCertField: can't build on a decoded cert!\n");
1124 CssmError::throwMe(CSSMERR_CL_INTERNAL_ERROR);
1125 }
1126 if((fieldValue.data() == NULL) || (fieldValue.length() == 0)) {
1127 CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER);
1128 }
1129 const oidToFieldFuncs *fieldFuncs = oidToFields(fieldId);
1130 const CssmData &value = CssmData::overlay(fieldValue);
1131 fieldFuncs->setFcn(*this, value);
1132 }
1133
1134 /*
1135 * Free the fieldId-specific data referred to by fieldValue->Data.
1136 */
1137 void DecodedCert::freeCertFieldData(
1138 const CssmOid &fieldId,
1139 CssmOwnedData &fieldValue)
1140 {
1141 if((fieldValue.data() == NULL) || (fieldValue.length() == 0)) {
1142 CssmError::throwMe(CSSM_ERRCODE_INVALID_FIELD_POINTER);
1143 }
1144 const oidToFieldFuncs *fieldFuncs = oidToFields(fieldId);
1145 if(fieldFuncs->freeFcn != NULL) {
1146 /* optional - simple cases handled below */
1147 fieldFuncs->freeFcn(fieldValue);
1148 }
1149 fieldValue.reset();
1150 fieldValue.release();
1151
1152 }
1153
1154
1155 /*
1156 * Common means to get all fields from a decoded cert. Used in
1157 * CertGetAllTemplateFields and CertGetAllFields.
1158 */
1159 void DecodedCert::getAllParsedCertFields(
1160 uint32 &NumberOfFields, // RETURNED
1161 CSSM_FIELD_PTR &CertFields) // RETURNED
1162 {
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));
1166
1167 /*
1168 * We'll be copying oids and values for fields we find into
1169 * outFields; current number of valid fields found in numOutFields.
1170 */
1171 memset(outFields, 0, maxFields * sizeof(CSSM_FIELD));
1172 uint32 numOutFields = 0;
1173 CSSM_FIELD_PTR currOutField;
1174 uint32 currOidDex;
1175 const CSSM_OID *currOid;
1176 CssmAutoData aData(alloc); // for malloc/copy of outgoing data
1177
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
1183
1184 /*
1185 * Return false if field not there, which is not an error here.
1186 * Actual exceptions are fatal.
1187 */
1188 if(!fieldFuncs->getFcn(*this,
1189 0, // index - looking for first one
1190 numFields,
1191 aData)) {
1192 continue;
1193 }
1194
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();
1201 numOutFields++;
1202
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,
1207 fieldDex,
1208 numFields, // shouldn't change
1209 aData);
1210 if(!brtn) {
1211 errorLog0("getAllParsedCertFields: index screwup\n");
1212 CssmError::throwMe(CSSMERR_CL_INTERNAL_ERROR);
1213 }
1214 CASSERT(numOutFields < maxFields);
1215 currOutField = &outFields[numOutFields];
1216 currOutField->FieldValue = aData.release();
1217 aData.copy(*currOid);
1218 currOutField->FieldOid = aData.release();
1219 numOutFields++;
1220 } /* multiple fields for currOid */
1221 } /* for each known OID */
1222
1223 NumberOfFields = numOutFields;
1224 CertFields = outFields;
1225 }
1226
1227 void
1228 DecodedCert::describeFormat(
1229 CssmAllocator &alloc,
1230 uint32 &NumberOfFields,
1231 CSSM_OID_PTR &OidList)
1232 {
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();
1240 }
1241 NumberOfFields = NUM_KNOWN_FIELDS;
1242 OidList = oidList;
1243 }