/ sslViewer / sslServe.cpp
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  }