security/nss/cmd/strsclnt/strsclnt.c

changeset 0
6474c204b198
     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 +

mercurial