2 * kcTime.cpp - measure performance of keychain ops
5 #include <Security/Security.h>
6 #include <security_cdsa_utils/cuFileIo.h>
11 #include <CoreFoundation/CoreFoundation.h>
12 #include <utilLib/common.h>
13 #include <utilLib/cputime.h>
14 #include <Security/SecImportExport.h>
16 /* Hard coded test params */
19 * Number of keychains to create/search
21 #define KT_NUM_KEYCHAINS 10
24 * Certs and P12 blobs to add to keychain
26 #define KT_CERT0_NAME "amazon_v3.100.cer"
27 #define KT_CERT1_NAME "SecureServer.509.cer"
28 #define KT_P12_PFX "test1.p12"
29 #define KT_P12_PASSWORD "password"
32 * Base name of keychains we create. We delete them before we start.
33 * They're in the user's home directory to faciliate testing NFS vs. local.
35 #define KT_KC_NAME "kcTime_test_"
37 static void usage(char **argv
)
39 printf("Usage: %s [option ...]\n", argv
[0]);
41 printf(" v verbose\n");
46 static void printAllTimes(
54 for(unsigned dex
=0; dex
<numSamples
; dex
++) {
55 printf(" sample[%u] %8.4f\n", dex
, delta
[dex
]);
59 static void printSecErr(
66 int main(int argc
, char **argv
)
68 SecKeychainRef kcRefs
[KT_NUM_KEYCHAINS
];
72 char kcName
[KT_NUM_KEYCHAINS
][80];
74 unsigned char *cert0Data
;
76 unsigned char *cert1Data
;
78 SecCertificateRef certRef0
[KT_NUM_KEYCHAINS
];
79 SecCertificateRef certRef1
[KT_NUM_KEYCHAINS
];
80 CFArrayRef savedSearchList
;
81 CFMutableArrayRef ourSearchList
;
83 CPUTime startTime
, endTime
;
84 double deltaMs
[KT_NUM_KEYCHAINS
* 2];
85 double deltaMs2
[KT_NUM_KEYCHAINS
];
86 double deltaMs3
[KT_NUM_KEYCHAINS
];
87 SecKeychainSearchRef srchRef
;
92 memset(kcRefs
, 0, sizeof(SecKeychainRef
) * KT_NUM_KEYCHAINS
);
94 for(arg
=1; arg
<argc
; arg
++) {
105 printf("Starting kcTime test using %d keychains\n", KT_NUM_KEYCHAINS
);
107 /* generate keychain names */
108 for(dex
=0; dex
<KT_NUM_KEYCHAINS
; dex
++) {
109 sprintf(kcName
[dex
], "%s%d", KT_KC_NAME
, dex
);
112 /* delete existing keychains we created in the past */
113 for(dex
=0; dex
<KT_NUM_KEYCHAINS
; dex
++) {
115 * It may or may not exist, and may or may not be in the search
116 * list. Brute force and ignore errors.
119 ortn
= SecKeychainOpen(kcName
[dex
], &kc
);
121 SecKeychainDelete(kc
);
124 /* brute force UNIX file delete too */
125 char *userHome
= getenv("HOME");
127 if(userHome
== NULL
) {
128 userHome
= (char *)"";
130 sprintf(fullPath
, "%s/Library/Keychains/%s",
131 userHome
, kcName
[dex
]);
135 /* read in certificate data */
136 irtn
= readFile(KT_CERT0_NAME
, &cert0Data
, &cert0Len
);
138 printf("I cannot find file %s in cwd.\n", KT_CERT0_NAME
);
141 irtn
= readFile(KT_CERT1_NAME
, &cert1Data
, &cert1Len
);
143 printf("I cannot find file %s in cwd.\n", KT_CERT1_NAME
);
147 /* save KC search list; we'll restore it at end */
148 ortn
= SecKeychainCopySearchList(&savedSearchList
);
150 printSecErr("SecKeychainCopySearchList", ortn
);
153 /* subsequent errors to errOut: to restore searchList! */
155 /* TIME: create n keychains */
156 for(dex
=0; dex
<KT_NUM_KEYCHAINS
; dex
++) {
157 unsigned pwdLen
= strlen(kcName
[dex
]);
158 startTime
= CPUTimeRead();
159 ortn
= SecKeychainCreate(kcName
[dex
],
162 false, // promptUser,
163 nil
, // initialAccess
165 endTime
= CPUTimeRead();
167 printSecErr("SecKeychainCreate", ortn
);
170 deltaMs
[dex
] = CPUTimeDeltaMs(startTime
, endTime
);
172 printf("Create : %7.3f ms per op\n",
173 CPUTimeAvg(deltaMs
, KT_NUM_KEYCHAINS
));
174 printAllTimes(verbose
, deltaMs
, KT_NUM_KEYCHAINS
);
176 /* set KC search list to only the ones we just created */
177 ourSearchList
= CFArrayCreateMutable(NULL
, KT_NUM_KEYCHAINS
, NULL
);
178 for(dex
=0; dex
<KT_NUM_KEYCHAINS
; dex
++) {
179 CFArrayInsertValueAtIndex(ourSearchList
, dex
, kcRefs
[dex
]);
181 ortn
= SecKeychainSetSearchList(ourSearchList
);
183 printSecErr("SecKeychainSetSearchList", ortn
);
186 CFRelease(ourSearchList
);
188 /* TIME: close all of them */
189 for(dex
=0; dex
<KT_NUM_KEYCHAINS
; dex
++) {
190 startTime
= CPUTimeRead();
191 CFRelease(kcRefs
[dex
]);
192 endTime
= CPUTimeRead();
193 deltaMs
[dex
] = CPUTimeDeltaMs(startTime
, endTime
);
195 printf("Close : %7.3f ms per op\n",
196 CPUTimeAvg(deltaMs
, KT_NUM_KEYCHAINS
));
197 printAllTimes(verbose
, deltaMs
, KT_NUM_KEYCHAINS
);
199 /* TIME: open all of them */
200 /* This is so fast that we just measure the total time */
201 startTime
= CPUTimeRead();
202 for(dex
=0; dex
<KT_NUM_KEYCHAINS
; dex
++) {
203 ortn
= SecKeychainOpen(kcName
[dex
], &kcRefs
[dex
]);
205 printSecErr("SecKeychainOpen", ortn
);
209 endTime
= CPUTimeRead();
210 deltaMs
[0] = CPUTimeDeltaMs(startTime
, endTime
);
211 printf("Open : %7.3f ms per op\n",
212 deltaMs
[0] / KT_NUM_KEYCHAINS
);
214 printf(" total time %7.3f ms\n", deltaMs
[0]);
217 /* TIME: get status on all of them */
218 for(dex
=0; dex
<KT_NUM_KEYCHAINS
; dex
++) {
219 SecKeychainStatus status
;
220 startTime
= CPUTimeRead();
221 ortn
= SecKeychainGetStatus(kcRefs
[dex
], &status
);
222 endTime
= CPUTimeRead();
224 printSecErr("SecKeychainGetStatus", ortn
);
227 deltaMs
[dex
] = CPUTimeDeltaMs(startTime
, endTime
);
229 printf("Get Status : %7.3f ms per op\n",
230 CPUTimeAvg(deltaMs
, KT_NUM_KEYCHAINS
));
231 printAllTimes(verbose
, deltaMs
, KT_NUM_KEYCHAINS
);
233 /* TIME: unlock each keychain */
234 for(dex
=0; dex
<KT_NUM_KEYCHAINS
; dex
++) {
235 unsigned pwdLen
= strlen(kcName
[dex
]);
236 startTime
= CPUTimeRead();
237 ortn
= SecKeychainUnlock(kcRefs
[dex
],
238 pwdLen
, kcName
[dex
], true);
239 endTime
= CPUTimeRead();
241 printSecErr("SecKeychainUnlock", ortn
);
244 deltaMs
[dex
] = CPUTimeDeltaMs(startTime
, endTime
);
246 printf("Unlock : %7.3f ms per op\n",
247 CPUTimeAvg(deltaMs
, KT_NUM_KEYCHAINS
));
248 printAllTimes(verbose
, deltaMs
, KT_NUM_KEYCHAINS
);
250 /* TIME: create two SecCertificateRefs for each KC */
251 /* this is fast, just measure total time */
252 startTime
= CPUTimeRead();
253 for(dex
=0; dex
<KT_NUM_KEYCHAINS
; dex
++) {
254 CSSM_DATA cdata
= {cert0Len
, cert0Data
};
255 ortn
= SecCertificateCreateFromData(&cdata
,
257 CSSM_CERT_ENCODING_DER
,
260 printSecErr("SecCertificateCreateFromData", ortn
);
263 cdata
.Length
= cert1Len
;
264 cdata
.Data
= cert1Data
;
265 ortn
= SecCertificateCreateFromData(&cdata
,
267 CSSM_CERT_ENCODING_DER
,
270 printSecErr("SecCertificateCreateFromData", ortn
);
274 endTime
= CPUTimeRead();
275 deltaMs
[0] = CPUTimeDeltaMs(startTime
, endTime
);
276 /* we created KT_NUM_KEYCHAINS*2 certs in KT_NUM_KEYCHAINS samples */
277 printf("SecCertificateCreateFromData : %7.3f ms per op\n",
278 deltaMs
[0] / (KT_NUM_KEYCHAINS
* 2.0));
280 printf(" total time %7.3f ms\n", deltaMs
[0]);
285 /* TIME: add two certs to each keychain */
286 for(dex
=0; dex
<KT_NUM_KEYCHAINS
; dex
++) {
287 startTime
= CPUTimeRead();
288 ortn
= SecCertificateAddToKeychain(certRef0
[dex
], kcRefs
[dex
]);
290 printSecErr("SecCertificateAddToKeychain", ortn
);
293 ortn
= SecCertificateAddToKeychain(certRef1
[dex
], kcRefs
[dex
]);
294 endTime
= CPUTimeRead();
296 printSecErr("SecCertificateAddToKeychain", ortn
);
299 deltaMs
[dex
] = CPUTimeDeltaMs(startTime
, endTime
);
301 /* we added KT_NUM_KEYCHAINS*2 certs in KT_NUM_KEYCHAINS samples */
302 printf("SecCertificateAddToKeychain : %7.3f ms per op\n",
303 CPUTimeAvg(deltaMs
, KT_NUM_KEYCHAINS
) / 2.0);
304 printAllTimes(verbose
, deltaMs
, KT_NUM_KEYCHAINS
);
306 /* free the certRefs */
307 for(dex
=0; dex
<KT_NUM_KEYCHAINS
; dex
++) {
308 CFRelease(certRef0
[dex
]);
309 CFRelease(certRef1
[dex
]);
314 * -- search for the first cert
315 * -- search for the next one
316 * -- search once more to end (not found)
318 for(dex
=0; dex
<KT_NUM_KEYCHAINS
; dex
++) {
319 SecKeychainItemRef certRef
= NULL
;
321 /* step 1. set up search, get first item */
322 startTime
= CPUTimeRead();
323 ortn
= SecKeychainSearchCreateFromAttributes(kcRefs
[dex
],
324 kSecCertificateItemClass
,
328 printSecErr("SecKeychainSearchCreateFromAttributes", ortn
);
331 ortn
= SecKeychainSearchCopyNext(srchRef
, &certRef
);
332 /* might be necessary to actually bring in the cert */
333 if(SecCertificateGetTypeID() != CFGetTypeID(certRef
)) {
334 printf("***Unexpected CFType on cert search\n");
337 endTime
= CPUTimeRead();
339 printSecErr("SecKeychainSearchCopyNext", ortn
);
342 deltaMs
[dex
] = CPUTimeDeltaMs(startTime
, endTime
);
345 /* step 2. get next item */
346 startTime
= CPUTimeRead();
347 ortn
= SecKeychainSearchCopyNext(srchRef
, &certRef
);
348 if(SecCertificateGetTypeID() != CFGetTypeID(certRef
)) {
349 printf("***Unexpected CFType on cert search\n");
352 endTime
= CPUTimeRead();
354 printSecErr("SecKeychainSearchCreateFromAttributes", ortn
);
357 deltaMs2
[dex
] = CPUTimeDeltaMs(startTime
, endTime
);
360 /* step 3. one more search for nonexistent item */
361 startTime
= CPUTimeRead();
362 ortn
= SecKeychainSearchCopyNext(srchRef
, &certRef
);
363 endTime
= CPUTimeRead();
364 if(ortn
!= errSecItemNotFound
) {
366 printf("***SecKeychainSearchCopyNext got noErr, "
367 "expected notFound\n");
370 printSecErr("SecKeychainSearchCopyNext", ortn
);
374 deltaMs3
[dex
] = CPUTimeDeltaMs(startTime
, endTime
);
377 printf("SecKeychainSearch first item : %7.3f ms per op\n",
378 CPUTimeAvg(deltaMs
, KT_NUM_KEYCHAINS
));
379 printAllTimes(verbose
, deltaMs
, KT_NUM_KEYCHAINS
);
380 printf("SecKeychainSearch next item : %7.3f ms per op\n",
381 CPUTimeAvg(deltaMs2
, KT_NUM_KEYCHAINS
));
382 printAllTimes(verbose
, deltaMs2
, KT_NUM_KEYCHAINS
);
383 printf("SecKeychainSearch end of list : %7.3f ms per op\n",
384 CPUTimeAvg(deltaMs3
, KT_NUM_KEYCHAINS
));
385 printAllTimes(verbose
, deltaMs3
, KT_NUM_KEYCHAINS
);
388 * TIME: search all certs in all keychains
389 * This search create is outside the loop....
391 ortn
= SecKeychainSearchCreateFromAttributes(NULL
,
392 kSecCertificateItemClass
,
396 printSecErr("SecKeychainSearchCreateFromAttributes", ortn
);
399 /* we have 2 certs per keychain, search all of them */
400 for(dex
=0; dex
<KT_NUM_KEYCHAINS
*2; dex
++) {
401 SecKeychainItemRef certRef
= NULL
;
403 startTime
= CPUTimeRead();
404 ortn
= SecKeychainSearchCopyNext(srchRef
, &certRef
);
405 /* might be necessary to actually bring in the cert */
406 if(SecCertificateGetTypeID() != CFGetTypeID(certRef
)) {
407 printf("***Unexpected CFType on cert search\n");
410 endTime
= CPUTimeRead();
411 deltaMs
[dex
] = CPUTimeDeltaMs(startTime
, endTime
);
414 printf("SecKeychainSearch all KCs : %7.3f ms per op\n",
415 CPUTimeAvg(deltaMs
, KT_NUM_KEYCHAINS
* 2));
416 printAllTimes(verbose
, deltaMs
, KT_NUM_KEYCHAINS
* 2);
419 * TIME: import a p12 identity into each keychain
421 * First, read the file
423 irtn
= readFile(KT_P12_PFX
, &cert0Data
, &cert0Len
);
425 printf("I cannot find file %s in cwd.\n", KT_P12_PFX
);
428 p12Data
= CFDataCreate(NULL
, cert0Data
, cert0Len
);
429 p12Pwd
= CFStringCreateWithCString(NULL
, KT_P12_PASSWORD
,
430 kCFStringEncodingASCII
);
432 for(dex
=0; dex
<KT_NUM_KEYCHAINS
; dex
++) {
433 SecExternalFormat format
= kSecFormatPKCS12
;
434 SecExternalItemType itemType
= kSecItemTypeAggregate
;
435 SecKeyImportExportParameters keyParams
;
436 memset(&keyParams
, 0, sizeof(keyParams
));
437 keyParams
.version
= SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION
;
438 keyParams
.flags
= kSecKeyNoAccessControl
;
439 keyParams
.passphrase
= p12Pwd
;
441 keyParams
.keyAttributes
= CSSM_KEYATTR_PERMANENT
| CSSM_KEYATTR_SENSITIVE
|
442 CSSM_KEYATTR_EXTRACTABLE
;
444 startTime
= CPUTimeRead();
445 ortn
= SecKeychainItemImport(p12Data
,
446 NULL
, // fileNameOrExtension
453 printSecErr("SecKeychainItemImport(p12)", ortn
);
456 endTime
= CPUTimeRead();
457 deltaMs
[dex
] = CPUTimeDeltaMs(startTime
, endTime
);
461 printf("P12 Import : %7.3f ms per op\n",
462 CPUTimeAvg(deltaMs
, KT_NUM_KEYCHAINS
));
463 printAllTimes(verbose
, deltaMs
, KT_NUM_KEYCHAINS
);
465 /* TIME: identity search in each keychain */
466 for(dex
=0; dex
<KT_NUM_KEYCHAINS
; dex
++) {
467 SecIdentitySearchRef idSrch
;
468 SecIdentityRef idRef
;
469 startTime
= CPUTimeRead();
470 ortn
= SecIdentitySearchCreate(kcRefs
[dex
], 0, &idSrch
);
472 printSecErr("SecIdentitySearchCreate", ortn
);
475 ortn
= SecIdentitySearchCopyNext(idSrch
, &idRef
);
476 endTime
= CPUTimeRead();
478 printSecErr("SecIdentitySearchCopyNext", ortn
);
481 deltaMs
[dex
] = CPUTimeDeltaMs(startTime
, endTime
);
485 printf("SecIdentity search : %7.3f ms per op\n",
486 CPUTimeAvg(deltaMs
, KT_NUM_KEYCHAINS
));
487 printAllTimes(verbose
, deltaMs
, KT_NUM_KEYCHAINS
);
490 ortn
= SecKeychainSetSearchList(savedSearchList
);
492 printSecErr("SecKeychainSetSearchList", ortn
);
495 /* delete all the keychains we created */
496 for(dex
=0; dex
<KT_NUM_KEYCHAINS
; dex
++) {
497 if(kcRefs
[dex
] != NULL
) {
498 SecKeychainDelete(kcRefs
[dex
]);
502 /* other cleanup if anyone cares */