tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

strsclnt.c (49125B)


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