2 * Measure performance of SecureTransport - setup and sustained data
5 * Written by Doug Mitchell.
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>
13 #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
19 #include <sys/param.h>
20 #include <CoreFoundation/CoreFoundation.h>
21 #include <security_utilities/devrandom.h>
23 /* default - run both server and client on this machine, port 1200 */
24 #define HOST_DEF "localhost"
27 /* default keychain */
28 #define DEFAULT_KC "localcert"
30 #define XFERSIZE_DEF (1024 * 1024)
33 #define DH_PARAM_FILE "dhParams_1024.der"
35 static void usage(char **argv
)
37 printf("Usage: %s s[erver]|c[lient] [option ...]\n", argv
[0]);
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");
55 int main(int argc
, char **argv
)
57 /* user-spec'd variables */
58 const char *kcName
= DEFAULT_KC
;
59 unsigned xferSize
= XFERSIZE_DEF
;
61 const char *hostName
= HOST_DEF
;
62 SSLCipherSuite cipherSuite
= TLS_RSA_WITH_AES_128_CBC_SHA
;
63 SSLProtocol prot
= kTLSProtocol1Only
;
65 bool clientAuthEnable
= false;
66 bool isServer
= false;
67 unsigned bufSize
= BUFSIZE
;
68 bool diffieHellman
= false;
90 while ((arg
= getopt(argc
, argv
, "h:p:k:x:c:v:w:b:aB")) != -1) {
102 xferSize
= atoi(optarg
);
106 printf("***Specify cipherSuite on server side.\n");
111 cipherSuite
= SSL_RSA_WITH_RC4_128_SHA
;
114 cipherSuite
= SSL_RSA_WITH_DES_CBC_SHA
;
117 cipherSuite
= SSL_RSA_WITH_3DES_EDE_CBC_SHA
;
120 cipherSuite
= SSL_DH_anon_WITH_RC4_128_MD5
;
121 diffieHellman
= true;
124 cipherSuite
= SSL_DHE_DSS_WITH_DES_CBC_SHA
;
125 diffieHellman
= true;
128 cipherSuite
= TLS_RSA_WITH_AES_256_CBC_SHA
;
136 printf("***Specify protocol on server side.\n");
141 prot
= kTLSProtocol1Only
;
144 prot
= kSSLProtocol2
;
147 prot
= kSSLProtocol3Only
;
154 strcpy(password
, optarg
);
157 bufSize
= atoi(optarg
);
160 clientAuthEnable
= true;
170 /* per-transfer buffer - make it random for server */
171 char *buf
= (char *)malloc(bufSize
);
173 Security::DevRandomGenerator rng
;
174 rng
.random(buf
, bufSize
);
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");
188 * Open keychain; both sides use the same one.
191 SecKeychainRef certKc
= NULL
;
192 CFAbsoluteTime kcOpenStart
= CFAbsoluteTimeGetCurrent();
193 ortn
= SecKeychainOpen(kcName
, &certKc
);
195 printf("Error opening keychain %s (%d); aborting.\n",
200 ortn
= SecKeychainUnlock(certKc
, strlen(password
), password
, true);
202 printf("SecKeychainUnlock returned %d\n", (int)ortn
);
206 CFAbsoluteTime kcOpenEnd
= CFAbsoluteTimeGetCurrent();
208 otSocket peerSock
= 0;
209 otSocket listenSock
= 0; // for server only
213 printf("...listening for client connection on port %d\n", port
);
214 ortn
= ListenForClients(port
, nonBlocking
, &listenSock
);
216 printf("...error establishing a listen socket. Aborting.\n");
219 ortn
= AcceptClientConnection(listenSock
, &peerSock
, &peerId
);
221 printf("...error listening for connection. Aborting.\n");
226 printf("...connecting to host %s at port %d\n", hostName
, port
);
227 ortn
= MakeServerConnection(hostName
, port
, nonBlocking
, &peerSock
,
230 printf("...error connecting to server %s. Aborting.\n",
236 /* start timing SSL setup */
237 CFAbsoluteTime setupStart
= CFAbsoluteTimeGetCurrent();
240 ortn
= SSLNewContext(isServer
, &ctx
);
242 printSslErrStr("SSLNewContext", ortn
);
245 ortn
= SSLSetIOFuncs(ctx
, SocketRead
, SocketWrite
);
247 printSslErrStr("SSLSetIOFuncs", ortn
);
250 ortn
= SSLSetConnection(ctx
, (SSLConnectionRef
)peerSock
);
252 printSslErrStr("SSLSetConnection", ortn
);
255 ortn
= SSLSetPeerDomainName(ctx
, hostName
, strlen(hostName
) + 1);
257 printSslErrStr("SSLSetPeerDomainName", ortn
);
262 * Server/client specific setup.
264 * Client uses the same keychain as server, but it uses it for
265 * sslAddTrustedRoots() instead of getSslCerts() and
266 * SSLSetCertificate().
268 CFArrayRef myCerts
= NULL
;
269 if(clientAuthEnable
|| isServer
) {
270 myCerts
= sslKcRefToCertArray(certKc
, CSSM_FALSE
, CSSM_FALSE
, NULL
, NULL
);
271 if(myCerts
== NULL
) {
274 ortn
= addIdentityAsTrustedRoot(ctx
, myCerts
);
278 ortn
= SSLSetCertificate(ctx
, myCerts
);
280 printSslErrStr("SSLSetCertificate", ortn
);
285 SSLAuthenticate auth
;
286 if(clientAuthEnable
) {
287 auth
= kAlwaysAuthenticate
;
290 auth
= kNeverAuthenticate
;
292 ortn
= SSLSetClientSideAuthenticate(ctx
, auth
);
294 printSslErrStr("SSLSetClientSideAuthenticate", ortn
);
297 ortn
= SSLSetEnabledCiphers(ctx
, &cipherSuite
, 1);
299 printSslErrStr("SSLSetEnabledCiphers", ortn
);
302 ortn
= SSLSetProtocolVersion(ctx
, prot
);
304 printSslErrStr("SSLSetProtocolVersion", ortn
);
307 if(dhParams
!= NULL
) {
308 ortn
= SSLSetDiffieHellmanParams(ctx
, dhParams
, dhParamsLen
);
310 printSslErrStr("SSLSetDiffieHellmanParams", ortn
);
317 if(!clientAuthEnable
) {
318 /* We're not presenting a cert; trust the server certs */
320 ortn
= sslAddTrustedRoots(ctx
, certKc
, &foundOne
);
322 printSslErrStr("sslAddTrustedRoots", ortn
);
329 * Context setup complete. Start timing handshake.
331 CFAbsoluteTime hshakeStart
= CFAbsoluteTimeGetCurrent();
333 ortn
= SSLHandshake(ctx
);
334 } while (ortn
== errSSLWouldBlock
);
336 printSslErrStr("SSLHandshake", ortn
);
339 CFAbsoluteTime hshakeEnd
= CFAbsoluteTimeGetCurrent();
341 /* snag these before data xfer possibly shuts down connection */
342 SSLProtocol negVersion
;
343 SSLCipherSuite negCipher
;
344 SSLClientCertificateState certState
; // RETURNED
346 SSLGetNegotiatedCipher(ctx
, &negCipher
);
347 SSLGetNegotiatedProtocolVersion(ctx
, &negVersion
);
348 SSLGetClientCertificateState(ctx
, &certState
);
350 /* server sends xferSize bytes to client and shuts down */
353 CFAbsoluteTime dataStart
= CFAbsoluteTimeGetCurrent();
354 size_t totalMoved
= 0;
356 size_t bytesToGo
= xferSize
;
359 size_t thisMove
= bufSize
;
360 if(thisMove
> bytesToGo
) {
361 thisMove
= bytesToGo
;
363 ortn
= SSLWrite(ctx
, buf
, thisMove
, &bytesMoved
);
366 case errSSLWouldBlock
:
372 bytesToGo
-= bytesMoved
;
373 totalMoved
+= bytesMoved
;
379 printSslErrStr("SSLWrite", ortn
);
384 /* client reads until error or errSSLClosedGraceful */
387 ortn
= SSLRead(ctx
, buf
, bufSize
, &bytesMoved
);
389 case errSSLClosedGraceful
:
393 case errSSLWouldBlock
:
399 totalMoved
+= bytesMoved
;
401 if(ortn
!= errSSLClosedGraceful
) {
402 printSslErrStr("SSLRead", ortn
);
407 /* shut down channel */
408 ortn
= SSLClose(ctx
);
410 printSslErrStr("SSLCLose", ortn
);
413 CFAbsoluteTime dataEnd
= CFAbsoluteTimeGetCurrent();
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
));
424 printf("keychain open/unlock : ");
427 printf("keychain open : ");
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);