~ubuntu-branches/ubuntu/trusty/xulrunner/trusty

« back to all changes in this revision

Viewing changes to security/nss-fips/cmd/strsclnt/strsclnt.c

  • Committer: Bazaar Package Importer
  • Author(s): Devid Antonio Filoni
  • Date: 2008-08-25 13:04:18 UTC
  • mfrom: (1.1.12 upstream)
  • Revision ID: james.westby@ubuntu.com-20080825130418-ck1i2ms384tzb9m0
Tags: 1.8.1.16+nobinonly-0ubuntu1
* New upstream release (taken from upstream CVS), LP: #254618.
* Fix MFSA 2008-35, MFSA 2008-34, MFSA 2008-33, MFSA 2008-32, MFSA 2008-31,
  MFSA 2008-30, MFSA 2008-29, MFSA 2008-28, MFSA 2008-27, MFSA 2008-25,
  MFSA 2008-24, MFSA 2008-23, MFSA 2008-22, MFSA 2008-21, MFSA 2008-26 also
  known as CVE-2008-2933, CVE-2008-2785, CVE-2008-2811, CVE-2008-2810,
  CVE-2008-2809, CVE-2008-2808, CVE-2008-2807, CVE-2008-2806, CVE-2008-2805,
  CVE-2008-2803, CVE-2008-2802, CVE-2008-2801, CVE-2008-2800, CVE-2008-2798.
* Drop 89_bz419350_attachment_306066 patch, merged upstream.
* Bump Standards-Version to 3.8.0.

Show diffs side-by-side

added added

removed removed

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