1/*
2 * ringBufferThreads.cpp - SecureTransport client and server thread
3 *		routines which use ringBufferIo for I/O (no sockets).
4 *
5 * Customized for EAP-FAST testing; uses SSLInternalSetMasterSecretFunction()
6 * and SSLInternalSetSessionTicket().
7 */
8
9#include "ringBufferThreads.h"
10#include <stdlib.h>
11#include <pthread.h>
12#include <stdio.h>
13#include <strings.h>
14#include <clAppUtils/sslAppUtils.h>
15#include <utilLib/common.h>
16#include <CommonCrypto/CommonDigest.h>
17
18#define LOG_TOP_IO	0
19#if		LOG_TOP_IO
20
21static void logWrite(
22	char *who,
23	size_t written)
24{
25	pthread_mutex_lock(&printfMutex);
26	printf("+++ %s wrote %4lu bytes\n", who, (unsigned long)written);
27	pthread_mutex_unlock(&printfMutex);
28}
29
30static void logRead(
31	char *who,
32	size_t bytesRead)
33{
34	pthread_mutex_lock(&printfMutex);
35	printf("+++ %s  read %4lu bytes\n", who, (unsigned long)bytesRead);
36	pthread_mutex_unlock(&printfMutex);
37}
38
39#else	/* LOG_TOP_IO */
40#define logWrite(who, w)
41#define logRead(who, r)
42#endif	/* LOG_TOP_IO */
43
44/*
45 * Callback from ST to calculate master secret.
46 * We do a poor person's T_PRF(), taking the hash of:
47 *
48 *   serverRandom | clientRandom | sharedSecret
49 *
50 * ...to prove that both sides can come up with a master secret
51 * independently, using both sides' random values and the shared secret
52 * supplied by the app.
53 *
54 * We happen to have a digest that produces the required number
55 * of bytes (48)...
56 */
57static void sslMasterSecretFunction(
58	SSLContextRef ctx,
59	const void *arg,		/* actually a RingBufferArgs */
60	void *secret,			/* mallocd by caller, SSL_MASTER_SECRET_SIZE */
61	size_t *secretLength)	/* in/out */
62{
63	RingBufferArgs *sslArgs = (RingBufferArgs *)arg;
64	if(*secretLength < SSL_MASTER_SECRET_SIZE) {
65		printf("**Hey! insufficient space for master secret!\n");
66		return;
67	}
68
69	unsigned char r[SSL_CLIENT_SRVR_RAND_SIZE];
70	size_t rSize = SSL_CLIENT_SRVR_RAND_SIZE;
71	CC_SHA512_CTX digestCtx;
72	CC_SHA384_Init(&digestCtx);
73	SSLInternalServerRandom(ctx, r, &rSize);
74	CC_SHA384_Update(&digestCtx, r, rSize);
75	SSLInternalClientRandom(ctx, r, &rSize);
76	CC_SHA384_Update(&digestCtx, r, rSize);
77	CC_SHA384_Update(&digestCtx, sslArgs->sharedSecret, SHARED_SECRET_SIZE);
78	CC_SHA384_Final((unsigned char *)secret, &digestCtx);
79	*secretLength = CC_SHA384_DIGEST_LENGTH;
80}
81
82/* client thread - handshake and write some data */
83void *rbClientThread(void *arg)
84{
85	RingBufferArgs		*sslArgs = (RingBufferArgs *)arg;
86    OSStatus            ortn;
87    SSLContextRef       ctx = NULL;
88	RingBuffers			ringBufs = {sslArgs->ringRead, sslArgs->ringWrite};
89	char				sessionID[MAX_SESSION_ID_LENGTH];
90	size_t				sessionIDLen = MAX_SESSION_ID_LENGTH;
91	unsigned			toMove;
92	unsigned			thisMove;
93
94	ortn = SSLNewContext(false, &ctx);
95	if(ortn) {
96		printSslErrStr("SSLNewContext", ortn);
97		goto cleanup;
98	}
99	ortn = SSLSetIOFuncs(ctx, ringReadFunc, ringWriteFunc);
100	if(ortn) {
101		printSslErrStr("SSLSetIOFuncs", ortn);
102		goto cleanup;
103	}
104	ortn = SSLSetConnection(ctx, (SSLConnectionRef)&ringBufs);
105	if(ortn) {
106		printSslErrStr("SSLSetConnection", ortn);
107		goto cleanup;
108	}
109	/* EAP is TLS only - disable the SSLv2-capable handshake */
110	ortn = SSLSetProtocolVersionEnabled(ctx, kSSLProtocol2, false);
111	if(ortn) {
112		printSslErrStr("SSLSetProtocolVersionEnabled", ortn);
113		goto cleanup;
114	}
115	ortn = SSLInternalSetMasterSecretFunction(ctx, sslMasterSecretFunction, sslArgs);
116	if(ortn) {
117		printSslErrStr("SSLInternalSetMasterSecretFunction", ortn);
118		goto cleanup;
119	}
120	ortn = SSLInternalSetSessionTicket(ctx, sslArgs->sessionTicket,
121		sslArgs->sessionTicketLen);
122	if(ortn) {
123		printSslErrStr("SSLInternalSetSessionTicket", ortn);
124		goto cleanup;
125	}
126	if(sslArgs->trustedRoots) {
127		ortn = SSLSetTrustedRoots(ctx, sslArgs->trustedRoots, true);
128		if(ortn) {
129			printSslErrStr("SSLSetTrustedRoots", ortn);
130			goto cleanup;
131		}
132	}
133	if(sslArgs->hostName) {
134		ortn = SSLSetPeerDomainName(ctx, sslArgs->hostName, strlen(sslArgs->hostName));
135		if(ortn) {
136			printSslErrStr("SSLSetPeerDomainName", ortn);
137			goto cleanup;
138		}
139	}
140
141	/* tell main thread we're ready; wait for sync flag */
142	sslArgs->iAmReady = true;
143	while(!(*sslArgs->goFlag)) {
144		if(*sslArgs->abortFlag) {
145			goto cleanup;
146		}
147	}
148
149	/* GO handshake */
150	sslArgs->startHandshake = CFAbsoluteTimeGetCurrent();
151	do {
152		ortn = SSLHandshake(ctx);
153		if(*sslArgs->abortFlag) {
154			goto cleanup;
155		}
156    } while (ortn == errSSLWouldBlock);
157
158	if(ortn) {
159		printSslErrStr("SSLHandshake", ortn);
160		goto cleanup;
161	}
162
163	SSLGetNegotiatedCipher(ctx, &sslArgs->negotiatedCipher);
164	SSLGetNegotiatedProtocolVersion(ctx, &sslArgs->negotiatedProt);
165
166	ortn = SSLGetResumableSessionInfo(ctx, &sslArgs->sessionWasResumed, sessionID, &sessionIDLen);
167	if(ortn) {
168		printSslErrStr("SSLGetResumableSessionInfo", ortn);
169		goto cleanup;
170	}
171
172	sslArgs->startData = CFAbsoluteTimeGetCurrent();
173
174	toMove = sslArgs->xferSize;
175
176	if(toMove == 0) {
177		sslArgs->endData = sslArgs->startData;
178		goto cleanup;
179	}
180
181	/* GO data xfer */
182	do {
183		thisMove = sslArgs->chunkSize;
184		if(thisMove > toMove) {
185			thisMove = toMove;
186		}
187		size_t moved;
188		ortn = SSLWrite(ctx, sslArgs->xferBuf, thisMove, &moved);
189		/* should never fail - implemented as blocking */
190		if(ortn) {
191			printSslErrStr("SSLWrite", ortn);
192			goto cleanup;
193		}
194		logWrite("client", moved);
195		toMove -= moved;
196		if(*sslArgs->abortFlag) {
197			goto cleanup;
198		}
199	} while(toMove);
200
201	sslArgs->endData = CFAbsoluteTimeGetCurrent();
202
203cleanup:
204	if(ortn) {
205		*sslArgs->abortFlag = true;
206	}
207	if(*sslArgs->abortFlag && sslArgs->pauseOnError) {
208		/* abort for any reason - freeze! */
209		testError(CSSM_FALSE);
210	}
211	if(ctx) {
212		SSLClose(ctx);
213		SSLDisposeContext(ctx);
214	}
215	if(ortn) {
216		printf("***Client thread returning %lu\n", (unsigned long)ortn);
217	}
218	pthread_exit((void*)ortn);
219	/* NOT REACHED */
220	return (void *)ortn;
221
222}
223
224/* server function - like clientThread except it runs from the main thread */
225/* handshake and read some data */
226OSStatus rbServerThread(RingBufferArgs *sslArgs)
227{
228    OSStatus            ortn;
229    SSLContextRef       ctx = NULL;
230	RingBuffers			ringBufs = {sslArgs->ringRead, sslArgs->ringWrite};
231	char				sessionID[MAX_SESSION_ID_LENGTH];
232	size_t				sessionIDLen = MAX_SESSION_ID_LENGTH;
233	unsigned			toMove;
234	unsigned			thisMove;
235
236	ortn = SSLNewContext(true, &ctx);
237	if(ortn) {
238		printSslErrStr("SSLNewContext", ortn);
239		goto cleanup;
240	}
241	ortn = SSLSetIOFuncs(ctx, ringReadFunc, ringWriteFunc);
242	if(ortn) {
243		printSslErrStr("SSLSetIOFuncs", ortn);
244		goto cleanup;
245	}
246	ortn = SSLSetConnection(ctx, (SSLConnectionRef)&ringBufs);
247	if(ortn) {
248		printSslErrStr("SSLSetConnection", ortn);
249		goto cleanup;
250	}
251	if(sslArgs->setMasterSecret) {
252		ortn = SSLInternalSetMasterSecretFunction(ctx, sslMasterSecretFunction, sslArgs);
253		if(ortn) {
254			printSslErrStr("SSLInternalSetMasterSecretFunction", ortn);
255			goto cleanup;
256		}
257	}
258	if(sslArgs->idArray) {
259		ortn = SSLSetCertificate(ctx, sslArgs->idArray);
260		if(ortn) {
261			printSslErrStr("SSLSetCertificate", ortn);
262			goto cleanup;
263		}
264	}
265	if(sslArgs->trustedRoots) {
266		ortn = SSLSetTrustedRoots(ctx, sslArgs->trustedRoots, true);
267		if(ortn) {
268			printSslErrStr("SSLSetTrustedRoots", ortn);
269			goto cleanup;
270		}
271	}
272
273	/* tell client thread we're ready; wait for sync flag */
274	sslArgs->iAmReady = true;
275	while(!(*sslArgs->goFlag)) {
276		if(*sslArgs->abortFlag) {
277			goto cleanup;
278		}
279	}
280
281	/* GO handshake */
282	sslArgs->startHandshake = CFAbsoluteTimeGetCurrent();
283	do {
284		ortn = SSLHandshake(ctx);
285		if(*sslArgs->abortFlag) {
286			goto cleanup;
287		}
288    } while (ortn == errSSLWouldBlock);
289
290	if(ortn) {
291		printSslErrStr("SSLHandshake", ortn);
292		goto cleanup;
293	}
294
295	SSLGetNegotiatedCipher(ctx, &sslArgs->negotiatedCipher);
296	SSLGetNegotiatedProtocolVersion(ctx, &sslArgs->negotiatedProt);
297	ortn = SSLGetResumableSessionInfo(ctx, &sslArgs->sessionWasResumed, sessionID, &sessionIDLen);
298	if(ortn) {
299		printSslErrStr("SSLGetResumableSessionInfo", ortn);
300		goto cleanup;
301	}
302
303	sslArgs->startData = CFAbsoluteTimeGetCurrent();
304
305	toMove = sslArgs->xferSize;
306
307	if(toMove == 0) {
308		sslArgs->endData = sslArgs->startData;
309		goto cleanup;
310	}
311
312	/* GO data xfer */
313	do {
314		thisMove = sslArgs->xferSize;
315		if(thisMove > toMove) {
316			thisMove = toMove;
317		}
318		size_t moved;
319		ortn = SSLRead(ctx, sslArgs->xferBuf, thisMove, &moved);
320		switch(ortn) {
321			case noErr:
322				break;
323			case errSSLWouldBlock:
324				/* cool, try again */
325				ortn = noErr;
326				break;
327			default:
328				break;
329		}
330		if(ortn) {
331			printSslErrStr("SSLRead", ortn);
332			goto cleanup;
333		}
334		logRead("server", moved);
335		toMove -= moved;
336		if(*sslArgs->abortFlag) {
337			goto cleanup;
338		}
339	} while(toMove);
340
341	sslArgs->endData = CFAbsoluteTimeGetCurrent();
342
343cleanup:
344	if(ortn) {
345		*sslArgs->abortFlag = true;
346	}
347	if(*sslArgs->abortFlag && sslArgs->pauseOnError) {
348		/* abort for any reason - freeze! */
349		testError(CSSM_FALSE);
350	}
351	if(ctx) {
352		SSLClose(ctx);
353		SSLDisposeContext(ctx);
354	}
355	if(ortn) {
356		printf("***Server thread returning %lu\n", (unsigned long)ortn);
357	}
358	return ortn;
359}
360