#include <Security/Security.h>
#include <security_cdsa_utils/cuFileIo.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/param.h>
#include <CoreFoundation/CoreFoundation.h>
#include <security_utilities/devrandom.h>
#include <clAppUtils/certVerify.h>
#include <clAppUtils/clutils.h>
#include <utilLib/common.h>
#define ST_KC_NAME "secTimeKc"
typedef struct {
const char *certFileName;
const char *hostName;
} CertToVerify;
static const CertToVerify certsToVerify[] =
{
{
"amazon_v3.100.cer",
"www.amazon.com"
},
{
"firstamlink.cer",
"www.firstamlink.com"
},
};
#define NUM_ST_CERTS (sizeof(certsToVerify) / sizeof(certsToVerify[0]))
#define ST_ANCHOR_NAME "SecureServer.509.cer"
#define THAWTE_LEAF "dmitchThawte.cer"
#define THAWTE_CA "ThawteCA.cer"
#define THAWTE_ROOT "ThawteRoot.cer"
static void usage(char **argv)
{
printf("Usage: %s [option ...]\n", argv[0]);
printf("Options:\n");
printf(" t=testspec; default=all\n");
printf(" test specs: o keychainOpen\n");
printf(" s keychainSearch\n");
printf(" e secTrustEvaluate\n");
printf(" k SecKeychainCopySearchList\n");
printf(" v TP CertGroupVerify, system anchor\n");
printf(" V TP CertGroupVerify, explicit anchor\n");
printf(" 3 TP CertGroupVerify, 3 certs w/anchor\n");
printf(" l=loops (only valid if testspec is given)\n");
exit(1);
}
static void printSecErr(
const char *op,
OSStatus ortn)
{
printf("%s returned %ld\n", op, (unsigned long)ortn);
}
typedef struct {
const char *testName;
void *testPriv;
} TestParams;
typedef OSStatus (*testInitFcn)(TestParams *testParams);
typedef OSStatus (*testRunFcn)(TestParams *testParams,
unsigned loopNum,
CFAbsoluteTime *timeSpent);
typedef OSStatus (*testCleanupFcn)(TestParams *testParams);
typedef struct {
const char *testName;
unsigned loops;
testInitFcn init;
testRunFcn run;
testCleanupFcn cleanup;
char testSpec; } TestDefs;
#pragma mark ---- Individual tests ----
#ifdef use_these_as_a_template
static OSStatus xxxInit(
TestParams *testParams)
{
return noErr;
}
static OSStatus xxRun(
TestParams *testParams,
unsigned loopNum,
CFAbsoluteTime *timeSpent)
{
CFAbsoluteTime startTime = CFAbsoluteTimeGetCurrent();
*timeSpent = CFAbsoluteTimeGetCurrent() - startTime;
return noErr;
}
static OSStatus xxxCleanup(
TestParams *testParams)
{
return noErr;
}
#endif
#pragma mark -- keychain open --
static OSStatus kcOpenInit(
TestParams *testParams)
{
return noErr;
}
static OSStatus kcOpenRun(
TestParams *testParams,
unsigned loopNum,
CFAbsoluteTime *timeSpent)
{
SecKeychainRef kcRef;
SecKeychainStatus status;
CFAbsoluteTime startTime = CFAbsoluteTimeGetCurrent();
OSStatus ortn = SecKeychainOpen(ST_KC_NAME, &kcRef);
if(ortn) {
printSecErr("SecKeychainOpen", ortn);
return ortn;
}
ortn = SecKeychainGetStatus(kcRef, &status);
if(ortn) {
printSecErr("SecKeychainGetStatus", ortn);
CFRelease(kcRef);
if(errSecNoSuchKeychain == ortn) {
printf("The keychain %s does not exist. Please create it"
" and populate it like so:\n", ST_KC_NAME);
printf(" certtool c k=%s c p=%s Z\n",
ST_KC_NAME, ST_KC_NAME);
}
return ortn;
}
CFAbsoluteTime endTime = CFAbsoluteTimeGetCurrent();
*timeSpent = endTime - startTime;
CFRelease(kcRef);
return noErr;
}
static OSStatus kcOpenCleanup(
TestParams *testParams)
{
return noErr;
}
#pragma mark -- keychain lookup --
static OSStatus kcSearchInit(
TestParams *testParams)
{
SecKeychainRef kcRef;
OSStatus ortn = SecKeychainOpen(ST_KC_NAME, &kcRef);
if(ortn) {
printSecErr("SecKeychainOpen", ortn);
return ortn;
}
testParams->testPriv = (void *)kcRef;
return noErr;
}
static OSStatus kcSearchRun(
TestParams *testParams,
unsigned loopNum,
CFAbsoluteTime *timeSpent)
{
SecKeychainRef kcRef = (SecKeychainRef)testParams->testPriv;
SecKeychainSearchRef srchRef = NULL;
SecKeychainItemRef certRef = NULL;
CFAbsoluteTime endTime;
CFAbsoluteTime startTime = CFAbsoluteTimeGetCurrent();
OSStatus ortn = SecKeychainSearchCreateFromAttributes(kcRef,
kSecCertificateItemClass,
NULL, &srchRef);
if(ortn) {
printSecErr("SecKeychainSearchCreateFromAttributes", ortn);
return ortn;
}
ortn = SecKeychainSearchCopyNext(srchRef, &certRef);
if(ortn) {
printSecErr("SecKeychainSearchCopyNext", ortn);
goto done;
}
endTime = CFAbsoluteTimeGetCurrent();
*timeSpent = endTime - startTime;
done:
if(srchRef) {
CFRelease(srchRef);
}
if(certRef) {
CFRelease(certRef);
}
return ortn;
}
static OSStatus kcSearchCleanup(
TestParams *testParams)
{
SecKeychainRef kcRef = (SecKeychainRef)testParams->testPriv;
CFRelease(kcRef);
return noErr;
}
#pragma mark -- SecTrustEvaluate --
static OSStatus secTrustInit(
TestParams *testParams)
{
unsigned char *certData;
unsigned certLen;
CSSM_DATA cdata;
SecCertificateRef *certRefs;
certRefs = (SecCertificateRef *)malloc(
sizeof(SecCertificateRef) * NUM_ST_CERTS);
for(unsigned dex=0; dex<NUM_ST_CERTS; dex++) {
if(readFile(certsToVerify[dex].certFileName, &certData, &certLen)) {
printf("***Can not find cert file %s. Aborting.\n",
certsToVerify[dex].certFileName);
return -1;
}
cdata.Data = certData;
cdata.Length = certLen;
SecCertificateRef certRef;
OSStatus ortn = SecCertificateCreateFromData(&cdata,
CSSM_CERT_X_509v3,
CSSM_CERT_ENCODING_DER,
&certRef);
if(ortn) {
printSecErr("SecCertificateCreateFromData", ortn);
return ortn;
}
free(certData); certRefs[dex] = certRef;
}
testParams->testPriv = certRefs;
return noErr;
}
static OSStatus secTrustRun(
TestParams *testParams,
unsigned loopNum,
CFAbsoluteTime *timeSpent)
{
unsigned whichDex = loopNum % NUM_ST_CERTS;
SecCertificateRef *certRefs = (SecCertificateRef *)testParams->testPriv;
SecCertificateRef certRef = certRefs[whichDex];
CFAbsoluteTime startTime = CFAbsoluteTimeGetCurrent();
CFMutableArrayRef certs;
certs = CFArrayCreateMutable(NULL, 1, &kCFTypeArrayCallBacks);
CFArrayInsertValueAtIndex(certs, 0, certRef);
SecPolicyRef policy = NULL;
SecPolicySearchRef policySearch = NULL;
OSStatus ortn = SecPolicySearchCreate(CSSM_CERT_X_509v3,
&CSSMOID_APPLE_TP_SSL,
NULL, &policySearch);
if(ortn) {
printSecErr("SecPolicySearchCreate", ortn);
return ortn;
}
ortn = SecPolicySearchCopyNext(policySearch, &policy);
if(ortn) {
printSecErr("SecPolicySearchCopyNext", ortn);
return ortn;
}
CFRelease(policySearch);
SecTrustRef secTrust;
ortn = SecTrustCreateWithCertificates(certs, policy, &secTrust);
if(ortn) {
printSecErr("SecTrustCreateWithCertificates", ortn);
return ortn;
}
SecTrustResultType secTrustResult;
ortn = SecTrustEvaluate(secTrust, &secTrustResult);
if(ortn) {
printSecErr("SecTrustEvaluate", ortn);
return ortn;
}
CFRelease(certs);
CFRelease(secTrust);
CFRelease(policy);
CFAbsoluteTime endTime = CFAbsoluteTimeGetCurrent();
*timeSpent = endTime - startTime;
return noErr;
}
static OSStatus secTrustCleanup(
TestParams *testParams)
{
SecCertificateRef *certRefs = (SecCertificateRef*)testParams->testPriv;
for(unsigned dex=0; dex<NUM_ST_CERTS; dex++) {
CFRelease(certRefs[dex]);
}
free(certRefs);
return noErr;
}
#pragma mark -- SecKeychainCopySearchList --
static OSStatus kcCSLInit(
TestParams *testParams)
{
return noErr;
}
static OSStatus kcCSLRun(
TestParams *testParams,
unsigned loopNum,
CFAbsoluteTime *timeSpent)
{
CFArrayRef sl;
CFAbsoluteTime startTime = CFAbsoluteTimeGetCurrent();
OSStatus ortn = SecKeychainCopySearchList(&sl);
if(ortn) {
printSecErr("SecKeychainCopySearchList", ortn);
return ortn;
}
CFRelease(sl);
*timeSpent = CFAbsoluteTimeGetCurrent() - startTime;
return noErr;
}
static OSStatus kcCSLCleanup(
TestParams *testParams)
{
return noErr;
}
#pragma mark -- CSSM_TP_CertGroupVerify, system anchors --
typedef struct {
CSSM_TP_HANDLE tpHand;
CSSM_CL_HANDLE clHand;
CSSM_CSP_HANDLE cspHand;
BlobList *certs[NUM_ST_CERTS];
BlobList *anchors;
} CgvParams;
static OSStatus cgvInit(
TestParams *testParams)
{
CgvParams *cgvParams = (CgvParams *)malloc(sizeof(CgvParams));
memset(cgvParams, 0, sizeof(CgvParams));
cgvParams->tpHand = tpStartup();
cgvParams->clHand = clStartup();
cgvParams->cspHand = cspStartup();
for(unsigned dex=0; dex<NUM_ST_CERTS; dex++) {
cgvParams->certs[dex] = new BlobList();
cgvParams->certs[dex]->addFile(certsToVerify[dex].certFileName);
}
cgvParams->anchors = NULL;
testParams->testPriv = cgvParams;
return noErr;
}
static OSStatus cgvRun(
TestParams *testParams,
unsigned loopNum,
CFAbsoluteTime *timeSpent)
{
CgvParams *cgvParams = (CgvParams *)testParams->testPriv;
BlobList nullList;
unsigned whichDex = loopNum % NUM_ST_CERTS;
BlobList *certBlob = cgvParams->certs[whichDex];
CFAbsoluteTime startTime = CFAbsoluteTimeGetCurrent();
int rtn = certVerifySimple(
cgvParams->tpHand,
cgvParams->clHand,
cgvParams->cspHand,
*certBlob, nullList, CSSM_TRUE, CSSM_FALSE, CSSM_FALSE, CVP_SSL,
certsToVerify[whichDex].hostName,
CSSM_FALSE, NULL, 0, NULL, 0, NULL,
0, NULL,
CSSM_FALSE, CSSM_TRUE, CSSM_FALSE); *timeSpent = CFAbsoluteTimeGetCurrent() - startTime;
if(rtn) {
printf("***certVerify error\n");
return (OSStatus)rtn;
}
return noErr;
}
static OSStatus cgvCleanup(
TestParams *testParams)
{
CgvParams *cgvParams = (CgvParams *)testParams->testPriv;
CSSM_ModuleDetach(cgvParams->cspHand);
CSSM_ModuleDetach(cgvParams->tpHand);
CSSM_ModuleDetach(cgvParams->clHand);
for(unsigned dex=0; dex<NUM_ST_CERTS; dex++) {
delete cgvParams->certs[dex];
}
if(cgvParams->anchors) {
delete(cgvParams->anchors);
}
free(cgvParams);
return noErr;
}
#pragma mark -- CSSM_TP_CertGroupVerify, explicit anchors --
static OSStatus cgvAnchorInit(
TestParams *testParams)
{
CgvParams *cgvParams = (CgvParams *)malloc(sizeof(CgvParams));
memset(cgvParams, 0, sizeof(CgvParams));
cgvParams->tpHand = tpStartup();
cgvParams->clHand = clStartup();
cgvParams->cspHand = cspStartup();
cgvParams->certs[0] = new BlobList();
cgvParams->certs[0]->addFile(certsToVerify[0].certFileName);
cgvParams->anchors = new BlobList();
cgvParams->anchors->addFile(ST_ANCHOR_NAME);
testParams->testPriv = cgvParams;
return noErr;
}
static OSStatus cgvAnchorRun(
TestParams *testParams,
unsigned loopNum,
CFAbsoluteTime *timeSpent)
{
CgvParams *cgvParams = (CgvParams *)testParams->testPriv;
BlobList nullList;
CertVerifyArgs vfyArgs;
memset(&vfyArgs, 0, sizeof(vfyArgs));
vfyArgs.version = CERT_VFY_ARGS_VERS;
vfyArgs.tpHand = cgvParams->tpHand;
vfyArgs.clHand = cgvParams->clHand;
vfyArgs.cspHand = cgvParams->cspHand;
vfyArgs.certs = cgvParams->certs[0];
vfyArgs.roots = cgvParams->anchors;
vfyArgs.allowUnverified = CSSM_TRUE;
vfyArgs.vfyPolicy = CVP_SSL;
vfyArgs.revokePolicy = CRP_None;
vfyArgs.sslHost = certsToVerify[0].hostName;
vfyArgs.revokePolicy = CRP_None;
vfyArgs.quiet = CSSM_TRUE;
CFAbsoluteTime startTime = CFAbsoluteTimeGetCurrent();
int rtn = certVerify(&vfyArgs);
*timeSpent = CFAbsoluteTimeGetCurrent() - startTime;
if(rtn) {
printf("***certVerify error\n");
return (OSStatus)rtn;
}
return noErr;
}
#pragma mark -- CSSM_TP_CertGroupVerify, 3 certs with anchor --
static OSStatus cgv3Init(
TestParams *testParams)
{
CgvParams *cgvParams = (CgvParams *)malloc(sizeof(CgvParams));
memset(cgvParams, 0, sizeof(CgvParams));
cgvParams->tpHand = tpStartup();
cgvParams->clHand = clStartup();
cgvParams->cspHand = cspStartup();
cgvParams->certs[0] = new BlobList();
cgvParams->certs[0]->addFile(THAWTE_LEAF);
cgvParams->certs[0]->addFile(THAWTE_CA);
cgvParams->certs[0]->addFile(THAWTE_ROOT);
cgvParams->anchors = new BlobList();
cgvParams->anchors->addFile(THAWTE_ROOT);
testParams->testPriv = cgvParams;
return noErr;
}
static OSStatus cgv3Run(
TestParams *testParams,
unsigned loopNum,
CFAbsoluteTime *timeSpent)
{
CgvParams *cgvParams = (CgvParams *)testParams->testPriv;
BlobList nullList;
CertVerifyArgs vfyArgs;
memset(&vfyArgs, 0, sizeof(vfyArgs));
vfyArgs.version = CERT_VFY_ARGS_VERS;
vfyArgs.tpHand = cgvParams->tpHand;
vfyArgs.clHand = cgvParams->clHand;
vfyArgs.cspHand = cgvParams->cspHand;
vfyArgs.certs = cgvParams->certs[0];
vfyArgs.roots = cgvParams->anchors;
vfyArgs.allowUnverified = CSSM_TRUE;
vfyArgs.vfyPolicy = CVP_Basic;
vfyArgs.revokePolicy = CRP_None;
vfyArgs.sslHost = certsToVerify[0].hostName;
vfyArgs.revokePolicy = CRP_None;
vfyArgs.quiet = CSSM_TRUE;
CFAbsoluteTime startTime = CFAbsoluteTimeGetCurrent();
int rtn = certVerify(&vfyArgs);
*timeSpent = CFAbsoluteTimeGetCurrent() - startTime;
if(rtn) {
printf("***certVerify error\n");
return (OSStatus)rtn;
}
return noErr;
}
static OSStatus cgv3Cleanup(
TestParams *testParams)
{
CgvParams *cgvParams = (CgvParams *)testParams->testPriv;
CSSM_ModuleDetach(cgvParams->cspHand);
CSSM_ModuleDetach(cgvParams->tpHand);
CSSM_ModuleDetach(cgvParams->clHand);
delete cgvParams->certs[0];
delete(cgvParams->anchors);
free(cgvParams);
return noErr;
}
#pragma mark ---- Static array of all tests ----
static TestDefs testDefs[] =
{
{ "Keychain open",
100,
kcOpenInit,
kcOpenRun,
kcOpenCleanup,
'o',
},
{ "Keychain cert search",
100,
kcSearchInit,
kcSearchRun,
kcSearchCleanup,
's',
},
{ "SecTrustEvaluate",
100,
secTrustInit,
secTrustRun,
secTrustCleanup,
'e',
},
{ "TP CertGroupVerify, system anchors",
100,
cgvInit,
cgvRun,
cgvCleanup,
'v',
},
{ "TP CertGroupVerify, explicit anchor",
100,
cgvAnchorInit,
cgvAnchorRun,
cgvCleanup,
'V',
},
{ "TP CertGroupVerify, 3 certs with anchor",
100,
cgv3Init,
cgv3Run,
cgv3Cleanup,
'3',
},
{ "SecKeychainCopySearchList",
100,
kcCSLInit,
kcCSLRun,
kcCSLCleanup,
'k',
},
};
#define NUM_TESTS (sizeof(testDefs) / sizeof(testDefs[0]))
int main(int argc, char **argv)
{
TestParams testParams;
TestDefs *testDef;
OSStatus ortn;
int arg;
char *argp;
unsigned cmdLoops = 0; char testSpec = '\0';
for(arg=1; arg<argc; arg++) {
argp = argv[arg];
switch(argp[0]) {
case 't':
testSpec = argp[2];
break;
case 'l':
cmdLoops = atoi(&argp[2]);
break;
default:
usage(argv);
}
}
for(unsigned testNum=0; testNum<NUM_TESTS; testNum++) {
testDef = &testDefs[testNum];
unsigned loopCount;
if(testSpec && (testDef->testSpec != testSpec)) {
continue;
}
printf("%s:\n", testDef->testName);
ortn = testDef->init(&testParams);
if(ortn) {
exit(1);
}
if(cmdLoops) {
loopCount = cmdLoops;
}
else {
loopCount = testDef->loops;
}
CFAbsoluteTime totalTime = 0;
CFAbsoluteTime thisTime;
for(unsigned loop=0; loop<loopCount; loop++) {
ortn = testDef->run(&testParams, loop, &thisTime);
if(ortn) {
exit(1);
}
totalTime += thisTime;
}
testDef->cleanup(&testParams);
printf(" %3.2f ms per op\n", (totalTime / loopCount) * 1000.0);
}
return 0;
}