#include <Security/Security.h>
#include <security_cdsa_utils/cuFileIo.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <CoreFoundation/CoreFoundation.h>
#include <utilLib/common.h>
#include <utilLib/cputime.h>
#include <Security/SecImportExport.h>
#define KT_NUM_KEYCHAINS 10
#define KT_CERT0_NAME "amazon_v3.100.cer"
#define KT_CERT1_NAME "SecureServer.509.cer"
#define KT_P12_PFX "test1.p12"
#define KT_P12_PASSWORD "password"
#define KT_KC_NAME "kcTime_test_"
static void usage(char **argv)
{
printf("Usage: %s [option ...]\n", argv[0]);
printf("Options:\n");
printf(" v verbose\n");
printf(" h help\n");
exit(1);
}
static void printAllTimes(
bool verbose,
double *delta,
unsigned numSamples)
{
if(!verbose) {
return;
}
for(unsigned dex=0; dex<numSamples; dex++) {
printf(" sample[%u] %8.4f\n", dex, delta[dex]);
}
}
static void printSecErr(
const char *op,
OSStatus ortn)
{
cssmPerror(op, ortn);
}
int main(int argc, char **argv)
{
SecKeychainRef kcRefs[KT_NUM_KEYCHAINS];
OSStatus ortn;
int arg;
char *argp;
char kcName[KT_NUM_KEYCHAINS][80];
unsigned dex;
unsigned char *cert0Data;
unsigned cert0Len;
unsigned char *cert1Data;
unsigned cert1Len;
SecCertificateRef certRef0[KT_NUM_KEYCHAINS];
SecCertificateRef certRef1[KT_NUM_KEYCHAINS];
CFArrayRef savedSearchList;
CFMutableArrayRef ourSearchList;
int irtn;
CPUTime startTime, endTime;
double deltaMs[KT_NUM_KEYCHAINS * 2];
double deltaMs2[KT_NUM_KEYCHAINS];
double deltaMs3[KT_NUM_KEYCHAINS];
SecKeychainSearchRef srchRef;
CFStringRef p12Pwd;
CFDataRef p12Data;
bool verbose = false;
memset(kcRefs, 0, sizeof(SecKeychainRef) * KT_NUM_KEYCHAINS);
for(arg=1; arg<argc; arg++) {
argp = argv[arg];
switch(argp[0]) {
case 'v':
verbose = true;
break;
default:
usage(argv);
}
}
printf("Starting kcTime test using %d keychains\n", KT_NUM_KEYCHAINS);
for(dex=0; dex<KT_NUM_KEYCHAINS; dex++) {
sprintf(kcName[dex], "%s%d", KT_KC_NAME, dex);
}
for(dex=0; dex<KT_NUM_KEYCHAINS; dex++) {
SecKeychainRef kc;
ortn = SecKeychainOpen(kcName[dex], &kc);
if(ortn == noErr) {
SecKeychainDelete(kc);
}
char *userHome = getenv("HOME");
char fullPath[1024];
if(userHome == NULL) {
userHome = (char *)"";
}
sprintf(fullPath, "%s/Library/Keychains/%s",
userHome, kcName[dex]);
unlink(fullPath);
}
irtn = readFile(KT_CERT0_NAME, &cert0Data, &cert0Len);
if(irtn) {
printf("I cannot find file %s in cwd.\n", KT_CERT0_NAME);
exit(1);
}
irtn = readFile(KT_CERT1_NAME, &cert1Data, &cert1Len);
if(irtn) {
printf("I cannot find file %s in cwd.\n", KT_CERT1_NAME);
exit(1);
}
ortn = SecKeychainCopySearchList(&savedSearchList);
if(ortn) {
printSecErr("SecKeychainCopySearchList", ortn);
return 1;
}
for(dex=0; dex<KT_NUM_KEYCHAINS; dex++) {
unsigned pwdLen = strlen(kcName[dex]);
startTime = CPUTimeRead();
ortn = SecKeychainCreate(kcName[dex],
pwdLen,
kcName[dex],
false, nil, &kcRefs[dex]);
endTime = CPUTimeRead();
if(ortn) {
printSecErr("SecKeychainCreate", ortn);
goto errOut;
}
deltaMs[dex] = CPUTimeDeltaMs(startTime, endTime);
}
printf("Create : %7.3f ms per op\n",
CPUTimeAvg(deltaMs, KT_NUM_KEYCHAINS));
printAllTimes(verbose, deltaMs, KT_NUM_KEYCHAINS);
ourSearchList = CFArrayCreateMutable(NULL, KT_NUM_KEYCHAINS, NULL);
for(dex=0; dex<KT_NUM_KEYCHAINS; dex++) {
CFArrayInsertValueAtIndex(ourSearchList, dex, kcRefs[dex]);
}
ortn = SecKeychainSetSearchList(ourSearchList);
if(ortn) {
printSecErr("SecKeychainSetSearchList", ortn);
goto errOut;
}
CFRelease(ourSearchList);
for(dex=0; dex<KT_NUM_KEYCHAINS; dex++) {
startTime = CPUTimeRead();
CFRelease(kcRefs[dex]);
endTime = CPUTimeRead();
deltaMs[dex] = CPUTimeDeltaMs(startTime, endTime);
}
printf("Close : %7.3f ms per op\n",
CPUTimeAvg(deltaMs, KT_NUM_KEYCHAINS));
printAllTimes(verbose, deltaMs, KT_NUM_KEYCHAINS);
startTime = CPUTimeRead();
for(dex=0; dex<KT_NUM_KEYCHAINS; dex++) {
ortn = SecKeychainOpen(kcName[dex], &kcRefs[dex]);
if(ortn) {
printSecErr("SecKeychainOpen", ortn);
goto errOut;
}
}
endTime = CPUTimeRead();
deltaMs[0] = CPUTimeDeltaMs(startTime, endTime);
printf("Open : %7.3f ms per op\n",
deltaMs[0] / KT_NUM_KEYCHAINS);
if(verbose) {
printf(" total time %7.3f ms\n", deltaMs[0]);
}
for(dex=0; dex<KT_NUM_KEYCHAINS; dex++) {
SecKeychainStatus status;
startTime = CPUTimeRead();
ortn = SecKeychainGetStatus(kcRefs[dex], &status);
endTime = CPUTimeRead();
if(ortn) {
printSecErr("SecKeychainGetStatus", ortn);
goto errOut;
}
deltaMs[dex] = CPUTimeDeltaMs(startTime, endTime);
}
printf("Get Status : %7.3f ms per op\n",
CPUTimeAvg(deltaMs, KT_NUM_KEYCHAINS));
printAllTimes(verbose, deltaMs, KT_NUM_KEYCHAINS);
for(dex=0; dex<KT_NUM_KEYCHAINS; dex++) {
unsigned pwdLen = strlen(kcName[dex]);
startTime = CPUTimeRead();
ortn = SecKeychainUnlock(kcRefs[dex],
pwdLen, kcName[dex], true);
endTime = CPUTimeRead();
if(ortn) {
printSecErr("SecKeychainUnlock", ortn);
goto errOut;
}
deltaMs[dex] = CPUTimeDeltaMs(startTime, endTime);
}
printf("Unlock : %7.3f ms per op\n",
CPUTimeAvg(deltaMs, KT_NUM_KEYCHAINS));
printAllTimes(verbose, deltaMs, KT_NUM_KEYCHAINS);
startTime = CPUTimeRead();
for(dex=0; dex<KT_NUM_KEYCHAINS; dex++) {
CSSM_DATA cdata = {cert0Len, cert0Data};
ortn = SecCertificateCreateFromData(&cdata,
CSSM_CERT_X_509v3,
CSSM_CERT_ENCODING_DER,
&certRef0[dex]);
if(ortn) {
printSecErr("SecCertificateCreateFromData", ortn);
goto errOut;
}
cdata.Length = cert1Len;
cdata.Data = cert1Data;
ortn = SecCertificateCreateFromData(&cdata,
CSSM_CERT_X_509v3,
CSSM_CERT_ENCODING_DER,
&certRef1[dex]);
if(ortn) {
printSecErr("SecCertificateCreateFromData", ortn);
goto errOut;
}
}
endTime = CPUTimeRead();
deltaMs[0] = CPUTimeDeltaMs(startTime, endTime);
printf("SecCertificateCreateFromData : %7.3f ms per op\n",
deltaMs[0] / (KT_NUM_KEYCHAINS * 2.0));
if(verbose) {
printf(" total time %7.3f ms\n", deltaMs[0]);
}
free(cert0Data);
free(cert1Data);
for(dex=0; dex<KT_NUM_KEYCHAINS; dex++) {
startTime = CPUTimeRead();
ortn = SecCertificateAddToKeychain(certRef0[dex], kcRefs[dex]);
if(ortn) {
printSecErr("SecCertificateAddToKeychain", ortn);
goto errOut;
}
ortn = SecCertificateAddToKeychain(certRef1[dex], kcRefs[dex]);
endTime = CPUTimeRead();
if(ortn) {
printSecErr("SecCertificateAddToKeychain", ortn);
goto errOut;
}
deltaMs[dex] = CPUTimeDeltaMs(startTime, endTime);
}
printf("SecCertificateAddToKeychain : %7.3f ms per op\n",
CPUTimeAvg(deltaMs, KT_NUM_KEYCHAINS) / 2.0);
printAllTimes(verbose, deltaMs, KT_NUM_KEYCHAINS);
for(dex=0; dex<KT_NUM_KEYCHAINS; dex++) {
CFRelease(certRef0[dex]);
CFRelease(certRef1[dex]);
}
for(dex=0; dex<KT_NUM_KEYCHAINS; dex++) {
SecKeychainItemRef certRef = NULL;
startTime = CPUTimeRead();
ortn = SecKeychainSearchCreateFromAttributes(kcRefs[dex],
kSecCertificateItemClass,
NULL, &srchRef);
if(ortn) {
printSecErr("SecKeychainSearchCreateFromAttributes", ortn);
goto errOut;
}
ortn = SecKeychainSearchCopyNext(srchRef, &certRef);
if(SecCertificateGetTypeID() != CFGetTypeID(certRef)) {
printf("***Unexpected CFType on cert search\n");
goto errOut;
}
endTime = CPUTimeRead();
if(ortn) {
printSecErr("SecKeychainSearchCopyNext", ortn);
goto errOut;
}
deltaMs[dex] = CPUTimeDeltaMs(startTime, endTime);
CFRelease(certRef);
startTime = CPUTimeRead();
ortn = SecKeychainSearchCopyNext(srchRef, &certRef);
if(SecCertificateGetTypeID() != CFGetTypeID(certRef)) {
printf("***Unexpected CFType on cert search\n");
goto errOut;
}
endTime = CPUTimeRead();
if(ortn) {
printSecErr("SecKeychainSearchCreateFromAttributes", ortn);
goto errOut;
}
deltaMs2[dex] = CPUTimeDeltaMs(startTime, endTime);
CFRelease(certRef);
startTime = CPUTimeRead();
ortn = SecKeychainSearchCopyNext(srchRef, &certRef);
endTime = CPUTimeRead();
if(ortn != errSecItemNotFound) {
if(ortn == noErr) {
printf("***SecKeychainSearchCopyNext got noErr, "
"expected notFound\n");
}
else {
printSecErr("SecKeychainSearchCopyNext", ortn);
}
goto errOut;
}
deltaMs3[dex] = CPUTimeDeltaMs(startTime, endTime);
CFRelease(srchRef);
}
printf("SecKeychainSearch first item : %7.3f ms per op\n",
CPUTimeAvg(deltaMs, KT_NUM_KEYCHAINS));
printAllTimes(verbose, deltaMs, KT_NUM_KEYCHAINS);
printf("SecKeychainSearch next item : %7.3f ms per op\n",
CPUTimeAvg(deltaMs2, KT_NUM_KEYCHAINS));
printAllTimes(verbose, deltaMs2, KT_NUM_KEYCHAINS);
printf("SecKeychainSearch end of list : %7.3f ms per op\n",
CPUTimeAvg(deltaMs3, KT_NUM_KEYCHAINS));
printAllTimes(verbose, deltaMs3, KT_NUM_KEYCHAINS);
ortn = SecKeychainSearchCreateFromAttributes(NULL,
kSecCertificateItemClass,
NULL, &srchRef);
if(ortn) {
printSecErr("SecKeychainSearchCreateFromAttributes", ortn);
goto errOut;
}
for(dex=0; dex<KT_NUM_KEYCHAINS*2; dex++) {
SecKeychainItemRef certRef = NULL;
startTime = CPUTimeRead();
ortn = SecKeychainSearchCopyNext(srchRef, &certRef);
if(SecCertificateGetTypeID() != CFGetTypeID(certRef)) {
printf("***Unexpected CFType on cert search\n");
goto errOut;
}
endTime = CPUTimeRead();
deltaMs[dex] = CPUTimeDeltaMs(startTime, endTime);
CFRelease(certRef);
}
printf("SecKeychainSearch all KCs : %7.3f ms per op\n",
CPUTimeAvg(deltaMs, KT_NUM_KEYCHAINS * 2));
printAllTimes(verbose, deltaMs, KT_NUM_KEYCHAINS * 2);
irtn = readFile(KT_P12_PFX, &cert0Data, &cert0Len);
if(irtn) {
printf("I cannot find file %s in cwd.\n", KT_P12_PFX);
exit(1);
}
p12Data = CFDataCreate(NULL, cert0Data, cert0Len);
p12Pwd = CFStringCreateWithCString(NULL, KT_P12_PASSWORD,
kCFStringEncodingASCII);
for(dex=0; dex<KT_NUM_KEYCHAINS; dex++) {
SecExternalFormat format = kSecFormatPKCS12;
SecExternalItemType itemType = kSecItemTypeAggregate;
SecKeyImportExportParameters keyParams;
memset(&keyParams, 0, sizeof(keyParams));
keyParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
keyParams.flags = kSecKeyNoAccessControl;
keyParams.passphrase = p12Pwd;
keyParams.keyAttributes = CSSM_KEYATTR_PERMANENT | CSSM_KEYATTR_SENSITIVE |
CSSM_KEYATTR_EXTRACTABLE;
startTime = CPUTimeRead();
ortn = SecKeychainItemImport(p12Data,
NULL, &format, &itemType,
0, &keyParams,
kcRefs[dex],
NULL); if(ortn) {
printSecErr("SecKeychainItemImport(p12)", ortn);
goto errOut;
}
endTime = CPUTimeRead();
deltaMs[dex] = CPUTimeDeltaMs(startTime, endTime);
}
CFRelease(p12Data);
CFRelease(p12Pwd);
printf("P12 Import : %7.3f ms per op\n",
CPUTimeAvg(deltaMs, KT_NUM_KEYCHAINS));
printAllTimes(verbose, deltaMs, KT_NUM_KEYCHAINS);
for(dex=0; dex<KT_NUM_KEYCHAINS; dex++) {
SecIdentitySearchRef idSrch;
SecIdentityRef idRef;
startTime = CPUTimeRead();
ortn = SecIdentitySearchCreate(kcRefs[dex], 0, &idSrch);
if(ortn) {
printSecErr("SecIdentitySearchCreate", ortn);
goto errOut;
}
ortn = SecIdentitySearchCopyNext(idSrch, &idRef);
endTime = CPUTimeRead();
if(ortn) {
printSecErr("SecIdentitySearchCopyNext", ortn);
goto errOut;
}
deltaMs[dex] = CPUTimeDeltaMs(startTime, endTime);
CFRelease(idSrch);
CFRelease(idRef);
}
printf("SecIdentity search : %7.3f ms per op\n",
CPUTimeAvg(deltaMs, KT_NUM_KEYCHAINS));
printAllTimes(verbose, deltaMs, KT_NUM_KEYCHAINS);
errOut:
ortn = SecKeychainSetSearchList(savedSearchList);
if(ortn) {
printSecErr("SecKeychainSetSearchList", ortn);
}
for(dex=0; dex<KT_NUM_KEYCHAINS; dex++) {
if(kcRefs[dex] != NULL) {
SecKeychainDelete(kcRefs[dex]);
}
}
return 0;
}