2 * tpUtils.cpp - TP and cert group test support
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>
17 #include <Security/SecKeychainItem.h>
18 #include <Security/SecKeychain.h>
19 #include <Security/SecCertificate.h>
20 #include <security_cdsa_utils/cuFileIo.h>
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.
29 * Turn this option off if and when Radar 2927378 is approved and
30 * integrated into Security TOT.
32 #define FAKE_ADD_CERT_SCHEMA 1
33 #if FAKE_ADD_CERT_SCHEMA
35 /* defined in SecKeychainAPIPriv.h */
36 // static const int kSecAlias = 'alis';
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 }
42 /* Too bad we can't get this from inside of the Security framework. */
43 static CSSM_DB_SCHEMA_ATTRIBUTE_INFO certSchemaAttrInfo
[] =
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
)
55 #define NUM_CERT_SCHEMA_ATTRS \
56 (sizeof(certSchemaAttrInfo) / sizeof(CSSM_DB_SCHEMA_ATTRIBUTE_INFO))
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 }
63 static CSSM_DB_SCHEMA_INDEX_INFO certSchemaIndices
[] =
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
)
75 #define NUM_CERT_INDICES \
76 (sizeof(certSchemaIndices) / sizeof(CSSM_DB_SCHEMA_INDEX_INFO))
79 CSSM_RETURN
tpAddCertSchema(
80 CSSM_DL_DB_HANDLE dlDbHand
)
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
,
90 #endif /* FAKE_ADD_CERT_SCHEMA */
93 * Given a raw cert, extract DER-encoded normalized subject and issuer names.
95 static CSSM_DATA_PTR
tpGetNormSubject(
96 CSSM_CL_HANDLE clHand
,
97 const CSSM_DATA
*rawCert
)
100 CSSM_HANDLE searchHand
= CSSM_INVALID_HANDLE
;
102 CSSM_DATA_PTR fieldValue
;
104 crtn
= CSSM_CL_CertGetFirstFieldValue(clHand
,
106 &CSSMOID_X509V1SubjectName
,
111 printError("CSSM_CL_CertGetFirstFieldValue", crtn
);
114 CSSM_CL_CertAbortQuery(clHand
, searchHand
);
118 static CSSM_DATA_PTR
tpGetNormIssuer(
119 CSSM_CL_HANDLE clHand
,
120 const CSSM_DATA
*rawCert
)
123 CSSM_HANDLE searchHand
= CSSM_INVALID_HANDLE
;
125 CSSM_DATA_PTR fieldValue
;
127 crtn
= CSSM_CL_CertGetFirstFieldValue(clHand
,
129 &CSSMOID_X509V1IssuerName
,
134 printError("CSSM_CL_CertGetFirstFieldValue", crtn
);
137 CSSM_CL_CertAbortQuery(clHand
, searchHand
);
142 #define SERIAL_NUMBER_BASE 0x33445566
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.
151 CSSM_RETURN
tpMakeRandCertGroup(
152 CSSM_CL_HANDLE clHand
,
153 CSSM_DL_DB_LIST_PTR dbList
,
154 const CSSM_DATA_PTR certs
,
156 CSSM_CERTGROUP_PTR certGroup
,
157 CSSM_BOOL firstCertIsSubject
, // true: certs[0] goes to head
160 CSSM_BOOL allInDbs
, // all certs go to DBs
161 CSSM_BOOL skipFirstDb
) // no certs go to db[0]
163 unsigned startDex
= 0; // where to start processing
164 unsigned certDex
; // into certs and certGroup
169 if((dbList
== NULL
) && (allInDbs
| skipFirstDb
)) {
170 printf("need dbList for allInDbs or skipFirstDb\n");
171 return CSSM_ERRCODE_INTERNAL_ERROR
;
173 if(skipFirstDb
&& (dbList
->NumHandles
== 1)) {
174 printf("Need more than one DB for skipFirstDb\n");
175 return CSSM_ERRCODE_INTERNAL_ERROR
;
179 printf("TP/DB not supported yet\n");
180 return CSSMERR_CSSM_INTERNAL_ERROR
;
184 certGroup
->NumCerts
= 0;
185 certGroup
->CertGroupType
= CSSM_CERTGROUP_DATA
;
186 certGroup
->CertType
= CSSM_CERT_X_509v3
;
187 certGroup
->CertEncoding
= CSSM_CERT_ENCODING_DER
;
190 certGroup
->GroupList
.CertList
= NULL
;
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
;
200 if(firstCertIsSubject
) {
201 certGroup
->GroupList
.CertList
[0] = certs
[0];
202 certGroup
->NumCerts
= 1;
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 */
212 die
= genRand(1, dbList
->NumHandles
-1);
215 die
= genRand(0, dbList
->NumHandles
-1);
218 printf(" ...cert %d to DB[%d]\n", certDex
, die
);
220 crtn
= tpStoreRawCert(dbList
->DLDBHandle
[die
],
228 /* find a random unused place in certGroupFrag */
229 CSSM_DATA_PTR certData
;
232 die
= genRand(0, numCerts
-1);
233 certData
= &certGroup
->GroupList
.CertList
[die
];
234 if(certData
->Data
== NULL
) {
235 *certData
= certs
[certDex
];
236 certGroup
->NumCerts
++;
238 printf(" ...cert %d to frag[%d]\n",
243 /* else try again and hope we don't spin forever */
245 } /* random place in certGroup */
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.
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
) {
262 printf(" ...frag[%d] to frag[%d]\n",
265 certGroup
->GroupList
.CertList
[certDex
] =
266 certGroup
->GroupList
.CertList
[i
];
267 certGroup
->GroupList
.CertList
[i
].Data
= NULL
;
278 * Store a cert in specified DL/DB. All attributes are optional except
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
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
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
;
304 printf("***For now, must specify cert issuer when storing\n");
305 return CSSM_ERRCODE_INTERNAL_ERROR
;
308 /* how many attributes are we storing? */
309 numAttributes
= 4; // certType, serialNum, issuer, certEncoding
310 if(printName
!= NULL
) {
313 if(subject
!= NULL
) {
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
;
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
);
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
;
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
;
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
;
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
;
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
;
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
;
376 /* Okay, here we go */
377 CSSM_RETURN crtn
= CSSM_DL_DataInsert(dlDb
,
378 CSSM_DL_DB_RECORD_X509_CERTIFICATE
,
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
,
395 #endif /* FAKE_ADD_CERT_SCHEMA */
397 /* free resources allocated to get this far */
398 appFreeCssmData(serialNumData
, CSSM_TRUE
);
399 if(recordPtr
!= NULL
) {
400 CSSM_DL_FreeUniqueRecord(dlDb
, recordPtr
);
403 printError("CSSM_DL_DataInsert", crtn
);
409 * Store a cert when we don't already know the required fields. We'll
410 * extract them or make them up.
412 CSSM_RETURN
tpStoreRawCert(
413 CSSM_DL_DB_HANDLE dlDb
,
414 CSSM_CL_HANDLE clHand
,
415 const CSSM_DATA_PTR cert
)
417 CSSM_DATA_PTR normSubj
;
418 CSSM_DATA_PTR normIssuer
;
421 static uint32 fakeSerialNum
= 0;
423 normSubj
= tpGetNormSubject(clHand
, cert
);
424 normIssuer
= tpGetNormIssuer(clHand
, cert
);
425 if((normSubj
== NULL
) || (normIssuer
== NULL
)) {
426 return CSSM_ERRCODE_INTERNAL_ERROR
;
428 printName
.Data
= (uint8
*)"Some Printable Name";
429 printName
.Length
= strlen((char *)printName
.Data
);
430 crtn
= tpStoreCert(dlDb
,
435 CSSM_CERT_ENCODING_DER
,
438 appFreeCssmData(normSubj
, CSSM_TRUE
);
439 appFreeCssmData(normIssuer
, CSSM_TRUE
);
444 * Generate numKeyPairs key pairs of specified algorithm and size.
445 * Key labels will be 'keyLabelBase' concatenated with a 4-digit
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 */
462 unsigned labelLen
= strlen(keyLabelBase
);
464 memset(pubKeys
, 0, numKeyPairs
* sizeof(CSSM_KEY
));
465 memset(privKeys
, 0, numKeyPairs
* sizeof(CSSM_KEY
));
466 memmove(label
, keyLabelBase
, labelLen
);
468 for(i
=0; i
<numKeyPairs
; i
++) {
470 sprintf(label
+labelLen
, "%04d", i
);
471 if(keyGenAlg
== CSSM_ALGID_DSA
) {
472 crtn
= cspGenDSAKeyPair(cspHand
,
477 CSSM_FALSE
, // pubIsRef
478 CSSM_KEYUSE_VERIFY
, // pubKeyUsage
479 CSSM_KEYBLOB_RAW_FORMAT_NONE
,
481 CSSM_TRUE
, // privIsRef
483 CSSM_KEYBLOB_RAW_FORMAT_NONE
,
484 CSSM_FALSE
, // genParams
488 crtn
= cspGenKeyPair(cspHand
,
490 // not used in X, yet dbHand,
495 CSSM_FALSE
, // pubIsRef
496 CSSM_KEYUSE_VERIFY
, // pubKeyUsage
497 CSSM_KEYBLOB_RAW_FORMAT_NONE
,
499 CSSM_TRUE
, /// privIsRef
501 CSSM_KEYBLOB_RAW_FORMAT_NONE
,
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
);
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.
526 CSSM_RETURN
tpGenCerts(
527 CSSM_CSP_HANDLE cspHand
,
528 CSSM_CL_HANDLE clHand
,
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() */
538 return tpGenCertsStore(cspHand
,
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.
557 CSSM_RETURN
tpGenCertsStore(
558 CSSM_CSP_HANDLE cspHand
,
559 CSSM_CL_HANDLE clHand
,
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() */
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
580 CSSM_KEY_PTR signerKey
; // signs the cert
581 CSSM_CC_HANDLE signContext
;
583 CSSM_DATA_PTR thisCert
; // ptr into certs[]
585 CE_BasicConstraints bc
;
586 CSSM_X509_EXTENSION exten
;
588 nameOid
.oid
= &CSSMOID_OrganizationName
; // const
589 nameOid
.string
= nameStr
;
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;
599 bc
.pathLenConstraintPresent
= CSSM_FALSE
;
600 bc
.pathLenConstraint
= 0;
602 /* main loop - once per keypair/cert - starting at end/root */
603 for(dex
=numCerts
-1; dex
>=0; dex
--) {
604 thisCert
= &certs
[dex
];
606 thisCert
->Data
= NULL
;
607 thisCert
->Length
= 0;
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);
614 signerKey
= &privKeys
[dex
];
617 /* previous subject becomes current issuer */
618 CB_FreeX509Name(issuerName
);
619 issuerName
= subjectName
;
620 signerKey
= &privKeys
[dex
+1];
622 subjectName
= CB_BuildX509Name(&nameOid
, 1);
623 if((subjectName
== NULL
) || (issuerName
== NULL
)) {
624 printf("Error creating X509Names\n");
625 crtn
= CSSMERR_CSSM_MEMORY_ERROR
;
630 * not before/after in Y2k-compliant generalized time format.
631 * These come preformatted from our caller.
633 notBefore
= CB_BuildX509Time(0, notBeforeStr
);
634 notAfter
= CB_BuildX509Time(0, notAfterStr
);
637 * Cook up cert template
638 * Note serial number would be app-specified in real world
640 rawCert
= CB_MakeCertTemplate(clHand
,
641 SERIAL_NUMBER_BASE
+ dex
, // serial number
648 NULL
, // subj unique ID
649 NULL
, // issuer unique ID
650 &exten
, // extensions
651 (dex
== 0) ? 0 : 1);// numExtensions
653 if(rawCert
== NULL
) {
654 crtn
= CSSM_ERRCODE_INTERNAL_ERROR
;
658 /* Free the stuff we allocd to get here */
659 CB_FreeX509Time(notBefore
);
660 CB_FreeX509Time(notAfter
);
662 /**** sign the cert ****/
663 /* 1. get a signing context */
664 crtn
= CSSM_CSP_CreateSignatureContext(cspHand
,
666 NULL
, // no passphrase for now
670 printError("CreateSignatureContext", crtn
);
674 /* 2. use CL to sign the cert */
675 signedCert
.Data
= NULL
;
676 signedCert
.Length
= 0;
677 crtn
= CSSM_CL_CertSign(clHand
,
679 rawCert
, // CertToBeSigned
680 NULL
, // SignScope per spec
681 0, // ScopeSize per spec
684 printError("CSSM_CL_CertSign", crtn
);
688 /* 3. Optionally store the cert in DL */
689 if((storeArray
!= NULL
) && storeArray
[dex
].DBHandle
!= 0) {
690 crtn
= tpStoreRawCert(storeArray
[dex
],
698 /* 4. delete signing context */
699 crtn
= CSSM_DeleteContext(signContext
);
701 printError("CSSM_DeleteContext", crtn
);
706 * CSSM_CL_CertSign() returned us a mallocd CSSM_DATA. Copy
707 * its fields to caller's cert.
709 certs
[dex
] = signedCert
;
711 /* and the raw unsigned cert as well */
712 appFreeCssmData(rawCert
, CSSM_TRUE
);
717 if(issuerName
!= NULL
) {
718 CB_FreeX509Name(issuerName
);
720 if(subjectName
!= NULL
) {
721 CB_FreeX509Name(subjectName
);
726 /* compare two CSSM_CERTGROUPs, returns CSSM_TRUE on success */
727 CSSM_BOOL
tpCompareCertGroups(
728 const CSSM_CERTGROUP
*grp1
,
729 const CSSM_CERTGROUP
*grp2
)
735 if(grp1
->NumCerts
!= grp2
->NumCerts
) {
738 for(i
=0; i
<grp1
->NumCerts
; i
++) {
739 d1
= &grp1
->GroupList
.CertList
[i
];
740 d2
= &grp2
->GroupList
.CertList
[i
];
742 /* these are all errors */
743 if((d1
->Data
== NULL
) ||
745 (d2
->Data
== NULL
) ||
747 printf("compareCertGroups: bad cert group!\n");
750 if(d1
->Length
!= d2
->Length
) {
753 if(memcmp(d1
->Data
, d2
->Data
, d1
->Length
)) {
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
768 if(certGroup
== NULL
) {
773 /* free the individual cert Data fields */
774 for(dex
=0; dex
<certGroup
->NumCerts
; dex
++) {
775 appFreeCssmData(&certGroup
->GroupList
.CertList
[dex
], CSSM_FALSE
);
779 /* and the array of CSSM_DATAs */
780 if(certGroup
->GroupList
.CertList
) {
781 CSSM_FREE(certGroup
->GroupList
.CertList
);
785 CSSM_FREE(certGroup
);
789 CSSM_RETURN
clDeleteAllCerts(CSSM_DL_DB_HANDLE dlDb
)
792 CSSM_DB_UNIQUE_RECORD_PTR record
= NULL
;
794 CSSM_HANDLE resultHand
;
795 CSSM_DB_RECORD_ATTRIBUTE_DATA recordAttrs
;
797 recordAttrs
.DataRecordType
= CSSM_DL_DB_RECORD_X509_CERTIFICATE
;
798 recordAttrs
.NumberOfAttributes
= 0;
799 recordAttrs
.AttributeData
= NULL
;
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?
810 crtn
= CSSM_DL_DataGetFirst(dlDb
,
819 case CSSMERR_DL_ENDOFDATA
:
823 printError("DataGetFirst", crtn
);
827 crtn
= CSSM_DL_DataDelete(dlDb
, record
);
829 printError("CSSM_DL_DataDelete", crtn
);
832 CSSM_DL_FreeUniqueRecord(dlDb
, record
);
834 /* now the rest of them */
836 crtn
= CSSM_DL_DataGetNext(dlDb
,
843 crtn
= CSSM_DL_DataDelete(dlDb
, record
);
845 printError("CSSM_DL_DataDelete", crtn
);
848 CSSM_DL_FreeUniqueRecord(dlDb
, record
);
849 break; // and go again
850 case CSSMERR_DL_ENDOFDATA
:
851 /* normal termination */
854 printError("DataGetNext", crtn
);
857 if(crtn
!= CSSM_OK
) {
861 CSSM_DL_DataAbortQuery(dlDb
, resultHand
);
866 * Wrapper for CSSM_TP_CertGroupVerify. What an ugly API.
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
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
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
;
888 memset(&vfyCtx
, 0, sizeof(CSSM_TP_VERIFY_CONTEXT
));
889 vfyCtx
.Action
= CSSM_TP_ACTION_DEFAULT
;
891 vfyCtx
.ActionData
= *actionData
;
894 vfyCtx
.ActionData
.Data
= NULL
;
895 vfyCtx
.ActionData
.Length
= 0;
897 vfyCtx
.Cred
= &authCtx
;
899 /* CSSM_TP_CALLERAUTH_CONTEXT components */
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;
912 /* zero or one policy here */
915 policyId
.FieldOid
= (CSSM_OID
)*policy
;
916 authCtx
.Policy
.NumberOfPolicyIds
= 1;
917 authCtx
.Policy
.PolicyIds
= &policyId
;
918 if(fieldOpts
!= NULL
) {
919 policyId
.FieldValue
= *fieldOpts
;
922 policyId
.FieldValue
.Data
= NULL
;
923 policyId
.FieldValue
.Length
= 0;
927 authCtx
.Policy
.NumberOfPolicyIds
= 0;
928 authCtx
.Policy
.PolicyIds
= NULL
;
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
;
939 return CSSM_TP_CertGroupVerify(tpHand
,
948 * Open, optionally create, KC-style DLDB.
950 #define KC_DB_PATH "Library/Keychains" /* relative to home */
952 CSSM_RETURN
tpKcOpen(
953 CSSM_DL_HANDLE dlHand
,
955 const char *pwd
, // optional to avoid UI
957 CSSM_DB_HANDLE
*dbHand
) // RETURNED
960 const char *kcFileName
= kcName
;
961 char *userHome
= getenv("HOME");
963 if(userHome
== NULL
) {
964 /* well, this is probably not going to work */
965 userHome
= (char *)"";
967 sprintf(kcPath
, "%s/%s/%s", userHome
, KC_DB_PATH
, kcFileName
);
968 return dbCreateOpen(dlHand
, kcPath
,
969 doCreate
, CSSM_FALSE
, pwd
, dbHand
);
973 * Free the contents of a CSSM_TP_VERIFY_CONTEXT_RESULT returned from
974 * CSSM_TP_CertGroupVerify().
976 CSSM_RETURN
freeVfyResult(
977 CSSM_TP_VERIFY_CONTEXT_RESULT
*ctx
)
980 CSSM_RETURN crtn
= CSSM_OK
;
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
;
990 case CSSM_EVIDENCE_FORM_APPLE_CERTGROUP
:
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
;
999 case CSSM_EVIDENCE_FORM_APPLE_CERT_INFO
:
1001 /* Evidence = array of CSSM_TP_APPLE_EVIDENCE_INFO */
1003 /* Haven't gotten a CSSM_CERTGROUP_PTR! */
1004 printf("***Malformed VerifyContextResult (2)\n");
1005 crtn
= CSSMERR_TP_INTERNAL_ERROR
;
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
=
1014 if(thisEvInfo
->StatusCodes
) {
1015 appFree(thisEvInfo
->StatusCodes
, NULL
);
1017 if(thisEvInfo
->UniqueRecord
) {
1019 CSSM_DL_FreeUniqueRecord(thisEvInfo
->DlDbHandle
,
1020 thisEvInfo
->UniqueRecord
);
1022 printError("CSSM_DL_FreeUniqueRecord", crtn
);
1023 printf(" Record %p\n", thisEvInfo
->UniqueRecord
);
1026 thisEvInfo
->UniqueRecord
= NULL
;
1028 } /* for each cert info */
1029 appFree(evp
->Evidence
, NULL
);
1030 evp
->Evidence
= NULL
;
1032 } /* CSSM_EVIDENCE_FORM_APPLE_CERT_INFO */
1033 } /* switch(evp->EvidenceForm) */
1034 } /* for each evidence */
1036 appFree(ctx
->Evidence
, NULL
);
1037 ctx
->Evidence
= NULL
;
1042 /* Display verify results */
1043 static void statusBitTest(
1044 CSSM_TP_APPLE_CERT_STATUS certStatus
,
1048 if(certStatus
& bit
) {
1054 unsigned numCerts
, // from CertGroup
1055 const CSSM_TP_APPLE_EVIDENCE_INFO
*info
)
1057 CSSM_TP_APPLE_CERT_STATUS cs
;
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
);
1066 statusBitTest(cs
, CSSM_CERT_STATUS_EXPIRED
, "EXPIRED");
1067 statusBitTest(cs
, CSSM_CERT_STATUS_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
,
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");
1092 printf(" NumStatusCodes : %u ",
1093 (unsigned)thisInfo
->NumStatusCodes
);
1094 for(unsigned j
=0; j
<thisInfo
->NumStatusCodes
; j
++) {
1096 cssmErrToStr(thisInfo
->StatusCodes
[j
]));
1099 printf(" Index: %u\n", (unsigned)thisInfo
->Index
);
1104 /* we really only need CSSM_EVIDENCE_FORM_APPLE_CERT_INFO */
1105 #define SHOW_ALL_VFY_RESULTS 0
1108 const CSSM_TP_VERIFY_CONTEXT_RESULT
*vfyResult
)
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
);
1118 switch(ev
->EvidenceForm
) {
1119 case CSSM_EVIDENCE_FORM_APPLE_HEADER
:
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
);
1128 case CSSM_EVIDENCE_FORM_APPLE_CERTGROUP
:
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
);
1140 case CSSM_EVIDENCE_FORM_APPLE_CERT_INFO
:
1142 const CSSM_TP_APPLE_EVIDENCE_INFO
*info
=
1143 (const CSSM_TP_APPLE_EVIDENCE_INFO
*)ev
->Evidence
;
1144 printCertInfo(numCerts
, info
);
1148 printf("***UNKNOWN Evidence form (%u)\n",
1149 (unsigned)ev
->EvidenceForm
);
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.
1161 OSStatus
getSystemAnchors(
1162 CFArrayRef
*rootArray
, /* RETURNED */
1163 CSSM_DATA
**anchors
, /* RETURNED */
1164 unsigned *numAnchors
) /* RETURNED */
1167 CFArrayRef cfAnchors
;
1168 CSSM_DATA
*cssmAnchors
;
1170 ortn
= SecTrustSettingsCopyUnrestrictedRoots(false, false, true,
1173 cssmPerror("SecTrustSettingsCopyUnrestrictedRoots", ortn
);
1176 unsigned _numAnchors
= CFArrayGetCount(cfAnchors
);
1177 cssmAnchors
= (CSSM_DATA
*)malloc(sizeof(CSSM_DATA
) * _numAnchors
);
1179 for(dex
=0; dex
<_numAnchors
; dex
++) {
1180 SecCertificateRef root
= (SecCertificateRef
)CFArrayGetValueAtIndex(
1182 ortn
= SecCertificateGetData(root
, &cssmAnchors
[dex
]);
1184 cssmPerror("SecCertificateGetData", ortn
);
1188 *rootArray
= cfAnchors
;
1189 *anchors
= cssmAnchors
;
1190 *numAnchors
= _numAnchors
;
1194 /* get a SecCertificateRef from a file */
1195 SecCertificateRef
certFromFile(
1196 const char *fileName
)
1198 unsigned char *cp
= NULL
;
1200 if(readFile(fileName
, &cp
, &len
)) {
1201 printf("***Error reading file %s\n", fileName
);
1204 SecCertificateRef certRef
;
1205 CSSM_DATA certData
= {len
, cp
};
1206 OSStatus ortn
= SecCertificateCreateFromData(&certData
,
1207 CSSM_CERT_X_509v3
, CSSM_CERT_ENCODING_DER
, &certRef
);
1209 cssmPerror("SecCertificateCreateFromData", ortn
);