1/*
2 * sslServe.cpp : perform one server side sesssion
3 */
4#include <Security/SecureTransport.h>
5#include <Security/Security.h>
6#include <clAppUtils/sslAppUtils.h>
7#include <clAppUtils/ioSock.h>
8#include <clAppUtils/sslThreading.h>
9#include <clAppUtils/ringBufferIo.h>
10#include <security_cdsa_utils/cuFileIo.h>
11#include <utilLib/common.h>
12#include <security_cdsa_utils/cuPrintCert.h>
13
14#include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
15#include <stdio.h>
16#include <stdlib.h>
17#include <string.h>
18#include <time.h>
19#include <ctype.h>
20#include <sys/param.h>
21
22#define BIND_RETRIES	50
23
24#define SERVER_MESSAGE  "HTTP/1.0 200 OK\015\012\015\012" \
25	"<HTML><HEAD><TITLE>SecureTransport Test Server</TITLE></HEAD>" \
26	"<BODY><H2>Secure connection established.</H2>" \
27	"Message from the 'sslServe' test library.\015\012</BODY>" \
28	"</HTML>\015\012"
29
30#define READBUF_LEN		256
31
32/*
33 * When true, delay setting the serverReady semaphore until we've finished
34 * setting up our SSLContext. This is a workaround for known thread-unsafety
35 * related to module attach and detach and context create/destroy:
36 *
37 *   <rdar://problem/6618834> Crash in KCCursorImpl::next
38 *   <rdar://problem/6621552> module/context handles not thread safe
39 */
40#define SERVER_READY_DELAY      1
41
42/*
43 * params->lock is held for us by runSession() - we use it as a semapahore by
44 * unlocking it when we've created a port to listen on.
45 * This is generally run from a thread via sslRunSession() and
46 * sslServerThread() in sslAppUtils.cpp.
47 */
48OSStatus sslAppServe(
49	SslAppTestParams	*params)
50{
51	otSocket			listenSock = 0;
52	otSocket			acceptSock = 0;
53    PeerSpec            peerId;
54    OSStatus            ortn = noErr;
55    SSLContextRef       ctx = NULL;
56	SecKeychainRef		serverKc = nil;
57	CFArrayRef			serverCerts = nil;
58	RingBuffers			ringBufs = {params->clientToServerRing, params->serverToClientRing};
59
60	sslThrDebug("Server", "starting");
61    params->negVersion = kSSLProtocolUnknown;
62    params->negCipher = SSL_NULL_WITH_NULL_NULL;
63	params->ortn = noHardwareErr;
64
65	if(params->serverToClientRing == NULL) {
66		/* set up a socket on which to listen */
67		for(unsigned retry=0; retry<BIND_RETRIES; retry++) {
68			ortn = ListenForClients(params->port, params->nonBlocking,
69				&listenSock);
70			switch(ortn) {
71				case noErr:
72					break;
73				case opWrErr:
74					/* port already in use - try another */
75					params->port++;
76					if(params->verbose || THREADING_DEBUG) {
77						printf("...retrying ListenForClients at port %d\n",
78							params->port);
79					}
80					break;
81				default:
82					break;
83			}
84			if(ortn != opWrErr) {
85				break;
86			}
87		}
88	}
89
90    #if     !SERVER_READY_DELAY
91	/* let main thread know a socket is ready */
92	if(pthread_mutex_lock(&params->pthreadMutex)) {
93		printf("***Error acquiring server lock; aborting.\n");
94		return -1;
95	}
96	params->serverReady = true;
97	if(pthread_cond_broadcast(&params->pthreadCond)) {
98		printf("***Error waking main thread; aborting.\n");
99		return -1;
100	}
101	if(pthread_mutex_unlock(&params->pthreadMutex)) {
102		printf("***Error acquiring server lock; aborting.\n");
103		return -1;
104	}
105
106	if(ortn) {
107		printf("ListenForClients returned %d; aborting\n", (int)ortn);
108		return ortn;
109	}
110
111	if(params->serverToClientRing == NULL) {
112		/* wait for a connection */
113		if(params->verbose) {
114			printf("Waiting for client connection...");
115			fflush(stdout);
116		}
117		ortn = AcceptClientConnection(listenSock, &acceptSock, &peerId);
118		if(ortn) {
119			printf("AcceptClientConnection returned %d; aborting\n", (int)ortn);
120			return ortn;
121		}
122	}
123    #endif  /* SERVER_READY_DELAY */
124
125	/*
126	 * Set up a SecureTransport session.
127	 */
128	ortn = SSLNewContext(true, &ctx);
129	if(ortn) {
130		printSslErrStr("SSLNewContext", ortn);
131		goto cleanup;
132	}
133
134    #if     !SERVER_READY_DELAY
135	if(params->serverToClientRing) {
136		/* RingBuffer I/O */
137		ortn = SSLSetIOFuncs(ctx, ringReadFunc, ringWriteFunc);
138		if(ortn) {
139			printSslErrStr("SSLSetIOFuncs", ortn);
140			goto cleanup;
141		}
142		ortn = SSLSetConnection(ctx, (SSLConnectionRef)&ringBufs);
143		if(ortn) {
144			printSslErrStr("SSLSetConnection", ortn);
145			goto cleanup;
146		}
147	}
148	else {
149		/* normal socket I/O */
150		ortn = SSLSetIOFuncs(ctx, SocketRead, SocketWrite);
151		if(ortn) {
152			printSslErrStr("SSLSetIOFuncs", ortn);
153			goto cleanup;
154		}
155		ortn = SSLSetConnection(ctx, (SSLConnectionRef)acceptSock);
156		if(ortn) {
157			printSslErrStr("SSLSetConnection", ortn);
158			goto cleanup;
159		}
160	}
161    #endif  /* SERVER_READY_DELAY */
162
163	if(params->anchorFile) {
164		ortn = sslAddTrustedRoot(ctx, params->anchorFile,
165			params->replaceAnchors);
166		if(ortn) {
167			goto cleanup;
168		}
169	}
170	if(params->myCertKcName != NULL) {
171		/* if not, better be trying anonymous diff-hellman... :-) */
172		serverCerts = getSslCerts(params->myCertKcName, CSSM_FALSE, CSSM_FALSE, NULL,
173			&serverKc);
174		if(serverCerts == nil) {
175			exit(1);
176		}
177		if(params->password) {
178			ortn = SecKeychainUnlock(serverKc, strlen(params->password),
179					(void *)params->password, true);
180			if(ortn) {
181				printf("SecKeychainUnlock returned %d\n", (int)ortn);
182				/* oh well */
183			}
184		}
185		if(params->idIsTrustedRoot) {
186			/* assume this is a root we want to implicitly trust */
187			ortn = addIdentityAsTrustedRoot(ctx, serverCerts);
188			if(ortn) {
189				goto cleanup;
190			}
191		}
192		ortn = SSLSetCertificate(ctx, serverCerts);
193		if(ortn) {
194			printSslErrStr("SSLSetCertificate", ortn);
195			goto cleanup;
196		}
197	}
198
199	if(params->disableCertVerify) {
200		ortn = SSLSetEnableCertVerify(ctx, false);
201		if(ortn) {
202			printSslErrStr("SSLSetEnableCertVerify", ortn);
203			goto cleanup;
204		}
205	}
206	if(!params->noProtSpec) {
207		ortn = sslSetProtocols(ctx, params->acceptedProts, params->tryVersion);
208		if(ortn) {
209			goto cleanup;
210		}
211	}
212	if(params->resumeEnable) {
213		ortn = SSLSetPeerID(ctx, &peerId, sizeof(PeerSpec));
214		if(ortn) {
215			printSslErrStr("SSLSetPeerID", ortn);
216			goto cleanup;
217		}
218	}
219	if(params->ciphers != NULL) {
220		ortn = sslSetEnabledCiphers(ctx, params->ciphers);
221		if(ortn) {
222			goto cleanup;
223		}
224	}
225	if(params->authenticate != kNeverAuthenticate) {
226		ortn = SSLSetClientSideAuthenticate(ctx, params->authenticate);
227		if(ortn) {
228			printSslErrStr("SSLSetClientSideAuthenticate", ortn);
229			goto cleanup;
230		}
231	}
232	if(params->dhParams) {
233		ortn = SSLSetDiffieHellmanParams(ctx, params->dhParams,
234			params->dhParamsLen);
235		if(ortn) {
236			printSslErrStr("SSLSetDiffieHellmanParams", ortn);
237			goto cleanup;
238		}
239	}
240
241    #if     SERVER_READY_DELAY
242	/* let main thread know server is fully functional */
243	if(pthread_mutex_lock(&params->pthreadMutex)) {
244		printf("***Error acquiring server lock; aborting.\n");
245		ortn = internalComponentErr;
246        goto cleanup;
247	}
248	params->serverReady = true;
249	if(pthread_cond_broadcast(&params->pthreadCond)) {
250		printf("***Error waking main thread; aborting.\n");
251		ortn = internalComponentErr;
252        goto cleanup;
253	}
254	if(pthread_mutex_unlock(&params->pthreadMutex)) {
255		printf("***Error acquiring server lock; aborting.\n");
256		ortn = internalComponentErr;
257        goto cleanup;
258	}
259
260	if(params->serverToClientRing == NULL) {
261		/* wait for a connection */
262		if(params->verbose) {
263			printf("Waiting for client connection...");
264			fflush(stdout);
265		}
266		ortn = AcceptClientConnection(listenSock, &acceptSock, &peerId);
267		if(ortn) {
268			printf("AcceptClientConnection returned %d; aborting\n", (int)ortn);
269			return ortn;
270		}
271	}
272
273    /* Last part of SSLContext setup, now that we're connected to the client */
274	if(params->serverToClientRing) {
275		/* RingBuffer I/O */
276		ortn = SSLSetIOFuncs(ctx, ringReadFunc, ringWriteFunc);
277		if(ortn) {
278			printSslErrStr("SSLSetIOFuncs", ortn);
279			goto cleanup;
280		}
281		ortn = SSLSetConnection(ctx, (SSLConnectionRef)&ringBufs);
282		if(ortn) {
283			printSslErrStr("SSLSetConnection", ortn);
284			goto cleanup;
285		}
286	}
287	else {
288		/* normal socket I/O */
289		ortn = SSLSetIOFuncs(ctx, SocketRead, SocketWrite);
290		if(ortn) {
291			printSslErrStr("SSLSetIOFuncs", ortn);
292			goto cleanup;
293		}
294		ortn = SSLSetConnection(ctx, (SSLConnectionRef)acceptSock);
295		if(ortn) {
296			printSslErrStr("SSLSetConnection", ortn);
297			goto cleanup;
298		}
299	}
300
301    #endif  /* SERVER_READY_DELAY */
302
303	/* Perform SSL/TLS handshake */
304    do {
305		ortn = SSLHandshake(ctx);
306	    if((ortn == errSSLWouldBlock) && !params->silent) {
307	    	/* keep UI responsive */
308	    	sslOutputDot();
309	    }
310    } while (ortn == errSSLWouldBlock);
311
312	SSLGetClientCertificateState(ctx, &params->certState);
313	SSLGetNegotiatedCipher(ctx, &params->negCipher);
314	SSLGetNegotiatedProtocolVersion(ctx, &params->negVersion);
315
316	if(params->verbose) {
317		printf("\n");
318	}
319	if(ortn) {
320		goto cleanup;
321	}
322
323	/* wait for one complete line */
324	char readBuf[READBUF_LEN];
325	size_t length;
326	while(ortn == noErr) {
327	    length = READBUF_LEN;
328	    ortn = SSLRead(ctx, readBuf, length, &length);
329	    if (ortn == errSSLWouldBlock) {
330			/* keep trying */
331	        ortn = noErr;
332			continue;
333	    }
334	    if(length == 0) {
335			/* keep trying */
336			continue;
337	    }
338
339	    /* poor person's line completion scan */
340	    for(unsigned i=0; i<length; i++) {
341	    	if((readBuf[i] == '\n') || (readBuf[i] == '\r')) {
342	    		goto serverResp;
343	    	}
344	    }
345	}
346
347serverResp:
348	/* send out canned response */
349	ortn = SSLWrite(ctx, SERVER_MESSAGE, strlen(SERVER_MESSAGE), &length);
350	if(ortn) {
351		printSslErrStr("SSLWrite", ortn);
352	}
353
354cleanup:
355	/*
356	 * always do close, even on error - to flush outgoing write queue
357	 */
358	if(ctx) {
359		OSStatus cerr = SSLClose(ctx);
360		if(ortn == noErr) {
361			ortn = cerr;
362		}
363	}
364	while(!params->clientDone && !params->serverAbort && (ortn == params->expectRtn)) {
365		usleep(100);
366	}
367	if(acceptSock) {
368		endpointShutdown(acceptSock);
369	}
370	ringBuffersClose(&ringBufs);	/* tolerates NULLs */
371	if(listenSock) {
372		endpointShutdown(listenSock);
373	}
374	if(ctx) {
375	    SSLDisposeContext(ctx);
376	}
377	params->ortn = ortn;
378	sslThrDebug("Server", "done");
379	return ortn;
380}
381