1/*
2 * cmsTime.cpp - measure performance of CMS decode & verify
3 */
4
5#include <stdlib.h>
6#include <strings.h>
7#include <stdio.h>
8#include <unistd.h>
9#include <CoreFoundation/CoreFoundation.h>
10#include <Security/Security.h>
11#include <Security/CMSDecoder.h>
12#include <security_cdsa_utils/cuFileIo.h>
13#include <utilLib/common.h>
14
15#define LOOPS_DEF			100
16#define SIGNED_FILE			"noRoot.p7"
17
18static void usage(char **argv)
19{
20	printf("usage: %s [options]\n", argv[0]);
21	printf("Options:\n");
22	printf("  -l loops        -- loops; default %d; 0=forever\n", LOOPS_DEF);
23	printf("  -i inFile       -- input file; default is %s\n", SIGNED_FILE);
24	printf("  -K              -- set empty KC list\n");
25	/* etc. */
26	exit(1);
27}
28
29/* perform one CMS decode */
30static OSStatus doDecode(
31	const void *cmsData,
32	size_t cmsDataLen,
33	SecPolicyRef policyRef,
34	CFArrayRef kcArray)			/* optional */
35
36{
37	OSStatus ortn;
38	CMSDecoderRef cmsDecoder = NULL;
39
40	CMSDecoderCreate(&cmsDecoder);
41	if(kcArray) {
42		ortn = CMSDecoderSetSearchKeychain(cmsDecoder, kcArray);
43		if(ortn) {
44			cssmPerror("CMSDecoderSetSearchKeychain", ortn);
45			return ortn;
46		}
47	}
48	ortn = CMSDecoderUpdateMessage(cmsDecoder, cmsData, cmsDataLen);
49	if(ortn) {
50		cssmPerror("CMSDecoderUpdateMessage", ortn);
51		return ortn;
52	}
53	ortn = CMSDecoderFinalizeMessage(cmsDecoder);
54	if(ortn) {
55		cssmPerror("CMSDecoderFinalizeMessage", ortn);
56		return ortn;
57	}
58
59	CMSSignerStatus signerStatus;
60	ortn = CMSDecoderCopySignerStatus(cmsDecoder, 0, policyRef, true, &signerStatus, NULL, NULL);
61	if(ortn) {
62		cssmPerror("CMSDecoderCopySignerStatus", ortn);
63		return ortn;
64	}
65	if(signerStatus != kCMSSignerValid) {
66		printf("***Bad signerStatus (%d)\n", (int)signerStatus);
67		ortn = -1;
68	}
69	CFRelease(cmsDecoder);
70	return ortn;
71}
72
73int main(int argc, char **argv)
74{
75	unsigned dex;
76
77	CFArrayRef 			emptyKCList = NULL;
78	unsigned char 		*blob = NULL;
79	unsigned	 		blobLen;
80	SecPolicyRef      	policyRef = NULL;
81
82	/* user-spec'd variables */
83	unsigned loops = LOOPS_DEF;
84	char *blobFile = SIGNED_FILE;
85	bool emptyList = false;			/* specify empty KC list */
86
87	extern char *optarg;
88	int arg;
89	while ((arg = getopt(argc, argv, "l:i:Kh")) != -1) {
90		switch (arg) {
91			case 'l':
92				loops = atoi(optarg);
93				break;
94			case 'i':
95				blobFile = optarg;
96				break;
97			case 'K':
98				emptyList = true;
99				emptyKCList = CFArrayCreate(NULL, NULL, 0, &kCFTypeArrayCallBacks);
100				break;
101			case 'h':
102				usage(argv);
103		}
104	}
105	if(optind != argc) {
106		usage(argv);
107	}
108
109	if(readFile(blobFile, &blob, &blobLen)) {
110		printf("***Error reading %s\n", blobFile);
111		exit(1);
112	}
113	/* cook up reusable policy object */
114	SecPolicySearchRef	policySearch = NULL;
115	OSStatus ortn = SecPolicySearchCreate(CSSM_CERT_X_509v3,
116		&CSSMOID_APPLE_X509_BASIC,
117		NULL,				// policy opts
118		&policySearch);
119	if(ortn) {
120		cssmPerror("SecPolicySearchCreate", ortn);
121		exit(1);
122	}
123	ortn = SecPolicySearchCopyNext(policySearch, &policyRef);
124	if(ortn) {
125		cssmPerror("SecPolicySearchCopyNext", ortn);
126		exit(1);
127	}
128	CFRelease(policySearch);
129
130	CFAbsoluteTime startTimeFirst;
131	CFAbsoluteTime endTimeFirst;
132	CFAbsoluteTime startTimeMulti;
133	CFAbsoluteTime endTimeMulti;
134
135	/* GO */
136	startTimeFirst = CFAbsoluteTimeGetCurrent();
137	if(doDecode(blob, blobLen, policyRef, emptyKCList)) {
138		exit(1);
139	}
140	endTimeFirst = CFAbsoluteTimeGetCurrent();
141
142	startTimeMulti = CFAbsoluteTimeGetCurrent();
143	for(dex=0; dex<loops; dex++) {
144		if(doDecode(blob, blobLen, policyRef, emptyKCList)) {
145			exit(1);
146		}
147	}
148	endTimeMulti = CFAbsoluteTimeGetCurrent();
149	CFTimeInterval elapsed = endTimeMulti - startTimeMulti;
150
151	printf("First decode = %4.1f ms\n", (endTimeFirst - startTimeFirst) * 1000.0);
152	printf("Next decodes = %4.2f ms/op (%f s total for %u loops)\n",
153		elapsed * 1000.0 / loops, elapsed, loops);
154
155	return 0;
156}
157