]> git.saurik.com Git - apple/security.git/blob - SecurityTests/clxutils/clAppUtils/tpUtils.cpp
Security-57336.1.9.tar.gz
[apple/security.git] / SecurityTests / clxutils / clAppUtils / tpUtils.cpp
1 /*
2 * tpUtils.cpp - TP and cert group test support
3 */
4
5 #include <Security/cssmtype.h>
6 #include <clAppUtils/tpUtils.h>
7 #include <clAppUtils/clutils.h>
8 #include <utilLib/common.h>
9 #include <utilLib/cspwrap.h>
10 #include <clAppUtils/CertBuilderApp.h>
11 #include <Security/oidsattr.h>
12 #include <Security/oidscert.h>
13 #include <Security/SecTrustSettingsPriv.h>
14 #include <stdlib.h>
15 #include <stdio.h>
16 #include <string.h>
17 #include <Security/SecKeychainItem.h>
18 #include <Security/SecKeychain.h>
19 #include <Security/SecCertificate.h>
20 #include <security_cdsa_utils/cuFileIo.h>
21
22 /*
23 * Currently, DBs created with SecKeychainCreateNew() do not contain
24 * the schema for CSSM_DL_DB_RECORD_X509_CERTIFICATE records. Keychain
25 * code (Certificate::add()) does this on the fly, I don't know why.
26 * To avoid dependencies on KC - other than SecKeychainCreateNew - we'll
27 * emulate that "add this schema on the fly" logic here.
28 *
29 * Turn this option off if and when Radar 2927378 is approved and
30 * integrated into Security TOT.
31 */
32 #define FAKE_ADD_CERT_SCHEMA 1
33 #if FAKE_ADD_CERT_SCHEMA
34
35 /* defined in SecKeychainAPIPriv.h */
36 // static const int kSecAlias = 'alis';
37
38 /* Macro to declare a CSSM_DB_SCHEMA_ATTRIBUTE_INFO */
39 #define SCHEMA_ATTR_INFO(id, name, type) \
40 { id, (char *)name, {0, NULL}, CSSM_DB_ATTRIBUTE_FORMAT_ ## type }
41
42 /* Too bad we can't get this from inside of the Security framework. */
43 static CSSM_DB_SCHEMA_ATTRIBUTE_INFO certSchemaAttrInfo[] =
44 {
45 SCHEMA_ATTR_INFO(kSecCertTypeItemAttr, "CertType", UINT32),
46 SCHEMA_ATTR_INFO(kSecCertEncodingItemAttr, "CertEncoding", UINT32),
47 SCHEMA_ATTR_INFO(kSecLabelItemAttr, "PrintName", BLOB),
48 SCHEMA_ATTR_INFO(kSecAlias, "Alias", BLOB),
49 SCHEMA_ATTR_INFO(kSecSubjectItemAttr, "Subject", BLOB),
50 SCHEMA_ATTR_INFO(kSecIssuerItemAttr, "Issuer", BLOB),
51 SCHEMA_ATTR_INFO(kSecSerialNumberItemAttr, "SerialNumber", BLOB),
52 SCHEMA_ATTR_INFO(kSecSubjectKeyIdentifierItemAttr, "SubjectKeyIdentifier", BLOB),
53 SCHEMA_ATTR_INFO(kSecPublicKeyHashItemAttr, "PublicKeyHash", BLOB)
54 };
55 #define NUM_CERT_SCHEMA_ATTRS \
56 (sizeof(certSchemaAttrInfo) / sizeof(CSSM_DB_SCHEMA_ATTRIBUTE_INFO))
57
58 /* Macro to declare a CSSM_DB_SCHEMA_INDEX_INFO */
59 #define SCHEMA_INDEX_INFO(id, indexNum, indexType) \
60 { id, CSSM_DB_INDEX_ ## indexType, CSSM_DB_INDEX_ON_ATTRIBUTE }
61
62
63 static CSSM_DB_SCHEMA_INDEX_INFO certSchemaIndices[] =
64 {
65 SCHEMA_INDEX_INFO(kSecCertTypeItemAttr, 0, UNIQUE),
66 SCHEMA_INDEX_INFO(kSecIssuerItemAttr, 0, UNIQUE),
67 SCHEMA_INDEX_INFO(kSecSerialNumberItemAttr, 0, UNIQUE),
68 SCHEMA_INDEX_INFO(kSecCertTypeItemAttr, 1, NONUNIQUE),
69 SCHEMA_INDEX_INFO(kSecSubjectItemAttr, 2, NONUNIQUE),
70 SCHEMA_INDEX_INFO(kSecIssuerItemAttr, 3, NONUNIQUE),
71 SCHEMA_INDEX_INFO(kSecSerialNumberItemAttr, 4, NONUNIQUE),
72 SCHEMA_INDEX_INFO(kSecSubjectKeyIdentifierItemAttr, 5, NONUNIQUE),
73 SCHEMA_INDEX_INFO(kSecPublicKeyHashItemAttr, 6, NONUNIQUE)
74 };
75 #define NUM_CERT_INDICES \
76 (sizeof(certSchemaIndices) / sizeof(CSSM_DB_SCHEMA_INDEX_INFO))
77
78
79 CSSM_RETURN tpAddCertSchema(
80 CSSM_DL_DB_HANDLE dlDbHand)
81 {
82 return CSSM_DL_CreateRelation(dlDbHand,
83 CSSM_DL_DB_RECORD_X509_CERTIFICATE,
84 "CSSM_DL_DB_RECORD_X509_CERTIFICATE",
85 NUM_CERT_SCHEMA_ATTRS,
86 certSchemaAttrInfo,
87 NUM_CERT_INDICES,
88 certSchemaIndices);
89 }
90 #endif /* FAKE_ADD_CERT_SCHEMA */
91
92 /*
93 * Given a raw cert, extract DER-encoded normalized subject and issuer names.
94 */
95 static CSSM_DATA_PTR tpGetNormSubject(
96 CSSM_CL_HANDLE clHand,
97 const CSSM_DATA *rawCert)
98 {
99 CSSM_RETURN crtn;
100 CSSM_HANDLE searchHand = CSSM_INVALID_HANDLE;
101 uint32 numFields;
102 CSSM_DATA_PTR fieldValue;
103
104 crtn = CSSM_CL_CertGetFirstFieldValue(clHand,
105 rawCert,
106 &CSSMOID_X509V1SubjectName,
107 &searchHand,
108 &numFields,
109 &fieldValue);
110 if(crtn) {
111 printError("CSSM_CL_CertGetFirstFieldValue", crtn);
112 return NULL;
113 }
114 CSSM_CL_CertAbortQuery(clHand, searchHand);
115 return fieldValue;
116 }
117
118 static CSSM_DATA_PTR tpGetNormIssuer(
119 CSSM_CL_HANDLE clHand,
120 const CSSM_DATA *rawCert)
121 {
122 CSSM_RETURN crtn;
123 CSSM_HANDLE searchHand = CSSM_INVALID_HANDLE;
124 uint32 numFields;
125 CSSM_DATA_PTR fieldValue;
126
127 crtn = CSSM_CL_CertGetFirstFieldValue(clHand,
128 rawCert,
129 &CSSMOID_X509V1IssuerName,
130 &searchHand,
131 &numFields,
132 &fieldValue);
133 if(crtn) {
134 printError("CSSM_CL_CertGetFirstFieldValue", crtn);
135 return NULL;
136 }
137 CSSM_CL_CertAbortQuery(clHand, searchHand);
138 return fieldValue;
139 }
140
141
142 #define SERIAL_NUMBER_BASE 0x33445566
143
144 /*
145 * Given an array of certs and an uninitialized CSSM_CERTGROUP, place the
146 * certs into the certgroup and optionally into one of a list of DBs in
147 * random order. Optionally the first cert in the array is placed in the
148 * first element of certgroup. Only error is memory error. It's legal to
149 * pass in an empty cert array.
150 */
151 CSSM_RETURN tpMakeRandCertGroup(
152 CSSM_CL_HANDLE clHand,
153 CSSM_DL_DB_LIST_PTR dbList,
154 const CSSM_DATA_PTR certs,
155 unsigned numCerts,
156 CSSM_CERTGROUP_PTR certGroup,
157 CSSM_BOOL firstCertIsSubject, // true: certs[0] goes to head
158 // of certGroup
159 CSSM_BOOL verbose,
160 CSSM_BOOL allInDbs, // all certs go to DBs
161 CSSM_BOOL skipFirstDb) // no certs go to db[0]
162 {
163 unsigned startDex = 0; // where to start processing
164 unsigned certDex; // into certs and certGroup
165 unsigned die;
166 CSSM_RETURN crtn;
167
168 #if TP_DB_ENABLE
169 if((dbList == NULL) && (allInDbs | skipFirstDb)) {
170 printf("need dbList for allInDbs or skipFirstDb\n");
171 return CSSM_ERRCODE_INTERNAL_ERROR;
172 }
173 if(skipFirstDb && (dbList->NumHandles == 1)) {
174 printf("Need more than one DB for skipFirstDb\n");
175 return CSSM_ERRCODE_INTERNAL_ERROR;
176 }
177 #else
178 if(dbList != NULL) {
179 printf("TP/DB not supported yet\n");
180 return CSSMERR_CSSM_INTERNAL_ERROR;
181 }
182 #endif
183
184 certGroup->NumCerts = 0;
185 certGroup->CertGroupType = CSSM_CERTGROUP_DATA;
186 certGroup->CertType = CSSM_CERT_X_509v3;
187 certGroup->CertEncoding = CSSM_CERT_ENCODING_DER;
188 if(numCerts == 0) {
189 /* legal */
190 certGroup->GroupList.CertList = NULL;
191 return CSSM_OK;
192 }
193
194 /* make CertList big enough for all certs */
195 certGroup->GroupList.CertList = (CSSM_DATA_PTR)CSSM_CALLOC(numCerts, sizeof(CSSM_DATA));
196 if(certGroup->GroupList.CertList == NULL) {
197 printf("Memory error!\n");
198 return CSSMERR_CSSM_MEMORY_ERROR;
199 }
200 if(firstCertIsSubject) {
201 certGroup->GroupList.CertList[0] = certs[0];
202 certGroup->NumCerts = 1;
203 startDex = 1;
204 }
205 for(certDex=startDex; certDex<numCerts; certDex++) {
206 /* flip a coin, half of the certs go into a DB */
207 die = genRand(1, 2); // one random bit
208 if( ( (dbList != NULL) && (dbList->NumHandles != 0) ) &&
209 ( (die == 1) || allInDbs) ) {
210 /* put this cert in one of the DBs */
211 if(skipFirstDb) {
212 die = genRand(1, dbList->NumHandles-1);
213 }
214 else {
215 die = genRand(0, dbList->NumHandles-1);
216 }
217 if(verbose) {
218 printf(" ...cert %d to DB[%d]\n", certDex, die);
219 }
220 crtn = tpStoreRawCert(dbList->DLDBHandle[die],
221 clHand,
222 &certs[certDex]);
223 if(crtn) {
224 return crtn;
225 }
226 }
227 else {
228 /* find a random unused place in certGroupFrag */
229 CSSM_DATA_PTR certData;
230
231 while(1) {
232 die = genRand(0, numCerts-1);
233 certData = &certGroup->GroupList.CertList[die];
234 if(certData->Data == NULL) {
235 *certData = certs[certDex];
236 certGroup->NumCerts++;
237 if(verbose) {
238 printf(" ...cert %d to frag[%d]\n",
239 certDex, die);
240 }
241 break;
242 }
243 /* else try again and hope we don't spin forever */
244 }
245 } /* random place in certGroup */
246 } /* main loop */
247
248 if(dbList != NULL) {
249 /*
250 * Since we put some of the certs in dlDb rather than in certGroup,
251 * compact the contents of certGroup. Its NumCerts is correct,
252 * but some of the entries in CertList are empty.
253 */
254 unsigned i;
255
256 for(certDex=0; certDex<numCerts; certDex++) {
257 if(certGroup->GroupList.CertList[certDex].Data == NULL) {
258 /* find next non-NULL cert */
259 for(i=certDex+1; i<numCerts; i++) {
260 if(certGroup->GroupList.CertList[i].Data != NULL) {
261 if(verbose) {
262 printf(" ...frag[%d] to frag[%d]\n",
263 i, certDex);
264 }
265 certGroup->GroupList.CertList[certDex] =
266 certGroup->GroupList.CertList[i];
267 certGroup->GroupList.CertList[i].Data = NULL;
268 break;
269 }
270 }
271 }
272 }
273 }
274 return CSSM_OK;
275 }
276
277 /*
278 * Store a cert in specified DL/DB. All attributes are optional except
279 * as noted (right?).
280 */
281 CSSM_RETURN tpStoreCert(
282 CSSM_DL_DB_HANDLE dlDb,
283 const CSSM_DATA_PTR cert,
284 /* REQUIRED fields */
285 CSSM_CERT_TYPE certType, // e.g. CSSM_CERT_X_509v3
286 uint32 serialNum,
287 const CSSM_DATA *issuer, // (shouldn't this be subject?)
288 // normalized & encoded
289 /* OPTIONAL fields */
290 CSSM_CERT_ENCODING certEncoding, // e.g. CSSM_CERT_ENCODING_DER
291 const CSSM_DATA *printName,
292 const CSSM_DATA *subject) // normalized & encoded
293 {
294 CSSM_DB_ATTRIBUTE_DATA attrs[6];
295 CSSM_DB_RECORD_ATTRIBUTE_DATA recordAttrs;
296 CSSM_DB_ATTRIBUTE_DATA_PTR attr = &attrs[0];
297 CSSM_DB_UNIQUE_RECORD_PTR recordPtr = NULL;
298 CSSM_DATA certTypeData;
299 CSSM_DATA certEncData;
300 CSSM_DATA_PTR serialNumData;
301 uint32 numAttributes;
302
303 if(issuer == NULL) {
304 printf("***For now, must specify cert issuer when storing\n");
305 return CSSM_ERRCODE_INTERNAL_ERROR;
306 }
307
308 /* how many attributes are we storing? */
309 numAttributes = 4; // certType, serialNum, issuer, certEncoding
310 if(printName != NULL) {
311 numAttributes++;
312 }
313 if(subject != NULL) {
314 numAttributes++;
315 }
316
317 /* cook up CSSM_DB_RECORD_ATTRIBUTE_DATA */
318 recordAttrs.DataRecordType = CSSM_DL_DB_RECORD_X509_CERTIFICATE;
319 recordAttrs.SemanticInformation = 0;
320 recordAttrs.NumberOfAttributes = numAttributes;
321 recordAttrs.AttributeData = attrs;
322
323 /* grind thru the attributes - first the required ones plus certEncoding */
324 certTypeData.Data = (uint8 *)&certType;
325 certTypeData.Length = sizeof(CSSM_CERT_TYPE);
326 certEncData.Data = (uint8 *)&certEncoding;
327 certEncData.Length = sizeof(CSSM_CERT_ENCODING);
328 serialNumData = intToDER(serialNum);
329
330 attr->Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_STRING;
331 attr->Info.Label.AttributeName = (char *)"CertType";
332 attr->Info.AttributeFormat = CSSM_DB_ATTRIBUTE_FORMAT_UINT32;
333 attr->NumberOfValues = 1;
334 attr->Value = &certTypeData;
335 attr++;
336
337 attr->Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_STRING;
338 attr->Info.Label.AttributeName = (char *)"CertEncoding";
339 attr->Info.AttributeFormat = CSSM_DB_ATTRIBUTE_FORMAT_UINT32;
340 attr->NumberOfValues = 1;
341 attr->Value = &certEncData;
342 attr++;
343
344 attr->Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_STRING;
345 attr->Info.Label.AttributeName = (char *)"SerialNumber";
346 attr->Info.AttributeFormat = CSSM_DB_ATTRIBUTE_FORMAT_BLOB;
347 attr->NumberOfValues = 1;
348 attr->Value = serialNumData;
349 attr++;
350
351 attr->Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_STRING;
352 attr->Info.Label.AttributeName = (char *)"Issuer";
353 attr->Info.AttributeFormat = CSSM_DB_ATTRIBUTE_FORMAT_BLOB;
354 attr->NumberOfValues = 1;
355 attr->Value = (CSSM_DATA_PTR)issuer;
356 attr++;
357
358 /* now the options */
359 if(printName != NULL) {
360 attr->Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_STRING;
361 attr->Info.Label.AttributeName = (char *)"PrintName";
362 attr->Info.AttributeFormat = CSSM_DB_ATTRIBUTE_FORMAT_BLOB;
363 attr->NumberOfValues = 1;
364 attr->Value = (CSSM_DATA_PTR)printName;
365 attr++;
366 }
367 if(subject != NULL) {
368 attr->Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_STRING;
369 attr->Info.Label.AttributeName = (char *)"Subject";
370 attr->Info.AttributeFormat = CSSM_DB_ATTRIBUTE_FORMAT_BLOB;
371 attr->NumberOfValues = 1;
372 attr->Value = (CSSM_DATA_PTR)subject;
373 attr++;
374 }
375
376 /* Okay, here we go */
377 CSSM_RETURN crtn = CSSM_DL_DataInsert(dlDb,
378 CSSM_DL_DB_RECORD_X509_CERTIFICATE,
379 &recordAttrs,
380 cert,
381 &recordPtr);
382 #if FAKE_ADD_CERT_SCHEMA
383 if(crtn == CSSMERR_DL_INVALID_RECORDTYPE) {
384 /* gross hack of inserting this "new" schema that Keychain didn't specify */
385 crtn = tpAddCertSchema(dlDb);
386 if(crtn == CSSM_OK) {
387 /* Retry with a fully capable DLDB */
388 crtn = CSSM_DL_DataInsert(dlDb,
389 CSSM_DL_DB_RECORD_X509_CERTIFICATE,
390 &recordAttrs,
391 cert,
392 &recordPtr);
393 }
394 }
395 #endif /* FAKE_ADD_CERT_SCHEMA */
396
397 /* free resources allocated to get this far */
398 appFreeCssmData(serialNumData, CSSM_TRUE);
399 if(recordPtr != NULL) {
400 CSSM_DL_FreeUniqueRecord(dlDb, recordPtr);
401 }
402 if(crtn) {
403 printError("CSSM_DL_DataInsert", crtn);
404 }
405 return crtn;
406 }
407
408 /*
409 * Store a cert when we don't already know the required fields. We'll
410 * extract them or make them up.
411 */
412 CSSM_RETURN tpStoreRawCert(
413 CSSM_DL_DB_HANDLE dlDb,
414 CSSM_CL_HANDLE clHand,
415 const CSSM_DATA_PTR cert)
416 {
417 CSSM_DATA_PTR normSubj;
418 CSSM_DATA_PTR normIssuer;
419 CSSM_DATA printName;
420 CSSM_RETURN crtn;
421 static uint32 fakeSerialNum = 0;
422
423 normSubj = tpGetNormSubject(clHand, cert);
424 normIssuer = tpGetNormIssuer(clHand, cert);
425 if((normSubj == NULL) || (normIssuer == NULL)) {
426 return CSSM_ERRCODE_INTERNAL_ERROR;
427 }
428 printName.Data = (uint8 *)"Some Printable Name";
429 printName.Length = strlen((char *)printName.Data);
430 crtn = tpStoreCert(dlDb,
431 cert,
432 CSSM_CERT_X_509v3,
433 fakeSerialNum++,
434 normIssuer,
435 CSSM_CERT_ENCODING_DER,
436 &printName,
437 normSubj);
438 appFreeCssmData(normSubj, CSSM_TRUE);
439 appFreeCssmData(normIssuer, CSSM_TRUE);
440 return crtn;
441 }
442
443 /*
444 * Generate numKeyPairs key pairs of specified algorithm and size.
445 * Key labels will be 'keyLabelBase' concatenated with a 4-digit
446 * decimal number.
447 */
448 CSSM_RETURN tpGenKeys(
449 CSSM_CSP_HANDLE cspHand,
450 CSSM_DL_DB_HANDLE dbHand, /* keys go here */
451 unsigned numKeyPairs,
452 uint32 keyGenAlg, /* CSSM_ALGID_RSA, etc. */
453 uint32 keySizeInBits,
454 const char *keyLabelBase, /* C string */
455 CSSM_KEY_PTR pubKeys, /* array of keys RETURNED here */
456 CSSM_KEY_PTR privKeys, /* array of keys RETURNED here */
457 CSSM_DATA_PTR paramData) /* optional DSA params */
458 {
459 CSSM_RETURN crtn;
460 unsigned i;
461 char label[80];
462 unsigned labelLen = strlen(keyLabelBase);
463
464 memset(pubKeys, 0, numKeyPairs * sizeof(CSSM_KEY));
465 memset(privKeys, 0, numKeyPairs * sizeof(CSSM_KEY));
466 memmove(label, keyLabelBase, labelLen);
467
468 for(i=0; i<numKeyPairs; i++) {
469 /* unique label */
470 sprintf(label+labelLen, "%04d", i);
471 if(keyGenAlg == CSSM_ALGID_DSA) {
472 crtn = cspGenDSAKeyPair(cspHand,
473 label,
474 labelLen + 4,
475 keySizeInBits,
476 &pubKeys[i],
477 CSSM_FALSE, // pubIsRef
478 CSSM_KEYUSE_VERIFY, // pubKeyUsage
479 CSSM_KEYBLOB_RAW_FORMAT_NONE,
480 &privKeys[i],
481 CSSM_TRUE, // privIsRef
482 CSSM_KEYUSE_SIGN,
483 CSSM_KEYBLOB_RAW_FORMAT_NONE,
484 CSSM_FALSE, // genParams
485 paramData);
486 }
487 else {
488 crtn = cspGenKeyPair(cspHand,
489 keyGenAlg,
490 // not used in X, yet dbHand,
491 label,
492 labelLen + 4,
493 keySizeInBits,
494 &pubKeys[i],
495 CSSM_FALSE, // pubIsRef
496 CSSM_KEYUSE_VERIFY, // pubKeyUsage
497 CSSM_KEYBLOB_RAW_FORMAT_NONE,
498 &privKeys[i],
499 CSSM_TRUE, /// privIsRef
500 CSSM_KEYUSE_SIGN,
501 CSSM_KEYBLOB_RAW_FORMAT_NONE,
502 CSSM_FALSE);
503 }
504 if(crtn) {
505 return crtn;
506 }
507 }
508
509 /* verify they are all different keys */
510 for(i=0; i<numKeyPairs; i++) {
511 CSSM_DATA_PTR k1 = &pubKeys[i].KeyData;
512 for(unsigned j=i+1; j<numKeyPairs; j++) {
513 CSSM_DATA_PTR k2 = &pubKeys[j].KeyData;
514 if(appCompareCssmData(k1, k2)) {
515 printf("***HEY! public keys %d and %d are indentical!\n", i, j);
516 }
517 }
518 }
519 return crtn;
520 }
521
522 /*
523 * Generate a cert chain using specified key pairs. The last cert in the
524 * chain (certs[numCerts-1]) is a root cert, self-signed.
525 */
526 CSSM_RETURN tpGenCerts(
527 CSSM_CSP_HANDLE cspHand,
528 CSSM_CL_HANDLE clHand,
529 unsigned numCerts,
530 uint32 sigAlg, /* CSSM_ALGID_SHA1WithRSA, etc. */
531 const char *nameBase, /* C string */
532 CSSM_KEY_PTR pubKeys, /* array of public keys */
533 CSSM_KEY_PTR privKeys, /* array of private keys */
534 CSSM_DATA_PTR certs, /* array of certs RETURNED here */
535 const char *notBeforeStr, /* from genTimeAtNowPlus() */
536 const char *notAfterStr) /* from genTimeAtNowPlus() */
537 {
538 return tpGenCertsStore(cspHand,
539 clHand,
540 numCerts,
541 sigAlg,
542 nameBase,
543 pubKeys,
544 privKeys,
545 NULL, // storeArray
546 certs,
547 notBeforeStr,
548 notAfterStr);
549 }
550
551 /*
552 * Generate a cert chain using specified key pairs. The last cert in the
553 * chain (certs[numCerts-1]) is a root cert, self-signed. Store
554 * the certs indicated by corresponding element on storeArray. If
555 * storeArray[n].DLHandle == 0, the cert is not stored.
556 */
557 CSSM_RETURN tpGenCertsStore(
558 CSSM_CSP_HANDLE cspHand,
559 CSSM_CL_HANDLE clHand,
560 unsigned numCerts,
561 uint32 sigAlg, /* CSSM_ALGID_SHA1WithRSA, etc. */
562 const char *nameBase, /* C string */
563 CSSM_KEY_PTR pubKeys, /* array of public keys */
564 CSSM_KEY_PTR privKeys, /* array of private keys */
565 CSSM_DL_DB_HANDLE *storeArray, /* array of certs stored here */
566 CSSM_DATA_PTR certs, /* array of certs RETURNED here */
567 const char *notBeforeStr, /* from genTimeAtNowPlus() */
568 const char *notAfterStr) /* from genTimeAtNowPlus() */
569
570 {
571 int dex;
572 CSSM_RETURN crtn;
573 CSSM_X509_NAME *issuerName = NULL;
574 CSSM_X509_NAME *subjectName = NULL;
575 CSSM_X509_TIME *notBefore; // UTC-style "not before" time
576 CSSM_X509_TIME *notAfter; // UTC-style "not after" time
577 CSSM_DATA_PTR rawCert = NULL; // from CSSM_CL_CertCreateTemplate
578 CSSM_DATA signedCert; // from CSSM_CL_CertSign
579 uint32 rtn;
580 CSSM_KEY_PTR signerKey; // signs the cert
581 CSSM_CC_HANDLE signContext;
582 char nameStr[100];
583 CSSM_DATA_PTR thisCert; // ptr into certs[]
584 CB_NameOid nameOid;
585 CE_BasicConstraints bc;
586 CSSM_X509_EXTENSION exten;
587
588 nameOid.oid = &CSSMOID_OrganizationName; // const
589 nameOid.string = nameStr;
590
591 /* one extension for nonleaf indicating cA */
592 exten.extnId = CSSMOID_BasicConstraints;
593 exten.critical = CSSM_TRUE;
594 exten.format = CSSM_X509_DATAFORMAT_PARSED;
595 exten.value.parsedValue = &bc;
596 exten.BERvalue.Data = NULL;
597 exten.BERvalue.Length = 0;
598 bc.cA = CSSM_TRUE;
599 bc.pathLenConstraintPresent = CSSM_FALSE;
600 bc.pathLenConstraint = 0;
601
602 /* main loop - once per keypair/cert - starting at end/root */
603 for(dex=numCerts-1; dex>=0; dex--) {
604 thisCert = &certs[dex];
605
606 thisCert->Data = NULL;
607 thisCert->Length = 0;
608
609 sprintf(nameStr, "%s%04d", nameBase, dex);
610 if(issuerName == NULL) {
611 /* last (root) cert - subject same as issuer */
612 issuerName = CB_BuildX509Name(&nameOid, 1);
613 /* self-signed */
614 signerKey = &privKeys[dex];
615 }
616 else {
617 /* previous subject becomes current issuer */
618 CB_FreeX509Name(issuerName);
619 issuerName = subjectName;
620 signerKey = &privKeys[dex+1];
621 }
622 subjectName = CB_BuildX509Name(&nameOid, 1);
623 if((subjectName == NULL) || (issuerName == NULL)) {
624 printf("Error creating X509Names\n");
625 crtn = CSSMERR_CSSM_MEMORY_ERROR;
626 break;
627 }
628
629 /*
630 * not before/after in Y2k-compliant generalized time format.
631 * These come preformatted from our caller.
632 */
633 notBefore = CB_BuildX509Time(0, notBeforeStr);
634 notAfter = CB_BuildX509Time(0, notAfterStr);
635
636 /*
637 * Cook up cert template
638 * Note serial number would be app-specified in real world
639 */
640 rawCert = CB_MakeCertTemplate(clHand,
641 SERIAL_NUMBER_BASE + dex, // serial number
642 issuerName,
643 subjectName,
644 notBefore,
645 notAfter,
646 &pubKeys[dex],
647 sigAlg,
648 NULL, // subj unique ID
649 NULL, // issuer unique ID
650 &exten, // extensions
651 (dex == 0) ? 0 : 1);// numExtensions
652
653 if(rawCert == NULL) {
654 crtn = CSSM_ERRCODE_INTERNAL_ERROR;
655 break;
656 }
657
658 /* Free the stuff we allocd to get here */
659 CB_FreeX509Time(notBefore);
660 CB_FreeX509Time(notAfter);
661
662 /**** sign the cert ****/
663 /* 1. get a signing context */
664 crtn = CSSM_CSP_CreateSignatureContext(cspHand,
665 sigAlg,
666 NULL, // no passphrase for now
667 signerKey,
668 &signContext);
669 if(crtn) {
670 printError("CreateSignatureContext", crtn);
671 break;
672 }
673
674 /* 2. use CL to sign the cert */
675 signedCert.Data = NULL;
676 signedCert.Length = 0;
677 crtn = CSSM_CL_CertSign(clHand,
678 signContext,
679 rawCert, // CertToBeSigned
680 NULL, // SignScope per spec
681 0, // ScopeSize per spec
682 &signedCert);
683 if(crtn) {
684 printError("CSSM_CL_CertSign", crtn);
685 break;
686 }
687
688 /* 3. Optionally store the cert in DL */
689 if((storeArray != NULL) && storeArray[dex].DBHandle != 0) {
690 crtn = tpStoreRawCert(storeArray[dex],
691 clHand,
692 &signedCert);
693 if(crtn) {
694 break;
695 }
696 }
697
698 /* 4. delete signing context */
699 crtn = CSSM_DeleteContext(signContext);
700 if(crtn) {
701 printError("CSSM_DeleteContext", crtn);
702 break;
703 }
704
705 /*
706 * CSSM_CL_CertSign() returned us a mallocd CSSM_DATA. Copy
707 * its fields to caller's cert.
708 */
709 certs[dex] = signedCert;
710
711 /* and the raw unsigned cert as well */
712 appFreeCssmData(rawCert, CSSM_TRUE);
713 rtn = 0;
714 }
715
716 /* free resources */
717 if(issuerName != NULL) {
718 CB_FreeX509Name(issuerName);
719 }
720 if(subjectName != NULL) {
721 CB_FreeX509Name(subjectName);
722 }
723 return crtn;
724 }
725
726 /* compare two CSSM_CERTGROUPs, returns CSSM_TRUE on success */
727 CSSM_BOOL tpCompareCertGroups(
728 const CSSM_CERTGROUP *grp1,
729 const CSSM_CERTGROUP *grp2)
730 {
731 unsigned i;
732 CSSM_DATA_PTR d1;
733 CSSM_DATA_PTR d2;
734
735 if(grp1->NumCerts != grp2->NumCerts) {
736 return CSSM_FALSE;
737 }
738 for(i=0; i<grp1->NumCerts; i++) {
739 d1 = &grp1->GroupList.CertList[i];
740 d2 = &grp2->GroupList.CertList[i];
741
742 /* these are all errors */
743 if((d1->Data == NULL) ||
744 (d1->Length == 0) ||
745 (d2->Data == NULL) ||
746 (d2->Length == 0)) {
747 printf("compareCertGroups: bad cert group!\n");
748 return CSSM_FALSE;
749 }
750 if(d1->Length != d2->Length) {
751 return CSSM_FALSE;
752 }
753 if(memcmp(d1->Data, d2->Data, d1->Length)) {
754 return CSSM_FALSE;
755 }
756 }
757 return CSSM_TRUE;
758 }
759
760 /* free a CSSM_CERT_GROUP */
761 void tpFreeCertGroup(
762 CSSM_CERTGROUP_PTR certGroup,
763 CSSM_BOOL freeCertData, // free individual CertList.Data
764 CSSM_BOOL freeStruct) // free the overall CSSM_CERTGROUP
765 {
766 unsigned dex;
767
768 if(certGroup == NULL) {
769 return;
770 }
771
772 if(freeCertData) {
773 /* free the individual cert Data fields */
774 for(dex=0; dex<certGroup->NumCerts; dex++) {
775 appFreeCssmData(&certGroup->GroupList.CertList[dex], CSSM_FALSE);
776 }
777 }
778
779 /* and the array of CSSM_DATAs */
780 if(certGroup->GroupList.CertList) {
781 CSSM_FREE(certGroup->GroupList.CertList);
782 }
783
784 if(freeStruct) {
785 CSSM_FREE(certGroup);
786 }
787 }
788
789 CSSM_RETURN clDeleteAllCerts(CSSM_DL_DB_HANDLE dlDb)
790 {
791 CSSM_QUERY query;
792 CSSM_DB_UNIQUE_RECORD_PTR record = NULL;
793 CSSM_RETURN crtn;
794 CSSM_HANDLE resultHand;
795 CSSM_DB_RECORD_ATTRIBUTE_DATA recordAttrs;
796
797 recordAttrs.DataRecordType = CSSM_DL_DB_RECORD_X509_CERTIFICATE;
798 recordAttrs.NumberOfAttributes = 0;
799 recordAttrs.AttributeData = NULL;
800
801 /* just search by recordType, no predicates */
802 query.RecordType = CSSM_DL_DB_RECORD_X509_CERTIFICATE;
803 query.Conjunctive = CSSM_DB_NONE;
804 query.NumSelectionPredicates = 0;
805 query.SelectionPredicate = NULL;
806 query.QueryLimits.TimeLimit = 0; // FIXME - meaningful?
807 query.QueryLimits.SizeLimit = 1; // FIXME - meaningful?
808 query.QueryFlags = 0; // CSSM_QUERY_RETURN_DATA...FIXME - used?
809
810 crtn = CSSM_DL_DataGetFirst(dlDb,
811 &query,
812 &resultHand,
813 &recordAttrs,
814 NULL, // No data
815 &record);
816 switch(crtn) {
817 case CSSM_OK:
818 break; // proceed
819 case CSSMERR_DL_ENDOFDATA:
820 /* OK, no certs */
821 return CSSM_OK;
822 default:
823 printError("DataGetFirst", crtn);
824 return crtn;
825 }
826
827 crtn = CSSM_DL_DataDelete(dlDb, record);
828 if(crtn) {
829 printError("CSSM_DL_DataDelete", crtn);
830 return crtn;
831 }
832 CSSM_DL_FreeUniqueRecord(dlDb, record);
833
834 /* now the rest of them */
835 for(;;) {
836 crtn = CSSM_DL_DataGetNext(dlDb,
837 resultHand,
838 &recordAttrs,
839 NULL,
840 &record);
841 switch(crtn) {
842 case CSSM_OK:
843 crtn = CSSM_DL_DataDelete(dlDb, record);
844 if(crtn) {
845 printError("CSSM_DL_DataDelete", crtn);
846 return crtn;
847 }
848 CSSM_DL_FreeUniqueRecord(dlDb, record);
849 break; // and go again
850 case CSSMERR_DL_ENDOFDATA:
851 /* normal termination */
852 break;
853 default:
854 printError("DataGetNext", crtn);
855 return crtn;
856 }
857 if(crtn != CSSM_OK) {
858 break;
859 }
860 }
861 CSSM_DL_DataAbortQuery(dlDb, resultHand);
862 return CSSM_OK;
863 }
864
865 /*
866 * Wrapper for CSSM_TP_CertGroupVerify. What an ugly API.
867 */
868 CSSM_RETURN tpCertGroupVerify(
869 CSSM_TP_HANDLE tpHand,
870 CSSM_CL_HANDLE clHand,
871 CSSM_CSP_HANDLE cspHand,
872 CSSM_DL_DB_LIST_PTR dbListPtr,
873 const CSSM_OID *policy, // optional
874 const CSSM_DATA *fieldOpts, // optional
875 const CSSM_DATA *actionData, // optional
876 void *policyOpts,
877 const CSSM_CERTGROUP *certGroup,
878 CSSM_DATA_PTR anchorCerts,
879 unsigned numAnchorCerts,
880 CSSM_TP_STOP_ON stopOn, // CSSM_TP_STOP_ON_POLICY, etc.
881 CSSM_TIMESTRING cssmTimeStr,// optional
882 CSSM_TP_VERIFY_CONTEXT_RESULT_PTR result) // optional, RETURNED
883 {
884 /* main job is building a CSSM_TP_VERIFY_CONTEXT and its components */
885 CSSM_TP_VERIFY_CONTEXT vfyCtx;
886 CSSM_TP_CALLERAUTH_CONTEXT authCtx;
887
888 memset(&vfyCtx, 0, sizeof(CSSM_TP_VERIFY_CONTEXT));
889 vfyCtx.Action = CSSM_TP_ACTION_DEFAULT;
890 if(actionData) {
891 vfyCtx.ActionData = *actionData;
892 }
893 else {
894 vfyCtx.ActionData.Data = NULL;
895 vfyCtx.ActionData.Length = 0;
896 }
897 vfyCtx.Cred = &authCtx;
898
899 /* CSSM_TP_CALLERAUTH_CONTEXT components */
900 /*
901 typedef struct cssm_tp_callerauth_context {
902 CSSM_TP_POLICYINFO Policy;
903 CSSM_TIMESTRING VerifyTime;
904 CSSM_TP_STOP_ON VerificationAbortOn;
905 CSSM_TP_VERIFICATION_RESULTS_CALLBACK CallbackWithVerifiedCert;
906 uint32 NumberOfAnchorCerts;
907 CSSM_DATA_PTR AnchorCerts;
908 CSSM_DL_DB_LIST_PTR DBList;
909 CSSM_ACCESS_CREDENTIALS_PTR CallerCredentials;
910 } CSSM_TP_CALLERAUTH_CONTEXT, *CSSM_TP_CALLERAUTH_CONTEXT_PTR;
911 */
912 /* zero or one policy here */
913 CSSM_FIELD policyId;
914 if(policy != NULL) {
915 policyId.FieldOid = (CSSM_OID)*policy;
916 authCtx.Policy.NumberOfPolicyIds = 1;
917 authCtx.Policy.PolicyIds = &policyId;
918 if(fieldOpts != NULL) {
919 policyId.FieldValue = *fieldOpts;
920 }
921 else {
922 policyId.FieldValue.Data = NULL;
923 policyId.FieldValue.Length = 0;
924 }
925 }
926 else {
927 authCtx.Policy.NumberOfPolicyIds = 0;
928 authCtx.Policy.PolicyIds = NULL;
929 }
930 authCtx.Policy.PolicyControl = policyOpts;
931 authCtx.VerifyTime = cssmTimeStr; // may be NULL
932 authCtx.VerificationAbortOn = stopOn;
933 authCtx.CallbackWithVerifiedCert = NULL;
934 authCtx.NumberOfAnchorCerts = numAnchorCerts;
935 authCtx.AnchorCerts = anchorCerts;
936 authCtx.DBList = dbListPtr;
937 authCtx.CallerCredentials = NULL;
938
939 return CSSM_TP_CertGroupVerify(tpHand,
940 clHand,
941 cspHand,
942 certGroup,
943 &vfyCtx,
944 result);
945 }
946
947 /*
948 * Open, optionally create, KC-style DLDB.
949 */
950 #define KC_DB_PATH "Library/Keychains" /* relative to home */
951
952 CSSM_RETURN tpKcOpen(
953 CSSM_DL_HANDLE dlHand,
954 const char *kcName,
955 const char *pwd, // optional to avoid UI
956 CSSM_BOOL doCreate,
957 CSSM_DB_HANDLE *dbHand) // RETURNED
958 {
959 char kcPath[300];
960 const char *kcFileName = kcName;
961 char *userHome = getenv("HOME");
962
963 if(userHome == NULL) {
964 /* well, this is probably not going to work */
965 userHome = (char *)"";
966 }
967 sprintf(kcPath, "%s/%s/%s", userHome, KC_DB_PATH, kcFileName);
968 return dbCreateOpen(dlHand, kcPath,
969 doCreate, CSSM_FALSE, pwd, dbHand);
970 }
971
972 /*
973 * Free the contents of a CSSM_TP_VERIFY_CONTEXT_RESULT returned from
974 * CSSM_TP_CertGroupVerify().
975 */
976 CSSM_RETURN freeVfyResult(
977 CSSM_TP_VERIFY_CONTEXT_RESULT *ctx)
978 {
979 int numCerts = -1;
980 CSSM_RETURN crtn = CSSM_OK;
981
982 for(unsigned i=0; i<ctx->NumberOfEvidences; i++) {
983 CSSM_EVIDENCE_PTR evp = &ctx->Evidence[i];
984 switch(evp->EvidenceForm) {
985 case CSSM_EVIDENCE_FORM_APPLE_HEADER:
986 /* Evidence = (CSSM_TP_APPLE_EVIDENCE_HEADER *) */
987 appFree(evp->Evidence, NULL);
988 evp->Evidence = NULL;
989 break;
990 case CSSM_EVIDENCE_FORM_APPLE_CERTGROUP:
991 {
992 /* Evidence = CSSM_CERTGROUP_PTR */
993 CSSM_CERTGROUP_PTR cgp = (CSSM_CERTGROUP_PTR)evp->Evidence;
994 numCerts = cgp->NumCerts;
995 tpFreeCertGroup(cgp, CSSM_TRUE, CSSM_TRUE);
996 evp->Evidence = NULL;
997 break;
998 }
999 case CSSM_EVIDENCE_FORM_APPLE_CERT_INFO:
1000 {
1001 /* Evidence = array of CSSM_TP_APPLE_EVIDENCE_INFO */
1002 if(numCerts < 0) {
1003 /* Haven't gotten a CSSM_CERTGROUP_PTR! */
1004 printf("***Malformed VerifyContextResult (2)\n");
1005 crtn = CSSMERR_TP_INTERNAL_ERROR;
1006 break;
1007 }
1008 CSSM_TP_APPLE_EVIDENCE_INFO *evInfo =
1009 (CSSM_TP_APPLE_EVIDENCE_INFO *)evp->Evidence;
1010 for(unsigned k=0; k<(unsigned)numCerts; k++) {
1011 /* Dispose of StatusCodes, UniqueRecord */
1012 CSSM_TP_APPLE_EVIDENCE_INFO *thisEvInfo =
1013 &evInfo[k];
1014 if(thisEvInfo->StatusCodes) {
1015 appFree(thisEvInfo->StatusCodes, NULL);
1016 }
1017 if(thisEvInfo->UniqueRecord) {
1018 CSSM_RETURN crtn =
1019 CSSM_DL_FreeUniqueRecord(thisEvInfo->DlDbHandle,
1020 thisEvInfo->UniqueRecord);
1021 if(crtn) {
1022 printError("CSSM_DL_FreeUniqueRecord", crtn);
1023 printf(" Record %p\n", thisEvInfo->UniqueRecord);
1024 break;
1025 }
1026 thisEvInfo->UniqueRecord = NULL;
1027 }
1028 } /* for each cert info */
1029 appFree(evp->Evidence, NULL);
1030 evp->Evidence = NULL;
1031 break;
1032 } /* CSSM_EVIDENCE_FORM_APPLE_CERT_INFO */
1033 } /* switch(evp->EvidenceForm) */
1034 } /* for each evidence */
1035 if(ctx->Evidence) {
1036 appFree(ctx->Evidence, NULL);
1037 ctx->Evidence = NULL;
1038 }
1039 return crtn;
1040 }
1041
1042 /* Display verify results */
1043 static void statusBitTest(
1044 CSSM_TP_APPLE_CERT_STATUS certStatus,
1045 uint32 bit,
1046 const char *str)
1047 {
1048 if(certStatus & bit) {
1049 printf("%s ", str);
1050 }
1051 }
1052
1053 void printCertInfo(
1054 unsigned numCerts, // from CertGroup
1055 const CSSM_TP_APPLE_EVIDENCE_INFO *info)
1056 {
1057 CSSM_TP_APPLE_CERT_STATUS cs;
1058
1059 for(unsigned i=0; i<numCerts; i++) {
1060 const CSSM_TP_APPLE_EVIDENCE_INFO *thisInfo = &info[i];
1061 cs = thisInfo->StatusBits;
1062 printf(" cert %u:\n", i);
1063 printf(" StatusBits : 0x%x", (unsigned)cs);
1064 if(cs) {
1065 printf(" ( ");
1066 statusBitTest(cs, CSSM_CERT_STATUS_EXPIRED, "EXPIRED");
1067 statusBitTest(cs, CSSM_CERT_STATUS_NOT_VALID_YET,
1068 "NOT_VALID_YET");
1069 statusBitTest(cs, CSSM_CERT_STATUS_IS_IN_INPUT_CERTS,
1070 "IS_IN_INPUT_CERTS");
1071 statusBitTest(cs, CSSM_CERT_STATUS_IS_IN_ANCHORS,
1072 "IS_IN_ANCHORS");
1073 statusBitTest(cs, CSSM_CERT_STATUS_IS_ROOT, "IS_ROOT");
1074 statusBitTest(cs, CSSM_CERT_STATUS_IS_FROM_NET, "IS_FROM_NET");
1075 statusBitTest(cs, CSSM_CERT_STATUS_TRUST_SETTINGS_FOUND_USER,
1076 "TRUST_SETTINGS_FOUND_USER");
1077 statusBitTest(cs, CSSM_CERT_STATUS_TRUST_SETTINGS_FOUND_ADMIN,
1078 "TRUST_SETTINGS_FOUND_ADMIN");
1079 statusBitTest(cs, CSSM_CERT_STATUS_TRUST_SETTINGS_FOUND_SYSTEM,
1080 "TRUST_SETTINGS_FOUND_SYSTEM");
1081 statusBitTest(cs, CSSM_CERT_STATUS_TRUST_SETTINGS_TRUST,
1082 "TRUST_SETTINGS_TRUST");
1083 statusBitTest(cs, CSSM_CERT_STATUS_TRUST_SETTINGS_DENY,
1084 "TRUST_SETTINGS_DENY");
1085 statusBitTest(cs, CSSM_CERT_STATUS_TRUST_SETTINGS_IGNORED_ERROR,
1086 "TRUST_SETTINGS_IGNORED_ERROR");
1087 printf(")\n");
1088 }
1089 else {
1090 printf("\n");
1091 }
1092 printf(" NumStatusCodes : %u ",
1093 (unsigned)thisInfo->NumStatusCodes);
1094 for(unsigned j=0; j<thisInfo->NumStatusCodes; j++) {
1095 printf("%s ",
1096 cssmErrToStr(thisInfo->StatusCodes[j]));
1097 }
1098 printf("\n");
1099 printf(" Index: %u\n", (unsigned)thisInfo->Index);
1100 }
1101 return;
1102 }
1103
1104 /* we really only need CSSM_EVIDENCE_FORM_APPLE_CERT_INFO */
1105 #define SHOW_ALL_VFY_RESULTS 0
1106
1107 void dumpVfyResult(
1108 const CSSM_TP_VERIFY_CONTEXT_RESULT *vfyResult)
1109 {
1110 unsigned numEvidences = vfyResult->NumberOfEvidences;
1111 unsigned numCerts = 0;
1112 printf("Returned evidence:\n");
1113 for(unsigned dex=0; dex<numEvidences; dex++) {
1114 CSSM_EVIDENCE_PTR ev = &vfyResult->Evidence[dex];
1115 #if SHOW_ALL_VFY_RESULTS
1116 printf(" Evidence %u:\n", dex);
1117 #endif
1118 switch(ev->EvidenceForm) {
1119 case CSSM_EVIDENCE_FORM_APPLE_HEADER:
1120 {
1121 #if SHOW_ALL_VFY_RESULTS
1122 const CSSM_TP_APPLE_EVIDENCE_HEADER *hdr =
1123 (const CSSM_TP_APPLE_EVIDENCE_HEADER *)(ev->Evidence);
1124 printf(" Form = HEADER; Version = %u\n", hdr->Version);
1125 #endif
1126 break;
1127 }
1128 case CSSM_EVIDENCE_FORM_APPLE_CERTGROUP:
1129 {
1130 const CSSM_CERTGROUP *grp =
1131 (const CSSM_CERTGROUP *)ev->Evidence;
1132 numCerts = grp->NumCerts;
1133 #if SHOW_ALL_VFY_RESULTS
1134 /* parse the rest of this eventually */
1135 /* Note we depend on this coming before the CERT_INFO */
1136 printf(" Form = CERTGROUP; numCerts = %u\n", numCerts);
1137 #endif
1138 break;
1139 }
1140 case CSSM_EVIDENCE_FORM_APPLE_CERT_INFO:
1141 {
1142 const CSSM_TP_APPLE_EVIDENCE_INFO *info =
1143 (const CSSM_TP_APPLE_EVIDENCE_INFO *)ev->Evidence;
1144 printCertInfo(numCerts, info);
1145 break;
1146 }
1147 default:
1148 printf("***UNKNOWN Evidence form (%u)\n",
1149 (unsigned)ev->EvidenceForm);
1150 break;
1151 }
1152 }
1153 }
1154
1155 /*
1156 * Obtain system anchors in CF and in CSSM_DATA form.
1157 * Caller must CFRelease the returned rootArray and
1158 * free() the returned CSSM_DATA array, but not its
1159 * contents - SecCertificates themselves own that.
1160 */
1161 OSStatus getSystemAnchors(
1162 CFArrayRef *rootArray, /* RETURNED */
1163 CSSM_DATA **anchors, /* RETURNED */
1164 unsigned *numAnchors) /* RETURNED */
1165 {
1166 OSStatus ortn;
1167 CFArrayRef cfAnchors;
1168 CSSM_DATA *cssmAnchors;
1169
1170 ortn = SecTrustSettingsCopyUnrestrictedRoots(false, false, true,
1171 &cfAnchors);
1172 if(ortn) {
1173 cssmPerror("SecTrustSettingsCopyUnrestrictedRoots", ortn);
1174 return ortn;
1175 }
1176 unsigned _numAnchors = CFArrayGetCount(cfAnchors);
1177 cssmAnchors = (CSSM_DATA *)malloc(sizeof(CSSM_DATA) * _numAnchors);
1178 unsigned dex;
1179 for(dex=0; dex<_numAnchors; dex++) {
1180 SecCertificateRef root = (SecCertificateRef)CFArrayGetValueAtIndex(
1181 cfAnchors, dex);
1182 ortn = SecCertificateGetData(root, &cssmAnchors[dex]);
1183 if(ortn) {
1184 cssmPerror("SecCertificateGetData", ortn);
1185 return ortn;
1186 }
1187 }
1188 *rootArray = cfAnchors;
1189 *anchors = cssmAnchors;
1190 *numAnchors = _numAnchors;
1191 return noErr;
1192 }
1193
1194 /* get a SecCertificateRef from a file */
1195 SecCertificateRef certFromFile(
1196 const char *fileName)
1197 {
1198 unsigned char *cp = NULL;
1199 unsigned len = 0;
1200 if(readFile(fileName, &cp, &len)) {
1201 printf("***Error reading file %s\n", fileName);
1202 return NULL;
1203 }
1204 SecCertificateRef certRef;
1205 CSSM_DATA certData = {len, cp};
1206 OSStatus ortn = SecCertificateCreateFromData(&certData,
1207 CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_DER, &certRef);
1208 if(ortn) {
1209 cssmPerror("SecCertificateCreateFromData", ortn);
1210 return NULL;
1211 }
1212 free(cp);
1213 return certRef;
1214 }
1215