summaryrefslogtreecommitdiff
path: root/cmd
diff options
context:
space:
mode:
authorMartin Thomson <martin.thomson@gmail.com>2016-11-12 14:04:36 +1100
committerMartin Thomson <martin.thomson@gmail.com>2016-11-12 14:04:36 +1100
commit456bee602bac4865c9689d753256b1a85fae59c5 (patch)
tree15b6498f67c953176e287200e16a827299cecf90 /cmd
parentf5bd9e780d82645e2ba37650479a2a29be7ef92a (diff)
downloadnss-hg-456bee602bac4865c9689d753256b1a85fae59c5.tar.gz
Backed out changesets e76d6d66733d, 37723fa31b87, 0d5d0574e512
Diffstat (limited to 'cmd')
-rw-r--r--cmd/tstclnt/tstclnt.c1025
1 files changed, 461 insertions, 564 deletions
diff --git a/cmd/tstclnt/tstclnt.c b/cmd/tstclnt/tstclnt.c
index 8b9b47a28..6b2d12740 100644
--- a/cmd/tstclnt/tstclnt.c
+++ b/cmd/tstclnt/tstclnt.c
@@ -191,8 +191,7 @@ PrintUsageHeader(const char *progName)
"[-D | -d certdir] [-C] [-b | -R root-module] \n"
"[-n nickname] [-Bafosvx] [-c ciphers] [-Y]\n"
"[-V [min-version]:[max-version]] [-K] [-T] [-U]\n"
- "[-r N] [-w passwd] [-W pwfile] [-q [-t seconds]] [-I groups]\n"
- "[-A requestfile] [-L totalconnections]",
+ "[-r N] [-w passwd] [-W pwfile] [-q [-t seconds]] [-I groups]\n",
progName);
}
@@ -259,8 +258,6 @@ PrintParameterUsage(void)
fprintf(stderr, "%-20s Require the use of FFDHE supported groups "
"[I-D.ietf-tls-negotiated-ff-dhe]\n",
"-H");
- fprintf(stderr, "%-20s Read from a file instead of stdin\n", "-A");
- fprintf(stderr, "%-20s Disconnect and reconnect up to N times total\n", "-L");
fprintf(stderr, "%-20s Comma separated list of enabled groups for TLS key exchange.\n"
"%-20s The following values are valid:\n"
"%-20s P256, P384, P521, x25519, FF2048, FF3072, FF4096, FF6144, FF8192\n",
@@ -893,556 +890,54 @@ restartHandshakeAfterServerCertIfNeeded(PRFileDesc *fd,
return rv;
}
-char *host = NULL;
-char *nickname = NULL;
-char *cipherString = NULL;
-int multiplier = 0;
-SSLVersionRange enabledVersions;
-int disableLocking = 0;
-int enableSessionTickets = 0;
-int enableCompression = 0;
-int enableFalseStart = 0;
-int enableCertStatus = 0;
-int enableSignedCertTimestamps = 0;
-int forceFallbackSCSV = 0;
-int enableExtendedMasterSecret = 0;
-PRBool requireDHNamedGroups = 0;
-PRSocketOptionData opt;
-PRNetAddr addr;
-PRBool allowIPv4 = PR_TRUE;
-PRBool allowIPv6 = PR_TRUE;
-PRBool pingServerFirst = PR_FALSE;
-int pingTimeoutSeconds = -1;
-PRBool clientSpeaksFirst = PR_FALSE;
-PRBool skipProtoHeader = PR_FALSE;
-ServerCertAuth serverCertAuth;
-char *hs1SniHostName = NULL;
-char *hs2SniHostName = NULL;
-PRUint16 portno = 443;
-int override = 0;
-char *requestString = NULL;
-PRInt32 requestStringLen = 0;
-
-static int
-writeBytesToServer(PRFileDesc *s, PRPollDesc *pollset, const char *buf, int nb)
-{
- SECStatus rv;
- const char *bufp = buf;
-
- FPRINTF(stderr, "%s: Writing %d bytes to server\n",
- progName, nb);
- do {
- PRInt32 cc = PR_Send(s, bufp, nb, 0, maxInterval);
- if (cc < 0) {
- PRErrorCode err = PR_GetError();
- if (err != PR_WOULD_BLOCK_ERROR) {
- SECU_PrintError(progName,
- "write to SSL socket failed");
- return 254;
- }
- cc = 0;
- }
- bufp += cc;
- nb -= cc;
- if (nb <= 0)
- break;
-
- rv = restartHandshakeAfterServerCertIfNeeded(s,
- &serverCertAuth, override);
- if (rv != SECSuccess) {
- SECU_PrintError(progName, "authentication of server cert failed");
- return EXIT_CODE_HANDSHAKE_FAILED;
- }
-
- pollset[SSOCK_FD].in_flags = PR_POLL_WRITE | PR_POLL_EXCEPT;
- pollset[SSOCK_FD].out_flags = 0;
- FPRINTF(stderr,
- "%s: about to call PR_Poll on writable socket !\n",
- progName);
- cc = PR_Poll(pollset, 1, PR_INTERVAL_NO_TIMEOUT);
- if (cc < 0) {
- SECU_PrintError(progName,
- "PR_Poll failed");
- return -1;
- }
- FPRINTF(stderr,
- "%s: PR_Poll returned with writable socket !\n",
- progName);
- } while (1);
-
- return 0;
-}
-
-static int
-run_client(void)
+int
+main(int argc, char **argv)
{
- int headerSeparatorPtrnId = 0;
- int error = 0;
+ PRFileDesc *s = NULL;
+ PRFileDesc *std_out;
+ char *host = NULL;
+ char *certDir = NULL;
+ char *nickname = NULL;
+ char *cipherString = NULL;
+ char *tmp;
+ int multiplier = 0;
SECStatus rv;
PRStatus status;
PRInt32 filesReady;
int npds;
- PRFileDesc *s = NULL;
- PRFileDesc *std_out;
+ int override = 0;
+ SSLVersionRange enabledVersions;
+ int disableLocking = 0;
+ int enableSessionTickets = 0;
+ int enableCompression = 0;
+ int enableFalseStart = 0;
+ int enableCertStatus = 0;
+ int enableSignedCertTimestamps = 0;
+ int forceFallbackSCSV = 0;
+ int enableExtendedMasterSecret = 0;
+ PRBool requireDHNamedGroups = 0;
+ PRSocketOptionData opt;
+ PRNetAddr addr;
PRPollDesc pollset[2];
+ PRBool allowIPv4 = PR_TRUE;
+ PRBool allowIPv6 = PR_TRUE;
+ PRBool pingServerFirst = PR_FALSE;
+ int pingTimeoutSeconds = -1;
+ PRBool clientSpeaksFirst = PR_FALSE;
PRBool wrStarted = PR_FALSE;
- char *requestStringInt = requestString;
-
- /* Create socket */
- s = PR_OpenTCPSocket(addr.raw.family);
- if (s == NULL) {
- SECU_PrintError(progName, "error creating socket");
- error = 1;
- goto done;
- }
-
- opt.option = PR_SockOpt_Nonblocking;
- opt.value.non_blocking = PR_TRUE; /* default */
- if (serverCertAuth.testFreshStatusFromSideChannel) {
- opt.value.non_blocking = PR_FALSE;
- }
- PR_SetSocketOption(s, &opt);
- /*PR_SetSocketOption(PR_GetSpecialFD(PR_StandardInput), &opt);*/
-
- s = SSL_ImportFD(NULL, s);
- if (s == NULL) {
- SECU_PrintError(progName, "error importing socket");
- error = 1;
- goto done;
- }
-
- SSL_SetPKCS11PinArg(s, &pwdata);
-
- rv = SSL_OptionSet(s, SSL_SECURITY, 1);
- if (rv != SECSuccess) {
- SECU_PrintError(progName, "error enabling socket");
- error = 1;
- goto done;
- }
-
- rv = SSL_OptionSet(s, SSL_HANDSHAKE_AS_CLIENT, 1);
- if (rv != SECSuccess) {
- SECU_PrintError(progName, "error enabling client handshake");
- error = 1;
- goto done;
- }
-
- /* all SSL3 cipher suites are enabled by default. */
- if (cipherString) {
- char *cstringSaved = cipherString;
- int ndx;
-
- while (0 != (ndx = *cipherString++)) {
- int cipher = 0;
-
- if (ndx == ':') {
- int ctmp = 0;
-
- HEXCHAR_TO_INT(*cipherString, ctmp)
- cipher |= (ctmp << 12);
- cipherString++;
- HEXCHAR_TO_INT(*cipherString, ctmp)
- cipher |= (ctmp << 8);
- cipherString++;
- HEXCHAR_TO_INT(*cipherString, ctmp)
- cipher |= (ctmp << 4);
- cipherString++;
- HEXCHAR_TO_INT(*cipherString, ctmp)
- cipher |= ctmp;
- cipherString++;
- } else {
- if (!isalpha(ndx))
- Usage(progName);
- ndx = tolower(ndx) - 'a';
- if (ndx < PR_ARRAY_SIZE(ssl3CipherSuites)) {
- cipher = ssl3CipherSuites[ndx];
- }
- }
- if (cipher > 0) {
- SECStatus status;
- status = SSL_CipherPrefSet(s, cipher, SSL_ALLOWED);
- if (status != SECSuccess)
- SECU_PrintError(progName, "SSL_CipherPrefSet()");
- } else {
- Usage(progName);
- }
- }
- PORT_Free(cstringSaved);
- }
-
- rv = SSL_VersionRangeSet(s, &enabledVersions);
- if (rv != SECSuccess) {
- SECU_PrintError(progName, "error setting SSL/TLS version range ");
- error = 1;
- goto done;
- }
-
- /* disable SSL socket locking */
- rv = SSL_OptionSet(s, SSL_NO_LOCKS, disableLocking);
- if (rv != SECSuccess) {
- SECU_PrintError(progName, "error disabling SSL socket locking");
- error = 1;
- goto done;
- }
-
- /* enable Session Ticket extension. */
- rv = SSL_OptionSet(s, SSL_ENABLE_SESSION_TICKETS, enableSessionTickets);
- if (rv != SECSuccess) {
- SECU_PrintError(progName, "error enabling Session Ticket extension");
- error = 1;
- goto done;
- }
-
- /* enable compression. */
- rv = SSL_OptionSet(s, SSL_ENABLE_DEFLATE, enableCompression);
- if (rv != SECSuccess) {
- SECU_PrintError(progName, "error enabling compression");
- error = 1;
- goto done;
- }
-
- /* enable false start. */
- rv = SSL_OptionSet(s, SSL_ENABLE_FALSE_START, enableFalseStart);
- if (rv != SECSuccess) {
- SECU_PrintError(progName, "error enabling false start");
- error = 1;
- goto done;
- }
-
- if (forceFallbackSCSV) {
- rv = SSL_OptionSet(s, SSL_ENABLE_FALLBACK_SCSV, PR_TRUE);
- if (rv != SECSuccess) {
- SECU_PrintError(progName, "error forcing fallback scsv");
- error = 1;
- goto done;
- }
- }
-
- /* enable cert status (OCSP stapling). */
- rv = SSL_OptionSet(s, SSL_ENABLE_OCSP_STAPLING, enableCertStatus);
- if (rv != SECSuccess) {
- SECU_PrintError(progName, "error enabling cert status (OCSP stapling)");
- error = 1;
- goto done;
- }
-
- /* enable extended master secret mode */
- if (enableExtendedMasterSecret) {
- rv = SSL_OptionSet(s, SSL_ENABLE_EXTENDED_MASTER_SECRET, PR_TRUE);
- if (rv != SECSuccess) {
- SECU_PrintError(progName, "error enabling extended master secret");
- error = 1;
- goto done;
- }
- }
-
- /* require the use of fixed finite-field DH groups */
- if (requireDHNamedGroups) {
- rv = SSL_OptionSet(s, SSL_REQUIRE_DH_NAMED_GROUPS, PR_TRUE);
- if (rv != SECSuccess) {
- SECU_PrintError(progName, "error in requiring the use of fixed finite-field DH groups");
- error = 1;
- goto done;
- }
- }
-
- /* enable Signed Certificate Timestamps. */
- rv = SSL_OptionSet(s, SSL_ENABLE_SIGNED_CERT_TIMESTAMPS,
- enableSignedCertTimestamps);
- if (rv != SECSuccess) {
- SECU_PrintError(progName, "error enabling signed cert timestamps");
- error = 1;
- goto done;
- }
-
- if (enabledGroups) {
- rv = SSL_NamedGroupConfig(s, enabledGroups, enabledGroupsCount);
- if (rv < 0) {
- SECU_PrintError(progName, "SSL_NamedGroupConfig failed");
- error = 1;
- goto done;
- }
- }
-
- serverCertAuth.dbHandle = CERT_GetDefaultCertDB();
-
- SSL_AuthCertificateHook(s, ownAuthCertificate, &serverCertAuth);
- if (override) {
- SSL_BadCertHook(s, ownBadCertHandler, NULL);
- }
- SSL_GetClientAuthDataHook(s, own_GetClientAuthData, (void *)nickname);
- SSL_HandshakeCallback(s, handshakeCallback, hs2SniHostName);
- if (hs1SniHostName) {
- SSL_SetURL(s, hs1SniHostName);
- } else {
- SSL_SetURL(s, host);
- }
-
- /* Try to connect to the server */
- status = PR_Connect(s, &addr, PR_INTERVAL_NO_TIMEOUT);
- if (status != PR_SUCCESS) {
- if (PR_GetError() == PR_IN_PROGRESS_ERROR) {
- if (verbose)
- SECU_PrintError(progName, "connect");
- milliPause(50 * multiplier);
- pollset[SSOCK_FD].in_flags = PR_POLL_WRITE | PR_POLL_EXCEPT;
- pollset[SSOCK_FD].out_flags = 0;
- pollset[SSOCK_FD].fd = s;
- while (1) {
- FPRINTF(stderr,
- "%s: about to call PR_Poll for connect completion!\n",
- progName);
- filesReady = PR_Poll(pollset, 1, PR_INTERVAL_NO_TIMEOUT);
- if (filesReady < 0) {
- SECU_PrintError(progName, "unable to connect (poll)");
- error = 1;
- goto done;
- }
- FPRINTF(stderr,
- "%s: PR_Poll returned 0x%02x for socket out_flags.\n",
- progName, pollset[SSOCK_FD].out_flags);
- if (filesReady == 0) { /* shouldn't happen! */
- FPRINTF(stderr, "%s: PR_Poll returned zero!\n", progName);
- error = 1;
- goto done;
- }
- status = PR_GetConnectStatus(pollset);
- if (status == PR_SUCCESS) {
- break;
- }
- if (PR_GetError() != PR_IN_PROGRESS_ERROR) {
- SECU_PrintError(progName, "unable to connect (poll)");
- error = 1;
- goto done;
- }
- SECU_PrintError(progName, "poll");
- milliPause(50 * multiplier);
- }
- } else {
- SECU_PrintError(progName, "unable to connect");
- error = 1;
- goto done;
- }
- }
-
- pollset[SSOCK_FD].fd = s;
- pollset[SSOCK_FD].in_flags = PR_POLL_EXCEPT |
- (clientSpeaksFirst ? 0 : PR_POLL_READ);
- pollset[STDIN_FD].fd = PR_GetSpecialFD(PR_StandardInput);
- if (!requestStringInt) {
- pollset[STDIN_FD].in_flags = PR_POLL_READ;
- npds = 1;
- } else {
- npds = 2;
- }
- std_out = PR_GetSpecialFD(PR_StandardOutput);
-
-#if defined(WIN32) || defined(OS2)
- /* PR_Poll cannot be used with stdin on Windows or OS/2. (sigh).
- ** But use of PR_Poll and non-blocking sockets is a major feature
- ** of this program. So, we simulate a pollable stdin with a
- ** TCP socket pair and a thread that reads stdin and writes to
- ** that socket pair.
- */
- {
- PRFileDesc *fds[2];
- PRThread *thread;
-
- int nspr_rv = PR_NewTCPSocketPair(fds);
- if (nspr_rv != PR_SUCCESS) {
- SECU_PrintError(progName, "PR_NewTCPSocketPair failed");
- error = 1;
- goto done;
- }
- pollset[STDIN_FD].fd = fds[1];
-
- thread = PR_CreateThread(PR_USER_THREAD, thread_main, fds[0],
- PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
- PR_UNJOINABLE_THREAD, 0);
- if (!thread) {
- SECU_PrintError(progName, "PR_CreateThread failed");
- error = 1;
- goto done;
- }
- }
-#endif
-
- if (serverCertAuth.testFreshStatusFromSideChannel) {
- SSL_ForceHandshake(s);
- error = serverCertAuth.sideChannelRevocationTestResultCode;
- goto done;
- }
-
- /*
- ** Select on stdin and on the socket. Write data from stdin to
- ** socket, read data from socket and write to stdout.
- */
- FPRINTF(stderr, "%s: ready...\n", progName);
- while ((pollset[SSOCK_FD].in_flags | pollset[STDIN_FD].in_flags) ||
- requestStringInt) {
- char buf[4000]; /* buffer for stdin */
- int nb; /* num bytes read from stdin. */
-
- rv = restartHandshakeAfterServerCertIfNeeded(s, &serverCertAuth,
- override);
- if (rv != SECSuccess) {
- error = EXIT_CODE_HANDSHAKE_FAILED;
- SECU_PrintError(progName, "authentication of server cert failed");
- goto done;
- }
-
- pollset[SSOCK_FD].out_flags = 0;
- pollset[STDIN_FD].out_flags = 0;
-
- FPRINTF(stderr, "%s: about to call PR_Poll !\n", progName);
- filesReady = PR_Poll(pollset, npds, PR_INTERVAL_NO_TIMEOUT);
- if (filesReady < 0) {
- SECU_PrintError(progName, "select failed");
- error = 1;
- goto done;
- }
- if (filesReady == 0) { /* shouldn't happen! */
- FPRINTF(stderr, "%s: PR_Poll returned zero!\n", progName);
- error = 1;
- goto done;
- }
- FPRINTF(stderr, "%s: PR_Poll returned!\n", progName);
- if (pollset[STDIN_FD].in_flags) {
- FPRINTF(stderr,
- "%s: PR_Poll returned 0x%02x for stdin out_flags.\n",
- progName, pollset[STDIN_FD].out_flags);
- }
- if (pollset[SSOCK_FD].in_flags) {
- FPRINTF(stderr,
- "%s: PR_Poll returned 0x%02x for socket out_flags.\n",
- progName, pollset[SSOCK_FD].out_flags);
- }
- if (requestStringInt) {
- error = writeBytesToServer(s, pollset,
- requestStringInt, requestStringLen);
- if (error) {
- goto done;
- }
- requestStringInt = NULL;
- pollset[SSOCK_FD].in_flags = PR_POLL_READ;
- }
- if (pollset[STDIN_FD].out_flags & PR_POLL_READ) {
- /* Read from stdin and write to socket */
- nb = PR_Read(pollset[STDIN_FD].fd, buf, sizeof(buf));
- FPRINTF(stderr, "%s: stdin read %d bytes\n", progName, nb);
- if (nb < 0) {
- if (PR_GetError() != PR_WOULD_BLOCK_ERROR) {
- SECU_PrintError(progName, "read from stdin failed");
- error = 1;
- break;
- }
- } else if (nb == 0) {
- /* EOF on stdin, stop polling stdin for read. */
- pollset[STDIN_FD].in_flags = 0;
- } else {
- error = writeBytesToServer(s, pollset, buf, nb);
- if (error) {
- goto done;
- }
- pollset[SSOCK_FD].in_flags = PR_POLL_READ;
- }
- }
-
- if (pollset[SSOCK_FD].in_flags) {
- FPRINTF(stderr,
- "%s: PR_Poll returned 0x%02x for socket out_flags.\n",
- progName, pollset[SSOCK_FD].out_flags);
- }
- if ((pollset[SSOCK_FD].out_flags & PR_POLL_READ) ||
- (pollset[SSOCK_FD].out_flags & PR_POLL_ERR)
-#ifdef PR_POLL_HUP
- || (pollset[SSOCK_FD].out_flags & PR_POLL_HUP)
-#endif
- ) {
- /* Read from socket and write to stdout */
- nb = PR_Recv(pollset[SSOCK_FD].fd, buf, sizeof buf, 0, maxInterval);
- FPRINTF(stderr, "%s: Read from server %d bytes\n", progName, nb);
- if (nb < 0) {
- if (PR_GetError() != PR_WOULD_BLOCK_ERROR) {
- SECU_PrintError(progName, "read from socket failed");
- error = 1;
- goto done;
- }
- } else if (nb == 0) {
- /* EOF from socket... stop polling socket for read */
- pollset[SSOCK_FD].in_flags = 0;
- } else {
- if (skipProtoHeader != PR_TRUE || wrStarted == PR_TRUE) {
- PR_Write(std_out, buf, nb);
- } else {
- separateReqHeader(std_out, buf, nb, &wrStarted,
- &headerSeparatorPtrnId);
- }
- if (verbose)
- fputs("\n\n", stderr);
- }
- }
- milliPause(50 * multiplier);
- }
-
-done:
- if (s) {
- PR_Close(s);
- }
-
- return error;
-}
-
-PRInt32
-ReadFile(const char *filename, char **data)
-{
- char *ret = NULL;
- char buf[8192];
- unsigned int len = 0;
- PRStatus rv;
-
- PRFileDesc *fd = PR_Open(filename, PR_RDONLY, 0);
- if (!fd)
- return -1;
-
- for (;;) {
- rv = PR_Read(fd, buf, sizeof(buf));
- if (rv < 0) {
- PR_Free(ret);
- return rv;
- }
-
- if (!rv)
- break;
-
- ret = PR_Realloc(ret, len + rv);
- if (!ret) {
- return -1;
- }
- PORT_Memcpy(ret + len, buf, rv);
- len += rv;
- }
-
- *data = ret;
- return len;
-}
-
-int
-main(int argc, char **argv)
-{
+ PRBool skipProtoHeader = PR_FALSE;
+ ServerCertAuth serverCertAuth;
+ int headerSeparatorPtrnId = 0;
+ int error = 0;
+ PRUint16 portno = 443;
+ char *hs1SniHostName = NULL;
+ char *hs2SniHostName = NULL;
PLOptState *optstate;
PLOptStatus optstatus;
- PRStatus status;
PRStatus prStatus;
- int error = 0;
- char *tmp;
- SECStatus rv;
- char *certDir = NULL;
PRBool openDB = PR_TRUE;
PRBool loadDefaultRootCAs = PR_FALSE;
char *rootModule = NULL;
- int numConnections = 1;
- PRFileDesc *s = NULL;
serverCertAuth.shouldPause = PR_TRUE;
serverCertAuth.isPaused = PR_FALSE;
@@ -1471,7 +966,7 @@ main(int argc, char **argv)
/* XXX: 'B' was used in the past but removed in 3.28,
* please leave some time before resuing it. */
optstate = PL_CreateOptState(argc, argv,
- "46A:CDFGHI:KL:M:OR:STUV:WZ:Ya:bc:d:fgh:m:n:op:qr:st:uvw:z");
+ "46CDFGHI:KM:OR:STUV:W:Ya:bc:d:fgh:m:n:op:qr:st:uvw:z");
while ((optstatus = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
switch (optstate->option) {
case '?':
@@ -1490,14 +985,6 @@ main(int argc, char **argv)
Usage(progName);
break;
- case 'A':
- requestStringLen = ReadFile(optstate->value, &requestString);
- if (requestStringLen < 0) {
- fprintf(stderr, "Couldn't read file %s\n", optstate->value);
- exit(1);
- }
- break;
-
case 'C':
++dumpServerChain;
break;
@@ -1530,10 +1017,6 @@ main(int argc, char **argv)
forceFallbackSCSV = PR_TRUE;
break;
- case 'L':
- numConnections = atoi(optstate->value);
- break;
-
case 'M':
switch (atoi(optstate->value)) {
case 1:
@@ -1759,7 +1242,6 @@ main(int argc, char **argv)
if (pingServerFirst) {
int iter = 0;
PRErrorCode err;
-
int max_attempts = MAX_WAIT_FOR_SERVER;
if (pingTimeoutSeconds >= 0) {
/* If caller requested a timeout, let's try just twice. */
@@ -1788,7 +1270,7 @@ main(int argc, char **argv)
prStatus = PR_Connect(s, &addr, timeoutInterval);
if (prStatus == PR_SUCCESS) {
PR_Shutdown(s, PR_SHUTDOWN_BOTH);
- goto success;
+ goto done;
}
err = PR_GetError();
if ((err != PR_CONNECT_REFUSED_ERROR) &&
@@ -1807,7 +1289,6 @@ main(int argc, char **argv)
goto done;
}
-success:
/* open the cert DB, the key DB, and the secmod DB. */
if (openDB) {
rv = NSS_Init(certDir);
@@ -1838,18 +1319,431 @@ success:
disableAllSSLCiphers();
}
- while (numConnections--) {
- error = run_client();
- if (error) {
+ /* Create socket */
+ s = PR_OpenTCPSocket(addr.raw.family);
+ if (s == NULL) {
+ SECU_PrintError(progName, "error creating socket");
+ error = 1;
+ goto done;
+ }
+
+ opt.option = PR_SockOpt_Nonblocking;
+ opt.value.non_blocking = PR_TRUE; /* default */
+ if (serverCertAuth.testFreshStatusFromSideChannel) {
+ opt.value.non_blocking = PR_FALSE;
+ }
+ PR_SetSocketOption(s, &opt);
+ /*PR_SetSocketOption(PR_GetSpecialFD(PR_StandardInput), &opt);*/
+
+ s = SSL_ImportFD(NULL, s);
+ if (s == NULL) {
+ SECU_PrintError(progName, "error importing socket");
+ error = 1;
+ goto done;
+ }
+
+ SSL_SetPKCS11PinArg(s, &pwdata);
+
+ rv = SSL_OptionSet(s, SSL_SECURITY, 1);
+ if (rv != SECSuccess) {
+ SECU_PrintError(progName, "error enabling socket");
+ error = 1;
+ goto done;
+ }
+
+ rv = SSL_OptionSet(s, SSL_HANDSHAKE_AS_CLIENT, 1);
+ if (rv != SECSuccess) {
+ SECU_PrintError(progName, "error enabling client handshake");
+ error = 1;
+ goto done;
+ }
+
+ /* all SSL3 cipher suites are enabled by default. */
+ if (cipherString) {
+ char *cstringSaved = cipherString;
+ int ndx;
+
+ while (0 != (ndx = *cipherString++)) {
+ int cipher = 0;
+
+ if (ndx == ':') {
+ int ctmp = 0;
+
+ HEXCHAR_TO_INT(*cipherString, ctmp)
+ cipher |= (ctmp << 12);
+ cipherString++;
+ HEXCHAR_TO_INT(*cipherString, ctmp)
+ cipher |= (ctmp << 8);
+ cipherString++;
+ HEXCHAR_TO_INT(*cipherString, ctmp)
+ cipher |= (ctmp << 4);
+ cipherString++;
+ HEXCHAR_TO_INT(*cipherString, ctmp)
+ cipher |= ctmp;
+ cipherString++;
+ } else {
+ if (!isalpha(ndx))
+ Usage(progName);
+ ndx = tolower(ndx) - 'a';
+ if (ndx < PR_ARRAY_SIZE(ssl3CipherSuites)) {
+ cipher = ssl3CipherSuites[ndx];
+ }
+ }
+ if (cipher > 0) {
+ SECStatus status;
+ status = SSL_CipherPrefSet(s, cipher, SSL_ALLOWED);
+ if (status != SECSuccess)
+ SECU_PrintError(progName, "SSL_CipherPrefSet()");
+ } else {
+ Usage(progName);
+ }
+ }
+ PORT_Free(cstringSaved);
+ }
+
+ rv = SSL_VersionRangeSet(s, &enabledVersions);
+ if (rv != SECSuccess) {
+ SECU_PrintError(progName, "error setting SSL/TLS version range ");
+ error = 1;
+ goto done;
+ }
+
+ /* disable SSL socket locking */
+ rv = SSL_OptionSet(s, SSL_NO_LOCKS, disableLocking);
+ if (rv != SECSuccess) {
+ SECU_PrintError(progName, "error disabling SSL socket locking");
+ error = 1;
+ goto done;
+ }
+
+ /* enable Session Ticket extension. */
+ rv = SSL_OptionSet(s, SSL_ENABLE_SESSION_TICKETS, enableSessionTickets);
+ if (rv != SECSuccess) {
+ SECU_PrintError(progName, "error enabling Session Ticket extension");
+ error = 1;
+ goto done;
+ }
+
+ /* enable compression. */
+ rv = SSL_OptionSet(s, SSL_ENABLE_DEFLATE, enableCompression);
+ if (rv != SECSuccess) {
+ SECU_PrintError(progName, "error enabling compression");
+ error = 1;
+ goto done;
+ }
+
+ /* enable false start. */
+ rv = SSL_OptionSet(s, SSL_ENABLE_FALSE_START, enableFalseStart);
+ if (rv != SECSuccess) {
+ SECU_PrintError(progName, "error enabling false start");
+ error = 1;
+ goto done;
+ }
+
+ if (forceFallbackSCSV) {
+ rv = SSL_OptionSet(s, SSL_ENABLE_FALLBACK_SCSV, PR_TRUE);
+ if (rv != SECSuccess) {
+ SECU_PrintError(progName, "error forcing fallback scsv");
+ error = 1;
goto done;
}
}
-done:
- if (s) {
- PR_Close(s);
+ /* enable cert status (OCSP stapling). */
+ rv = SSL_OptionSet(s, SSL_ENABLE_OCSP_STAPLING, enableCertStatus);
+ if (rv != SECSuccess) {
+ SECU_PrintError(progName, "error enabling cert status (OCSP stapling)");
+ error = 1;
+ goto done;
+ }
+
+ /* enable extended master secret mode */
+ if (enableExtendedMasterSecret) {
+ rv = SSL_OptionSet(s, SSL_ENABLE_EXTENDED_MASTER_SECRET, PR_TRUE);
+ if (rv != SECSuccess) {
+ SECU_PrintError(progName, "error enabling extended master secret");
+ error = 1;
+ goto done;
+ }
+ }
+
+ /* require the use of fixed finite-field DH groups */
+ if (requireDHNamedGroups) {
+ rv = SSL_OptionSet(s, SSL_REQUIRE_DH_NAMED_GROUPS, PR_TRUE);
+ if (rv != SECSuccess) {
+ SECU_PrintError(progName, "error in requiring the use of fixed finite-field DH groups");
+ error = 1;
+ goto done;
+ }
+ }
+
+ /* enable Signed Certificate Timestamps. */
+ rv = SSL_OptionSet(s, SSL_ENABLE_SIGNED_CERT_TIMESTAMPS,
+ enableSignedCertTimestamps);
+ if (rv != SECSuccess) {
+ SECU_PrintError(progName, "error enabling signed cert timestamps");
+ error = 1;
+ goto done;
+ }
+
+ if (enabledGroups) {
+ rv = SSL_NamedGroupConfig(s, enabledGroups, enabledGroupsCount);
+ if (rv < 0) {
+ SECU_PrintError(progName, "SSL_NamedGroupConfig failed");
+ error = 1;
+ goto done;
+ }
+ }
+
+ serverCertAuth.dbHandle = CERT_GetDefaultCertDB();
+
+ SSL_AuthCertificateHook(s, ownAuthCertificate, &serverCertAuth);
+ if (override) {
+ SSL_BadCertHook(s, ownBadCertHandler, NULL);
+ }
+ SSL_GetClientAuthDataHook(s, own_GetClientAuthData, (void *)nickname);
+ SSL_HandshakeCallback(s, handshakeCallback, hs2SniHostName);
+ if (hs1SniHostName) {
+ SSL_SetURL(s, hs1SniHostName);
+ } else {
+ SSL_SetURL(s, host);
}
+ /* Try to connect to the server */
+ status = PR_Connect(s, &addr, PR_INTERVAL_NO_TIMEOUT);
+ if (status != PR_SUCCESS) {
+ if (PR_GetError() == PR_IN_PROGRESS_ERROR) {
+ if (verbose)
+ SECU_PrintError(progName, "connect");
+ milliPause(50 * multiplier);
+ pollset[SSOCK_FD].in_flags = PR_POLL_WRITE | PR_POLL_EXCEPT;
+ pollset[SSOCK_FD].out_flags = 0;
+ pollset[SSOCK_FD].fd = s;
+ while (1) {
+ FPRINTF(stderr,
+ "%s: about to call PR_Poll for connect completion!\n",
+ progName);
+ filesReady = PR_Poll(pollset, 1, PR_INTERVAL_NO_TIMEOUT);
+ if (filesReady < 0) {
+ SECU_PrintError(progName, "unable to connect (poll)");
+ error = 1;
+ goto done;
+ }
+ FPRINTF(stderr,
+ "%s: PR_Poll returned 0x%02x for socket out_flags.\n",
+ progName, pollset[SSOCK_FD].out_flags);
+ if (filesReady == 0) { /* shouldn't happen! */
+ FPRINTF(stderr, "%s: PR_Poll returned zero!\n", progName);
+ error = 1;
+ goto done;
+ }
+ status = PR_GetConnectStatus(pollset);
+ if (status == PR_SUCCESS) {
+ break;
+ }
+ if (PR_GetError() != PR_IN_PROGRESS_ERROR) {
+ SECU_PrintError(progName, "unable to connect (poll)");
+ error = 1;
+ goto done;
+ }
+ SECU_PrintError(progName, "poll");
+ milliPause(50 * multiplier);
+ }
+ } else {
+ SECU_PrintError(progName, "unable to connect");
+ error = 1;
+ goto done;
+ }
+ }
+
+ pollset[SSOCK_FD].fd = s;
+ pollset[SSOCK_FD].in_flags = PR_POLL_EXCEPT |
+ (clientSpeaksFirst ? 0 : PR_POLL_READ);
+ pollset[STDIN_FD].fd = PR_GetSpecialFD(PR_StandardInput);
+ pollset[STDIN_FD].in_flags = PR_POLL_READ;
+ npds = 2;
+ std_out = PR_GetSpecialFD(PR_StandardOutput);
+
+#if defined(WIN32) || defined(OS2)
+ /* PR_Poll cannot be used with stdin on Windows or OS/2. (sigh).
+ ** But use of PR_Poll and non-blocking sockets is a major feature
+ ** of this program. So, we simulate a pollable stdin with a
+ ** TCP socket pair and a thread that reads stdin and writes to
+ ** that socket pair.
+ */
+ {
+ PRFileDesc *fds[2];
+ PRThread *thread;
+
+ int nspr_rv = PR_NewTCPSocketPair(fds);
+ if (nspr_rv != PR_SUCCESS) {
+ SECU_PrintError(progName, "PR_NewTCPSocketPair failed");
+ error = 1;
+ goto done;
+ }
+ pollset[STDIN_FD].fd = fds[1];
+
+ thread = PR_CreateThread(PR_USER_THREAD, thread_main, fds[0],
+ PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
+ PR_UNJOINABLE_THREAD, 0);
+ if (!thread) {
+ SECU_PrintError(progName, "PR_CreateThread failed");
+ error = 1;
+ goto done;
+ }
+ }
+#endif
+
+ if (serverCertAuth.testFreshStatusFromSideChannel) {
+ SSL_ForceHandshake(s);
+ error = serverCertAuth.sideChannelRevocationTestResultCode;
+ goto done;
+ }
+
+ /*
+ ** Select on stdin and on the socket. Write data from stdin to
+ ** socket, read data from socket and write to stdout.
+ */
+ FPRINTF(stderr, "%s: ready...\n", progName);
+
+ while (pollset[SSOCK_FD].in_flags | pollset[STDIN_FD].in_flags) {
+ char buf[4000]; /* buffer for stdin */
+ int nb; /* num bytes read from stdin. */
+
+ rv = restartHandshakeAfterServerCertIfNeeded(s, &serverCertAuth,
+ override);
+ if (rv != SECSuccess) {
+ error = EXIT_CODE_HANDSHAKE_FAILED;
+ SECU_PrintError(progName, "authentication of server cert failed");
+ goto done;
+ }
+
+ pollset[SSOCK_FD].out_flags = 0;
+ pollset[STDIN_FD].out_flags = 0;
+
+ FPRINTF(stderr, "%s: about to call PR_Poll !\n", progName);
+ filesReady = PR_Poll(pollset, npds, PR_INTERVAL_NO_TIMEOUT);
+ if (filesReady < 0) {
+ SECU_PrintError(progName, "select failed");
+ error = 1;
+ goto done;
+ }
+ if (filesReady == 0) { /* shouldn't happen! */
+ FPRINTF(stderr, "%s: PR_Poll returned zero!\n", progName);
+ error = 1;
+ goto done;
+ }
+ FPRINTF(stderr, "%s: PR_Poll returned!\n", progName);
+ if (pollset[STDIN_FD].in_flags) {
+ FPRINTF(stderr,
+ "%s: PR_Poll returned 0x%02x for stdin out_flags.\n",
+ progName, pollset[STDIN_FD].out_flags);
+ }
+ if (pollset[SSOCK_FD].in_flags) {
+ FPRINTF(stderr,
+ "%s: PR_Poll returned 0x%02x for socket out_flags.\n",
+ progName, pollset[SSOCK_FD].out_flags);
+ }
+ if (pollset[STDIN_FD].out_flags & PR_POLL_READ) {
+ /* Read from stdin and write to socket */
+ nb = PR_Read(pollset[STDIN_FD].fd, buf, sizeof(buf));
+ FPRINTF(stderr, "%s: stdin read %d bytes\n", progName, nb);
+ if (nb < 0) {
+ if (PR_GetError() != PR_WOULD_BLOCK_ERROR) {
+ SECU_PrintError(progName, "read from stdin failed");
+ error = 1;
+ break;
+ }
+ } else if (nb == 0) {
+ /* EOF on stdin, stop polling stdin for read. */
+ pollset[STDIN_FD].in_flags = 0;
+ } else {
+ char *bufp = buf;
+ FPRINTF(stderr, "%s: Writing %d bytes to server\n",
+ progName, nb);
+ do {
+ PRInt32 cc = PR_Send(s, bufp, nb, 0, maxInterval);
+ if (cc < 0) {
+ PRErrorCode err = PR_GetError();
+ if (err != PR_WOULD_BLOCK_ERROR) {
+ SECU_PrintError(progName,
+ "write to SSL socket failed");
+ error = 254;
+ goto done;
+ }
+ cc = 0;
+ }
+ bufp += cc;
+ nb -= cc;
+ if (nb <= 0)
+ break;
+
+ rv = restartHandshakeAfterServerCertIfNeeded(s,
+ &serverCertAuth, override);
+ if (rv != SECSuccess) {
+ error = EXIT_CODE_HANDSHAKE_FAILED;
+ SECU_PrintError(progName, "authentication of server cert failed");
+ goto done;
+ }
+
+ pollset[SSOCK_FD].in_flags = PR_POLL_WRITE | PR_POLL_EXCEPT;
+ pollset[SSOCK_FD].out_flags = 0;
+ FPRINTF(stderr,
+ "%s: about to call PR_Poll on writable socket !\n",
+ progName);
+ cc = PR_Poll(pollset, 1, PR_INTERVAL_NO_TIMEOUT);
+ if (cc < 0) {
+ SECU_PrintError(progName,
+ "PR_Poll failed");
+ error = 1;
+ goto done;
+ }
+ FPRINTF(stderr,
+ "%s: PR_Poll returned with writable socket !\n",
+ progName);
+ } while (1);
+ pollset[SSOCK_FD].in_flags = PR_POLL_READ;
+ }
+ }
+
+ if (pollset[SSOCK_FD].in_flags) {
+ FPRINTF(stderr,
+ "%s: PR_Poll returned 0x%02x for socket out_flags.\n",
+ progName, pollset[SSOCK_FD].out_flags);
+ }
+ if ((pollset[SSOCK_FD].out_flags & PR_POLL_READ) ||
+ (pollset[SSOCK_FD].out_flags & PR_POLL_ERR)
+#ifdef PR_POLL_HUP
+ || (pollset[SSOCK_FD].out_flags & PR_POLL_HUP)
+#endif
+ ) {
+ /* Read from socket and write to stdout */
+ nb = PR_Recv(pollset[SSOCK_FD].fd, buf, sizeof buf, 0, maxInterval);
+ FPRINTF(stderr, "%s: Read from server %d bytes\n", progName, nb);
+ if (nb < 0) {
+ if (PR_GetError() != PR_WOULD_BLOCK_ERROR) {
+ SECU_PrintError(progName, "read from socket failed");
+ error = 1;
+ goto done;
+ }
+ } else if (nb == 0) {
+ /* EOF from socket... stop polling socket for read */
+ pollset[SSOCK_FD].in_flags = 0;
+ } else {
+ if (skipProtoHeader != PR_TRUE || wrStarted == PR_TRUE) {
+ PR_Write(std_out, buf, nb);
+ } else {
+ separateReqHeader(std_out, buf, nb, &wrStarted,
+ &headerSeparatorPtrnId);
+ }
+ if (verbose)
+ fputs("\n\n", stderr);
+ }
+ }
+ milliPause(50 * multiplier);
+ }
+
+done:
if (hs1SniHostName) {
PORT_Free(hs1SniHostName);
}
@@ -1863,11 +1757,14 @@ done:
PORT_Free(pwdata.data);
}
PORT_Free(host);
- PORT_Free(requestString);
+ if (s) {
+ PR_Close(s);
+ }
if (enabledGroups) {
PORT_Free(enabledGroups);
}
+
if (NSS_IsInitialized()) {
SSL_ClearSessionCache();
if (NSS_Shutdown() != SECSuccess) {