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
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.
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
50 #include <ctype.h> /* for isalpha() */
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
;
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
)
138 if ( (!retry
) && arg
) {
139 passwd
= PL_strdup((char *)arg
);
144 void printSecurityInfo(PRFileDesc
*fd
)
146 CERTCertificate
* cert
;
147 SSL3Statistics
* ssl3stats
= SSL_GetStatistics();
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
) {
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
);
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
);
172 char * ip
= CERT_NameToAscii(&cert
->issuer
);
173 char * sp
= CERT_NameToAscii(&cert
->subject
);
175 fprintf(stderr
, "subject DN: %s\n", sp
);
179 fprintf(stderr
, "issuer DN: %s\n", ip
);
182 CERT_DestroyCertificate(cert
);
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
);
193 handshakeCallback(PRFileDesc
*fd
, void *client_data
)
195 printSecurityInfo(fd
);
196 if (renegotiate
> 0) {
198 SSL_ReHandshake(fd
, PR_FALSE
);
202 static void Usage(const char *progName
)
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");
210 "%-20s Directory with cert database (default is ~/.netscape)\n",
212 fprintf(stderr
, "%-20s Nickname of key and cert for client auth\n",
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",
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"
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"
262 ":WXYZ Use cipher with hex code { 0xWX , 0xYZ } in TLS\n"
268 milliPause(PRUint32 milli
)
270 PRIntervalTime ticks
= PR_MillisecondsToInterval(milli
);
275 disableAllSSLCiphers(void)
277 const PRUint16
*cipherSuites
= SSL_ImplementedCiphers
;
278 int i
= SSL_NumImplementedCiphers
;
281 /* disable all the SSL3 cipher suites */
283 PRUint16 suite
= cipherSuites
[i
];
284 rv
= SSL_CipherPrefSetDefault(suite
, PR_FALSE
);
285 if (rv
!= SECSuccess
) {
286 PRErrorCode err
= PR_GetError();
288 "SSL_CipherPrefSet didn't like value 0x%04x (i = %d): %s\n",
289 suite
, i
, SECU_Strerror(err
));
296 * Callback is called when incoming certificate is not valid.
297 * Returns SECSuccess to accept the cert anyway, SECFailure to reject.
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
,
306 return SECSuccess
; /* override, say it's OK. */
310 own_GetClientAuthData(void * arg
,
312 struct CERTDistNamesStr
* caNames
,
313 struct CERTCertificateStr
** pRetCert
,
314 struct SECKEYPrivateKeyStr
**pRetKey
)
318 fprintf(stderr
, "Server requested Client Authentication\n");
319 if (caNames
&& caNames
->nnames
> 0) {
320 PLArenaPool
*arena
= caNames
->arena
;
322 arena
= PORT_NewArena(2048);
325 for (i
= 0; i
< caNames
->nnames
; ++i
) {
328 rv
= SEC_QuickDERDecodeItem(arena
,
330 SEC_ASN1_GET(CERT_NameTemplate
),
332 if (rv
!= SECSuccess
)
334 nameString
= CERT_NameToAscii(&dn
);
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
));
349 fprintf(stderr
, "sent cert: %s\n", nameString
);
350 PORT_Free(nameString
);
353 fprintf(stderr
, "send no cert\n");
357 return NSS_GetClientAuthData(arg
, socket
, caNames
, pRetCert
, pRetKey
);
360 #if defined(WIN32) || defined(OS2)
362 thread_main(void * arg
)
364 PRFileDesc
* ps
= (PRFileDesc
*)arg
;
365 PRFileDesc
* std_in
= PR_GetSpecialFD(PR_StandardInput
);
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
);
377 "%s: Cannot change stdin to binary mode. Use -i option instead.\n",
379 /* plow ahead anyway */
385 rc
= PR_Read(std_in
, buf
, sizeof buf
);
388 wc
= PR_Send(ps
, buf
, rc
, 0, maxInterval
);
396 printHostNameAndAddr(const char * host
, const PRNetAddr
* addr
)
398 PRUint16 port
= PR_NetAddrInetPort(addr
);
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.
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";
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
;
446 /* we are here only when nb == 1 && *ptrnMatched == 2 */
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
;
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.*/
469 for(i
= 1 ;i
< 3;i
++) {
476 bufPrt
= (char*)(buf
+ nb
- strSize
);
478 if (PL_strncmp(bufPrt
, ptrnStr
, strSize
) == 0) {
489 #define HEXCHAR_TO_INT(c, i) \
490 if (((c) >= '0') && ((c) <= '9')) { \
492 } else if (((c) >= 'a') && ((c) <= 'f')) { \
493 i = (c) - 'a' + 10; \
494 } else if (((c) >= 'A') && ((c) <= 'F')) { \
495 i = (c) - 'A' + 10; \
500 int main(int argc
, char **argv
)
503 PRFileDesc
* std_out
;
504 CERTCertDBHandle
* handle
;
506 char * certDir
= NULL
;
507 char * nickname
= NULL
;
508 char * cipherString
= NULL
;
519 int bypassPKCS11
= 0;
520 int disableLocking
= 0;
521 int useExportPolicy
= 0;
522 int enableSessionTickets
= 0;
523 PRSocketOptionData opt
;
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;
533 PRUint16 portno
= 443;
534 PLOptState
*optstate
;
535 PLOptStatus optstatus
;
538 progName
= strrchr(argv
[0], '/');
540 progName
= strrchr(argv
[0], '\\');
541 progName
= progName
? progName
+1 : argv
[0];
543 tmp
= PR_GetEnv("NSS_DEBUG_TIMEOUT");
545 int sec
= PORT_Atoi(tmp
);
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
) {
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;
576 multiplier
= atoi(optstate
->value
);
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;
598 password
= PORT_Strdup(optstate
->value
);
599 useCommandLinePassword
= PR_TRUE
;
602 case 'x': useExportPolicy
= 1; break;
606 PL_DestroyOptState(optstate
);
608 if (optstatus
== PL_OPT_BAD
)
611 if (!host
|| !portno
)
614 PR_Init( PR_SYSTEM_THREAD
, PR_PRIORITY_NORMAL
, 1);
616 /* set our password function */
617 if ( useCommandLinePassword
) {
618 PK11_SetPasswordFunc(ownPasswd
);
620 PK11_SetPasswordFunc(SECU_GetModulePassword
);
623 /* open the cert DB, the key DB, and the secmod DB. */
625 certDir
= SECU_DefaultSSLDir(); /* Look in $SSL_DIR */
626 certDir
= SECU_ConfigDirectory(certDir
);
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");
636 rv
= CERT_OpenVolatileCertDB(handle
);
637 CERT_SetDefaultCertDB(handle
);
642 handle
= CERT_GetDefaultCertDB();
644 /* set the policy bits true for all the cipher suites. */
646 NSS_SetExportPolicy();
648 NSS_SetDomesticPolicy();
650 /* all the SSL2 and SSL3 cipher suites are enabled by default. */
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
);
661 PRAddrInfo
*addrInfo
;
662 void *enumPtr
= NULL
;
664 addrInfo
= PR_GetAddrInfoByName(host
, PR_AF_UNSPEC
,
665 PR_AI_ADDRCONFIG
| PR_AI_NOCANONNAME
);
667 SECU_PrintError(progName
, "error looking up host");
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");
682 printHostNameAndAddr(host
, &addr
);
684 if (pingServerFirst
) {
688 s
= PR_OpenTCPSocket(addr
.raw
.family
);
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
) {
697 SECU_PrintError(progName
,
698 "Failed to set blocking socket option");
701 prStatus
= PR_Connect(s
, &addr
, PR_INTERVAL_NO_TIMEOUT
);
702 if (prStatus
== PR_SUCCESS
) {
703 PR_Shutdown(s
, PR_SHUTDOWN_BOTH
);
705 if (NSS_Shutdown() != SECSuccess
) {
712 if ((err
!= PR_CONNECT_REFUSED_ERROR
) &&
713 (err
!= PR_CONNECT_RESET_ERROR
)) {
714 SECU_PrintError(progName
, "TCP Connection failed");
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");
726 s
= PR_OpenTCPSocket(addr
.raw
.family
);
728 SECU_PrintError(progName
, "error creating socket");
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
);
739 SECU_PrintError(progName
, "error importing socket");
743 rv
= SSL_OptionSet(s
, SSL_SECURITY
, 1);
744 if (rv
!= SECSuccess
) {
745 SECU_PrintError(progName
, "error enabling socket");
749 rv
= SSL_OptionSet(s
, SSL_HANDSHAKE_AS_CLIENT
, 1);
750 if (rv
!= SECSuccess
) {
751 SECU_PrintError(progName
, "error enabling client handshake");
755 /* all the SSL2 and SSL3 cipher suites are enabled by default. */
757 char *cstringSaved
= cipherString
;
760 while (0 != (ndx
= *cipherString
++)) {
767 HEXCHAR_TO_INT(*cipherString
, ctmp
)
768 cipher
|= (ctmp
<< 12);
770 HEXCHAR_TO_INT(*cipherString
, ctmp
)
771 cipher
|= (ctmp
<< 8);
773 HEXCHAR_TO_INT(*cipherString
, ctmp
)
774 cipher
|= (ctmp
<< 4);
776 HEXCHAR_TO_INT(*cipherString
, ctmp
)
784 cptr
= islower(ndx
) ? ssl3CipherSuites
: ssl2CipherSuites
;
785 for (ndx
&= 0x1f; (cipher
= *cptr
++) != 0 && --ndx
> 0; )
790 status
= SSL_CipherPrefSet(s
, cipher
, SSL_ALLOWED
);
791 if (status
!= SECSuccess
)
792 SECU_PrintError(progName
, "SSL_CipherPrefSet()");
797 PORT_Free(cstringSaved
);
800 rv
= SSL_OptionSet(s
, SSL_ENABLE_SSL2
, !disableSSL2
);
801 if (rv
!= SECSuccess
) {
802 SECU_PrintError(progName
, "error enabling SSLv2 ");
806 rv
= SSL_OptionSet(s
, SSL_ENABLE_SSL3
, !disableSSL3
);
807 if (rv
!= SECSuccess
) {
808 SECU_PrintError(progName
, "error enabling SSLv3 ");
812 rv
= SSL_OptionSet(s
, SSL_ENABLE_TLS
, !disableTLS
);
813 if (rv
!= SECSuccess
) {
814 SECU_PrintError(progName
, "error enabling TLS ");
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");
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");
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");
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");
846 if (useCommandLinePassword
) {
847 SSL_SetPKCS11PinArg(s
, password
);
850 SSL_AuthCertificateHook(s
, SSL_AuthCertificate
, (void *)handle
);
852 SSL_BadCertHook(s
, ownBadCertHandler
, NULL
);
854 SSL_GetClientAuthDataHook(s
, own_GetClientAuthData
, (void *)nickname
);
855 SSL_HandshakeCallback(s
, handshakeCallback
, NULL
);
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
) {
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
;
870 "%s: about to call PR_Poll for connect completion!\n",
872 filesReady
= PR_Poll(pollset
, 1, PR_INTERVAL_NO_TIMEOUT
);
873 if (filesReady
< 0) {
874 SECU_PrintError(progName
, "unable to connect (poll)");
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
);
884 /* Must milliPause between PR_Poll and PR_GetConnectStatus,
885 * Or else winsock gets mighty confused.
889 status
= PR_GetConnectStatus(pollset
);
890 if (status
== PR_SUCCESS
) {
893 if (PR_GetError() != PR_IN_PROGRESS_ERROR
) {
894 SECU_PrintError(progName
, "unable to connect (poll)");
897 SECU_PrintError(progName
, "poll");
898 milliPause(50 * multiplier
);
901 SECU_PrintError(progName
, "unable to connect");
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
;
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
925 int nspr_rv
= PR_NewTCPSocketPair(fds
);
926 if (nspr_rv
!= PR_SUCCESS
) {
927 SECU_PrintError(progName
, "PR_NewTCPSocketPair failed");
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);
937 SECU_PrintError(progName
, "PR_CreateThread failed");
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");
964 if (filesReady
== 0) { /* shouldn't happen! */
965 FPRINTF(stderr
, "%s: PR_Poll returned zero!\n", progName
);
968 FPRINTF(stderr
, "%s: PR_Poll returned!\n", progName
);
969 if (pollset
[STDIN_FD
].in_flags
) {
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
) {
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
);
984 if (PR_GetError() != PR_WOULD_BLOCK_ERROR
) {
985 SECU_PrintError(progName
, "read from stdin failed");
989 } else if (nb
== 0) {
990 /* EOF on stdin, stop polling stdin for read. */
991 pollset
[STDIN_FD
].in_flags
= 0;
994 FPRINTF(stderr
, "%s: Writing %d bytes to server\n",
997 PRInt32 cc
= PR_Send(s
, bufp
, nb
, 0, maxInterval
);
999 PRErrorCode err
= PR_GetError();
1000 if (err
!= PR_WOULD_BLOCK_ERROR
) {
1001 SECU_PrintError(progName
,
1002 "write to SSL socket failed");
1012 pollset
[SSOCK_FD
].in_flags
= PR_POLL_WRITE
| PR_POLL_EXCEPT
;
1013 pollset
[SSOCK_FD
].out_flags
= 0;
1015 "%s: about to call PR_Poll on writable socket !\n",
1017 cc
= PR_Poll(pollset
, 1, PR_INTERVAL_NO_TIMEOUT
);
1019 "%s: PR_Poll returned with writable socket !\n",
1022 pollset
[SSOCK_FD
].in_flags
= PR_POLL_READ
;
1026 if (pollset
[SSOCK_FD
].in_flags
) {
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
)
1034 || (pollset
[SSOCK_FD
].out_flags
& PR_POLL_HUP
)
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
);
1041 if (PR_GetError() != PR_WOULD_BLOCK_ERROR
) {
1042 SECU_PrintError(progName
, "read from socket failed");
1046 } else if (nb
== 0) {
1047 /* EOF from socket... stop polling socket for read */
1048 pollset
[SSOCK_FD
].in_flags
= 0;
1050 if (skipProtoHeader
!= PR_TRUE
|| wrStarted
== PR_TRUE
) {
1051 PR_Write(std_out
, buf
, nb
);
1053 separateReqHeader(std_out
, buf
, nb
, &wrStarted
,
1054 &headerSeparatorPtrnId
);
1057 fputs("\n\n", stderr
);
1060 milliPause(50 * multiplier
);
1065 PORT_Free(nickname
);
1068 PORT_Free(password
);
1073 SSL_ClearSessionCache();
1074 if (NSS_Shutdown() != SECSuccess
) {