]> git.saurik.com Git - apple/security.git/blob - SecurityTests/clxutils/clAppUtils/sslServe.cpp
Security-57031.1.35.tar.gz
[apple/security.git] / SecurityTests / clxutils / clAppUtils / sslServe.cpp
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 */
48 OSStatus 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
347 serverResp:
348 /* send out canned response */
349 ortn = SSLWrite(ctx, SERVER_MESSAGE, strlen(SERVER_MESSAGE), &length);
350 if(ortn) {
351 printSslErrStr("SSLWrite", ortn);
352 }
353
354 cleanup:
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 }