--- /dev/null
+/*
+ * secTrustTime.cpp - measure performance of SecTrust and TP cert verify
+ */
+
+#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");
+ /* etc. */
+ 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;
+}
+
+/* perfrom one cert chain evaluation using SecTrust */
+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;
+}
+
+/* cached CSSM anchors - simulate old SecTrustGetCSSMAnchorCertificates() */
+static CFArrayRef cachedRootArray = NULL;
+static CSSM_DATA *cachedAnchors = NULL;
+static unsigned cachedNumAnchors = 0;
+
+static OSStatus getAnchors(
+ CSSM_DATA **anchors, /* RETURNED */
+ unsigned *numAnchors) /* RETURNED */
+{
+ if(cachedRootArray == NULL) {
+ /* fetch, once */
+ OSStatus ortn = getSystemAnchors(&cachedRootArray, &cachedAnchors,
+ &cachedNumAnchors);
+ if(ortn) {
+ return ortn;
+ }
+ }
+ *anchors = cachedAnchors;
+ *numAnchors = cachedNumAnchors;
+ return noErr;
+}
+
+/* perfrom one cert chain evaluation using CSSM_TP_CertGroupVerify */
+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); /* no results */
+ if(crtn) {
+ cssmPerror("CSSM_TP_CertGroupVerify", crtn);
+ }
+ return crtn;
+}
+
+int main(int argc, char **argv)
+{
+ unsigned dex;
+ CSSM_RETURN crtn;
+
+ /* common SecTrust args */
+ CFMutableArrayRef kcList = NULL;
+ CFMutableArrayRef certArray = NULL;
+ SecPolicyRef policyRef = NULL;
+ unsigned numCerts = NUM_CERTS;
+ CFArrayRef emptyKCList = NULL;
+
+ /* common TP args */
+ CSSM_TP_HANDLE tpHand;
+ CSSM_CL_HANDLE clHand;
+ CSSM_CSP_HANDLE cspHand;
+ CSSM_DATA cssmCerts[NUM_CERTS];
+
+ /* user-spec'd variables */
+ unsigned loops = LOOPS_DEF;
+ bool holdKeychains = false; /* hold references to KC list during operation */
+ bool useTp = false; /* TP, not SecTrust */
+ bool useTrustSettings = true; /* TP w/TrustSettings; false = old school TP way */
+ bool noRoot = false; /* don't include root in chain to be verified */
+ bool emptyList = false; /* SecTrust only: specify empty KC list */
+
+ 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);
+ }
+
+ /* gather certs to verify */
+ 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);
+ }
+
+ /* prepare for one method or another */
+ 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 {
+ /* cook up reusable policy object */
+ SecPolicySearchRef policySearch = NULL;
+ OSStatus ortn = SecPolicySearchCreate(CSSM_CERT_X_509v3,
+ &CSSMOID_APPLE_X509_BASIC,
+ NULL, // policy opts
+ &policySearch);
+ if(ortn) {
+ cssmPerror("SecPolicySearchCreate", ortn);
+ exit(1);
+ }
+ ortn = SecPolicySearchCopyNext(policySearch, &policyRef);
+ if(ortn) {
+ cssmPerror("SecPolicySearchCopyNext", ortn);
+ exit(1);
+ }
+ CFRelease(policySearch);
+
+ if(holdKeychains) {
+ /* the standard keychains */
+ ortn = SecKeychainCopySearchList((CFArrayRef *)&kcList);
+ if(ortn) {
+ cssmPerror("SecKeychainCopySearchList", ortn);
+ exit(1);
+ }
+
+ /* plus the ones TrustSettings needs */
+ 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;
+
+ /* print a banner describing current test parameters */
+ 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");
+ }
+
+ /* GO */
+ 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;
+}