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