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/. */
32 #define PORT_Sprintf sprintf
36 #define PORT_Strstr strstr
40 #define PORT_Malloc PR_Malloc
43 #define RD_BUF_SIZE (60 * 1024)
45 /* Include these cipher suite arrays to re-use tstclnt's
46 * cipher selection code.
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 */
59 int ssl3CipherSuites[] = {
60 -1, /* SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA* a */
61 -1, /* SSL_FORTEZZA_DMS_WITH_RC4_128_SHA * b */
62 SSL_RSA_WITH_RC4_128_MD5, /* c */
63 SSL_RSA_WITH_3DES_EDE_CBC_SHA, /* d */
64 SSL_RSA_WITH_DES_CBC_SHA, /* e */
65 SSL_RSA_EXPORT_WITH_RC4_40_MD5, /* f */
66 SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5, /* g */
67 -1, /* SSL_FORTEZZA_DMS_WITH_NULL_SHA * h */
68 SSL_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 SSL_RSA_WITH_RC4_128_SHA, /* n */
74 TLS_DHE_DSS_WITH_RC4_128_SHA, /* o */
75 SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, /* p */
76 SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, /* q */
77 SSL_DHE_RSA_WITH_DES_CBC_SHA, /* r */
78 SSL_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 SSL_RSA_WITH_NULL_SHA, /* z */
89 #define NO_FULLHS_PERCENTAGE -1
91 /* This global string is so that client main can see
92 * which ciphers to use.
95 static const char *cipherString;
97 static PRInt32 certsTested;
98 static int MakeCertOK;
100 static int fullhs = NO_FULLHS_PERCENTAGE; /* percentage of full handshakes to
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
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;
138 secuPWData pwdata = { PW_NONE, 0 };
144 #define PRINTF if (verbose) printf
145 #define FPRINTF if (verbose) fprintf
148 Usage(const char *progName)
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",
180 errWarn(char * funcString)
182 PRErrorCode perr = PR_GetError();
183 const char * errString = SECU_Strerror(perr);
185 fprintf(stderr, "strsclnt: %s returned error %d:\n%s\n",
186 funcString, perr, errString);
190 errExit(char * funcString)
196 /**************************************************************************
198 ** Routines for disabling SSL ciphers.
200 **************************************************************************/
203 disableAllSSLCiphers(void)
205 const PRUint16 *cipherSuites = SSL_GetImplementedCiphers();
206 int i = SSL_GetNumImplementedCiphers();
209 /* disable all the SSL3 cipher suites */
211 PRUint16 suite = cipherSuites[i];
212 rv = SSL_CipherPrefSetDefault(suite, PR_FALSE);
213 if (rv != SECSuccess) {
214 printf("SSL_CipherPrefSetDefault didn't like value 0x%04x (i = %d)\n",
216 errWarn("SSL_CipherPrefSetDefault");
222 /* This invokes the "default" AuthCert handler in libssl.
223 ** The only reason to use this one is that it prints out info as it goes.
226 mySSLAuthCertificate(void *arg, PRFileDesc *fd, PRBool checkSig,
230 CERTCertificate * peerCert;
231 const SECItemArray *csa;
236 peerCert = SSL_PeerCertificate(fd);
238 PRINTF("strsclnt: Subject: %s\nstrsclnt: Issuer : %s\n",
239 peerCert->subjectName, peerCert->issuerName);
240 csa = SSL_PeerStapledOCSPResponses(fd);
242 PRINTF("Received %d Cert Status items (OCSP stapled data)\n",
245 /* invoke the "default" AuthCert handler. */
246 rv = SSL_AuthCertificate(arg, fd, checkSig, isServer);
248 PR_ATOMIC_INCREMENT(&certsTested);
249 if (rv == SECSuccess) {
250 fputs("strsclnt: -- SSL: Server Certificate Validated.\n", stderr);
252 CERT_DestroyCertificate(peerCert);
253 /* error, if any, will be displayed by the Bad Cert Handler. */
258 myBadCertHandler( void *arg, PRFileDesc *fd)
260 PRErrorCode err = PR_GetError();
263 "strsclnt: -- SSL: Server Certificate Invalid, err %d.\n%s\n",
264 err, SECU_Strerror(err));
265 return (MakeCertOK ? SECSuccess : SECFailure);
269 printSecurityInfo(PRFileDesc *fd)
271 CERTCertificate * cert = NULL;
272 SSL3Statistics * ssl3stats = SSL_GetStatistics();
274 SSLChannelInfo channel;
275 SSLCipherSuiteInfo suite;
277 static int only_once;
279 if (only_once && verbose < 2)
283 result = SSL_GetChannelInfo(fd, &channel, sizeof channel);
284 if (result == SECSuccess &&
285 channel.length == sizeof channel &&
286 channel.cipherSuite) {
287 result = SSL_GetCipherSuiteInfo(channel.cipherSuite,
288 &suite, sizeof suite);
289 if (result == SECSuccess) {
291 "strsclnt: SSL version %d.%d using %d-bit %s with %d-bit %s MAC\n",
292 channel.protocolVersion >> 8, channel.protocolVersion & 0xff,
293 suite.effectiveKeyBits, suite.symCipherName,
294 suite.macBits, suite.macAlgorithmName);
296 "strsclnt: Server Auth: %d-bit %s, Key Exchange: %d-bit %s\n"
297 " Compression: %s\n",
298 channel.authKeyBits, suite.authAlgorithmName,
299 channel.keaKeyBits, suite.keaTypeName,
300 channel.compressionMethodName);
304 cert = SSL_LocalCertificate(fd);
306 cert = SSL_PeerCertificate(fd);
308 if (verbose && cert) {
309 char * ip = CERT_NameToAscii(&cert->issuer);
310 char * sp = CERT_NameToAscii(&cert->subject);
312 fprintf(stderr, "strsclnt: subject DN: %s\n", sp);
316 fprintf(stderr, "strsclnt: issuer DN: %s\n", ip);
321 CERT_DestroyCertificate(cert);
325 "strsclnt: %ld cache hits; %ld cache misses, %ld cache not reusable\n"
326 " %ld stateless resumes\n",
327 ssl3stats->hsh_sid_cache_hits,
328 ssl3stats->hsh_sid_cache_misses,
329 ssl3stats->hsh_sid_cache_not_ok,
330 ssl3stats->hsh_sid_stateless_resumes);
334 /**************************************************************************
335 ** Begin thread management routines and data.
336 **************************************************************************/
338 #define MAX_THREADS 128
340 typedef int startFn(void *a, void *b, int c);
343 static PRInt32 numConnected;
344 static int max_threads; /* peak threads allowed */
346 typedef struct perThreadStr {
356 perThread threads[MAX_THREADS];
359 thread_wrapper(void * arg)
361 perThread * slot = (perThread *)arg;
362 PRBool done = PR_FALSE;
365 PRBool doop = PR_FALSE;
366 PRBool dosleep = PR_FALSE;
367 PRTime now = PR_Now();
370 if (! (slot->tid < active_threads)) {
371 /* this thread isn't supposed to be running */
373 /* we'll never need this thread again, so abort it */
375 } else if (remaining_connections > 0) {
376 /* we may still need this thread, so just sleep for 1s */
378 /* the conditions to trigger a throttle up are :
379 ** 1. last PR_Connect failure must have happened more than
381 ** 2. last throttling up must have happened more than 0.5s ago
382 ** 3. there must be a more recent PR_Connect success than
385 if ( (now - lastConnectFailure > 10 * PR_USEC_PER_SEC) &&
386 ( (!lastThrottleUp) || ( (now - lastThrottleUp) >=
387 (PR_USEC_PER_SEC/2)) ) &&
388 (lastConnectSuccess > lastConnectFailure) ) {
389 /* try throttling up by one thread */
390 active_threads = PR_MIN(max_threads, active_threads+1);
391 fprintf(stderr,"active_threads set up to %d\n",
393 lastThrottleUp = PR_MAX(now, lastThrottleUp);
396 /* no more connections left, we are done */
400 /* this thread should run */
401 if (--remaining_connections >= 0) { /* protected by threadLock */
407 PR_Unlock(threadLock);
409 slot->rv = (* slot->startFunc)(slot->a, slot->b, slot->tid);
410 PRINTF("strsclnt: Thread in slot %d returned %d\n",
411 slot->tid, slot->rv);
414 PR_Sleep(PR_SecondsToInterval(1));
416 } while (!done && (!failed_already || ignoreErrors));
431 PORT_Assert(numUsed < MAX_THREADS);
432 if (! (numUsed < MAX_THREADS)) {
433 PR_Unlock(threadLock);
443 slot->startFunc = startFunc;
445 slot->prThread = PR_CreateThread(PR_USER_THREAD,
446 thread_wrapper, slot,
447 PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
448 PR_JOINABLE_THREAD, 0);
449 if (slot->prThread == NULL) {
450 PR_Unlock(threadLock);
451 printf("strsclnt: Failed to launch thread!\n");
456 PR_Unlock(threadLock);
457 PRINTF("strsclnt: Launched thread in slot %d \n", i);
462 /* join all the threads */
468 for (i = 0; i < MAX_THREADS; ++i) {
469 if (threads[i].prThread) {
470 PR_JoinThread(threads[i].prThread);
471 threads[i].prThread = NULL;
478 destroy_thread_data(void)
480 PORT_Memset(threads, 0, sizeof threads);
483 PR_DestroyLock(threadLock);
489 init_thread_data(void)
491 threadLock = PR_NewLock();
494 /**************************************************************************
495 ** End thread management routines.
496 **************************************************************************/
498 PRBool useModelSocket = PR_TRUE;
500 static const char stopCmd[] = { "GET /stop " };
501 static const char outHeader[] = {
502 "HTTP/1.0 200 OK\r\n"
503 "Server: Netscape-Enterprise/2.0a\r\n"
504 "Date: Tue, 26 Aug 1997 22:10:05 GMT\r\n"
505 "Content-type: text/plain\r\n"
509 struct lockedVarsStr {
516 typedef struct lockedVarsStr lockedVars;
519 lockedVars_Init( lockedVars * lv)
523 lv->lock = PR_NewLock();
524 lv->condVar = PR_NewCondVar(lv->lock);
528 lockedVars_Destroy( lockedVars * lv)
530 PR_DestroyCondVar(lv->condVar);
533 PR_DestroyLock(lv->lock);
538 lockedVars_WaitForDone(lockedVars * lv)
541 while (lv->count > 0) {
542 PR_WaitCondVar(lv->condVar, PR_INTERVAL_NO_TIMEOUT);
547 int /* returns count */
548 lockedVars_AddToCount(lockedVars * lv, int addend)
553 rv = lv->count += addend;
555 PR_NotifyCondVar(lv->condVar);
567 PRFileDesc * ssl_sock = (PRFileDesc *)a;
568 lockedVars * lv = (lockedVars *)b;
572 while (sent < bigBuf.len) {
574 count = PR_Send(ssl_sock, bigBuf.data + sent, bigBuf.len - sent,
577 errWarn("PR_Send bigBuf");
580 FPRINTF(stderr, "strsclnt: PR_Send wrote %d bytes from bigBuf\n",
584 if (count >= 0) { /* last write didn't fail. */
585 PR_Shutdown(ssl_sock, PR_SHUTDOWN_SEND);
588 /* notify the reader that we're done. */
589 lockedVars_AddToCount(lv, -1);
590 return (sent < bigBuf.len) ? SECFailure : SECSuccess;
594 handle_fdx_connection( PRFileDesc * ssl_sock, int connection)
603 lockedVars_Init(&lv);
604 lockedVars_AddToCount(&lv, 1);
606 /* Attempt to launch the writer thread. */
607 result = launch_thread(do_writes, ssl_sock, &lv, connection);
609 if (result != SECSuccess)
612 buf = PR_Malloc(RD_BUF_SIZE);
619 count = PR_Recv(ssl_sock, buf, RD_BUF_SIZE, 0, maxInterval);
626 "strsclnt: connection %d read %d bytes (%d total).\n",
627 connection, count, countRead );
630 printSecurityInfo(ssl_sock);
632 } while (lockedVars_AddToCount(&lv, 0) > 0);
637 /* Wait for writer to finish */
638 lockedVars_WaitForDone(&lv);
639 lockedVars_Destroy(&lv);
642 "strsclnt: connection %d read %d bytes total. -----------------------\n",
643 connection, countRead);
646 /* Caller closes the socket. */
651 const char request[] = {"GET /abc HTTP/1.0\r\n\r\n" };
654 handle_connection( PRFileDesc *ssl_sock, int tid)
660 buf = PR_Malloc(RD_BUF_SIZE);
664 /* compose the http request here. */
666 rv = PR_Send(ssl_sock, request, strlen(request), 0, maxInterval);
674 printSecurityInfo(ssl_sock);
678 rv = PR_Recv(ssl_sock, buf, RD_BUF_SIZE, 0, maxInterval);
690 "strsclnt: connection on thread %d read %d bytes (%d total).\n",
691 tid, rv, countRead );
696 /* Caller closes the socket. */
699 "strsclnt: connection on thread %d read %d bytes total. ---------\n",
702 return SECSuccess; /* success */
705 #define USE_SOCK_PEER_ID 1
707 #ifdef USE_SOCK_PEER_ID
709 PRInt32 lastFullHandshakePeerID;
712 myHandshakeCallback(PRFileDesc *socket, void *arg)
714 PR_ATOMIC_SET(&lastFullHandshakePeerID, (PRInt32) arg);
719 /* one copy of this function is launched in a separate thread for each
720 ** connection to be made.
728 PRNetAddr * addr = (PRNetAddr *) a;
729 PRFileDesc * model_sock = (PRFileDesc *) b;
730 PRFileDesc * ssl_sock = 0;
731 PRFileDesc * tcp_sock = 0;
733 PRUint32 sleepInterval = 50; /* milliseconds */
736 PRSocketOptionData opt;
740 tcp_sock = PR_OpenTCPSocket(addr->raw.family);
741 if (tcp_sock == NULL) {
742 errExit("PR_OpenTCPSocket");
745 opt.option = PR_SockOpt_Nonblocking;
746 opt.value.non_blocking = PR_FALSE;
747 prStatus = PR_SetSocketOption(tcp_sock, &opt);
748 if (prStatus != PR_SUCCESS) {
749 errWarn("PR_SetSocketOption(PR_SockOpt_Nonblocking, PR_FALSE)");
755 opt.option = PR_SockOpt_NoDelay;
756 opt.value.no_delay = PR_TRUE;
757 prStatus = PR_SetSocketOption(tcp_sock, &opt);
758 if (prStatus != PR_SUCCESS) {
759 errWarn("PR_SetSocketOption(PR_SockOpt_NoDelay, PR_TRUE)");
765 prStatus = PR_Connect(tcp_sock, addr, PR_INTERVAL_NO_TIMEOUT);
766 if (prStatus != PR_SUCCESS) {
767 PRErrorCode err = PR_GetError(); /* save error code */
769 PRTime now = PR_Now();
771 lastConnectFailure = PR_MAX(now, lastConnectFailure);
772 PR_Unlock(threadLock);
774 if ((err == PR_CONNECT_REFUSED_ERROR) ||
775 (err == PR_CONNECT_RESET_ERROR) ) {
776 int connections = numConnected;
780 if (connections > 2 && active_threads >= connections) {
781 active_threads = connections - 1;
782 fprintf(stderr,"active_threads set down to %d\n",
785 PR_Unlock(threadLock);
787 if (QuitOnTimeout && sleepInterval > 40000) {
789 "strsclnt: Client timed out waiting for connection to server.\n");
792 PR_Sleep(PR_MillisecondsToInterval(sleepInterval));
796 errWarn("PR_Connect");
801 PRTime now = PR_Now();
803 lastConnectSuccess = PR_MAX(now, lastConnectSuccess);
804 PR_Unlock(threadLock);
808 ssl_sock = SSL_ImportFD(model_sock, tcp_sock);
809 /* XXX if this import fails, close tcp_sock and return. */
814 if (fullhs != NO_FULLHS_PERCENTAGE) {
815 #ifdef USE_SOCK_PEER_ID
816 char sockPeerIDString[512];
817 static PRInt32 sockPeerID = 0; /* atomically incremented */
820 PRInt32 savid = PR_ATOMIC_INCREMENT(&globalconid);
821 PRInt32 conid = 1 + (savid - 1) % 100;
822 /* don't change peer ID on the very first handshake, which is always
823 a full, so the session gets stored into the client cache */
825 ( ( (savid <= total_connections_rounded_down_to_hundreds) &&
826 (conid <= fullhs) ) ||
827 (conid*100 <= total_connections_modulo_100*fullhs ) ) )
828 #ifdef USE_SOCK_PEER_ID
830 /* force a full handshake by changing the socket peer ID */
831 thisPeerID = PR_ATOMIC_INCREMENT(&sockPeerID);
833 /* reuse previous sockPeerID for restart handhsake */
834 thisPeerID = lastFullHandshakePeerID;
836 PR_snprintf(sockPeerIDString, sizeof(sockPeerIDString), "ID%d",
838 SSL_SetSockPeerID(ssl_sock, sockPeerIDString);
839 SSL_HandshakeCallback(ssl_sock, myHandshakeCallback, (void*)thisPeerID);
841 /* force a full handshake by setting the no cache option */
842 SSL_OptionSet(ssl_sock, SSL_NO_CACHE, 1);
845 rv = SSL_ResetHandshake(ssl_sock, /* asServer */ 0);
846 if (rv != SECSuccess) {
847 errWarn("SSL_ResetHandshake");
851 PR_ATOMIC_INCREMENT(&numConnected);
853 if (bigBuf.data != NULL) {
854 result = handle_fdx_connection( ssl_sock, tid);
856 result = handle_connection( ssl_sock, tid);
859 PR_ATOMIC_DECREMENT(&numConnected);
864 } else if (tcp_sock) {
874 CERTCertificate* cert;
875 SECKEYPrivateKey* key;
879 PRBool FindCertAndKey(cert_and_key* Cert_And_Key)
881 if ( (NULL == Cert_And_Key->nickname) || (0 == strcmp(Cert_And_Key->nickname,"none"))) {
884 Cert_And_Key->cert = CERT_FindUserCertByUsage(CERT_GetDefaultCertDB(),
885 Cert_And_Key->nickname, certUsageSSLClient,
886 PR_FALSE, Cert_And_Key->wincx);
887 if (Cert_And_Key->cert) {
888 Cert_And_Key->key = PK11_FindKeyByAnyCert(Cert_And_Key->cert, Cert_And_Key->wincx);
890 if (Cert_And_Key->cert && Cert_And_Key->key) {
897 PRBool LoggedIn(CERTCertificate* cert, SECKEYPrivateKey* key)
899 if ( (cert->slot) && (key->pkcs11Slot) &&
900 (PR_TRUE == PK11_IsLoggedIn(cert->slot, NULL)) &&
901 (PR_TRUE == PK11_IsLoggedIn(key->pkcs11Slot, NULL)) ) {
909 StressClient_GetClientAuthData(void * arg,
911 struct CERTDistNamesStr * caNames,
912 struct CERTCertificateStr ** pRetCert,
913 struct SECKEYPrivateKeyStr **pRetKey)
915 cert_and_key* Cert_And_Key = (cert_and_key*) arg;
917 if (!pRetCert || !pRetKey) {
918 /* bad pointers, can't return a cert or key */
925 if (Cert_And_Key && Cert_And_Key->nickname) {
927 if (Cert_And_Key && Cert_And_Key->lock) {
929 PR_Lock(Cert_And_Key->lock);
931 if (Cert_And_Key->cert) {
932 *pRetCert = CERT_DupCertificate(Cert_And_Key->cert);
935 if (Cert_And_Key->key) {
936 *pRetKey = SECKEY_CopyPrivateKey(Cert_And_Key->key);
938 PR_Unlock(Cert_And_Key->lock);
939 if (!*pRetCert || !*pRetKey) {
940 /* one or both of them failed to copy. Either the source was NULL, or there was
941 ** an out of memory condition. Free any allocated copy and fail */
943 CERT_DestroyCertificate(*pRetCert);
947 SECKEY_DestroyPrivateKey(*pRetKey);
952 /* now check if those objects are valid */
953 if ( PR_FALSE == LoggedIn(*pRetCert, *pRetKey) ) {
954 /* token is no longer logged in, it was removed */
956 /* first, delete and clear our invalid local objects */
957 CERT_DestroyCertificate(*pRetCert);
958 SECKEY_DestroyPrivateKey(*pRetKey);
962 PR_Lock(Cert_And_Key->lock);
963 /* check if another thread already logged back in */
964 if (PR_TRUE == LoggedIn(Cert_And_Key->cert, Cert_And_Key->key)) {
965 /* yes : try again */
966 PR_Unlock(Cert_And_Key->lock);
969 /* this is the thread to retry */
970 CERT_DestroyCertificate(Cert_And_Key->cert);
971 SECKEY_DestroyPrivateKey(Cert_And_Key->key);
972 Cert_And_Key->cert = NULL;
973 Cert_And_Key->key = NULL;
976 /* now look up the cert and key again */
977 while (PR_FALSE == FindCertAndKey(Cert_And_Key) ) {
978 PR_Sleep(PR_SecondsToInterval(1));
981 printf("\nToken pulled and not reinserted early enough : aborting.\n");
985 PR_Unlock(Cert_And_Key->lock);
987 /* try again to reduce code size */
996 /* no cert configured, automatically find the right cert. */
997 CERTCertificate * cert = NULL;
998 SECKEYPrivateKey * privkey = NULL;
999 CERTCertNicknames * names;
1001 void * proto_win = NULL;
1002 SECStatus rv = SECFailure;
1005 proto_win = Cert_And_Key->wincx;
1008 names = CERT_GetCertNicknames(CERT_GetDefaultCertDB(),
1009 SEC_CERT_NICKNAMES_USER, proto_win);
1010 if (names != NULL) {
1011 for (i = 0; i < names->numnicknames; i++) {
1012 cert = CERT_FindUserCertByUsage(CERT_GetDefaultCertDB(),
1013 names->nicknames[i], certUsageSSLClient,
1014 PR_FALSE, proto_win);
1017 /* Only check unexpired certs */
1018 if (CERT_CheckCertValidTimes(cert, PR_Now(), PR_TRUE) !=
1019 secCertTimeValid ) {
1020 CERT_DestroyCertificate(cert);
1023 rv = NSS_CmpCertChainWCANames(cert, caNames);
1024 if ( rv == SECSuccess ) {
1025 privkey = PK11_FindKeyByAnyCert(cert, proto_win);
1030 CERT_DestroyCertificate(cert);
1032 CERT_FreeNicknames(names);
1034 if (rv == SECSuccess) {
1043 hexchar_to_int(int c)
1045 if (((c) >= '0') && ((c) <= '9'))
1047 if (((c) >= 'a') && ((c) <= 'f'))
1048 return (c) - 'a' + 10;
1049 if (((c) >= 'A') && ((c) <= 'F'))
1050 return (c) - 'A' + 10;
1057 unsigned short port,
1059 cert_and_key* Cert_And_Key,
1060 const char * hostName,
1061 const char * sniHostName)
1063 PRFileDesc *model_sock = NULL;
1069 status = PR_StringToNetAddr(hostName, &addr);
1070 if (status == PR_SUCCESS) {
1071 addr.inet.port = PR_htons(port);
1074 PRAddrInfo *addrInfo;
1075 void *enumPtr = NULL;
1077 addrInfo = PR_GetAddrInfoByName(hostName, PR_AF_UNSPEC,
1078 PR_AI_ADDRCONFIG | PR_AI_NOCANONNAME);
1080 SECU_PrintError(progName, "error looking up host");
1084 enumPtr = PR_EnumerateAddrInfo(enumPtr, addrInfo, port, &addr);
1085 } while (enumPtr != NULL &&
1086 addr.raw.family != PR_AF_INET &&
1087 addr.raw.family != PR_AF_INET6);
1088 PR_FreeAddrInfo(addrInfo);
1089 if (enumPtr == NULL) {
1090 SECU_PrintError(progName, "error looking up host address");
1095 /* all suites except RSA_NULL_MD5 are enabled by Domestic Policy */
1096 NSS_SetDomesticPolicy();
1098 /* all the SSL2 and SSL3 cipher suites are enabled by default. */
1102 /* disable all the ciphers, then enable the ones we want. */
1103 disableAllSSLCiphers();
1105 while (0 != (ndx = *cipherString)) {
1106 const char * startCipher = cipherString++;
1111 cipher = hexchar_to_int(*cipherString++);
1113 cipher |= hexchar_to_int(*cipherString++);
1115 cipher |= hexchar_to_int(*cipherString++);
1117 cipher |= hexchar_to_int(*cipherString++);
1119 fprintf(stderr, "strsclnt: Invalid cipher value: %-5.5s\n",
1128 cptr = islower(ndx) ? ssl3CipherSuites : ssl2CipherSuites;
1129 for (ndx &= 0x1f; (cipher = *cptr++) != 0 && --ndx > 0; )
1133 fprintf(stderr, "strsclnt: Invalid cipher letter: %c\n",
1139 rv = SSL_CipherPrefSetDefault(cipher, PR_TRUE);
1140 if (rv != SECSuccess) {
1142 "strsclnt: SSL_CipherPrefSetDefault(0x%04x) failed\n",
1150 /* configure model SSL socket. */
1152 model_sock = PR_OpenTCPSocket(addr.raw.family);
1153 if (model_sock == NULL) {
1154 errExit("PR_OpenTCPSocket for model socket");
1157 model_sock = SSL_ImportFD(NULL, model_sock);
1158 if (model_sock == NULL) {
1159 errExit("SSL_ImportFD");
1162 /* do SSL configuration. */
1164 rv = SSL_OptionSet(model_sock, SSL_SECURITY,
1165 enableSSL2 || enabledVersions.min != 0);
1167 errExit("SSL_OptionSet SSL_SECURITY");
1170 rv = SSL_VersionRangeSet(model_sock, &enabledVersions);
1171 if (rv != SECSuccess) {
1172 errExit("error setting SSL/TLS version range ");
1175 rv = SSL_OptionSet(model_sock, SSL_ENABLE_SSL2, enableSSL2);
1176 if (rv != SECSuccess) {
1177 errExit("error enabling SSLv2 ");
1180 rv = SSL_OptionSet(model_sock, SSL_V2_COMPATIBLE_HELLO, enableSSL2);
1181 if (rv != SECSuccess) {
1182 errExit("error enabling SSLv2 compatible hellos ");
1185 if (bigBuf.data) { /* doing FDX */
1186 rv = SSL_OptionSet(model_sock, SSL_ENABLE_FDX, 1);
1188 errExit("SSL_OptionSet SSL_ENABLE_FDX");
1193 rv = SSL_OptionSet(model_sock, SSL_NO_CACHE, 1);
1195 errExit("SSL_OptionSet SSL_NO_CACHE");
1200 rv = SSL_OptionSet(model_sock, SSL_BYPASS_PKCS11, 1);
1202 errExit("SSL_OptionSet SSL_BYPASS_PKCS11");
1206 if (disableLocking) {
1207 rv = SSL_OptionSet(model_sock, SSL_NO_LOCKS, 1);
1209 errExit("SSL_OptionSet SSL_NO_LOCKS");
1213 if (enableSessionTickets) {
1214 rv = SSL_OptionSet(model_sock, SSL_ENABLE_SESSION_TICKETS, PR_TRUE);
1215 if (rv != SECSuccess)
1216 errExit("SSL_OptionSet SSL_ENABLE_SESSION_TICKETS");
1219 if (enableCompression) {
1220 rv = SSL_OptionSet(model_sock, SSL_ENABLE_DEFLATE, PR_TRUE);
1221 if (rv != SECSuccess)
1222 errExit("SSL_OptionSet SSL_ENABLE_DEFLATE");
1225 if (enableFalseStart) {
1226 rv = SSL_OptionSet(model_sock, SSL_ENABLE_FALSE_START, PR_TRUE);
1227 if (rv != SECSuccess)
1228 errExit("SSL_OptionSet SSL_ENABLE_FALSE_START");
1231 if (enableCertStatus) {
1232 rv = SSL_OptionSet(model_sock, SSL_ENABLE_OCSP_STAPLING, PR_TRUE);
1233 if (rv != SECSuccess)
1234 errExit("SSL_OptionSet SSL_ENABLE_OCSP_STAPLING");
1237 SSL_SetPKCS11PinArg(model_sock, &pwdata);
1239 SSL_SetURL(model_sock, hostName);
1241 SSL_AuthCertificateHook(model_sock, mySSLAuthCertificate,
1242 (void *)CERT_GetDefaultCertDB());
1243 SSL_BadCertHook(model_sock, myBadCertHandler, NULL);
1245 SSL_GetClientAuthDataHook(model_sock, StressClient_GetClientAuthData, (void*)Cert_And_Key);
1248 SSL_SetURL(model_sock, sniHostName);
1250 /* I'm not going to set the HandshakeCallback function. */
1252 /* end of ssl configuration. */
1256 remaining_connections = total_connections = connections;
1257 total_connections_modulo_100 = total_connections % 100;
1258 total_connections_rounded_down_to_hundreds =
1259 total_connections - total_connections_modulo_100;
1262 remaining_connections = 1;
1263 rv = launch_thread(do_connects, &addr, model_sock, 0);
1264 /* wait for the first connection to terminate, then launch the rest. */
1266 remaining_connections = total_connections - 1 ;
1268 if (remaining_connections > 0) {
1269 active_threads = PR_MIN(active_threads, remaining_connections);
1270 /* Start up the threads */
1271 for (i=0;i<active_threads;i++) {
1272 rv = launch_thread(do_connects, &addr, model_sock, i);
1276 destroy_thread_data();
1278 PR_Close(model_sock);
1282 readBigFile(const char * fileName)
1286 SECStatus rv = SECFailure;
1289 PRFileDesc *local_file_fd = NULL;
1291 status = PR_GetFileInfo(fileName, &info);
1293 if (status == PR_SUCCESS &&
1294 info.type == PR_FILE_FILE &&
1296 NULL != (local_file_fd = PR_Open(fileName, PR_RDONLY, 0))) {
1298 hdrLen = PORT_Strlen(outHeader);
1299 bigBuf.len = hdrLen + info.size;
1300 bigBuf.data = PORT_Malloc(bigBuf.len + 4095);
1302 errWarn("PORT_Malloc");
1306 PORT_Memcpy(bigBuf.data, outHeader, hdrLen);
1308 count = PR_Read(local_file_fd, bigBuf.data + hdrLen, info.size);
1309 if (count != info.size) {
1310 errWarn("PR_Read local file");
1315 PR_Close(local_file_fd);
1321 main(int argc, char **argv)
1323 const char * dir = ".";
1324 const char * fileName = NULL;
1325 char * hostName = NULL;
1326 char * nickName = NULL;
1328 int connections = 1;
1331 unsigned short port = 443;
1333 PLOptState * optstate;
1335 cert_and_key Cert_And_Key;
1336 char * sniHostName = NULL;
1338 /* Call the NSPR initialization routines */
1339 PR_Init( PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
1340 SSL_VersionRangeGetSupported(ssl_variant_stream, &enabledVersions);
1342 tmp = strrchr(argv[0], '/');
1343 tmp = tmp ? tmp + 1 : argv[0];
1344 progName = strrchr(tmp, '\\');
1345 progName = progName ? progName + 1 : tmp;
1348 optstate = PL_CreateOptState(argc, argv,
1349 "BC:DNP:TUV:W:a:c:d:f:gin:op:qst:uvw:z");
1350 while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
1351 switch(optstate->option) {
1352 case 'B': bypassPKCS11 = PR_TRUE; break;
1354 case 'C': cipherString = optstate->value; break;
1356 case 'D': NoDelay = PR_TRUE; break;
1358 case 'I': /* reserved for OCSP multi-stapling */ break;
1360 case 'N': NoReuse = 1; break;
1362 case 'P': fullhs = PORT_Atoi(optstate->value); break;
1364 case 'T': enableCertStatus = PR_TRUE; break;
1366 case 'U': ThrottleUp = PR_TRUE; break;
1368 case 'V': if (SECU_ParseSSLVersionRangeString(optstate->value,
1369 enabledVersions, enableSSL2,
1370 &enabledVersions, &enableSSL2) != SECSuccess) {
1375 case 'a': sniHostName = PL_strdup(optstate->value); break;
1377 case 'c': connections = PORT_Atoi(optstate->value); break;
1379 case 'd': dir = optstate->value; break;
1381 case 'f': fileName = optstate->value; break;
1383 case 'g': enableFalseStart = PR_TRUE; break;
1385 case 'i': ignoreErrors = PR_TRUE; break;
1387 case 'n': nickName = PL_strdup(optstate->value); break;
1389 case 'o': MakeCertOK++; break;
1391 case 'p': port = PORT_Atoi(optstate->value); break;
1393 case 'q': QuitOnTimeout = PR_TRUE; break;
1395 case 's': disableLocking = PR_TRUE; break;
1398 tmpInt = PORT_Atoi(optstate->value);
1399 if (tmpInt > 0 && tmpInt < MAX_THREADS)
1400 max_threads = active_threads = tmpInt;
1403 case 'u': enableSessionTickets = PR_TRUE; break;
1405 case 'v': verbose++; break;
1408 pwdata.source = PW_PLAINTEXT;
1409 pwdata.data = PL_strdup(optstate->value);
1413 pwdata.source = PW_FROMFILE;
1414 pwdata.data = PL_strdup(optstate->value);
1417 case 'z': enableCompression = PR_TRUE; break;
1419 case 0: /* positional parameter */
1423 hostName = PL_strdup(optstate->value);
1433 PL_DestroyOptState(optstate);
1435 if (!hostName || status == PL_OPT_BAD)
1438 if (fullhs!= NO_FULLHS_PERCENTAGE && (fullhs < 0 || fullhs>100 || NoReuse) )
1445 readBigFile(fileName);
1447 PK11_SetPasswordFunc(SECU_GetModulePassword);
1449 tmp = PR_GetEnv("NSS_DEBUG_TIMEOUT");
1450 if (tmp && tmp[0]) {
1451 int sec = PORT_Atoi(tmp);
1453 maxInterval = PR_SecondsToInterval(sec);
1457 /* Call the NSS initialization routines */
1458 rv = NSS_Initialize(dir, "", "", SECMOD_DB, NSS_INIT_READONLY);
1459 if (rv != SECSuccess) {
1460 fputs("NSS_Init failed.\n", stderr);
1463 ssl3stats = SSL_GetStatistics();
1464 Cert_And_Key.lock = PR_NewLock();
1465 Cert_And_Key.nickname = nickName;
1466 Cert_And_Key.wincx = &pwdata;
1467 Cert_And_Key.cert = NULL;
1468 Cert_And_Key.key = NULL;
1470 if (PR_FALSE == FindCertAndKey(&Cert_And_Key)) {
1472 if (Cert_And_Key.cert == NULL) {
1473 fprintf(stderr, "strsclnt: Can't find certificate %s\n", Cert_And_Key.nickname);
1477 if (Cert_And_Key.key == NULL) {
1478 fprintf(stderr, "strsclnt: Can't find Private Key for cert %s\n",
1479 Cert_And_Key.nickname);
1485 client_main(port, connections, &Cert_And_Key, hostName,
1489 if (Cert_And_Key.cert) {
1490 CERT_DestroyCertificate(Cert_And_Key.cert);
1492 if (Cert_And_Key.key) {
1493 SECKEY_DestroyPrivateKey(Cert_And_Key.key);
1496 PR_DestroyLock(Cert_And_Key.lock);
1499 PL_strfree(pwdata.data);
1501 if (Cert_And_Key.nickname) {
1502 PL_strfree(Cert_And_Key.nickname);
1505 PL_strfree(sniHostName);
1508 PL_strfree(hostName);
1510 /* some final stats. */
1511 if (ssl3stats->hsh_sid_cache_hits +
1512 ssl3stats->hsh_sid_cache_misses +
1513 ssl3stats->hsh_sid_cache_not_ok +
1514 ssl3stats->hsh_sid_stateless_resumes == 0) {
1515 /* presumably we were testing SSL2. */
1516 printf("strsclnt: SSL2 - %d server certificates tested.\n",
1520 "strsclnt: %ld cache hits; %ld cache misses, %ld cache not reusable\n"
1521 " %ld stateless resumes\n",
1522 ssl3stats->hsh_sid_cache_hits,
1523 ssl3stats->hsh_sid_cache_misses,
1524 ssl3stats->hsh_sid_cache_not_ok,
1525 ssl3stats->hsh_sid_stateless_resumes);
1529 if (enableSessionTickets)
1530 exitVal = (ssl3stats->hsh_sid_stateless_resumes == 0);
1532 exitVal = (ssl3stats->hsh_sid_cache_misses > 1) ||
1533 (ssl3stats->hsh_sid_stateless_resumes != 0);
1535 exitVal = (ssl3stats->hsh_sid_cache_not_ok != 0) ||
1538 printf("strsclnt: NoReuse - %d server certificates tested.\n",
1540 if (ssl3stats->hsh_sid_cache_hits +
1541 ssl3stats->hsh_sid_cache_misses +
1542 ssl3stats->hsh_sid_cache_not_ok +
1543 ssl3stats->hsh_sid_stateless_resumes > 0) {
1544 exitVal = (ssl3stats->hsh_sid_cache_misses != connections) ||
1545 (ssl3stats->hsh_sid_stateless_resumes != 0) ||
1546 (certsTested != connections);
1547 } else { /* ssl2 connections */
1548 exitVal = (certsTested != connections);
1552 exitVal = ( exitVal || failed_already );
1553 SSL_ClearSessionCache();
1554 if (NSS_Shutdown() != SECSuccess) {
1555 printf("strsclnt: NSS_Shutdown() failed.\n");