Back to index

lightning-sunbird  0.9+nobinonly
tstclnt.c
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is the Netscape security libraries.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 1994-2000
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *   Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
00023  *   Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 /*
00040 **
00041 ** Sample client side test program that uses SSL and libsec
00042 **
00043 */
00044 
00045 #include "secutil.h"
00046 
00047 #if defined(XP_UNIX)
00048 #include <unistd.h>
00049 #else
00050 #include <ctype.h>   /* for isalpha() */
00051 #endif
00052 
00053 #include <stdio.h>
00054 #include <string.h>
00055 #include <stdlib.h>
00056 #include <errno.h>
00057 #include <fcntl.h>
00058 #include <stdarg.h>
00059 
00060 #include "nspr.h"
00061 #include "prio.h"
00062 #include "prnetdb.h"
00063 #include "nss.h"
00064 #include "ssl.h"
00065 #include "sslproto.h"
00066 #include "pk11func.h"
00067 #include "plgetopt.h"
00068 
00069 #if defined(WIN32)
00070 #include <fcntl.h>
00071 #include <io.h>
00072 #endif
00073 
00074 #define PRINTF  if (verbose)  printf
00075 #define FPRINTF if (verbose) fprintf
00076 
00077 #define MAX_WAIT_FOR_SERVER 600
00078 #define WAIT_INTERVAL       100
00079 
00080 PRIntervalTime maxInterval    = PR_INTERVAL_NO_TIMEOUT;
00081 
00082 int ssl2CipherSuites[] = {
00083     SSL_EN_RC4_128_WITH_MD5,                     /* A */
00084     SSL_EN_RC4_128_EXPORT40_WITH_MD5,            /* B */
00085     SSL_EN_RC2_128_CBC_WITH_MD5,          /* C */
00086     SSL_EN_RC2_128_CBC_EXPORT40_WITH_MD5, /* D */
00087     SSL_EN_DES_64_CBC_WITH_MD5,                  /* E */
00088     SSL_EN_DES_192_EDE3_CBC_WITH_MD5,            /* F */
00089     0
00090 };
00091 
00092 int ssl3CipherSuites[] = {
00093     -1, /* SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA* a */
00094     -1, /* SSL_FORTEZZA_DMS_WITH_RC4_128_SHA,     * b */
00095     SSL_RSA_WITH_RC4_128_MD5,                    /* c */
00096     SSL_RSA_WITH_3DES_EDE_CBC_SHA,        /* d */
00097     SSL_RSA_WITH_DES_CBC_SHA,                    /* e */
00098     SSL_RSA_EXPORT_WITH_RC4_40_MD5,              /* f */
00099     SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5,          /* g */
00100     -1, /* SSL_FORTEZZA_DMS_WITH_NULL_SHA,        * h */
00101     SSL_RSA_WITH_NULL_MD5,                /* i */
00102     SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA,          /* j */
00103     SSL_RSA_FIPS_WITH_DES_CBC_SHA,        /* k */
00104     TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA,  /* l */
00105     TLS_RSA_EXPORT1024_WITH_RC4_56_SHA,           /* m */
00106     SSL_RSA_WITH_RC4_128_SHA,                    /* n */
00107     TLS_DHE_DSS_WITH_RC4_128_SHA,         /* o */
00108     SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA,           /* p */
00109     SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA,           /* q */
00110     SSL_DHE_RSA_WITH_DES_CBC_SHA,         /* r */
00111     SSL_DHE_DSS_WITH_DES_CBC_SHA,         /* s */
00112     TLS_DHE_DSS_WITH_AES_128_CBC_SHA,            /* t */
00113     TLS_DHE_RSA_WITH_AES_128_CBC_SHA,            /* u */
00114     TLS_RSA_WITH_AES_128_CBC_SHA,                /* v */
00115     TLS_DHE_DSS_WITH_AES_256_CBC_SHA,            /* w */
00116     TLS_DHE_RSA_WITH_AES_256_CBC_SHA,            /* x */
00117     TLS_RSA_WITH_AES_256_CBC_SHA,                /* y */
00118     SSL_RSA_WITH_NULL_SHA,                /* z */
00119     0
00120 };
00121 
00122 unsigned long __cmp_umuls;
00123 PRBool verbose;
00124 
00125 static char *progName;
00126 
00127 /* This exists only for the automated test suite. It allows us to
00128  * pass in a password on the command line. 
00129  */
00130 
00131 char *password = NULL;
00132 
00133 char * ownPasswd( PK11SlotInfo *slot, PRBool retry, void *arg)
00134 {
00135        char *passwd = NULL;
00136        if ( (!retry) && arg ) {
00137               passwd = PL_strdup((char *)arg);
00138        }
00139        return passwd;
00140 }
00141 
00142 void printSecurityInfo(PRFileDesc *fd)
00143 {
00144     CERTCertificate * cert;
00145     SSL3Statistics * ssl3stats = SSL_GetStatistics();
00146     SECStatus result;
00147     SSLChannelInfo    channel;
00148     SSLCipherSuiteInfo suite;
00149 
00150     result = SSL_GetChannelInfo(fd, &channel, sizeof channel);
00151     if (result == SECSuccess && 
00152         channel.length == sizeof channel && 
00153        channel.cipherSuite) {
00154        result = SSL_GetCipherSuiteInfo(channel.cipherSuite, 
00155                                    &suite, sizeof suite);
00156        if (result == SECSuccess) {
00157            FPRINTF(stderr, 
00158            "tstclnt: SSL version %d.%d using %d-bit %s with %d-bit %s MAC\n",
00159               channel.protocolVersion >> 8, channel.protocolVersion & 0xff,
00160               suite.effectiveKeyBits, suite.symCipherName, 
00161               suite.macBits, suite.macAlgorithmName);
00162            FPRINTF(stderr, 
00163            "tstclnt: Server Auth: %d-bit %s, Key Exchange: %d-bit %s\n",
00164               channel.authKeyBits, suite.authAlgorithmName,
00165               channel.keaKeyBits,  suite.keaTypeName);
00166        }
00167     }
00168     cert = SSL_RevealCert(fd);
00169     if (cert) {
00170        char * ip = CERT_NameToAscii(&cert->issuer);
00171        char * sp = CERT_NameToAscii(&cert->subject);
00172         if (sp) {
00173            fprintf(stderr, "subject DN: %s\n", sp);
00174            PORT_Free(sp);
00175        }
00176         if (ip) {
00177            fprintf(stderr, "issuer  DN: %s\n", ip);
00178            PORT_Free(ip);
00179        }
00180        CERT_DestroyCertificate(cert);
00181        cert = NULL;
00182     }
00183     fprintf(stderr,
00184        "%ld cache hits; %ld cache misses, %ld cache not reusable\n",
00185        ssl3stats->hsh_sid_cache_hits, ssl3stats->hsh_sid_cache_misses,
00186        ssl3stats->hsh_sid_cache_not_ok);
00187 
00188 }
00189 
00190 void
00191 handshakeCallback(PRFileDesc *fd, void *client_data)
00192 {
00193     printSecurityInfo(fd);
00194 }
00195 
00196 static void Usage(const char *progName)
00197 {
00198     fprintf(stderr, 
00199 "Usage:  %s -h host [-p port] [-d certdir] [-n nickname] [-23BTfosvx] \n"
00200 "                   [-c ciphers] [-w passwd] [-q]\n", progName);
00201     fprintf(stderr, "%-20s Hostname to connect with\n", "-h host");
00202     fprintf(stderr, "%-20s Port number for SSL server\n", "-p port");
00203     fprintf(stderr, 
00204             "%-20s Directory with cert database (default is ~/.netscape)\n",
00205            "-d certdir");
00206     fprintf(stderr, "%-20s Nickname of key and cert for client auth\n", 
00207                     "-n nickname");
00208     fprintf(stderr, 
00209             "%-20s Bypass PKCS11 layer for SSL encryption and MACing.\n", "-B");
00210     fprintf(stderr, "%-20s Disable SSL v2.\n", "-2");
00211     fprintf(stderr, "%-20s Disable SSL v3.\n", "-3");
00212     fprintf(stderr, "%-20s Disable TLS (SSL v3.1).\n", "-T");
00213     fprintf(stderr, "%-20s Client speaks first. \n", "-f");
00214     fprintf(stderr, "%-20s Override bad server cert. Make it OK.\n", "-o");
00215     fprintf(stderr, "%-20s Disable SSL socket locking.\n", "-s");
00216     fprintf(stderr, "%-20s Verbose progress reporting.\n", "-v");
00217     fprintf(stderr, "%-20s Use export policy.\n", "-x");
00218     fprintf(stderr, "%-20s Ping the server and then exit.\n", "-q");
00219     fprintf(stderr, "%-20s Letter(s) chosen from the following list\n", 
00220                     "-c ciphers");
00221     fprintf(stderr, 
00222 "A    SSL2 RC4 128 WITH MD5\n"
00223 "B    SSL2 RC4 128 EXPORT40 WITH MD5\n"
00224 "C    SSL2 RC2 128 CBC WITH MD5\n"
00225 "D    SSL2 RC2 128 CBC EXPORT40 WITH MD5\n"
00226 "E    SSL2 DES 64 CBC WITH MD5\n"
00227 "F    SSL2 DES 192 EDE3 CBC WITH MD5\n"
00228 "\n"
00229 "c    SSL3 RSA WITH RC4 128 MD5\n"
00230 "d    SSL3 RSA WITH 3DES EDE CBC SHA\n"
00231 "e    SSL3 RSA WITH DES CBC SHA\n"
00232 "f    SSL3 RSA EXPORT WITH RC4 40 MD5\n"
00233 "g    SSL3 RSA EXPORT WITH RC2 CBC 40 MD5\n"
00234 "i    SSL3 RSA WITH NULL MD5\n"
00235 "j    SSL3 RSA FIPS WITH 3DES EDE CBC SHA\n"
00236 "k    SSL3 RSA FIPS WITH DES CBC SHA\n"
00237 "l    SSL3 RSA EXPORT WITH DES CBC SHA\t(new)\n"
00238 "m    SSL3 RSA EXPORT WITH RC4 56 SHA\t(new)\n"
00239 "n    SSL3 RSA WITH RC4 128 SHA\n"
00240 "o    SSL3 DHE DSS WITH RC4 128 SHA\n"
00241 "p    SSL3 DHE RSA WITH 3DES EDE CBC SHA\n"
00242 "q    SSL3 DHE DSS WITH 3DES EDE CBC SHA\n"
00243 "r    SSL3 DHE RSA WITH DES CBC SHA\n"
00244 "s    SSL3 DHE DSS WITH DES CBC SHA\n"
00245 "t    SSL3 DHE DSS WITH AES 128 CBC SHA\n"
00246 "u    SSL3 DHE RSA WITH AES 128 CBC SHA\n"
00247 "v    SSL3 RSA WITH AES 128 CBC SHA\n"
00248 "w    SSL3 DHE DSS WITH AES 256 CBC SHA\n"
00249 "x    SSL3 DHE RSA WITH AES 256 CBC SHA\n"
00250 "y    SSL3 RSA WITH AES 256 CBC SHA\n"
00251 "z    SSL3 RSA WITH NULL SHA\n"
00252 "\n"
00253 ":WXYZ  Use cipher with hex code { 0xWX , 0xYZ } in TLS\n"
00254        );
00255     exit(1);
00256 }
00257 
00258 void
00259 milliPause(PRUint32 milli)
00260 {
00261     PRIntervalTime ticks = PR_MillisecondsToInterval(milli);
00262     PR_Sleep(ticks);
00263 }
00264 
00265 void
00266 disableAllSSLCiphers(void)
00267 {
00268     const PRUint16 *cipherSuites = SSL_ImplementedCiphers;
00269     int             i            = SSL_NumImplementedCiphers;
00270     SECStatus       rv;
00271 
00272     /* disable all the SSL3 cipher suites */
00273     while (--i >= 0) {
00274        PRUint16 suite = cipherSuites[i];
00275         rv = SSL_CipherPrefSetDefault(suite, PR_FALSE);
00276        if (rv != SECSuccess) {
00277            PRErrorCode err = PR_GetError();
00278            fprintf(stderr,
00279                    "SSL_CipherPrefSet didn't like value 0x%04x (i = %d): %s\n",
00280                  suite, i, SECU_Strerror(err));
00281            exit(2);
00282        }
00283     }
00284 }
00285 
00286 /*
00287  * Callback is called when incoming certificate is not valid.
00288  * Returns SECSuccess to accept the cert anyway, SECFailure to reject.
00289  */
00290 static SECStatus 
00291 ownBadCertHandler(void * arg, PRFileDesc * socket)
00292 {
00293     PRErrorCode err = PR_GetError();
00294     /* can log invalid cert here */
00295     fprintf(stderr, "Bad server certificate: %d, %s\n", err, 
00296             SECU_Strerror(err));
00297     return SECSuccess;      /* override, say it's OK. */
00298 }
00299 
00300 SECStatus
00301 own_GetClientAuthData(void *                       arg,
00302                       PRFileDesc *                 socket,
00303                       struct CERTDistNamesStr *    caNames,
00304                       struct CERTCertificateStr ** pRetCert,
00305                       struct SECKEYPrivateKeyStr **pRetKey)
00306 {
00307     if (verbose > 1) {
00308        SECStatus rv;
00309         fprintf(stderr, "Server requested Client Authentication\n");
00310        if (caNames && caNames->nnames > 0) {
00311            PLArenaPool *arena = caNames->arena;
00312            if (!arena)
00313               arena = PORT_NewArena(2048);
00314            if (arena) {
00315               int i;
00316               for (i = 0; i < caNames->nnames; ++i) {
00317                   char *nameString;
00318                   CERTName dn;
00319                   rv = SEC_QuickDERDecodeItem(arena, 
00320                                        &dn,
00321                                        SEC_ASN1_GET(CERT_NameTemplate), 
00322                                        caNames->names + i);
00323                   if (rv != SECSuccess)
00324                      continue;
00325                   nameString = CERT_NameToAscii(&dn);
00326                   if (!nameString)
00327                      continue;
00328                   fprintf(stderr, "CA[%d]: %s\n", i + 1, nameString);
00329                   PORT_Free(nameString);
00330               }
00331               if (!caNames->arena) {
00332                   PORT_FreeArena(arena, PR_FALSE);
00333               }
00334            }
00335        }
00336        rv = NSS_GetClientAuthData(arg, socket, caNames, pRetCert, pRetKey);
00337        if (rv == SECSuccess && *pRetCert) {
00338            char *nameString = CERT_NameToAscii(&((*pRetCert)->subject));
00339            if (nameString) {
00340               fprintf(stderr, "sent cert: %s\n", nameString);
00341               PORT_Free(nameString);
00342            }
00343        } else {
00344            fprintf(stderr, "send no cert\n");
00345        }
00346        return rv;
00347     }
00348     return NSS_GetClientAuthData(arg, socket, caNames, pRetCert, pRetKey);
00349 }
00350 
00351 #if defined(WIN32) || defined(OS2)
00352 void
00353 thread_main(void * arg)
00354 {
00355     PRFileDesc * ps     = (PRFileDesc *)arg;
00356     PRFileDesc * std_in = PR_GetSpecialFD(PR_StandardInput);
00357     int wc, rc;
00358     char buf[256];
00359 
00360 #ifdef WIN32
00361     {
00362        /* Put stdin into O_BINARY mode 
00363        ** or else incoming \r\n's will become \n's.
00364        */
00365        int smrv = _setmode(_fileno(stdin), _O_BINARY);
00366        if (smrv == -1) {
00367            fprintf(stderr,
00368            "%s: Cannot change stdin to binary mode. Use -i option instead.\n",
00369                    progName);
00370            /* plow ahead anyway */
00371        }
00372     }
00373 #endif
00374 
00375     do {
00376        rc = PR_Read(std_in, buf, sizeof buf);
00377        if (rc <= 0)
00378            break;
00379        wc = PR_Send(ps, buf, rc, 0, maxInterval);
00380     } while (wc == rc);
00381     PR_Close(ps);
00382 }
00383 
00384 #endif
00385 
00386 static void
00387 printHostNameAndAddr(const char * host, const PRNetAddr * addr)
00388 {
00389     PRUint16 port = PR_NetAddrInetPort(addr);
00390     char addrBuf[80];
00391     PRStatus st = PR_NetAddrToString(addr, addrBuf, sizeof addrBuf);
00392 
00393     if (st == PR_SUCCESS) {
00394        port = PR_ntohs(port);
00395        FPRINTF(stderr, "%s: connecting to %s:%hu (address=%s)\n",
00396               progName, host, port, addrBuf);
00397     }
00398 }
00399 
00400 #define SSOCK_FD 0
00401 #define STDIN_FD 1
00402 
00403 #define HEXCHAR_TO_INT(c, i) \
00404     if (((c) >= '0') && ((c) <= '9')) { \
00405        i = (c) - '0'; \
00406     } else if (((c) >= 'a') && ((c) <= 'f')) { \
00407        i = (c) - 'a' + 10; \
00408     } else if (((c) >= 'A') && ((c) <= 'F')) { \
00409        i = (c) - 'A' + 10; \
00410     } else { \
00411        Usage(progName); \
00412     }
00413 
00414 int main(int argc, char **argv)
00415 {
00416     PRFileDesc *       s;
00417     PRFileDesc *       std_out;
00418     CERTCertDBHandle * handle;
00419     char *             host =  NULL;
00420     char *             port =  "443";
00421     char *             certDir  =  NULL;
00422     char *             nickname =  NULL;
00423     char *             cipherString = NULL;
00424     char *             tmp;
00425     int                multiplier = 0;
00426     SECStatus          rv;
00427     PRStatus           status;
00428     PRInt32            filesReady;
00429     int                npds;
00430     int                override = 0;
00431     int                disableSSL2 = 0;
00432     int                disableSSL3 = 0;
00433     int                disableTLS  = 0;
00434     int                bypassPKCS11 = 0;
00435     int                disableLocking = 0;
00436     int                useExportPolicy = 0;
00437     PRSocketOptionData opt;
00438     PRNetAddr          addr;
00439     PRHostEnt          hp;
00440     PRPollDesc         pollset[2];
00441     PRBool             useCommandLinePassword = PR_FALSE;
00442     PRBool             pingServerFirst = PR_FALSE;
00443     PRBool             clientSpeaksFirst = PR_FALSE;
00444     int                error = 0;
00445     PLOptState *optstate;
00446     PLOptStatus optstatus;
00447     PRStatus prStatus;
00448 
00449     progName = strrchr(argv[0], '/');
00450     if (!progName)
00451        progName = strrchr(argv[0], '\\');
00452     progName = progName ? progName+1 : argv[0];
00453 
00454     tmp = PR_GetEnv("NSS_DEBUG_TIMEOUT");
00455     if (tmp && tmp[0]) {
00456        int sec = PORT_Atoi(tmp);
00457        if (sec > 0) {
00458            maxInterval = PR_SecondsToInterval(sec);
00459        }
00460     }
00461 
00462     optstate = PL_CreateOptState(argc, argv, "23BTfc:h:p:d:m:n:oqsvw:x");
00463     while ((optstatus = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
00464        switch (optstate->option) {
00465          case '?':
00466          default : Usage(progName);                     break;
00467 
00468           case '2': disableSSL2 = 1;                    break;
00469 
00470           case '3': disableSSL3 = 1;                    break;
00471 
00472           case 'B': bypassPKCS11 = 1;                   break;
00473 
00474           case 'T': disableTLS  = 1;                    break;
00475 
00476           case 'c': cipherString = strdup(optstate->value); break;
00477 
00478           case 'h': host = strdup(optstate->value);     break;
00479 
00480           case 'f':  clientSpeaksFirst = PR_TRUE;       break;
00481 
00482          case 'd':
00483            certDir = strdup(optstate->value);
00484            certDir = SECU_ConfigDirectory(certDir);
00485            break;
00486 
00487          case 'm':
00488            multiplier = atoi(optstate->value);
00489            if (multiplier < 0)
00490               multiplier = 0;
00491            break;
00492 
00493          case 'n': nickname = strdup(optstate->value);  break;
00494 
00495          case 'o': override = 1;                 break;
00496 
00497          case 'p': port = strdup(optstate->value);      break;
00498 
00499          case 'q': pingServerFirst = PR_TRUE;          break;
00500 
00501          case 's': disableLocking = 1;                 break;
00502 
00503          case 'v': verbose++;                           break;
00504 
00505          case 'w':
00506               password = PORT_Strdup(optstate->value);
00507               useCommandLinePassword = PR_TRUE;
00508               break;
00509 
00510          case 'x': useExportPolicy = 1;          break;
00511        }
00512     }
00513     if (optstatus == PL_OPT_BAD)
00514        Usage(progName);
00515 
00516     if (!host || !port) Usage(progName);
00517 
00518     if (!certDir) {
00519        certDir = SECU_DefaultSSLDir();    /* Look in $SSL_DIR */
00520        certDir = SECU_ConfigDirectory(certDir); /* call even if it's NULL */
00521     }
00522 
00523     PR_Init( PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
00524 
00525     /* set our password function */
00526     if ( useCommandLinePassword ) {
00527        PK11_SetPasswordFunc(ownPasswd);
00528     } else {
00529        PK11_SetPasswordFunc(SECU_GetModulePassword);
00530     }
00531 
00532     /* open the cert DB, the key DB, and the secmod DB. */
00533     rv = NSS_Init(certDir);
00534     if (rv != SECSuccess) {
00535        SECU_PrintError(progName, "unable to open cert database");
00536 #if 0
00537     rv = CERT_OpenVolatileCertDB(handle);
00538        CERT_SetDefaultCertDB(handle);
00539 #else
00540        return 1;
00541 #endif
00542     }
00543     handle = CERT_GetDefaultCertDB();
00544 
00545     /* set the policy bits true for all the cipher suites. */
00546     if (useExportPolicy)
00547        NSS_SetExportPolicy();
00548     else
00549        NSS_SetDomesticPolicy();
00550 
00551     /* all the SSL2 and SSL3 cipher suites are enabled by default. */
00552     if (cipherString) {
00553        /* disable all the ciphers, then enable the ones we want. */
00554        disableAllSSLCiphers();
00555     }
00556 
00557     status = PR_StringToNetAddr(host, &addr);
00558     if (status == PR_SUCCESS) {
00559        int portno = atoi(port);
00560        addr.inet.port = PR_htons((PRUint16)portno);
00561     } else {
00562        /* Lookup host */
00563        char buf[PR_NETDB_BUF_SIZE];
00564        status = PR_GetIPNodeByName(host, PR_AF_INET6, PR_AI_DEFAULT, 
00565                                 buf, sizeof buf, &hp);
00566        if (status != PR_SUCCESS) {
00567            SECU_PrintError(progName, "error looking up host");
00568            return 1;
00569        }
00570        if (PR_EnumerateHostEnt(0, &hp, (PRUint16)atoi(port), &addr) == -1) {
00571            SECU_PrintError(progName, "error looking up host address");
00572            return 1;
00573        }
00574     }
00575 
00576     if (PR_IsNetAddrType(&addr, PR_IpAddrV4Mapped)) {
00577        /* convert to IPv4.  */
00578        addr.inet.family = PR_AF_INET;
00579        memcpy(&addr.inet.ip, &addr.ipv6.ip.pr_s6_addr[12], 4);
00580        memset(&addr.inet.pad[0], 0, sizeof addr.inet.pad);
00581     }
00582 
00583     printHostNameAndAddr(host, &addr);
00584 
00585     if (pingServerFirst) {
00586        int iter = 0;
00587        PRErrorCode err;
00588        do {
00589            s = PR_NewTCPSocket();
00590            if (s == NULL) {
00591               SECU_PrintError(progName, "Failed to create a TCP socket");
00592            }
00593            opt.option             = PR_SockOpt_Nonblocking;
00594            opt.value.non_blocking = PR_FALSE;
00595            prStatus = PR_SetSocketOption(s, &opt);
00596            if (prStatus != PR_SUCCESS) {
00597               PR_Close(s);
00598               SECU_PrintError(progName, 
00599                               "Failed to set blocking socket option");
00600               return 1;
00601            }
00602            prStatus = PR_Connect(s, &addr, PR_INTERVAL_NO_TIMEOUT);
00603            if (prStatus == PR_SUCCESS) {
00604               PR_Shutdown(s, PR_SHUTDOWN_BOTH);
00605               PR_Close(s);
00606                if (NSS_Shutdown() != SECSuccess) {
00607                    exit(1);
00608                }
00609               PR_Cleanup();
00610               return 0;
00611            }
00612            err = PR_GetError();
00613            if ((err != PR_CONNECT_REFUSED_ERROR) && 
00614                (err != PR_CONNECT_RESET_ERROR)) {
00615               SECU_PrintError(progName, "TCP Connection failed");
00616               return 1;
00617            }
00618            PR_Close(s);
00619            PR_Sleep(PR_MillisecondsToInterval(WAIT_INTERVAL));
00620        } while (++iter < MAX_WAIT_FOR_SERVER);
00621        SECU_PrintError(progName, 
00622                      "Client timed out while waiting for connection to server");
00623        return 1;
00624     }
00625 
00626     /* Create socket */
00627     s = PR_NewTCPSocket();
00628     if (s == NULL) {
00629        SECU_PrintError(progName, "error creating socket");
00630        return 1;
00631     }
00632 
00633     opt.option = PR_SockOpt_Nonblocking;
00634     opt.value.non_blocking = PR_TRUE;
00635     PR_SetSocketOption(s, &opt);
00636     /*PR_SetSocketOption(PR_GetSpecialFD(PR_StandardInput), &opt);*/
00637 
00638     s = SSL_ImportFD(NULL, s);
00639     if (s == NULL) {
00640        SECU_PrintError(progName, "error importing socket");
00641        return 1;
00642     }
00643 
00644     rv = SSL_OptionSet(s, SSL_SECURITY, 1);
00645     if (rv != SECSuccess) {
00646         SECU_PrintError(progName, "error enabling socket");
00647        return 1;
00648     }
00649 
00650     rv = SSL_OptionSet(s, SSL_HANDSHAKE_AS_CLIENT, 1);
00651     if (rv != SECSuccess) {
00652        SECU_PrintError(progName, "error enabling client handshake");
00653        return 1;
00654     }
00655 
00656     /* all the SSL2 and SSL3 cipher suites are enabled by default. */
00657     if (cipherString) {
00658        int ndx;
00659 
00660        while (0 != (ndx = *cipherString++)) {
00661            int  cipher;
00662 
00663            if (ndx == ':') {
00664               int ctmp;
00665 
00666               cipher = 0;
00667               HEXCHAR_TO_INT(*cipherString, ctmp)
00668               cipher |= (ctmp << 12);
00669               cipherString++;
00670               HEXCHAR_TO_INT(*cipherString, ctmp)
00671               cipher |= (ctmp << 8);
00672               cipherString++;
00673               HEXCHAR_TO_INT(*cipherString, ctmp)
00674               cipher |= (ctmp << 4);
00675               cipherString++;
00676               HEXCHAR_TO_INT(*cipherString, ctmp)
00677               cipher |= ctmp;
00678               cipherString++;
00679            } else {
00680               const int *cptr;
00681 
00682               if (! isalpha(ndx))
00683                   Usage(progName);
00684               cptr = islower(ndx) ? ssl3CipherSuites : ssl2CipherSuites;
00685               for (ndx &= 0x1f; (cipher = *cptr++) != 0 && --ndx > 0; ) 
00686                   /* do nothing */;
00687            }
00688            if (cipher > 0) {
00689               SECStatus status;
00690               status = SSL_CipherPrefSet(s, cipher, SSL_ALLOWED);
00691               if (status != SECSuccess) 
00692                   SECU_PrintError(progName, "SSL_CipherPrefSet()");
00693            } else {
00694               Usage(progName);
00695            }
00696        }
00697     }
00698 
00699     rv = SSL_OptionSet(s, SSL_ENABLE_SSL2, !disableSSL2);
00700     if (rv != SECSuccess) {
00701        SECU_PrintError(progName, "error enabling SSLv2 ");
00702        return 1;
00703     }
00704 
00705     rv = SSL_OptionSet(s, SSL_ENABLE_SSL3, !disableSSL3);
00706     if (rv != SECSuccess) {
00707        SECU_PrintError(progName, "error enabling SSLv3 ");
00708        return 1;
00709     }
00710 
00711     rv = SSL_OptionSet(s, SSL_ENABLE_TLS, !disableTLS);
00712     if (rv != SECSuccess) {
00713        SECU_PrintError(progName, "error enabling TLS ");
00714        return 1;
00715     }
00716 
00717     /* disable ssl2 and ssl2-compatible client hellos. */
00718     rv = SSL_OptionSet(s, SSL_V2_COMPATIBLE_HELLO, !disableSSL2);
00719     if (rv != SECSuccess) {
00720        SECU_PrintError(progName, "error disabling v2 compatibility");
00721        return 1;
00722     }
00723 
00724     /* enable PKCS11 bypass */
00725     rv = SSL_OptionSet(s, SSL_BYPASS_PKCS11, bypassPKCS11);
00726     if (rv != SECSuccess) {
00727        SECU_PrintError(progName, "error enabling PKCS11 bypass");
00728        return 1;
00729     }
00730 
00731     /* disable SSL socket locking */
00732     rv = SSL_OptionSet(s, SSL_NO_LOCKS, disableLocking);
00733     if (rv != SECSuccess) {
00734        SECU_PrintError(progName, "error disabling SSL socket locking");
00735        return 1;
00736     }
00737 
00738 
00739     if (useCommandLinePassword) {
00740        SSL_SetPKCS11PinArg(s, password);
00741     }
00742 
00743     SSL_AuthCertificateHook(s, SSL_AuthCertificate, (void *)handle);
00744     if (override) {
00745        SSL_BadCertHook(s, ownBadCertHandler, NULL);
00746     }
00747     SSL_GetClientAuthDataHook(s, own_GetClientAuthData, (void *)nickname);
00748     SSL_HandshakeCallback(s, handshakeCallback, NULL);
00749     SSL_SetURL(s, host);
00750 
00751     /* Try to connect to the server */
00752     status = PR_Connect(s, &addr, PR_INTERVAL_NO_TIMEOUT);
00753     if (status != PR_SUCCESS) {
00754        if (PR_GetError() == PR_IN_PROGRESS_ERROR) {
00755            if (verbose)
00756               SECU_PrintError(progName, "connect");
00757            milliPause(50 * multiplier);
00758            pollset[SSOCK_FD].in_flags = PR_POLL_WRITE | PR_POLL_EXCEPT;
00759            pollset[SSOCK_FD].out_flags = 0;
00760            pollset[SSOCK_FD].fd = s;
00761            while(1) {
00762               FPRINTF(stderr, 
00763                       "%s: about to call PR_Poll for connect completion!\n", 
00764                      progName);
00765               filesReady = PR_Poll(pollset, 1, PR_INTERVAL_NO_TIMEOUT);
00766               if (filesReady < 0) {
00767                   SECU_PrintError(progName, "unable to connect (poll)");
00768                   return 1;
00769               }
00770               FPRINTF(stderr,
00771                       "%s: PR_Poll returned 0x%02x for socket out_flags.\n",
00772                      progName, pollset[SSOCK_FD].out_flags);
00773               if (filesReady == 0) {      /* shouldn't happen! */
00774                   FPRINTF(stderr, "%s: PR_Poll returned zero!\n", progName);
00775                   return 1;
00776               }
00777               /* Must milliPause between PR_Poll and PR_GetConnectStatus,
00778                * Or else winsock gets mighty confused.
00779                * Sleep(0);
00780                */
00781               milliPause(1);
00782               status = PR_GetConnectStatus(pollset);
00783               if (status == PR_SUCCESS) {
00784                   break;
00785               }
00786               if (PR_GetError() != PR_IN_PROGRESS_ERROR) {
00787                   SECU_PrintError(progName, "unable to connect (poll)");
00788                   return 1;
00789               }
00790               SECU_PrintError(progName, "poll");
00791               milliPause(50 * multiplier);
00792            }
00793        } else {
00794            SECU_PrintError(progName, "unable to connect");
00795            return 1;
00796        }
00797     }
00798 
00799     pollset[SSOCK_FD].fd        = s;
00800     pollset[SSOCK_FD].in_flags  = PR_POLL_EXCEPT |
00801                                   (clientSpeaksFirst ? 0 : PR_POLL_READ);
00802     pollset[STDIN_FD].fd        = PR_GetSpecialFD(PR_StandardInput);
00803     pollset[STDIN_FD].in_flags  = PR_POLL_READ;
00804     npds                 = 2;
00805     std_out              = PR_GetSpecialFD(PR_StandardOutput);
00806 
00807 #if defined(WIN32) || defined(OS2)
00808     /* PR_Poll cannot be used with stdin on Windows or OS/2.  (sigh). 
00809     ** But use of PR_Poll and non-blocking sockets is a major feature
00810     ** of this program.  So, we simulate a pollable stdin with a 
00811     ** TCP socket pair and a  thread that reads stdin and writes to 
00812     ** that socket pair.
00813     */
00814   {
00815     PRFileDesc * fds[2];
00816     PRThread *   thread;
00817 
00818     int nspr_rv = PR_NewTCPSocketPair(fds);
00819     if (nspr_rv != PR_SUCCESS) {
00820         SECU_PrintError(progName, "PR_NewTCPSocketPair failed");
00821        error = 1;
00822        goto done;
00823     }
00824     pollset[STDIN_FD].fd = fds[1];
00825 
00826     thread = PR_CreateThread(PR_USER_THREAD, thread_main, fds[0], 
00827                              PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, 
00828                              PR_UNJOINABLE_THREAD, 0);
00829     if (!thread) {
00830         SECU_PrintError(progName, "PR_CreateThread failed");
00831        error = 1;
00832        goto done;
00833     }
00834   }
00835 #endif
00836 
00837     /*
00838     ** Select on stdin and on the socket. Write data from stdin to
00839     ** socket, read data from socket and write to stdout.
00840     */
00841     FPRINTF(stderr, "%s: ready...\n", progName);
00842 
00843     while (pollset[SSOCK_FD].in_flags | pollset[STDIN_FD].in_flags) {
00844        char buf[4000];      /* buffer for stdin */
00845        int nb;              /* num bytes read from stdin. */
00846 
00847        pollset[SSOCK_FD].out_flags = 0;
00848        pollset[STDIN_FD].out_flags = 0;
00849 
00850        FPRINTF(stderr, "%s: about to call PR_Poll !\n", progName);
00851        filesReady = PR_Poll(pollset, npds, PR_INTERVAL_NO_TIMEOUT);
00852        if (filesReady < 0) {
00853            SECU_PrintError(progName, "select failed");
00854            error = 1;
00855            goto done;
00856        }
00857        if (filesReady == 0) {      /* shouldn't happen! */
00858            FPRINTF(stderr, "%s: PR_Poll returned zero!\n", progName);
00859            return 1;
00860        }
00861        FPRINTF(stderr, "%s: PR_Poll returned!\n", progName);
00862        if (pollset[STDIN_FD].in_flags) {
00863            FPRINTF(stderr,
00864                   "%s: PR_Poll returned 0x%02x for stdin out_flags.\n",
00865                   progName, pollset[STDIN_FD].out_flags);
00866        }
00867        if (pollset[SSOCK_FD].in_flags) {
00868            FPRINTF(stderr, 
00869                    "%s: PR_Poll returned 0x%02x for socket out_flags.\n",
00870                   progName, pollset[SSOCK_FD].out_flags);
00871        }
00872        if (pollset[STDIN_FD].out_flags & PR_POLL_READ) {
00873            /* Read from stdin and write to socket */
00874            nb = PR_Read(pollset[STDIN_FD].fd, buf, sizeof(buf));
00875            FPRINTF(stderr, "%s: stdin read %d bytes\n", progName, nb);
00876            if (nb < 0) {
00877               if (PR_GetError() != PR_WOULD_BLOCK_ERROR) {
00878                   SECU_PrintError(progName, "read from stdin failed");
00879                    error = 1;
00880                   break;
00881               }
00882            } else if (nb == 0) {
00883               /* EOF on stdin, stop polling stdin for read. */
00884               pollset[STDIN_FD].in_flags = 0;
00885            } else {
00886               char * bufp = buf;
00887               FPRINTF(stderr, "%s: Writing %d bytes to server\n", 
00888                       progName, nb);
00889               do {
00890                   PRInt32 cc = PR_Send(s, bufp, nb, 0, maxInterval);
00891                   if (cc < 0) {
00892                      PRErrorCode err = PR_GetError();
00893                      if (err != PR_WOULD_BLOCK_ERROR) {
00894                          SECU_PrintError(progName, 
00895                                          "write to SSL socket failed");
00896                          error = 254;
00897                          goto done;
00898                      }
00899                      cc = 0;
00900                   }
00901                   bufp += cc;
00902                   nb   -= cc;
00903                   if (nb <= 0) 
00904                      break;
00905                   pollset[SSOCK_FD].in_flags = PR_POLL_WRITE | PR_POLL_EXCEPT;
00906                   pollset[SSOCK_FD].out_flags = 0;
00907                   FPRINTF(stderr,
00908                           "%s: about to call PR_Poll on writable socket !\n", 
00909                          progName);
00910                   cc = PR_Poll(pollset, 1, PR_INTERVAL_NO_TIMEOUT);
00911                   FPRINTF(stderr,
00912                           "%s: PR_Poll returned with writable socket !\n", 
00913                          progName);
00914               } while (1);
00915               pollset[SSOCK_FD].in_flags  = PR_POLL_READ;
00916            }
00917        }
00918 
00919        if (pollset[SSOCK_FD].in_flags) {
00920            FPRINTF(stderr, 
00921                    "%s: PR_Poll returned 0x%02x for socket out_flags.\n",
00922                   progName, pollset[SSOCK_FD].out_flags);
00923        }
00924        if (   (pollset[SSOCK_FD].out_flags & PR_POLL_READ) 
00925            || (pollset[SSOCK_FD].out_flags & PR_POLL_ERR)  
00926 #ifdef PR_POLL_HUP
00927            || (pollset[SSOCK_FD].out_flags & PR_POLL_HUP)
00928 #endif
00929            ) {
00930            /* Read from socket and write to stdout */
00931            nb = PR_Recv(pollset[SSOCK_FD].fd, buf, sizeof buf, 0, maxInterval);
00932            FPRINTF(stderr, "%s: Read from server %d bytes\n", progName, nb);
00933            if (nb < 0) {
00934               if (PR_GetError() != PR_WOULD_BLOCK_ERROR) {
00935                   SECU_PrintError(progName, "read from socket failed");
00936                   error = 1;
00937                   goto done;
00938               }
00939            } else if (nb == 0) {
00940               /* EOF from socket... stop polling socket for read */
00941               pollset[SSOCK_FD].in_flags = 0;
00942            } else {
00943               PR_Write(std_out, buf, nb);
00944               if (verbose)
00945                   fputs("\n\n", stderr);
00946            }
00947        }
00948        milliPause(50 * multiplier);
00949     }
00950 
00951   done:
00952     PR_Close(s);
00953     SSL_ClearSessionCache();
00954     if (NSS_Shutdown() != SECSuccess) {
00955         exit(1);
00956     }
00957 
00958     PR_Cleanup();
00959     return error;
00960 }