#include <stdlib.h>
#include <strings.h>
#include <stdio.h>
#include <unistd.h>
#include <CoreFoundation/CoreFoundation.h>
#include <Security/Security.h>
#include <Security/TrustSettingsSchema.h>
#include <security_cdsa_utils/cuFileIo.h>
#include <utilLib/common.h>
#include <clAppUtils/clutils.h>
#include <clAppUtils/tpUtils.h>
#define LOOPS_DEF 100
const char *certFiles[] = {
"keybank_v3.100.cer", "keybank_v3.101.cer", "keybank_v3.102.cer"
};
#define NUM_CERTS (sizeof(certFiles) / sizeof(certFiles[0]))
static void usage(char **argv)
{
printf("usage: %s [options]\n", argv[0]);
printf("Options:\n");
printf(" -l loops -- loops; default %d; 0=forever\n", LOOPS_DEF);
printf(" -k -- open and hold keychains\n");
printf(" -t -- TP, not SecTrust\n");
printf(" -T -- TP, no Trust Settings\n");
printf(" -n -- don't include root in cert chain\n");
printf(" -K -- set empty KC list\n");
exit(1);
}
static SecCertificateRef readCertFile(
const char *fileName)
{
unsigned char *cp = NULL;
unsigned len = 0;
CSSM_DATA certData;
OSStatus ortn;
if(readFile(fileName, &cp, &len)) {
printf("***Error reading file %s\n", fileName);
return NULL;
}
certData.Length = len;
certData.Data = cp;
SecCertificateRef certRef;
ortn = SecCertificateCreateFromData(&certData,
CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_DER, &certRef);
if(ortn) {
cssmPerror("SecCertificateCreateFromData", ortn);
return NULL;
}
free(cp);
return certRef;
}
static OSStatus doEval(
CFArrayRef certArray,
SecPolicyRef policyRef,
CFArrayRef kcList)
{
OSStatus ortn;
SecTrustRef trustRef;
ortn = SecTrustCreateWithCertificates(certArray, policyRef, &trustRef);
if(ortn) {
cssmPerror("SecTrustCreateWithCertificates", ortn);
return ortn;
}
if(kcList) {
ortn = SecTrustSetKeychains(trustRef, kcList);
if(ortn) {
cssmPerror("SecTrustCreateWithCertificates", ortn);
return ortn;
}
}
SecTrustResultType secTrustResult;
ortn = SecTrustEvaluate(trustRef, &secTrustResult);
if(ortn) {
cssmPerror("SecTrustEvaluate", ortn);
return ortn;
}
switch(secTrustResult) {
case kSecTrustResultProceed:
case kSecTrustResultUnspecified:
break;
default:
printf("***Unexpected SecTrustResultType (%d)\n", (int)secTrustResult);
ortn = -1;
}
CFRelease(trustRef);
return ortn;
}
static CFArrayRef cachedRootArray = NULL;
static CSSM_DATA *cachedAnchors = NULL;
static unsigned cachedNumAnchors = 0;
static OSStatus getAnchors(
CSSM_DATA **anchors,
unsigned *numAnchors)
{
if(cachedRootArray == NULL) {
OSStatus ortn = getSystemAnchors(&cachedRootArray, &cachedAnchors,
&cachedNumAnchors);
if(ortn) {
return ortn;
}
}
*anchors = cachedAnchors;
*numAnchors = cachedNumAnchors;
return noErr;
}
static CSSM_RETURN doTpEval(
CSSM_TP_HANDLE tpHand,
CSSM_CL_HANDLE clHand,
CSSM_CSP_HANDLE cspHand,
CSSM_DATA_PTR certs,
uint32 numCerts,
bool useTrustSettings)
{
CSSM_FIELD policyId;
policyId.FieldOid = CSSMOID_APPLE_X509_BASIC;
policyId.FieldValue.Data = NULL;
policyId.FieldValue.Length = 0;
CSSM_TP_CALLERAUTH_CONTEXT authCtx;
memset(&authCtx, 0, sizeof(CSSM_TP_CALLERAUTH_CONTEXT));
authCtx.Policy.NumberOfPolicyIds = 1;
authCtx.Policy.PolicyIds = &policyId;
authCtx.VerificationAbortOn = CSSM_TP_STOP_ON_POLICY;
if(!useTrustSettings) {
OSStatus ortn = getAnchors(&authCtx.AnchorCerts,
&authCtx.NumberOfAnchorCerts);
if(ortn) {
return ortn;
}
}
CSSM_APPLE_TP_ACTION_DATA tpAction;
tpAction.Version = CSSM_APPLE_TP_ACTION_VERSION;
if(useTrustSettings) {
tpAction.ActionFlags = CSSM_TP_ACTION_TRUST_SETTINGS;
}
else {
tpAction.ActionFlags = 0;
}
CSSM_TP_VERIFY_CONTEXT vfyCtx;
memset(&vfyCtx, 0, sizeof(CSSM_TP_VERIFY_CONTEXT));
vfyCtx.ActionData.Data = (uint8 *)&tpAction;
vfyCtx.ActionData.Length = sizeof(tpAction);
vfyCtx.Action = CSSM_TP_ACTION_DEFAULT;
vfyCtx.Cred = &authCtx;
CSSM_CERTGROUP cssmCerts;
cssmCerts.CertType = CSSM_CERT_X_509v3;
cssmCerts.CertEncoding = CSSM_CERT_ENCODING_DER;
cssmCerts.NumCerts = numCerts;
cssmCerts.GroupList.CertList = certs;
cssmCerts.CertGroupType = CSSM_CERTGROUP_DATA;
CSSM_RETURN crtn = CSSM_TP_CertGroupVerify(tpHand, clHand, cspHand,
&cssmCerts,
&vfyCtx,
NULL);
if(crtn) {
cssmPerror("CSSM_TP_CertGroupVerify", crtn);
}
return crtn;
}
int main(int argc, char **argv)
{
unsigned dex;
CSSM_RETURN crtn;
CFMutableArrayRef kcList = NULL;
CFMutableArrayRef certArray = NULL;
SecPolicyRef policyRef = NULL;
unsigned numCerts = NUM_CERTS;
CFArrayRef emptyKCList = NULL;
CSSM_TP_HANDLE tpHand;
CSSM_CL_HANDLE clHand;
CSSM_CSP_HANDLE cspHand;
CSSM_DATA cssmCerts[NUM_CERTS];
unsigned loops = LOOPS_DEF;
bool holdKeychains = false;
bool useTp = false;
bool useTrustSettings = true;
bool noRoot = false;
bool emptyList = false;
extern char *optarg;
int arg;
while ((arg = getopt(argc, argv, "l:ktTnKh")) != -1) {
switch (arg) {
case 'l':
loops = atoi(optarg);
break;
case 'k':
holdKeychains = true;
break;
case 't':
useTp = true;
break;
case 'T':
useTp = true;
useTrustSettings = false;
break;
case 'n':
numCerts--;
noRoot = true;
break;
case 'K':
emptyList = true;
emptyKCList = CFArrayCreate(NULL, NULL, 0, &kCFTypeArrayCallBacks);
break;
case 'h':
usage(argv);
}
}
if(optind != argc) {
usage(argv);
}
certArray = CFArrayCreateMutable(NULL, 3, &kCFTypeArrayCallBacks);
for(dex=0; dex<numCerts; dex++) {
SecCertificateRef certRef = readCertFile(certFiles[dex]);
if(certRef == NULL) {
exit(1);
}
CFArrayInsertValueAtIndex(certArray, dex, certRef);
CFRelease(certRef);
}
if(useTp) {
for(dex=0; dex<numCerts; dex++) {
crtn = SecCertificateGetData(
(SecCertificateRef)CFArrayGetValueAtIndex(certArray, dex),
&cssmCerts[dex]);
if(crtn) {
cssmPerror("SecCertificateGetData", crtn);
exit(1);
}
}
tpHand = tpStartup();
clHand = clStartup();
cspHand = cspStartup();
}
else {
SecPolicySearchRef policySearch = NULL;
OSStatus ortn = SecPolicySearchCreate(CSSM_CERT_X_509v3,
&CSSMOID_APPLE_X509_BASIC,
NULL, &policySearch);
if(ortn) {
cssmPerror("SecPolicySearchCreate", ortn);
exit(1);
}
ortn = SecPolicySearchCopyNext(policySearch, &policyRef);
if(ortn) {
cssmPerror("SecPolicySearchCopyNext", ortn);
exit(1);
}
CFRelease(policySearch);
if(holdKeychains) {
ortn = SecKeychainCopySearchList((CFArrayRef *)&kcList);
if(ortn) {
cssmPerror("SecKeychainCopySearchList", ortn);
exit(1);
}
SecKeychainRef rootKc;
ortn = SecKeychainOpen(SYSTEM_ROOT_STORE_PATH, &rootKc);
if(ortn) {
cssmPerror("SecKeychainOpen", ortn);
exit(1);
}
CFArrayAppendValue(kcList, rootKc);
CFRelease(rootKc);
}
}
CFAbsoluteTime startTimeFirst;
CFAbsoluteTime endTimeFirst;
CFAbsoluteTime startTimeMulti;
CFAbsoluteTime endTimeMulti;
printf("Starting test: mode = ");
if(useTp) {
if(useTrustSettings) {
printf("TP w/TrustSettings");
}
else {
printf("TP w/o TrustSettings");
}
}
else {
printf("SecTrust");
if(holdKeychains) {
printf("; hold KC refs");
}
if(emptyList) {
printf("; empty KC list");
}
}
if(noRoot) {
printf("; no root in input certs\n");
}
else {
printf("\n");
}
startTimeFirst = CFAbsoluteTimeGetCurrent();
if(useTp) {
if(doTpEval(tpHand, clHand, cspHand, cssmCerts, numCerts,
useTrustSettings)) {
exit(1);
}
endTimeFirst = CFAbsoluteTimeGetCurrent();
startTimeMulti = CFAbsoluteTimeGetCurrent();
for(dex=0; dex<loops; dex++) {
if(doTpEval(tpHand, clHand, cspHand, cssmCerts, numCerts,
useTrustSettings)) {
exit(1);
}
}
}
else {
if(doEval(certArray, policyRef, emptyKCList)) {
exit(1);
}
endTimeFirst = CFAbsoluteTimeGetCurrent();
startTimeMulti = CFAbsoluteTimeGetCurrent();
for(dex=0; dex<loops; dex++) {
if(doEval(certArray, policyRef, emptyKCList)) {
exit(1);
}
}
}
endTimeMulti = CFAbsoluteTimeGetCurrent();
CFTimeInterval elapsed = endTimeMulti - startTimeMulti;
printf("First eval = %4.1f ms\n", (endTimeFirst - startTimeFirst) * 1000.0);
printf("Next evals = %4.2f ms/op (%f s total for %u loops)\n",
elapsed * 1000.0 / loops, elapsed, loops);
return 0;
}