]> git.saurik.com Git - apple/security.git/blob - sslViewer/sslServe.cpp
Security-58286.200.222.tar.gz
[apple/security.git] / sslViewer / sslServe.cpp
1 /*
2 * Copyright (c) 2006-2008,2010,2013 Apple Inc. All Rights Reserved.
3 *
4 * sslServe.cpp : perform one server side sesssion
5 */
6
7 #include <Security/SecureTransport.h>
8 #include <Security/Security.h>
9 #include <clAppUtils/sslAppUtils.h>
10 #include <clAppUtils/ioSock.h>
11 #include <clAppUtils/sslThreading.h>
12 #include <utilLib/fileIo.h>
13 #include <utilLib/common.h>
14 #include <security_cdsa_utils/cuPrintCert.h>
15
16 #include <Security/SecBase.h>
17
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <time.h>
22 #include <ctype.h>
23 #include <sys/param.h>
24
25 #define BIND_RETRIES 10
26
27 #define SERVER_MESSAGE "HTTP/1.0 200 OK\015\012\015\012" \
28 "<HTML><HEAD><TITLE>SecureTransport Test Server</TITLE></HEAD>" \
29 "<BODY><H2>Secure connection established.</H2>" \
30 "Message from the 'sslServe' test library.\015\012</BODY>" \
31 "</HTML>\015\012"
32
33 #define READBUF_LEN 256
34
35 /* relies on SSLSetProtocolVersionEnabled */
36
37 /*
38 * params->lock is held for us by runSession() - we use it as a semapahore by
39 * unlocking it when we've created a port to listen on.
40 * This is generally run from a thread via sslRunSession() and
41 * sslServerThread() in sslAppUtils.cpp.
42 */
43 OSStatus sslAppServe(
44 SslAppTestParams *params)
45 {
46 otSocket listenSock = 0;
47 otSocket acceptSock = 0;
48 PeerSpec peerId;
49 OSStatus ortn;
50 SSLContextRef ctx = NULL;
51 SecKeychainRef serverKc = nil;
52 CFArrayRef serverCerts = nil;
53
54 sslThrDebug("Server", "starting");
55 params->negVersion = kSSLProtocolUnknown;
56 params->negCipher = SSL_NULL_WITH_NULL_NULL;
57 params->ortn = noHardwareErr;
58
59 /* set up a socket on which to listen */
60 for(unsigned retry=0; retry<BIND_RETRIES; retry++) {
61 ortn = ListenForClients(params->port, params->nonBlocking,
62 &listenSock);
63 switch(ortn) {
64 case errSecSuccess:
65 break;
66 case errSecOpWr:
67 /* port already in use - try another */
68 params->port++;
69 if(params->verbose || THREADING_DEBUG) {
70 printf("...retrying ListenForClients at port %d\n",
71 params->port);
72 }
73 break;
74 default:
75 break;
76 }
77 if(ortn != errSecOpWr) {
78 break;
79 }
80 }
81
82 /* let main thread know a socket is ready */
83 if(pthread_mutex_lock(&params->pthreadMutex)) {
84 printf("***Error acquiring server lock; aborting.\n");
85 return -1;
86 }
87 params->serverReady = true;
88 if(pthread_cond_broadcast(&params->pthreadCond)) {
89 printf("***Error waking main thread; aborting.\n");
90 return -1;
91 }
92 if(pthread_mutex_unlock(&params->pthreadMutex)) {
93 printf("***Error acquiring server lock; aborting.\n");
94 return -1;
95 }
96
97 if(ortn) {
98 printf("ListenForClients returned %d; aborting\n", (int)ortn);
99 return ortn;
100 }
101
102 /* wait for a connection */
103 if(params->verbose) {
104 printf("Waiting for client connection...");
105 fflush(stdout);
106 }
107 ortn = AcceptClientConnection(listenSock, &acceptSock, &peerId);
108 if(ortn) {
109 printf("AcceptClientConnection returned %d; aborting\n", (int)ortn);
110 return ortn;
111 }
112
113 /*
114 * Set up a SecureTransport session.
115 */
116 ortn = SSLNewContext(true, &ctx);
117 if(ortn) {
118 printSslErrStr("SSLNewContext", ortn);
119 goto cleanup;
120 }
121 ortn = SSLSetIOFuncs(ctx, SocketRead, SocketWrite);
122 if(ortn) {
123 printSslErrStr("SSLSetIOFuncs", ortn);
124 goto cleanup;
125 }
126 ortn = SSLSetConnection(ctx, (SSLConnectionRef)acceptSock);
127 if(ortn) {
128 printSslErrStr("SSLSetConnection", ortn);
129 goto cleanup;
130 }
131
132 if(params->anchorFile) {
133 ortn = sslAddTrustedRoot(ctx, params->anchorFile,
134 params->replaceAnchors);
135 if(ortn) {
136 goto cleanup;
137 }
138 }
139 if(params->myCertKcName != NULL) {
140 /* if not, better be trying anonymous diff-hellman... :-) */
141 serverCerts = getSslCerts(params->myCertKcName, false, false, NULL,
142 &serverKc);
143 if(serverCerts == nil) {
144 exit(1);
145 }
146 if(params->password) {
147 ortn = SecKeychainUnlock(serverKc, strlen(params->password),
148 (void *)params->password, true);
149 if(ortn) {
150 printf("SecKeychainUnlock returned %d\n", (int)ortn);
151 /* oh well */
152 }
153 }
154 if(params->idIsTrustedRoot) {
155 /* assume this is a root we want to implicitly trust */
156 ortn = addIdentityAsTrustedRoot(ctx, serverCerts);
157 if(ortn) {
158 goto cleanup;
159 }
160 }
161 ortn = SSLSetCertificate(ctx, serverCerts);
162 if(ortn) {
163 printSslErrStr("SSLSetCertificate", ortn);
164 goto cleanup;
165 }
166 }
167
168 if(params->disableCertVerify) {
169 ortn = SSLSetEnableCertVerify(ctx, false);
170 if(ortn) {
171 printSslErrStr("SSLSetEnableCertVerify", ortn);
172 goto cleanup;
173 }
174 }
175 ortn = sslSetProtocols(ctx, params->acceptedProts, params->tryVersion);
176 if(ortn) {
177 goto cleanup;
178 }
179 if(params->resumeEnable) {
180 ortn = SSLSetPeerID(ctx, &peerId, sizeof(PeerSpec));
181 if(ortn) {
182 printSslErrStr("SSLSetPeerID", ortn);
183 goto cleanup;
184 }
185 }
186 if(params->ciphers != NULL) {
187 ortn = sslSetEnabledCiphers(ctx, params->ciphers);
188 if(ortn) {
189 goto cleanup;
190 }
191 }
192 if(params->authenticate != kNeverAuthenticate) {
193 ortn = SSLSetClientSideAuthenticate(ctx, params->authenticate);
194 if(ortn) {
195 printSslErrStr("SSLSetClientSideAuthenticate", ortn);
196 goto cleanup;
197 }
198 }
199 if(params->dhParams) {
200 #if JAGUAR_BUILD
201 printf("***Diffie-Hellman not supported in this config.\n");
202 #else
203 ortn = SSLSetDiffieHellmanParams(ctx, params->dhParams,
204 params->dhParamsLen);
205 if(ortn) {
206 printSslErrStr("SSLSetDiffieHellmanParams", ortn);
207 goto cleanup;
208 }
209 #endif
210 }
211
212 /* Perform SSL/TLS handshake */
213 do {
214 ortn = SSLHandshake(ctx);
215 if((ortn == errSSLWouldBlock) && !params->silent) {
216 /* keep UI responsive */
217 sslOutputDot();
218 }
219 } while (ortn == errSSLWouldBlock);
220
221 SSLGetClientCertificateState(ctx, &params->certState);
222 SSLGetNegotiatedCipher(ctx, &params->negCipher);
223 SSLGetNegotiatedProtocolVersion(ctx, &params->negVersion);
224
225 if(params->verbose) {
226 printf("\n");
227 }
228 if(ortn) {
229 goto cleanup;
230 }
231
232 /* wait for one complete line */
233 char readBuf[READBUF_LEN];
234 size_t length;
235 while(ortn == errSecSuccess) {
236 length = READBUF_LEN;
237 ortn = SSLRead(ctx, readBuf, length, &length);
238 if (ortn == errSSLWouldBlock) {
239 /* keep trying */
240 ortn = errSecSuccess;
241 continue;
242 }
243 if(length == 0) {
244 /* keep trying */
245 continue;
246 }
247
248 /* poor person's line completion scan */
249 for(unsigned i=0; i<length; i++) {
250 if((readBuf[i] == '\n') || (readBuf[i] == '\r')) {
251 goto serverResp;
252 }
253 }
254 }
255
256 serverResp:
257 /* send out canned response */
258 ortn = SSLWrite(ctx, SERVER_MESSAGE, strlen(SERVER_MESSAGE), &length);
259 if(ortn) {
260 printSslErrStr("SSLWrite", ortn);
261 }
262
263 cleanup:
264 /*
265 * always do close, even on error - to flush outgoing write queue
266 */
267 if(ctx) {
268 OSStatus cerr = SSLClose(ctx);
269 if(ortn == errSecSuccess) {
270 ortn = cerr;
271 }
272 }
273 if(acceptSock) {
274 while(!params->clientDone && !params->serverAbort) {
275 usleep(100);
276 }
277 endpointShutdown(acceptSock);
278 }
279 if(listenSock) {
280 endpointShutdown(listenSock);
281 }
282 if(ctx) {
283 SSLDisposeContext(ctx);
284 }
285 params->ortn = ortn;
286 sslThrDebug("Server", "done");
287 return ortn;
288 }