X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/80e2389990082500d76eb566d4946be3e786c3ef..d8f41ccd20de16f8ebe2ccc84d47bf1cb2b26bbb:/SecurityTests/clxutils/clAppUtils/sslServe.cpp diff --git a/SecurityTests/clxutils/clAppUtils/sslServe.cpp b/SecurityTests/clxutils/clAppUtils/sslServe.cpp new file mode 100644 index 00000000..c529238d --- /dev/null +++ b/SecurityTests/clxutils/clAppUtils/sslServe.cpp @@ -0,0 +1,380 @@ +/* + * sslServe.cpp : perform one server side sesssion + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define BIND_RETRIES 50 + +#define SERVER_MESSAGE "HTTP/1.0 200 OK\015\012\015\012" \ + "SecureTransport Test Server" \ + "

Secure connection established.

" \ + "Message from the 'sslServe' test library.\015\012" \ + "\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: + * + * Crash in KCCursorImpl::next + * 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; retryport, 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; iclientDone && !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; +}