security/nss/cmd/strsclnt/strsclnt.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4 #include <stdio.h>
michael@0 5 #include <string.h>
michael@0 6
michael@0 7 #include "secutil.h"
michael@0 8 #include "basicutil.h"
michael@0 9
michael@0 10 #if defined(XP_UNIX)
michael@0 11 #include <unistd.h>
michael@0 12 #endif
michael@0 13 #include <stdlib.h>
michael@0 14 #include <errno.h>
michael@0 15 #include <fcntl.h>
michael@0 16 #include <stdarg.h>
michael@0 17
michael@0 18 #include "plgetopt.h"
michael@0 19
michael@0 20 #include "nspr.h"
michael@0 21 #include "prio.h"
michael@0 22 #include "prnetdb.h"
michael@0 23 #include "prerror.h"
michael@0 24
michael@0 25 #include "pk11func.h"
michael@0 26 #include "secitem.h"
michael@0 27 #include "sslproto.h"
michael@0 28 #include "nss.h"
michael@0 29 #include "ssl.h"
michael@0 30
michael@0 31 #ifndef PORT_Sprintf
michael@0 32 #define PORT_Sprintf sprintf
michael@0 33 #endif
michael@0 34
michael@0 35 #ifndef PORT_Strstr
michael@0 36 #define PORT_Strstr strstr
michael@0 37 #endif
michael@0 38
michael@0 39 #ifndef PORT_Malloc
michael@0 40 #define PORT_Malloc PR_Malloc
michael@0 41 #endif
michael@0 42
michael@0 43 #define RD_BUF_SIZE (60 * 1024)
michael@0 44
michael@0 45 /* Include these cipher suite arrays to re-use tstclnt's
michael@0 46 * cipher selection code.
michael@0 47 */
michael@0 48
michael@0 49 int ssl2CipherSuites[] = {
michael@0 50 SSL_EN_RC4_128_WITH_MD5, /* A */
michael@0 51 SSL_EN_RC4_128_EXPORT40_WITH_MD5, /* B */
michael@0 52 SSL_EN_RC2_128_CBC_WITH_MD5, /* C */
michael@0 53 SSL_EN_RC2_128_CBC_EXPORT40_WITH_MD5, /* D */
michael@0 54 SSL_EN_DES_64_CBC_WITH_MD5, /* E */
michael@0 55 SSL_EN_DES_192_EDE3_CBC_WITH_MD5, /* F */
michael@0 56 0
michael@0 57 };
michael@0 58
michael@0 59 int ssl3CipherSuites[] = {
michael@0 60 -1, /* SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA* a */
michael@0 61 -1, /* SSL_FORTEZZA_DMS_WITH_RC4_128_SHA * b */
michael@0 62 TLS_RSA_WITH_RC4_128_MD5, /* c */
michael@0 63 TLS_RSA_WITH_3DES_EDE_CBC_SHA, /* d */
michael@0 64 TLS_RSA_WITH_DES_CBC_SHA, /* e */
michael@0 65 TLS_RSA_EXPORT_WITH_RC4_40_MD5, /* f */
michael@0 66 TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5, /* g */
michael@0 67 -1, /* SSL_FORTEZZA_DMS_WITH_NULL_SHA * h */
michael@0 68 TLS_RSA_WITH_NULL_MD5, /* i */
michael@0 69 SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA, /* j */
michael@0 70 SSL_RSA_FIPS_WITH_DES_CBC_SHA, /* k */
michael@0 71 TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA, /* l */
michael@0 72 TLS_RSA_EXPORT1024_WITH_RC4_56_SHA, /* m */
michael@0 73 TLS_RSA_WITH_RC4_128_SHA, /* n */
michael@0 74 TLS_DHE_DSS_WITH_RC4_128_SHA, /* o */
michael@0 75 TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, /* p */
michael@0 76 TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA, /* q */
michael@0 77 TLS_DHE_RSA_WITH_DES_CBC_SHA, /* r */
michael@0 78 TLS_DHE_DSS_WITH_DES_CBC_SHA, /* s */
michael@0 79 TLS_DHE_DSS_WITH_AES_128_CBC_SHA, /* t */
michael@0 80 TLS_DHE_RSA_WITH_AES_128_CBC_SHA, /* u */
michael@0 81 TLS_RSA_WITH_AES_128_CBC_SHA, /* v */
michael@0 82 TLS_DHE_DSS_WITH_AES_256_CBC_SHA, /* w */
michael@0 83 TLS_DHE_RSA_WITH_AES_256_CBC_SHA, /* x */
michael@0 84 TLS_RSA_WITH_AES_256_CBC_SHA, /* y */
michael@0 85 TLS_RSA_WITH_NULL_SHA, /* z */
michael@0 86 0
michael@0 87 };
michael@0 88
michael@0 89 #define NO_FULLHS_PERCENTAGE -1
michael@0 90
michael@0 91 /* This global string is so that client main can see
michael@0 92 * which ciphers to use.
michael@0 93 */
michael@0 94
michael@0 95 static const char *cipherString;
michael@0 96
michael@0 97 static PRInt32 certsTested;
michael@0 98 static int MakeCertOK;
michael@0 99 static int NoReuse;
michael@0 100 static int fullhs = NO_FULLHS_PERCENTAGE; /* percentage of full handshakes to
michael@0 101 ** perform */
michael@0 102 static PRInt32 globalconid = 0; /* atomically set */
michael@0 103 static int total_connections; /* total number of connections to perform */
michael@0 104 static int total_connections_rounded_down_to_hundreds;
michael@0 105 static int total_connections_modulo_100;
michael@0 106
michael@0 107 static PRBool NoDelay;
michael@0 108 static PRBool QuitOnTimeout = PR_FALSE;
michael@0 109 static PRBool ThrottleUp = PR_FALSE;
michael@0 110
michael@0 111 static PRLock * threadLock; /* protects the global variables below */
michael@0 112 static PRTime lastConnectFailure;
michael@0 113 static PRTime lastConnectSuccess;
michael@0 114 static PRTime lastThrottleUp;
michael@0 115 static PRInt32 remaining_connections; /* number of connections left */
michael@0 116 static int active_threads = 8; /* number of threads currently trying to
michael@0 117 ** connect */
michael@0 118 static PRInt32 numUsed;
michael@0 119 /* end of variables protected by threadLock */
michael@0 120
michael@0 121 static SSL3Statistics * ssl3stats;
michael@0 122
michael@0 123 static int failed_already = 0;
michael@0 124 static SSLVersionRange enabledVersions;
michael@0 125 static PRBool enableSSL2 = PR_TRUE;
michael@0 126 static PRBool bypassPKCS11 = PR_FALSE;
michael@0 127 static PRBool disableLocking = PR_FALSE;
michael@0 128 static PRBool ignoreErrors = PR_FALSE;
michael@0 129 static PRBool enableSessionTickets = PR_FALSE;
michael@0 130 static PRBool enableCompression = PR_FALSE;
michael@0 131 static PRBool enableFalseStart = PR_FALSE;
michael@0 132 static PRBool enableCertStatus = PR_FALSE;
michael@0 133
michael@0 134 PRIntervalTime maxInterval = PR_INTERVAL_NO_TIMEOUT;
michael@0 135
michael@0 136 char * progName;
michael@0 137
michael@0 138 secuPWData pwdata = { PW_NONE, 0 };
michael@0 139
michael@0 140 int stopping;
michael@0 141 int verbose;
michael@0 142 SECItem bigBuf;
michael@0 143
michael@0 144 #define PRINTF if (verbose) printf
michael@0 145 #define FPRINTF if (verbose) fprintf
michael@0 146
michael@0 147 static void
michael@0 148 Usage(const char *progName)
michael@0 149 {
michael@0 150 fprintf(stderr,
michael@0 151 "Usage: %s [-n nickname] [-p port] [-d dbdir] [-c connections]\n"
michael@0 152 " [-BDNovqs] [-f filename] [-N | -P percentage]\n"
michael@0 153 " [-w dbpasswd] [-C cipher(s)] [-t threads] [-W pwfile]\n"
michael@0 154 " [-V [min-version]:[max-version]] [-a sniHostName] hostname\n"
michael@0 155 " where -v means verbose\n"
michael@0 156 " -o flag is interpreted as follows:\n"
michael@0 157 " 1 -o means override the result of server certificate validation.\n"
michael@0 158 " 2 -o's mean skip server certificate validation altogether.\n"
michael@0 159 " -D means no TCP delays\n"
michael@0 160 " -q means quit when server gone (timeout rather than retry forever)\n"
michael@0 161 " -s means disable SSL socket locking\n"
michael@0 162 " -N means no session reuse\n"
michael@0 163 " -P means do a specified percentage of full handshakes (0-100)\n"
michael@0 164 " -V [min]:[max] restricts the set of enabled SSL/TLS protocols versions.\n"
michael@0 165 " All versions are enabled by default.\n"
michael@0 166 " Possible values for min/max: ssl2 ssl3 tls1.0 tls1.1 tls1.2\n"
michael@0 167 " Example: \"-V ssl3:\" enables SSL 3 and newer.\n"
michael@0 168 " -U means enable throttling up threads\n"
michael@0 169 " -B bypasses the PKCS11 layer for SSL encryption and MACing\n"
michael@0 170 " -T enable the cert_status extension (OCSP stapling)\n"
michael@0 171 " -u enable TLS Session Ticket extension\n"
michael@0 172 " -z enable compression\n"
michael@0 173 " -g enable false start\n",
michael@0 174 progName);
michael@0 175 exit(1);
michael@0 176 }
michael@0 177
michael@0 178
michael@0 179 static void
michael@0 180 errWarn(char * funcString)
michael@0 181 {
michael@0 182 PRErrorCode perr = PR_GetError();
michael@0 183 PRInt32 oserr = PR_GetOSError();
michael@0 184 const char * errString = SECU_Strerror(perr);
michael@0 185
michael@0 186 fprintf(stderr, "strsclnt: %s returned error %d, OS error %d: %s\n",
michael@0 187 funcString, perr, oserr, errString);
michael@0 188 }
michael@0 189
michael@0 190 static void
michael@0 191 errExit(char * funcString)
michael@0 192 {
michael@0 193 errWarn(funcString);
michael@0 194 exit(1);
michael@0 195 }
michael@0 196
michael@0 197 /**************************************************************************
michael@0 198 **
michael@0 199 ** Routines for disabling SSL ciphers.
michael@0 200 **
michael@0 201 **************************************************************************/
michael@0 202
michael@0 203 void
michael@0 204 disableAllSSLCiphers(void)
michael@0 205 {
michael@0 206 const PRUint16 *cipherSuites = SSL_GetImplementedCiphers();
michael@0 207 int i = SSL_GetNumImplementedCiphers();
michael@0 208 SECStatus rv;
michael@0 209
michael@0 210 /* disable all the SSL3 cipher suites */
michael@0 211 while (--i >= 0) {
michael@0 212 PRUint16 suite = cipherSuites[i];
michael@0 213 rv = SSL_CipherPrefSetDefault(suite, PR_FALSE);
michael@0 214 if (rv != SECSuccess) {
michael@0 215 printf("SSL_CipherPrefSetDefault didn't like value 0x%04x (i = %d)\n",
michael@0 216 suite, i);
michael@0 217 errWarn("SSL_CipherPrefSetDefault");
michael@0 218 exit(2);
michael@0 219 }
michael@0 220 }
michael@0 221 }
michael@0 222
michael@0 223 /* This invokes the "default" AuthCert handler in libssl.
michael@0 224 ** The only reason to use this one is that it prints out info as it goes.
michael@0 225 */
michael@0 226 static SECStatus
michael@0 227 mySSLAuthCertificate(void *arg, PRFileDesc *fd, PRBool checkSig,
michael@0 228 PRBool isServer)
michael@0 229 {
michael@0 230 SECStatus rv;
michael@0 231 CERTCertificate * peerCert;
michael@0 232 const SECItemArray *csa;
michael@0 233
michael@0 234 if (MakeCertOK>=2) {
michael@0 235 return SECSuccess;
michael@0 236 }
michael@0 237 peerCert = SSL_PeerCertificate(fd);
michael@0 238
michael@0 239 PRINTF("strsclnt: Subject: %s\nstrsclnt: Issuer : %s\n",
michael@0 240 peerCert->subjectName, peerCert->issuerName);
michael@0 241 csa = SSL_PeerStapledOCSPResponses(fd);
michael@0 242 if (csa) {
michael@0 243 PRINTF("Received %d Cert Status items (OCSP stapled data)\n",
michael@0 244 csa->len);
michael@0 245 }
michael@0 246 /* invoke the "default" AuthCert handler. */
michael@0 247 rv = SSL_AuthCertificate(arg, fd, checkSig, isServer);
michael@0 248
michael@0 249 PR_ATOMIC_INCREMENT(&certsTested);
michael@0 250 if (rv == SECSuccess) {
michael@0 251 fputs("strsclnt: -- SSL: Server Certificate Validated.\n", stderr);
michael@0 252 }
michael@0 253 CERT_DestroyCertificate(peerCert);
michael@0 254 /* error, if any, will be displayed by the Bad Cert Handler. */
michael@0 255 return rv;
michael@0 256 }
michael@0 257
michael@0 258 static SECStatus
michael@0 259 myBadCertHandler( void *arg, PRFileDesc *fd)
michael@0 260 {
michael@0 261 PRErrorCode err = PR_GetError();
michael@0 262 if (!MakeCertOK)
michael@0 263 fprintf(stderr,
michael@0 264 "strsclnt: -- SSL: Server Certificate Invalid, err %d.\n%s\n",
michael@0 265 err, SECU_Strerror(err));
michael@0 266 return (MakeCertOK ? SECSuccess : SECFailure);
michael@0 267 }
michael@0 268
michael@0 269 void
michael@0 270 printSecurityInfo(PRFileDesc *fd)
michael@0 271 {
michael@0 272 CERTCertificate * cert = NULL;
michael@0 273 SSL3Statistics * ssl3stats = SSL_GetStatistics();
michael@0 274 SECStatus result;
michael@0 275 SSLChannelInfo channel;
michael@0 276 SSLCipherSuiteInfo suite;
michael@0 277
michael@0 278 static int only_once;
michael@0 279
michael@0 280 if (only_once && verbose < 2)
michael@0 281 return;
michael@0 282 only_once = 1;
michael@0 283
michael@0 284 result = SSL_GetChannelInfo(fd, &channel, sizeof channel);
michael@0 285 if (result == SECSuccess &&
michael@0 286 channel.length == sizeof channel &&
michael@0 287 channel.cipherSuite) {
michael@0 288 result = SSL_GetCipherSuiteInfo(channel.cipherSuite,
michael@0 289 &suite, sizeof suite);
michael@0 290 if (result == SECSuccess) {
michael@0 291 FPRINTF(stderr,
michael@0 292 "strsclnt: SSL version %d.%d using %d-bit %s with %d-bit %s MAC\n",
michael@0 293 channel.protocolVersion >> 8, channel.protocolVersion & 0xff,
michael@0 294 suite.effectiveKeyBits, suite.symCipherName,
michael@0 295 suite.macBits, suite.macAlgorithmName);
michael@0 296 FPRINTF(stderr,
michael@0 297 "strsclnt: Server Auth: %d-bit %s, Key Exchange: %d-bit %s\n"
michael@0 298 " Compression: %s\n",
michael@0 299 channel.authKeyBits, suite.authAlgorithmName,
michael@0 300 channel.keaKeyBits, suite.keaTypeName,
michael@0 301 channel.compressionMethodName);
michael@0 302 }
michael@0 303 }
michael@0 304
michael@0 305 cert = SSL_LocalCertificate(fd);
michael@0 306 if (!cert)
michael@0 307 cert = SSL_PeerCertificate(fd);
michael@0 308
michael@0 309 if (verbose && cert) {
michael@0 310 char * ip = CERT_NameToAscii(&cert->issuer);
michael@0 311 char * sp = CERT_NameToAscii(&cert->subject);
michael@0 312 if (sp) {
michael@0 313 fprintf(stderr, "strsclnt: subject DN: %s\n", sp);
michael@0 314 PORT_Free(sp);
michael@0 315 }
michael@0 316 if (ip) {
michael@0 317 fprintf(stderr, "strsclnt: issuer DN: %s\n", ip);
michael@0 318 PORT_Free(ip);
michael@0 319 }
michael@0 320 }
michael@0 321 if (cert) {
michael@0 322 CERT_DestroyCertificate(cert);
michael@0 323 cert = NULL;
michael@0 324 }
michael@0 325 fprintf(stderr,
michael@0 326 "strsclnt: %ld cache hits; %ld cache misses, %ld cache not reusable\n"
michael@0 327 " %ld stateless resumes\n",
michael@0 328 ssl3stats->hsh_sid_cache_hits,
michael@0 329 ssl3stats->hsh_sid_cache_misses,
michael@0 330 ssl3stats->hsh_sid_cache_not_ok,
michael@0 331 ssl3stats->hsh_sid_stateless_resumes);
michael@0 332
michael@0 333 }
michael@0 334
michael@0 335 /**************************************************************************
michael@0 336 ** Begin thread management routines and data.
michael@0 337 **************************************************************************/
michael@0 338
michael@0 339 #define MAX_THREADS 128
michael@0 340
michael@0 341 typedef int startFn(void *a, void *b, int c);
michael@0 342
michael@0 343
michael@0 344 static PRInt32 numConnected;
michael@0 345 static int max_threads; /* peak threads allowed */
michael@0 346
michael@0 347 typedef struct perThreadStr {
michael@0 348 void * a;
michael@0 349 void * b;
michael@0 350 int tid;
michael@0 351 int rv;
michael@0 352 startFn * startFunc;
michael@0 353 PRThread * prThread;
michael@0 354 PRBool inUse;
michael@0 355 } perThread;
michael@0 356
michael@0 357 perThread threads[MAX_THREADS];
michael@0 358
michael@0 359 void
michael@0 360 thread_wrapper(void * arg)
michael@0 361 {
michael@0 362 perThread * slot = (perThread *)arg;
michael@0 363 PRBool done = PR_FALSE;
michael@0 364
michael@0 365 do {
michael@0 366 PRBool doop = PR_FALSE;
michael@0 367 PRBool dosleep = PR_FALSE;
michael@0 368 PRTime now = PR_Now();
michael@0 369
michael@0 370 PR_Lock(threadLock);
michael@0 371 if (! (slot->tid < active_threads)) {
michael@0 372 /* this thread isn't supposed to be running */
michael@0 373 if (!ThrottleUp) {
michael@0 374 /* we'll never need this thread again, so abort it */
michael@0 375 done = PR_TRUE;
michael@0 376 } else if (remaining_connections > 0) {
michael@0 377 /* we may still need this thread, so just sleep for 1s */
michael@0 378 dosleep = PR_TRUE;
michael@0 379 /* the conditions to trigger a throttle up are :
michael@0 380 ** 1. last PR_Connect failure must have happened more than
michael@0 381 ** 10s ago
michael@0 382 ** 2. last throttling up must have happened more than 0.5s ago
michael@0 383 ** 3. there must be a more recent PR_Connect success than
michael@0 384 ** failure
michael@0 385 */
michael@0 386 if ( (now - lastConnectFailure > 10 * PR_USEC_PER_SEC) &&
michael@0 387 ( (!lastThrottleUp) || ( (now - lastThrottleUp) >=
michael@0 388 (PR_USEC_PER_SEC/2)) ) &&
michael@0 389 (lastConnectSuccess > lastConnectFailure) ) {
michael@0 390 /* try throttling up by one thread */
michael@0 391 active_threads = PR_MIN(max_threads, active_threads+1);
michael@0 392 fprintf(stderr,"active_threads set up to %d\n",
michael@0 393 active_threads);
michael@0 394 lastThrottleUp = PR_MAX(now, lastThrottleUp);
michael@0 395 }
michael@0 396 } else {
michael@0 397 /* no more connections left, we are done */
michael@0 398 done = PR_TRUE;
michael@0 399 }
michael@0 400 } else {
michael@0 401 /* this thread should run */
michael@0 402 if (--remaining_connections >= 0) { /* protected by threadLock */
michael@0 403 doop = PR_TRUE;
michael@0 404 } else {
michael@0 405 done = PR_TRUE;
michael@0 406 }
michael@0 407 }
michael@0 408 PR_Unlock(threadLock);
michael@0 409 if (doop) {
michael@0 410 slot->rv = (* slot->startFunc)(slot->a, slot->b, slot->tid);
michael@0 411 PRINTF("strsclnt: Thread in slot %d returned %d\n",
michael@0 412 slot->tid, slot->rv);
michael@0 413 }
michael@0 414 if (dosleep) {
michael@0 415 PR_Sleep(PR_SecondsToInterval(1));
michael@0 416 }
michael@0 417 } while (!done && (!failed_already || ignoreErrors));
michael@0 418 }
michael@0 419
michael@0 420 SECStatus
michael@0 421 launch_thread(
michael@0 422 startFn * startFunc,
michael@0 423 void * a,
michael@0 424 void * b,
michael@0 425 int tid)
michael@0 426 {
michael@0 427 PRUint32 i;
michael@0 428 perThread * slot;
michael@0 429
michael@0 430 PR_Lock(threadLock);
michael@0 431
michael@0 432 PORT_Assert(numUsed < MAX_THREADS);
michael@0 433 if (! (numUsed < MAX_THREADS)) {
michael@0 434 PR_Unlock(threadLock);
michael@0 435 return SECFailure;
michael@0 436 }
michael@0 437
michael@0 438 i = numUsed++;
michael@0 439 slot = &threads[i];
michael@0 440 slot->a = a;
michael@0 441 slot->b = b;
michael@0 442 slot->tid = tid;
michael@0 443
michael@0 444 slot->startFunc = startFunc;
michael@0 445
michael@0 446 slot->prThread = PR_CreateThread(PR_USER_THREAD,
michael@0 447 thread_wrapper, slot,
michael@0 448 PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
michael@0 449 PR_JOINABLE_THREAD, 0);
michael@0 450 if (slot->prThread == NULL) {
michael@0 451 PR_Unlock(threadLock);
michael@0 452 printf("strsclnt: Failed to launch thread!\n");
michael@0 453 return SECFailure;
michael@0 454 }
michael@0 455
michael@0 456 slot->inUse = 1;
michael@0 457 PR_Unlock(threadLock);
michael@0 458 PRINTF("strsclnt: Launched thread in slot %d \n", i);
michael@0 459
michael@0 460 return SECSuccess;
michael@0 461 }
michael@0 462
michael@0 463 /* join all the threads */
michael@0 464 int
michael@0 465 reap_threads(void)
michael@0 466 {
michael@0 467 int i;
michael@0 468
michael@0 469 for (i = 0; i < MAX_THREADS; ++i) {
michael@0 470 if (threads[i].prThread) {
michael@0 471 PR_JoinThread(threads[i].prThread);
michael@0 472 threads[i].prThread = NULL;
michael@0 473 }
michael@0 474 }
michael@0 475 return 0;
michael@0 476 }
michael@0 477
michael@0 478 void
michael@0 479 destroy_thread_data(void)
michael@0 480 {
michael@0 481 PORT_Memset(threads, 0, sizeof threads);
michael@0 482
michael@0 483 if (threadLock) {
michael@0 484 PR_DestroyLock(threadLock);
michael@0 485 threadLock = NULL;
michael@0 486 }
michael@0 487 }
michael@0 488
michael@0 489 void
michael@0 490 init_thread_data(void)
michael@0 491 {
michael@0 492 threadLock = PR_NewLock();
michael@0 493 }
michael@0 494
michael@0 495 /**************************************************************************
michael@0 496 ** End thread management routines.
michael@0 497 **************************************************************************/
michael@0 498
michael@0 499 PRBool useModelSocket = PR_TRUE;
michael@0 500
michael@0 501 static const char stopCmd[] = { "GET /stop " };
michael@0 502 static const char outHeader[] = {
michael@0 503 "HTTP/1.0 200 OK\r\n"
michael@0 504 "Server: Netscape-Enterprise/2.0a\r\n"
michael@0 505 "Date: Tue, 26 Aug 1997 22:10:05 GMT\r\n"
michael@0 506 "Content-type: text/plain\r\n"
michael@0 507 "\r\n"
michael@0 508 };
michael@0 509
michael@0 510 struct lockedVarsStr {
michael@0 511 PRLock * lock;
michael@0 512 int count;
michael@0 513 int waiters;
michael@0 514 PRCondVar * condVar;
michael@0 515 };
michael@0 516
michael@0 517 typedef struct lockedVarsStr lockedVars;
michael@0 518
michael@0 519 void
michael@0 520 lockedVars_Init( lockedVars * lv)
michael@0 521 {
michael@0 522 lv->count = 0;
michael@0 523 lv->waiters = 0;
michael@0 524 lv->lock = PR_NewLock();
michael@0 525 lv->condVar = PR_NewCondVar(lv->lock);
michael@0 526 }
michael@0 527
michael@0 528 void
michael@0 529 lockedVars_Destroy( lockedVars * lv)
michael@0 530 {
michael@0 531 PR_DestroyCondVar(lv->condVar);
michael@0 532 lv->condVar = NULL;
michael@0 533
michael@0 534 PR_DestroyLock(lv->lock);
michael@0 535 lv->lock = NULL;
michael@0 536 }
michael@0 537
michael@0 538 void
michael@0 539 lockedVars_WaitForDone(lockedVars * lv)
michael@0 540 {
michael@0 541 PR_Lock(lv->lock);
michael@0 542 while (lv->count > 0) {
michael@0 543 PR_WaitCondVar(lv->condVar, PR_INTERVAL_NO_TIMEOUT);
michael@0 544 }
michael@0 545 PR_Unlock(lv->lock);
michael@0 546 }
michael@0 547
michael@0 548 int /* returns count */
michael@0 549 lockedVars_AddToCount(lockedVars * lv, int addend)
michael@0 550 {
michael@0 551 int rv;
michael@0 552
michael@0 553 PR_Lock(lv->lock);
michael@0 554 rv = lv->count += addend;
michael@0 555 if (rv <= 0) {
michael@0 556 PR_NotifyCondVar(lv->condVar);
michael@0 557 }
michael@0 558 PR_Unlock(lv->lock);
michael@0 559 return rv;
michael@0 560 }
michael@0 561
michael@0 562 int
michael@0 563 do_writes(
michael@0 564 void * a,
michael@0 565 void * b,
michael@0 566 int c)
michael@0 567 {
michael@0 568 PRFileDesc * ssl_sock = (PRFileDesc *)a;
michael@0 569 lockedVars * lv = (lockedVars *)b;
michael@0 570 int sent = 0;
michael@0 571 int count = 0;
michael@0 572
michael@0 573 while (sent < bigBuf.len) {
michael@0 574
michael@0 575 count = PR_Send(ssl_sock, bigBuf.data + sent, bigBuf.len - sent,
michael@0 576 0, maxInterval);
michael@0 577 if (count < 0) {
michael@0 578 errWarn("PR_Send bigBuf");
michael@0 579 break;
michael@0 580 }
michael@0 581 FPRINTF(stderr, "strsclnt: PR_Send wrote %d bytes from bigBuf\n",
michael@0 582 count );
michael@0 583 sent += count;
michael@0 584 }
michael@0 585 if (count >= 0) { /* last write didn't fail. */
michael@0 586 PR_Shutdown(ssl_sock, PR_SHUTDOWN_SEND);
michael@0 587 }
michael@0 588
michael@0 589 /* notify the reader that we're done. */
michael@0 590 lockedVars_AddToCount(lv, -1);
michael@0 591 return (sent < bigBuf.len) ? SECFailure : SECSuccess;
michael@0 592 }
michael@0 593
michael@0 594 int
michael@0 595 handle_fdx_connection( PRFileDesc * ssl_sock, int connection)
michael@0 596 {
michael@0 597 SECStatus result;
michael@0 598 int firstTime = 1;
michael@0 599 int countRead = 0;
michael@0 600 lockedVars lv;
michael@0 601 char *buf;
michael@0 602
michael@0 603
michael@0 604 lockedVars_Init(&lv);
michael@0 605 lockedVars_AddToCount(&lv, 1);
michael@0 606
michael@0 607 /* Attempt to launch the writer thread. */
michael@0 608 result = launch_thread(do_writes, ssl_sock, &lv, connection);
michael@0 609
michael@0 610 if (result != SECSuccess)
michael@0 611 goto cleanup;
michael@0 612
michael@0 613 buf = PR_Malloc(RD_BUF_SIZE);
michael@0 614
michael@0 615 if (buf) {
michael@0 616 do {
michael@0 617 /* do reads here. */
michael@0 618 PRInt32 count;
michael@0 619
michael@0 620 count = PR_Recv(ssl_sock, buf, RD_BUF_SIZE, 0, maxInterval);
michael@0 621 if (count < 0) {
michael@0 622 errWarn("PR_Recv");
michael@0 623 break;
michael@0 624 }
michael@0 625 countRead += count;
michael@0 626 FPRINTF(stderr,
michael@0 627 "strsclnt: connection %d read %d bytes (%d total).\n",
michael@0 628 connection, count, countRead );
michael@0 629 if (firstTime) {
michael@0 630 firstTime = 0;
michael@0 631 printSecurityInfo(ssl_sock);
michael@0 632 }
michael@0 633 } while (lockedVars_AddToCount(&lv, 0) > 0);
michael@0 634 PR_Free(buf);
michael@0 635 buf = 0;
michael@0 636 }
michael@0 637
michael@0 638 /* Wait for writer to finish */
michael@0 639 lockedVars_WaitForDone(&lv);
michael@0 640 lockedVars_Destroy(&lv);
michael@0 641
michael@0 642 FPRINTF(stderr,
michael@0 643 "strsclnt: connection %d read %d bytes total. -----------------------\n",
michael@0 644 connection, countRead);
michael@0 645
michael@0 646 cleanup:
michael@0 647 /* Caller closes the socket. */
michael@0 648
michael@0 649 return SECSuccess;
michael@0 650 }
michael@0 651
michael@0 652 const char request[] = {"GET /abc HTTP/1.0\r\n\r\n" };
michael@0 653
michael@0 654 SECStatus
michael@0 655 handle_connection( PRFileDesc *ssl_sock, int tid)
michael@0 656 {
michael@0 657 int countRead = 0;
michael@0 658 PRInt32 rv;
michael@0 659 char *buf;
michael@0 660
michael@0 661 buf = PR_Malloc(RD_BUF_SIZE);
michael@0 662 if (!buf)
michael@0 663 return SECFailure;
michael@0 664
michael@0 665 /* compose the http request here. */
michael@0 666
michael@0 667 rv = PR_Send(ssl_sock, request, strlen(request), 0, maxInterval);
michael@0 668 if (rv <= 0) {
michael@0 669 errWarn("PR_Send");
michael@0 670 PR_Free(buf);
michael@0 671 buf = 0;
michael@0 672 failed_already = 1;
michael@0 673 return SECFailure;
michael@0 674 }
michael@0 675 printSecurityInfo(ssl_sock);
michael@0 676
michael@0 677 /* read until EOF */
michael@0 678 while (1) {
michael@0 679 rv = PR_Recv(ssl_sock, buf, RD_BUF_SIZE, 0, maxInterval);
michael@0 680 if (rv == 0) {
michael@0 681 break; /* EOF */
michael@0 682 }
michael@0 683 if (rv < 0) {
michael@0 684 errWarn("PR_Recv");
michael@0 685 failed_already = 1;
michael@0 686 break;
michael@0 687 }
michael@0 688
michael@0 689 countRead += rv;
michael@0 690 FPRINTF(stderr,
michael@0 691 "strsclnt: connection on thread %d read %d bytes (%d total).\n",
michael@0 692 tid, rv, countRead );
michael@0 693 }
michael@0 694 PR_Free(buf);
michael@0 695 buf = 0;
michael@0 696
michael@0 697 /* Caller closes the socket. */
michael@0 698
michael@0 699 FPRINTF(stderr,
michael@0 700 "strsclnt: connection on thread %d read %d bytes total. ---------\n",
michael@0 701 tid, countRead);
michael@0 702
michael@0 703 return SECSuccess; /* success */
michael@0 704 }
michael@0 705
michael@0 706 #define USE_SOCK_PEER_ID 1
michael@0 707
michael@0 708 #ifdef USE_SOCK_PEER_ID
michael@0 709
michael@0 710 PRInt32 lastFullHandshakePeerID;
michael@0 711
michael@0 712 void
michael@0 713 myHandshakeCallback(PRFileDesc *socket, void *arg)
michael@0 714 {
michael@0 715 PR_ATOMIC_SET(&lastFullHandshakePeerID, (PRInt32) arg);
michael@0 716 }
michael@0 717
michael@0 718 #endif
michael@0 719
michael@0 720 /* one copy of this function is launched in a separate thread for each
michael@0 721 ** connection to be made.
michael@0 722 */
michael@0 723 int
michael@0 724 do_connects(
michael@0 725 void * a,
michael@0 726 void * b,
michael@0 727 int tid)
michael@0 728 {
michael@0 729 PRNetAddr * addr = (PRNetAddr *) a;
michael@0 730 PRFileDesc * model_sock = (PRFileDesc *) b;
michael@0 731 PRFileDesc * ssl_sock = 0;
michael@0 732 PRFileDesc * tcp_sock = 0;
michael@0 733 PRStatus prStatus;
michael@0 734 PRUint32 sleepInterval = 50; /* milliseconds */
michael@0 735 SECStatus result;
michael@0 736 int rv = SECSuccess;
michael@0 737 PRSocketOptionData opt;
michael@0 738
michael@0 739 retry:
michael@0 740
michael@0 741 tcp_sock = PR_OpenTCPSocket(addr->raw.family);
michael@0 742 if (tcp_sock == NULL) {
michael@0 743 errExit("PR_OpenTCPSocket");
michael@0 744 }
michael@0 745
michael@0 746 opt.option = PR_SockOpt_Nonblocking;
michael@0 747 opt.value.non_blocking = PR_FALSE;
michael@0 748 prStatus = PR_SetSocketOption(tcp_sock, &opt);
michael@0 749 if (prStatus != PR_SUCCESS) {
michael@0 750 errWarn("PR_SetSocketOption(PR_SockOpt_Nonblocking, PR_FALSE)");
michael@0 751 PR_Close(tcp_sock);
michael@0 752 return SECSuccess;
michael@0 753 }
michael@0 754
michael@0 755 if (NoDelay) {
michael@0 756 opt.option = PR_SockOpt_NoDelay;
michael@0 757 opt.value.no_delay = PR_TRUE;
michael@0 758 prStatus = PR_SetSocketOption(tcp_sock, &opt);
michael@0 759 if (prStatus != PR_SUCCESS) {
michael@0 760 errWarn("PR_SetSocketOption(PR_SockOpt_NoDelay, PR_TRUE)");
michael@0 761 PR_Close(tcp_sock);
michael@0 762 return SECSuccess;
michael@0 763 }
michael@0 764 }
michael@0 765
michael@0 766 prStatus = PR_Connect(tcp_sock, addr, PR_INTERVAL_NO_TIMEOUT);
michael@0 767 if (prStatus != PR_SUCCESS) {
michael@0 768 PRErrorCode err = PR_GetError(); /* save error code */
michael@0 769 PRInt32 oserr = PR_GetOSError();
michael@0 770 if (ThrottleUp) {
michael@0 771 PRTime now = PR_Now();
michael@0 772 PR_Lock(threadLock);
michael@0 773 lastConnectFailure = PR_MAX(now, lastConnectFailure);
michael@0 774 PR_Unlock(threadLock);
michael@0 775 PR_SetError(err, oserr); /* restore error code */
michael@0 776 }
michael@0 777 if ((err == PR_CONNECT_REFUSED_ERROR) ||
michael@0 778 (err == PR_CONNECT_RESET_ERROR) ) {
michael@0 779 int connections = numConnected;
michael@0 780
michael@0 781 PR_Close(tcp_sock);
michael@0 782 PR_Lock(threadLock);
michael@0 783 if (connections > 2 && active_threads >= connections) {
michael@0 784 active_threads = connections - 1;
michael@0 785 fprintf(stderr,"active_threads set down to %d\n",
michael@0 786 active_threads);
michael@0 787 }
michael@0 788 PR_Unlock(threadLock);
michael@0 789
michael@0 790 if (QuitOnTimeout && sleepInterval > 40000) {
michael@0 791 fprintf(stderr,
michael@0 792 "strsclnt: Client timed out waiting for connection to server.\n");
michael@0 793 exit(1);
michael@0 794 }
michael@0 795 PR_Sleep(PR_MillisecondsToInterval(sleepInterval));
michael@0 796 sleepInterval <<= 1;
michael@0 797 goto retry;
michael@0 798 }
michael@0 799 errWarn("PR_Connect");
michael@0 800 rv = SECFailure;
michael@0 801 goto done;
michael@0 802 } else {
michael@0 803 if (ThrottleUp) {
michael@0 804 PRTime now = PR_Now();
michael@0 805 PR_Lock(threadLock);
michael@0 806 lastConnectSuccess = PR_MAX(now, lastConnectSuccess);
michael@0 807 PR_Unlock(threadLock);
michael@0 808 }
michael@0 809 }
michael@0 810
michael@0 811 ssl_sock = SSL_ImportFD(model_sock, tcp_sock);
michael@0 812 /* XXX if this import fails, close tcp_sock and return. */
michael@0 813 if (!ssl_sock) {
michael@0 814 PR_Close(tcp_sock);
michael@0 815 return SECSuccess;
michael@0 816 }
michael@0 817 if (fullhs != NO_FULLHS_PERCENTAGE) {
michael@0 818 #ifdef USE_SOCK_PEER_ID
michael@0 819 char sockPeerIDString[512];
michael@0 820 static PRInt32 sockPeerID = 0; /* atomically incremented */
michael@0 821 PRInt32 thisPeerID;
michael@0 822 #endif
michael@0 823 PRInt32 savid = PR_ATOMIC_INCREMENT(&globalconid);
michael@0 824 PRInt32 conid = 1 + (savid - 1) % 100;
michael@0 825 /* don't change peer ID on the very first handshake, which is always
michael@0 826 a full, so the session gets stored into the client cache */
michael@0 827 if ( (savid != 1) &&
michael@0 828 ( ( (savid <= total_connections_rounded_down_to_hundreds) &&
michael@0 829 (conid <= fullhs) ) ||
michael@0 830 (conid*100 <= total_connections_modulo_100*fullhs ) ) )
michael@0 831 #ifdef USE_SOCK_PEER_ID
michael@0 832 {
michael@0 833 /* force a full handshake by changing the socket peer ID */
michael@0 834 thisPeerID = PR_ATOMIC_INCREMENT(&sockPeerID);
michael@0 835 } else {
michael@0 836 /* reuse previous sockPeerID for restart handhsake */
michael@0 837 thisPeerID = lastFullHandshakePeerID;
michael@0 838 }
michael@0 839 PR_snprintf(sockPeerIDString, sizeof(sockPeerIDString), "ID%d",
michael@0 840 thisPeerID);
michael@0 841 SSL_SetSockPeerID(ssl_sock, sockPeerIDString);
michael@0 842 SSL_HandshakeCallback(ssl_sock, myHandshakeCallback, (void*)thisPeerID);
michael@0 843 #else
michael@0 844 /* force a full handshake by setting the no cache option */
michael@0 845 SSL_OptionSet(ssl_sock, SSL_NO_CACHE, 1);
michael@0 846 #endif
michael@0 847 }
michael@0 848 rv = SSL_ResetHandshake(ssl_sock, /* asServer */ 0);
michael@0 849 if (rv != SECSuccess) {
michael@0 850 errWarn("SSL_ResetHandshake");
michael@0 851 goto done;
michael@0 852 }
michael@0 853
michael@0 854 PR_ATOMIC_INCREMENT(&numConnected);
michael@0 855
michael@0 856 if (bigBuf.data != NULL) {
michael@0 857 result = handle_fdx_connection( ssl_sock, tid);
michael@0 858 } else {
michael@0 859 result = handle_connection( ssl_sock, tid);
michael@0 860 }
michael@0 861
michael@0 862 PR_ATOMIC_DECREMENT(&numConnected);
michael@0 863
michael@0 864 done:
michael@0 865 if (ssl_sock) {
michael@0 866 PR_Close(ssl_sock);
michael@0 867 } else if (tcp_sock) {
michael@0 868 PR_Close(tcp_sock);
michael@0 869 }
michael@0 870 return SECSuccess;
michael@0 871 }
michael@0 872
michael@0 873
michael@0 874 typedef struct {
michael@0 875 PRLock* lock;
michael@0 876 char* nickname;
michael@0 877 CERTCertificate* cert;
michael@0 878 SECKEYPrivateKey* key;
michael@0 879 void* wincx;
michael@0 880 } cert_and_key;
michael@0 881
michael@0 882 PRBool FindCertAndKey(cert_and_key* Cert_And_Key)
michael@0 883 {
michael@0 884 if ( (NULL == Cert_And_Key->nickname) || (0 == strcmp(Cert_And_Key->nickname,"none"))) {
michael@0 885 return PR_TRUE;
michael@0 886 }
michael@0 887 Cert_And_Key->cert = CERT_FindUserCertByUsage(CERT_GetDefaultCertDB(),
michael@0 888 Cert_And_Key->nickname, certUsageSSLClient,
michael@0 889 PR_FALSE, Cert_And_Key->wincx);
michael@0 890 if (Cert_And_Key->cert) {
michael@0 891 Cert_And_Key->key = PK11_FindKeyByAnyCert(Cert_And_Key->cert, Cert_And_Key->wincx);
michael@0 892 }
michael@0 893 if (Cert_And_Key->cert && Cert_And_Key->key) {
michael@0 894 return PR_TRUE;
michael@0 895 } else {
michael@0 896 return PR_FALSE;
michael@0 897 }
michael@0 898 }
michael@0 899
michael@0 900 PRBool LoggedIn(CERTCertificate* cert, SECKEYPrivateKey* key)
michael@0 901 {
michael@0 902 if ( (cert->slot) && (key->pkcs11Slot) &&
michael@0 903 (PR_TRUE == PK11_IsLoggedIn(cert->slot, NULL)) &&
michael@0 904 (PR_TRUE == PK11_IsLoggedIn(key->pkcs11Slot, NULL)) ) {
michael@0 905 return PR_TRUE;
michael@0 906 }
michael@0 907
michael@0 908 return PR_FALSE;
michael@0 909 }
michael@0 910
michael@0 911 SECStatus
michael@0 912 StressClient_GetClientAuthData(void * arg,
michael@0 913 PRFileDesc * socket,
michael@0 914 struct CERTDistNamesStr * caNames,
michael@0 915 struct CERTCertificateStr ** pRetCert,
michael@0 916 struct SECKEYPrivateKeyStr **pRetKey)
michael@0 917 {
michael@0 918 cert_and_key* Cert_And_Key = (cert_and_key*) arg;
michael@0 919
michael@0 920 if (!pRetCert || !pRetKey) {
michael@0 921 /* bad pointers, can't return a cert or key */
michael@0 922 return SECFailure;
michael@0 923 }
michael@0 924
michael@0 925 *pRetCert = NULL;
michael@0 926 *pRetKey = NULL;
michael@0 927
michael@0 928 if (Cert_And_Key && Cert_And_Key->nickname) {
michael@0 929 while (PR_TRUE) {
michael@0 930 if (Cert_And_Key && Cert_And_Key->lock) {
michael@0 931 int timeout = 0;
michael@0 932 PR_Lock(Cert_And_Key->lock);
michael@0 933
michael@0 934 if (Cert_And_Key->cert) {
michael@0 935 *pRetCert = CERT_DupCertificate(Cert_And_Key->cert);
michael@0 936 }
michael@0 937
michael@0 938 if (Cert_And_Key->key) {
michael@0 939 *pRetKey = SECKEY_CopyPrivateKey(Cert_And_Key->key);
michael@0 940 }
michael@0 941 PR_Unlock(Cert_And_Key->lock);
michael@0 942 if (!*pRetCert || !*pRetKey) {
michael@0 943 /* one or both of them failed to copy. Either the source was NULL, or there was
michael@0 944 ** an out of memory condition. Free any allocated copy and fail */
michael@0 945 if (*pRetCert) {
michael@0 946 CERT_DestroyCertificate(*pRetCert);
michael@0 947 *pRetCert = NULL;
michael@0 948 }
michael@0 949 if (*pRetKey) {
michael@0 950 SECKEY_DestroyPrivateKey(*pRetKey);
michael@0 951 *pRetKey = NULL;
michael@0 952 }
michael@0 953 break;
michael@0 954 }
michael@0 955 /* now check if those objects are valid */
michael@0 956 if ( PR_FALSE == LoggedIn(*pRetCert, *pRetKey) ) {
michael@0 957 /* token is no longer logged in, it was removed */
michael@0 958
michael@0 959 /* first, delete and clear our invalid local objects */
michael@0 960 CERT_DestroyCertificate(*pRetCert);
michael@0 961 SECKEY_DestroyPrivateKey(*pRetKey);
michael@0 962 *pRetCert = NULL;
michael@0 963 *pRetKey = NULL;
michael@0 964
michael@0 965 PR_Lock(Cert_And_Key->lock);
michael@0 966 /* check if another thread already logged back in */
michael@0 967 if (PR_TRUE == LoggedIn(Cert_And_Key->cert, Cert_And_Key->key)) {
michael@0 968 /* yes : try again */
michael@0 969 PR_Unlock(Cert_And_Key->lock);
michael@0 970 continue;
michael@0 971 }
michael@0 972 /* this is the thread to retry */
michael@0 973 CERT_DestroyCertificate(Cert_And_Key->cert);
michael@0 974 SECKEY_DestroyPrivateKey(Cert_And_Key->key);
michael@0 975 Cert_And_Key->cert = NULL;
michael@0 976 Cert_And_Key->key = NULL;
michael@0 977
michael@0 978
michael@0 979 /* now look up the cert and key again */
michael@0 980 while (PR_FALSE == FindCertAndKey(Cert_And_Key) ) {
michael@0 981 PR_Sleep(PR_SecondsToInterval(1));
michael@0 982 timeout++;
michael@0 983 if (timeout>=60) {
michael@0 984 printf("\nToken pulled and not reinserted early enough : aborting.\n");
michael@0 985 exit(1);
michael@0 986 }
michael@0 987 }
michael@0 988 PR_Unlock(Cert_And_Key->lock);
michael@0 989 continue;
michael@0 990 /* try again to reduce code size */
michael@0 991 }
michael@0 992 return SECSuccess;
michael@0 993 }
michael@0 994 }
michael@0 995 *pRetCert = NULL;
michael@0 996 *pRetKey = NULL;
michael@0 997 return SECFailure;
michael@0 998 } else {
michael@0 999 /* no cert configured, automatically find the right cert. */
michael@0 1000 CERTCertificate * cert = NULL;
michael@0 1001 SECKEYPrivateKey * privkey = NULL;
michael@0 1002 CERTCertNicknames * names;
michael@0 1003 int i;
michael@0 1004 void * proto_win = NULL;
michael@0 1005 SECStatus rv = SECFailure;
michael@0 1006
michael@0 1007 if (Cert_And_Key) {
michael@0 1008 proto_win = Cert_And_Key->wincx;
michael@0 1009 }
michael@0 1010
michael@0 1011 names = CERT_GetCertNicknames(CERT_GetDefaultCertDB(),
michael@0 1012 SEC_CERT_NICKNAMES_USER, proto_win);
michael@0 1013 if (names != NULL) {
michael@0 1014 for (i = 0; i < names->numnicknames; i++) {
michael@0 1015 cert = CERT_FindUserCertByUsage(CERT_GetDefaultCertDB(),
michael@0 1016 names->nicknames[i], certUsageSSLClient,
michael@0 1017 PR_FALSE, proto_win);
michael@0 1018 if ( !cert )
michael@0 1019 continue;
michael@0 1020 /* Only check unexpired certs */
michael@0 1021 if (CERT_CheckCertValidTimes(cert, PR_Now(), PR_TRUE) !=
michael@0 1022 secCertTimeValid ) {
michael@0 1023 CERT_DestroyCertificate(cert);
michael@0 1024 continue;
michael@0 1025 }
michael@0 1026 rv = NSS_CmpCertChainWCANames(cert, caNames);
michael@0 1027 if ( rv == SECSuccess ) {
michael@0 1028 privkey = PK11_FindKeyByAnyCert(cert, proto_win);
michael@0 1029 if ( privkey )
michael@0 1030 break;
michael@0 1031 }
michael@0 1032 rv = SECFailure;
michael@0 1033 CERT_DestroyCertificate(cert);
michael@0 1034 }
michael@0 1035 CERT_FreeNicknames(names);
michael@0 1036 }
michael@0 1037 if (rv == SECSuccess) {
michael@0 1038 *pRetCert = cert;
michael@0 1039 *pRetKey = privkey;
michael@0 1040 }
michael@0 1041 return rv;
michael@0 1042 }
michael@0 1043 }
michael@0 1044
michael@0 1045 int
michael@0 1046 hexchar_to_int(int c)
michael@0 1047 {
michael@0 1048 if (((c) >= '0') && ((c) <= '9'))
michael@0 1049 return (c) - '0';
michael@0 1050 if (((c) >= 'a') && ((c) <= 'f'))
michael@0 1051 return (c) - 'a' + 10;
michael@0 1052 if (((c) >= 'A') && ((c) <= 'F'))
michael@0 1053 return (c) - 'A' + 10;
michael@0 1054 failed_already = 1;
michael@0 1055 return -1;
michael@0 1056 }
michael@0 1057
michael@0 1058 void
michael@0 1059 client_main(
michael@0 1060 unsigned short port,
michael@0 1061 int connections,
michael@0 1062 cert_and_key* Cert_And_Key,
michael@0 1063 const char * hostName,
michael@0 1064 const char * sniHostName)
michael@0 1065 {
michael@0 1066 PRFileDesc *model_sock = NULL;
michael@0 1067 int i;
michael@0 1068 int rv;
michael@0 1069 PRStatus status;
michael@0 1070 PRNetAddr addr;
michael@0 1071
michael@0 1072 status = PR_StringToNetAddr(hostName, &addr);
michael@0 1073 if (status == PR_SUCCESS) {
michael@0 1074 addr.inet.port = PR_htons(port);
michael@0 1075 } else {
michael@0 1076 /* Lookup host */
michael@0 1077 PRAddrInfo *addrInfo;
michael@0 1078 void *enumPtr = NULL;
michael@0 1079
michael@0 1080 addrInfo = PR_GetAddrInfoByName(hostName, PR_AF_UNSPEC,
michael@0 1081 PR_AI_ADDRCONFIG | PR_AI_NOCANONNAME);
michael@0 1082 if (!addrInfo) {
michael@0 1083 SECU_PrintError(progName, "error looking up host");
michael@0 1084 return;
michael@0 1085 }
michael@0 1086 do {
michael@0 1087 enumPtr = PR_EnumerateAddrInfo(enumPtr, addrInfo, port, &addr);
michael@0 1088 } while (enumPtr != NULL &&
michael@0 1089 addr.raw.family != PR_AF_INET &&
michael@0 1090 addr.raw.family != PR_AF_INET6);
michael@0 1091 PR_FreeAddrInfo(addrInfo);
michael@0 1092 if (enumPtr == NULL) {
michael@0 1093 SECU_PrintError(progName, "error looking up host address");
michael@0 1094 return;
michael@0 1095 }
michael@0 1096 }
michael@0 1097
michael@0 1098 /* all suites except RSA_NULL_MD5 are enabled by Domestic Policy */
michael@0 1099 NSS_SetDomesticPolicy();
michael@0 1100
michael@0 1101 /* all the SSL2 and SSL3 cipher suites are enabled by default. */
michael@0 1102 if (cipherString) {
michael@0 1103 int ndx;
michael@0 1104
michael@0 1105 /* disable all the ciphers, then enable the ones we want. */
michael@0 1106 disableAllSSLCiphers();
michael@0 1107
michael@0 1108 while (0 != (ndx = *cipherString)) {
michael@0 1109 const char * startCipher = cipherString++;
michael@0 1110 int cipher = 0;
michael@0 1111 SECStatus rv;
michael@0 1112
michael@0 1113 if (ndx == ':') {
michael@0 1114 cipher = hexchar_to_int(*cipherString++);
michael@0 1115 cipher <<= 4;
michael@0 1116 cipher |= hexchar_to_int(*cipherString++);
michael@0 1117 cipher <<= 4;
michael@0 1118 cipher |= hexchar_to_int(*cipherString++);
michael@0 1119 cipher <<= 4;
michael@0 1120 cipher |= hexchar_to_int(*cipherString++);
michael@0 1121 if (cipher <= 0) {
michael@0 1122 fprintf(stderr, "strsclnt: Invalid cipher value: %-5.5s\n",
michael@0 1123 startCipher);
michael@0 1124 failed_already = 1;
michael@0 1125 return;
michael@0 1126 }
michael@0 1127 } else {
michael@0 1128 if (isalpha(ndx)) {
michael@0 1129 const int *cptr;
michael@0 1130
michael@0 1131 cptr = islower(ndx) ? ssl3CipherSuites : ssl2CipherSuites;
michael@0 1132 for (ndx &= 0x1f; (cipher = *cptr++) != 0 && --ndx > 0; )
michael@0 1133 /* do nothing */;
michael@0 1134 }
michael@0 1135 if (cipher <= 0) {
michael@0 1136 fprintf(stderr, "strsclnt: Invalid cipher letter: %c\n",
michael@0 1137 *startCipher);
michael@0 1138 failed_already = 1;
michael@0 1139 return;
michael@0 1140 }
michael@0 1141 }
michael@0 1142 rv = SSL_CipherPrefSetDefault(cipher, PR_TRUE);
michael@0 1143 if (rv != SECSuccess) {
michael@0 1144 fprintf(stderr,
michael@0 1145 "strsclnt: SSL_CipherPrefSetDefault(0x%04x) failed\n",
michael@0 1146 cipher);
michael@0 1147 failed_already = 1;
michael@0 1148 return;
michael@0 1149 }
michael@0 1150 }
michael@0 1151 }
michael@0 1152
michael@0 1153 /* configure model SSL socket. */
michael@0 1154
michael@0 1155 model_sock = PR_OpenTCPSocket(addr.raw.family);
michael@0 1156 if (model_sock == NULL) {
michael@0 1157 errExit("PR_OpenTCPSocket for model socket");
michael@0 1158 }
michael@0 1159
michael@0 1160 model_sock = SSL_ImportFD(NULL, model_sock);
michael@0 1161 if (model_sock == NULL) {
michael@0 1162 errExit("SSL_ImportFD");
michael@0 1163 }
michael@0 1164
michael@0 1165 /* do SSL configuration. */
michael@0 1166
michael@0 1167 rv = SSL_OptionSet(model_sock, SSL_SECURITY,
michael@0 1168 enableSSL2 || enabledVersions.min != 0);
michael@0 1169 if (rv < 0) {
michael@0 1170 errExit("SSL_OptionSet SSL_SECURITY");
michael@0 1171 }
michael@0 1172
michael@0 1173 rv = SSL_VersionRangeSet(model_sock, &enabledVersions);
michael@0 1174 if (rv != SECSuccess) {
michael@0 1175 errExit("error setting SSL/TLS version range ");
michael@0 1176 }
michael@0 1177
michael@0 1178 rv = SSL_OptionSet(model_sock, SSL_ENABLE_SSL2, enableSSL2);
michael@0 1179 if (rv != SECSuccess) {
michael@0 1180 errExit("error enabling SSLv2 ");
michael@0 1181 }
michael@0 1182
michael@0 1183 rv = SSL_OptionSet(model_sock, SSL_V2_COMPATIBLE_HELLO, enableSSL2);
michael@0 1184 if (rv != SECSuccess) {
michael@0 1185 errExit("error enabling SSLv2 compatible hellos ");
michael@0 1186 }
michael@0 1187
michael@0 1188 if (bigBuf.data) { /* doing FDX */
michael@0 1189 rv = SSL_OptionSet(model_sock, SSL_ENABLE_FDX, 1);
michael@0 1190 if (rv < 0) {
michael@0 1191 errExit("SSL_OptionSet SSL_ENABLE_FDX");
michael@0 1192 }
michael@0 1193 }
michael@0 1194
michael@0 1195 if (NoReuse) {
michael@0 1196 rv = SSL_OptionSet(model_sock, SSL_NO_CACHE, 1);
michael@0 1197 if (rv < 0) {
michael@0 1198 errExit("SSL_OptionSet SSL_NO_CACHE");
michael@0 1199 }
michael@0 1200 }
michael@0 1201
michael@0 1202 if (bypassPKCS11) {
michael@0 1203 rv = SSL_OptionSet(model_sock, SSL_BYPASS_PKCS11, 1);
michael@0 1204 if (rv < 0) {
michael@0 1205 errExit("SSL_OptionSet SSL_BYPASS_PKCS11");
michael@0 1206 }
michael@0 1207 }
michael@0 1208
michael@0 1209 if (disableLocking) {
michael@0 1210 rv = SSL_OptionSet(model_sock, SSL_NO_LOCKS, 1);
michael@0 1211 if (rv < 0) {
michael@0 1212 errExit("SSL_OptionSet SSL_NO_LOCKS");
michael@0 1213 }
michael@0 1214 }
michael@0 1215
michael@0 1216 if (enableSessionTickets) {
michael@0 1217 rv = SSL_OptionSet(model_sock, SSL_ENABLE_SESSION_TICKETS, PR_TRUE);
michael@0 1218 if (rv != SECSuccess)
michael@0 1219 errExit("SSL_OptionSet SSL_ENABLE_SESSION_TICKETS");
michael@0 1220 }
michael@0 1221
michael@0 1222 if (enableCompression) {
michael@0 1223 rv = SSL_OptionSet(model_sock, SSL_ENABLE_DEFLATE, PR_TRUE);
michael@0 1224 if (rv != SECSuccess)
michael@0 1225 errExit("SSL_OptionSet SSL_ENABLE_DEFLATE");
michael@0 1226 }
michael@0 1227
michael@0 1228 if (enableFalseStart) {
michael@0 1229 rv = SSL_OptionSet(model_sock, SSL_ENABLE_FALSE_START, PR_TRUE);
michael@0 1230 if (rv != SECSuccess)
michael@0 1231 errExit("SSL_OptionSet SSL_ENABLE_FALSE_START");
michael@0 1232 }
michael@0 1233
michael@0 1234 if (enableCertStatus) {
michael@0 1235 rv = SSL_OptionSet(model_sock, SSL_ENABLE_OCSP_STAPLING, PR_TRUE);
michael@0 1236 if (rv != SECSuccess)
michael@0 1237 errExit("SSL_OptionSet SSL_ENABLE_OCSP_STAPLING");
michael@0 1238 }
michael@0 1239
michael@0 1240 SSL_SetPKCS11PinArg(model_sock, &pwdata);
michael@0 1241
michael@0 1242 SSL_SetURL(model_sock, hostName);
michael@0 1243
michael@0 1244 SSL_AuthCertificateHook(model_sock, mySSLAuthCertificate,
michael@0 1245 (void *)CERT_GetDefaultCertDB());
michael@0 1246 SSL_BadCertHook(model_sock, myBadCertHandler, NULL);
michael@0 1247
michael@0 1248 SSL_GetClientAuthDataHook(model_sock, StressClient_GetClientAuthData, (void*)Cert_And_Key);
michael@0 1249
michael@0 1250 if (sniHostName) {
michael@0 1251 SSL_SetURL(model_sock, sniHostName);
michael@0 1252 }
michael@0 1253 /* I'm not going to set the HandshakeCallback function. */
michael@0 1254
michael@0 1255 /* end of ssl configuration. */
michael@0 1256
michael@0 1257 init_thread_data();
michael@0 1258
michael@0 1259 remaining_connections = total_connections = connections;
michael@0 1260 total_connections_modulo_100 = total_connections % 100;
michael@0 1261 total_connections_rounded_down_to_hundreds =
michael@0 1262 total_connections - total_connections_modulo_100;
michael@0 1263
michael@0 1264 if (!NoReuse) {
michael@0 1265 remaining_connections = 1;
michael@0 1266 rv = launch_thread(do_connects, &addr, model_sock, 0);
michael@0 1267 /* wait for the first connection to terminate, then launch the rest. */
michael@0 1268 reap_threads();
michael@0 1269 remaining_connections = total_connections - 1 ;
michael@0 1270 }
michael@0 1271 if (remaining_connections > 0) {
michael@0 1272 active_threads = PR_MIN(active_threads, remaining_connections);
michael@0 1273 /* Start up the threads */
michael@0 1274 for (i=0;i<active_threads;i++) {
michael@0 1275 rv = launch_thread(do_connects, &addr, model_sock, i);
michael@0 1276 }
michael@0 1277 reap_threads();
michael@0 1278 }
michael@0 1279 destroy_thread_data();
michael@0 1280
michael@0 1281 PR_Close(model_sock);
michael@0 1282 }
michael@0 1283
michael@0 1284 SECStatus
michael@0 1285 readBigFile(const char * fileName)
michael@0 1286 {
michael@0 1287 PRFileInfo info;
michael@0 1288 PRStatus status;
michael@0 1289 SECStatus rv = SECFailure;
michael@0 1290 int count;
michael@0 1291 int hdrLen;
michael@0 1292 PRFileDesc *local_file_fd = NULL;
michael@0 1293
michael@0 1294 status = PR_GetFileInfo(fileName, &info);
michael@0 1295
michael@0 1296 if (status == PR_SUCCESS &&
michael@0 1297 info.type == PR_FILE_FILE &&
michael@0 1298 info.size > 0 &&
michael@0 1299 NULL != (local_file_fd = PR_Open(fileName, PR_RDONLY, 0))) {
michael@0 1300
michael@0 1301 hdrLen = PORT_Strlen(outHeader);
michael@0 1302 bigBuf.len = hdrLen + info.size;
michael@0 1303 bigBuf.data = PORT_Malloc(bigBuf.len + 4095);
michael@0 1304 if (!bigBuf.data) {
michael@0 1305 errWarn("PORT_Malloc");
michael@0 1306 goto done;
michael@0 1307 }
michael@0 1308
michael@0 1309 PORT_Memcpy(bigBuf.data, outHeader, hdrLen);
michael@0 1310
michael@0 1311 count = PR_Read(local_file_fd, bigBuf.data + hdrLen, info.size);
michael@0 1312 if (count != info.size) {
michael@0 1313 errWarn("PR_Read local file");
michael@0 1314 goto done;
michael@0 1315 }
michael@0 1316 rv = SECSuccess;
michael@0 1317 done:
michael@0 1318 PR_Close(local_file_fd);
michael@0 1319 }
michael@0 1320 return rv;
michael@0 1321 }
michael@0 1322
michael@0 1323 int
michael@0 1324 main(int argc, char **argv)
michael@0 1325 {
michael@0 1326 const char * dir = ".";
michael@0 1327 const char * fileName = NULL;
michael@0 1328 char * hostName = NULL;
michael@0 1329 char * nickName = NULL;
michael@0 1330 char * tmp = NULL;
michael@0 1331 int connections = 1;
michael@0 1332 int exitVal;
michael@0 1333 int tmpInt;
michael@0 1334 unsigned short port = 443;
michael@0 1335 SECStatus rv;
michael@0 1336 PLOptState * optstate;
michael@0 1337 PLOptStatus status;
michael@0 1338 cert_and_key Cert_And_Key;
michael@0 1339 char * sniHostName = NULL;
michael@0 1340
michael@0 1341 /* Call the NSPR initialization routines */
michael@0 1342 PR_Init( PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
michael@0 1343 SSL_VersionRangeGetSupported(ssl_variant_stream, &enabledVersions);
michael@0 1344
michael@0 1345 tmp = strrchr(argv[0], '/');
michael@0 1346 tmp = tmp ? tmp + 1 : argv[0];
michael@0 1347 progName = strrchr(tmp, '\\');
michael@0 1348 progName = progName ? progName + 1 : tmp;
michael@0 1349
michael@0 1350
michael@0 1351 optstate = PL_CreateOptState(argc, argv,
michael@0 1352 "BC:DNP:TUV:W:a:c:d:f:gin:op:qst:uvw:z");
michael@0 1353 while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
michael@0 1354 switch(optstate->option) {
michael@0 1355 case 'B': bypassPKCS11 = PR_TRUE; break;
michael@0 1356
michael@0 1357 case 'C': cipherString = optstate->value; break;
michael@0 1358
michael@0 1359 case 'D': NoDelay = PR_TRUE; break;
michael@0 1360
michael@0 1361 case 'I': /* reserved for OCSP multi-stapling */ break;
michael@0 1362
michael@0 1363 case 'N': NoReuse = 1; break;
michael@0 1364
michael@0 1365 case 'P': fullhs = PORT_Atoi(optstate->value); break;
michael@0 1366
michael@0 1367 case 'T': enableCertStatus = PR_TRUE; break;
michael@0 1368
michael@0 1369 case 'U': ThrottleUp = PR_TRUE; break;
michael@0 1370
michael@0 1371 case 'V': if (SECU_ParseSSLVersionRangeString(optstate->value,
michael@0 1372 enabledVersions, enableSSL2,
michael@0 1373 &enabledVersions, &enableSSL2) != SECSuccess) {
michael@0 1374 Usage(progName);
michael@0 1375 }
michael@0 1376 break;
michael@0 1377
michael@0 1378 case 'a': sniHostName = PL_strdup(optstate->value); break;
michael@0 1379
michael@0 1380 case 'c': connections = PORT_Atoi(optstate->value); break;
michael@0 1381
michael@0 1382 case 'd': dir = optstate->value; break;
michael@0 1383
michael@0 1384 case 'f': fileName = optstate->value; break;
michael@0 1385
michael@0 1386 case 'g': enableFalseStart = PR_TRUE; break;
michael@0 1387
michael@0 1388 case 'i': ignoreErrors = PR_TRUE; break;
michael@0 1389
michael@0 1390 case 'n': nickName = PL_strdup(optstate->value); break;
michael@0 1391
michael@0 1392 case 'o': MakeCertOK++; break;
michael@0 1393
michael@0 1394 case 'p': port = PORT_Atoi(optstate->value); break;
michael@0 1395
michael@0 1396 case 'q': QuitOnTimeout = PR_TRUE; break;
michael@0 1397
michael@0 1398 case 's': disableLocking = PR_TRUE; break;
michael@0 1399
michael@0 1400 case 't':
michael@0 1401 tmpInt = PORT_Atoi(optstate->value);
michael@0 1402 if (tmpInt > 0 && tmpInt < MAX_THREADS)
michael@0 1403 max_threads = active_threads = tmpInt;
michael@0 1404 break;
michael@0 1405
michael@0 1406 case 'u': enableSessionTickets = PR_TRUE; break;
michael@0 1407
michael@0 1408 case 'v': verbose++; break;
michael@0 1409
michael@0 1410 case 'w':
michael@0 1411 pwdata.source = PW_PLAINTEXT;
michael@0 1412 pwdata.data = PL_strdup(optstate->value);
michael@0 1413 break;
michael@0 1414
michael@0 1415 case 'W':
michael@0 1416 pwdata.source = PW_FROMFILE;
michael@0 1417 pwdata.data = PL_strdup(optstate->value);
michael@0 1418 break;
michael@0 1419
michael@0 1420 case 'z': enableCompression = PR_TRUE; break;
michael@0 1421
michael@0 1422 case 0: /* positional parameter */
michael@0 1423 if (hostName) {
michael@0 1424 Usage(progName);
michael@0 1425 }
michael@0 1426 hostName = PL_strdup(optstate->value);
michael@0 1427 break;
michael@0 1428
michael@0 1429 default:
michael@0 1430 case '?':
michael@0 1431 Usage(progName);
michael@0 1432 break;
michael@0 1433
michael@0 1434 }
michael@0 1435 }
michael@0 1436 PL_DestroyOptState(optstate);
michael@0 1437
michael@0 1438 if (!hostName || status == PL_OPT_BAD)
michael@0 1439 Usage(progName);
michael@0 1440
michael@0 1441 if (fullhs!= NO_FULLHS_PERCENTAGE && (fullhs < 0 || fullhs>100 || NoReuse) )
michael@0 1442 Usage(progName);
michael@0 1443
michael@0 1444 if (port == 0)
michael@0 1445 Usage(progName);
michael@0 1446
michael@0 1447 if (fileName)
michael@0 1448 readBigFile(fileName);
michael@0 1449
michael@0 1450 PK11_SetPasswordFunc(SECU_GetModulePassword);
michael@0 1451
michael@0 1452 tmp = PR_GetEnv("NSS_DEBUG_TIMEOUT");
michael@0 1453 if (tmp && tmp[0]) {
michael@0 1454 int sec = PORT_Atoi(tmp);
michael@0 1455 if (sec > 0) {
michael@0 1456 maxInterval = PR_SecondsToInterval(sec);
michael@0 1457 }
michael@0 1458 }
michael@0 1459
michael@0 1460 /* Call the NSS initialization routines */
michael@0 1461 rv = NSS_Initialize(dir, "", "", SECMOD_DB, NSS_INIT_READONLY);
michael@0 1462 if (rv != SECSuccess) {
michael@0 1463 fputs("NSS_Init failed.\n", stderr);
michael@0 1464 exit(1);
michael@0 1465 }
michael@0 1466 ssl3stats = SSL_GetStatistics();
michael@0 1467 Cert_And_Key.lock = PR_NewLock();
michael@0 1468 Cert_And_Key.nickname = nickName;
michael@0 1469 Cert_And_Key.wincx = &pwdata;
michael@0 1470 Cert_And_Key.cert = NULL;
michael@0 1471 Cert_And_Key.key = NULL;
michael@0 1472
michael@0 1473 if (PR_FALSE == FindCertAndKey(&Cert_And_Key)) {
michael@0 1474
michael@0 1475 if (Cert_And_Key.cert == NULL) {
michael@0 1476 fprintf(stderr, "strsclnt: Can't find certificate %s\n", Cert_And_Key.nickname);
michael@0 1477 exit(1);
michael@0 1478 }
michael@0 1479
michael@0 1480 if (Cert_And_Key.key == NULL) {
michael@0 1481 fprintf(stderr, "strsclnt: Can't find Private Key for cert %s\n",
michael@0 1482 Cert_And_Key.nickname);
michael@0 1483 exit(1);
michael@0 1484 }
michael@0 1485
michael@0 1486 }
michael@0 1487
michael@0 1488 client_main(port, connections, &Cert_And_Key, hostName,
michael@0 1489 sniHostName);
michael@0 1490
michael@0 1491 /* clean up */
michael@0 1492 if (Cert_And_Key.cert) {
michael@0 1493 CERT_DestroyCertificate(Cert_And_Key.cert);
michael@0 1494 }
michael@0 1495 if (Cert_And_Key.key) {
michael@0 1496 SECKEY_DestroyPrivateKey(Cert_And_Key.key);
michael@0 1497 }
michael@0 1498
michael@0 1499 PR_DestroyLock(Cert_And_Key.lock);
michael@0 1500
michael@0 1501 if (pwdata.data) {
michael@0 1502 PL_strfree(pwdata.data);
michael@0 1503 }
michael@0 1504 if (Cert_And_Key.nickname) {
michael@0 1505 PL_strfree(Cert_And_Key.nickname);
michael@0 1506 }
michael@0 1507 if (sniHostName) {
michael@0 1508 PL_strfree(sniHostName);
michael@0 1509 }
michael@0 1510
michael@0 1511 PL_strfree(hostName);
michael@0 1512
michael@0 1513 /* some final stats. */
michael@0 1514 if (ssl3stats->hsh_sid_cache_hits +
michael@0 1515 ssl3stats->hsh_sid_cache_misses +
michael@0 1516 ssl3stats->hsh_sid_cache_not_ok +
michael@0 1517 ssl3stats->hsh_sid_stateless_resumes == 0) {
michael@0 1518 /* presumably we were testing SSL2. */
michael@0 1519 printf("strsclnt: SSL2 - %d server certificates tested.\n",
michael@0 1520 certsTested);
michael@0 1521 } else {
michael@0 1522 printf(
michael@0 1523 "strsclnt: %ld cache hits; %ld cache misses, %ld cache not reusable\n"
michael@0 1524 " %ld stateless resumes\n",
michael@0 1525 ssl3stats->hsh_sid_cache_hits,
michael@0 1526 ssl3stats->hsh_sid_cache_misses,
michael@0 1527 ssl3stats->hsh_sid_cache_not_ok,
michael@0 1528 ssl3stats->hsh_sid_stateless_resumes);
michael@0 1529 }
michael@0 1530
michael@0 1531 if (!NoReuse) {
michael@0 1532 if (enableSessionTickets)
michael@0 1533 exitVal = (ssl3stats->hsh_sid_stateless_resumes == 0);
michael@0 1534 else
michael@0 1535 exitVal = (ssl3stats->hsh_sid_cache_misses > 1) ||
michael@0 1536 (ssl3stats->hsh_sid_stateless_resumes != 0);
michael@0 1537 if (!exitVal)
michael@0 1538 exitVal = (ssl3stats->hsh_sid_cache_not_ok != 0) ||
michael@0 1539 (certsTested > 1);
michael@0 1540 } else {
michael@0 1541 printf("strsclnt: NoReuse - %d server certificates tested.\n",
michael@0 1542 certsTested);
michael@0 1543 if (ssl3stats->hsh_sid_cache_hits +
michael@0 1544 ssl3stats->hsh_sid_cache_misses +
michael@0 1545 ssl3stats->hsh_sid_cache_not_ok +
michael@0 1546 ssl3stats->hsh_sid_stateless_resumes > 0) {
michael@0 1547 exitVal = (ssl3stats->hsh_sid_cache_misses != connections) ||
michael@0 1548 (ssl3stats->hsh_sid_stateless_resumes != 0) ||
michael@0 1549 (certsTested != connections);
michael@0 1550 } else { /* ssl2 connections */
michael@0 1551 exitVal = (certsTested != connections);
michael@0 1552 }
michael@0 1553 }
michael@0 1554
michael@0 1555 exitVal = ( exitVal || failed_already );
michael@0 1556 SSL_ClearSessionCache();
michael@0 1557 if (NSS_Shutdown() != SECSuccess) {
michael@0 1558 printf("strsclnt: NSS_Shutdown() failed.\n");
michael@0 1559 exit(1);
michael@0 1560 }
michael@0 1561
michael@0 1562 PR_Cleanup();
michael@0 1563 return exitVal;
michael@0 1564 }
michael@0 1565

mercurial