#include <Security/SecureTransport.h>
#include <Security/Security.h>
#include <clAppUtils/sslAppUtils.h>
#include <clAppUtils/ioSock.h>
#include <clAppUtils/sslThreading.h>
#include <utilLib/fileIo.h>
#include <utilLib/common.h>
#include <security_cdsa_utils/cuPrintCert.h>
#include <Security/SecBase.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <ctype.h>
#include <sys/param.h>
#define BIND_RETRIES 10
#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
OSStatus sslAppServe(
SslAppTestParams *params)
{
otSocket listenSock = 0;
otSocket acceptSock = 0;
PeerSpec peerId;
OSStatus ortn;
SSLContextRef ctx = NULL;
SecKeychainRef serverKc = nil;
CFArrayRef serverCerts = nil;
sslThrDebug("Server", "starting");
params->negVersion = kSSLProtocolUnknown;
params->negCipher = SSL_NULL_WITH_NULL_NULL;
params->ortn = noHardwareErr;
for(unsigned retry=0; retry<BIND_RETRIES; retry++) {
ortn = ListenForClients(params->port, params->nonBlocking,
&listenSock);
switch(ortn) {
case errSecSuccess:
break;
case errSecOpWr:
params->port++;
if(params->verbose || THREADING_DEBUG) {
printf("...retrying ListenForClients at port %d\n",
params->port);
}
break;
default:
break;
}
if(ortn != errSecOpWr) {
break;
}
}
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->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;
}
ortn = SSLNewContext(true, &ctx);
if(ortn) {
printSslErrStr("SSLNewContext", ortn);
goto cleanup;
}
ortn = SSLSetIOFuncs(ctx, SocketRead, SocketWrite);
if(ortn) {
printSslErrStr("SSLSetIOFuncs", ortn);
goto cleanup;
}
ortn = SSLSetConnection(ctx, (SSLConnectionRef)acceptSock);
if(ortn) {
printSslErrStr("SSLSetConnection", ortn);
goto cleanup;
}
if(params->anchorFile) {
ortn = sslAddTrustedRoot(ctx, params->anchorFile,
params->replaceAnchors);
if(ortn) {
goto cleanup;
}
}
if(params->myCertKcName != NULL) {
serverCerts = getSslCerts(params->myCertKcName, false, 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);
}
}
if(params->idIsTrustedRoot) {
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;
}
}
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) {
#if JAGUAR_BUILD
printf("***Diffie-Hellman not supported in this config.\n");
#else
ortn = SSLSetDiffieHellmanParams(ctx, params->dhParams,
params->dhParamsLen);
if(ortn) {
printSslErrStr("SSLSetDiffieHellmanParams", ortn);
goto cleanup;
}
#endif
}
do {
ortn = SSLHandshake(ctx);
if((ortn == errSSLWouldBlock) && !params->silent) {
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;
}
char readBuf[READBUF_LEN];
size_t length;
while(ortn == errSecSuccess) {
length = READBUF_LEN;
ortn = SSLRead(ctx, readBuf, length, &length);
if (ortn == errSSLWouldBlock) {
ortn = errSecSuccess;
continue;
}
if(length == 0) {
continue;
}
for(unsigned i=0; i<length; i++) {
if((readBuf[i] == '\n') || (readBuf[i] == '\r')) {
goto serverResp;
}
}
}
serverResp:
ortn = SSLWrite(ctx, SERVER_MESSAGE, strlen(SERVER_MESSAGE), &length);
if(ortn) {
printSslErrStr("SSLWrite", ortn);
}
cleanup:
if(ctx) {
OSStatus cerr = SSLClose(ctx);
if(ortn == errSecSuccess) {
ortn = cerr;
}
}
if(acceptSock) {
while(!params->clientDone && !params->serverAbort) {
usleep(100);
}
endpointShutdown(acceptSock);
}
if(listenSock) {
endpointShutdown(listenSock);
}
if(ctx) {
SSLDisposeContext(ctx);
}
params->ortn = ortn;
sslThrDebug("Server", "done");
return ortn;
}