+++ /dev/null
-/*
- * 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(¶ms->pthreadMutex)) {
- printf("***Error acquiring server lock; aborting.\n");
- return -1;
- }
- params->serverReady = true;
- if(pthread_cond_broadcast(¶ms->pthreadCond)) {
- printf("***Error waking main thread; aborting.\n");
- return -1;
- }
- if(pthread_mutex_unlock(¶ms->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(¶ms->pthreadMutex)) {
- printf("***Error acquiring server lock; aborting.\n");
- ortn = internalComponentErr;
- goto cleanup;
- }
- params->serverReady = true;
- if(pthread_cond_broadcast(¶ms->pthreadCond)) {
- printf("***Error waking main thread; aborting.\n");
- ortn = internalComponentErr;
- goto cleanup;
- }
- if(pthread_mutex_unlock(¶ms->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, ¶ms->certState);
- SSLGetNegotiatedCipher(ctx, ¶ms->negCipher);
- SSLGetNegotiatedProtocolVersion(ctx, ¶ms->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;
-}