2 * secTime.cpp - measure performance of Sec* ops
5 #include <Security/Security.h>
6 #include <security_cdsa_utils/cuFileIo.h>
10 #include <sys/param.h>
11 #include <CoreFoundation/CoreFoundation.h>
12 #include <security_utilities/devrandom.h>
13 #include <clAppUtils/certVerify.h>
14 #include <clAppUtils/clutils.h>
15 #include <utilLib/common.h>
18 * Hard coded test params
22 * The keychain we open and search for certs.
23 * MUST exist in ~/Library/Keychains.
24 * YOU can create it with
25 * % certtool c k=secTimeKc c p=secTimeKc Z
27 #define ST_KC_NAME "secTimeKc"
30 * Certs to verify with SecTrust. We have a variety because the timing on
31 * this test is highly dependent on the position of the verifying anchor
32 * within the system anchors list. (This does not apply to Trust Settings).
35 const char *certFileName
;
39 static const CertToVerify certsToVerify
[] =
42 /* issuer: Secure Server Certification Authority */
47 /* issuer: Equifax Secure Certificate Authority */
53 #define NUM_ST_CERTS (sizeof(certsToVerify) / sizeof(certsToVerify[0]))
55 /* explicit anchor for certsToVerify[0] */
56 #define ST_ANCHOR_NAME "SecureServer.509.cer" /* verifies ST_CERT_HOST */
59 * Cert chain for cgv3*()
61 #define THAWTE_LEAF "dmitchThawte.cer"
62 #define THAWTE_CA "ThawteCA.cer"
63 #define THAWTE_ROOT "ThawteRoot.cer"
65 static void usage(char **argv
)
67 printf("Usage: %s [option ...]\n", argv
[0]);
69 printf(" t=testspec; default=all\n");
70 printf(" test specs: o keychainOpen\n");
71 printf(" s keychainSearch\n");
72 printf(" e secTrustEvaluate\n");
73 printf(" k SecKeychainCopySearchList\n");
74 printf(" v TP CertGroupVerify, system anchor\n");
75 printf(" V TP CertGroupVerify, explicit anchor\n");
76 printf(" 3 TP CertGroupVerify, 3 certs w/anchor\n");
77 printf(" l=loops (only valid if testspec is given)\n");
81 static void printSecErr(
85 printf("%s returned %ld\n", op
, (unsigned long)ortn
);
89 * Struct passed around to test-specific functions.
97 * Each subtest has three functions - init, run, cleanup, called out
100 * Init's job is one-time setup - open files, setup buffers, etc.
101 * PErsistent state can be saved in TestParams->testPriv.
103 typedef OSStatus (*testInitFcn
)(TestParams
*testParams
);
106 * Run's job is to perform 1 iteration with as
107 * little overhead as possible. Return the time spect actually
108 * doing the deed in *timeSpent.
110 typedef OSStatus (*testRunFcn
)(TestParams
*testParams
,
112 CFAbsoluteTime
*timeSpent
);
115 * CLeanu up any resources allocd in init.
117 typedef OSStatus (*testCleanupFcn
)(TestParams
*testParams
);
120 * Static declaration of a test
123 const char *testName
;
127 testCleanupFcn cleanup
;
128 char testSpec
; // for t=xxx cmd line opt
131 #pragma mark ---- Individual tests ----
133 #ifdef use_these_as_a_template
135 static OSStatus
xxxInit(
136 TestParams
*testParams
)
141 static OSStatus
xxRun(
142 TestParams
*testParams
,
144 CFAbsoluteTime
*timeSpent
)
146 CFAbsoluteTime startTime
= CFAbsoluteTimeGetCurrent();
148 *timeSpent
= CFAbsoluteTimeGetCurrent() - startTime
;
152 static OSStatus
xxxCleanup(
153 TestParams
*testParams
)
157 #endif /* template */
159 #pragma mark -- keychain open --
161 static OSStatus
kcOpenInit(
162 TestParams
*testParams
)
167 static OSStatus
kcOpenRun(
168 TestParams
*testParams
,
170 CFAbsoluteTime
*timeSpent
)
172 SecKeychainRef kcRef
;
173 SecKeychainStatus status
;
175 CFAbsoluteTime startTime
= CFAbsoluteTimeGetCurrent();
176 OSStatus ortn
= SecKeychainOpen(ST_KC_NAME
, &kcRef
);
178 printSecErr("SecKeychainOpen", ortn
);
181 ortn
= SecKeychainGetStatus(kcRef
, &status
);
183 printSecErr("SecKeychainGetStatus", ortn
);
185 if(errSecNoSuchKeychain
== ortn
) {
186 printf("The keychain %s does not exist. Please create it"
187 " and populate it like so:\n", ST_KC_NAME
);
188 printf(" certtool c k=%s c p=%s Z\n",
189 ST_KC_NAME
, ST_KC_NAME
);
193 CFAbsoluteTime endTime
= CFAbsoluteTimeGetCurrent();
194 *timeSpent
= endTime
- startTime
;
199 static OSStatus
kcOpenCleanup(
200 TestParams
*testParams
)
205 #pragma mark -- keychain lookup --
208 * Private *testPriv is a kcRef.
210 static OSStatus
kcSearchInit(
211 TestParams
*testParams
)
213 SecKeychainRef kcRef
;
214 OSStatus ortn
= SecKeychainOpen(ST_KC_NAME
, &kcRef
);
216 printSecErr("SecKeychainOpen", ortn
);
219 testParams
->testPriv
= (void *)kcRef
;
223 static OSStatus
kcSearchRun(
224 TestParams
*testParams
,
226 CFAbsoluteTime
*timeSpent
)
228 SecKeychainRef kcRef
= (SecKeychainRef
)testParams
->testPriv
;
229 SecKeychainSearchRef srchRef
= NULL
;
230 SecKeychainItemRef certRef
= NULL
;
231 CFAbsoluteTime endTime
;
232 CFAbsoluteTime startTime
= CFAbsoluteTimeGetCurrent();
234 /* search for any cert */
235 OSStatus ortn
= SecKeychainSearchCreateFromAttributes(kcRef
,
236 kSecCertificateItemClass
,
240 printSecErr("SecKeychainSearchCreateFromAttributes", ortn
);
243 ortn
= SecKeychainSearchCopyNext(srchRef
, &certRef
);
245 printSecErr("SecKeychainSearchCopyNext", ortn
);
248 endTime
= CFAbsoluteTimeGetCurrent();
249 *timeSpent
= endTime
- startTime
;
261 static OSStatus
kcSearchCleanup(
262 TestParams
*testParams
)
264 SecKeychainRef kcRef
= (SecKeychainRef
)testParams
->testPriv
;
269 #pragma mark -- SecTrustEvaluate --
272 * Priv data is an array of SecCertificateRef containing certs to evaluate.
273 * Each run evaluates one of them.
275 static OSStatus
secTrustInit(
276 TestParams
*testParams
)
278 unsigned char *certData
;
282 SecCertificateRef
*certRefs
;
284 certRefs
= (SecCertificateRef
*)malloc(
285 sizeof(SecCertificateRef
) * NUM_ST_CERTS
);
287 for(unsigned dex
=0; dex
<NUM_ST_CERTS
; dex
++) {
288 if(readFile(certsToVerify
[dex
].certFileName
, &certData
, &certLen
)) {
289 printf("***Can not find cert file %s. Aborting.\n",
290 certsToVerify
[dex
].certFileName
);
293 cdata
.Data
= certData
;
294 cdata
.Length
= certLen
;
295 SecCertificateRef certRef
;
296 OSStatus ortn
= SecCertificateCreateFromData(&cdata
,
298 CSSM_CERT_ENCODING_DER
,
301 printSecErr("SecCertificateCreateFromData", ortn
);
304 free(certData
); // mallocd by readFile()
305 certRefs
[dex
] = certRef
;
307 testParams
->testPriv
= certRefs
;
311 static OSStatus
secTrustRun(
312 TestParams
*testParams
,
314 CFAbsoluteTime
*timeSpent
)
316 unsigned whichDex
= loopNum
% NUM_ST_CERTS
;
317 SecCertificateRef
*certRefs
= (SecCertificateRef
*)testParams
->testPriv
;
318 SecCertificateRef certRef
= certRefs
[whichDex
];
321 * We measure the whole enchilada, that's what SecureTransport
324 CFAbsoluteTime startTime
= CFAbsoluteTimeGetCurrent();
326 CFMutableArrayRef certs
;
327 certs
= CFArrayCreateMutable(NULL
, 1, &kCFTypeArrayCallBacks
);
328 CFArrayInsertValueAtIndex(certs
, 0, certRef
);
330 SecPolicyRef policy
= NULL
;
331 SecPolicySearchRef policySearch
= NULL
;
333 OSStatus ortn
= SecPolicySearchCreate(CSSM_CERT_X_509v3
,
334 &CSSMOID_APPLE_TP_SSL
,
338 printSecErr("SecPolicySearchCreate", ortn
);
342 ortn
= SecPolicySearchCopyNext(policySearch
, &policy
);
344 printSecErr("SecPolicySearchCopyNext", ortn
);
347 CFRelease(policySearch
);
349 SecTrustRef secTrust
;
350 ortn
= SecTrustCreateWithCertificates(certs
, policy
, &secTrust
);
352 printSecErr("SecTrustCreateWithCertificates", ortn
);
355 /* no action data for now */
357 SecTrustResultType secTrustResult
;
358 ortn
= SecTrustEvaluate(secTrust
, &secTrustResult
);
360 printSecErr("SecTrustEvaluate", ortn
);
368 CFAbsoluteTime endTime
= CFAbsoluteTimeGetCurrent();
369 *timeSpent
= endTime
- startTime
;
374 static OSStatus
secTrustCleanup(
375 TestParams
*testParams
)
377 SecCertificateRef
*certRefs
= (SecCertificateRef
*)testParams
->testPriv
;
378 for(unsigned dex
=0; dex
<NUM_ST_CERTS
; dex
++) {
379 CFRelease(certRefs
[dex
]);
385 #pragma mark -- SecKeychainCopySearchList --
387 static OSStatus
kcCSLInit(
388 TestParams
*testParams
)
393 static OSStatus
kcCSLRun(
394 TestParams
*testParams
,
396 CFAbsoluteTime
*timeSpent
)
399 CFAbsoluteTime startTime
= CFAbsoluteTimeGetCurrent();
400 OSStatus ortn
= SecKeychainCopySearchList(&sl
);
402 printSecErr("SecKeychainCopySearchList", ortn
);
406 *timeSpent
= CFAbsoluteTimeGetCurrent() - startTime
;
410 static OSStatus
kcCSLCleanup(
411 TestParams
*testParams
)
416 #pragma mark -- CSSM_TP_CertGroupVerify, system anchors --
418 /* private data allocated in cgvInit */
420 CSSM_TP_HANDLE tpHand
;
421 CSSM_CL_HANDLE clHand
;
422 CSSM_CSP_HANDLE cspHand
;
423 BlobList
*certs
[NUM_ST_CERTS
];
424 BlobList
*anchors
; /* cgvAnchor* only */
427 static OSStatus
cgvInit(
428 TestParams
*testParams
)
430 CgvParams
*cgvParams
= (CgvParams
*)malloc(sizeof(CgvParams
));
431 memset(cgvParams
, 0, sizeof(CgvParams
));
432 cgvParams
->tpHand
= tpStartup();
433 cgvParams
->clHand
= clStartup();
434 cgvParams
->cspHand
= cspStartup();
435 for(unsigned dex
=0; dex
<NUM_ST_CERTS
; dex
++) {
436 cgvParams
->certs
[dex
] = new BlobList();
437 cgvParams
->certs
[dex
]->addFile(certsToVerify
[dex
].certFileName
);
439 cgvParams
->anchors
= NULL
;
440 testParams
->testPriv
= cgvParams
;
444 static OSStatus
cgvRun(
445 TestParams
*testParams
,
447 CFAbsoluteTime
*timeSpent
)
449 CgvParams
*cgvParams
= (CgvParams
*)testParams
->testPriv
;
451 unsigned whichDex
= loopNum
% NUM_ST_CERTS
;
452 BlobList
*certBlob
= cgvParams
->certs
[whichDex
];
454 CFAbsoluteTime startTime
= CFAbsoluteTimeGetCurrent();
455 int rtn
= certVerifySimple(
459 *certBlob
, // contains one cert, the subject
461 CSSM_TRUE
, // useSystemAnchors
462 CSSM_FALSE
, // leafCertIsCa
463 CSSM_FALSE
, // allow expired root
465 certsToVerify
[whichDex
].hostName
,
466 CSSM_FALSE
, // sslClient
469 NULL
, // expected error str
474 CSSM_FALSE
, // trustSettings
476 CSSM_FALSE
); // verbose
477 *timeSpent
= CFAbsoluteTimeGetCurrent() - startTime
;
479 printf("***certVerify error\n");
480 return (OSStatus
)rtn
;
485 static OSStatus
cgvCleanup(
486 TestParams
*testParams
)
488 CgvParams
*cgvParams
= (CgvParams
*)testParams
->testPriv
;
489 CSSM_ModuleDetach(cgvParams
->cspHand
);
490 CSSM_ModuleDetach(cgvParams
->tpHand
);
491 CSSM_ModuleDetach(cgvParams
->clHand
);
492 for(unsigned dex
=0; dex
<NUM_ST_CERTS
; dex
++) {
493 delete cgvParams
->certs
[dex
];
495 if(cgvParams
->anchors
) {
496 delete(cgvParams
->anchors
);
502 #pragma mark -- CSSM_TP_CertGroupVerify, explicit anchors --
504 static OSStatus
cgvAnchorInit(
505 TestParams
*testParams
)
507 CgvParams
*cgvParams
= (CgvParams
*)malloc(sizeof(CgvParams
));
508 memset(cgvParams
, 0, sizeof(CgvParams
));
509 cgvParams
->tpHand
= tpStartup();
510 cgvParams
->clHand
= clStartup();
511 cgvParams
->cspHand
= cspStartup();
512 cgvParams
->certs
[0] = new BlobList();
513 cgvParams
->certs
[0]->addFile(certsToVerify
[0].certFileName
);
514 cgvParams
->anchors
= new BlobList();
515 cgvParams
->anchors
->addFile(ST_ANCHOR_NAME
);
516 testParams
->testPriv
= cgvParams
;
520 static OSStatus
cgvAnchorRun(
521 TestParams
*testParams
,
523 CFAbsoluteTime
*timeSpent
)
525 CgvParams
*cgvParams
= (CgvParams
*)testParams
->testPriv
;
528 CertVerifyArgs vfyArgs
;
529 memset(&vfyArgs
, 0, sizeof(vfyArgs
));
530 vfyArgs
.version
= CERT_VFY_ARGS_VERS
;
532 vfyArgs
.tpHand
= cgvParams
->tpHand
;
533 vfyArgs
.clHand
= cgvParams
->clHand
;
534 vfyArgs
.cspHand
= cgvParams
->cspHand
;
535 vfyArgs
.certs
= cgvParams
->certs
[0];
536 vfyArgs
.roots
= cgvParams
->anchors
;
537 vfyArgs
.allowUnverified
= CSSM_TRUE
;
538 vfyArgs
.vfyPolicy
= CVP_SSL
;
539 vfyArgs
.revokePolicy
= CRP_None
;
540 vfyArgs
.sslHost
= certsToVerify
[0].hostName
;
541 vfyArgs
.revokePolicy
= CRP_None
;
542 vfyArgs
.quiet
= CSSM_TRUE
;
544 CFAbsoluteTime startTime
= CFAbsoluteTimeGetCurrent();
545 int rtn
= certVerify(&vfyArgs
);
546 *timeSpent
= CFAbsoluteTimeGetCurrent() - startTime
;
548 printf("***certVerify error\n");
549 return (OSStatus
)rtn
;
554 /* cleanup - use cgvCleanup() */
556 #pragma mark -- CSSM_TP_CertGroupVerify, 3 certs with anchor --
558 static OSStatus
cgv3Init(
559 TestParams
*testParams
)
561 CgvParams
*cgvParams
= (CgvParams
*)malloc(sizeof(CgvParams
));
562 memset(cgvParams
, 0, sizeof(CgvParams
));
563 cgvParams
->tpHand
= tpStartup();
564 cgvParams
->clHand
= clStartup();
565 cgvParams
->cspHand
= cspStartup();
566 cgvParams
->certs
[0] = new BlobList();
567 cgvParams
->certs
[0]->addFile(THAWTE_LEAF
);
568 cgvParams
->certs
[0]->addFile(THAWTE_CA
);
569 cgvParams
->certs
[0]->addFile(THAWTE_ROOT
);
570 cgvParams
->anchors
= new BlobList();
571 cgvParams
->anchors
->addFile(THAWTE_ROOT
);
572 testParams
->testPriv
= cgvParams
;
576 static OSStatus
cgv3Run(
577 TestParams
*testParams
,
579 CFAbsoluteTime
*timeSpent
)
581 CgvParams
*cgvParams
= (CgvParams
*)testParams
->testPriv
;
584 CertVerifyArgs vfyArgs
;
585 memset(&vfyArgs
, 0, sizeof(vfyArgs
));
586 vfyArgs
.version
= CERT_VFY_ARGS_VERS
;
588 vfyArgs
.tpHand
= cgvParams
->tpHand
;
589 vfyArgs
.clHand
= cgvParams
->clHand
;
590 vfyArgs
.cspHand
= cgvParams
->cspHand
;
591 vfyArgs
.certs
= cgvParams
->certs
[0]; /* that's three certs */
592 vfyArgs
.roots
= cgvParams
->anchors
;
593 vfyArgs
.allowUnverified
= CSSM_TRUE
;
594 vfyArgs
.vfyPolicy
= CVP_Basic
;
595 vfyArgs
.revokePolicy
= CRP_None
;
596 vfyArgs
.sslHost
= certsToVerify
[0].hostName
;
597 vfyArgs
.revokePolicy
= CRP_None
;
598 vfyArgs
.quiet
= CSSM_TRUE
;
600 CFAbsoluteTime startTime
= CFAbsoluteTimeGetCurrent();
601 int rtn
= certVerify(&vfyArgs
);
602 *timeSpent
= CFAbsoluteTimeGetCurrent() - startTime
;
604 printf("***certVerify error\n");
605 return (OSStatus
)rtn
;
610 static OSStatus
cgv3Cleanup(
611 TestParams
*testParams
)
613 CgvParams
*cgvParams
= (CgvParams
*)testParams
->testPriv
;
614 CSSM_ModuleDetach(cgvParams
->cspHand
);
615 CSSM_ModuleDetach(cgvParams
->tpHand
);
616 CSSM_ModuleDetach(cgvParams
->clHand
);
617 delete cgvParams
->certs
[0];
618 delete(cgvParams
->anchors
);
623 #pragma mark ---- Static array of all tests ----
625 static TestDefs testDefs
[] =
634 { "Keychain cert search",
641 { "SecTrustEvaluate",
648 { "TP CertGroupVerify, system anchors",
655 { "TP CertGroupVerify, explicit anchor",
662 { "TP CertGroupVerify, 3 certs with anchor",
669 { "SecKeychainCopySearchList",
678 #define NUM_TESTS (sizeof(testDefs) / sizeof(testDefs[0]))
680 int main(int argc
, char **argv
)
682 TestParams testParams
;
687 unsigned cmdLoops
= 0; // can be specified in cmd line
688 // if not, use TestDefs.loops
689 char testSpec
= '\0'; // allows specification of one test
692 for(arg
=1; arg
<argc
; arg
++) {
699 cmdLoops
= atoi(&argp
[2]);
706 for(unsigned testNum
=0; testNum
<NUM_TESTS
; testNum
++) {
707 testDef
= &testDefs
[testNum
];
710 if(testSpec
&& (testDef
->testSpec
!= testSpec
)) {
713 printf("%s:\n", testDef
->testName
);
714 ortn
= testDef
->init(&testParams
);
720 loopCount
= cmdLoops
;
724 loopCount
= testDef
->loops
;
726 CFAbsoluteTime totalTime
= 0;
727 CFAbsoluteTime thisTime
;
728 for(unsigned loop
=0; loop
<loopCount
; loop
++) {
729 ortn
= testDef
->run(&testParams
, loop
, &thisTime
);
733 totalTime
+= thisTime
;
735 testDef
->cleanup(&testParams
);
736 printf(" %3.2f ms per op\n", (totalTime
/ loopCount
) * 1000.0);