]> git.saurik.com Git - apple/security.git/blobdiff - SecurityTests/clxutils/clAppUtils/sslServe.cpp
Security-57031.1.35.tar.gz
[apple/security.git] / SecurityTests / clxutils / clAppUtils / sslServe.cpp
diff --git a/SecurityTests/clxutils/clAppUtils/sslServe.cpp b/SecurityTests/clxutils/clAppUtils/sslServe.cpp
new file mode 100644 (file)
index 0000000..c529238
--- /dev/null
@@ -0,0 +1,380 @@
+/*
+ * sslServe.cpp : perform one server side sesssion 
+ */
+#include <Security/SecureTransport.h>
+#include <Security/Security.h>
+#include <clAppUtils/sslAppUtils.h>
+#include <clAppUtils/ioSock.h>
+#include <clAppUtils/sslThreading.h>
+#include <clAppUtils/ringBufferIo.h>
+#include <security_cdsa_utils/cuFileIo.h>
+#include <utilLib/common.h>
+#include <security_cdsa_utils/cuPrintCert.h>
+
+#include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <ctype.h>
+#include <sys/param.h>
+
+#define BIND_RETRIES   50
+
+#define SERVER_MESSAGE  "HTTP/1.0 200 OK\015\012\015\012" \
+       "<HTML><HEAD><TITLE>SecureTransport Test Server</TITLE></HEAD>" \
+       "<BODY><H2>Secure connection established.</H2>" \
+       "Message from the 'sslServe' test library.\015\012</BODY>" \
+       "</HTML>\015\012"
+
+#define READBUF_LEN            256
+
+/*
+ * When true, delay setting the serverReady semaphore until we've finished
+ * setting up our SSLContext. This is a workaround for known thread-unsafety
+ * related to module attach and detach and context create/destroy:
+ *
+ *   <rdar://problem/6618834> Crash in KCCursorImpl::next
+ *   <rdar://problem/6621552> module/context handles not thread safe
+ */
+#define SERVER_READY_DELAY      1
+
+/*
+ * params->lock is held for us by runSession() - we use it as a semapahore by
+ * unlocking it when we've created a port to listen on. 
+ * This is generally run from a thread via sslRunSession() and 
+ * sslServerThread() in sslAppUtils.cpp. 
+ */
+OSStatus sslAppServe(
+       SslAppTestParams        *params)
+{
+       otSocket                        listenSock = 0;
+       otSocket                        acceptSock = 0;
+    PeerSpec            peerId;
+    OSStatus            ortn = noErr;
+    SSLContextRef       ctx = NULL;
+       SecKeychainRef          serverKc = nil;
+       CFArrayRef                      serverCerts = nil;
+       RingBuffers                     ringBufs = {params->clientToServerRing, params->serverToClientRing};
+       
+       sslThrDebug("Server", "starting");
+    params->negVersion = kSSLProtocolUnknown;
+    params->negCipher = SSL_NULL_WITH_NULL_NULL;
+       params->ortn = noHardwareErr;
+    
+       if(params->serverToClientRing == NULL) {
+               /* set up a socket on which to listen */
+               for(unsigned retry=0; retry<BIND_RETRIES; retry++) {
+                       ortn = ListenForClients(params->port, params->nonBlocking,
+                               &listenSock);
+                       switch(ortn) {
+                               case noErr:
+                                       break;
+                               case opWrErr:
+                                       /* port already in use - try another */
+                                       params->port++;
+                                       if(params->verbose || THREADING_DEBUG) {
+                                               printf("...retrying ListenForClients at port %d\n",
+                                                       params->port);
+                                       }
+                                       break;
+                               default:
+                                       break;
+                       }
+                       if(ortn != opWrErr) {
+                               break;
+                       }
+               }
+       }
+
+    #if     !SERVER_READY_DELAY
+       /* let main thread know a socket is ready */
+       if(pthread_mutex_lock(&params->pthreadMutex)) {
+               printf("***Error acquiring server lock; aborting.\n");
+               return -1;
+       }
+       params->serverReady = true;
+       if(pthread_cond_broadcast(&params->pthreadCond)) {
+               printf("***Error waking main thread; aborting.\n");
+               return -1;
+       }
+       if(pthread_mutex_unlock(&params->pthreadMutex)) {
+               printf("***Error acquiring server lock; aborting.\n");
+               return -1;
+       }
+    
+       if(ortn) {
+               printf("ListenForClients returned %d; aborting\n", (int)ortn);
+               return ortn;
+       }
+
+       if(params->serverToClientRing == NULL) {
+               /* wait for a connection */
+               if(params->verbose) {
+                       printf("Waiting for client connection...");
+                       fflush(stdout);
+               }
+               ortn = AcceptClientConnection(listenSock, &acceptSock, &peerId);
+               if(ortn) {
+                       printf("AcceptClientConnection returned %d; aborting\n", (int)ortn);
+                       return ortn;
+               }
+       }
+    #endif  /* SERVER_READY_DELAY */
+
+       /* 
+        * Set up a SecureTransport session.
+        */
+       ortn = SSLNewContext(true, &ctx);
+       if(ortn) {
+               printSslErrStr("SSLNewContext", ortn);
+               goto cleanup;
+       } 
+    
+    #if     !SERVER_READY_DELAY
+       if(params->serverToClientRing) {
+               /* RingBuffer I/O */
+               ortn = SSLSetIOFuncs(ctx, ringReadFunc, ringWriteFunc);
+               if(ortn) {
+                       printSslErrStr("SSLSetIOFuncs", ortn);
+                       goto cleanup;
+               } 
+               ortn = SSLSetConnection(ctx, (SSLConnectionRef)&ringBufs);
+               if(ortn) {
+                       printSslErrStr("SSLSetConnection", ortn);
+                       goto cleanup;
+               }
+       }
+       else {
+               /* normal socket I/O */         
+               ortn = SSLSetIOFuncs(ctx, SocketRead, SocketWrite);
+               if(ortn) {
+                       printSslErrStr("SSLSetIOFuncs", ortn);
+                       goto cleanup;
+               } 
+               ortn = SSLSetConnection(ctx, (SSLConnectionRef)acceptSock);
+               if(ortn) {
+                       printSslErrStr("SSLSetConnection", ortn);
+                       goto cleanup;
+               }
+       }
+    #endif  /* SERVER_READY_DELAY */
+    
+       if(params->anchorFile) {
+               ortn = sslAddTrustedRoot(ctx, params->anchorFile, 
+                       params->replaceAnchors);
+               if(ortn) {
+                       goto cleanup;
+               }
+       }
+       if(params->myCertKcName != NULL) {
+               /* if not, better be trying anonymous diff-hellman... :-) */
+               serverCerts = getSslCerts(params->myCertKcName, CSSM_FALSE, CSSM_FALSE, NULL,
+                       &serverKc);
+               if(serverCerts == nil) {
+                       exit(1);
+               }
+               if(params->password) {
+                       ortn = SecKeychainUnlock(serverKc, strlen(params->password), 
+                                       (void *)params->password, true);
+                       if(ortn) {
+                               printf("SecKeychainUnlock returned %d\n", (int)ortn);
+                               /* oh well */
+                       }
+               }
+               if(params->idIsTrustedRoot) {
+                       /* assume this is a root we want to implicitly trust */
+                       ortn = addIdentityAsTrustedRoot(ctx, serverCerts);
+                       if(ortn) {
+                               goto cleanup;
+                       }
+               }
+               ortn = SSLSetCertificate(ctx, serverCerts);
+               if(ortn) {
+                       printSslErrStr("SSLSetCertificate", ortn);
+                       goto cleanup;
+               }
+       }
+       
+       if(params->disableCertVerify) {
+               ortn = SSLSetEnableCertVerify(ctx, false);
+               if(ortn) {
+                       printSslErrStr("SSLSetEnableCertVerify", ortn);
+                       goto cleanup;
+               }
+       }
+       if(!params->noProtSpec) {
+               ortn = sslSetProtocols(ctx, params->acceptedProts, params->tryVersion);
+               if(ortn) {
+                       goto cleanup;
+               }
+       }
+       if(params->resumeEnable) {
+               ortn = SSLSetPeerID(ctx, &peerId, sizeof(PeerSpec));
+               if(ortn) {
+                       printSslErrStr("SSLSetPeerID", ortn);
+                       goto cleanup;
+               }
+       }
+       if(params->ciphers != NULL) {
+               ortn = sslSetEnabledCiphers(ctx, params->ciphers);
+               if(ortn) {
+                       goto cleanup;
+               }
+       }
+       if(params->authenticate != kNeverAuthenticate) {
+               ortn = SSLSetClientSideAuthenticate(ctx, params->authenticate);
+               if(ortn) {
+                       printSslErrStr("SSLSetClientSideAuthenticate", ortn);
+                       goto cleanup;
+               }
+       }
+       if(params->dhParams) {
+               ortn = SSLSetDiffieHellmanParams(ctx, params->dhParams, 
+                       params->dhParamsLen);
+               if(ortn) {
+                       printSslErrStr("SSLSetDiffieHellmanParams", ortn);
+                       goto cleanup;
+               }
+       }
+
+    #if     SERVER_READY_DELAY
+       /* let main thread know server is fully functional */
+       if(pthread_mutex_lock(&params->pthreadMutex)) {
+               printf("***Error acquiring server lock; aborting.\n");
+               ortn = internalComponentErr;
+        goto cleanup;
+       }
+       params->serverReady = true;
+       if(pthread_cond_broadcast(&params->pthreadCond)) {
+               printf("***Error waking main thread; aborting.\n");
+               ortn = internalComponentErr;
+        goto cleanup;
+       }
+       if(pthread_mutex_unlock(&params->pthreadMutex)) {
+               printf("***Error acquiring server lock; aborting.\n");
+               ortn = internalComponentErr;
+        goto cleanup;
+       }
+    
+       if(params->serverToClientRing == NULL) {
+               /* wait for a connection */
+               if(params->verbose) {
+                       printf("Waiting for client connection...");
+                       fflush(stdout);
+               }
+               ortn = AcceptClientConnection(listenSock, &acceptSock, &peerId);
+               if(ortn) {
+                       printf("AcceptClientConnection returned %d; aborting\n", (int)ortn);
+                       return ortn;
+               }
+       }
+
+    /* Last part of SSLContext setup, now that we're connected to the client */
+       if(params->serverToClientRing) {
+               /* RingBuffer I/O */
+               ortn = SSLSetIOFuncs(ctx, ringReadFunc, ringWriteFunc);
+               if(ortn) {
+                       printSslErrStr("SSLSetIOFuncs", ortn);
+                       goto cleanup;
+               } 
+               ortn = SSLSetConnection(ctx, (SSLConnectionRef)&ringBufs);
+               if(ortn) {
+                       printSslErrStr("SSLSetConnection", ortn);
+                       goto cleanup;
+               }
+       }
+       else {
+               /* normal socket I/O */         
+               ortn = SSLSetIOFuncs(ctx, SocketRead, SocketWrite);
+               if(ortn) {
+                       printSslErrStr("SSLSetIOFuncs", ortn);
+                       goto cleanup;
+               } 
+               ortn = SSLSetConnection(ctx, (SSLConnectionRef)acceptSock);
+               if(ortn) {
+                       printSslErrStr("SSLSetConnection", ortn);
+                       goto cleanup;
+               }
+       }
+
+    #endif  /* SERVER_READY_DELAY */
+
+       /* Perform SSL/TLS handshake */
+    do {   
+               ortn = SSLHandshake(ctx);
+           if((ortn == errSSLWouldBlock) && !params->silent) {
+               /* keep UI responsive */ 
+               sslOutputDot();
+           }
+    } while (ortn == errSSLWouldBlock);
+       
+       SSLGetClientCertificateState(ctx, &params->certState);
+       SSLGetNegotiatedCipher(ctx, &params->negCipher);
+       SSLGetNegotiatedProtocolVersion(ctx, &params->negVersion);
+       
+       if(params->verbose) {
+               printf("\n");
+       }
+       if(ortn) {
+               goto cleanup;
+       }
+
+       /* wait for one complete line */
+       char readBuf[READBUF_LEN];
+       size_t length;
+       while(ortn == noErr) {
+           length = READBUF_LEN;
+           ortn = SSLRead(ctx, readBuf, length, &length);
+           if (ortn == errSSLWouldBlock) {
+                       /* keep trying */
+               ortn = noErr;
+                       continue;
+           }
+           if(length == 0) {
+                       /* keep trying */
+                       continue;
+           }
+           
+           /* poor person's line completion scan */
+           for(unsigned i=0; i<length; i++) {
+               if((readBuf[i] == '\n') || (readBuf[i] == '\r')) {
+                       goto serverResp;
+               }
+           }
+       }
+       
+serverResp:
+       /* send out canned response */
+       ortn = SSLWrite(ctx, SERVER_MESSAGE, strlen(SERVER_MESSAGE), &length);
+       if(ortn) {
+               printSslErrStr("SSLWrite", ortn);
+       }
+
+cleanup:
+       /*
+        * always do close, even on error - to flush outgoing write queue 
+        */
+       if(ctx) {
+               OSStatus cerr = SSLClose(ctx);
+               if(ortn == noErr) {
+                       ortn = cerr;
+               }
+       }
+       while(!params->clientDone && !params->serverAbort && (ortn == params->expectRtn)) {
+               usleep(100);
+       }
+       if(acceptSock) {
+               endpointShutdown(acceptSock);
+       }
+       ringBuffersClose(&ringBufs);    /* tolerates NULLs */
+       if(listenSock) {
+               endpointShutdown(listenSock);
+       }
+       if(ctx) {
+           SSLDisposeContext(ctx);  
+       }    
+       params->ortn = ortn;
+       sslThrDebug("Server", "done");
+       return ortn;
+}