security/nss/cmd/tstclnt/tstclnt.c

Wed, 31 Dec 2014 06:55:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:50 +0100
changeset 2
7e26c7da4463
permissions
-rw-r--r--

Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 /*
michael@0 6 **
michael@0 7 ** Sample client side test program that uses SSL and NSS
michael@0 8 **
michael@0 9 */
michael@0 10
michael@0 11 #include "secutil.h"
michael@0 12 #include "basicutil.h"
michael@0 13
michael@0 14 #if defined(XP_UNIX)
michael@0 15 #include <unistd.h>
michael@0 16 #else
michael@0 17 #include <ctype.h> /* for isalpha() */
michael@0 18 #endif
michael@0 19
michael@0 20 #include <stdio.h>
michael@0 21 #include <string.h>
michael@0 22 #include <stdlib.h>
michael@0 23 #include <errno.h>
michael@0 24 #include <fcntl.h>
michael@0 25 #include <stdarg.h>
michael@0 26
michael@0 27 #include "nspr.h"
michael@0 28 #include "prio.h"
michael@0 29 #include "prnetdb.h"
michael@0 30 #include "nss.h"
michael@0 31 #include "ocsp.h"
michael@0 32 #include "ssl.h"
michael@0 33 #include "sslproto.h"
michael@0 34 #include "pk11func.h"
michael@0 35 #include "plgetopt.h"
michael@0 36 #include "plstr.h"
michael@0 37
michael@0 38 #if defined(WIN32)
michael@0 39 #include <fcntl.h>
michael@0 40 #include <io.h>
michael@0 41 #endif
michael@0 42
michael@0 43 #define PRINTF if (verbose) printf
michael@0 44 #define FPRINTF if (verbose) fprintf
michael@0 45
michael@0 46 #define MAX_WAIT_FOR_SERVER 600
michael@0 47 #define WAIT_INTERVAL 100
michael@0 48
michael@0 49 #define EXIT_CODE_HANDSHAKE_FAILED 254
michael@0 50
michael@0 51 #define EXIT_CODE_SIDECHANNELTEST_GOOD 0
michael@0 52 #define EXIT_CODE_SIDECHANNELTEST_BADCERT 1
michael@0 53 #define EXIT_CODE_SIDECHANNELTEST_NODATA 2
michael@0 54 #define EXIT_CODE_SIDECHANNELTEST_REVOKED 3
michael@0 55
michael@0 56 PRIntervalTime maxInterval = PR_INTERVAL_NO_TIMEOUT;
michael@0 57
michael@0 58 int ssl2CipherSuites[] = {
michael@0 59 SSL_EN_RC4_128_WITH_MD5, /* A */
michael@0 60 SSL_EN_RC4_128_EXPORT40_WITH_MD5, /* B */
michael@0 61 SSL_EN_RC2_128_CBC_WITH_MD5, /* C */
michael@0 62 SSL_EN_RC2_128_CBC_EXPORT40_WITH_MD5, /* D */
michael@0 63 SSL_EN_DES_64_CBC_WITH_MD5, /* E */
michael@0 64 SSL_EN_DES_192_EDE3_CBC_WITH_MD5, /* F */
michael@0 65 0
michael@0 66 };
michael@0 67
michael@0 68 int ssl3CipherSuites[] = {
michael@0 69 -1, /* SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA* a */
michael@0 70 -1, /* SSL_FORTEZZA_DMS_WITH_RC4_128_SHA, * b */
michael@0 71 TLS_RSA_WITH_RC4_128_MD5, /* c */
michael@0 72 TLS_RSA_WITH_3DES_EDE_CBC_SHA, /* d */
michael@0 73 TLS_RSA_WITH_DES_CBC_SHA, /* e */
michael@0 74 TLS_RSA_EXPORT_WITH_RC4_40_MD5, /* f */
michael@0 75 TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5, /* g */
michael@0 76 -1, /* SSL_FORTEZZA_DMS_WITH_NULL_SHA, * h */
michael@0 77 TLS_RSA_WITH_NULL_MD5, /* i */
michael@0 78 SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA, /* j */
michael@0 79 SSL_RSA_FIPS_WITH_DES_CBC_SHA, /* k */
michael@0 80 TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA, /* l */
michael@0 81 TLS_RSA_EXPORT1024_WITH_RC4_56_SHA, /* m */
michael@0 82 TLS_RSA_WITH_RC4_128_SHA, /* n */
michael@0 83 TLS_DHE_DSS_WITH_RC4_128_SHA, /* o */
michael@0 84 TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, /* p */
michael@0 85 TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA, /* q */
michael@0 86 TLS_DHE_RSA_WITH_DES_CBC_SHA, /* r */
michael@0 87 TLS_DHE_DSS_WITH_DES_CBC_SHA, /* s */
michael@0 88 TLS_DHE_DSS_WITH_AES_128_CBC_SHA, /* t */
michael@0 89 TLS_DHE_RSA_WITH_AES_128_CBC_SHA, /* u */
michael@0 90 TLS_RSA_WITH_AES_128_CBC_SHA, /* v */
michael@0 91 TLS_DHE_DSS_WITH_AES_256_CBC_SHA, /* w */
michael@0 92 TLS_DHE_RSA_WITH_AES_256_CBC_SHA, /* x */
michael@0 93 TLS_RSA_WITH_AES_256_CBC_SHA, /* y */
michael@0 94 TLS_RSA_WITH_NULL_SHA, /* z */
michael@0 95 0
michael@0 96 };
michael@0 97
michael@0 98 unsigned long __cmp_umuls;
michael@0 99 PRBool verbose;
michael@0 100 int renegotiationsToDo = 0;
michael@0 101 int renegotiationsDone = 0;
michael@0 102
michael@0 103 static char *progName;
michael@0 104
michael@0 105 secuPWData pwdata = { PW_NONE, 0 };
michael@0 106
michael@0 107 void printSecurityInfo(PRFileDesc *fd)
michael@0 108 {
michael@0 109 CERTCertificate * cert;
michael@0 110 const SECItemArray *csa;
michael@0 111 SSL3Statistics * ssl3stats = SSL_GetStatistics();
michael@0 112 SECStatus result;
michael@0 113 SSLChannelInfo channel;
michael@0 114 SSLCipherSuiteInfo suite;
michael@0 115
michael@0 116 result = SSL_GetChannelInfo(fd, &channel, sizeof channel);
michael@0 117 if (result == SECSuccess &&
michael@0 118 channel.length == sizeof channel &&
michael@0 119 channel.cipherSuite) {
michael@0 120 result = SSL_GetCipherSuiteInfo(channel.cipherSuite,
michael@0 121 &suite, sizeof suite);
michael@0 122 if (result == SECSuccess) {
michael@0 123 FPRINTF(stderr,
michael@0 124 "tstclnt: SSL version %d.%d using %d-bit %s with %d-bit %s MAC\n",
michael@0 125 channel.protocolVersion >> 8, channel.protocolVersion & 0xff,
michael@0 126 suite.effectiveKeyBits, suite.symCipherName,
michael@0 127 suite.macBits, suite.macAlgorithmName);
michael@0 128 FPRINTF(stderr,
michael@0 129 "tstclnt: Server Auth: %d-bit %s, Key Exchange: %d-bit %s\n"
michael@0 130 " Compression: %s\n",
michael@0 131 channel.authKeyBits, suite.authAlgorithmName,
michael@0 132 channel.keaKeyBits, suite.keaTypeName,
michael@0 133 channel.compressionMethodName);
michael@0 134 }
michael@0 135 }
michael@0 136 cert = SSL_RevealCert(fd);
michael@0 137 if (cert) {
michael@0 138 char * ip = CERT_NameToAscii(&cert->issuer);
michael@0 139 char * sp = CERT_NameToAscii(&cert->subject);
michael@0 140 if (sp) {
michael@0 141 fprintf(stderr, "subject DN: %s\n", sp);
michael@0 142 PORT_Free(sp);
michael@0 143 }
michael@0 144 if (ip) {
michael@0 145 fprintf(stderr, "issuer DN: %s\n", ip);
michael@0 146 PORT_Free(ip);
michael@0 147 }
michael@0 148 CERT_DestroyCertificate(cert);
michael@0 149 cert = NULL;
michael@0 150 }
michael@0 151 fprintf(stderr,
michael@0 152 "%ld cache hits; %ld cache misses, %ld cache not reusable\n"
michael@0 153 "%ld stateless resumes\n",
michael@0 154 ssl3stats->hsh_sid_cache_hits, ssl3stats->hsh_sid_cache_misses,
michael@0 155 ssl3stats->hsh_sid_cache_not_ok, ssl3stats->hsh_sid_stateless_resumes);
michael@0 156
michael@0 157 csa = SSL_PeerStapledOCSPResponses(fd);
michael@0 158 if (csa) {
michael@0 159 fprintf(stderr, "Received %d Cert Status items (OCSP stapled data)\n",
michael@0 160 csa->len);
michael@0 161 }
michael@0 162 }
michael@0 163
michael@0 164 void
michael@0 165 handshakeCallback(PRFileDesc *fd, void *client_data)
michael@0 166 {
michael@0 167 const char *secondHandshakeName = (char *)client_data;
michael@0 168 if (secondHandshakeName) {
michael@0 169 SSL_SetURL(fd, secondHandshakeName);
michael@0 170 }
michael@0 171 printSecurityInfo(fd);
michael@0 172 if (renegotiationsDone < renegotiationsToDo) {
michael@0 173 SSL_ReHandshake(fd, (renegotiationsToDo < 2));
michael@0 174 ++renegotiationsDone;
michael@0 175 }
michael@0 176 }
michael@0 177
michael@0 178 static void PrintUsageHeader(const char *progName)
michael@0 179 {
michael@0 180 fprintf(stderr,
michael@0 181 "Usage: %s -h host [-a 1st_hs_name ] [-a 2nd_hs_name ] [-p port]\n"
michael@0 182 "[-d certdir] [-n nickname] [-Bafosvx] [-c ciphers] [-Y]\n"
michael@0 183 "[-V [min-version]:[max-version]] [-T]\n"
michael@0 184 "[-r N] [-w passwd] [-W pwfile] [-q [-t seconds]]\n",
michael@0 185 progName);
michael@0 186 }
michael@0 187
michael@0 188 static void PrintParameterUsage(void)
michael@0 189 {
michael@0 190 fprintf(stderr, "%-20s Send different SNI name. 1st_hs_name - at first\n"
michael@0 191 "%-20s handshake, 2nd_hs_name - at second handshake.\n"
michael@0 192 "%-20s Default is host from the -h argument.\n", "-a name",
michael@0 193 "", "");
michael@0 194 fprintf(stderr, "%-20s Hostname to connect with\n", "-h host");
michael@0 195 fprintf(stderr, "%-20s Port number for SSL server\n", "-p port");
michael@0 196 fprintf(stderr,
michael@0 197 "%-20s Directory with cert database (default is ~/.netscape)\n",
michael@0 198 "-d certdir");
michael@0 199 fprintf(stderr, "%-20s Nickname of key and cert for client auth\n",
michael@0 200 "-n nickname");
michael@0 201 fprintf(stderr,
michael@0 202 "%-20s Bypass PKCS11 layer for SSL encryption and MACing.\n", "-B");
michael@0 203 fprintf(stderr,
michael@0 204 "%-20s Restricts the set of enabled SSL/TLS protocols versions.\n"
michael@0 205 "%-20s All versions are enabled by default.\n"
michael@0 206 "%-20s Possible values for min/max: ssl2 ssl3 tls1.0 tls1.1 tls1.2\n"
michael@0 207 "%-20s Example: \"-V ssl3:\" enables SSL 3 and newer.\n",
michael@0 208 "-V [min]:[max]", "", "", "");
michael@0 209 fprintf(stderr, "%-20s Prints only payload data. Skips HTTP header.\n", "-S");
michael@0 210 fprintf(stderr, "%-20s Client speaks first. \n", "-f");
michael@0 211 fprintf(stderr, "%-20s Use synchronous certificate validation "
michael@0 212 "(required for SSL2)\n", "-O");
michael@0 213 fprintf(stderr, "%-20s Override bad server cert. Make it OK.\n", "-o");
michael@0 214 fprintf(stderr, "%-20s Disable SSL socket locking.\n", "-s");
michael@0 215 fprintf(stderr, "%-20s Verbose progress reporting.\n", "-v");
michael@0 216 fprintf(stderr, "%-20s Use export policy.\n", "-x");
michael@0 217 fprintf(stderr, "%-20s Ping the server and then exit.\n", "-q");
michael@0 218 fprintf(stderr, "%-20s Timeout for server ping (default: no timeout).\n", "-t seconds");
michael@0 219 fprintf(stderr, "%-20s Renegotiate N times (resuming session if N>1).\n", "-r N");
michael@0 220 fprintf(stderr, "%-20s Enable the session ticket extension.\n", "-u");
michael@0 221 fprintf(stderr, "%-20s Enable compression.\n", "-z");
michael@0 222 fprintf(stderr, "%-20s Enable false start.\n", "-g");
michael@0 223 fprintf(stderr, "%-20s Enable the cert_status extension (OCSP stapling).\n", "-T");
michael@0 224 fprintf(stderr, "%-20s Require fresh revocation info from side channel.\n"
michael@0 225 "%-20s -F once means: require for server cert only\n"
michael@0 226 "%-20s -F twice means: require for intermediates, too\n"
michael@0 227 "%-20s (Connect, handshake with server, disable dynamic download\n"
michael@0 228 "%-20s of OCSP/CRL, verify cert using CERT_PKIXVerifyCert.)\n"
michael@0 229 "%-20s Exit code:\n"
michael@0 230 "%-20s 0: have fresh and valid revocation data, status good\n"
michael@0 231 "%-20s 1: cert failed to verify, prior to revocation checking\n"
michael@0 232 "%-20s 2: missing, old or invalid revocation data\n"
michael@0 233 "%-20s 3: have fresh and valid revocation data, status revoked\n",
michael@0 234 "-F", "", "", "", "", "", "", "", "", "");
michael@0 235 fprintf(stderr, "%-20s Test -F allows 0=any (default), 1=only OCSP, 2=only CRL\n", "-M");
michael@0 236 fprintf(stderr, "%-20s Restrict ciphers\n", "-c ciphers");
michael@0 237 fprintf(stderr, "%-20s Print cipher values allowed for parameter -c and exit\n", "-Y");
michael@0 238 fprintf(stderr, "%-20s Enforce using an IPv4 destination address\n", "-4");
michael@0 239 fprintf(stderr, "%-20s Enforce using an IPv6 destination address\n", "-6");
michael@0 240 fprintf(stderr, "%-20s (Options -4 and -6 cannot be combined.)\n", "");
michael@0 241 }
michael@0 242
michael@0 243 static void Usage(const char *progName)
michael@0 244 {
michael@0 245 PrintUsageHeader(progName);
michael@0 246 PrintParameterUsage();
michael@0 247 exit(1);
michael@0 248 }
michael@0 249
michael@0 250 static void PrintCipherUsage(const char *progName)
michael@0 251 {
michael@0 252 PrintUsageHeader(progName);
michael@0 253 fprintf(stderr, "%-20s Letter(s) chosen from the following list\n",
michael@0 254 "-c ciphers");
michael@0 255 fprintf(stderr,
michael@0 256 "A SSL2 RC4 128 WITH MD5\n"
michael@0 257 "B SSL2 RC4 128 EXPORT40 WITH MD5\n"
michael@0 258 "C SSL2 RC2 128 CBC WITH MD5\n"
michael@0 259 "D SSL2 RC2 128 CBC EXPORT40 WITH MD5\n"
michael@0 260 "E SSL2 DES 64 CBC WITH MD5\n"
michael@0 261 "F SSL2 DES 192 EDE3 CBC WITH MD5\n"
michael@0 262 "\n"
michael@0 263 "c SSL3 RSA WITH RC4 128 MD5\n"
michael@0 264 "d SSL3 RSA WITH 3DES EDE CBC SHA\n"
michael@0 265 "e SSL3 RSA WITH DES CBC SHA\n"
michael@0 266 "f SSL3 RSA EXPORT WITH RC4 40 MD5\n"
michael@0 267 "g SSL3 RSA EXPORT WITH RC2 CBC 40 MD5\n"
michael@0 268 "i SSL3 RSA WITH NULL MD5\n"
michael@0 269 "j SSL3 RSA FIPS WITH 3DES EDE CBC SHA\n"
michael@0 270 "k SSL3 RSA FIPS WITH DES CBC SHA\n"
michael@0 271 "l SSL3 RSA EXPORT WITH DES CBC SHA\t(new)\n"
michael@0 272 "m SSL3 RSA EXPORT WITH RC4 56 SHA\t(new)\n"
michael@0 273 "n SSL3 RSA WITH RC4 128 SHA\n"
michael@0 274 "o SSL3 DHE DSS WITH RC4 128 SHA\n"
michael@0 275 "p SSL3 DHE RSA WITH 3DES EDE CBC SHA\n"
michael@0 276 "q SSL3 DHE DSS WITH 3DES EDE CBC SHA\n"
michael@0 277 "r SSL3 DHE RSA WITH DES CBC SHA\n"
michael@0 278 "s SSL3 DHE DSS WITH DES CBC SHA\n"
michael@0 279 "t SSL3 DHE DSS WITH AES 128 CBC SHA\n"
michael@0 280 "u SSL3 DHE RSA WITH AES 128 CBC SHA\n"
michael@0 281 "v SSL3 RSA WITH AES 128 CBC SHA\n"
michael@0 282 "w SSL3 DHE DSS WITH AES 256 CBC SHA\n"
michael@0 283 "x SSL3 DHE RSA WITH AES 256 CBC SHA\n"
michael@0 284 "y SSL3 RSA WITH AES 256 CBC SHA\n"
michael@0 285 "z SSL3 RSA WITH NULL SHA\n"
michael@0 286 "\n"
michael@0 287 ":WXYZ Use cipher with hex code { 0xWX , 0xYZ } in TLS\n"
michael@0 288 );
michael@0 289 exit(1);
michael@0 290 }
michael@0 291
michael@0 292 void
michael@0 293 milliPause(PRUint32 milli)
michael@0 294 {
michael@0 295 PRIntervalTime ticks = PR_MillisecondsToInterval(milli);
michael@0 296 PR_Sleep(ticks);
michael@0 297 }
michael@0 298
michael@0 299 void
michael@0 300 disableAllSSLCiphers(void)
michael@0 301 {
michael@0 302 const PRUint16 *cipherSuites = SSL_GetImplementedCiphers();
michael@0 303 int i = SSL_GetNumImplementedCiphers();
michael@0 304 SECStatus rv;
michael@0 305
michael@0 306 /* disable all the SSL3 cipher suites */
michael@0 307 while (--i >= 0) {
michael@0 308 PRUint16 suite = cipherSuites[i];
michael@0 309 rv = SSL_CipherPrefSetDefault(suite, PR_FALSE);
michael@0 310 if (rv != SECSuccess) {
michael@0 311 PRErrorCode err = PR_GetError();
michael@0 312 fprintf(stderr,
michael@0 313 "SSL_CipherPrefSet didn't like value 0x%04x (i = %d): %s\n",
michael@0 314 suite, i, SECU_Strerror(err));
michael@0 315 exit(2);
michael@0 316 }
michael@0 317 }
michael@0 318 }
michael@0 319
michael@0 320 typedef struct
michael@0 321 {
michael@0 322 PRBool shouldPause; /* PR_TRUE if we should use asynchronous peer cert
michael@0 323 * authentication */
michael@0 324 PRBool isPaused; /* PR_TRUE if libssl is waiting for us to validate the
michael@0 325 * peer's certificate and restart the handshake. */
michael@0 326 void * dbHandle; /* Certificate database handle to use while
michael@0 327 * authenticating the peer's certificate. */
michael@0 328 PRBool testFreshStatusFromSideChannel;
michael@0 329 PRErrorCode sideChannelRevocationTestResultCode;
michael@0 330 PRBool requireDataForIntermediates;
michael@0 331 PRBool allowOCSPSideChannelData;
michael@0 332 PRBool allowCRLSideChannelData;
michael@0 333 } ServerCertAuth;
michael@0 334
michael@0 335
michael@0 336 /*
michael@0 337 * Callback is called when incoming certificate is not valid.
michael@0 338 * Returns SECSuccess to accept the cert anyway, SECFailure to reject.
michael@0 339 */
michael@0 340 static SECStatus
michael@0 341 ownBadCertHandler(void * arg, PRFileDesc * socket)
michael@0 342 {
michael@0 343 PRErrorCode err = PR_GetError();
michael@0 344 /* can log invalid cert here */
michael@0 345 fprintf(stderr, "Bad server certificate: %d, %s\n", err,
michael@0 346 SECU_Strerror(err));
michael@0 347 return SECSuccess; /* override, say it's OK. */
michael@0 348 }
michael@0 349
michael@0 350
michael@0 351
michael@0 352 #define EXIT_CODE_SIDECHANNELTEST_GOOD 0
michael@0 353 #define EXIT_CODE_SIDECHANNELTEST_BADCERT 1
michael@0 354 #define EXIT_CODE_SIDECHANNELTEST_NODATA 2
michael@0 355 #define EXIT_CODE_SIDECHANNELTEST_REVOKED 3
michael@0 356
michael@0 357 static void
michael@0 358 verifyFromSideChannel(CERTCertificate *cert, ServerCertAuth *sca)
michael@0 359 {
michael@0 360 PRUint64 revDoNotUse =
michael@0 361 CERT_REV_M_DO_NOT_TEST_USING_THIS_METHOD;
michael@0 362
michael@0 363 PRUint64 revUseLocalOnlyAndSoftFail =
michael@0 364 CERT_REV_M_TEST_USING_THIS_METHOD
michael@0 365 | CERT_REV_M_FORBID_NETWORK_FETCHING
michael@0 366 | CERT_REV_M_REQUIRE_INFO_ON_MISSING_SOURCE
michael@0 367 | CERT_REV_M_IGNORE_MISSING_FRESH_INFO
michael@0 368 | CERT_REV_M_STOP_TESTING_ON_FRESH_INFO;
michael@0 369
michael@0 370 PRUint64 revUseLocalOnlyAndHardFail =
michael@0 371 CERT_REV_M_TEST_USING_THIS_METHOD
michael@0 372 | CERT_REV_M_FORBID_NETWORK_FETCHING
michael@0 373 | CERT_REV_M_REQUIRE_INFO_ON_MISSING_SOURCE
michael@0 374 | CERT_REV_M_FAIL_ON_MISSING_FRESH_INFO
michael@0 375 | CERT_REV_M_STOP_TESTING_ON_FRESH_INFO;
michael@0 376
michael@0 377 PRUint64 methodFlagsDoNotUse[2];
michael@0 378 PRUint64 methodFlagsCheckSoftFail[2];
michael@0 379 PRUint64 methodFlagsCheckHardFail[2];
michael@0 380 CERTRevocationTests revTestsDoNotCheck;
michael@0 381 CERTRevocationTests revTestsOverallSoftFail;
michael@0 382 CERTRevocationTests revTestsOverallHardFail;
michael@0 383 CERTRevocationFlags rev;
michael@0 384 CERTValInParam cvin[2];
michael@0 385 CERTValOutParam cvout[1];
michael@0 386 SECStatus rv;
michael@0 387
michael@0 388 methodFlagsDoNotUse[cert_revocation_method_crl] = revDoNotUse;
michael@0 389 methodFlagsDoNotUse[cert_revocation_method_ocsp] = revDoNotUse;
michael@0 390
michael@0 391 methodFlagsCheckSoftFail[cert_revocation_method_crl] =
michael@0 392 sca->allowCRLSideChannelData ? revUseLocalOnlyAndSoftFail : revDoNotUse;
michael@0 393 methodFlagsCheckSoftFail[cert_revocation_method_ocsp] =
michael@0 394 sca->allowOCSPSideChannelData ? revUseLocalOnlyAndSoftFail : revDoNotUse;
michael@0 395
michael@0 396 methodFlagsCheckHardFail[cert_revocation_method_crl] =
michael@0 397 sca->allowCRLSideChannelData ? revUseLocalOnlyAndHardFail : revDoNotUse;
michael@0 398 methodFlagsCheckHardFail[cert_revocation_method_ocsp] =
michael@0 399 sca->allowOCSPSideChannelData ? revUseLocalOnlyAndHardFail : revDoNotUse;
michael@0 400
michael@0 401 revTestsDoNotCheck.cert_rev_flags_per_method = methodFlagsDoNotUse;
michael@0 402 revTestsDoNotCheck.number_of_defined_methods = 2;
michael@0 403 revTestsDoNotCheck.number_of_preferred_methods = 0;
michael@0 404 revTestsDoNotCheck.cert_rev_method_independent_flags =
michael@0 405 CERT_REV_MI_TEST_ALL_LOCAL_INFORMATION_FIRST
michael@0 406 | CERT_REV_MI_NO_OVERALL_INFO_REQUIREMENT;
michael@0 407
michael@0 408 revTestsOverallSoftFail.cert_rev_flags_per_method = 0; /* must define later */
michael@0 409 revTestsOverallSoftFail.number_of_defined_methods = 2;
michael@0 410 revTestsOverallSoftFail.number_of_preferred_methods = 0;
michael@0 411 revTestsOverallSoftFail.cert_rev_method_independent_flags =
michael@0 412 CERT_REV_MI_TEST_ALL_LOCAL_INFORMATION_FIRST
michael@0 413 | CERT_REV_MI_NO_OVERALL_INFO_REQUIREMENT;
michael@0 414
michael@0 415 revTestsOverallHardFail.cert_rev_flags_per_method = 0; /* must define later */
michael@0 416 revTestsOverallHardFail.number_of_defined_methods = 2;
michael@0 417 revTestsOverallHardFail.number_of_preferred_methods = 0;
michael@0 418 revTestsOverallHardFail.cert_rev_method_independent_flags =
michael@0 419 CERT_REV_MI_TEST_ALL_LOCAL_INFORMATION_FIRST
michael@0 420 | CERT_REV_MI_REQUIRE_SOME_FRESH_INFO_AVAILABLE;
michael@0 421
michael@0 422 rev.chainTests = revTestsDoNotCheck;
michael@0 423 rev.leafTests = revTestsDoNotCheck;
michael@0 424
michael@0 425 cvin[0].type = cert_pi_revocationFlags;
michael@0 426 cvin[0].value.pointer.revocation = &rev;
michael@0 427 cvin[1].type = cert_pi_end;
michael@0 428
michael@0 429 cvout[0].type = cert_po_end;
michael@0 430
michael@0 431 /* Strategy:
michael@0 432 *
michael@0 433 * Verify with revocation checking disabled.
michael@0 434 * On failure return 1.
michael@0 435 *
michael@0 436 * if result if "good", then continue testing.
michael@0 437 *
michael@0 438 * Verify with CERT_REV_M_FAIL_ON_MISSING_FRESH_INFO.
michael@0 439 * If result is good, return 0.
michael@0 440 *
michael@0 441 * On failure continue testing, find out why it failed.
michael@0 442 *
michael@0 443 * Verify with CERT_REV_M_IGNORE_MISSING_FRESH_INFO
michael@0 444 *
michael@0 445 * If result is "good", then our previous test failed,
michael@0 446 * because we don't have fresh revocation info, return 2.
michael@0 447 *
michael@0 448 * If result is still bad, we do have revocation info,
michael@0 449 * and it says "revoked" or something equivalent, return 3.
michael@0 450 */
michael@0 451
michael@0 452 /* revocation checking disabled */
michael@0 453 rv = CERT_PKIXVerifyCert(cert, certificateUsageSSLServer,
michael@0 454 cvin, cvout, NULL);
michael@0 455 if (rv != SECSuccess) {
michael@0 456 sca->sideChannelRevocationTestResultCode =
michael@0 457 EXIT_CODE_SIDECHANNELTEST_BADCERT;
michael@0 458 return;
michael@0 459 }
michael@0 460
michael@0 461 /* revocation checking, hard fail */
michael@0 462 if (sca->allowOCSPSideChannelData && sca->allowCRLSideChannelData) {
michael@0 463 /* any method is allowed. use soft fail on individual checks,
michael@0 464 * but use hard fail on the overall check
michael@0 465 */
michael@0 466 revTestsOverallHardFail.cert_rev_flags_per_method = methodFlagsCheckSoftFail;
michael@0 467 }
michael@0 468 else {
michael@0 469 /* only one method is allowed. use hard fail on the individual checks.
michael@0 470 * hard/soft fail is irrelevant on overall flags.
michael@0 471 */
michael@0 472 revTestsOverallHardFail.cert_rev_flags_per_method = methodFlagsCheckHardFail;
michael@0 473 }
michael@0 474 rev.leafTests = revTestsOverallHardFail;
michael@0 475 rev.chainTests =
michael@0 476 sca->requireDataForIntermediates ? revTestsOverallHardFail : revTestsDoNotCheck;
michael@0 477 rv = CERT_PKIXVerifyCert(cert, certificateUsageSSLServer,
michael@0 478 cvin, cvout, NULL);
michael@0 479 if (rv == SECSuccess) {
michael@0 480 sca->sideChannelRevocationTestResultCode =
michael@0 481 EXIT_CODE_SIDECHANNELTEST_GOOD;
michael@0 482 return;
michael@0 483 }
michael@0 484
michael@0 485 /* revocation checking, soft fail */
michael@0 486 revTestsOverallSoftFail.cert_rev_flags_per_method = methodFlagsCheckSoftFail;
michael@0 487 rev.leafTests = revTestsOverallSoftFail;
michael@0 488 rev.chainTests =
michael@0 489 sca->requireDataForIntermediates ? revTestsOverallSoftFail : revTestsDoNotCheck;
michael@0 490 rv = CERT_PKIXVerifyCert(cert, certificateUsageSSLServer,
michael@0 491 cvin, cvout, NULL);
michael@0 492 if (rv == SECSuccess) {
michael@0 493 sca->sideChannelRevocationTestResultCode =
michael@0 494 EXIT_CODE_SIDECHANNELTEST_NODATA;
michael@0 495 return;
michael@0 496 }
michael@0 497
michael@0 498 sca->sideChannelRevocationTestResultCode =
michael@0 499 EXIT_CODE_SIDECHANNELTEST_REVOKED;
michael@0 500 }
michael@0 501
michael@0 502 static SECStatus
michael@0 503 ownAuthCertificate(void *arg, PRFileDesc *fd, PRBool checkSig,
michael@0 504 PRBool isServer)
michael@0 505 {
michael@0 506 ServerCertAuth * serverCertAuth = (ServerCertAuth *) arg;
michael@0 507
michael@0 508 if (!serverCertAuth->shouldPause) {
michael@0 509 CERTCertificate *cert;
michael@0 510 int i;
michael@0 511 const SECItemArray *csa;
michael@0 512
michael@0 513 if (!serverCertAuth->testFreshStatusFromSideChannel) {
michael@0 514 return SSL_AuthCertificate(serverCertAuth->dbHandle,
michael@0 515 fd, checkSig, isServer);
michael@0 516 }
michael@0 517
michael@0 518 /* No verification attempt must have happened before now,
michael@0 519 * to ensure revocation data has been actively retrieved yet,
michael@0 520 * or our test will produce incorrect results.
michael@0 521 */
michael@0 522
michael@0 523 cert = SSL_RevealCert(fd);
michael@0 524 if (!cert) {
michael@0 525 exit(254);
michael@0 526 }
michael@0 527
michael@0 528 csa = SSL_PeerStapledOCSPResponses(fd);
michael@0 529 if (csa) {
michael@0 530 for (i = 0; i < csa->len; ++i) {
michael@0 531 PORT_SetError(0);
michael@0 532 if (CERT_CacheOCSPResponseFromSideChannel(
michael@0 533 serverCertAuth->dbHandle, cert, PR_Now(),
michael@0 534 &csa->items[i], arg) != SECSuccess) {
michael@0 535 PRErrorCode error = PR_GetError();
michael@0 536 PORT_Assert(error != 0);
michael@0 537 }
michael@0 538 }
michael@0 539 }
michael@0 540
michael@0 541 verifyFromSideChannel(cert, serverCertAuth);
michael@0 542 CERT_DestroyCertificate(cert);
michael@0 543 /* return success to ensure our caller will continue and we will
michael@0 544 * reach the code that handles
michael@0 545 * serverCertAuth->sideChannelRevocationTestResultCode
michael@0 546 */
michael@0 547 return SECSuccess;
michael@0 548 }
michael@0 549
michael@0 550 FPRINTF(stderr, "%s: using asynchronous certificate validation\n",
michael@0 551 progName);
michael@0 552
michael@0 553 PORT_Assert(!serverCertAuth->isPaused);
michael@0 554 serverCertAuth->isPaused = PR_TRUE;
michael@0 555 return SECWouldBlock;
michael@0 556 }
michael@0 557
michael@0 558 SECStatus
michael@0 559 own_GetClientAuthData(void * arg,
michael@0 560 PRFileDesc * socket,
michael@0 561 struct CERTDistNamesStr * caNames,
michael@0 562 struct CERTCertificateStr ** pRetCert,
michael@0 563 struct SECKEYPrivateKeyStr **pRetKey)
michael@0 564 {
michael@0 565 if (verbose > 1) {
michael@0 566 SECStatus rv;
michael@0 567 fprintf(stderr, "Server requested Client Authentication\n");
michael@0 568 if (caNames && caNames->nnames > 0) {
michael@0 569 PLArenaPool *arena = caNames->arena;
michael@0 570 if (!arena)
michael@0 571 arena = PORT_NewArena(2048);
michael@0 572 if (arena) {
michael@0 573 int i;
michael@0 574 for (i = 0; i < caNames->nnames; ++i) {
michael@0 575 char *nameString;
michael@0 576 CERTName dn;
michael@0 577 rv = SEC_QuickDERDecodeItem(arena,
michael@0 578 &dn,
michael@0 579 SEC_ASN1_GET(CERT_NameTemplate),
michael@0 580 caNames->names + i);
michael@0 581 if (rv != SECSuccess)
michael@0 582 continue;
michael@0 583 nameString = CERT_NameToAscii(&dn);
michael@0 584 if (!nameString)
michael@0 585 continue;
michael@0 586 fprintf(stderr, "CA[%d]: %s\n", i + 1, nameString);
michael@0 587 PORT_Free(nameString);
michael@0 588 }
michael@0 589 if (!caNames->arena) {
michael@0 590 PORT_FreeArena(arena, PR_FALSE);
michael@0 591 }
michael@0 592 }
michael@0 593 }
michael@0 594 rv = NSS_GetClientAuthData(arg, socket, caNames, pRetCert, pRetKey);
michael@0 595 if (rv == SECSuccess && *pRetCert) {
michael@0 596 char *nameString = CERT_NameToAscii(&((*pRetCert)->subject));
michael@0 597 if (nameString) {
michael@0 598 fprintf(stderr, "sent cert: %s\n", nameString);
michael@0 599 PORT_Free(nameString);
michael@0 600 }
michael@0 601 } else {
michael@0 602 fprintf(stderr, "send no cert\n");
michael@0 603 }
michael@0 604 return rv;
michael@0 605 }
michael@0 606 return NSS_GetClientAuthData(arg, socket, caNames, pRetCert, pRetKey);
michael@0 607 }
michael@0 608
michael@0 609 #if defined(WIN32) || defined(OS2)
michael@0 610 void
michael@0 611 thread_main(void * arg)
michael@0 612 {
michael@0 613 PRFileDesc * ps = (PRFileDesc *)arg;
michael@0 614 PRFileDesc * std_in = PR_GetSpecialFD(PR_StandardInput);
michael@0 615 int wc, rc;
michael@0 616 char buf[256];
michael@0 617
michael@0 618 #ifdef WIN32
michael@0 619 {
michael@0 620 /* Put stdin into O_BINARY mode
michael@0 621 ** or else incoming \r\n's will become \n's.
michael@0 622 */
michael@0 623 int smrv = _setmode(_fileno(stdin), _O_BINARY);
michael@0 624 if (smrv == -1) {
michael@0 625 fprintf(stderr,
michael@0 626 "%s: Cannot change stdin to binary mode. Use -i option instead.\n",
michael@0 627 progName);
michael@0 628 /* plow ahead anyway */
michael@0 629 }
michael@0 630 }
michael@0 631 #endif
michael@0 632
michael@0 633 do {
michael@0 634 rc = PR_Read(std_in, buf, sizeof buf);
michael@0 635 if (rc <= 0)
michael@0 636 break;
michael@0 637 wc = PR_Send(ps, buf, rc, 0, maxInterval);
michael@0 638 } while (wc == rc);
michael@0 639 PR_Close(ps);
michael@0 640 }
michael@0 641
michael@0 642 #endif
michael@0 643
michael@0 644 static void
michael@0 645 printHostNameAndAddr(const char * host, const PRNetAddr * addr)
michael@0 646 {
michael@0 647 PRUint16 port = PR_NetAddrInetPort(addr);
michael@0 648 char addrBuf[80];
michael@0 649 PRStatus st = PR_NetAddrToString(addr, addrBuf, sizeof addrBuf);
michael@0 650
michael@0 651 if (st == PR_SUCCESS) {
michael@0 652 port = PR_ntohs(port);
michael@0 653 FPRINTF(stderr, "%s: connecting to %s:%hu (address=%s)\n",
michael@0 654 progName, host, port, addrBuf);
michael@0 655 }
michael@0 656 }
michael@0 657
michael@0 658 /*
michael@0 659 * Prints output according to skipProtoHeader flag. If skipProtoHeader
michael@0 660 * is not set, prints without any changes, otherwise looking
michael@0 661 * for \n\r\n(empty line sequence: HTTP header separator) and
michael@0 662 * prints everything after it.
michael@0 663 */
michael@0 664 static void
michael@0 665 separateReqHeader(const PRFileDesc* outFd, const char* buf, const int nb,
michael@0 666 PRBool *wrStarted, int *ptrnMatched) {
michael@0 667
michael@0 668 /* it is sufficient to look for only "\n\r\n". Hopping that
michael@0 669 * HTTP response format satisfies the standard */
michael@0 670 char *ptrnStr = "\n\r\n";
michael@0 671 char *resPtr;
michael@0 672
michael@0 673 if (nb == 0) {
michael@0 674 return;
michael@0 675 }
michael@0 676
michael@0 677 if (*ptrnMatched > 0) {
michael@0 678 /* Get here only if previous separateReqHeader call found
michael@0 679 * only a fragment of "\n\r\n" in previous buffer. */
michael@0 680 PORT_Assert(*ptrnMatched < 3);
michael@0 681
michael@0 682 /* the size of fragment of "\n\r\n" what we want to find in this
michael@0 683 * buffer is equal to *ptrnMatched */
michael@0 684 if (*ptrnMatched <= nb) {
michael@0 685 /* move the pointer to the beginning of the fragment */
michael@0 686 int strSize = *ptrnMatched;
michael@0 687 char *tmpPtrn = ptrnStr + (3 - strSize);
michael@0 688 if (PL_strncmp(buf, tmpPtrn, strSize) == 0) {
michael@0 689 /* print the rest of the buffer(without the fragment) */
michael@0 690 PR_Write((void*)outFd, buf + strSize, nb - strSize);
michael@0 691 *wrStarted = PR_TRUE;
michael@0 692 return;
michael@0 693 }
michael@0 694 } else {
michael@0 695 /* we are here only when nb == 1 && *ptrnMatched == 2 */
michael@0 696 if (*buf == '\r') {
michael@0 697 *ptrnMatched = 1;
michael@0 698 } else {
michael@0 699 *ptrnMatched = 0;
michael@0 700 }
michael@0 701 return;
michael@0 702 }
michael@0 703 }
michael@0 704 resPtr = PL_strnstr(buf, ptrnStr, nb);
michael@0 705 if (resPtr != NULL) {
michael@0 706 /* if "\n\r\n" was found in the buffer, calculate offset
michael@0 707 * and print the rest of the buffer */
michael@0 708 int newBn = nb - (resPtr - buf + 3); /* 3 is the length of "\n\r\n" */
michael@0 709
michael@0 710 PR_Write((void*)outFd, resPtr + 3, newBn);
michael@0 711 *wrStarted = PR_TRUE;
michael@0 712 return;
michael@0 713 } else {
michael@0 714 /* try to find a fragment of "\n\r\n" at the end of the buffer.
michael@0 715 * if found, set *ptrnMatched to the number of chars left to find
michael@0 716 * in the next buffer.*/
michael@0 717 int i;
michael@0 718 for(i = 1 ;i < 3;i++) {
michael@0 719 char *bufPrt;
michael@0 720 int strSize = 3 - i;
michael@0 721
michael@0 722 if (strSize > nb) {
michael@0 723 continue;
michael@0 724 }
michael@0 725 bufPrt = (char*)(buf + nb - strSize);
michael@0 726
michael@0 727 if (PL_strncmp(bufPrt, ptrnStr, strSize) == 0) {
michael@0 728 *ptrnMatched = i;
michael@0 729 return;
michael@0 730 }
michael@0 731 }
michael@0 732 }
michael@0 733 }
michael@0 734
michael@0 735 #define SSOCK_FD 0
michael@0 736 #define STDIN_FD 1
michael@0 737
michael@0 738 #define HEXCHAR_TO_INT(c, i) \
michael@0 739 if (((c) >= '0') && ((c) <= '9')) { \
michael@0 740 i = (c) - '0'; \
michael@0 741 } else if (((c) >= 'a') && ((c) <= 'f')) { \
michael@0 742 i = (c) - 'a' + 10; \
michael@0 743 } else if (((c) >= 'A') && ((c) <= 'F')) { \
michael@0 744 i = (c) - 'A' + 10; \
michael@0 745 } else { \
michael@0 746 Usage(progName); \
michael@0 747 }
michael@0 748
michael@0 749 static SECStatus
michael@0 750 restartHandshakeAfterServerCertIfNeeded(PRFileDesc * fd,
michael@0 751 ServerCertAuth * serverCertAuth,
michael@0 752 PRBool override)
michael@0 753 {
michael@0 754 SECStatus rv;
michael@0 755 PRErrorCode error;
michael@0 756
michael@0 757 if (!serverCertAuth->isPaused)
michael@0 758 return SECSuccess;
michael@0 759
michael@0 760 FPRINTF(stderr, "%s: handshake was paused by auth certificate hook\n",
michael@0 761 progName);
michael@0 762
michael@0 763 serverCertAuth->isPaused = PR_FALSE;
michael@0 764 rv = SSL_AuthCertificate(serverCertAuth->dbHandle, fd, PR_TRUE, PR_FALSE);
michael@0 765 if (rv != SECSuccess) {
michael@0 766 error = PR_GetError();
michael@0 767 if (error == 0) {
michael@0 768 PR_NOT_REACHED("SSL_AuthCertificate return SECFailure without "
michael@0 769 "setting error code.");
michael@0 770 error = PR_INVALID_STATE_ERROR;
michael@0 771 } else if (override) {
michael@0 772 rv = ownBadCertHandler(NULL, fd);
michael@0 773 }
michael@0 774 }
michael@0 775 if (rv == SECSuccess) {
michael@0 776 error = 0;
michael@0 777 }
michael@0 778
michael@0 779 if (SSL_AuthCertificateComplete(fd, error) != SECSuccess) {
michael@0 780 rv = SECFailure;
michael@0 781 }
michael@0 782
michael@0 783 return rv;
michael@0 784 }
michael@0 785
michael@0 786 int main(int argc, char **argv)
michael@0 787 {
michael@0 788 PRFileDesc * s;
michael@0 789 PRFileDesc * std_out;
michael@0 790 char * host = NULL;
michael@0 791 char * certDir = NULL;
michael@0 792 char * nickname = NULL;
michael@0 793 char * cipherString = NULL;
michael@0 794 char * tmp;
michael@0 795 int multiplier = 0;
michael@0 796 SECStatus rv;
michael@0 797 PRStatus status;
michael@0 798 PRInt32 filesReady;
michael@0 799 int npds;
michael@0 800 int override = 0;
michael@0 801 SSLVersionRange enabledVersions;
michael@0 802 PRBool enableSSL2 = PR_TRUE;
michael@0 803 int bypassPKCS11 = 0;
michael@0 804 int disableLocking = 0;
michael@0 805 int useExportPolicy = 0;
michael@0 806 int enableSessionTickets = 0;
michael@0 807 int enableCompression = 0;
michael@0 808 int enableFalseStart = 0;
michael@0 809 int enableCertStatus = 0;
michael@0 810 PRSocketOptionData opt;
michael@0 811 PRNetAddr addr;
michael@0 812 PRPollDesc pollset[2];
michael@0 813 PRBool allowIPv4 = PR_TRUE;
michael@0 814 PRBool allowIPv6 = PR_TRUE;
michael@0 815 PRBool pingServerFirst = PR_FALSE;
michael@0 816 int pingTimeoutSeconds = -1;
michael@0 817 PRBool clientSpeaksFirst = PR_FALSE;
michael@0 818 PRBool wrStarted = PR_FALSE;
michael@0 819 PRBool skipProtoHeader = PR_FALSE;
michael@0 820 ServerCertAuth serverCertAuth;
michael@0 821 int headerSeparatorPtrnId = 0;
michael@0 822 int error = 0;
michael@0 823 PRUint16 portno = 443;
michael@0 824 char * hs1SniHostName = NULL;
michael@0 825 char * hs2SniHostName = NULL;
michael@0 826 PLOptState *optstate;
michael@0 827 PLOptStatus optstatus;
michael@0 828 PRStatus prStatus;
michael@0 829
michael@0 830 serverCertAuth.shouldPause = PR_TRUE;
michael@0 831 serverCertAuth.isPaused = PR_FALSE;
michael@0 832 serverCertAuth.dbHandle = NULL;
michael@0 833 serverCertAuth.testFreshStatusFromSideChannel = PR_FALSE;
michael@0 834 serverCertAuth.sideChannelRevocationTestResultCode = EXIT_CODE_HANDSHAKE_FAILED;
michael@0 835 serverCertAuth.requireDataForIntermediates = PR_FALSE;
michael@0 836 serverCertAuth.allowOCSPSideChannelData = PR_TRUE;
michael@0 837 serverCertAuth.allowCRLSideChannelData = PR_TRUE;
michael@0 838
michael@0 839 progName = strrchr(argv[0], '/');
michael@0 840 if (!progName)
michael@0 841 progName = strrchr(argv[0], '\\');
michael@0 842 progName = progName ? progName+1 : argv[0];
michael@0 843
michael@0 844 tmp = PR_GetEnv("NSS_DEBUG_TIMEOUT");
michael@0 845 if (tmp && tmp[0]) {
michael@0 846 int sec = PORT_Atoi(tmp);
michael@0 847 if (sec > 0) {
michael@0 848 maxInterval = PR_SecondsToInterval(sec);
michael@0 849 }
michael@0 850 }
michael@0 851
michael@0 852 SSL_VersionRangeGetSupported(ssl_variant_stream, &enabledVersions);
michael@0 853
michael@0 854 optstate = PL_CreateOptState(argc, argv,
michael@0 855 "46BFM:OSTV:W:Ya:c:d:fgh:m:n:op:qr:st:uvw:xz");
michael@0 856 while ((optstatus = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
michael@0 857 switch (optstate->option) {
michael@0 858 case '?':
michael@0 859 default : Usage(progName); break;
michael@0 860
michael@0 861 case '4': allowIPv6 = PR_FALSE; if (!allowIPv4) Usage(progName); break;
michael@0 862 case '6': allowIPv4 = PR_FALSE; if (!allowIPv6) Usage(progName); break;
michael@0 863
michael@0 864 case 'B': bypassPKCS11 = 1; break;
michael@0 865
michael@0 866 case 'F': if (serverCertAuth.testFreshStatusFromSideChannel) {
michael@0 867 /* parameter given twice or more */
michael@0 868 serverCertAuth.requireDataForIntermediates = PR_TRUE;
michael@0 869 }
michael@0 870 serverCertAuth.testFreshStatusFromSideChannel = PR_TRUE;
michael@0 871 break;
michael@0 872
michael@0 873 case 'I': /* reserved for OCSP multi-stapling */ break;
michael@0 874
michael@0 875 case 'O': serverCertAuth.shouldPause = PR_FALSE; break;
michael@0 876
michael@0 877 case 'M': switch (atoi(optstate->value)) {
michael@0 878 case 1:
michael@0 879 serverCertAuth.allowOCSPSideChannelData = PR_TRUE;
michael@0 880 serverCertAuth.allowCRLSideChannelData = PR_FALSE;
michael@0 881 break;
michael@0 882 case 2:
michael@0 883 serverCertAuth.allowOCSPSideChannelData = PR_FALSE;
michael@0 884 serverCertAuth.allowCRLSideChannelData = PR_TRUE;
michael@0 885 break;
michael@0 886 case 0:
michael@0 887 default:
michael@0 888 serverCertAuth.allowOCSPSideChannelData = PR_TRUE;
michael@0 889 serverCertAuth.allowCRLSideChannelData = PR_TRUE;
michael@0 890 break;
michael@0 891 };
michael@0 892 break;
michael@0 893
michael@0 894 case 'S': skipProtoHeader = PR_TRUE; break;
michael@0 895
michael@0 896 case 'T': enableCertStatus = 1; break;
michael@0 897
michael@0 898 case 'V': if (SECU_ParseSSLVersionRangeString(optstate->value,
michael@0 899 enabledVersions, enableSSL2,
michael@0 900 &enabledVersions, &enableSSL2) != SECSuccess) {
michael@0 901 Usage(progName);
michael@0 902 }
michael@0 903 break;
michael@0 904
michael@0 905 case 'Y': PrintCipherUsage(progName); exit(0); break;
michael@0 906
michael@0 907 case 'a': if (!hs1SniHostName) {
michael@0 908 hs1SniHostName = PORT_Strdup(optstate->value);
michael@0 909 } else if (!hs2SniHostName) {
michael@0 910 hs2SniHostName = PORT_Strdup(optstate->value);
michael@0 911 } else {
michael@0 912 Usage(progName);
michael@0 913 }
michael@0 914 break;
michael@0 915
michael@0 916 case 'c': cipherString = PORT_Strdup(optstate->value); break;
michael@0 917
michael@0 918 case 'g': enableFalseStart = 1; break;
michael@0 919
michael@0 920 case 'd': certDir = PORT_Strdup(optstate->value); break;
michael@0 921
michael@0 922 case 'f': clientSpeaksFirst = PR_TRUE; break;
michael@0 923
michael@0 924 case 'h': host = PORT_Strdup(optstate->value); break;
michael@0 925
michael@0 926 case 'm':
michael@0 927 multiplier = atoi(optstate->value);
michael@0 928 if (multiplier < 0)
michael@0 929 multiplier = 0;
michael@0 930 break;
michael@0 931
michael@0 932 case 'n': nickname = PORT_Strdup(optstate->value); break;
michael@0 933
michael@0 934 case 'o': override = 1; break;
michael@0 935
michael@0 936 case 'p': portno = (PRUint16)atoi(optstate->value); break;
michael@0 937
michael@0 938 case 'q': pingServerFirst = PR_TRUE; break;
michael@0 939
michael@0 940 case 's': disableLocking = 1; break;
michael@0 941
michael@0 942 case 't': pingTimeoutSeconds = atoi(optstate->value); break;
michael@0 943
michael@0 944 case 'u': enableSessionTickets = PR_TRUE; break;
michael@0 945
michael@0 946 case 'v': verbose++; break;
michael@0 947
michael@0 948 case 'r': renegotiationsToDo = atoi(optstate->value); break;
michael@0 949
michael@0 950 case 'w':
michael@0 951 pwdata.source = PW_PLAINTEXT;
michael@0 952 pwdata.data = PORT_Strdup(optstate->value);
michael@0 953 break;
michael@0 954
michael@0 955 case 'W':
michael@0 956 pwdata.source = PW_FROMFILE;
michael@0 957 pwdata.data = PORT_Strdup(optstate->value);
michael@0 958 break;
michael@0 959
michael@0 960 case 'x': useExportPolicy = 1; break;
michael@0 961
michael@0 962 case 'z': enableCompression = 1; break;
michael@0 963 }
michael@0 964 }
michael@0 965
michael@0 966 PL_DestroyOptState(optstate);
michael@0 967
michael@0 968 if (optstatus == PL_OPT_BAD)
michael@0 969 Usage(progName);
michael@0 970
michael@0 971 if (!host || !portno)
michael@0 972 Usage(progName);
michael@0 973
michael@0 974 if (serverCertAuth.testFreshStatusFromSideChannel
michael@0 975 && serverCertAuth.shouldPause) {
michael@0 976 fprintf(stderr, "%s: -F requires the use of -O\n", progName);
michael@0 977 exit(1);
michael@0 978 }
michael@0 979
michael@0 980 PR_Init( PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
michael@0 981
michael@0 982 PK11_SetPasswordFunc(SECU_GetModulePassword);
michael@0 983
michael@0 984 status = PR_StringToNetAddr(host, &addr);
michael@0 985 if (status == PR_SUCCESS) {
michael@0 986 addr.inet.port = PR_htons(portno);
michael@0 987 } else {
michael@0 988 /* Lookup host */
michael@0 989 PRAddrInfo *addrInfo;
michael@0 990 void *enumPtr = NULL;
michael@0 991
michael@0 992 addrInfo = PR_GetAddrInfoByName(host, PR_AF_UNSPEC,
michael@0 993 PR_AI_ADDRCONFIG | PR_AI_NOCANONNAME);
michael@0 994 if (!addrInfo) {
michael@0 995 SECU_PrintError(progName, "error looking up host");
michael@0 996 return 1;
michael@0 997 }
michael@0 998 for (;;) {
michael@0 999 enumPtr = PR_EnumerateAddrInfo(enumPtr, addrInfo, portno, &addr);
michael@0 1000 if (enumPtr == NULL)
michael@0 1001 break;
michael@0 1002 if (addr.raw.family == PR_AF_INET && allowIPv4)
michael@0 1003 break;
michael@0 1004 if (addr.raw.family == PR_AF_INET6 && allowIPv6)
michael@0 1005 break;
michael@0 1006 }
michael@0 1007 PR_FreeAddrInfo(addrInfo);
michael@0 1008 if (enumPtr == NULL) {
michael@0 1009 SECU_PrintError(progName, "error looking up host address");
michael@0 1010 return 1;
michael@0 1011 }
michael@0 1012 }
michael@0 1013
michael@0 1014 printHostNameAndAddr(host, &addr);
michael@0 1015
michael@0 1016 if (pingServerFirst) {
michael@0 1017 int iter = 0;
michael@0 1018 PRErrorCode err;
michael@0 1019 int max_attempts = MAX_WAIT_FOR_SERVER;
michael@0 1020 if (pingTimeoutSeconds >= 0) {
michael@0 1021 /* If caller requested a timeout, let's try just twice. */
michael@0 1022 max_attempts = 2;
michael@0 1023 }
michael@0 1024 do {
michael@0 1025 PRIntervalTime timeoutInterval = PR_INTERVAL_NO_TIMEOUT;
michael@0 1026 s = PR_OpenTCPSocket(addr.raw.family);
michael@0 1027 if (s == NULL) {
michael@0 1028 SECU_PrintError(progName, "Failed to create a TCP socket");
michael@0 1029 }
michael@0 1030 opt.option = PR_SockOpt_Nonblocking;
michael@0 1031 opt.value.non_blocking = PR_FALSE;
michael@0 1032 prStatus = PR_SetSocketOption(s, &opt);
michael@0 1033 if (prStatus != PR_SUCCESS) {
michael@0 1034 PR_Close(s);
michael@0 1035 SECU_PrintError(progName,
michael@0 1036 "Failed to set blocking socket option");
michael@0 1037 return 1;
michael@0 1038 }
michael@0 1039 if (pingTimeoutSeconds >= 0) {
michael@0 1040 timeoutInterval = PR_SecondsToInterval(pingTimeoutSeconds);
michael@0 1041 }
michael@0 1042 prStatus = PR_Connect(s, &addr, timeoutInterval);
michael@0 1043 if (prStatus == PR_SUCCESS) {
michael@0 1044 PR_Shutdown(s, PR_SHUTDOWN_BOTH);
michael@0 1045 PR_Close(s);
michael@0 1046 PR_Cleanup();
michael@0 1047 return 0;
michael@0 1048 }
michael@0 1049 err = PR_GetError();
michael@0 1050 if ((err != PR_CONNECT_REFUSED_ERROR) &&
michael@0 1051 (err != PR_CONNECT_RESET_ERROR)) {
michael@0 1052 SECU_PrintError(progName, "TCP Connection failed");
michael@0 1053 return 1;
michael@0 1054 }
michael@0 1055 PR_Close(s);
michael@0 1056 PR_Sleep(PR_MillisecondsToInterval(WAIT_INTERVAL));
michael@0 1057 } while (++iter < max_attempts);
michael@0 1058 SECU_PrintError(progName,
michael@0 1059 "Client timed out while waiting for connection to server");
michael@0 1060 return 1;
michael@0 1061 }
michael@0 1062
michael@0 1063 /* open the cert DB, the key DB, and the secmod DB. */
michael@0 1064 if (!certDir) {
michael@0 1065 certDir = SECU_DefaultSSLDir(); /* Look in $SSL_DIR */
michael@0 1066 certDir = SECU_ConfigDirectory(certDir);
michael@0 1067 } else {
michael@0 1068 char *certDirTmp = certDir;
michael@0 1069 certDir = SECU_ConfigDirectory(certDirTmp);
michael@0 1070 PORT_Free(certDirTmp);
michael@0 1071 }
michael@0 1072 rv = NSS_Init(certDir);
michael@0 1073 if (rv != SECSuccess) {
michael@0 1074 SECU_PrintError(progName, "unable to open cert database");
michael@0 1075 return 1;
michael@0 1076 }
michael@0 1077
michael@0 1078 /* set the policy bits true for all the cipher suites. */
michael@0 1079 if (useExportPolicy)
michael@0 1080 NSS_SetExportPolicy();
michael@0 1081 else
michael@0 1082 NSS_SetDomesticPolicy();
michael@0 1083
michael@0 1084 /* all the SSL2 and SSL3 cipher suites are enabled by default. */
michael@0 1085 if (cipherString) {
michael@0 1086 /* disable all the ciphers, then enable the ones we want. */
michael@0 1087 disableAllSSLCiphers();
michael@0 1088 }
michael@0 1089
michael@0 1090 /* Create socket */
michael@0 1091 s = PR_OpenTCPSocket(addr.raw.family);
michael@0 1092 if (s == NULL) {
michael@0 1093 SECU_PrintError(progName, "error creating socket");
michael@0 1094 return 1;
michael@0 1095 }
michael@0 1096
michael@0 1097 opt.option = PR_SockOpt_Nonblocking;
michael@0 1098 opt.value.non_blocking = PR_TRUE; /* default */
michael@0 1099 if (serverCertAuth.testFreshStatusFromSideChannel) {
michael@0 1100 opt.value.non_blocking = PR_FALSE;
michael@0 1101 }
michael@0 1102 PR_SetSocketOption(s, &opt);
michael@0 1103 /*PR_SetSocketOption(PR_GetSpecialFD(PR_StandardInput), &opt);*/
michael@0 1104
michael@0 1105 s = SSL_ImportFD(NULL, s);
michael@0 1106 if (s == NULL) {
michael@0 1107 SECU_PrintError(progName, "error importing socket");
michael@0 1108 return 1;
michael@0 1109 }
michael@0 1110
michael@0 1111 rv = SSL_OptionSet(s, SSL_SECURITY, 1);
michael@0 1112 if (rv != SECSuccess) {
michael@0 1113 SECU_PrintError(progName, "error enabling socket");
michael@0 1114 return 1;
michael@0 1115 }
michael@0 1116
michael@0 1117 rv = SSL_OptionSet(s, SSL_HANDSHAKE_AS_CLIENT, 1);
michael@0 1118 if (rv != SECSuccess) {
michael@0 1119 SECU_PrintError(progName, "error enabling client handshake");
michael@0 1120 return 1;
michael@0 1121 }
michael@0 1122
michael@0 1123 /* all the SSL2 and SSL3 cipher suites are enabled by default. */
michael@0 1124 if (cipherString) {
michael@0 1125 char *cstringSaved = cipherString;
michael@0 1126 int ndx;
michael@0 1127
michael@0 1128 while (0 != (ndx = *cipherString++)) {
michael@0 1129 int cipher;
michael@0 1130
michael@0 1131 if (ndx == ':') {
michael@0 1132 int ctmp;
michael@0 1133
michael@0 1134 cipher = 0;
michael@0 1135 HEXCHAR_TO_INT(*cipherString, ctmp)
michael@0 1136 cipher |= (ctmp << 12);
michael@0 1137 cipherString++;
michael@0 1138 HEXCHAR_TO_INT(*cipherString, ctmp)
michael@0 1139 cipher |= (ctmp << 8);
michael@0 1140 cipherString++;
michael@0 1141 HEXCHAR_TO_INT(*cipherString, ctmp)
michael@0 1142 cipher |= (ctmp << 4);
michael@0 1143 cipherString++;
michael@0 1144 HEXCHAR_TO_INT(*cipherString, ctmp)
michael@0 1145 cipher |= ctmp;
michael@0 1146 cipherString++;
michael@0 1147 } else {
michael@0 1148 const int *cptr;
michael@0 1149
michael@0 1150 if (! isalpha(ndx))
michael@0 1151 Usage(progName);
michael@0 1152 cptr = islower(ndx) ? ssl3CipherSuites : ssl2CipherSuites;
michael@0 1153 for (ndx &= 0x1f; (cipher = *cptr++) != 0 && --ndx > 0; )
michael@0 1154 /* do nothing */;
michael@0 1155 }
michael@0 1156 if (cipher > 0) {
michael@0 1157 SECStatus status;
michael@0 1158 status = SSL_CipherPrefSet(s, cipher, SSL_ALLOWED);
michael@0 1159 if (status != SECSuccess)
michael@0 1160 SECU_PrintError(progName, "SSL_CipherPrefSet()");
michael@0 1161 } else {
michael@0 1162 Usage(progName);
michael@0 1163 }
michael@0 1164 }
michael@0 1165 PORT_Free(cstringSaved);
michael@0 1166 }
michael@0 1167
michael@0 1168 rv = SSL_VersionRangeSet(s, &enabledVersions);
michael@0 1169 if (rv != SECSuccess) {
michael@0 1170 SECU_PrintError(progName, "error setting SSL/TLS version range ");
michael@0 1171 return 1;
michael@0 1172 }
michael@0 1173
michael@0 1174 rv = SSL_OptionSet(s, SSL_ENABLE_SSL2, enableSSL2);
michael@0 1175 if (rv != SECSuccess) {
michael@0 1176 SECU_PrintError(progName, "error enabling SSLv2 ");
michael@0 1177 return 1;
michael@0 1178 }
michael@0 1179
michael@0 1180 rv = SSL_OptionSet(s, SSL_V2_COMPATIBLE_HELLO, enableSSL2);
michael@0 1181 if (rv != SECSuccess) {
michael@0 1182 SECU_PrintError(progName, "error enabling SSLv2 compatible hellos ");
michael@0 1183 return 1;
michael@0 1184 }
michael@0 1185
michael@0 1186 /* enable PKCS11 bypass */
michael@0 1187 rv = SSL_OptionSet(s, SSL_BYPASS_PKCS11, bypassPKCS11);
michael@0 1188 if (rv != SECSuccess) {
michael@0 1189 SECU_PrintError(progName, "error enabling PKCS11 bypass");
michael@0 1190 return 1;
michael@0 1191 }
michael@0 1192
michael@0 1193 /* disable SSL socket locking */
michael@0 1194 rv = SSL_OptionSet(s, SSL_NO_LOCKS, disableLocking);
michael@0 1195 if (rv != SECSuccess) {
michael@0 1196 SECU_PrintError(progName, "error disabling SSL socket locking");
michael@0 1197 return 1;
michael@0 1198 }
michael@0 1199
michael@0 1200 /* enable Session Ticket extension. */
michael@0 1201 rv = SSL_OptionSet(s, SSL_ENABLE_SESSION_TICKETS, enableSessionTickets);
michael@0 1202 if (rv != SECSuccess) {
michael@0 1203 SECU_PrintError(progName, "error enabling Session Ticket extension");
michael@0 1204 return 1;
michael@0 1205 }
michael@0 1206
michael@0 1207 /* enable compression. */
michael@0 1208 rv = SSL_OptionSet(s, SSL_ENABLE_DEFLATE, enableCompression);
michael@0 1209 if (rv != SECSuccess) {
michael@0 1210 SECU_PrintError(progName, "error enabling compression");
michael@0 1211 return 1;
michael@0 1212 }
michael@0 1213
michael@0 1214 /* enable false start. */
michael@0 1215 rv = SSL_OptionSet(s, SSL_ENABLE_FALSE_START, enableFalseStart);
michael@0 1216 if (rv != SECSuccess) {
michael@0 1217 SECU_PrintError(progName, "error enabling false start");
michael@0 1218 return 1;
michael@0 1219 }
michael@0 1220
michael@0 1221 /* enable cert status (OCSP stapling). */
michael@0 1222 rv = SSL_OptionSet(s, SSL_ENABLE_OCSP_STAPLING, enableCertStatus);
michael@0 1223 if (rv != SECSuccess) {
michael@0 1224 SECU_PrintError(progName, "error enabling cert status (OCSP stapling)");
michael@0 1225 return 1;
michael@0 1226 }
michael@0 1227
michael@0 1228 SSL_SetPKCS11PinArg(s, &pwdata);
michael@0 1229
michael@0 1230 serverCertAuth.dbHandle = CERT_GetDefaultCertDB();
michael@0 1231
michael@0 1232 SSL_AuthCertificateHook(s, ownAuthCertificate, &serverCertAuth);
michael@0 1233 if (override) {
michael@0 1234 SSL_BadCertHook(s, ownBadCertHandler, NULL);
michael@0 1235 }
michael@0 1236 SSL_GetClientAuthDataHook(s, own_GetClientAuthData, (void *)nickname);
michael@0 1237 SSL_HandshakeCallback(s, handshakeCallback, hs2SniHostName);
michael@0 1238 if (hs1SniHostName) {
michael@0 1239 SSL_SetURL(s, hs1SniHostName);
michael@0 1240 } else {
michael@0 1241 SSL_SetURL(s, host);
michael@0 1242 }
michael@0 1243
michael@0 1244 /* Try to connect to the server */
michael@0 1245 status = PR_Connect(s, &addr, PR_INTERVAL_NO_TIMEOUT);
michael@0 1246 if (status != PR_SUCCESS) {
michael@0 1247 if (PR_GetError() == PR_IN_PROGRESS_ERROR) {
michael@0 1248 if (verbose)
michael@0 1249 SECU_PrintError(progName, "connect");
michael@0 1250 milliPause(50 * multiplier);
michael@0 1251 pollset[SSOCK_FD].in_flags = PR_POLL_WRITE | PR_POLL_EXCEPT;
michael@0 1252 pollset[SSOCK_FD].out_flags = 0;
michael@0 1253 pollset[SSOCK_FD].fd = s;
michael@0 1254 while(1) {
michael@0 1255 FPRINTF(stderr,
michael@0 1256 "%s: about to call PR_Poll for connect completion!\n",
michael@0 1257 progName);
michael@0 1258 filesReady = PR_Poll(pollset, 1, PR_INTERVAL_NO_TIMEOUT);
michael@0 1259 if (filesReady < 0) {
michael@0 1260 SECU_PrintError(progName, "unable to connect (poll)");
michael@0 1261 return 1;
michael@0 1262 }
michael@0 1263 FPRINTF(stderr,
michael@0 1264 "%s: PR_Poll returned 0x%02x for socket out_flags.\n",
michael@0 1265 progName, pollset[SSOCK_FD].out_flags);
michael@0 1266 if (filesReady == 0) { /* shouldn't happen! */
michael@0 1267 FPRINTF(stderr, "%s: PR_Poll returned zero!\n", progName);
michael@0 1268 return 1;
michael@0 1269 }
michael@0 1270 status = PR_GetConnectStatus(pollset);
michael@0 1271 if (status == PR_SUCCESS) {
michael@0 1272 break;
michael@0 1273 }
michael@0 1274 if (PR_GetError() != PR_IN_PROGRESS_ERROR) {
michael@0 1275 SECU_PrintError(progName, "unable to connect (poll)");
michael@0 1276 return 1;
michael@0 1277 }
michael@0 1278 SECU_PrintError(progName, "poll");
michael@0 1279 milliPause(50 * multiplier);
michael@0 1280 }
michael@0 1281 } else {
michael@0 1282 SECU_PrintError(progName, "unable to connect");
michael@0 1283 return 1;
michael@0 1284 }
michael@0 1285 }
michael@0 1286
michael@0 1287 pollset[SSOCK_FD].fd = s;
michael@0 1288 pollset[SSOCK_FD].in_flags = PR_POLL_EXCEPT |
michael@0 1289 (clientSpeaksFirst ? 0 : PR_POLL_READ);
michael@0 1290 pollset[STDIN_FD].fd = PR_GetSpecialFD(PR_StandardInput);
michael@0 1291 pollset[STDIN_FD].in_flags = PR_POLL_READ;
michael@0 1292 npds = 2;
michael@0 1293 std_out = PR_GetSpecialFD(PR_StandardOutput);
michael@0 1294
michael@0 1295 #if defined(WIN32) || defined(OS2)
michael@0 1296 /* PR_Poll cannot be used with stdin on Windows or OS/2. (sigh).
michael@0 1297 ** But use of PR_Poll and non-blocking sockets is a major feature
michael@0 1298 ** of this program. So, we simulate a pollable stdin with a
michael@0 1299 ** TCP socket pair and a thread that reads stdin and writes to
michael@0 1300 ** that socket pair.
michael@0 1301 */
michael@0 1302 {
michael@0 1303 PRFileDesc * fds[2];
michael@0 1304 PRThread * thread;
michael@0 1305
michael@0 1306 int nspr_rv = PR_NewTCPSocketPair(fds);
michael@0 1307 if (nspr_rv != PR_SUCCESS) {
michael@0 1308 SECU_PrintError(progName, "PR_NewTCPSocketPair failed");
michael@0 1309 error = 1;
michael@0 1310 goto done;
michael@0 1311 }
michael@0 1312 pollset[STDIN_FD].fd = fds[1];
michael@0 1313
michael@0 1314 thread = PR_CreateThread(PR_USER_THREAD, thread_main, fds[0],
michael@0 1315 PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
michael@0 1316 PR_UNJOINABLE_THREAD, 0);
michael@0 1317 if (!thread) {
michael@0 1318 SECU_PrintError(progName, "PR_CreateThread failed");
michael@0 1319 error = 1;
michael@0 1320 goto done;
michael@0 1321 }
michael@0 1322 }
michael@0 1323 #endif
michael@0 1324
michael@0 1325 if (serverCertAuth.testFreshStatusFromSideChannel) {
michael@0 1326 SSL_ForceHandshake(s);
michael@0 1327 error = serverCertAuth.sideChannelRevocationTestResultCode;
michael@0 1328 goto done;
michael@0 1329 }
michael@0 1330
michael@0 1331 /*
michael@0 1332 ** Select on stdin and on the socket. Write data from stdin to
michael@0 1333 ** socket, read data from socket and write to stdout.
michael@0 1334 */
michael@0 1335 FPRINTF(stderr, "%s: ready...\n", progName);
michael@0 1336
michael@0 1337 while (pollset[SSOCK_FD].in_flags | pollset[STDIN_FD].in_flags) {
michael@0 1338 char buf[4000]; /* buffer for stdin */
michael@0 1339 int nb; /* num bytes read from stdin. */
michael@0 1340
michael@0 1341 rv = restartHandshakeAfterServerCertIfNeeded(s, &serverCertAuth,
michael@0 1342 override);
michael@0 1343 if (rv != SECSuccess) {
michael@0 1344 error = EXIT_CODE_HANDSHAKE_FAILED;
michael@0 1345 SECU_PrintError(progName, "authentication of server cert failed");
michael@0 1346 goto done;
michael@0 1347 }
michael@0 1348
michael@0 1349 pollset[SSOCK_FD].out_flags = 0;
michael@0 1350 pollset[STDIN_FD].out_flags = 0;
michael@0 1351
michael@0 1352 FPRINTF(stderr, "%s: about to call PR_Poll !\n", progName);
michael@0 1353 filesReady = PR_Poll(pollset, npds, PR_INTERVAL_NO_TIMEOUT);
michael@0 1354 if (filesReady < 0) {
michael@0 1355 SECU_PrintError(progName, "select failed");
michael@0 1356 error = 1;
michael@0 1357 goto done;
michael@0 1358 }
michael@0 1359 if (filesReady == 0) { /* shouldn't happen! */
michael@0 1360 FPRINTF(stderr, "%s: PR_Poll returned zero!\n", progName);
michael@0 1361 return 1;
michael@0 1362 }
michael@0 1363 FPRINTF(stderr, "%s: PR_Poll returned!\n", progName);
michael@0 1364 if (pollset[STDIN_FD].in_flags) {
michael@0 1365 FPRINTF(stderr,
michael@0 1366 "%s: PR_Poll returned 0x%02x for stdin out_flags.\n",
michael@0 1367 progName, pollset[STDIN_FD].out_flags);
michael@0 1368 }
michael@0 1369 if (pollset[SSOCK_FD].in_flags) {
michael@0 1370 FPRINTF(stderr,
michael@0 1371 "%s: PR_Poll returned 0x%02x for socket out_flags.\n",
michael@0 1372 progName, pollset[SSOCK_FD].out_flags);
michael@0 1373 }
michael@0 1374 if (pollset[STDIN_FD].out_flags & PR_POLL_READ) {
michael@0 1375 /* Read from stdin and write to socket */
michael@0 1376 nb = PR_Read(pollset[STDIN_FD].fd, buf, sizeof(buf));
michael@0 1377 FPRINTF(stderr, "%s: stdin read %d bytes\n", progName, nb);
michael@0 1378 if (nb < 0) {
michael@0 1379 if (PR_GetError() != PR_WOULD_BLOCK_ERROR) {
michael@0 1380 SECU_PrintError(progName, "read from stdin failed");
michael@0 1381 error = 1;
michael@0 1382 break;
michael@0 1383 }
michael@0 1384 } else if (nb == 0) {
michael@0 1385 /* EOF on stdin, stop polling stdin for read. */
michael@0 1386 pollset[STDIN_FD].in_flags = 0;
michael@0 1387 } else {
michael@0 1388 char * bufp = buf;
michael@0 1389 FPRINTF(stderr, "%s: Writing %d bytes to server\n",
michael@0 1390 progName, nb);
michael@0 1391 do {
michael@0 1392 PRInt32 cc = PR_Send(s, bufp, nb, 0, maxInterval);
michael@0 1393 if (cc < 0) {
michael@0 1394 PRErrorCode err = PR_GetError();
michael@0 1395 if (err != PR_WOULD_BLOCK_ERROR) {
michael@0 1396 SECU_PrintError(progName,
michael@0 1397 "write to SSL socket failed");
michael@0 1398 error = 254;
michael@0 1399 goto done;
michael@0 1400 }
michael@0 1401 cc = 0;
michael@0 1402 }
michael@0 1403 bufp += cc;
michael@0 1404 nb -= cc;
michael@0 1405 if (nb <= 0)
michael@0 1406 break;
michael@0 1407
michael@0 1408 rv = restartHandshakeAfterServerCertIfNeeded(s,
michael@0 1409 &serverCertAuth, override);
michael@0 1410 if (rv != SECSuccess) {
michael@0 1411 error = EXIT_CODE_HANDSHAKE_FAILED;
michael@0 1412 SECU_PrintError(progName, "authentication of server cert failed");
michael@0 1413 goto done;
michael@0 1414 }
michael@0 1415
michael@0 1416 pollset[SSOCK_FD].in_flags = PR_POLL_WRITE | PR_POLL_EXCEPT;
michael@0 1417 pollset[SSOCK_FD].out_flags = 0;
michael@0 1418 FPRINTF(stderr,
michael@0 1419 "%s: about to call PR_Poll on writable socket !\n",
michael@0 1420 progName);
michael@0 1421 cc = PR_Poll(pollset, 1, PR_INTERVAL_NO_TIMEOUT);
michael@0 1422 FPRINTF(stderr,
michael@0 1423 "%s: PR_Poll returned with writable socket !\n",
michael@0 1424 progName);
michael@0 1425 } while (1);
michael@0 1426 pollset[SSOCK_FD].in_flags = PR_POLL_READ;
michael@0 1427 }
michael@0 1428 }
michael@0 1429
michael@0 1430 if (pollset[SSOCK_FD].in_flags) {
michael@0 1431 FPRINTF(stderr,
michael@0 1432 "%s: PR_Poll returned 0x%02x for socket out_flags.\n",
michael@0 1433 progName, pollset[SSOCK_FD].out_flags);
michael@0 1434 }
michael@0 1435 if ( (pollset[SSOCK_FD].out_flags & PR_POLL_READ)
michael@0 1436 || (pollset[SSOCK_FD].out_flags & PR_POLL_ERR)
michael@0 1437 #ifdef PR_POLL_HUP
michael@0 1438 || (pollset[SSOCK_FD].out_flags & PR_POLL_HUP)
michael@0 1439 #endif
michael@0 1440 ) {
michael@0 1441 /* Read from socket and write to stdout */
michael@0 1442 nb = PR_Recv(pollset[SSOCK_FD].fd, buf, sizeof buf, 0, maxInterval);
michael@0 1443 FPRINTF(stderr, "%s: Read from server %d bytes\n", progName, nb);
michael@0 1444 if (nb < 0) {
michael@0 1445 if (PR_GetError() != PR_WOULD_BLOCK_ERROR) {
michael@0 1446 SECU_PrintError(progName, "read from socket failed");
michael@0 1447 error = 1;
michael@0 1448 goto done;
michael@0 1449 }
michael@0 1450 } else if (nb == 0) {
michael@0 1451 /* EOF from socket... stop polling socket for read */
michael@0 1452 pollset[SSOCK_FD].in_flags = 0;
michael@0 1453 } else {
michael@0 1454 if (skipProtoHeader != PR_TRUE || wrStarted == PR_TRUE) {
michael@0 1455 PR_Write(std_out, buf, nb);
michael@0 1456 } else {
michael@0 1457 separateReqHeader(std_out, buf, nb, &wrStarted,
michael@0 1458 &headerSeparatorPtrnId);
michael@0 1459 }
michael@0 1460 if (verbose)
michael@0 1461 fputs("\n\n", stderr);
michael@0 1462 }
michael@0 1463 }
michael@0 1464 milliPause(50 * multiplier);
michael@0 1465 }
michael@0 1466
michael@0 1467 done:
michael@0 1468 if (hs1SniHostName) {
michael@0 1469 PORT_Free(hs1SniHostName);
michael@0 1470 }
michael@0 1471 if (hs2SniHostName) {
michael@0 1472 PORT_Free(hs2SniHostName);
michael@0 1473 }
michael@0 1474 if (nickname) {
michael@0 1475 PORT_Free(nickname);
michael@0 1476 }
michael@0 1477 if (pwdata.data) {
michael@0 1478 PORT_Free(pwdata.data);
michael@0 1479 }
michael@0 1480 PORT_Free(host);
michael@0 1481
michael@0 1482 PR_Close(s);
michael@0 1483 SSL_ClearSessionCache();
michael@0 1484 if (NSS_Shutdown() != SECSuccess) {
michael@0 1485 exit(1);
michael@0 1486 }
michael@0 1487
michael@0 1488 FPRINTF(stderr, "tstclnt: exiting with return code %d\n", error);
michael@0 1489 PR_Cleanup();
michael@0 1490 return error;
michael@0 1491 }

mercurial