Import from 1.9a8 tarball
[mozilla-nss.git] / security / nss / cmd / vfyserv / vfyserv.c
blobf4da4e130a1cfd4c330f84c8014c00e9dc1c793f
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 * 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. *
41 * *
42 * This code was modified from the SSLSample code also kept in the NSS *
43 * directory. *
44 ****************************************************************************/
46 #include <stdio.h>
47 #include <string.h>
49 #if defined(XP_UNIX)
50 #include <unistd.h>
51 #endif
53 #include "prerror.h"
55 #include "pk11func.h"
56 #include "secmod.h"
57 #include "secitem.h"
60 #include <stdlib.h>
61 #include <errno.h>
62 #include <fcntl.h>
63 #include <stdarg.h>
65 #include "nspr.h"
66 #include "plgetopt.h"
67 #include "prio.h"
68 #include "prnetdb.h"
69 #include "nss.h"
70 #include "secutil.h"
71 #include "ocsp.h"
73 #include "vfyserv.h"
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;
85 PRBool dumpChain;
87 static void
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",
97 progName);
98 PR_fprintf (pr_stderr, "\nWhere:\n");
99 PR_fprintf (pr_stderr,
100 " %-13s dump server cert chain into files\n",
101 "-c");
102 PR_fprintf (pr_stderr,
103 " %-13s perform server cert OCSP check\n",
104 "-o");
105 PR_fprintf (pr_stderr,
106 " %-13s server port to be used\n",
107 "-p");
108 PR_fprintf (pr_stderr,
109 " %-13s use security databases in \"dbdir\"\n",
110 "-d dbdir");
111 PR_fprintf (pr_stderr,
112 " %-13s key database password\n",
113 "-w password");
114 PR_fprintf (pr_stderr,
115 " %-13s communication cipher list\n",
116 "-C cipher(s)");
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",
125 "-t nickname");
127 exit(1);
130 PRFileDesc *
131 setupSSLSocket(PRNetAddr *addr)
133 PRFileDesc *tcpSocket;
134 PRFileDesc *sslSocket;
135 PRSocketOptionData socketOption;
136 PRStatus prStatus;
137 SECStatus secStatus;
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");
152 goto loser;
156 /* Import the socket into the SSL layer. */
157 sslSocket = SSL_ImportFD(NULL, tcpSocket);
158 if (!sslSocket) {
159 errWarn("SSL_ImportFD");
160 goto loser;
163 /* Set configuration options. */
164 secStatus = SSL_OptionSet(sslSocket, SSL_SECURITY, PR_TRUE);
165 if (secStatus != SECSuccess) {
166 errWarn("SSL_OptionSet:SSL_SECURITY");
167 goto loser;
170 secStatus = SSL_OptionSet(sslSocket, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE);
171 if (secStatus != SECSuccess) {
172 errWarn("SSL_OptionSet:SSL_HANDSHAKE_AS_CLIENT");
173 goto loser;
176 /* Set SSL callback routines. */
177 secStatus = SSL_GetClientAuthDataHook(sslSocket,
178 (SSLGetClientAuthData)myGetClientAuthData,
179 (void *)certNickname);
180 if (secStatus != SECSuccess) {
181 errWarn("SSL_GetClientAuthDataHook");
182 goto loser;
185 secStatus = SSL_AuthCertificateHook(sslSocket,
186 (SSLAuthCertificate)myAuthCertificate,
187 (void *)CERT_GetDefaultCertDB());
188 if (secStatus != SECSuccess) {
189 errWarn("SSL_AuthCertificateHook");
190 goto loser;
193 secStatus = SSL_BadCertHook(sslSocket,
194 (SSLBadCertHandler)myBadCertHandler, NULL);
195 if (secStatus != SECSuccess) {
196 errWarn("SSL_BadCertHook");
197 goto loser;
200 secStatus = SSL_HandshakeCallback(sslSocket,
201 (SSLHandshakeCallback)myHandshakeCallback,
202 NULL);
203 if (secStatus != SECSuccess) {
204 errWarn("SSL_HandshakeCallback");
205 goto loser;
208 return sslSocket;
210 loser:
212 PR_Close(tcpSocket);
213 return NULL;
217 const char requestString[] = {"GET /testfile HTTP/1.0\r\n\r\n" };
219 SECStatus
220 handle_connection(PRFileDesc *sslSocket, int connection)
222 int countRead = 0;
223 PRInt32 numBytes;
224 char *readBuffer;
226 readBuffer = PORT_Alloc(RD_BUF_SIZE);
227 if (!readBuffer) {
228 exitErr("PORT_Alloc");
231 /* compose the http request here. */
233 numBytes = PR_Write(sslSocket, requestString, strlen(requestString));
234 if (numBytes <= 0) {
235 errWarn("PR_Write");
236 PR_Free(readBuffer);
237 readBuffer = NULL;
238 return SECFailure;
241 /* read until EOF */
242 while (PR_TRUE) {
243 numBytes = PR_Read(sslSocket, readBuffer, RD_BUF_SIZE);
244 if (numBytes == 0) {
245 break; /* EOF */
247 if (numBytes < 0) {
248 errWarn("PR_Read");
249 break;
251 countRead += numBytes;
254 printSecurityInfo(stderr, sslSocket);
256 PR_Free(readBuffer);
257 readBuffer = NULL;
259 /* Caller closes the socket. */
261 fprintf(stderr,
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.
273 SECStatus
274 do_connects(void *a, int connection)
276 PRNetAddr *addr = (PRNetAddr *)a;
277 PRFileDesc *sslSocket;
278 PRHostEnt hostEntry;
279 char buffer[PR_NETDB_BUF_SIZE];
280 PRStatus prStatus;
281 PRIntn hostenum;
282 PRInt32 ip;
283 SECStatus secStatus;
285 /* Set up SSL secure socket. */
286 sslSocket = setupSSLSocket(addr);
287 if (sslSocket == NULL) {
288 errWarn("setupSSLSocket");
289 return SECFailure;
292 secStatus = SSL_SetPKCS11PinArg(sslSocket, password);
293 if (secStatus != SECSuccess) {
294 errWarn("SSL_SetPKCS11PinArg");
295 return secStatus;
298 secStatus = SSL_SetURL(sslSocket, hostName);
299 if (secStatus != SECSuccess) {
300 errWarn("SSL_SetURL");
301 return secStatus;
304 /* Prepare and setup network connection. */
305 prStatus = PR_GetHostByName(hostName, buffer, sizeof(buffer), &hostEntry);
306 if (prStatus != PR_SUCCESS) {
307 errWarn("PR_GetHostByName");
308 return SECFailure;
311 hostenum = PR_EnumerateHostEnt(0, &hostEntry, port, addr);
312 if (hostenum == -1) {
313 errWarn("PR_EnumerateHostEnt");
314 return SECFailure;
317 ip = PR_ntohl(addr->inet.ip);
318 fprintf(stderr,
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");
326 return SECFailure;
329 /* Established SSL connection, ready to send data. */
330 #if 0
331 secStatus = SSL_ForceHandshake(sslSocket);
332 if (secStatus != SECSuccess) {
333 errWarn("SSL_ForceHandshake");
334 return secStatus;
336 #endif
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) {
343 errWarn("PR_Close");
345 return secStatus;
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) {
354 errWarn("PR_Close");
356 return secStatus;
359 PR_Close(sslSocket);
360 return SECSuccess;
363 void
364 client_main(unsigned short port,
365 int connections,
366 const char * hostName)
368 int i;
369 SECStatus secStatus;
370 PRStatus prStatus;
371 PRInt32 rv;
372 PRNetAddr addr;
373 PRHostEnt hostEntry;
374 char buffer[256];
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);
383 if (rv < 0) {
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')) { \
410 i = (c) - '0'; \
411 } else if (((c) >= 'a') && ((c) <= 'f')) { \
412 i = (c) - 'a' + 10; \
413 } else if (((c) >= 'A') && ((c) <= 'F')) { \
414 i = (c) - 'A' + 10; \
415 } else { \
416 Usage(progName); \
420 main(int argc, char **argv)
422 char * certDir = NULL;
423 char * progName = NULL;
424 int connections = 1;
425 char * cipherString = NULL;
426 char * respUrl = NULL;
427 char * respCertName = NULL;
428 SECStatus secStatus;
429 PLOptState * optstate;
430 PLOptStatus status;
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]);
438 hostName = NULL;
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);
455 if (port == 0) {
456 port = 443;
459 if (port == 0 || hostName == NULL)
460 Usage(progName);
462 if (doOcspCheck &&
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");
467 Usage(progName);
470 /* Set our password function callback. */
471 PK11_SetPasswordFunc(myPasswd);
473 /* Initialize the NSS libraries. */
474 if (certDir) {
475 secStatus = NSS_Init(certDir);
476 } else {
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) {
484 exitErr("NSS_Init");
486 SECU_RegisterDynamicOids();
488 if (doOcspCheck == PR_TRUE) {
489 SECStatus rv;
490 CERTCertDBHandle *handle = CERT_GetDefaultCertDB();
491 if (handle == NULL) {
492 SECU_PrintError (progName, "problem getting certdb handle");
493 goto cleanup;
496 rv = CERT_EnableOCSPChecking (handle);
497 if (rv != SECSuccess) {
498 SECU_PrintError (progName, "error enabling OCSP checking");
499 goto cleanup;
502 if (respUrl != NULL) {
503 rv = CERT_SetOCSPDefaultResponder (handle, respUrl,
504 respCertName);
505 if (rv != SECSuccess) {
506 SECU_PrintError (progName,
507 "error setting default responder");
508 goto cleanup;
511 rv = CERT_EnableOCSPDefaultResponder (handle);
512 if (rv != SECSuccess) {
513 SECU_PrintError (progName,
514 "error enabling default responder");
515 goto cleanup;
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. */
526 if (cipherString) {
527 int ndx;
529 /* disable all the ciphers, then enable the ones we want. */
530 disableAllSSLCiphers();
532 while (0 != (ndx = *cipherString++)) {
533 int cipher;
535 if (ndx == ':') {
536 int ctmp;
538 cipher = 0;
539 HEXCHAR_TO_INT(*cipherString, ctmp)
540 cipher |= (ctmp << 12);
541 cipherString++;
542 HEXCHAR_TO_INT(*cipherString, ctmp)
543 cipher |= (ctmp << 8);
544 cipherString++;
545 HEXCHAR_TO_INT(*cipherString, ctmp)
546 cipher |= (ctmp << 4);
547 cipherString++;
548 HEXCHAR_TO_INT(*cipherString, ctmp)
549 cipher |= ctmp;
550 cipherString++;
551 } else {
552 const int *cptr;
553 if (! isalpha(ndx))
554 Usage(progName);
555 cptr = islower(ndx) ? ssl3CipherSuites : ssl2CipherSuites;
556 for (ndx &= 0x1f; (cipher = *cptr++) != 0 && --ndx > 0; )
557 /* do nothing */;
559 if (cipher > 0) {
560 SSL_CipherPrefSetDefault(cipher, PR_TRUE);
561 } else {
562 Usage(progName);
567 client_main(port, connections, hostName);
569 cleanup:
570 if (doOcspCheck) {
571 CERTCertDBHandle *handle = CERT_GetDefaultCertDB();
572 CERT_DisableOCSPDefaultResponder(handle);
573 CERT_DisableOCSPChecking (handle);
576 if (NSS_Shutdown() != SECSuccess) {
577 exit(1);
580 PR_Cleanup();
581 PORT_Free(progName);
582 return 0;