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