1/*
2 * sslHandshakeTimeRB - measure SSL handshake timing, RingBuffer version (no
3 *						socket I/O).
4 *
5 * Written by Doug Mitchell.
6 */
7#include <Security/SecureTransport.h>
8#include <clAppUtils/sslAppUtils.h>
9#include <utilLib/common.h>
10#include <clAppUtils/ringBufferIo.h>
11#include <clAppUtils/sslRingBufferThreads.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#define DEFAULT_KC		"localcert"			/* default keychain */
24
25/* we might make these user-tweakable */
26#define DEFAULT_NUM_BUFS	16
27#define DEFAULT_BUF_SIZE	1024		/* in the ring buffers */
28#define LOOPS_DEF			20
29
30static void usage(char **argv)
31{
32    printf("Usage: %s [option ...]\n", argv[0]);
33    printf("Options:\n");
34	printf("   -l loops (default= %d)\n", LOOPS_DEF);
35	printf("   -k keychain (default = %s)\n", DEFAULT_KC);
36	printf("   -c cipher (default = RSA/AES128\n");
37	printf("      ciphers: a=RSA/AES128; r=RSA/RC4; d=RSA/DES; D=RSA/3DES;\n");
38	printf("               h=DHA/RC4; H=DH/DSS/DES; A=AES256\n");
39	printf("   -v version (t|2|3; default = t(TLS1)\n");
40	printf("   -a (enable client authentication)\n");
41    exit(1);
42}
43
44static int doTest(
45	SslRingBufferArgs	*clientArgs,
46	SslRingBufferArgs	*serverArgs,
47	unsigned			loops,
48	CFAbsoluteTime		*totalElapsedClient,	/* RETURNED */
49	CFAbsoluteTime		*totalElapsedServer)	/* RETURNED */
50{
51	CFAbsoluteTime elapsedClient = 0.0;
52	CFAbsoluteTime elapsedServer = 0.0;
53	int result;
54	pthread_t client_thread = NULL;
55	unsigned dex;
56	void *status;
57
58	for(dex=0; dex<loops; dex++) {
59
60		ringBufferReset(clientArgs->ringWrite);
61		ringBufferReset(clientArgs->ringRead);
62		clientArgs->iAmReady = false;
63		serverArgs->iAmReady = false;
64
65		/* fire up client thread */
66		result = pthread_create(&client_thread, NULL,
67				sslRbClientThread, clientArgs);
68		if(result) {
69			printf("***pthread_create returned %d, aborting\n", result);
70			return -1;
71		}
72
73		/*
74		 * And the server pseudo thread. This returns when all data has been transferred.
75		 */
76		OSStatus ortn = sslRbServerThread(serverArgs);
77		if(*serverArgs->abortFlag || ortn) {
78			printf("***Test aborted (1).\n");
79			return -1;
80		}
81
82		/* now wait for client */
83		result = pthread_join(client_thread, &status);
84		if(result || *clientArgs->abortFlag) {
85			printf("***Test aborted (2).\n");
86			return -1;
87		}
88		elapsedClient += (clientArgs->startData - clientArgs->startHandshake);
89		elapsedServer += (serverArgs->startData - serverArgs->startHandshake);
90	}
91	*totalElapsedClient = elapsedClient;
92	*totalElapsedServer = elapsedServer;
93	return 0;
94}
95
96int main(int argc, char **argv)
97{
98	RingBuffer		serverToClientRing;
99	RingBuffer		clientToServerRing;
100	unsigned		numBufs = DEFAULT_NUM_BUFS;
101	unsigned		bufSize = DEFAULT_BUF_SIZE;
102	CFArrayRef		idArray;					/* for SSLSetCertificate */
103	CFArrayRef		anchorArray;				/* trusted roots */
104	SslRingBufferArgs clientArgs;
105	SslRingBufferArgs serverArgs;
106	SecKeychainRef	kcRef = NULL;
107	SecCertificateRef anchorCert = NULL;
108	SecIdentityRef	idRef = NULL;
109	bool			abortFlag = false;
110	bool			diffieHellman = true;		/* FIXME needs work */
111	OSStatus		ortn;
112	CFAbsoluteTime	clientFirst;
113	CFAbsoluteTime	serverFirst;
114	CFAbsoluteTime	clientTotal;
115	CFAbsoluteTime	serverTotal;
116
117	/* user-spec'd variables */
118	char 			*kcName = DEFAULT_KC;
119	SSLCipherSuite 	cipherSuite = TLS_RSA_WITH_AES_128_CBC_SHA;
120	SSLProtocol 	prot = kTLSProtocol1;
121	bool 			clientAuthEnable = false;
122	unsigned		loops = LOOPS_DEF;
123
124	extern int optind;
125	extern char *optarg;
126	int arg;
127	optind = 1;
128	while ((arg = getopt(argc, argv, "l:k:x:c:v:w:aB")) != -1) {
129		switch (arg) {
130			case 'l':
131				loops = atoi(optarg);
132				break;
133			case 'k':
134				kcName = optarg;
135				break;
136			case 'c':
137				switch(optarg[0]) {
138					case 'a':
139						cipherSuite = TLS_RSA_WITH_AES_128_CBC_SHA;
140						break;
141					case 'r':
142						cipherSuite = SSL_RSA_WITH_RC4_128_SHA;
143						break;
144					case 'd':
145						cipherSuite = SSL_RSA_WITH_DES_CBC_SHA;
146						break;
147					case 'D':
148						cipherSuite = SSL_RSA_WITH_3DES_EDE_CBC_SHA;
149						break;
150					case 'h':
151						cipherSuite = SSL_DH_anon_WITH_RC4_128_MD5;
152						diffieHellman = true;
153						break;
154					case 'H':
155						cipherSuite = SSL_DHE_DSS_WITH_DES_CBC_SHA;
156						diffieHellman = true;
157						break;
158					case 'A':
159						cipherSuite = TLS_RSA_WITH_AES_256_CBC_SHA;
160						break;
161					default:
162						usage(argv);
163				}
164				break;
165			case 'v':
166				switch(optarg[0]) {
167					case 't':
168						prot = kTLSProtocol1;
169						break;
170					case '2':
171						prot = kSSLProtocol2;
172						break;
173					case '3':
174						prot = kSSLProtocol3;
175						break;
176					default:
177						usage(argv);
178				}
179				break;
180			case 'a':
181				clientAuthEnable = true;
182				break;
183			default:
184				usage(argv);
185		}
186	}
187	if(optind != argc) {
188		usage(argv);
189	}
190
191	/* set up ring buffers */
192	ringBufSetup(&serverToClientRing, "serveToClient", numBufs, bufSize);
193	ringBufSetup(&clientToServerRing, "clientToServe", numBufs, bufSize);
194
195	/* get server SecIdentity */
196	idArray = getSslCerts(kcName,
197		CSSM_FALSE,		/* encryptOnly */
198		CSSM_FALSE,		/* completeCertChain */
199		NULL,			/* anchorFile */
200		&kcRef);
201	if(idArray == NULL) {
202		printf("***Can't get signing cert from %s\n", kcName);
203		exit(1);
204	}
205	idRef = (SecIdentityRef)CFArrayGetValueAtIndex(idArray, 0);
206	ortn = SecIdentityCopyCertificate(idRef, &anchorCert);
207	if(ortn) {
208		cssmPerror("SecIdentityCopyCertificate", ortn);
209		exit(1);
210	}
211	anchorArray = CFArrayCreate(NULL, (const void **)&anchorCert,
212			1, &kCFTypeArrayCallBacks);
213
214	CFRelease(kcRef);
215
216	/* set up server side */
217	memset(&serverArgs, 0, sizeof(serverArgs));
218	serverArgs.idArray = idArray;
219	serverArgs.trustedRoots = anchorArray;
220	serverArgs.xferSize = 0;
221	serverArgs.xferBuf = NULL;
222	serverArgs.chunkSize = 0;
223	serverArgs.cipherSuite = cipherSuite;
224	serverArgs.prot = prot;
225	serverArgs.ringWrite = &serverToClientRing;
226	serverArgs.ringRead = &clientToServerRing;
227	serverArgs.goFlag = &clientArgs.iAmReady;
228	serverArgs.abortFlag = &abortFlag;
229
230	/* set up client side */
231	memset(&clientArgs, 0, sizeof(clientArgs));
232	clientArgs.idArray = NULL;		/* until we do client auth */
233	clientArgs.trustedRoots = anchorArray;
234	clientArgs.xferSize = 0;
235	clientArgs.xferBuf = NULL;
236	clientArgs.chunkSize = 0;
237	clientArgs.cipherSuite = cipherSuite;
238	clientArgs.prot = prot;
239	clientArgs.ringWrite = &clientToServerRing;
240	clientArgs.ringRead = &serverToClientRing;
241	clientArgs.goFlag = &serverArgs.iAmReady;
242	clientArgs.abortFlag = &abortFlag;
243
244	/* cold start, one loop */
245	if(doTest(&clientArgs, &serverArgs, 1, &clientFirst, &serverFirst)) {
246		exit(1);
247	}
248
249	/* now the real test */
250	if(doTest(&clientArgs, &serverArgs, loops, &clientTotal, &serverTotal)) {
251		exit(1);
252	}
253
254	printf("\n");
255
256	printf("SSL Protocol Version : %s\n",
257		sslGetProtocolVersionString(serverArgs.negotiatedProt));
258	printf("SSL Cipher           : %s\n",
259		sslGetCipherSuiteString(serverArgs.negotiatedCipher));
260
261	printf("Client Handshake 1st : %f ms\n", clientFirst * 1000.0);
262	printf("Server Handshake 1st : %f ms\n", serverFirst * 1000.0);
263	printf("Client Handshake     : %f s in %u loops\n", clientTotal, loops);
264	printf("                       %f ms per handshake\n",
265		(clientTotal * 1000.0) / loops);
266	printf("Server Handshake     : %f s in %u loops\n", serverTotal, loops);
267	printf("                       %f ms per handshake\n",
268		(serverTotal * 1000.0) / loops);
269
270	return 0;
271}
272
273
274
275