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