X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/80e2389990082500d76eb566d4946be3e786c3ef..d8f41ccd20de16f8ebe2ccc84d47bf1cb2b26bbb:/SecurityTests/clxutils/sslThroughput/sslThroughput.cpp diff --git a/SecurityTests/clxutils/sslThroughput/sslThroughput.cpp b/SecurityTests/clxutils/sslThroughput/sslThroughput.cpp new file mode 100644 index 00000000..53a9ab25 --- /dev/null +++ b/SecurityTests/clxutils/sslThroughput/sslThroughput.cpp @@ -0,0 +1,283 @@ +/* + * Measure performance of SecureTransport - setup and sustained data + * throughput. Single process version, no sockets - all data transfer + * between client and server is via local memory shared between two + * threads. + * + * Written by Doug Mitchell. + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEFAULT_KC "localcert" /* default keychain */ +#define DEFAULT_XFER (1024 * 1024 * 20) /* total xfer size in bytes */ + +/* we might make these user-tweakable */ +#define DEFAULT_NUM_BUFS 16 +#define DEFAULT_BUF_SIZE 2048 /* in the ring buffers */ +#define DEFAULT_CHUNK 1024 /* bytes to write per SSLWrite() */ + +static void usage(char **argv) +{ + printf("Usage: %s [option ...]\n", argv[0]); + printf("Options:\n"); + printf(" -k keychain (default = %s)\n", DEFAULT_KC); + printf(" -x transferSize (default=%d; 0=forever)\n", DEFAULT_XFER); + printf(" -c cipher (default = RSA/AES128\n"); + printf(" ciphers: a=RSA/AES128; r=RSA/RC4; d=RSA/DES; D=RSA/3DES;\n"); + printf(" h=DHA/RC4; H=DH/DSS/DES; A=AES256\n"); + printf(" -v version (t|2|3; default = t(TLS1)\n"); + printf(" -w password (unlock server keychain with password)\n"); + printf(" -a (enable client authentication)\n"); + printf(" -p (pause on error)\n"); + printf(" -m (pause for malloc debug)\n"); + exit(1); +} + +int main(int argc, char **argv) +{ + RingBuffer serverToClientRing; + RingBuffer clientToServerRing; + unsigned numBufs = DEFAULT_NUM_BUFS; + unsigned bufSize = DEFAULT_BUF_SIZE; + unsigned chunkSize = DEFAULT_CHUNK; + unsigned char clientBuf[DEFAULT_CHUNK]; + unsigned char serverBuf[DEFAULT_CHUNK]; + CFArrayRef idArray; /* for SSLSetCertificate */ + CFArrayRef anchorArray; /* trusted roots */ + SslRingBufferArgs clientArgs; + SslRingBufferArgs serverArgs; + SecKeychainRef kcRef = NULL; + SecCertificateRef anchorCert = NULL; + SecIdentityRef idRef = NULL; + bool abortFlag = false; + pthread_t client_thread = NULL; + int result; + bool diffieHellman = true; /* FIXME needs work */ + OSStatus ortn; + + /* user-spec'd variables */ + char *kcName = DEFAULT_KC; + unsigned xferSize = DEFAULT_XFER; + SSLCipherSuite cipherSuite = TLS_RSA_WITH_AES_128_CBC_SHA; + SSLProtocol prot = kTLSProtocol1; + char password[200]; + bool clientAuthEnable = false; + bool pauseOnError = false; + bool runForever = false; + bool mallocPause = false; + + password[0] = 0; + + extern int optind; + extern char *optarg; + int arg; + optind = 1; + while ((arg = getopt(argc, argv, "k:x:c:v:w:aBpm")) != -1) { + switch (arg) { + case 'k': + kcName = optarg; + break; + case 'x': + { + unsigned xsize = atoi(optarg); + if(xsize == 0) { + runForever = true; + /* and leave xferSize alone */ + } + else { + xferSize = xsize; + } + break; + } + case 'c': + switch(optarg[0]) { + case 'a': + cipherSuite = TLS_RSA_WITH_AES_128_CBC_SHA; + break; + case 'r': + cipherSuite = SSL_RSA_WITH_RC4_128_SHA; + break; + case 'd': + cipherSuite = SSL_RSA_WITH_DES_CBC_SHA; + break; + case 'D': + cipherSuite = SSL_RSA_WITH_3DES_EDE_CBC_SHA; + break; + case 'h': + cipherSuite = SSL_DH_anon_WITH_RC4_128_MD5; + diffieHellman = true; + break; + case 'H': + cipherSuite = SSL_DHE_DSS_WITH_DES_CBC_SHA; + diffieHellman = true; + break; + case 'A': + cipherSuite = TLS_RSA_WITH_AES_256_CBC_SHA; + break; + default: + usage(argv); + } + break; + case 'v': + switch(optarg[0]) { + case 't': + prot = kTLSProtocol1; + break; + case '2': + prot = kSSLProtocol2; + break; + case '3': + prot = kSSLProtocol3; + break; + default: + usage(argv); + } + break; + case 'w': + strcpy(password, optarg); + break; + case 'a': + clientAuthEnable = true; + break; + case 'p': + pauseOnError = true; + break; + case 'm': + mallocPause = true; + break; + default: + usage(argv); + } + } + if(optind != argc) { + usage(argv); + } + + /* set up ring buffers */ + ringBufSetup(&serverToClientRing, "serveToClient", numBufs, bufSize); + ringBufSetup(&clientToServerRing, "clientToServe", numBufs, bufSize); + + /* get server SecIdentity */ + idArray = getSslCerts(kcName, + CSSM_FALSE, /* encryptOnly */ + CSSM_FALSE, /* completeCertChain */ + NULL, /* anchorFile */ + &kcRef); + if(idArray == NULL) { + printf("***Can't get signing cert from %s\n", kcName); + exit(1); + } + idRef = (SecIdentityRef)CFArrayGetValueAtIndex(idArray, 0); + ortn = SecIdentityCopyCertificate(idRef, &anchorCert); + if(ortn) { + cssmPerror("SecIdentityCopyCertificate", ortn); + exit(1); + } + anchorArray = CFArrayCreate(NULL, (const void **)&anchorCert, + 1, &kCFTypeArrayCallBacks); + + /* unlock keychain? */ + if(password[0]) { + ortn = SecKeychainUnlock(kcRef, strlen(password), password, true); + if(ortn) { + cssmPerror("SecKeychainUnlock", ortn); + /* oh well */ + } + } + CFRelease(kcRef); + + if(mallocPause) { + fpurge(stdin); + printf("Pausing for MallocDebug setup. CR to proceed: "); + getchar(); + } + + /* set up server side */ + memset(&serverArgs, 0, sizeof(serverArgs)); + serverArgs.idArray = idArray; + serverArgs.trustedRoots = anchorArray; + serverArgs.xferSize = xferSize; + serverArgs.xferBuf = serverBuf; + serverArgs.chunkSize = chunkSize; + serverArgs.runForever = runForever; + serverArgs.cipherSuite = cipherSuite; + serverArgs.prot = prot; + serverArgs.ringWrite = &serverToClientRing; + serverArgs.ringRead = &clientToServerRing; + serverArgs.goFlag = &clientArgs.iAmReady; + serverArgs.abortFlag = &abortFlag; + serverArgs.pauseOnError = pauseOnError; + + /* set up client side */ + memset(&clientArgs, 0, sizeof(clientArgs)); + clientArgs.idArray = NULL; /* until we do client auth */ + clientArgs.trustedRoots = anchorArray; + clientArgs.xferSize = xferSize; + clientArgs.xferBuf = clientBuf; + clientArgs.chunkSize = chunkSize; + clientArgs.runForever = runForever; + clientArgs.cipherSuite = cipherSuite; + clientArgs.prot = prot; + clientArgs.ringWrite = &clientToServerRing; + clientArgs.ringRead = &serverToClientRing; + clientArgs.goFlag = &serverArgs.iAmReady; + clientArgs.abortFlag = &abortFlag; + clientArgs.pauseOnError = pauseOnError; + + /* fire up client thread */ + result = pthread_create(&client_thread, NULL, + sslRbClientThread, &clientArgs); + if(result) { + printf("***pthread_create returned %d, aborting\n", result); + exit(1); + } + + /* + * And the server pseudo thread. This returns when all data has been transferred. + */ + ortn = sslRbServerThread(&serverArgs); + + if(abortFlag) { + printf("***Test aborted.\n"); + exit(1); + } + + printf("\n"); + + if(mallocPause) { + fpurge(stdin); + printf("End of test. Pausing for MallocDebug analysis. CR to proceed: "); + getchar(); + } + + printf("SSL Protocol Version : %s\n", + sslGetProtocolVersionString(serverArgs.negotiatedProt)); + printf("SSL Cipher : %s\n", + sslGetCipherSuiteString(serverArgs.negotiatedCipher)); + + printf("SSL Handshake : %f s\n", + serverArgs.startData - serverArgs.startHandshake); + printf("Data Transfer : %u bytes in %f s\n", (unsigned)xferSize, + serverArgs.endData - serverArgs.startHandshake); + printf(" : %.1f Kbytes/s\n", + xferSize / (serverArgs.endData - serverArgs.startHandshake) / 1024.0); + return 0; +} + + +