--- /dev/null
+/*
+ * ringBufferThreads.cpp - SecureTransport client and server thread
+ * routines which use ringBufferIo for I/O (no sockets).
+ *
+ * Customized for EAP-FAST testing; uses SSLInternalSetMasterSecretFunction()
+ * and SSLInternalSetSessionTicket().
+ */
+
+#include "ringBufferThreads.h"
+#include <stdlib.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <strings.h>
+#include <clAppUtils/sslAppUtils.h>
+#include <utilLib/common.h>
+#include <CommonCrypto/CommonDigest.h>
+
+#define LOG_TOP_IO 0
+#if LOG_TOP_IO
+
+static void logWrite(
+ char *who,
+ size_t written)
+{
+ pthread_mutex_lock(&printfMutex);
+ printf("+++ %s wrote %4lu bytes\n", who, (unsigned long)written);
+ pthread_mutex_unlock(&printfMutex);
+}
+
+static void logRead(
+ char *who,
+ size_t bytesRead)
+{
+ pthread_mutex_lock(&printfMutex);
+ printf("+++ %s read %4lu bytes\n", who, (unsigned long)bytesRead);
+ pthread_mutex_unlock(&printfMutex);
+}
+
+#else /* LOG_TOP_IO */
+#define logWrite(who, w)
+#define logRead(who, r)
+#endif /* LOG_TOP_IO */
+
+/*
+ * Callback from ST to calculate master secret.
+ * We do a poor person's T_PRF(), taking the hash of:
+ *
+ * serverRandom | clientRandom | sharedSecret
+ *
+ * ...to prove that both sides can come up with a master secret
+ * independently, using both sides' random values and the shared secret
+ * supplied by the app.
+ *
+ * We happen to have a digest that produces the required number
+ * of bytes (48)...
+ */
+static void sslMasterSecretFunction(
+ SSLContextRef ctx,
+ const void *arg, /* actually a RingBufferArgs */
+ void *secret, /* mallocd by caller, SSL_MASTER_SECRET_SIZE */
+ size_t *secretLength) /* in/out */
+{
+ RingBufferArgs *sslArgs = (RingBufferArgs *)arg;
+ if(*secretLength < SSL_MASTER_SECRET_SIZE) {
+ printf("**Hey! insufficient space for master secret!\n");
+ return;
+ }
+
+ unsigned char r[SSL_CLIENT_SRVR_RAND_SIZE];
+ size_t rSize = SSL_CLIENT_SRVR_RAND_SIZE;
+ CC_SHA512_CTX digestCtx;
+ CC_SHA384_Init(&digestCtx);
+ SSLInternalServerRandom(ctx, r, &rSize);
+ CC_SHA384_Update(&digestCtx, r, rSize);
+ SSLInternalClientRandom(ctx, r, &rSize);
+ CC_SHA384_Update(&digestCtx, r, rSize);
+ CC_SHA384_Update(&digestCtx, sslArgs->sharedSecret, SHARED_SECRET_SIZE);
+ CC_SHA384_Final((unsigned char *)secret, &digestCtx);
+ *secretLength = CC_SHA384_DIGEST_LENGTH;
+}
+
+/* client thread - handshake and write some data */
+void *rbClientThread(void *arg)
+{
+ RingBufferArgs *sslArgs = (RingBufferArgs *)arg;
+ OSStatus ortn;
+ SSLContextRef ctx = NULL;
+ RingBuffers ringBufs = {sslArgs->ringRead, sslArgs->ringWrite};
+ char sessionID[MAX_SESSION_ID_LENGTH];
+ size_t sessionIDLen = MAX_SESSION_ID_LENGTH;
+ unsigned toMove;
+ unsigned thisMove;
+
+ ortn = SSLNewContext(false, &ctx);
+ if(ortn) {
+ printSslErrStr("SSLNewContext", ortn);
+ goto cleanup;
+ }
+ ortn = SSLSetIOFuncs(ctx, ringReadFunc, ringWriteFunc);
+ if(ortn) {
+ printSslErrStr("SSLSetIOFuncs", ortn);
+ goto cleanup;
+ }
+ ortn = SSLSetConnection(ctx, (SSLConnectionRef)&ringBufs);
+ if(ortn) {
+ printSslErrStr("SSLSetConnection", ortn);
+ goto cleanup;
+ }
+ /* EAP is TLS only - disable the SSLv2-capable handshake */
+ ortn = SSLSetProtocolVersionEnabled(ctx, kSSLProtocol2, false);
+ if(ortn) {
+ printSslErrStr("SSLSetProtocolVersionEnabled", ortn);
+ goto cleanup;
+ }
+ ortn = SSLInternalSetMasterSecretFunction(ctx, sslMasterSecretFunction, sslArgs);
+ if(ortn) {
+ printSslErrStr("SSLInternalSetMasterSecretFunction", ortn);
+ goto cleanup;
+ }
+ ortn = SSLInternalSetSessionTicket(ctx, sslArgs->sessionTicket,
+ sslArgs->sessionTicketLen);
+ if(ortn) {
+ printSslErrStr("SSLInternalSetSessionTicket", ortn);
+ goto cleanup;
+ }
+ if(sslArgs->trustedRoots) {
+ ortn = SSLSetTrustedRoots(ctx, sslArgs->trustedRoots, true);
+ if(ortn) {
+ printSslErrStr("SSLSetTrustedRoots", ortn);
+ goto cleanup;
+ }
+ }
+ if(sslArgs->hostName) {
+ ortn = SSLSetPeerDomainName(ctx, sslArgs->hostName, strlen(sslArgs->hostName));
+ if(ortn) {
+ printSslErrStr("SSLSetPeerDomainName", ortn);
+ goto cleanup;
+ }
+ }
+
+ /* tell main thread we're ready; wait for sync flag */
+ sslArgs->iAmReady = true;
+ while(!(*sslArgs->goFlag)) {
+ if(*sslArgs->abortFlag) {
+ goto cleanup;
+ }
+ }
+
+ /* GO handshake */
+ sslArgs->startHandshake = CFAbsoluteTimeGetCurrent();
+ do {
+ ortn = SSLHandshake(ctx);
+ if(*sslArgs->abortFlag) {
+ goto cleanup;
+ }
+ } while (ortn == errSSLWouldBlock);
+
+ if(ortn) {
+ printSslErrStr("SSLHandshake", ortn);
+ goto cleanup;
+ }
+
+ SSLGetNegotiatedCipher(ctx, &sslArgs->negotiatedCipher);
+ SSLGetNegotiatedProtocolVersion(ctx, &sslArgs->negotiatedProt);
+
+ ortn = SSLGetResumableSessionInfo(ctx, &sslArgs->sessionWasResumed, sessionID, &sessionIDLen);
+ if(ortn) {
+ printSslErrStr("SSLGetResumableSessionInfo", ortn);
+ goto cleanup;
+ }
+
+ sslArgs->startData = CFAbsoluteTimeGetCurrent();
+
+ toMove = sslArgs->xferSize;
+
+ if(toMove == 0) {
+ sslArgs->endData = sslArgs->startData;
+ goto cleanup;
+ }
+
+ /* GO data xfer */
+ do {
+ thisMove = sslArgs->chunkSize;
+ if(thisMove > toMove) {
+ thisMove = toMove;
+ }
+ size_t moved;
+ ortn = SSLWrite(ctx, sslArgs->xferBuf, thisMove, &moved);
+ /* should never fail - implemented as blocking */
+ if(ortn) {
+ printSslErrStr("SSLWrite", ortn);
+ goto cleanup;
+ }
+ logWrite("client", moved);
+ toMove -= moved;
+ if(*sslArgs->abortFlag) {
+ goto cleanup;
+ }
+ } while(toMove);
+
+ sslArgs->endData = CFAbsoluteTimeGetCurrent();
+
+cleanup:
+ if(ortn) {
+ *sslArgs->abortFlag = true;
+ }
+ if(*sslArgs->abortFlag && sslArgs->pauseOnError) {
+ /* abort for any reason - freeze! */
+ testError(CSSM_FALSE);
+ }
+ if(ctx) {
+ SSLClose(ctx);
+ SSLDisposeContext(ctx);
+ }
+ if(ortn) {
+ printf("***Client thread returning %lu\n", (unsigned long)ortn);
+ }
+ pthread_exit((void*)ortn);
+ /* NOT REACHED */
+ return (void *)ortn;
+
+}
+
+/* server function - like clientThread except it runs from the main thread */
+/* handshake and read some data */
+OSStatus rbServerThread(RingBufferArgs *sslArgs)
+{
+ OSStatus ortn;
+ SSLContextRef ctx = NULL;
+ RingBuffers ringBufs = {sslArgs->ringRead, sslArgs->ringWrite};
+ char sessionID[MAX_SESSION_ID_LENGTH];
+ size_t sessionIDLen = MAX_SESSION_ID_LENGTH;
+ unsigned toMove;
+ unsigned thisMove;
+
+ ortn = SSLNewContext(true, &ctx);
+ if(ortn) {
+ printSslErrStr("SSLNewContext", ortn);
+ goto cleanup;
+ }
+ ortn = SSLSetIOFuncs(ctx, ringReadFunc, ringWriteFunc);
+ if(ortn) {
+ printSslErrStr("SSLSetIOFuncs", ortn);
+ goto cleanup;
+ }
+ ortn = SSLSetConnection(ctx, (SSLConnectionRef)&ringBufs);
+ if(ortn) {
+ printSslErrStr("SSLSetConnection", ortn);
+ goto cleanup;
+ }
+ if(sslArgs->setMasterSecret) {
+ ortn = SSLInternalSetMasterSecretFunction(ctx, sslMasterSecretFunction, sslArgs);
+ if(ortn) {
+ printSslErrStr("SSLInternalSetMasterSecretFunction", ortn);
+ goto cleanup;
+ }
+ }
+ if(sslArgs->idArray) {
+ ortn = SSLSetCertificate(ctx, sslArgs->idArray);
+ if(ortn) {
+ printSslErrStr("SSLSetCertificate", ortn);
+ goto cleanup;
+ }
+ }
+ if(sslArgs->trustedRoots) {
+ ortn = SSLSetTrustedRoots(ctx, sslArgs->trustedRoots, true);
+ if(ortn) {
+ printSslErrStr("SSLSetTrustedRoots", ortn);
+ goto cleanup;
+ }
+ }
+
+ /* tell client thread we're ready; wait for sync flag */
+ sslArgs->iAmReady = true;
+ while(!(*sslArgs->goFlag)) {
+ if(*sslArgs->abortFlag) {
+ goto cleanup;
+ }
+ }
+
+ /* GO handshake */
+ sslArgs->startHandshake = CFAbsoluteTimeGetCurrent();
+ do {
+ ortn = SSLHandshake(ctx);
+ if(*sslArgs->abortFlag) {
+ goto cleanup;
+ }
+ } while (ortn == errSSLWouldBlock);
+
+ if(ortn) {
+ printSslErrStr("SSLHandshake", ortn);
+ goto cleanup;
+ }
+
+ SSLGetNegotiatedCipher(ctx, &sslArgs->negotiatedCipher);
+ SSLGetNegotiatedProtocolVersion(ctx, &sslArgs->negotiatedProt);
+ ortn = SSLGetResumableSessionInfo(ctx, &sslArgs->sessionWasResumed, sessionID, &sessionIDLen);
+ if(ortn) {
+ printSslErrStr("SSLGetResumableSessionInfo", ortn);
+ goto cleanup;
+ }
+
+ sslArgs->startData = CFAbsoluteTimeGetCurrent();
+
+ toMove = sslArgs->xferSize;
+
+ if(toMove == 0) {
+ sslArgs->endData = sslArgs->startData;
+ goto cleanup;
+ }
+
+ /* GO data xfer */
+ do {
+ thisMove = sslArgs->xferSize;
+ if(thisMove > toMove) {
+ thisMove = toMove;
+ }
+ size_t moved;
+ ortn = SSLRead(ctx, sslArgs->xferBuf, thisMove, &moved);
+ switch(ortn) {
+ case noErr:
+ break;
+ case errSSLWouldBlock:
+ /* cool, try again */
+ ortn = noErr;
+ break;
+ default:
+ break;
+ }
+ if(ortn) {
+ printSslErrStr("SSLRead", ortn);
+ goto cleanup;
+ }
+ logRead("server", moved);
+ toMove -= moved;
+ if(*sslArgs->abortFlag) {
+ goto cleanup;
+ }
+ } while(toMove);
+
+ sslArgs->endData = CFAbsoluteTimeGetCurrent();
+
+cleanup:
+ if(ortn) {
+ *sslArgs->abortFlag = true;
+ }
+ if(*sslArgs->abortFlag && sslArgs->pauseOnError) {
+ /* abort for any reason - freeze! */
+ testError(CSSM_FALSE);
+ }
+ if(ctx) {
+ SSLClose(ctx);
+ SSLDisposeContext(ctx);
+ }
+ if(ortn) {
+ printf("***Server thread returning %lu\n", (unsigned long)ortn);
+ }
+ return ortn;
+}