1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/cmd/strsclnt/strsclnt.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1565 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 +#include <stdio.h> 1.8 +#include <string.h> 1.9 + 1.10 +#include "secutil.h" 1.11 +#include "basicutil.h" 1.12 + 1.13 +#if defined(XP_UNIX) 1.14 +#include <unistd.h> 1.15 +#endif 1.16 +#include <stdlib.h> 1.17 +#include <errno.h> 1.18 +#include <fcntl.h> 1.19 +#include <stdarg.h> 1.20 + 1.21 +#include "plgetopt.h" 1.22 + 1.23 +#include "nspr.h" 1.24 +#include "prio.h" 1.25 +#include "prnetdb.h" 1.26 +#include "prerror.h" 1.27 + 1.28 +#include "pk11func.h" 1.29 +#include "secitem.h" 1.30 +#include "sslproto.h" 1.31 +#include "nss.h" 1.32 +#include "ssl.h" 1.33 + 1.34 +#ifndef PORT_Sprintf 1.35 +#define PORT_Sprintf sprintf 1.36 +#endif 1.37 + 1.38 +#ifndef PORT_Strstr 1.39 +#define PORT_Strstr strstr 1.40 +#endif 1.41 + 1.42 +#ifndef PORT_Malloc 1.43 +#define PORT_Malloc PR_Malloc 1.44 +#endif 1.45 + 1.46 +#define RD_BUF_SIZE (60 * 1024) 1.47 + 1.48 +/* Include these cipher suite arrays to re-use tstclnt's 1.49 + * cipher selection code. 1.50 + */ 1.51 + 1.52 +int ssl2CipherSuites[] = { 1.53 + SSL_EN_RC4_128_WITH_MD5, /* A */ 1.54 + SSL_EN_RC4_128_EXPORT40_WITH_MD5, /* B */ 1.55 + SSL_EN_RC2_128_CBC_WITH_MD5, /* C */ 1.56 + SSL_EN_RC2_128_CBC_EXPORT40_WITH_MD5, /* D */ 1.57 + SSL_EN_DES_64_CBC_WITH_MD5, /* E */ 1.58 + SSL_EN_DES_192_EDE3_CBC_WITH_MD5, /* F */ 1.59 + 0 1.60 +}; 1.61 + 1.62 +int ssl3CipherSuites[] = { 1.63 + -1, /* SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA* a */ 1.64 + -1, /* SSL_FORTEZZA_DMS_WITH_RC4_128_SHA * b */ 1.65 + TLS_RSA_WITH_RC4_128_MD5, /* c */ 1.66 + TLS_RSA_WITH_3DES_EDE_CBC_SHA, /* d */ 1.67 + TLS_RSA_WITH_DES_CBC_SHA, /* e */ 1.68 + TLS_RSA_EXPORT_WITH_RC4_40_MD5, /* f */ 1.69 + TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5, /* g */ 1.70 + -1, /* SSL_FORTEZZA_DMS_WITH_NULL_SHA * h */ 1.71 + TLS_RSA_WITH_NULL_MD5, /* i */ 1.72 + SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA, /* j */ 1.73 + SSL_RSA_FIPS_WITH_DES_CBC_SHA, /* k */ 1.74 + TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA, /* l */ 1.75 + TLS_RSA_EXPORT1024_WITH_RC4_56_SHA, /* m */ 1.76 + TLS_RSA_WITH_RC4_128_SHA, /* n */ 1.77 + TLS_DHE_DSS_WITH_RC4_128_SHA, /* o */ 1.78 + TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, /* p */ 1.79 + TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA, /* q */ 1.80 + TLS_DHE_RSA_WITH_DES_CBC_SHA, /* r */ 1.81 + TLS_DHE_DSS_WITH_DES_CBC_SHA, /* s */ 1.82 + TLS_DHE_DSS_WITH_AES_128_CBC_SHA, /* t */ 1.83 + TLS_DHE_RSA_WITH_AES_128_CBC_SHA, /* u */ 1.84 + TLS_RSA_WITH_AES_128_CBC_SHA, /* v */ 1.85 + TLS_DHE_DSS_WITH_AES_256_CBC_SHA, /* w */ 1.86 + TLS_DHE_RSA_WITH_AES_256_CBC_SHA, /* x */ 1.87 + TLS_RSA_WITH_AES_256_CBC_SHA, /* y */ 1.88 + TLS_RSA_WITH_NULL_SHA, /* z */ 1.89 + 0 1.90 +}; 1.91 + 1.92 +#define NO_FULLHS_PERCENTAGE -1 1.93 + 1.94 +/* This global string is so that client main can see 1.95 + * which ciphers to use. 1.96 + */ 1.97 + 1.98 +static const char *cipherString; 1.99 + 1.100 +static PRInt32 certsTested; 1.101 +static int MakeCertOK; 1.102 +static int NoReuse; 1.103 +static int fullhs = NO_FULLHS_PERCENTAGE; /* percentage of full handshakes to 1.104 + ** perform */ 1.105 +static PRInt32 globalconid = 0; /* atomically set */ 1.106 +static int total_connections; /* total number of connections to perform */ 1.107 +static int total_connections_rounded_down_to_hundreds; 1.108 +static int total_connections_modulo_100; 1.109 + 1.110 +static PRBool NoDelay; 1.111 +static PRBool QuitOnTimeout = PR_FALSE; 1.112 +static PRBool ThrottleUp = PR_FALSE; 1.113 + 1.114 +static PRLock * threadLock; /* protects the global variables below */ 1.115 +static PRTime lastConnectFailure; 1.116 +static PRTime lastConnectSuccess; 1.117 +static PRTime lastThrottleUp; 1.118 +static PRInt32 remaining_connections; /* number of connections left */ 1.119 +static int active_threads = 8; /* number of threads currently trying to 1.120 + ** connect */ 1.121 +static PRInt32 numUsed; 1.122 +/* end of variables protected by threadLock */ 1.123 + 1.124 +static SSL3Statistics * ssl3stats; 1.125 + 1.126 +static int failed_already = 0; 1.127 +static SSLVersionRange enabledVersions; 1.128 +static PRBool enableSSL2 = PR_TRUE; 1.129 +static PRBool bypassPKCS11 = PR_FALSE; 1.130 +static PRBool disableLocking = PR_FALSE; 1.131 +static PRBool ignoreErrors = PR_FALSE; 1.132 +static PRBool enableSessionTickets = PR_FALSE; 1.133 +static PRBool enableCompression = PR_FALSE; 1.134 +static PRBool enableFalseStart = PR_FALSE; 1.135 +static PRBool enableCertStatus = PR_FALSE; 1.136 + 1.137 +PRIntervalTime maxInterval = PR_INTERVAL_NO_TIMEOUT; 1.138 + 1.139 +char * progName; 1.140 + 1.141 +secuPWData pwdata = { PW_NONE, 0 }; 1.142 + 1.143 +int stopping; 1.144 +int verbose; 1.145 +SECItem bigBuf; 1.146 + 1.147 +#define PRINTF if (verbose) printf 1.148 +#define FPRINTF if (verbose) fprintf 1.149 + 1.150 +static void 1.151 +Usage(const char *progName) 1.152 +{ 1.153 + fprintf(stderr, 1.154 + "Usage: %s [-n nickname] [-p port] [-d dbdir] [-c connections]\n" 1.155 + " [-BDNovqs] [-f filename] [-N | -P percentage]\n" 1.156 + " [-w dbpasswd] [-C cipher(s)] [-t threads] [-W pwfile]\n" 1.157 + " [-V [min-version]:[max-version]] [-a sniHostName] hostname\n" 1.158 + " where -v means verbose\n" 1.159 + " -o flag is interpreted as follows:\n" 1.160 + " 1 -o means override the result of server certificate validation.\n" 1.161 + " 2 -o's mean skip server certificate validation altogether.\n" 1.162 + " -D means no TCP delays\n" 1.163 + " -q means quit when server gone (timeout rather than retry forever)\n" 1.164 + " -s means disable SSL socket locking\n" 1.165 + " -N means no session reuse\n" 1.166 + " -P means do a specified percentage of full handshakes (0-100)\n" 1.167 + " -V [min]:[max] restricts the set of enabled SSL/TLS protocols versions.\n" 1.168 + " All versions are enabled by default.\n" 1.169 + " Possible values for min/max: ssl2 ssl3 tls1.0 tls1.1 tls1.2\n" 1.170 + " Example: \"-V ssl3:\" enables SSL 3 and newer.\n" 1.171 + " -U means enable throttling up threads\n" 1.172 + " -B bypasses the PKCS11 layer for SSL encryption and MACing\n" 1.173 + " -T enable the cert_status extension (OCSP stapling)\n" 1.174 + " -u enable TLS Session Ticket extension\n" 1.175 + " -z enable compression\n" 1.176 + " -g enable false start\n", 1.177 + progName); 1.178 + exit(1); 1.179 +} 1.180 + 1.181 + 1.182 +static void 1.183 +errWarn(char * funcString) 1.184 +{ 1.185 + PRErrorCode perr = PR_GetError(); 1.186 + PRInt32 oserr = PR_GetOSError(); 1.187 + const char * errString = SECU_Strerror(perr); 1.188 + 1.189 + fprintf(stderr, "strsclnt: %s returned error %d, OS error %d: %s\n", 1.190 + funcString, perr, oserr, errString); 1.191 +} 1.192 + 1.193 +static void 1.194 +errExit(char * funcString) 1.195 +{ 1.196 + errWarn(funcString); 1.197 + exit(1); 1.198 +} 1.199 + 1.200 +/************************************************************************** 1.201 +** 1.202 +** Routines for disabling SSL ciphers. 1.203 +** 1.204 +**************************************************************************/ 1.205 + 1.206 +void 1.207 +disableAllSSLCiphers(void) 1.208 +{ 1.209 + const PRUint16 *cipherSuites = SSL_GetImplementedCiphers(); 1.210 + int i = SSL_GetNumImplementedCiphers(); 1.211 + SECStatus rv; 1.212 + 1.213 + /* disable all the SSL3 cipher suites */ 1.214 + while (--i >= 0) { 1.215 + PRUint16 suite = cipherSuites[i]; 1.216 + rv = SSL_CipherPrefSetDefault(suite, PR_FALSE); 1.217 + if (rv != SECSuccess) { 1.218 + printf("SSL_CipherPrefSetDefault didn't like value 0x%04x (i = %d)\n", 1.219 + suite, i); 1.220 + errWarn("SSL_CipherPrefSetDefault"); 1.221 + exit(2); 1.222 + } 1.223 + } 1.224 +} 1.225 + 1.226 +/* This invokes the "default" AuthCert handler in libssl. 1.227 +** The only reason to use this one is that it prints out info as it goes. 1.228 +*/ 1.229 +static SECStatus 1.230 +mySSLAuthCertificate(void *arg, PRFileDesc *fd, PRBool checkSig, 1.231 + PRBool isServer) 1.232 +{ 1.233 + SECStatus rv; 1.234 + CERTCertificate * peerCert; 1.235 + const SECItemArray *csa; 1.236 + 1.237 + if (MakeCertOK>=2) { 1.238 + return SECSuccess; 1.239 + } 1.240 + peerCert = SSL_PeerCertificate(fd); 1.241 + 1.242 + PRINTF("strsclnt: Subject: %s\nstrsclnt: Issuer : %s\n", 1.243 + peerCert->subjectName, peerCert->issuerName); 1.244 + csa = SSL_PeerStapledOCSPResponses(fd); 1.245 + if (csa) { 1.246 + PRINTF("Received %d Cert Status items (OCSP stapled data)\n", 1.247 + csa->len); 1.248 + } 1.249 + /* invoke the "default" AuthCert handler. */ 1.250 + rv = SSL_AuthCertificate(arg, fd, checkSig, isServer); 1.251 + 1.252 + PR_ATOMIC_INCREMENT(&certsTested); 1.253 + if (rv == SECSuccess) { 1.254 + fputs("strsclnt: -- SSL: Server Certificate Validated.\n", stderr); 1.255 + } 1.256 + CERT_DestroyCertificate(peerCert); 1.257 + /* error, if any, will be displayed by the Bad Cert Handler. */ 1.258 + return rv; 1.259 +} 1.260 + 1.261 +static SECStatus 1.262 +myBadCertHandler( void *arg, PRFileDesc *fd) 1.263 +{ 1.264 + PRErrorCode err = PR_GetError(); 1.265 + if (!MakeCertOK) 1.266 + fprintf(stderr, 1.267 + "strsclnt: -- SSL: Server Certificate Invalid, err %d.\n%s\n", 1.268 + err, SECU_Strerror(err)); 1.269 + return (MakeCertOK ? SECSuccess : SECFailure); 1.270 +} 1.271 + 1.272 +void 1.273 +printSecurityInfo(PRFileDesc *fd) 1.274 +{ 1.275 + CERTCertificate * cert = NULL; 1.276 + SSL3Statistics * ssl3stats = SSL_GetStatistics(); 1.277 + SECStatus result; 1.278 + SSLChannelInfo channel; 1.279 + SSLCipherSuiteInfo suite; 1.280 + 1.281 + static int only_once; 1.282 + 1.283 + if (only_once && verbose < 2) 1.284 + return; 1.285 + only_once = 1; 1.286 + 1.287 + result = SSL_GetChannelInfo(fd, &channel, sizeof channel); 1.288 + if (result == SECSuccess && 1.289 + channel.length == sizeof channel && 1.290 + channel.cipherSuite) { 1.291 + result = SSL_GetCipherSuiteInfo(channel.cipherSuite, 1.292 + &suite, sizeof suite); 1.293 + if (result == SECSuccess) { 1.294 + FPRINTF(stderr, 1.295 + "strsclnt: SSL version %d.%d using %d-bit %s with %d-bit %s MAC\n", 1.296 + channel.protocolVersion >> 8, channel.protocolVersion & 0xff, 1.297 + suite.effectiveKeyBits, suite.symCipherName, 1.298 + suite.macBits, suite.macAlgorithmName); 1.299 + FPRINTF(stderr, 1.300 + "strsclnt: Server Auth: %d-bit %s, Key Exchange: %d-bit %s\n" 1.301 + " Compression: %s\n", 1.302 + channel.authKeyBits, suite.authAlgorithmName, 1.303 + channel.keaKeyBits, suite.keaTypeName, 1.304 + channel.compressionMethodName); 1.305 + } 1.306 + } 1.307 + 1.308 + cert = SSL_LocalCertificate(fd); 1.309 + if (!cert) 1.310 + cert = SSL_PeerCertificate(fd); 1.311 + 1.312 + if (verbose && cert) { 1.313 + char * ip = CERT_NameToAscii(&cert->issuer); 1.314 + char * sp = CERT_NameToAscii(&cert->subject); 1.315 + if (sp) { 1.316 + fprintf(stderr, "strsclnt: subject DN: %s\n", sp); 1.317 + PORT_Free(sp); 1.318 + } 1.319 + if (ip) { 1.320 + fprintf(stderr, "strsclnt: issuer DN: %s\n", ip); 1.321 + PORT_Free(ip); 1.322 + } 1.323 + } 1.324 + if (cert) { 1.325 + CERT_DestroyCertificate(cert); 1.326 + cert = NULL; 1.327 + } 1.328 + fprintf(stderr, 1.329 + "strsclnt: %ld cache hits; %ld cache misses, %ld cache not reusable\n" 1.330 + " %ld stateless resumes\n", 1.331 + ssl3stats->hsh_sid_cache_hits, 1.332 + ssl3stats->hsh_sid_cache_misses, 1.333 + ssl3stats->hsh_sid_cache_not_ok, 1.334 + ssl3stats->hsh_sid_stateless_resumes); 1.335 + 1.336 +} 1.337 + 1.338 +/************************************************************************** 1.339 +** Begin thread management routines and data. 1.340 +**************************************************************************/ 1.341 + 1.342 +#define MAX_THREADS 128 1.343 + 1.344 +typedef int startFn(void *a, void *b, int c); 1.345 + 1.346 + 1.347 +static PRInt32 numConnected; 1.348 +static int max_threads; /* peak threads allowed */ 1.349 + 1.350 +typedef struct perThreadStr { 1.351 + void * a; 1.352 + void * b; 1.353 + int tid; 1.354 + int rv; 1.355 + startFn * startFunc; 1.356 + PRThread * prThread; 1.357 + PRBool inUse; 1.358 +} perThread; 1.359 + 1.360 +perThread threads[MAX_THREADS]; 1.361 + 1.362 +void 1.363 +thread_wrapper(void * arg) 1.364 +{ 1.365 + perThread * slot = (perThread *)arg; 1.366 + PRBool done = PR_FALSE; 1.367 + 1.368 + do { 1.369 + PRBool doop = PR_FALSE; 1.370 + PRBool dosleep = PR_FALSE; 1.371 + PRTime now = PR_Now(); 1.372 + 1.373 + PR_Lock(threadLock); 1.374 + if (! (slot->tid < active_threads)) { 1.375 + /* this thread isn't supposed to be running */ 1.376 + if (!ThrottleUp) { 1.377 + /* we'll never need this thread again, so abort it */ 1.378 + done = PR_TRUE; 1.379 + } else if (remaining_connections > 0) { 1.380 + /* we may still need this thread, so just sleep for 1s */ 1.381 + dosleep = PR_TRUE; 1.382 + /* the conditions to trigger a throttle up are : 1.383 + ** 1. last PR_Connect failure must have happened more than 1.384 + ** 10s ago 1.385 + ** 2. last throttling up must have happened more than 0.5s ago 1.386 + ** 3. there must be a more recent PR_Connect success than 1.387 + ** failure 1.388 + */ 1.389 + if ( (now - lastConnectFailure > 10 * PR_USEC_PER_SEC) && 1.390 + ( (!lastThrottleUp) || ( (now - lastThrottleUp) >= 1.391 + (PR_USEC_PER_SEC/2)) ) && 1.392 + (lastConnectSuccess > lastConnectFailure) ) { 1.393 + /* try throttling up by one thread */ 1.394 + active_threads = PR_MIN(max_threads, active_threads+1); 1.395 + fprintf(stderr,"active_threads set up to %d\n", 1.396 + active_threads); 1.397 + lastThrottleUp = PR_MAX(now, lastThrottleUp); 1.398 + } 1.399 + } else { 1.400 + /* no more connections left, we are done */ 1.401 + done = PR_TRUE; 1.402 + } 1.403 + } else { 1.404 + /* this thread should run */ 1.405 + if (--remaining_connections >= 0) { /* protected by threadLock */ 1.406 + doop = PR_TRUE; 1.407 + } else { 1.408 + done = PR_TRUE; 1.409 + } 1.410 + } 1.411 + PR_Unlock(threadLock); 1.412 + if (doop) { 1.413 + slot->rv = (* slot->startFunc)(slot->a, slot->b, slot->tid); 1.414 + PRINTF("strsclnt: Thread in slot %d returned %d\n", 1.415 + slot->tid, slot->rv); 1.416 + } 1.417 + if (dosleep) { 1.418 + PR_Sleep(PR_SecondsToInterval(1)); 1.419 + } 1.420 + } while (!done && (!failed_already || ignoreErrors)); 1.421 +} 1.422 + 1.423 +SECStatus 1.424 +launch_thread( 1.425 + startFn * startFunc, 1.426 + void * a, 1.427 + void * b, 1.428 + int tid) 1.429 +{ 1.430 + PRUint32 i; 1.431 + perThread * slot; 1.432 + 1.433 + PR_Lock(threadLock); 1.434 + 1.435 + PORT_Assert(numUsed < MAX_THREADS); 1.436 + if (! (numUsed < MAX_THREADS)) { 1.437 + PR_Unlock(threadLock); 1.438 + return SECFailure; 1.439 + } 1.440 + 1.441 + i = numUsed++; 1.442 + slot = &threads[i]; 1.443 + slot->a = a; 1.444 + slot->b = b; 1.445 + slot->tid = tid; 1.446 + 1.447 + slot->startFunc = startFunc; 1.448 + 1.449 + slot->prThread = PR_CreateThread(PR_USER_THREAD, 1.450 + thread_wrapper, slot, 1.451 + PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, 1.452 + PR_JOINABLE_THREAD, 0); 1.453 + if (slot->prThread == NULL) { 1.454 + PR_Unlock(threadLock); 1.455 + printf("strsclnt: Failed to launch thread!\n"); 1.456 + return SECFailure; 1.457 + } 1.458 + 1.459 + slot->inUse = 1; 1.460 + PR_Unlock(threadLock); 1.461 + PRINTF("strsclnt: Launched thread in slot %d \n", i); 1.462 + 1.463 + return SECSuccess; 1.464 +} 1.465 + 1.466 +/* join all the threads */ 1.467 +int 1.468 +reap_threads(void) 1.469 +{ 1.470 + int i; 1.471 + 1.472 + for (i = 0; i < MAX_THREADS; ++i) { 1.473 + if (threads[i].prThread) { 1.474 + PR_JoinThread(threads[i].prThread); 1.475 + threads[i].prThread = NULL; 1.476 + } 1.477 + } 1.478 + return 0; 1.479 +} 1.480 + 1.481 +void 1.482 +destroy_thread_data(void) 1.483 +{ 1.484 + PORT_Memset(threads, 0, sizeof threads); 1.485 + 1.486 + if (threadLock) { 1.487 + PR_DestroyLock(threadLock); 1.488 + threadLock = NULL; 1.489 + } 1.490 +} 1.491 + 1.492 +void 1.493 +init_thread_data(void) 1.494 +{ 1.495 + threadLock = PR_NewLock(); 1.496 +} 1.497 + 1.498 +/************************************************************************** 1.499 +** End thread management routines. 1.500 +**************************************************************************/ 1.501 + 1.502 +PRBool useModelSocket = PR_TRUE; 1.503 + 1.504 +static const char stopCmd[] = { "GET /stop " }; 1.505 +static const char outHeader[] = { 1.506 + "HTTP/1.0 200 OK\r\n" 1.507 + "Server: Netscape-Enterprise/2.0a\r\n" 1.508 + "Date: Tue, 26 Aug 1997 22:10:05 GMT\r\n" 1.509 + "Content-type: text/plain\r\n" 1.510 + "\r\n" 1.511 +}; 1.512 + 1.513 +struct lockedVarsStr { 1.514 + PRLock * lock; 1.515 + int count; 1.516 + int waiters; 1.517 + PRCondVar * condVar; 1.518 +}; 1.519 + 1.520 +typedef struct lockedVarsStr lockedVars; 1.521 + 1.522 +void 1.523 +lockedVars_Init( lockedVars * lv) 1.524 +{ 1.525 + lv->count = 0; 1.526 + lv->waiters = 0; 1.527 + lv->lock = PR_NewLock(); 1.528 + lv->condVar = PR_NewCondVar(lv->lock); 1.529 +} 1.530 + 1.531 +void 1.532 +lockedVars_Destroy( lockedVars * lv) 1.533 +{ 1.534 + PR_DestroyCondVar(lv->condVar); 1.535 + lv->condVar = NULL; 1.536 + 1.537 + PR_DestroyLock(lv->lock); 1.538 + lv->lock = NULL; 1.539 +} 1.540 + 1.541 +void 1.542 +lockedVars_WaitForDone(lockedVars * lv) 1.543 +{ 1.544 + PR_Lock(lv->lock); 1.545 + while (lv->count > 0) { 1.546 + PR_WaitCondVar(lv->condVar, PR_INTERVAL_NO_TIMEOUT); 1.547 + } 1.548 + PR_Unlock(lv->lock); 1.549 +} 1.550 + 1.551 +int /* returns count */ 1.552 +lockedVars_AddToCount(lockedVars * lv, int addend) 1.553 +{ 1.554 + int rv; 1.555 + 1.556 + PR_Lock(lv->lock); 1.557 + rv = lv->count += addend; 1.558 + if (rv <= 0) { 1.559 + PR_NotifyCondVar(lv->condVar); 1.560 + } 1.561 + PR_Unlock(lv->lock); 1.562 + return rv; 1.563 +} 1.564 + 1.565 +int 1.566 +do_writes( 1.567 + void * a, 1.568 + void * b, 1.569 + int c) 1.570 +{ 1.571 + PRFileDesc * ssl_sock = (PRFileDesc *)a; 1.572 + lockedVars * lv = (lockedVars *)b; 1.573 + int sent = 0; 1.574 + int count = 0; 1.575 + 1.576 + while (sent < bigBuf.len) { 1.577 + 1.578 + count = PR_Send(ssl_sock, bigBuf.data + sent, bigBuf.len - sent, 1.579 + 0, maxInterval); 1.580 + if (count < 0) { 1.581 + errWarn("PR_Send bigBuf"); 1.582 + break; 1.583 + } 1.584 + FPRINTF(stderr, "strsclnt: PR_Send wrote %d bytes from bigBuf\n", 1.585 + count ); 1.586 + sent += count; 1.587 + } 1.588 + if (count >= 0) { /* last write didn't fail. */ 1.589 + PR_Shutdown(ssl_sock, PR_SHUTDOWN_SEND); 1.590 + } 1.591 + 1.592 + /* notify the reader that we're done. */ 1.593 + lockedVars_AddToCount(lv, -1); 1.594 + return (sent < bigBuf.len) ? SECFailure : SECSuccess; 1.595 +} 1.596 + 1.597 +int 1.598 +handle_fdx_connection( PRFileDesc * ssl_sock, int connection) 1.599 +{ 1.600 + SECStatus result; 1.601 + int firstTime = 1; 1.602 + int countRead = 0; 1.603 + lockedVars lv; 1.604 + char *buf; 1.605 + 1.606 + 1.607 + lockedVars_Init(&lv); 1.608 + lockedVars_AddToCount(&lv, 1); 1.609 + 1.610 + /* Attempt to launch the writer thread. */ 1.611 + result = launch_thread(do_writes, ssl_sock, &lv, connection); 1.612 + 1.613 + if (result != SECSuccess) 1.614 + goto cleanup; 1.615 + 1.616 + buf = PR_Malloc(RD_BUF_SIZE); 1.617 + 1.618 + if (buf) { 1.619 + do { 1.620 + /* do reads here. */ 1.621 + PRInt32 count; 1.622 + 1.623 + count = PR_Recv(ssl_sock, buf, RD_BUF_SIZE, 0, maxInterval); 1.624 + if (count < 0) { 1.625 + errWarn("PR_Recv"); 1.626 + break; 1.627 + } 1.628 + countRead += count; 1.629 + FPRINTF(stderr, 1.630 + "strsclnt: connection %d read %d bytes (%d total).\n", 1.631 + connection, count, countRead ); 1.632 + if (firstTime) { 1.633 + firstTime = 0; 1.634 + printSecurityInfo(ssl_sock); 1.635 + } 1.636 + } while (lockedVars_AddToCount(&lv, 0) > 0); 1.637 + PR_Free(buf); 1.638 + buf = 0; 1.639 + } 1.640 + 1.641 + /* Wait for writer to finish */ 1.642 + lockedVars_WaitForDone(&lv); 1.643 + lockedVars_Destroy(&lv); 1.644 + 1.645 + FPRINTF(stderr, 1.646 + "strsclnt: connection %d read %d bytes total. -----------------------\n", 1.647 + connection, countRead); 1.648 + 1.649 +cleanup: 1.650 + /* Caller closes the socket. */ 1.651 + 1.652 + return SECSuccess; 1.653 +} 1.654 + 1.655 +const char request[] = {"GET /abc HTTP/1.0\r\n\r\n" }; 1.656 + 1.657 +SECStatus 1.658 +handle_connection( PRFileDesc *ssl_sock, int tid) 1.659 +{ 1.660 + int countRead = 0; 1.661 + PRInt32 rv; 1.662 + char *buf; 1.663 + 1.664 + buf = PR_Malloc(RD_BUF_SIZE); 1.665 + if (!buf) 1.666 + return SECFailure; 1.667 + 1.668 + /* compose the http request here. */ 1.669 + 1.670 + rv = PR_Send(ssl_sock, request, strlen(request), 0, maxInterval); 1.671 + if (rv <= 0) { 1.672 + errWarn("PR_Send"); 1.673 + PR_Free(buf); 1.674 + buf = 0; 1.675 + failed_already = 1; 1.676 + return SECFailure; 1.677 + } 1.678 + printSecurityInfo(ssl_sock); 1.679 + 1.680 + /* read until EOF */ 1.681 + while (1) { 1.682 + rv = PR_Recv(ssl_sock, buf, RD_BUF_SIZE, 0, maxInterval); 1.683 + if (rv == 0) { 1.684 + break; /* EOF */ 1.685 + } 1.686 + if (rv < 0) { 1.687 + errWarn("PR_Recv"); 1.688 + failed_already = 1; 1.689 + break; 1.690 + } 1.691 + 1.692 + countRead += rv; 1.693 + FPRINTF(stderr, 1.694 + "strsclnt: connection on thread %d read %d bytes (%d total).\n", 1.695 + tid, rv, countRead ); 1.696 + } 1.697 + PR_Free(buf); 1.698 + buf = 0; 1.699 + 1.700 + /* Caller closes the socket. */ 1.701 + 1.702 + FPRINTF(stderr, 1.703 + "strsclnt: connection on thread %d read %d bytes total. ---------\n", 1.704 + tid, countRead); 1.705 + 1.706 + return SECSuccess; /* success */ 1.707 +} 1.708 + 1.709 +#define USE_SOCK_PEER_ID 1 1.710 + 1.711 +#ifdef USE_SOCK_PEER_ID 1.712 + 1.713 +PRInt32 lastFullHandshakePeerID; 1.714 + 1.715 +void 1.716 +myHandshakeCallback(PRFileDesc *socket, void *arg) 1.717 +{ 1.718 + PR_ATOMIC_SET(&lastFullHandshakePeerID, (PRInt32) arg); 1.719 +} 1.720 + 1.721 +#endif 1.722 + 1.723 +/* one copy of this function is launched in a separate thread for each 1.724 +** connection to be made. 1.725 +*/ 1.726 +int 1.727 +do_connects( 1.728 + void * a, 1.729 + void * b, 1.730 + int tid) 1.731 +{ 1.732 + PRNetAddr * addr = (PRNetAddr *) a; 1.733 + PRFileDesc * model_sock = (PRFileDesc *) b; 1.734 + PRFileDesc * ssl_sock = 0; 1.735 + PRFileDesc * tcp_sock = 0; 1.736 + PRStatus prStatus; 1.737 + PRUint32 sleepInterval = 50; /* milliseconds */ 1.738 + SECStatus result; 1.739 + int rv = SECSuccess; 1.740 + PRSocketOptionData opt; 1.741 + 1.742 +retry: 1.743 + 1.744 + tcp_sock = PR_OpenTCPSocket(addr->raw.family); 1.745 + if (tcp_sock == NULL) { 1.746 + errExit("PR_OpenTCPSocket"); 1.747 + } 1.748 + 1.749 + opt.option = PR_SockOpt_Nonblocking; 1.750 + opt.value.non_blocking = PR_FALSE; 1.751 + prStatus = PR_SetSocketOption(tcp_sock, &opt); 1.752 + if (prStatus != PR_SUCCESS) { 1.753 + errWarn("PR_SetSocketOption(PR_SockOpt_Nonblocking, PR_FALSE)"); 1.754 + PR_Close(tcp_sock); 1.755 + return SECSuccess; 1.756 + } 1.757 + 1.758 + if (NoDelay) { 1.759 + opt.option = PR_SockOpt_NoDelay; 1.760 + opt.value.no_delay = PR_TRUE; 1.761 + prStatus = PR_SetSocketOption(tcp_sock, &opt); 1.762 + if (prStatus != PR_SUCCESS) { 1.763 + errWarn("PR_SetSocketOption(PR_SockOpt_NoDelay, PR_TRUE)"); 1.764 + PR_Close(tcp_sock); 1.765 + return SECSuccess; 1.766 + } 1.767 + } 1.768 + 1.769 + prStatus = PR_Connect(tcp_sock, addr, PR_INTERVAL_NO_TIMEOUT); 1.770 + if (prStatus != PR_SUCCESS) { 1.771 + PRErrorCode err = PR_GetError(); /* save error code */ 1.772 + PRInt32 oserr = PR_GetOSError(); 1.773 + if (ThrottleUp) { 1.774 + PRTime now = PR_Now(); 1.775 + PR_Lock(threadLock); 1.776 + lastConnectFailure = PR_MAX(now, lastConnectFailure); 1.777 + PR_Unlock(threadLock); 1.778 + PR_SetError(err, oserr); /* restore error code */ 1.779 + } 1.780 + if ((err == PR_CONNECT_REFUSED_ERROR) || 1.781 + (err == PR_CONNECT_RESET_ERROR) ) { 1.782 + int connections = numConnected; 1.783 + 1.784 + PR_Close(tcp_sock); 1.785 + PR_Lock(threadLock); 1.786 + if (connections > 2 && active_threads >= connections) { 1.787 + active_threads = connections - 1; 1.788 + fprintf(stderr,"active_threads set down to %d\n", 1.789 + active_threads); 1.790 + } 1.791 + PR_Unlock(threadLock); 1.792 + 1.793 + if (QuitOnTimeout && sleepInterval > 40000) { 1.794 + fprintf(stderr, 1.795 + "strsclnt: Client timed out waiting for connection to server.\n"); 1.796 + exit(1); 1.797 + } 1.798 + PR_Sleep(PR_MillisecondsToInterval(sleepInterval)); 1.799 + sleepInterval <<= 1; 1.800 + goto retry; 1.801 + } 1.802 + errWarn("PR_Connect"); 1.803 + rv = SECFailure; 1.804 + goto done; 1.805 + } else { 1.806 + if (ThrottleUp) { 1.807 + PRTime now = PR_Now(); 1.808 + PR_Lock(threadLock); 1.809 + lastConnectSuccess = PR_MAX(now, lastConnectSuccess); 1.810 + PR_Unlock(threadLock); 1.811 + } 1.812 + } 1.813 + 1.814 + ssl_sock = SSL_ImportFD(model_sock, tcp_sock); 1.815 + /* XXX if this import fails, close tcp_sock and return. */ 1.816 + if (!ssl_sock) { 1.817 + PR_Close(tcp_sock); 1.818 + return SECSuccess; 1.819 + } 1.820 + if (fullhs != NO_FULLHS_PERCENTAGE) { 1.821 +#ifdef USE_SOCK_PEER_ID 1.822 + char sockPeerIDString[512]; 1.823 + static PRInt32 sockPeerID = 0; /* atomically incremented */ 1.824 + PRInt32 thisPeerID; 1.825 +#endif 1.826 + PRInt32 savid = PR_ATOMIC_INCREMENT(&globalconid); 1.827 + PRInt32 conid = 1 + (savid - 1) % 100; 1.828 + /* don't change peer ID on the very first handshake, which is always 1.829 + a full, so the session gets stored into the client cache */ 1.830 + if ( (savid != 1) && 1.831 + ( ( (savid <= total_connections_rounded_down_to_hundreds) && 1.832 + (conid <= fullhs) ) || 1.833 + (conid*100 <= total_connections_modulo_100*fullhs ) ) ) 1.834 +#ifdef USE_SOCK_PEER_ID 1.835 + { 1.836 + /* force a full handshake by changing the socket peer ID */ 1.837 + thisPeerID = PR_ATOMIC_INCREMENT(&sockPeerID); 1.838 + } else { 1.839 + /* reuse previous sockPeerID for restart handhsake */ 1.840 + thisPeerID = lastFullHandshakePeerID; 1.841 + } 1.842 + PR_snprintf(sockPeerIDString, sizeof(sockPeerIDString), "ID%d", 1.843 + thisPeerID); 1.844 + SSL_SetSockPeerID(ssl_sock, sockPeerIDString); 1.845 + SSL_HandshakeCallback(ssl_sock, myHandshakeCallback, (void*)thisPeerID); 1.846 +#else 1.847 + /* force a full handshake by setting the no cache option */ 1.848 + SSL_OptionSet(ssl_sock, SSL_NO_CACHE, 1); 1.849 +#endif 1.850 + } 1.851 + rv = SSL_ResetHandshake(ssl_sock, /* asServer */ 0); 1.852 + if (rv != SECSuccess) { 1.853 + errWarn("SSL_ResetHandshake"); 1.854 + goto done; 1.855 + } 1.856 + 1.857 + PR_ATOMIC_INCREMENT(&numConnected); 1.858 + 1.859 + if (bigBuf.data != NULL) { 1.860 + result = handle_fdx_connection( ssl_sock, tid); 1.861 + } else { 1.862 + result = handle_connection( ssl_sock, tid); 1.863 + } 1.864 + 1.865 + PR_ATOMIC_DECREMENT(&numConnected); 1.866 + 1.867 +done: 1.868 + if (ssl_sock) { 1.869 + PR_Close(ssl_sock); 1.870 + } else if (tcp_sock) { 1.871 + PR_Close(tcp_sock); 1.872 + } 1.873 + return SECSuccess; 1.874 +} 1.875 + 1.876 + 1.877 +typedef struct { 1.878 + PRLock* lock; 1.879 + char* nickname; 1.880 + CERTCertificate* cert; 1.881 + SECKEYPrivateKey* key; 1.882 + void* wincx; 1.883 +} cert_and_key; 1.884 + 1.885 +PRBool FindCertAndKey(cert_and_key* Cert_And_Key) 1.886 +{ 1.887 + if ( (NULL == Cert_And_Key->nickname) || (0 == strcmp(Cert_And_Key->nickname,"none"))) { 1.888 + return PR_TRUE; 1.889 + } 1.890 + Cert_And_Key->cert = CERT_FindUserCertByUsage(CERT_GetDefaultCertDB(), 1.891 + Cert_And_Key->nickname, certUsageSSLClient, 1.892 + PR_FALSE, Cert_And_Key->wincx); 1.893 + if (Cert_And_Key->cert) { 1.894 + Cert_And_Key->key = PK11_FindKeyByAnyCert(Cert_And_Key->cert, Cert_And_Key->wincx); 1.895 + } 1.896 + if (Cert_And_Key->cert && Cert_And_Key->key) { 1.897 + return PR_TRUE; 1.898 + } else { 1.899 + return PR_FALSE; 1.900 + } 1.901 +} 1.902 + 1.903 +PRBool LoggedIn(CERTCertificate* cert, SECKEYPrivateKey* key) 1.904 +{ 1.905 + if ( (cert->slot) && (key->pkcs11Slot) && 1.906 + (PR_TRUE == PK11_IsLoggedIn(cert->slot, NULL)) && 1.907 + (PR_TRUE == PK11_IsLoggedIn(key->pkcs11Slot, NULL)) ) { 1.908 + return PR_TRUE; 1.909 + } 1.910 + 1.911 + return PR_FALSE; 1.912 +} 1.913 + 1.914 +SECStatus 1.915 +StressClient_GetClientAuthData(void * arg, 1.916 + PRFileDesc * socket, 1.917 + struct CERTDistNamesStr * caNames, 1.918 + struct CERTCertificateStr ** pRetCert, 1.919 + struct SECKEYPrivateKeyStr **pRetKey) 1.920 +{ 1.921 + cert_and_key* Cert_And_Key = (cert_and_key*) arg; 1.922 + 1.923 + if (!pRetCert || !pRetKey) { 1.924 + /* bad pointers, can't return a cert or key */ 1.925 + return SECFailure; 1.926 + } 1.927 + 1.928 + *pRetCert = NULL; 1.929 + *pRetKey = NULL; 1.930 + 1.931 + if (Cert_And_Key && Cert_And_Key->nickname) { 1.932 + while (PR_TRUE) { 1.933 + if (Cert_And_Key && Cert_And_Key->lock) { 1.934 + int timeout = 0; 1.935 + PR_Lock(Cert_And_Key->lock); 1.936 + 1.937 + if (Cert_And_Key->cert) { 1.938 + *pRetCert = CERT_DupCertificate(Cert_And_Key->cert); 1.939 + } 1.940 + 1.941 + if (Cert_And_Key->key) { 1.942 + *pRetKey = SECKEY_CopyPrivateKey(Cert_And_Key->key); 1.943 + } 1.944 + PR_Unlock(Cert_And_Key->lock); 1.945 + if (!*pRetCert || !*pRetKey) { 1.946 + /* one or both of them failed to copy. Either the source was NULL, or there was 1.947 + ** an out of memory condition. Free any allocated copy and fail */ 1.948 + if (*pRetCert) { 1.949 + CERT_DestroyCertificate(*pRetCert); 1.950 + *pRetCert = NULL; 1.951 + } 1.952 + if (*pRetKey) { 1.953 + SECKEY_DestroyPrivateKey(*pRetKey); 1.954 + *pRetKey = NULL; 1.955 + } 1.956 + break; 1.957 + } 1.958 + /* now check if those objects are valid */ 1.959 + if ( PR_FALSE == LoggedIn(*pRetCert, *pRetKey) ) { 1.960 + /* token is no longer logged in, it was removed */ 1.961 + 1.962 + /* first, delete and clear our invalid local objects */ 1.963 + CERT_DestroyCertificate(*pRetCert); 1.964 + SECKEY_DestroyPrivateKey(*pRetKey); 1.965 + *pRetCert = NULL; 1.966 + *pRetKey = NULL; 1.967 + 1.968 + PR_Lock(Cert_And_Key->lock); 1.969 + /* check if another thread already logged back in */ 1.970 + if (PR_TRUE == LoggedIn(Cert_And_Key->cert, Cert_And_Key->key)) { 1.971 + /* yes : try again */ 1.972 + PR_Unlock(Cert_And_Key->lock); 1.973 + continue; 1.974 + } 1.975 + /* this is the thread to retry */ 1.976 + CERT_DestroyCertificate(Cert_And_Key->cert); 1.977 + SECKEY_DestroyPrivateKey(Cert_And_Key->key); 1.978 + Cert_And_Key->cert = NULL; 1.979 + Cert_And_Key->key = NULL; 1.980 + 1.981 + 1.982 + /* now look up the cert and key again */ 1.983 + while (PR_FALSE == FindCertAndKey(Cert_And_Key) ) { 1.984 + PR_Sleep(PR_SecondsToInterval(1)); 1.985 + timeout++; 1.986 + if (timeout>=60) { 1.987 + printf("\nToken pulled and not reinserted early enough : aborting.\n"); 1.988 + exit(1); 1.989 + } 1.990 + } 1.991 + PR_Unlock(Cert_And_Key->lock); 1.992 + continue; 1.993 + /* try again to reduce code size */ 1.994 + } 1.995 + return SECSuccess; 1.996 + } 1.997 + } 1.998 + *pRetCert = NULL; 1.999 + *pRetKey = NULL; 1.1000 + return SECFailure; 1.1001 + } else { 1.1002 + /* no cert configured, automatically find the right cert. */ 1.1003 + CERTCertificate * cert = NULL; 1.1004 + SECKEYPrivateKey * privkey = NULL; 1.1005 + CERTCertNicknames * names; 1.1006 + int i; 1.1007 + void * proto_win = NULL; 1.1008 + SECStatus rv = SECFailure; 1.1009 + 1.1010 + if (Cert_And_Key) { 1.1011 + proto_win = Cert_And_Key->wincx; 1.1012 + } 1.1013 + 1.1014 + names = CERT_GetCertNicknames(CERT_GetDefaultCertDB(), 1.1015 + SEC_CERT_NICKNAMES_USER, proto_win); 1.1016 + if (names != NULL) { 1.1017 + for (i = 0; i < names->numnicknames; i++) { 1.1018 + cert = CERT_FindUserCertByUsage(CERT_GetDefaultCertDB(), 1.1019 + names->nicknames[i], certUsageSSLClient, 1.1020 + PR_FALSE, proto_win); 1.1021 + if ( !cert ) 1.1022 + continue; 1.1023 + /* Only check unexpired certs */ 1.1024 + if (CERT_CheckCertValidTimes(cert, PR_Now(), PR_TRUE) != 1.1025 + secCertTimeValid ) { 1.1026 + CERT_DestroyCertificate(cert); 1.1027 + continue; 1.1028 + } 1.1029 + rv = NSS_CmpCertChainWCANames(cert, caNames); 1.1030 + if ( rv == SECSuccess ) { 1.1031 + privkey = PK11_FindKeyByAnyCert(cert, proto_win); 1.1032 + if ( privkey ) 1.1033 + break; 1.1034 + } 1.1035 + rv = SECFailure; 1.1036 + CERT_DestroyCertificate(cert); 1.1037 + } 1.1038 + CERT_FreeNicknames(names); 1.1039 + } 1.1040 + if (rv == SECSuccess) { 1.1041 + *pRetCert = cert; 1.1042 + *pRetKey = privkey; 1.1043 + } 1.1044 + return rv; 1.1045 + } 1.1046 +} 1.1047 + 1.1048 +int 1.1049 +hexchar_to_int(int c) 1.1050 +{ 1.1051 + if (((c) >= '0') && ((c) <= '9')) 1.1052 + return (c) - '0'; 1.1053 + if (((c) >= 'a') && ((c) <= 'f')) 1.1054 + return (c) - 'a' + 10; 1.1055 + if (((c) >= 'A') && ((c) <= 'F')) 1.1056 + return (c) - 'A' + 10; 1.1057 + failed_already = 1; 1.1058 + return -1; 1.1059 +} 1.1060 + 1.1061 +void 1.1062 +client_main( 1.1063 + unsigned short port, 1.1064 + int connections, 1.1065 + cert_and_key* Cert_And_Key, 1.1066 + const char * hostName, 1.1067 + const char * sniHostName) 1.1068 +{ 1.1069 + PRFileDesc *model_sock = NULL; 1.1070 + int i; 1.1071 + int rv; 1.1072 + PRStatus status; 1.1073 + PRNetAddr addr; 1.1074 + 1.1075 + status = PR_StringToNetAddr(hostName, &addr); 1.1076 + if (status == PR_SUCCESS) { 1.1077 + addr.inet.port = PR_htons(port); 1.1078 + } else { 1.1079 + /* Lookup host */ 1.1080 + PRAddrInfo *addrInfo; 1.1081 + void *enumPtr = NULL; 1.1082 + 1.1083 + addrInfo = PR_GetAddrInfoByName(hostName, PR_AF_UNSPEC, 1.1084 + PR_AI_ADDRCONFIG | PR_AI_NOCANONNAME); 1.1085 + if (!addrInfo) { 1.1086 + SECU_PrintError(progName, "error looking up host"); 1.1087 + return; 1.1088 + } 1.1089 + do { 1.1090 + enumPtr = PR_EnumerateAddrInfo(enumPtr, addrInfo, port, &addr); 1.1091 + } while (enumPtr != NULL && 1.1092 + addr.raw.family != PR_AF_INET && 1.1093 + addr.raw.family != PR_AF_INET6); 1.1094 + PR_FreeAddrInfo(addrInfo); 1.1095 + if (enumPtr == NULL) { 1.1096 + SECU_PrintError(progName, "error looking up host address"); 1.1097 + return; 1.1098 + } 1.1099 + } 1.1100 + 1.1101 + /* all suites except RSA_NULL_MD5 are enabled by Domestic Policy */ 1.1102 + NSS_SetDomesticPolicy(); 1.1103 + 1.1104 + /* all the SSL2 and SSL3 cipher suites are enabled by default. */ 1.1105 + if (cipherString) { 1.1106 + int ndx; 1.1107 + 1.1108 + /* disable all the ciphers, then enable the ones we want. */ 1.1109 + disableAllSSLCiphers(); 1.1110 + 1.1111 + while (0 != (ndx = *cipherString)) { 1.1112 + const char * startCipher = cipherString++; 1.1113 + int cipher = 0; 1.1114 + SECStatus rv; 1.1115 + 1.1116 + if (ndx == ':') { 1.1117 + cipher = hexchar_to_int(*cipherString++); 1.1118 + cipher <<= 4; 1.1119 + cipher |= hexchar_to_int(*cipherString++); 1.1120 + cipher <<= 4; 1.1121 + cipher |= hexchar_to_int(*cipherString++); 1.1122 + cipher <<= 4; 1.1123 + cipher |= hexchar_to_int(*cipherString++); 1.1124 + if (cipher <= 0) { 1.1125 + fprintf(stderr, "strsclnt: Invalid cipher value: %-5.5s\n", 1.1126 + startCipher); 1.1127 + failed_already = 1; 1.1128 + return; 1.1129 + } 1.1130 + } else { 1.1131 + if (isalpha(ndx)) { 1.1132 + const int *cptr; 1.1133 + 1.1134 + cptr = islower(ndx) ? ssl3CipherSuites : ssl2CipherSuites; 1.1135 + for (ndx &= 0x1f; (cipher = *cptr++) != 0 && --ndx > 0; ) 1.1136 + /* do nothing */; 1.1137 + } 1.1138 + if (cipher <= 0) { 1.1139 + fprintf(stderr, "strsclnt: Invalid cipher letter: %c\n", 1.1140 + *startCipher); 1.1141 + failed_already = 1; 1.1142 + return; 1.1143 + } 1.1144 + } 1.1145 + rv = SSL_CipherPrefSetDefault(cipher, PR_TRUE); 1.1146 + if (rv != SECSuccess) { 1.1147 + fprintf(stderr, 1.1148 + "strsclnt: SSL_CipherPrefSetDefault(0x%04x) failed\n", 1.1149 + cipher); 1.1150 + failed_already = 1; 1.1151 + return; 1.1152 + } 1.1153 + } 1.1154 + } 1.1155 + 1.1156 + /* configure model SSL socket. */ 1.1157 + 1.1158 + model_sock = PR_OpenTCPSocket(addr.raw.family); 1.1159 + if (model_sock == NULL) { 1.1160 + errExit("PR_OpenTCPSocket for model socket"); 1.1161 + } 1.1162 + 1.1163 + model_sock = SSL_ImportFD(NULL, model_sock); 1.1164 + if (model_sock == NULL) { 1.1165 + errExit("SSL_ImportFD"); 1.1166 + } 1.1167 + 1.1168 + /* do SSL configuration. */ 1.1169 + 1.1170 + rv = SSL_OptionSet(model_sock, SSL_SECURITY, 1.1171 + enableSSL2 || enabledVersions.min != 0); 1.1172 + if (rv < 0) { 1.1173 + errExit("SSL_OptionSet SSL_SECURITY"); 1.1174 + } 1.1175 + 1.1176 + rv = SSL_VersionRangeSet(model_sock, &enabledVersions); 1.1177 + if (rv != SECSuccess) { 1.1178 + errExit("error setting SSL/TLS version range "); 1.1179 + } 1.1180 + 1.1181 + rv = SSL_OptionSet(model_sock, SSL_ENABLE_SSL2, enableSSL2); 1.1182 + if (rv != SECSuccess) { 1.1183 + errExit("error enabling SSLv2 "); 1.1184 + } 1.1185 + 1.1186 + rv = SSL_OptionSet(model_sock, SSL_V2_COMPATIBLE_HELLO, enableSSL2); 1.1187 + if (rv != SECSuccess) { 1.1188 + errExit("error enabling SSLv2 compatible hellos "); 1.1189 + } 1.1190 + 1.1191 + if (bigBuf.data) { /* doing FDX */ 1.1192 + rv = SSL_OptionSet(model_sock, SSL_ENABLE_FDX, 1); 1.1193 + if (rv < 0) { 1.1194 + errExit("SSL_OptionSet SSL_ENABLE_FDX"); 1.1195 + } 1.1196 + } 1.1197 + 1.1198 + if (NoReuse) { 1.1199 + rv = SSL_OptionSet(model_sock, SSL_NO_CACHE, 1); 1.1200 + if (rv < 0) { 1.1201 + errExit("SSL_OptionSet SSL_NO_CACHE"); 1.1202 + } 1.1203 + } 1.1204 + 1.1205 + if (bypassPKCS11) { 1.1206 + rv = SSL_OptionSet(model_sock, SSL_BYPASS_PKCS11, 1); 1.1207 + if (rv < 0) { 1.1208 + errExit("SSL_OptionSet SSL_BYPASS_PKCS11"); 1.1209 + } 1.1210 + } 1.1211 + 1.1212 + if (disableLocking) { 1.1213 + rv = SSL_OptionSet(model_sock, SSL_NO_LOCKS, 1); 1.1214 + if (rv < 0) { 1.1215 + errExit("SSL_OptionSet SSL_NO_LOCKS"); 1.1216 + } 1.1217 + } 1.1218 + 1.1219 + if (enableSessionTickets) { 1.1220 + rv = SSL_OptionSet(model_sock, SSL_ENABLE_SESSION_TICKETS, PR_TRUE); 1.1221 + if (rv != SECSuccess) 1.1222 + errExit("SSL_OptionSet SSL_ENABLE_SESSION_TICKETS"); 1.1223 + } 1.1224 + 1.1225 + if (enableCompression) { 1.1226 + rv = SSL_OptionSet(model_sock, SSL_ENABLE_DEFLATE, PR_TRUE); 1.1227 + if (rv != SECSuccess) 1.1228 + errExit("SSL_OptionSet SSL_ENABLE_DEFLATE"); 1.1229 + } 1.1230 + 1.1231 + if (enableFalseStart) { 1.1232 + rv = SSL_OptionSet(model_sock, SSL_ENABLE_FALSE_START, PR_TRUE); 1.1233 + if (rv != SECSuccess) 1.1234 + errExit("SSL_OptionSet SSL_ENABLE_FALSE_START"); 1.1235 + } 1.1236 + 1.1237 + if (enableCertStatus) { 1.1238 + rv = SSL_OptionSet(model_sock, SSL_ENABLE_OCSP_STAPLING, PR_TRUE); 1.1239 + if (rv != SECSuccess) 1.1240 + errExit("SSL_OptionSet SSL_ENABLE_OCSP_STAPLING"); 1.1241 + } 1.1242 + 1.1243 + SSL_SetPKCS11PinArg(model_sock, &pwdata); 1.1244 + 1.1245 + SSL_SetURL(model_sock, hostName); 1.1246 + 1.1247 + SSL_AuthCertificateHook(model_sock, mySSLAuthCertificate, 1.1248 + (void *)CERT_GetDefaultCertDB()); 1.1249 + SSL_BadCertHook(model_sock, myBadCertHandler, NULL); 1.1250 + 1.1251 + SSL_GetClientAuthDataHook(model_sock, StressClient_GetClientAuthData, (void*)Cert_And_Key); 1.1252 + 1.1253 + if (sniHostName) { 1.1254 + SSL_SetURL(model_sock, sniHostName); 1.1255 + } 1.1256 + /* I'm not going to set the HandshakeCallback function. */ 1.1257 + 1.1258 + /* end of ssl configuration. */ 1.1259 + 1.1260 + init_thread_data(); 1.1261 + 1.1262 + remaining_connections = total_connections = connections; 1.1263 + total_connections_modulo_100 = total_connections % 100; 1.1264 + total_connections_rounded_down_to_hundreds = 1.1265 + total_connections - total_connections_modulo_100; 1.1266 + 1.1267 + if (!NoReuse) { 1.1268 + remaining_connections = 1; 1.1269 + rv = launch_thread(do_connects, &addr, model_sock, 0); 1.1270 + /* wait for the first connection to terminate, then launch the rest. */ 1.1271 + reap_threads(); 1.1272 + remaining_connections = total_connections - 1 ; 1.1273 + } 1.1274 + if (remaining_connections > 0) { 1.1275 + active_threads = PR_MIN(active_threads, remaining_connections); 1.1276 + /* Start up the threads */ 1.1277 + for (i=0;i<active_threads;i++) { 1.1278 + rv = launch_thread(do_connects, &addr, model_sock, i); 1.1279 + } 1.1280 + reap_threads(); 1.1281 + } 1.1282 + destroy_thread_data(); 1.1283 + 1.1284 + PR_Close(model_sock); 1.1285 +} 1.1286 + 1.1287 +SECStatus 1.1288 +readBigFile(const char * fileName) 1.1289 +{ 1.1290 + PRFileInfo info; 1.1291 + PRStatus status; 1.1292 + SECStatus rv = SECFailure; 1.1293 + int count; 1.1294 + int hdrLen; 1.1295 + PRFileDesc *local_file_fd = NULL; 1.1296 + 1.1297 + status = PR_GetFileInfo(fileName, &info); 1.1298 + 1.1299 + if (status == PR_SUCCESS && 1.1300 + info.type == PR_FILE_FILE && 1.1301 + info.size > 0 && 1.1302 + NULL != (local_file_fd = PR_Open(fileName, PR_RDONLY, 0))) { 1.1303 + 1.1304 + hdrLen = PORT_Strlen(outHeader); 1.1305 + bigBuf.len = hdrLen + info.size; 1.1306 + bigBuf.data = PORT_Malloc(bigBuf.len + 4095); 1.1307 + if (!bigBuf.data) { 1.1308 + errWarn("PORT_Malloc"); 1.1309 + goto done; 1.1310 + } 1.1311 + 1.1312 + PORT_Memcpy(bigBuf.data, outHeader, hdrLen); 1.1313 + 1.1314 + count = PR_Read(local_file_fd, bigBuf.data + hdrLen, info.size); 1.1315 + if (count != info.size) { 1.1316 + errWarn("PR_Read local file"); 1.1317 + goto done; 1.1318 + } 1.1319 + rv = SECSuccess; 1.1320 +done: 1.1321 + PR_Close(local_file_fd); 1.1322 + } 1.1323 + return rv; 1.1324 +} 1.1325 + 1.1326 +int 1.1327 +main(int argc, char **argv) 1.1328 +{ 1.1329 + const char * dir = "."; 1.1330 + const char * fileName = NULL; 1.1331 + char * hostName = NULL; 1.1332 + char * nickName = NULL; 1.1333 + char * tmp = NULL; 1.1334 + int connections = 1; 1.1335 + int exitVal; 1.1336 + int tmpInt; 1.1337 + unsigned short port = 443; 1.1338 + SECStatus rv; 1.1339 + PLOptState * optstate; 1.1340 + PLOptStatus status; 1.1341 + cert_and_key Cert_And_Key; 1.1342 + char * sniHostName = NULL; 1.1343 + 1.1344 + /* Call the NSPR initialization routines */ 1.1345 + PR_Init( PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); 1.1346 + SSL_VersionRangeGetSupported(ssl_variant_stream, &enabledVersions); 1.1347 + 1.1348 + tmp = strrchr(argv[0], '/'); 1.1349 + tmp = tmp ? tmp + 1 : argv[0]; 1.1350 + progName = strrchr(tmp, '\\'); 1.1351 + progName = progName ? progName + 1 : tmp; 1.1352 + 1.1353 + 1.1354 + optstate = PL_CreateOptState(argc, argv, 1.1355 + "BC:DNP:TUV:W:a:c:d:f:gin:op:qst:uvw:z"); 1.1356 + while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) { 1.1357 + switch(optstate->option) { 1.1358 + case 'B': bypassPKCS11 = PR_TRUE; break; 1.1359 + 1.1360 + case 'C': cipherString = optstate->value; break; 1.1361 + 1.1362 + case 'D': NoDelay = PR_TRUE; break; 1.1363 + 1.1364 + case 'I': /* reserved for OCSP multi-stapling */ break; 1.1365 + 1.1366 + case 'N': NoReuse = 1; break; 1.1367 + 1.1368 + case 'P': fullhs = PORT_Atoi(optstate->value); break; 1.1369 + 1.1370 + case 'T': enableCertStatus = PR_TRUE; break; 1.1371 + 1.1372 + case 'U': ThrottleUp = PR_TRUE; break; 1.1373 + 1.1374 + case 'V': if (SECU_ParseSSLVersionRangeString(optstate->value, 1.1375 + enabledVersions, enableSSL2, 1.1376 + &enabledVersions, &enableSSL2) != SECSuccess) { 1.1377 + Usage(progName); 1.1378 + } 1.1379 + break; 1.1380 + 1.1381 + case 'a': sniHostName = PL_strdup(optstate->value); break; 1.1382 + 1.1383 + case 'c': connections = PORT_Atoi(optstate->value); break; 1.1384 + 1.1385 + case 'd': dir = optstate->value; break; 1.1386 + 1.1387 + case 'f': fileName = optstate->value; break; 1.1388 + 1.1389 + case 'g': enableFalseStart = PR_TRUE; break; 1.1390 + 1.1391 + case 'i': ignoreErrors = PR_TRUE; break; 1.1392 + 1.1393 + case 'n': nickName = PL_strdup(optstate->value); break; 1.1394 + 1.1395 + case 'o': MakeCertOK++; break; 1.1396 + 1.1397 + case 'p': port = PORT_Atoi(optstate->value); break; 1.1398 + 1.1399 + case 'q': QuitOnTimeout = PR_TRUE; break; 1.1400 + 1.1401 + case 's': disableLocking = PR_TRUE; break; 1.1402 + 1.1403 + case 't': 1.1404 + tmpInt = PORT_Atoi(optstate->value); 1.1405 + if (tmpInt > 0 && tmpInt < MAX_THREADS) 1.1406 + max_threads = active_threads = tmpInt; 1.1407 + break; 1.1408 + 1.1409 + case 'u': enableSessionTickets = PR_TRUE; break; 1.1410 + 1.1411 + case 'v': verbose++; break; 1.1412 + 1.1413 + case 'w': 1.1414 + pwdata.source = PW_PLAINTEXT; 1.1415 + pwdata.data = PL_strdup(optstate->value); 1.1416 + break; 1.1417 + 1.1418 + case 'W': 1.1419 + pwdata.source = PW_FROMFILE; 1.1420 + pwdata.data = PL_strdup(optstate->value); 1.1421 + break; 1.1422 + 1.1423 + case 'z': enableCompression = PR_TRUE; break; 1.1424 + 1.1425 + case 0: /* positional parameter */ 1.1426 + if (hostName) { 1.1427 + Usage(progName); 1.1428 + } 1.1429 + hostName = PL_strdup(optstate->value); 1.1430 + break; 1.1431 + 1.1432 + default: 1.1433 + case '?': 1.1434 + Usage(progName); 1.1435 + break; 1.1436 + 1.1437 + } 1.1438 + } 1.1439 + PL_DestroyOptState(optstate); 1.1440 + 1.1441 + if (!hostName || status == PL_OPT_BAD) 1.1442 + Usage(progName); 1.1443 + 1.1444 + if (fullhs!= NO_FULLHS_PERCENTAGE && (fullhs < 0 || fullhs>100 || NoReuse) ) 1.1445 + Usage(progName); 1.1446 + 1.1447 + if (port == 0) 1.1448 + Usage(progName); 1.1449 + 1.1450 + if (fileName) 1.1451 + readBigFile(fileName); 1.1452 + 1.1453 + PK11_SetPasswordFunc(SECU_GetModulePassword); 1.1454 + 1.1455 + tmp = PR_GetEnv("NSS_DEBUG_TIMEOUT"); 1.1456 + if (tmp && tmp[0]) { 1.1457 + int sec = PORT_Atoi(tmp); 1.1458 + if (sec > 0) { 1.1459 + maxInterval = PR_SecondsToInterval(sec); 1.1460 + } 1.1461 + } 1.1462 + 1.1463 + /* Call the NSS initialization routines */ 1.1464 + rv = NSS_Initialize(dir, "", "", SECMOD_DB, NSS_INIT_READONLY); 1.1465 + if (rv != SECSuccess) { 1.1466 + fputs("NSS_Init failed.\n", stderr); 1.1467 + exit(1); 1.1468 + } 1.1469 + ssl3stats = SSL_GetStatistics(); 1.1470 + Cert_And_Key.lock = PR_NewLock(); 1.1471 + Cert_And_Key.nickname = nickName; 1.1472 + Cert_And_Key.wincx = &pwdata; 1.1473 + Cert_And_Key.cert = NULL; 1.1474 + Cert_And_Key.key = NULL; 1.1475 + 1.1476 + if (PR_FALSE == FindCertAndKey(&Cert_And_Key)) { 1.1477 + 1.1478 + if (Cert_And_Key.cert == NULL) { 1.1479 + fprintf(stderr, "strsclnt: Can't find certificate %s\n", Cert_And_Key.nickname); 1.1480 + exit(1); 1.1481 + } 1.1482 + 1.1483 + if (Cert_And_Key.key == NULL) { 1.1484 + fprintf(stderr, "strsclnt: Can't find Private Key for cert %s\n", 1.1485 + Cert_And_Key.nickname); 1.1486 + exit(1); 1.1487 + } 1.1488 + 1.1489 + } 1.1490 + 1.1491 + client_main(port, connections, &Cert_And_Key, hostName, 1.1492 + sniHostName); 1.1493 + 1.1494 + /* clean up */ 1.1495 + if (Cert_And_Key.cert) { 1.1496 + CERT_DestroyCertificate(Cert_And_Key.cert); 1.1497 + } 1.1498 + if (Cert_And_Key.key) { 1.1499 + SECKEY_DestroyPrivateKey(Cert_And_Key.key); 1.1500 + } 1.1501 + 1.1502 + PR_DestroyLock(Cert_And_Key.lock); 1.1503 + 1.1504 + if (pwdata.data) { 1.1505 + PL_strfree(pwdata.data); 1.1506 + } 1.1507 + if (Cert_And_Key.nickname) { 1.1508 + PL_strfree(Cert_And_Key.nickname); 1.1509 + } 1.1510 + if (sniHostName) { 1.1511 + PL_strfree(sniHostName); 1.1512 + } 1.1513 + 1.1514 + PL_strfree(hostName); 1.1515 + 1.1516 + /* some final stats. */ 1.1517 + if (ssl3stats->hsh_sid_cache_hits + 1.1518 + ssl3stats->hsh_sid_cache_misses + 1.1519 + ssl3stats->hsh_sid_cache_not_ok + 1.1520 + ssl3stats->hsh_sid_stateless_resumes == 0) { 1.1521 + /* presumably we were testing SSL2. */ 1.1522 + printf("strsclnt: SSL2 - %d server certificates tested.\n", 1.1523 + certsTested); 1.1524 + } else { 1.1525 + printf( 1.1526 + "strsclnt: %ld cache hits; %ld cache misses, %ld cache not reusable\n" 1.1527 + " %ld stateless resumes\n", 1.1528 + ssl3stats->hsh_sid_cache_hits, 1.1529 + ssl3stats->hsh_sid_cache_misses, 1.1530 + ssl3stats->hsh_sid_cache_not_ok, 1.1531 + ssl3stats->hsh_sid_stateless_resumes); 1.1532 + } 1.1533 + 1.1534 + if (!NoReuse) { 1.1535 + if (enableSessionTickets) 1.1536 + exitVal = (ssl3stats->hsh_sid_stateless_resumes == 0); 1.1537 + else 1.1538 + exitVal = (ssl3stats->hsh_sid_cache_misses > 1) || 1.1539 + (ssl3stats->hsh_sid_stateless_resumes != 0); 1.1540 + if (!exitVal) 1.1541 + exitVal = (ssl3stats->hsh_sid_cache_not_ok != 0) || 1.1542 + (certsTested > 1); 1.1543 + } else { 1.1544 + printf("strsclnt: NoReuse - %d server certificates tested.\n", 1.1545 + certsTested); 1.1546 + if (ssl3stats->hsh_sid_cache_hits + 1.1547 + ssl3stats->hsh_sid_cache_misses + 1.1548 + ssl3stats->hsh_sid_cache_not_ok + 1.1549 + ssl3stats->hsh_sid_stateless_resumes > 0) { 1.1550 + exitVal = (ssl3stats->hsh_sid_cache_misses != connections) || 1.1551 + (ssl3stats->hsh_sid_stateless_resumes != 0) || 1.1552 + (certsTested != connections); 1.1553 + } else { /* ssl2 connections */ 1.1554 + exitVal = (certsTested != connections); 1.1555 + } 1.1556 + } 1.1557 + 1.1558 + exitVal = ( exitVal || failed_already ); 1.1559 + SSL_ClearSessionCache(); 1.1560 + if (NSS_Shutdown() != SECSuccess) { 1.1561 + printf("strsclnt: NSS_Shutdown() failed.\n"); 1.1562 + exit(1); 1.1563 + } 1.1564 + 1.1565 + PR_Cleanup(); 1.1566 + return exitVal; 1.1567 +} 1.1568 +