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