1/* 2 * sslHandshakeTimeRB - measure SSL handshake timing, RingBuffer version (no 3 * socket I/O). 4 * 5 * Written by Doug Mitchell. 6 */ 7#include <Security/SecureTransport.h> 8#include <clAppUtils/sslAppUtils.h> 9#include <utilLib/common.h> 10#include <clAppUtils/ringBufferIo.h> 11#include <clAppUtils/sslRingBufferThreads.h> 12 13#include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h> 14#include <stdio.h> 15#include <stdlib.h> 16#include <string.h> 17#include <time.h> 18#include <ctype.h> 19#include <sys/param.h> 20#include <CoreFoundation/CoreFoundation.h> 21#include <security_utilities/devrandom.h> 22 23#define DEFAULT_KC "localcert" /* default keychain */ 24 25/* we might make these user-tweakable */ 26#define DEFAULT_NUM_BUFS 16 27#define DEFAULT_BUF_SIZE 1024 /* in the ring buffers */ 28#define LOOPS_DEF 20 29 30static void usage(char **argv) 31{ 32 printf("Usage: %s [option ...]\n", argv[0]); 33 printf("Options:\n"); 34 printf(" -l loops (default= %d)\n", LOOPS_DEF); 35 printf(" -k keychain (default = %s)\n", DEFAULT_KC); 36 printf(" -c cipher (default = RSA/AES128\n"); 37 printf(" ciphers: a=RSA/AES128; r=RSA/RC4; d=RSA/DES; D=RSA/3DES;\n"); 38 printf(" h=DHA/RC4; H=DH/DSS/DES; A=AES256\n"); 39 printf(" -v version (t|2|3; default = t(TLS1)\n"); 40 printf(" -a (enable client authentication)\n"); 41 exit(1); 42} 43 44static int doTest( 45 SslRingBufferArgs *clientArgs, 46 SslRingBufferArgs *serverArgs, 47 unsigned loops, 48 CFAbsoluteTime *totalElapsedClient, /* RETURNED */ 49 CFAbsoluteTime *totalElapsedServer) /* RETURNED */ 50{ 51 CFAbsoluteTime elapsedClient = 0.0; 52 CFAbsoluteTime elapsedServer = 0.0; 53 int result; 54 pthread_t client_thread = NULL; 55 unsigned dex; 56 void *status; 57 58 for(dex=0; dex<loops; dex++) { 59 60 ringBufferReset(clientArgs->ringWrite); 61 ringBufferReset(clientArgs->ringRead); 62 clientArgs->iAmReady = false; 63 serverArgs->iAmReady = false; 64 65 /* fire up client thread */ 66 result = pthread_create(&client_thread, NULL, 67 sslRbClientThread, clientArgs); 68 if(result) { 69 printf("***pthread_create returned %d, aborting\n", result); 70 return -1; 71 } 72 73 /* 74 * And the server pseudo thread. This returns when all data has been transferred. 75 */ 76 OSStatus ortn = sslRbServerThread(serverArgs); 77 if(*serverArgs->abortFlag || ortn) { 78 printf("***Test aborted (1).\n"); 79 return -1; 80 } 81 82 /* now wait for client */ 83 result = pthread_join(client_thread, &status); 84 if(result || *clientArgs->abortFlag) { 85 printf("***Test aborted (2).\n"); 86 return -1; 87 } 88 elapsedClient += (clientArgs->startData - clientArgs->startHandshake); 89 elapsedServer += (serverArgs->startData - serverArgs->startHandshake); 90 } 91 *totalElapsedClient = elapsedClient; 92 *totalElapsedServer = elapsedServer; 93 return 0; 94} 95 96int main(int argc, char **argv) 97{ 98 RingBuffer serverToClientRing; 99 RingBuffer clientToServerRing; 100 unsigned numBufs = DEFAULT_NUM_BUFS; 101 unsigned bufSize = DEFAULT_BUF_SIZE; 102 CFArrayRef idArray; /* for SSLSetCertificate */ 103 CFArrayRef anchorArray; /* trusted roots */ 104 SslRingBufferArgs clientArgs; 105 SslRingBufferArgs serverArgs; 106 SecKeychainRef kcRef = NULL; 107 SecCertificateRef anchorCert = NULL; 108 SecIdentityRef idRef = NULL; 109 bool abortFlag = false; 110 bool diffieHellman = true; /* FIXME needs work */ 111 OSStatus ortn; 112 CFAbsoluteTime clientFirst; 113 CFAbsoluteTime serverFirst; 114 CFAbsoluteTime clientTotal; 115 CFAbsoluteTime serverTotal; 116 117 /* user-spec'd variables */ 118 char *kcName = DEFAULT_KC; 119 SSLCipherSuite cipherSuite = TLS_RSA_WITH_AES_128_CBC_SHA; 120 SSLProtocol prot = kTLSProtocol1; 121 bool clientAuthEnable = false; 122 unsigned loops = LOOPS_DEF; 123 124 extern int optind; 125 extern char *optarg; 126 int arg; 127 optind = 1; 128 while ((arg = getopt(argc, argv, "l:k:x:c:v:w:aB")) != -1) { 129 switch (arg) { 130 case 'l': 131 loops = atoi(optarg); 132 break; 133 case 'k': 134 kcName = optarg; 135 break; 136 case 'c': 137 switch(optarg[0]) { 138 case 'a': 139 cipherSuite = TLS_RSA_WITH_AES_128_CBC_SHA; 140 break; 141 case 'r': 142 cipherSuite = SSL_RSA_WITH_RC4_128_SHA; 143 break; 144 case 'd': 145 cipherSuite = SSL_RSA_WITH_DES_CBC_SHA; 146 break; 147 case 'D': 148 cipherSuite = SSL_RSA_WITH_3DES_EDE_CBC_SHA; 149 break; 150 case 'h': 151 cipherSuite = SSL_DH_anon_WITH_RC4_128_MD5; 152 diffieHellman = true; 153 break; 154 case 'H': 155 cipherSuite = SSL_DHE_DSS_WITH_DES_CBC_SHA; 156 diffieHellman = true; 157 break; 158 case 'A': 159 cipherSuite = TLS_RSA_WITH_AES_256_CBC_SHA; 160 break; 161 default: 162 usage(argv); 163 } 164 break; 165 case 'v': 166 switch(optarg[0]) { 167 case 't': 168 prot = kTLSProtocol1; 169 break; 170 case '2': 171 prot = kSSLProtocol2; 172 break; 173 case '3': 174 prot = kSSLProtocol3; 175 break; 176 default: 177 usage(argv); 178 } 179 break; 180 case 'a': 181 clientAuthEnable = true; 182 break; 183 default: 184 usage(argv); 185 } 186 } 187 if(optind != argc) { 188 usage(argv); 189 } 190 191 /* set up ring buffers */ 192 ringBufSetup(&serverToClientRing, "serveToClient", numBufs, bufSize); 193 ringBufSetup(&clientToServerRing, "clientToServe", numBufs, bufSize); 194 195 /* get server SecIdentity */ 196 idArray = getSslCerts(kcName, 197 CSSM_FALSE, /* encryptOnly */ 198 CSSM_FALSE, /* completeCertChain */ 199 NULL, /* anchorFile */ 200 &kcRef); 201 if(idArray == NULL) { 202 printf("***Can't get signing cert from %s\n", kcName); 203 exit(1); 204 } 205 idRef = (SecIdentityRef)CFArrayGetValueAtIndex(idArray, 0); 206 ortn = SecIdentityCopyCertificate(idRef, &anchorCert); 207 if(ortn) { 208 cssmPerror("SecIdentityCopyCertificate", ortn); 209 exit(1); 210 } 211 anchorArray = CFArrayCreate(NULL, (const void **)&anchorCert, 212 1, &kCFTypeArrayCallBacks); 213 214 CFRelease(kcRef); 215 216 /* set up server side */ 217 memset(&serverArgs, 0, sizeof(serverArgs)); 218 serverArgs.idArray = idArray; 219 serverArgs.trustedRoots = anchorArray; 220 serverArgs.xferSize = 0; 221 serverArgs.xferBuf = NULL; 222 serverArgs.chunkSize = 0; 223 serverArgs.cipherSuite = cipherSuite; 224 serverArgs.prot = prot; 225 serverArgs.ringWrite = &serverToClientRing; 226 serverArgs.ringRead = &clientToServerRing; 227 serverArgs.goFlag = &clientArgs.iAmReady; 228 serverArgs.abortFlag = &abortFlag; 229 230 /* set up client side */ 231 memset(&clientArgs, 0, sizeof(clientArgs)); 232 clientArgs.idArray = NULL; /* until we do client auth */ 233 clientArgs.trustedRoots = anchorArray; 234 clientArgs.xferSize = 0; 235 clientArgs.xferBuf = NULL; 236 clientArgs.chunkSize = 0; 237 clientArgs.cipherSuite = cipherSuite; 238 clientArgs.prot = prot; 239 clientArgs.ringWrite = &clientToServerRing; 240 clientArgs.ringRead = &serverToClientRing; 241 clientArgs.goFlag = &serverArgs.iAmReady; 242 clientArgs.abortFlag = &abortFlag; 243 244 /* cold start, one loop */ 245 if(doTest(&clientArgs, &serverArgs, 1, &clientFirst, &serverFirst)) { 246 exit(1); 247 } 248 249 /* now the real test */ 250 if(doTest(&clientArgs, &serverArgs, loops, &clientTotal, &serverTotal)) { 251 exit(1); 252 } 253 254 printf("\n"); 255 256 printf("SSL Protocol Version : %s\n", 257 sslGetProtocolVersionString(serverArgs.negotiatedProt)); 258 printf("SSL Cipher : %s\n", 259 sslGetCipherSuiteString(serverArgs.negotiatedCipher)); 260 261 printf("Client Handshake 1st : %f ms\n", clientFirst * 1000.0); 262 printf("Server Handshake 1st : %f ms\n", serverFirst * 1000.0); 263 printf("Client Handshake : %f s in %u loops\n", clientTotal, loops); 264 printf(" %f ms per handshake\n", 265 (clientTotal * 1000.0) / loops); 266 printf("Server Handshake : %f s in %u loops\n", serverTotal, loops); 267 printf(" %f ms per handshake\n", 268 (serverTotal * 1000.0) / loops); 269 270 return 0; 271} 272 273 274 275