]> git.saurik.com Git - apple/security.git/blob - SecurityTests/clxutils/sslBench/sslBench.cpp
Security-57336.1.9.tar.gz
[apple/security.git] / SecurityTests / clxutils / sslBench / sslBench.cpp
1 /*
2 * Measure performance of SecureTransport - setup and sustained data
3 * throughput.
4 *
5 * Written by Doug Mitchell.
6 */
7 #include <Security/SecureTransport.h>
8 #include <clAppUtils/sslAppUtils.h>
9 #include <clAppUtils/ioSock.h>
10 #include <security_cdsa_utils/cuFileIo.h>
11 #include <utilLib/common.h>
12
13 #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <time.h>
18 #include <ctype.h>
19 #include <sys/param.h>
20 #include <CoreFoundation/CoreFoundation.h>
21 #include <security_utilities/devrandom.h>
22
23 /* default - run both server and client on this machine, port 1200 */
24 #define HOST_DEF "localhost"
25 #define PORT_DEF 1200
26
27 /* default keychain */
28 #define DEFAULT_KC "localcert"
29
30 #define XFERSIZE_DEF (1024 * 1024)
31 #define BUFSIZE 1024
32
33 #define DH_PARAM_FILE "dhParams_1024.der"
34
35 static void usage(char **argv)
36 {
37 printf("Usage: %s s[erver]|c[lient] [option ...]\n", argv[0]);
38 printf("Options:\n");
39 printf(" -h hostname (default = %s)\n", HOST_DEF);
40 printf(" -p port (default = %d)\n", PORT_DEF);
41 printf(" -k keychain (default = %s)\n", DEFAULT_KC);
42 printf(" -x transferSize (default = %d)\n", XFERSIZE_DEF);
43 printf(" -c cipher (default = RSA/AES128; server side only)\n");
44 printf(" ciphers: r=RSA/RC4; d=RSA/DES; D=RSA/3DES; h=DHA/RC4; "
45 "H=DH/DSS/DES; A=AES256\n");
46 printf(" -v version (t|2|3 default = t(TLS1); server side only)\n");
47 printf(" -b bufsize (default = %d)\n", BUFSIZE);
48 printf(" -w password (unlock server keychain with password)\n");
49 printf(" -a (enable client authentication)\n");
50 printf(" -B non-blocking I/O\n");
51 exit(1);
52 }
53
54
55 int main(int argc, char **argv)
56 {
57 /* user-spec'd variables */
58 const char *kcName = DEFAULT_KC;
59 unsigned xferSize = XFERSIZE_DEF;
60 int port = PORT_DEF;
61 const char *hostName = HOST_DEF;
62 SSLCipherSuite cipherSuite = TLS_RSA_WITH_AES_128_CBC_SHA;
63 SSLProtocol prot = kTLSProtocol1Only;
64 char password[200];
65 bool clientAuthEnable = false;
66 bool isServer = false;
67 unsigned bufSize = BUFSIZE;
68 bool diffieHellman = false;
69 int nonBlocking = 0;
70
71 if(argc < 2) {
72 usage(argv);
73 }
74 password[0] = 0;
75 switch(argv[1][0]) {
76 case 's':
77 isServer = true;
78 break;
79 case 'c':
80 isServer = false;
81 break;
82 default:
83 usage(argv);
84 }
85
86 extern int optind;
87 extern char *optarg;
88 int arg;
89 optind = 2;
90 while ((arg = getopt(argc, argv, "h:p:k:x:c:v:w:b:aB")) != -1) {
91 switch (arg) {
92 case 'h':
93 hostName = optarg;
94 break;
95 case 'p':
96 port = atoi(optarg);
97 break;
98 case 'k':
99 kcName = optarg;
100 break;
101 case 'x':
102 xferSize = atoi(optarg);
103 break;
104 case 'c':
105 if(!isServer) {
106 printf("***Specify cipherSuite on server side.\n");
107 exit(1);
108 }
109 switch(optarg[0]) {
110 case 'r':
111 cipherSuite = SSL_RSA_WITH_RC4_128_SHA;
112 break;
113 case 'd':
114 cipherSuite = SSL_RSA_WITH_DES_CBC_SHA;
115 break;
116 case 'D':
117 cipherSuite = SSL_RSA_WITH_3DES_EDE_CBC_SHA;
118 break;
119 case 'h':
120 cipherSuite = SSL_DH_anon_WITH_RC4_128_MD5;
121 diffieHellman = true;
122 break;
123 case 'H':
124 cipherSuite = SSL_DHE_DSS_WITH_DES_CBC_SHA;
125 diffieHellman = true;
126 break;
127 case 'A':
128 cipherSuite = TLS_RSA_WITH_AES_256_CBC_SHA;
129 break;
130 default:
131 usage(argv);
132 }
133 break;
134 case 'v':
135 if(!isServer) {
136 printf("***Specify protocol on server side.\n");
137 exit(1);
138 }
139 switch(optarg[0]) {
140 case 't':
141 prot = kTLSProtocol1Only;
142 break;
143 case '2':
144 prot = kSSLProtocol2;
145 break;
146 case '3':
147 prot = kSSLProtocol3Only;
148 break;
149 default:
150 usage(argv);
151 }
152 break;
153 case 'w':
154 strcpy(password, optarg);
155 break;
156 case 'b':
157 bufSize = atoi(optarg);
158 break;
159 case 'a':
160 clientAuthEnable = true;
161 break;
162 case 'B':
163 nonBlocking = 1;
164 break;
165 default:
166 usage(argv);
167 }
168 }
169
170 /* per-transfer buffer - make it random for server */
171 char *buf = (char *)malloc(bufSize);
172 if(isServer) {
173 Security::DevRandomGenerator rng;
174 rng.random(buf, bufSize);
175 }
176
177 /* gather Diffie-Hellman params from cwd */
178 unsigned char *dhParams = NULL;
179 unsigned dhParamsLen = 0;
180 if(diffieHellman && isServer) {
181 if(readFile(DH_PARAM_FILE, &dhParams, &dhParamsLen)) {
182 printf("***Error reading Diffie-Hellman Params. Prepare to "
183 "wait for a minute during SSL handshake.\n");
184 }
185 }
186
187 /*
188 * Open keychain; both sides use the same one.
189 */
190 OSStatus ortn;
191 SecKeychainRef certKc = NULL;
192 CFAbsoluteTime kcOpenStart = CFAbsoluteTimeGetCurrent();
193 ortn = SecKeychainOpen(kcName, &certKc);
194 if(ortn) {
195 printf("Error opening keychain %s (%d); aborting.\n",
196 kcName, (int)ortn);
197 exit(1);
198 }
199 if(password[0]) {
200 ortn = SecKeychainUnlock(certKc, strlen(password), password, true);
201 if(ortn) {
202 printf("SecKeychainUnlock returned %d\n", (int)ortn);
203 /* oh well */
204 }
205 }
206 CFAbsoluteTime kcOpenEnd = CFAbsoluteTimeGetCurrent();
207
208 otSocket peerSock = 0;
209 otSocket listenSock = 0; // for server only
210 PeerSpec peerId;
211
212 if(isServer) {
213 printf("...listening for client connection on port %d\n", port);
214 ortn = ListenForClients(port, nonBlocking, &listenSock);
215 if(ortn) {
216 printf("...error establishing a listen socket. Aborting.\n");
217 exit(1);
218 }
219 ortn = AcceptClientConnection(listenSock, &peerSock, &peerId);
220 if(ortn) {
221 printf("...error listening for connection. Aborting.\n");
222 exit(1);
223 }
224 }
225 else {
226 printf("...connecting to host %s at port %d\n", hostName, port);
227 ortn = MakeServerConnection(hostName, port, nonBlocking, &peerSock,
228 &peerId);
229 if(ortn) {
230 printf("...error connecting to server %s. Aborting.\n",
231 hostName);
232 exit(1);
233 }
234 }
235
236 /* start timing SSL setup */
237 CFAbsoluteTime setupStart = CFAbsoluteTimeGetCurrent();
238
239 SSLContextRef ctx;
240 ortn = SSLNewContext(isServer, &ctx);
241 if(ortn) {
242 printSslErrStr("SSLNewContext", ortn);
243 exit(1);
244 }
245 ortn = SSLSetIOFuncs(ctx, SocketRead, SocketWrite);
246 if(ortn) {
247 printSslErrStr("SSLSetIOFuncs", ortn);
248 exit(1);
249 }
250 ortn = SSLSetConnection(ctx, (SSLConnectionRef)peerSock);
251 if(ortn) {
252 printSslErrStr("SSLSetConnection", ortn);
253 exit(1);
254 }
255 ortn = SSLSetPeerDomainName(ctx, hostName, strlen(hostName) + 1);
256 if(ortn) {
257 printSslErrStr("SSLSetPeerDomainName", ortn);
258 exit(1);
259 }
260
261 /*
262 * Server/client specific setup.
263 *
264 * Client uses the same keychain as server, but it uses it for
265 * sslAddTrustedRoots() instead of getSslCerts() and
266 * SSLSetCertificate().
267 */
268 CFArrayRef myCerts = NULL;
269 if(clientAuthEnable || isServer) {
270 myCerts = sslKcRefToCertArray(certKc, CSSM_FALSE, CSSM_FALSE, NULL, NULL);
271 if(myCerts == NULL) {
272 exit(1);
273 }
274 ortn = addIdentityAsTrustedRoot(ctx, myCerts);
275 if(ortn) {
276 exit(1);
277 }
278 ortn = SSLSetCertificate(ctx, myCerts);
279 if(ortn) {
280 printSslErrStr("SSLSetCertificate", ortn);
281 exit(1);
282 }
283 }
284 if(isServer) {
285 SSLAuthenticate auth;
286 if(clientAuthEnable) {
287 auth = kAlwaysAuthenticate;
288 }
289 else {
290 auth = kNeverAuthenticate;
291 }
292 ortn = SSLSetClientSideAuthenticate(ctx, auth);
293 if(ortn) {
294 printSslErrStr("SSLSetClientSideAuthenticate", ortn);
295 exit(1);
296 }
297 ortn = SSLSetEnabledCiphers(ctx, &cipherSuite, 1);
298 if(ortn) {
299 printSslErrStr("SSLSetEnabledCiphers", ortn);
300 exit(1);
301 }
302 ortn = SSLSetProtocolVersion(ctx, prot);
303 if(ortn) {
304 printSslErrStr("SSLSetProtocolVersion", ortn);
305 exit(1);
306 }
307 if(dhParams != NULL) {
308 ortn = SSLSetDiffieHellmanParams(ctx, dhParams, dhParamsLen);
309 if(ortn) {
310 printSslErrStr("SSLSetDiffieHellmanParams", ortn);
311 exit(1);
312 }
313 }
314 }
315 else {
316 /* client setup */
317 if(!clientAuthEnable) {
318 /* We're not presenting a cert; trust the server certs */
319 bool foundOne;
320 ortn = sslAddTrustedRoots(ctx, certKc, &foundOne);
321 if(ortn) {
322 printSslErrStr("sslAddTrustedRoots", ortn);
323 exit(1);
324 }
325 }
326 }
327
328 /*
329 * Context setup complete. Start timing handshake.
330 */
331 CFAbsoluteTime hshakeStart = CFAbsoluteTimeGetCurrent();
332 do {
333 ortn = SSLHandshake(ctx);
334 } while (ortn == errSSLWouldBlock);
335 if(ortn) {
336 printSslErrStr("SSLHandshake", ortn);
337 exit(1);
338 }
339 CFAbsoluteTime hshakeEnd = CFAbsoluteTimeGetCurrent();
340
341 /* snag these before data xfer possibly shuts down connection */
342 SSLProtocol negVersion;
343 SSLCipherSuite negCipher;
344 SSLClientCertificateState certState; // RETURNED
345
346 SSLGetNegotiatedCipher(ctx, &negCipher);
347 SSLGetNegotiatedProtocolVersion(ctx, &negVersion);
348 SSLGetClientCertificateState(ctx, &certState);
349
350 /* server sends xferSize bytes to client and shuts down */
351 size_t bytesMoved;
352
353 CFAbsoluteTime dataStart = CFAbsoluteTimeGetCurrent();
354 size_t totalMoved = 0;
355 if(isServer) {
356 size_t bytesToGo = xferSize;
357 bool done = false;
358 do {
359 size_t thisMove = bufSize;
360 if(thisMove > bytesToGo) {
361 thisMove = bytesToGo;
362 }
363 ortn = SSLWrite(ctx, buf, thisMove, &bytesMoved);
364 switch(ortn) {
365 case noErr:
366 case errSSLWouldBlock:
367 break;
368 default:
369 done = true;
370 break;
371 }
372 bytesToGo -= bytesMoved;
373 totalMoved += bytesMoved;
374 if(bytesToGo == 0) {
375 done = true;
376 }
377 } while(!done);
378 if(ortn != noErr) {
379 printSslErrStr("SSLWrite", ortn);
380 exit(1);
381 }
382 }
383 else {
384 /* client reads until error or errSSLClosedGraceful */
385 bool done = false;
386 do {
387 ortn = SSLRead(ctx, buf, bufSize, &bytesMoved);
388 switch(ortn) {
389 case errSSLClosedGraceful:
390 done = true;
391 break;
392 case noErr:
393 case errSSLWouldBlock:
394 break;
395 default:
396 done = true;
397 break;
398 }
399 totalMoved += bytesMoved;
400 } while(!done);
401 if(ortn != errSSLClosedGraceful) {
402 printSslErrStr("SSLRead", ortn);
403 exit(1);
404 }
405 }
406
407 /* shut down channel */
408 ortn = SSLClose(ctx);
409 if(ortn) {
410 printSslErrStr("SSLCLose", ortn);
411 exit(1);
412 }
413 CFAbsoluteTime dataEnd = CFAbsoluteTimeGetCurrent();
414
415 /* how'd we do? */
416 printf("SSL version : %s\n",
417 sslGetProtocolVersionString(negVersion));
418 printf("CipherSuite : %s\n",
419 sslGetCipherSuiteString(negCipher));
420 printf("Client Cert State : %s\n",
421 sslGetClientCertStateString(certState));
422
423 if(password[0]) {
424 printf("keychain open/unlock : ");
425 }
426 else {
427 printf("keychain open : ");
428 }
429 printf("%f s\n", kcOpenEnd - kcOpenStart);
430 printf("SSLContext setup : %f s\n", hshakeStart - setupStart);
431 printf("SSL Handshake : %f s\n", hshakeEnd - hshakeStart);
432 printf("Data Transfer : %u bytes in %f s\n", (unsigned)totalMoved,
433 dataEnd - dataStart);
434 printf(" : %.1f Kbytes/s\n",
435 totalMoved / (dataEnd - dataStart) / 1024.0);
436 return 0;
437 }
438
439
440