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