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(¶ms->pthreadMutex)) { 93 printf("***Error acquiring server lock; aborting.\n"); 94 return -1; 95 } 96 params->serverReady = true; 97 if(pthread_cond_broadcast(¶ms->pthreadCond)) { 98 printf("***Error waking main thread; aborting.\n"); 99 return -1; 100 } 101 if(pthread_mutex_unlock(¶ms->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(¶ms->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(¶ms->pthreadCond)) { 250 printf("***Error waking main thread; aborting.\n"); 251 ortn = internalComponentErr; 252 goto cleanup; 253 } 254 if(pthread_mutex_unlock(¶ms->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, ¶ms->certState); 313 SSLGetNegotiatedCipher(ctx, ¶ms->negCipher); 314 SSLGetNegotiatedProtocolVersion(ctx, ¶ms->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