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 * Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
24 * Alternatively, the contents of this file may be used under the terms of
25 * either the GNU General Public License Version 2 or later (the "GPL"), or
26 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
38 /****************************************************************************
39 * SSL client program that tests a server for proper operation of SSL2, *
40 * SSL3, and TLS. Test propder certificate installation. *
42 * This code was modified from the SSLSample code also kept in the NSS *
44 ****************************************************************************/
75 #define RD_BUF_SIZE (60 * 1024)
77 extern int ssl2CipherSuites
[];
78 extern int ssl3CipherSuites
[];
80 GlobalThreadMgr threadMGR
;
81 char *certNickname
= NULL
;
82 char *hostName
= NULL
;
83 char *password
= NULL
;
84 unsigned short port
= 0;
88 Usage(const char *progName
)
90 PRFileDesc
*pr_stderr
;
92 pr_stderr
= PR_STDERR
;
94 PR_fprintf(pr_stderr
, "Usage:\n"
95 " %s [-c ] [-o] [-p port] [-d dbdir] [-w password]\n"
96 " \t\t[-C cipher(s)] [-l <url> -t <nickname> ] hostname",
98 PR_fprintf (pr_stderr
, "\nWhere:\n");
99 PR_fprintf (pr_stderr
,
100 " %-13s dump server cert chain into files\n",
102 PR_fprintf (pr_stderr
,
103 " %-13s perform server cert OCSP check\n",
105 PR_fprintf (pr_stderr
,
106 " %-13s server port to be used\n",
108 PR_fprintf (pr_stderr
,
109 " %-13s use security databases in \"dbdir\"\n",
111 PR_fprintf (pr_stderr
,
112 " %-13s key database password\n",
114 PR_fprintf (pr_stderr
,
115 " %-13s communication cipher list\n",
117 PR_fprintf (pr_stderr
,
118 " %-13s OCSP responder location. This location is used to\n"
119 " %-13s check status of a server certificate. If not \n"
120 " %-13s specified, location will be taken from the AIA\n"
121 " %-13s server certificate extension.\n",
122 "-l url", "", "", "");
123 PR_fprintf (pr_stderr
,
124 " %-13s OCSP Trusted Responder Cert nickname\n\n",
131 setupSSLSocket(PRNetAddr
*addr
)
133 PRFileDesc
*tcpSocket
;
134 PRFileDesc
*sslSocket
;
135 PRSocketOptionData socketOption
;
140 tcpSocket
= PR_NewTCPSocket();
141 if (tcpSocket
== NULL
) {
142 errWarn("PR_NewTCPSocket");
145 /* Make the socket blocking. */
146 socketOption
.option
= PR_SockOpt_Nonblocking
;
147 socketOption
.value
.non_blocking
= PR_FALSE
;
149 prStatus
= PR_SetSocketOption(tcpSocket
, &socketOption
);
150 if (prStatus
!= PR_SUCCESS
) {
151 errWarn("PR_SetSocketOption");
156 /* Import the socket into the SSL layer. */
157 sslSocket
= SSL_ImportFD(NULL
, tcpSocket
);
159 errWarn("SSL_ImportFD");
163 /* Set configuration options. */
164 secStatus
= SSL_OptionSet(sslSocket
, SSL_SECURITY
, PR_TRUE
);
165 if (secStatus
!= SECSuccess
) {
166 errWarn("SSL_OptionSet:SSL_SECURITY");
170 secStatus
= SSL_OptionSet(sslSocket
, SSL_HANDSHAKE_AS_CLIENT
, PR_TRUE
);
171 if (secStatus
!= SECSuccess
) {
172 errWarn("SSL_OptionSet:SSL_HANDSHAKE_AS_CLIENT");
176 /* Set SSL callback routines. */
177 secStatus
= SSL_GetClientAuthDataHook(sslSocket
,
178 (SSLGetClientAuthData
)myGetClientAuthData
,
179 (void *)certNickname
);
180 if (secStatus
!= SECSuccess
) {
181 errWarn("SSL_GetClientAuthDataHook");
185 secStatus
= SSL_AuthCertificateHook(sslSocket
,
186 (SSLAuthCertificate
)myAuthCertificate
,
187 (void *)CERT_GetDefaultCertDB());
188 if (secStatus
!= SECSuccess
) {
189 errWarn("SSL_AuthCertificateHook");
193 secStatus
= SSL_BadCertHook(sslSocket
,
194 (SSLBadCertHandler
)myBadCertHandler
, NULL
);
195 if (secStatus
!= SECSuccess
) {
196 errWarn("SSL_BadCertHook");
200 secStatus
= SSL_HandshakeCallback(sslSocket
,
201 (SSLHandshakeCallback
)myHandshakeCallback
,
203 if (secStatus
!= SECSuccess
) {
204 errWarn("SSL_HandshakeCallback");
217 const char requestString
[] = {"GET /testfile HTTP/1.0\r\n\r\n" };
220 handle_connection(PRFileDesc
*sslSocket
, int connection
)
226 readBuffer
= PORT_Alloc(RD_BUF_SIZE
);
228 exitErr("PORT_Alloc");
231 /* compose the http request here. */
233 numBytes
= PR_Write(sslSocket
, requestString
, strlen(requestString
));
243 numBytes
= PR_Read(sslSocket
, readBuffer
, RD_BUF_SIZE
);
251 countRead
+= numBytes
;
254 printSecurityInfo(stderr
, sslSocket
);
259 /* Caller closes the socket. */
262 "***** Connection %d read %d bytes total.\n",
263 connection
, countRead
);
265 return SECSuccess
; /* success */
268 #define BYTE(n,i) (((i)>>((n)*8))&0xff)
270 /* one copy of this function is launched in a separate thread for each
271 ** connection to be made.
274 do_connects(void *a
, int connection
)
276 PRNetAddr
*addr
= (PRNetAddr
*)a
;
277 PRFileDesc
*sslSocket
;
279 char buffer
[PR_NETDB_BUF_SIZE
];
285 /* Set up SSL secure socket. */
286 sslSocket
= setupSSLSocket(addr
);
287 if (sslSocket
== NULL
) {
288 errWarn("setupSSLSocket");
292 secStatus
= SSL_SetPKCS11PinArg(sslSocket
, password
);
293 if (secStatus
!= SECSuccess
) {
294 errWarn("SSL_SetPKCS11PinArg");
298 secStatus
= SSL_SetURL(sslSocket
, hostName
);
299 if (secStatus
!= SECSuccess
) {
300 errWarn("SSL_SetURL");
304 /* Prepare and setup network connection. */
305 prStatus
= PR_GetHostByName(hostName
, buffer
, sizeof(buffer
), &hostEntry
);
306 if (prStatus
!= PR_SUCCESS
) {
307 errWarn("PR_GetHostByName");
311 hostenum
= PR_EnumerateHostEnt(0, &hostEntry
, port
, addr
);
312 if (hostenum
== -1) {
313 errWarn("PR_EnumerateHostEnt");
317 ip
= PR_ntohl(addr
->inet
.ip
);
319 "Connecting to host %s (addr %d.%d.%d.%d) on port %d\n",
320 hostName
, BYTE(3,ip
), BYTE(2,ip
), BYTE(1,ip
),
321 BYTE(0,ip
), PR_ntohs(addr
->inet
.port
));
323 prStatus
= PR_Connect(sslSocket
, addr
, PR_INTERVAL_NO_TIMEOUT
);
324 if (prStatus
!= PR_SUCCESS
) {
325 errWarn("PR_Connect");
329 /* Established SSL connection, ready to send data. */
331 secStatus
= SSL_ForceHandshake(sslSocket
);
332 if (secStatus
!= SECSuccess
) {
333 errWarn("SSL_ForceHandshake");
338 secStatus
= SSL_ResetHandshake(sslSocket
, /* asServer */ PR_FALSE
);
339 if (secStatus
!= SECSuccess
) {
340 errWarn("SSL_ResetHandshake");
341 prStatus
= PR_Close(sslSocket
);
342 if (prStatus
!= PR_SUCCESS
) {
348 secStatus
= handle_connection(sslSocket
, connection
);
349 if (secStatus
!= SECSuccess
) {
350 /* error already printed out in handle_connection */
351 /* errWarn("handle_connection"); */
352 prStatus
= PR_Close(sslSocket
);
353 if (prStatus
!= PR_SUCCESS
) {
364 client_main(unsigned short port
,
366 const char * hostName
)
376 /* Setup network connection. */
377 prStatus
= PR_GetHostByName(hostName
, buffer
, 256, &hostEntry
);
378 if (prStatus
!= PR_SUCCESS
) {
379 exitErr("PR_GetHostByName");
382 rv
= PR_EnumerateHostEnt(0, &hostEntry
, port
, &addr
);
384 exitErr("PR_EnumerateHostEnt");
387 secStatus
= launch_thread(&threadMGR
, do_connects
, &addr
, 1);
388 if (secStatus
!= SECSuccess
) {
389 exitErr("launch_thread");
392 if (connections
> 1) {
393 /* wait for the first connection to terminate, then launch the rest. */
394 reap_threads(&threadMGR
);
395 /* Start up the connections */
396 for (i
= 2; i
<= connections
; ++i
) {
397 secStatus
= launch_thread(&threadMGR
, do_connects
, &addr
, i
);
398 if (secStatus
!= SECSuccess
) {
399 errWarn("launch_thread");
404 reap_threads(&threadMGR
);
405 destroy_thread_data(&threadMGR
);
408 #define HEXCHAR_TO_INT(c, i) \
409 if (((c) >= '0') && ((c) <= '9')) { \
411 } else if (((c) >= 'a') && ((c) <= 'f')) { \
412 i = (c) - 'a' + 10; \
413 } else if (((c) >= 'A') && ((c) <= 'F')) { \
414 i = (c) - 'A' + 10; \
420 main(int argc
, char **argv
)
422 char * certDir
= NULL
;
423 char * progName
= NULL
;
425 char * cipherString
= NULL
;
426 char * respUrl
= NULL
;
427 char * respCertName
= NULL
;
429 PLOptState
* optstate
;
431 PRBool doOcspCheck
= PR_FALSE
;
433 /* Call the NSPR initialization routines */
434 PR_Init( PR_SYSTEM_THREAD
, PR_PRIORITY_NORMAL
, 1);
436 progName
= PORT_Strdup(argv
[0]);
439 optstate
= PL_CreateOptState(argc
, argv
, "C:cd:l:n:p:ot:w:");
440 while ((status
= PL_GetNextOpt(optstate
)) == PL_OPT_OK
) {
441 switch(optstate
->option
) {
442 case 'C' : cipherString
= PL_strdup(optstate
->value
); break;
443 case 'c' : dumpChain
= PR_TRUE
; break;
444 case 'd' : certDir
= PL_strdup(optstate
->value
); break;
445 case 'l' : respUrl
= PL_strdup(optstate
->value
); break;
446 case 'p' : port
= PORT_Atoi(optstate
->value
); break;
447 case 'o' : doOcspCheck
= PR_TRUE
; break;
448 case 't' : respCertName
= PL_strdup(optstate
->value
); break;
449 case 'w' : password
= PL_strdup(optstate
->value
); break;
450 case '\0': hostName
= PL_strdup(optstate
->value
); break;
451 default : Usage(progName
);
459 if (port
== 0 || hostName
== NULL
)
463 ((respCertName
!= NULL
&& respUrl
== NULL
) ||
464 (respUrl
!= NULL
&& respCertName
== NULL
))) {
465 SECU_PrintError (progName
, "options -l <url> and -t "
466 "<responder> must be used together");
470 /* Set our password function callback. */
471 PK11_SetPasswordFunc(myPasswd
);
473 /* Initialize the NSS libraries. */
475 secStatus
= NSS_Init(certDir
);
477 secStatus
= NSS_NoDB_Init(NULL
);
479 /* load the builtins */
480 SECMOD_AddNewModule("Builtins",
481 DLL_PREFIX
"nssckbi."DLL_SUFFIX
, 0, 0);
483 if (secStatus
!= SECSuccess
) {
486 SECU_RegisterDynamicOids();
488 if (doOcspCheck
== PR_TRUE
) {
490 CERTCertDBHandle
*handle
= CERT_GetDefaultCertDB();
491 if (handle
== NULL
) {
492 SECU_PrintError (progName
, "problem getting certdb handle");
496 rv
= CERT_EnableOCSPChecking (handle
);
497 if (rv
!= SECSuccess
) {
498 SECU_PrintError (progName
, "error enabling OCSP checking");
502 if (respUrl
!= NULL
) {
503 rv
= CERT_SetOCSPDefaultResponder (handle
, respUrl
,
505 if (rv
!= SECSuccess
) {
506 SECU_PrintError (progName
,
507 "error setting default responder");
511 rv
= CERT_EnableOCSPDefaultResponder (handle
);
512 if (rv
!= SECSuccess
) {
513 SECU_PrintError (progName
,
514 "error enabling default responder");
520 /* All cipher suites except RSA_NULL_MD5 are enabled by
521 * Domestic Policy. */
522 NSS_SetDomesticPolicy();
523 SSL_CipherPrefSetDefault(SSL_RSA_WITH_NULL_MD5
, PR_TRUE
);
525 /* all the SSL2 and SSL3 cipher suites are enabled by default. */
529 /* disable all the ciphers, then enable the ones we want. */
530 disableAllSSLCiphers();
532 while (0 != (ndx
= *cipherString
++)) {
539 HEXCHAR_TO_INT(*cipherString
, ctmp
)
540 cipher
|= (ctmp
<< 12);
542 HEXCHAR_TO_INT(*cipherString
, ctmp
)
543 cipher
|= (ctmp
<< 8);
545 HEXCHAR_TO_INT(*cipherString
, ctmp
)
546 cipher
|= (ctmp
<< 4);
548 HEXCHAR_TO_INT(*cipherString
, ctmp
)
555 cptr
= islower(ndx
) ? ssl3CipherSuites
: ssl2CipherSuites
;
556 for (ndx
&= 0x1f; (cipher
= *cptr
++) != 0 && --ndx
> 0; )
560 SSL_CipherPrefSetDefault(cipher
, PR_TRUE
);
567 client_main(port
, connections
, hostName
);
571 CERTCertDBHandle
*handle
= CERT_GetDefaultCertDB();
572 CERT_DisableOCSPDefaultResponder(handle
);
573 CERT_DisableOCSPChecking (handle
);
576 if (NSS_Shutdown() != SECSuccess
) {