nss: import at 3.0.1 beta 1
[mozilla-nss.git] / security / nss / cmd / tstclnt / tstclnt.c
blob6377c0236b51f8e89e9e3c59ee68cd5b7e1793eb
1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
12 * License.
14 * The Original Code is the Netscape security libraries.
16 * The Initial Developer of the Original Code is
17 * Netscape Communications Corporation.
18 * Portions created by the Initial Developer are Copyright (C) 1994-2000
19 * the Initial Developer. All Rights Reserved.
21 * Contributor(s):
22 * Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
23 * Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
25 * Alternatively, the contents of this file may be used under the terms of
26 * either the GNU General Public License Version 2 or later (the "GPL"), or
27 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK ***** */
41 ** Sample client side test program that uses SSL and libsec
45 #include "secutil.h"
47 #if defined(XP_UNIX)
48 #include <unistd.h>
49 #else
50 #include <ctype.h> /* for isalpha() */
51 #endif
53 #include <stdio.h>
54 #include <string.h>
55 #include <stdlib.h>
56 #include <errno.h>
57 #include <fcntl.h>
58 #include <stdarg.h>
60 #include "nspr.h"
61 #include "prio.h"
62 #include "prnetdb.h"
63 #include "nss.h"
64 #include "ssl.h"
65 #include "sslproto.h"
66 #include "pk11func.h"
67 #include "plgetopt.h"
68 #include "plstr.h"
70 #if defined(WIN32)
71 #include <fcntl.h>
72 #include <io.h>
73 #endif
75 #define PRINTF if (verbose) printf
76 #define FPRINTF if (verbose) fprintf
78 #define MAX_WAIT_FOR_SERVER 600
79 #define WAIT_INTERVAL 100
81 PRIntervalTime maxInterval = PR_INTERVAL_NO_TIMEOUT;
83 int ssl2CipherSuites[] = {
84 SSL_EN_RC4_128_WITH_MD5, /* A */
85 SSL_EN_RC4_128_EXPORT40_WITH_MD5, /* B */
86 SSL_EN_RC2_128_CBC_WITH_MD5, /* C */
87 SSL_EN_RC2_128_CBC_EXPORT40_WITH_MD5, /* D */
88 SSL_EN_DES_64_CBC_WITH_MD5, /* E */
89 SSL_EN_DES_192_EDE3_CBC_WITH_MD5, /* F */
93 int ssl3CipherSuites[] = {
94 -1, /* SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA* a */
95 -1, /* SSL_FORTEZZA_DMS_WITH_RC4_128_SHA, * b */
96 SSL_RSA_WITH_RC4_128_MD5, /* c */
97 SSL_RSA_WITH_3DES_EDE_CBC_SHA, /* d */
98 SSL_RSA_WITH_DES_CBC_SHA, /* e */
99 SSL_RSA_EXPORT_WITH_RC4_40_MD5, /* f */
100 SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5, /* g */
101 -1, /* SSL_FORTEZZA_DMS_WITH_NULL_SHA, * h */
102 SSL_RSA_WITH_NULL_MD5, /* i */
103 SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA, /* j */
104 SSL_RSA_FIPS_WITH_DES_CBC_SHA, /* k */
105 TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA, /* l */
106 TLS_RSA_EXPORT1024_WITH_RC4_56_SHA, /* m */
107 SSL_RSA_WITH_RC4_128_SHA, /* n */
108 TLS_DHE_DSS_WITH_RC4_128_SHA, /* o */
109 SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, /* p */
110 SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, /* q */
111 SSL_DHE_RSA_WITH_DES_CBC_SHA, /* r */
112 SSL_DHE_DSS_WITH_DES_CBC_SHA, /* s */
113 TLS_DHE_DSS_WITH_AES_128_CBC_SHA, /* t */
114 TLS_DHE_RSA_WITH_AES_128_CBC_SHA, /* u */
115 TLS_RSA_WITH_AES_128_CBC_SHA, /* v */
116 TLS_DHE_DSS_WITH_AES_256_CBC_SHA, /* w */
117 TLS_DHE_RSA_WITH_AES_256_CBC_SHA, /* x */
118 TLS_RSA_WITH_AES_256_CBC_SHA, /* y */
119 SSL_RSA_WITH_NULL_SHA, /* z */
123 unsigned long __cmp_umuls;
124 PRBool verbose;
125 int renegotiate = 0;
127 static char *progName;
129 /* This exists only for the automated test suite. It allows us to
130 * pass in a password on the command line.
133 char *password = NULL;
135 char * ownPasswd( PK11SlotInfo *slot, PRBool retry, void *arg)
137 char *passwd = NULL;
138 if ( (!retry) && arg ) {
139 passwd = PL_strdup((char *)arg);
141 return passwd;
144 void printSecurityInfo(PRFileDesc *fd)
146 CERTCertificate * cert;
147 SSL3Statistics * ssl3stats = SSL_GetStatistics();
148 SECStatus result;
149 SSLChannelInfo channel;
150 SSLCipherSuiteInfo suite;
152 result = SSL_GetChannelInfo(fd, &channel, sizeof channel);
153 if (result == SECSuccess &&
154 channel.length == sizeof channel &&
155 channel.cipherSuite) {
156 result = SSL_GetCipherSuiteInfo(channel.cipherSuite,
157 &suite, sizeof suite);
158 if (result == SECSuccess) {
159 FPRINTF(stderr,
160 "tstclnt: SSL version %d.%d using %d-bit %s with %d-bit %s MAC\n",
161 channel.protocolVersion >> 8, channel.protocolVersion & 0xff,
162 suite.effectiveKeyBits, suite.symCipherName,
163 suite.macBits, suite.macAlgorithmName);
164 FPRINTF(stderr,
165 "tstclnt: Server Auth: %d-bit %s, Key Exchange: %d-bit %s\n",
166 channel.authKeyBits, suite.authAlgorithmName,
167 channel.keaKeyBits, suite.keaTypeName);
170 cert = SSL_RevealCert(fd);
171 if (cert) {
172 char * ip = CERT_NameToAscii(&cert->issuer);
173 char * sp = CERT_NameToAscii(&cert->subject);
174 if (sp) {
175 fprintf(stderr, "subject DN: %s\n", sp);
176 PORT_Free(sp);
178 if (ip) {
179 fprintf(stderr, "issuer DN: %s\n", ip);
180 PORT_Free(ip);
182 CERT_DestroyCertificate(cert);
183 cert = NULL;
185 fprintf(stderr,
186 "%ld cache hits; %ld cache misses, %ld cache not reusable\n"
187 "%ld stateless resumes\n",
188 ssl3stats->hsh_sid_cache_hits, ssl3stats->hsh_sid_cache_misses,
189 ssl3stats->hsh_sid_cache_not_ok, ssl3stats->hsh_sid_stateless_resumes);
192 void
193 handshakeCallback(PRFileDesc *fd, void *client_data)
195 printSecurityInfo(fd);
196 if (renegotiate > 0) {
197 renegotiate--;
198 SSL_ReHandshake(fd, PR_FALSE);
202 static void Usage(const char *progName)
204 fprintf(stderr,
205 "Usage: %s -h host [-p port] [-d certdir] [-n nickname] [-23BTfosvxr] \n"
206 " [-c ciphers] [-w passwd] [-q]\n", progName);
207 fprintf(stderr, "%-20s Hostname to connect with\n", "-h host");
208 fprintf(stderr, "%-20s Port number for SSL server\n", "-p port");
209 fprintf(stderr,
210 "%-20s Directory with cert database (default is ~/.netscape)\n",
211 "-d certdir");
212 fprintf(stderr, "%-20s Nickname of key and cert for client auth\n",
213 "-n nickname");
214 fprintf(stderr,
215 "%-20s Bypass PKCS11 layer for SSL encryption and MACing.\n", "-B");
216 fprintf(stderr, "%-20s Disable SSL v2.\n", "-2");
217 fprintf(stderr, "%-20s Disable SSL v3.\n", "-3");
218 fprintf(stderr, "%-20s Disable TLS (SSL v3.1).\n", "-T");
219 fprintf(stderr, "%-20s Prints only payload data. Skips HTTP header.\n", "-S");
220 fprintf(stderr, "%-20s Client speaks first. \n", "-f");
221 fprintf(stderr, "%-20s Override bad server cert. Make it OK.\n", "-o");
222 fprintf(stderr, "%-20s Disable SSL socket locking.\n", "-s");
223 fprintf(stderr, "%-20s Verbose progress reporting.\n", "-v");
224 fprintf(stderr, "%-20s Use export policy.\n", "-x");
225 fprintf(stderr, "%-20s Ping the server and then exit.\n", "-q");
226 fprintf(stderr, "%-20s Renegotiate with session resumption.\n", "-r");
227 fprintf(stderr, "%-20s Enable the session ticket extension.\n", "-u");
228 fprintf(stderr, "%-20s Letter(s) chosen from the following list\n",
229 "-c ciphers");
230 fprintf(stderr,
231 "A SSL2 RC4 128 WITH MD5\n"
232 "B SSL2 RC4 128 EXPORT40 WITH MD5\n"
233 "C SSL2 RC2 128 CBC WITH MD5\n"
234 "D SSL2 RC2 128 CBC EXPORT40 WITH MD5\n"
235 "E SSL2 DES 64 CBC WITH MD5\n"
236 "F SSL2 DES 192 EDE3 CBC WITH MD5\n"
237 "\n"
238 "c SSL3 RSA WITH RC4 128 MD5\n"
239 "d SSL3 RSA WITH 3DES EDE CBC SHA\n"
240 "e SSL3 RSA WITH DES CBC SHA\n"
241 "f SSL3 RSA EXPORT WITH RC4 40 MD5\n"
242 "g SSL3 RSA EXPORT WITH RC2 CBC 40 MD5\n"
243 "i SSL3 RSA WITH NULL MD5\n"
244 "j SSL3 RSA FIPS WITH 3DES EDE CBC SHA\n"
245 "k SSL3 RSA FIPS WITH DES CBC SHA\n"
246 "l SSL3 RSA EXPORT WITH DES CBC SHA\t(new)\n"
247 "m SSL3 RSA EXPORT WITH RC4 56 SHA\t(new)\n"
248 "n SSL3 RSA WITH RC4 128 SHA\n"
249 "o SSL3 DHE DSS WITH RC4 128 SHA\n"
250 "p SSL3 DHE RSA WITH 3DES EDE CBC SHA\n"
251 "q SSL3 DHE DSS WITH 3DES EDE CBC SHA\n"
252 "r SSL3 DHE RSA WITH DES CBC SHA\n"
253 "s SSL3 DHE DSS WITH DES CBC SHA\n"
254 "t SSL3 DHE DSS WITH AES 128 CBC SHA\n"
255 "u SSL3 DHE RSA WITH AES 128 CBC SHA\n"
256 "v SSL3 RSA WITH AES 128 CBC SHA\n"
257 "w SSL3 DHE DSS WITH AES 256 CBC SHA\n"
258 "x SSL3 DHE RSA WITH AES 256 CBC SHA\n"
259 "y SSL3 RSA WITH AES 256 CBC SHA\n"
260 "z SSL3 RSA WITH NULL SHA\n"
261 "\n"
262 ":WXYZ Use cipher with hex code { 0xWX , 0xYZ } in TLS\n"
264 exit(1);
267 void
268 milliPause(PRUint32 milli)
270 PRIntervalTime ticks = PR_MillisecondsToInterval(milli);
271 PR_Sleep(ticks);
274 void
275 disableAllSSLCiphers(void)
277 const PRUint16 *cipherSuites = SSL_ImplementedCiphers;
278 int i = SSL_NumImplementedCiphers;
279 SECStatus rv;
281 /* disable all the SSL3 cipher suites */
282 while (--i >= 0) {
283 PRUint16 suite = cipherSuites[i];
284 rv = SSL_CipherPrefSetDefault(suite, PR_FALSE);
285 if (rv != SECSuccess) {
286 PRErrorCode err = PR_GetError();
287 fprintf(stderr,
288 "SSL_CipherPrefSet didn't like value 0x%04x (i = %d): %s\n",
289 suite, i, SECU_Strerror(err));
290 exit(2);
296 * Callback is called when incoming certificate is not valid.
297 * Returns SECSuccess to accept the cert anyway, SECFailure to reject.
299 static SECStatus
300 ownBadCertHandler(void * arg, PRFileDesc * socket)
302 PRErrorCode err = PR_GetError();
303 /* can log invalid cert here */
304 fprintf(stderr, "Bad server certificate: %d, %s\n", err,
305 SECU_Strerror(err));
306 return SECSuccess; /* override, say it's OK. */
309 SECStatus
310 own_GetClientAuthData(void * arg,
311 PRFileDesc * socket,
312 struct CERTDistNamesStr * caNames,
313 struct CERTCertificateStr ** pRetCert,
314 struct SECKEYPrivateKeyStr **pRetKey)
316 if (verbose > 1) {
317 SECStatus rv;
318 fprintf(stderr, "Server requested Client Authentication\n");
319 if (caNames && caNames->nnames > 0) {
320 PLArenaPool *arena = caNames->arena;
321 if (!arena)
322 arena = PORT_NewArena(2048);
323 if (arena) {
324 int i;
325 for (i = 0; i < caNames->nnames; ++i) {
326 char *nameString;
327 CERTName dn;
328 rv = SEC_QuickDERDecodeItem(arena,
329 &dn,
330 SEC_ASN1_GET(CERT_NameTemplate),
331 caNames->names + i);
332 if (rv != SECSuccess)
333 continue;
334 nameString = CERT_NameToAscii(&dn);
335 if (!nameString)
336 continue;
337 fprintf(stderr, "CA[%d]: %s\n", i + 1, nameString);
338 PORT_Free(nameString);
340 if (!caNames->arena) {
341 PORT_FreeArena(arena, PR_FALSE);
345 rv = NSS_GetClientAuthData(arg, socket, caNames, pRetCert, pRetKey);
346 if (rv == SECSuccess && *pRetCert) {
347 char *nameString = CERT_NameToAscii(&((*pRetCert)->subject));
348 if (nameString) {
349 fprintf(stderr, "sent cert: %s\n", nameString);
350 PORT_Free(nameString);
352 } else {
353 fprintf(stderr, "send no cert\n");
355 return rv;
357 return NSS_GetClientAuthData(arg, socket, caNames, pRetCert, pRetKey);
360 #if defined(WIN32) || defined(OS2)
361 void
362 thread_main(void * arg)
364 PRFileDesc * ps = (PRFileDesc *)arg;
365 PRFileDesc * std_in = PR_GetSpecialFD(PR_StandardInput);
366 int wc, rc;
367 char buf[256];
369 #ifdef WIN32
371 /* Put stdin into O_BINARY mode
372 ** or else incoming \r\n's will become \n's.
374 int smrv = _setmode(_fileno(stdin), _O_BINARY);
375 if (smrv == -1) {
376 fprintf(stderr,
377 "%s: Cannot change stdin to binary mode. Use -i option instead.\n",
378 progName);
379 /* plow ahead anyway */
382 #endif
384 do {
385 rc = PR_Read(std_in, buf, sizeof buf);
386 if (rc <= 0)
387 break;
388 wc = PR_Send(ps, buf, rc, 0, maxInterval);
389 } while (wc == rc);
390 PR_Close(ps);
393 #endif
395 static void
396 printHostNameAndAddr(const char * host, const PRNetAddr * addr)
398 PRUint16 port = PR_NetAddrInetPort(addr);
399 char addrBuf[80];
400 PRStatus st = PR_NetAddrToString(addr, addrBuf, sizeof addrBuf);
402 if (st == PR_SUCCESS) {
403 port = PR_ntohs(port);
404 FPRINTF(stderr, "%s: connecting to %s:%hu (address=%s)\n",
405 progName, host, port, addrBuf);
410 * Prints output according to skipProtoHeader flag. If skipProtoHeader
411 * is not set, prints without any changes, otherwise looking
412 * for \n\r\n(empty line sequence: HTTP header separator) and
413 * prints everything after it.
415 static void
416 separateReqHeader(const PRFileDesc* outFd, const char* buf, const int nb,
417 PRBool *wrStarted, int *ptrnMatched) {
419 /* it is sufficient to look for only "\n\r\n". Hopping that
420 * HTTP response format satisfies the standard */
421 char *ptrnStr = "\n\r\n";
422 char *resPtr;
424 if (nb == 0) {
425 return;
428 if (*ptrnMatched > 0) {
429 /* Get here only if previous separateReqHeader call found
430 * only a fragment of "\n\r\n" in previous buffer. */
431 PORT_Assert(*ptrnMatched < 3);
433 /* the size of fragment of "\n\r\n" what we want to find in this
434 * buffer is equal to *ptrnMatched */
435 if (*ptrnMatched <= nb) {
436 /* move the pointer to the beginning of the fragment */
437 int strSize = *ptrnMatched;
438 char *tmpPtrn = ptrnStr + (3 - strSize);
439 if (PL_strncmp(buf, tmpPtrn, strSize) == 0) {
440 /* print the rest of the buffer(without the fragment) */
441 PR_Write((void*)outFd, buf + strSize, nb - strSize);
442 *wrStarted = PR_TRUE;
443 return;
445 } else {
446 /* we are here only when nb == 1 && *ptrnMatched == 2 */
447 if (*buf == '\r') {
448 *ptrnMatched = 1;
449 } else {
450 *ptrnMatched = 0;
452 return;
455 resPtr = PL_strnstr(buf, ptrnStr, nb);
456 if (resPtr != NULL) {
457 /* if "\n\r\n" was found in the buffer, calculate offset
458 * and print the rest of the buffer */
459 int newBn = nb - (resPtr - buf + 3); /* 3 is the length of "\n\r\n" */
461 PR_Write((void*)outFd, resPtr + 3, newBn);
462 *wrStarted = PR_TRUE;
463 return;
464 } else {
465 /* try to find a fragment of "\n\r\n" at the end of the buffer.
466 * if found, set *ptrnMatched to the number of chars left to find
467 * in the next buffer.*/
468 int i;
469 for(i = 1 ;i < 3;i++) {
470 char *bufPrt;
471 int strSize = 3 - i;
473 if (strSize > nb) {
474 continue;
476 bufPrt = (char*)(buf + nb - strSize);
478 if (PL_strncmp(bufPrt, ptrnStr, strSize) == 0) {
479 *ptrnMatched = i;
480 return;
486 #define SSOCK_FD 0
487 #define STDIN_FD 1
489 #define HEXCHAR_TO_INT(c, i) \
490 if (((c) >= '0') && ((c) <= '9')) { \
491 i = (c) - '0'; \
492 } else if (((c) >= 'a') && ((c) <= 'f')) { \
493 i = (c) - 'a' + 10; \
494 } else if (((c) >= 'A') && ((c) <= 'F')) { \
495 i = (c) - 'A' + 10; \
496 } else { \
497 Usage(progName); \
500 int main(int argc, char **argv)
502 PRFileDesc * s;
503 PRFileDesc * std_out;
504 CERTCertDBHandle * handle;
505 char * host = NULL;
506 char * certDir = NULL;
507 char * nickname = NULL;
508 char * cipherString = NULL;
509 char * tmp;
510 int multiplier = 0;
511 SECStatus rv;
512 PRStatus status;
513 PRInt32 filesReady;
514 int npds;
515 int override = 0;
516 int disableSSL2 = 0;
517 int disableSSL3 = 0;
518 int disableTLS = 0;
519 int bypassPKCS11 = 0;
520 int disableLocking = 0;
521 int useExportPolicy = 0;
522 int enableSessionTickets = 0;
523 PRSocketOptionData opt;
524 PRNetAddr addr;
525 PRPollDesc pollset[2];
526 PRBool useCommandLinePassword = PR_FALSE;
527 PRBool pingServerFirst = PR_FALSE;
528 PRBool clientSpeaksFirst = PR_FALSE;
529 PRBool wrStarted = PR_FALSE;
530 PRBool skipProtoHeader = PR_FALSE;
531 int headerSeparatorPtrnId = 0;
532 int error = 0;
533 PRUint16 portno = 443;
534 PLOptState *optstate;
535 PLOptStatus optstatus;
536 PRStatus prStatus;
538 progName = strrchr(argv[0], '/');
539 if (!progName)
540 progName = strrchr(argv[0], '\\');
541 progName = progName ? progName+1 : argv[0];
543 tmp = PR_GetEnv("NSS_DEBUG_TIMEOUT");
544 if (tmp && tmp[0]) {
545 int sec = PORT_Atoi(tmp);
546 if (sec > 0) {
547 maxInterval = PR_SecondsToInterval(sec);
551 optstate = PL_CreateOptState(argc, argv, "23BTSfc:h:p:d:m:n:oqr:suvw:x");
552 while ((optstatus = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
553 switch (optstate->option) {
554 case '?':
555 default : Usage(progName); break;
557 case '2': disableSSL2 = 1; break;
559 case '3': disableSSL3 = 1; break;
561 case 'B': bypassPKCS11 = 1; break;
563 case 'T': disableTLS = 1; break;
565 case 'S': skipProtoHeader = PR_TRUE; break;
567 case 'c': cipherString = PORT_Strdup(optstate->value); break;
569 case 'h': host = PORT_Strdup(optstate->value); break;
571 case 'f': clientSpeaksFirst = PR_TRUE; break;
573 case 'd': certDir = PORT_Strdup(optstate->value); break;
575 case 'm':
576 multiplier = atoi(optstate->value);
577 if (multiplier < 0)
578 multiplier = 0;
579 break;
581 case 'n': nickname = PORT_Strdup(optstate->value); break;
583 case 'o': override = 1; break;
585 case 'p': portno = (PRUint16)atoi(optstate->value); break;
587 case 'q': pingServerFirst = PR_TRUE; break;
589 case 's': disableLocking = 1; break;
591 case 'u': enableSessionTickets = PR_TRUE; break;
593 case 'v': verbose++; break;
595 case 'r': renegotiate = atoi(optstate->value); break;
597 case 'w':
598 password = PORT_Strdup(optstate->value);
599 useCommandLinePassword = PR_TRUE;
600 break;
602 case 'x': useExportPolicy = 1; break;
606 PL_DestroyOptState(optstate);
608 if (optstatus == PL_OPT_BAD)
609 Usage(progName);
611 if (!host || !portno)
612 Usage(progName);
614 PR_Init( PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
616 /* set our password function */
617 if ( useCommandLinePassword ) {
618 PK11_SetPasswordFunc(ownPasswd);
619 } else {
620 PK11_SetPasswordFunc(SECU_GetModulePassword);
623 /* open the cert DB, the key DB, and the secmod DB. */
624 if (!certDir) {
625 certDir = SECU_DefaultSSLDir(); /* Look in $SSL_DIR */
626 certDir = SECU_ConfigDirectory(certDir);
627 } else {
628 char *certDirTmp = certDir;
629 certDir = SECU_ConfigDirectory(certDirTmp);
630 PORT_Free(certDirTmp);
632 rv = NSS_Init(certDir);
633 if (rv != SECSuccess) {
634 SECU_PrintError(progName, "unable to open cert database");
635 #if 0
636 rv = CERT_OpenVolatileCertDB(handle);
637 CERT_SetDefaultCertDB(handle);
638 #else
639 return 1;
640 #endif
642 handle = CERT_GetDefaultCertDB();
644 /* set the policy bits true for all the cipher suites. */
645 if (useExportPolicy)
646 NSS_SetExportPolicy();
647 else
648 NSS_SetDomesticPolicy();
650 /* all the SSL2 and SSL3 cipher suites are enabled by default. */
651 if (cipherString) {
652 /* disable all the ciphers, then enable the ones we want. */
653 disableAllSSLCiphers();
656 status = PR_StringToNetAddr(host, &addr);
657 if (status == PR_SUCCESS) {
658 addr.inet.port = PR_htons(portno);
659 } else {
660 /* Lookup host */
661 PRAddrInfo *addrInfo;
662 void *enumPtr = NULL;
664 addrInfo = PR_GetAddrInfoByName(host, PR_AF_UNSPEC,
665 PR_AI_ADDRCONFIG | PR_AI_NOCANONNAME);
666 if (!addrInfo) {
667 SECU_PrintError(progName, "error looking up host");
668 return 1;
670 do {
671 enumPtr = PR_EnumerateAddrInfo(enumPtr, addrInfo, portno, &addr);
672 } while (enumPtr != NULL &&
673 addr.raw.family != PR_AF_INET &&
674 addr.raw.family != PR_AF_INET6);
675 PR_FreeAddrInfo(addrInfo);
676 if (enumPtr == NULL) {
677 SECU_PrintError(progName, "error looking up host address");
678 return 1;
682 printHostNameAndAddr(host, &addr);
684 if (pingServerFirst) {
685 int iter = 0;
686 PRErrorCode err;
687 do {
688 s = PR_OpenTCPSocket(addr.raw.family);
689 if (s == NULL) {
690 SECU_PrintError(progName, "Failed to create a TCP socket");
692 opt.option = PR_SockOpt_Nonblocking;
693 opt.value.non_blocking = PR_FALSE;
694 prStatus = PR_SetSocketOption(s, &opt);
695 if (prStatus != PR_SUCCESS) {
696 PR_Close(s);
697 SECU_PrintError(progName,
698 "Failed to set blocking socket option");
699 return 1;
701 prStatus = PR_Connect(s, &addr, PR_INTERVAL_NO_TIMEOUT);
702 if (prStatus == PR_SUCCESS) {
703 PR_Shutdown(s, PR_SHUTDOWN_BOTH);
704 PR_Close(s);
705 if (NSS_Shutdown() != SECSuccess) {
706 exit(1);
708 PR_Cleanup();
709 return 0;
711 err = PR_GetError();
712 if ((err != PR_CONNECT_REFUSED_ERROR) &&
713 (err != PR_CONNECT_RESET_ERROR)) {
714 SECU_PrintError(progName, "TCP Connection failed");
715 return 1;
717 PR_Close(s);
718 PR_Sleep(PR_MillisecondsToInterval(WAIT_INTERVAL));
719 } while (++iter < MAX_WAIT_FOR_SERVER);
720 SECU_PrintError(progName,
721 "Client timed out while waiting for connection to server");
722 return 1;
725 /* Create socket */
726 s = PR_OpenTCPSocket(addr.raw.family);
727 if (s == NULL) {
728 SECU_PrintError(progName, "error creating socket");
729 return 1;
732 opt.option = PR_SockOpt_Nonblocking;
733 opt.value.non_blocking = PR_TRUE;
734 PR_SetSocketOption(s, &opt);
735 /*PR_SetSocketOption(PR_GetSpecialFD(PR_StandardInput), &opt);*/
737 s = SSL_ImportFD(NULL, s);
738 if (s == NULL) {
739 SECU_PrintError(progName, "error importing socket");
740 return 1;
743 rv = SSL_OptionSet(s, SSL_SECURITY, 1);
744 if (rv != SECSuccess) {
745 SECU_PrintError(progName, "error enabling socket");
746 return 1;
749 rv = SSL_OptionSet(s, SSL_HANDSHAKE_AS_CLIENT, 1);
750 if (rv != SECSuccess) {
751 SECU_PrintError(progName, "error enabling client handshake");
752 return 1;
755 /* all the SSL2 and SSL3 cipher suites are enabled by default. */
756 if (cipherString) {
757 char *cstringSaved = cipherString;
758 int ndx;
760 while (0 != (ndx = *cipherString++)) {
761 int cipher;
763 if (ndx == ':') {
764 int ctmp;
766 cipher = 0;
767 HEXCHAR_TO_INT(*cipherString, ctmp)
768 cipher |= (ctmp << 12);
769 cipherString++;
770 HEXCHAR_TO_INT(*cipherString, ctmp)
771 cipher |= (ctmp << 8);
772 cipherString++;
773 HEXCHAR_TO_INT(*cipherString, ctmp)
774 cipher |= (ctmp << 4);
775 cipherString++;
776 HEXCHAR_TO_INT(*cipherString, ctmp)
777 cipher |= ctmp;
778 cipherString++;
779 } else {
780 const int *cptr;
782 if (! isalpha(ndx))
783 Usage(progName);
784 cptr = islower(ndx) ? ssl3CipherSuites : ssl2CipherSuites;
785 for (ndx &= 0x1f; (cipher = *cptr++) != 0 && --ndx > 0; )
786 /* do nothing */;
788 if (cipher > 0) {
789 SECStatus status;
790 status = SSL_CipherPrefSet(s, cipher, SSL_ALLOWED);
791 if (status != SECSuccess)
792 SECU_PrintError(progName, "SSL_CipherPrefSet()");
793 } else {
794 Usage(progName);
797 PORT_Free(cstringSaved);
800 rv = SSL_OptionSet(s, SSL_ENABLE_SSL2, !disableSSL2);
801 if (rv != SECSuccess) {
802 SECU_PrintError(progName, "error enabling SSLv2 ");
803 return 1;
806 rv = SSL_OptionSet(s, SSL_ENABLE_SSL3, !disableSSL3);
807 if (rv != SECSuccess) {
808 SECU_PrintError(progName, "error enabling SSLv3 ");
809 return 1;
812 rv = SSL_OptionSet(s, SSL_ENABLE_TLS, !disableTLS);
813 if (rv != SECSuccess) {
814 SECU_PrintError(progName, "error enabling TLS ");
815 return 1;
818 /* disable ssl2 and ssl2-compatible client hellos. */
819 rv = SSL_OptionSet(s, SSL_V2_COMPATIBLE_HELLO, !disableSSL2);
820 if (rv != SECSuccess) {
821 SECU_PrintError(progName, "error disabling v2 compatibility");
822 return 1;
825 /* enable PKCS11 bypass */
826 rv = SSL_OptionSet(s, SSL_BYPASS_PKCS11, bypassPKCS11);
827 if (rv != SECSuccess) {
828 SECU_PrintError(progName, "error enabling PKCS11 bypass");
829 return 1;
832 /* disable SSL socket locking */
833 rv = SSL_OptionSet(s, SSL_NO_LOCKS, disableLocking);
834 if (rv != SECSuccess) {
835 SECU_PrintError(progName, "error disabling SSL socket locking");
836 return 1;
839 /* enable Session Ticket extension. */
840 rv = SSL_OptionSet(s, SSL_ENABLE_SESSION_TICKETS, enableSessionTickets);
841 if (rv != SECSuccess) {
842 SECU_PrintError(progName, "error enabling Session Ticket extension");
843 return 1;
846 if (useCommandLinePassword) {
847 SSL_SetPKCS11PinArg(s, password);
850 SSL_AuthCertificateHook(s, SSL_AuthCertificate, (void *)handle);
851 if (override) {
852 SSL_BadCertHook(s, ownBadCertHandler, NULL);
854 SSL_GetClientAuthDataHook(s, own_GetClientAuthData, (void *)nickname);
855 SSL_HandshakeCallback(s, handshakeCallback, NULL);
856 SSL_SetURL(s, host);
858 /* Try to connect to the server */
859 status = PR_Connect(s, &addr, PR_INTERVAL_NO_TIMEOUT);
860 if (status != PR_SUCCESS) {
861 if (PR_GetError() == PR_IN_PROGRESS_ERROR) {
862 if (verbose)
863 SECU_PrintError(progName, "connect");
864 milliPause(50 * multiplier);
865 pollset[SSOCK_FD].in_flags = PR_POLL_WRITE | PR_POLL_EXCEPT;
866 pollset[SSOCK_FD].out_flags = 0;
867 pollset[SSOCK_FD].fd = s;
868 while(1) {
869 FPRINTF(stderr,
870 "%s: about to call PR_Poll for connect completion!\n",
871 progName);
872 filesReady = PR_Poll(pollset, 1, PR_INTERVAL_NO_TIMEOUT);
873 if (filesReady < 0) {
874 SECU_PrintError(progName, "unable to connect (poll)");
875 return 1;
877 FPRINTF(stderr,
878 "%s: PR_Poll returned 0x%02x for socket out_flags.\n",
879 progName, pollset[SSOCK_FD].out_flags);
880 if (filesReady == 0) { /* shouldn't happen! */
881 FPRINTF(stderr, "%s: PR_Poll returned zero!\n", progName);
882 return 1;
884 /* Must milliPause between PR_Poll and PR_GetConnectStatus,
885 * Or else winsock gets mighty confused.
886 * Sleep(0);
888 milliPause(1);
889 status = PR_GetConnectStatus(pollset);
890 if (status == PR_SUCCESS) {
891 break;
893 if (PR_GetError() != PR_IN_PROGRESS_ERROR) {
894 SECU_PrintError(progName, "unable to connect (poll)");
895 return 1;
897 SECU_PrintError(progName, "poll");
898 milliPause(50 * multiplier);
900 } else {
901 SECU_PrintError(progName, "unable to connect");
902 return 1;
906 pollset[SSOCK_FD].fd = s;
907 pollset[SSOCK_FD].in_flags = PR_POLL_EXCEPT |
908 (clientSpeaksFirst ? 0 : PR_POLL_READ);
909 pollset[STDIN_FD].fd = PR_GetSpecialFD(PR_StandardInput);
910 pollset[STDIN_FD].in_flags = PR_POLL_READ;
911 npds = 2;
912 std_out = PR_GetSpecialFD(PR_StandardOutput);
914 #if defined(WIN32) || defined(OS2)
915 /* PR_Poll cannot be used with stdin on Windows or OS/2. (sigh).
916 ** But use of PR_Poll and non-blocking sockets is a major feature
917 ** of this program. So, we simulate a pollable stdin with a
918 ** TCP socket pair and a thread that reads stdin and writes to
919 ** that socket pair.
922 PRFileDesc * fds[2];
923 PRThread * thread;
925 int nspr_rv = PR_NewTCPSocketPair(fds);
926 if (nspr_rv != PR_SUCCESS) {
927 SECU_PrintError(progName, "PR_NewTCPSocketPair failed");
928 error = 1;
929 goto done;
931 pollset[STDIN_FD].fd = fds[1];
933 thread = PR_CreateThread(PR_USER_THREAD, thread_main, fds[0],
934 PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
935 PR_UNJOINABLE_THREAD, 0);
936 if (!thread) {
937 SECU_PrintError(progName, "PR_CreateThread failed");
938 error = 1;
939 goto done;
942 #endif
945 ** Select on stdin and on the socket. Write data from stdin to
946 ** socket, read data from socket and write to stdout.
948 FPRINTF(stderr, "%s: ready...\n", progName);
950 while (pollset[SSOCK_FD].in_flags | pollset[STDIN_FD].in_flags) {
951 char buf[4000]; /* buffer for stdin */
952 int nb; /* num bytes read from stdin. */
954 pollset[SSOCK_FD].out_flags = 0;
955 pollset[STDIN_FD].out_flags = 0;
957 FPRINTF(stderr, "%s: about to call PR_Poll !\n", progName);
958 filesReady = PR_Poll(pollset, npds, PR_INTERVAL_NO_TIMEOUT);
959 if (filesReady < 0) {
960 SECU_PrintError(progName, "select failed");
961 error = 1;
962 goto done;
964 if (filesReady == 0) { /* shouldn't happen! */
965 FPRINTF(stderr, "%s: PR_Poll returned zero!\n", progName);
966 return 1;
968 FPRINTF(stderr, "%s: PR_Poll returned!\n", progName);
969 if (pollset[STDIN_FD].in_flags) {
970 FPRINTF(stderr,
971 "%s: PR_Poll returned 0x%02x for stdin out_flags.\n",
972 progName, pollset[STDIN_FD].out_flags);
974 if (pollset[SSOCK_FD].in_flags) {
975 FPRINTF(stderr,
976 "%s: PR_Poll returned 0x%02x for socket out_flags.\n",
977 progName, pollset[SSOCK_FD].out_flags);
979 if (pollset[STDIN_FD].out_flags & PR_POLL_READ) {
980 /* Read from stdin and write to socket */
981 nb = PR_Read(pollset[STDIN_FD].fd, buf, sizeof(buf));
982 FPRINTF(stderr, "%s: stdin read %d bytes\n", progName, nb);
983 if (nb < 0) {
984 if (PR_GetError() != PR_WOULD_BLOCK_ERROR) {
985 SECU_PrintError(progName, "read from stdin failed");
986 error = 1;
987 break;
989 } else if (nb == 0) {
990 /* EOF on stdin, stop polling stdin for read. */
991 pollset[STDIN_FD].in_flags = 0;
992 } else {
993 char * bufp = buf;
994 FPRINTF(stderr, "%s: Writing %d bytes to server\n",
995 progName, nb);
996 do {
997 PRInt32 cc = PR_Send(s, bufp, nb, 0, maxInterval);
998 if (cc < 0) {
999 PRErrorCode err = PR_GetError();
1000 if (err != PR_WOULD_BLOCK_ERROR) {
1001 SECU_PrintError(progName,
1002 "write to SSL socket failed");
1003 error = 254;
1004 goto done;
1006 cc = 0;
1008 bufp += cc;
1009 nb -= cc;
1010 if (nb <= 0)
1011 break;
1012 pollset[SSOCK_FD].in_flags = PR_POLL_WRITE | PR_POLL_EXCEPT;
1013 pollset[SSOCK_FD].out_flags = 0;
1014 FPRINTF(stderr,
1015 "%s: about to call PR_Poll on writable socket !\n",
1016 progName);
1017 cc = PR_Poll(pollset, 1, PR_INTERVAL_NO_TIMEOUT);
1018 FPRINTF(stderr,
1019 "%s: PR_Poll returned with writable socket !\n",
1020 progName);
1021 } while (1);
1022 pollset[SSOCK_FD].in_flags = PR_POLL_READ;
1026 if (pollset[SSOCK_FD].in_flags) {
1027 FPRINTF(stderr,
1028 "%s: PR_Poll returned 0x%02x for socket out_flags.\n",
1029 progName, pollset[SSOCK_FD].out_flags);
1031 if ( (pollset[SSOCK_FD].out_flags & PR_POLL_READ)
1032 || (pollset[SSOCK_FD].out_flags & PR_POLL_ERR)
1033 #ifdef PR_POLL_HUP
1034 || (pollset[SSOCK_FD].out_flags & PR_POLL_HUP)
1035 #endif
1037 /* Read from socket and write to stdout */
1038 nb = PR_Recv(pollset[SSOCK_FD].fd, buf, sizeof buf, 0, maxInterval);
1039 FPRINTF(stderr, "%s: Read from server %d bytes\n", progName, nb);
1040 if (nb < 0) {
1041 if (PR_GetError() != PR_WOULD_BLOCK_ERROR) {
1042 SECU_PrintError(progName, "read from socket failed");
1043 error = 1;
1044 goto done;
1046 } else if (nb == 0) {
1047 /* EOF from socket... stop polling socket for read */
1048 pollset[SSOCK_FD].in_flags = 0;
1049 } else {
1050 if (skipProtoHeader != PR_TRUE || wrStarted == PR_TRUE) {
1051 PR_Write(std_out, buf, nb);
1052 } else {
1053 separateReqHeader(std_out, buf, nb, &wrStarted,
1054 &headerSeparatorPtrnId);
1056 if (verbose)
1057 fputs("\n\n", stderr);
1060 milliPause(50 * multiplier);
1063 done:
1064 if (nickname) {
1065 PORT_Free(nickname);
1067 if (password) {
1068 PORT_Free(password);
1070 PORT_Free(host);
1072 PR_Close(s);
1073 SSL_ClearSessionCache();
1074 if (NSS_Shutdown() != SECSuccess) {
1075 exit(1);
1078 PR_Cleanup();
1079 return error;