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