2 * Measure performance of SecureTransport handshake
4 * Written by Doug Mitchell.
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>
12 #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
18 #include <sys/param.h>
19 #include <CoreFoundation/CoreFoundation.h>
21 /* default - run both server and client on this machine, port 1200 */
22 #define HOST_DEF "localhost"
25 /* default keychain */
26 #define DEFAULT_KC "localcert"
28 #define DH_PARAM_FILE "dhParams_1024.der"
30 #define GET_MSG "GET / HTTP/1.0\r\n\r\n"
32 static void usage(char **argv
)
34 printf("Usage: %s s[erver]|c[lient] loops [option ...]\n", argv
[0]);
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; "
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");
59 printf("***SIGPIPE***\n");
62 int main(int argc
, char **argv
)
64 /* user-spec'd variables */
66 char *kcName
= DEFAULT_KC
;
68 char *hostName
= HOST_DEF
;
69 SSLCipherSuite cipherSuite
= SSL_RSA_WITH_RC4_128_SHA
;
70 SSLProtocol prot
= kTLSProtocol1Only
;
72 bool clientAuthEnable
= false;
73 bool isServer
= false;
74 bool diffieHellman
= false;
76 bool resumeEnable
= false;
77 bool setClientAnchor
= true;
78 bool certVerifyEnable
= true;
79 bool checkHostName
= true;
82 otSocket listenSock
= 0; // for server only
83 CFArrayRef myCerts
= NULL
;
85 signal(SIGPIPE
, sigpipe
);
100 loops
= atoi(argv
[2]);
109 while ((arg
= getopt(argc
, argv
, "h:p:k:x:c:v:w:b:aVrndog")) != -1) {
122 printf("***Specify cipherSuite on server side.\n");
127 cipherSuite
= SSL_RSA_WITH_RC4_128_SHA
;
130 cipherSuite
= SSL_RSA_WITH_DES_CBC_SHA
;
133 cipherSuite
= SSL_RSA_WITH_3DES_EDE_CBC_SHA
;
136 cipherSuite
= SSL_DH_anon_WITH_RC4_128_MD5
;
137 diffieHellman
= true;
140 cipherSuite
= SSL_DHE_DSS_WITH_DES_CBC_SHA
;
141 diffieHellman
= true;
149 printf("***Specify protocol on server side.\n");
154 prot
= kTLSProtocol1Only
;
157 prot
= kSSLProtocol2
;
160 prot
= kSSLProtocol3Only
;
167 strcpy(password
, optarg
);
170 clientAuthEnable
= true;
179 setClientAnchor
= false;
182 certVerifyEnable
= false;
185 checkHostName
= false;
195 /* gather Diffie-Hellman params from cwd */
196 if(JAGUAR_BUILD
&& diffieHellman
) {
197 printf("***SOrry, DIffie Hellman not available in this config.\n");
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");
210 * Open keychain; both sides use the same one.
213 SecKeychainRef certKc
= NULL
;
214 if(isServer
|| clientAuthEnable
|| setClientAnchor
) {
215 ortn
= SecKeychainOpen(kcName
, &certKc
);
217 printf("Error opening keychain %s (%d); aborting.\n",
222 ortn
= SecKeychainUnlock(certKc
, strlen(password
), password
, true);
224 printf("SecKeychainUnlock returned %lu\n", ortn
);
230 /* just do this once */
231 if(clientAuthEnable
|| isServer
|| setClientAnchor
) {
232 myCerts
= sslKcRefToCertArray(certKc
, CSSM_FALSE
, CSSM_TRUE
, NULL
);
233 if(myCerts
== NULL
) {
238 /* server sets up listen port just once */
240 printf("...listening for client connection on port %d\n", port
);
241 ortn
= ListenForClients(port
, 0, &listenSock
);
243 printf("...error establishing a listen socket. Aborting.\n");
248 CFAbsoluteTime setupTotal
= 0;
249 CFAbsoluteTime handShakeTotal
= 0;
251 for(unsigned loop
=0; loop
<loops
; loop
++) {
252 otSocket peerSock
= 0;
256 ortn
= AcceptClientConnection(listenSock
, &peerSock
, &peerId
);
258 printf("...error listening for connection. Aborting.\n");
265 printf("...connecting to host %s at port %d\n", hostName
, port
);
267 ortn
= MakeServerConnection(hostName
, port
, 0, &peerSock
,
270 printf("...error connecting to server %s. Aborting.\n",
276 /* start timing SSL setup */
277 CFAbsoluteTime setupStart
= CFAbsoluteTimeGetCurrent();
280 ortn
= SSLNewContext(isServer
, &ctx
);
282 printSslErrStr("SSLNewContext", ortn
);
285 ortn
= SSLSetIOFuncs(ctx
, SocketRead
, SocketWrite
);
287 printSslErrStr("SSLSetIOFuncs", ortn
);
290 ortn
= SSLSetConnection(ctx
, peerSock
);
292 printSslErrStr("SSLSetConnection", ortn
);
296 ortn
= SSLSetPeerDomainName(ctx
, hostName
, strlen(hostName
) + 1);
298 printSslErrStr("SSLSetPeerDomainName", ortn
);
303 ortn
= SSLSetPeerID(ctx
, &peerId
, sizeof(PeerSpec
));
305 printSslErrStr("SSLSetPeerID", ortn
);
309 if(!certVerifyEnable
) {
311 * Do this before setting up certs to allow for optimization
312 * on server side (setting valid cert without verifying them)
314 ortn
= SSLSetEnableCertVerify(ctx
, false);
316 printSslErrStr("SSLSetPeerID", ortn
);
322 * Server/client specific setup.
324 * Client uses the same keychain as server, but it uses it for
325 * sslAddTrustedRoots() instead of getSslCerts() and
326 * SSLSetCertificate().
328 if(clientAuthEnable
|| isServer
) {
329 if(!certVerifyEnable
) {
330 /* don't bother...this is heavyweight */
331 ortn
= addIdentityAsTrustedRoot(ctx
, myCerts
);
336 ortn
= SSLSetCertificate(ctx
, myCerts
);
338 printSslErrStr("SSLSetCertificate", ortn
);
343 SSLAuthenticate auth
;
344 if(clientAuthEnable
) {
345 auth
= kAlwaysAuthenticate
;
348 auth
= kNeverAuthenticate
;
350 ortn
= SSLSetClientSideAuthenticate(ctx
, auth
);
352 printSslErrStr("SSLSetClientSideAuthenticate", ortn
);
355 ortn
= SSLSetEnabledCiphers(ctx
, &cipherSuite
, 1);
357 printSslErrStr("SSLSetEnabledCiphers", ortn
);
361 /* FIXME why does this fail on Jaguar? */
362 ortn
= SSLSetProtocolVersion(ctx
, prot
);
364 printSslErrStr("SSLSetProtocolVersion", ortn
);
369 if(dhParams
!= NULL
) {
370 ortn
= SSLSetDiffieHellmanParams(ctx
, dhParams
, dhParamsLen
);
372 printSslErrStr("SSLSetDiffieHellmanParams", ortn
);
380 if(!clientAuthEnable
&& setClientAnchor
) {
381 /* We're not presenting a cert; trust the server certs */
384 printf("sslAddTrustedRoots screwup\n");
387 ortn
= sslAddTrustedRoots(ctx
, certKc
, &foundOne
);
389 printSslErrStr("sslAddTrustedRoots", ortn
);
396 * Context setup complete. Start timing handshake.
398 CFAbsoluteTime hshakeStart
= CFAbsoluteTimeGetCurrent();
400 ortn
= SSLHandshake(ctx
);
401 } while (ortn
== errSSLWouldBlock
);
403 printSslErrStr("SSLHandshake", ortn
);
406 CFAbsoluteTime hshakeEnd
= CFAbsoluteTimeGetCurrent();
408 /* snag these before data xfer possibly shuts down connection */
409 SSLProtocol negVersion
;
410 SSLCipherSuite negCipher
;
411 SSLClientCertificateState certState
; // RETURNED
413 SSLGetNegotiatedCipher(ctx
, &negCipher
);
414 SSLGetNegotiatedProtocolVersion(ctx
, &negVersion
);
415 SSLGetClientCertificateState(ctx
, &certState
);
418 * Shut down. Server does the SSLClose while client tries to read. Client gets
419 * a errSSLClosedGraceful then does its SSLCLose.
426 ortn
= SSLWrite(ctx
, GET_MSG
, strlen(GET_MSG
), &actRead
);
428 printSslErrStr("SSLWrite", ortn
);
432 ortn
= SSLRead(ctx
, data
, 2, &actRead
);
434 case errSSLClosedGraceful
:
441 printf("Unexpected rtn on client SSLRead(); bytesRead %u\n",
443 printSslErrStr("SSLRead", ortn
);
450 /* shut down channel */
451 ortn
= SSLClose(ctx
);
453 printSslErrStr("SSLCLose", ortn
);
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
);
468 setupTotal
+= (hshakeStart
- setupStart
);
469 handShakeTotal
+= (hshakeEnd
- hshakeStart
);
473 printf("SSL setup avg %f s\n", setupTotal
/ loops
);
474 printf("SSL handshake avg %f s\n", handShakeTotal
/ loops
);