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(¶ms->pthreadMutex)) { 84 printf("***Error acquiring server lock; aborting.\n"); 85 return -1; 86 } 87 params->serverReady = true; 88 if(pthread_cond_broadcast(¶ms->pthreadCond)) { 89 printf("***Error waking main thread; aborting.\n"); 90 return -1; 91 } 92 if(pthread_mutex_unlock(¶ms->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, ¶ms->certState); 222 SSLGetNegotiatedCipher(ctx, ¶ms->negCipher); 223 SSLGetNegotiatedProtocolVersion(ctx, ¶ms->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 }