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