Imported Upstream version 3.13.6
[platform/upstream/nss.git] / mozilla / security / nss / cmd / vfyserv / vfyserv.c
1 /* ***** BEGIN LICENSE BLOCK *****
2  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3  *
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/
8  *
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.
13  *
14  * The Original Code is the Netscape security libraries.
15  *
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.
20  *
21  * Contributor(s):
22  *   Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
23  *
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.
35  *
36  * ***** END LICENSE BLOCK ***** */
37
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  ****************************************************************************/ 
45
46 #include <stdio.h>
47 #include <string.h>
48
49 #if defined(XP_UNIX)
50 #include <unistd.h>
51 #endif
52
53 #include "prerror.h"
54
55 #include "pk11func.h"
56 #include "secmod.h"
57 #include "secitem.h"
58
59
60 #include <stdlib.h>
61 #include <errno.h>
62 #include <fcntl.h>
63 #include <stdarg.h>
64
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"
72
73 #include "vfyserv.h"
74
75 #define RD_BUF_SIZE (60 * 1024)
76
77 extern int ssl2CipherSuites[];
78 extern int ssl3CipherSuites[];
79
80 GlobalThreadMgr threadMGR;
81 char *certNickname = NULL;
82 char *hostName = NULL;
83 secuPWData  pwdata          = { PW_NONE, 0 };
84 unsigned short port = 0;
85 PRBool dumpChain;
86
87 static void
88 Usage(const char *progName)
89 {
90     PRFileDesc *pr_stderr;
91
92     pr_stderr = PR_STDERR;
93
94     PR_fprintf(pr_stderr, "Usage:\n"
95                "   %s  [-c ] [-o] [-p port] [-d dbdir] [-w password] [-f pwfile]\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 token password file\n",
116                 "-f pwfile");
117     PR_fprintf (pr_stderr,
118                 "  %-13s communication cipher list\n",
119                 "-C cipher(s)");
120     PR_fprintf (pr_stderr,
121                 "  %-13s OCSP responder location. This location is used to\n"
122                 "  %-13s check  status  of a server  certificate.  If  not \n"
123                 "  %-13s specified, location  will  be taken  from the AIA\n"
124                 "  %-13s server certificate extension.\n",
125                 "-l url", "", "", "");
126     PR_fprintf (pr_stderr,
127                 "  %-13s OCSP Trusted Responder Cert nickname\n\n",
128                 "-t nickname");
129
130         exit(1);
131 }
132
133 PRFileDesc *
134 setupSSLSocket(PRNetAddr *addr)
135 {
136         PRFileDesc         *tcpSocket;
137         PRFileDesc         *sslSocket;
138         PRSocketOptionData      socketOption;
139         PRStatus            prStatus;
140         SECStatus           secStatus;
141
142
143         tcpSocket = PR_NewTCPSocket();
144         if (tcpSocket == NULL) {
145                 errWarn("PR_NewTCPSocket");
146         }
147
148         /* Make the socket blocking. */
149         socketOption.option                 = PR_SockOpt_Nonblocking;
150         socketOption.value.non_blocking = PR_FALSE;
151
152         prStatus = PR_SetSocketOption(tcpSocket, &socketOption);
153         if (prStatus != PR_SUCCESS) {
154                 errWarn("PR_SetSocketOption");
155                 goto loser;
156         } 
157
158
159         /* Import the socket into the SSL layer. */
160         sslSocket = SSL_ImportFD(NULL, tcpSocket);
161         if (!sslSocket) {
162                 errWarn("SSL_ImportFD");
163                 goto loser;
164         }
165
166         /* Set configuration options. */
167         secStatus = SSL_OptionSet(sslSocket, SSL_SECURITY, PR_TRUE);
168         if (secStatus != SECSuccess) {
169                 errWarn("SSL_OptionSet:SSL_SECURITY");
170                 goto loser;
171         }
172
173         secStatus = SSL_OptionSet(sslSocket, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE);
174         if (secStatus != SECSuccess) {
175                 errWarn("SSL_OptionSet:SSL_HANDSHAKE_AS_CLIENT");
176                 goto loser;
177         }
178
179         /* Set SSL callback routines. */
180         secStatus = SSL_GetClientAuthDataHook(sslSocket,
181                                   (SSLGetClientAuthData)myGetClientAuthData,
182                                   (void *)certNickname);
183         if (secStatus != SECSuccess) {
184                 errWarn("SSL_GetClientAuthDataHook");
185                 goto loser;
186         }
187
188         secStatus = SSL_AuthCertificateHook(sslSocket,
189                                            (SSLAuthCertificate)myAuthCertificate,
190                                        (void *)CERT_GetDefaultCertDB());
191         if (secStatus != SECSuccess) {
192                 errWarn("SSL_AuthCertificateHook");
193                 goto loser;
194         }
195
196         secStatus = SSL_BadCertHook(sslSocket, 
197                                    (SSLBadCertHandler)myBadCertHandler, NULL);
198         if (secStatus != SECSuccess) {
199                 errWarn("SSL_BadCertHook");
200                 goto loser;
201         }
202
203         secStatus = SSL_HandshakeCallback(sslSocket, 
204                                           myHandshakeCallback,
205                                           NULL);
206         if (secStatus != SECSuccess) {
207                 errWarn("SSL_HandshakeCallback");
208                 goto loser;
209         }
210
211         return sslSocket;
212
213 loser:
214
215         PR_Close(tcpSocket);
216         return NULL;
217 }
218
219
220 const char requestString[] = {"GET /testfile HTTP/1.0\r\n\r\n" };
221
222 SECStatus
223 handle_connection(PRFileDesc *sslSocket, int connection)
224 {
225         int     countRead = 0;
226         PRInt32  numBytes;
227         char    *readBuffer;
228
229         readBuffer = PORT_Alloc(RD_BUF_SIZE);
230         if (!readBuffer) {
231                 exitErr("PORT_Alloc");
232         }
233
234         /* compose the http request here. */
235
236         numBytes = PR_Write(sslSocket, requestString, strlen(requestString));
237         if (numBytes <= 0) {
238                 errWarn("PR_Write");
239                 PR_Free(readBuffer);
240                 readBuffer = NULL;
241                 return SECFailure;
242         }
243
244         /* read until EOF */
245         while (PR_TRUE) {
246                 numBytes = PR_Read(sslSocket, readBuffer, RD_BUF_SIZE);
247                 if (numBytes == 0) {
248                         break;  /* EOF */
249                 }
250                 if (numBytes < 0) {
251                         errWarn("PR_Read");
252                         break;
253                 }
254                 countRead += numBytes;
255         }
256
257         printSecurityInfo(stderr, sslSocket);
258         
259         PR_Free(readBuffer);
260         readBuffer = NULL;
261
262         /* Caller closes the socket. */
263
264         fprintf(stderr, 
265                 "***** Connection %d read %d bytes total.\n", 
266                 connection, countRead);
267
268         return SECSuccess;      /* success */
269 }
270
271 #define BYTE(n,i) (((i)>>((n)*8))&0xff)
272
273 /* one copy of this function is launched in a separate thread for each
274 ** connection to be made.
275 */
276 SECStatus
277 do_connects(void *a, int connection)
278 {
279         PRNetAddr  *addr = (PRNetAddr *)a;
280         PRFileDesc *sslSocket;
281         PRHostEnt   hostEntry;
282         char        buffer[PR_NETDB_BUF_SIZE];
283         PRStatus    prStatus;
284         PRIntn      hostenum;
285         PRInt32    ip;
286         SECStatus   secStatus;
287
288         /* Set up SSL secure socket. */
289         sslSocket = setupSSLSocket(addr);
290         if (sslSocket == NULL) {
291                 errWarn("setupSSLSocket");
292                 return SECFailure;
293         }
294
295         secStatus = SSL_SetPKCS11PinArg(sslSocket, &pwdata);
296         if (secStatus != SECSuccess) {
297                 errWarn("SSL_SetPKCS11PinArg");
298                 return secStatus;
299         }
300
301         secStatus = SSL_SetURL(sslSocket, hostName);
302         if (secStatus != SECSuccess) {
303                 errWarn("SSL_SetURL");
304                 return secStatus;
305         }
306
307         /* Prepare and setup network connection. */
308         prStatus = PR_GetHostByName(hostName, buffer, sizeof(buffer), &hostEntry);
309         if (prStatus != PR_SUCCESS) {
310                 errWarn("PR_GetHostByName");
311                 return SECFailure;
312         }
313
314         hostenum = PR_EnumerateHostEnt(0, &hostEntry, port, addr);
315         if (hostenum == -1) {
316                 errWarn("PR_EnumerateHostEnt");
317                 return SECFailure;
318         }
319
320         ip = PR_ntohl(addr->inet.ip);
321         fprintf(stderr,
322                 "Connecting to host %s (addr %d.%d.%d.%d) on port %d\n",
323                         hostName, BYTE(3,ip), BYTE(2,ip), BYTE(1,ip), 
324                         BYTE(0,ip), PR_ntohs(addr->inet.port)); 
325
326         prStatus = PR_Connect(sslSocket, addr, PR_INTERVAL_NO_TIMEOUT);
327         if (prStatus != PR_SUCCESS) {
328                 errWarn("PR_Connect");
329                 return SECFailure;
330         }
331
332         /* Established SSL connection, ready to send data. */
333 #if 0
334         secStatus = SSL_ForceHandshake(sslSocket);
335         if (secStatus != SECSuccess) {
336                 errWarn("SSL_ForceHandshake");
337                 return secStatus;
338         }
339 #endif
340
341         secStatus = SSL_ResetHandshake(sslSocket, /* asServer */ PR_FALSE);
342         if (secStatus != SECSuccess) {
343                 errWarn("SSL_ResetHandshake");
344                 prStatus = PR_Close(sslSocket);
345                 if (prStatus != PR_SUCCESS) {
346                         errWarn("PR_Close");
347                 }
348                 return secStatus;
349         }
350
351         secStatus = handle_connection(sslSocket, connection);
352         if (secStatus != SECSuccess) {
353                 /* error already printed out in handle_connection */
354                 /* errWarn("handle_connection"); */
355                 prStatus = PR_Close(sslSocket);
356                 if (prStatus != PR_SUCCESS) {
357                         errWarn("PR_Close");
358                 }
359                 return secStatus;
360         }
361
362         PR_Close(sslSocket);
363         return SECSuccess;
364 }
365
366 void
367 client_main(unsigned short      port, 
368             int                 connections, 
369             const char *        hostName)
370 {
371         int                     i;
372         SECStatus       secStatus;
373         PRStatus    prStatus;
374         PRInt32     rv;
375         PRNetAddr       addr;
376         PRHostEnt   hostEntry;
377         char        buffer[PR_NETDB_BUF_SIZE];
378
379         /* Setup network connection. */
380         prStatus = PR_GetHostByName(hostName, buffer, sizeof(buffer), &hostEntry);
381         if (prStatus != PR_SUCCESS) {
382                 exitErr("PR_GetHostByName");
383         }
384
385         rv = PR_EnumerateHostEnt(0, &hostEntry, port, &addr);
386         if (rv < 0) {
387                 exitErr("PR_EnumerateHostEnt");
388         }
389
390         secStatus = launch_thread(&threadMGR, do_connects, &addr, 1);
391         if (secStatus != SECSuccess) {
392                 exitErr("launch_thread");
393         }
394
395         if (connections > 1) {
396                 /* wait for the first connection to terminate, then launch the rest. */
397                 reap_threads(&threadMGR);
398                 /* Start up the connections */
399                 for (i = 2; i <= connections; ++i) {
400                         secStatus = launch_thread(&threadMGR, do_connects, &addr, i);
401                         if (secStatus != SECSuccess) {
402                                 errWarn("launch_thread");
403                         }
404                 }
405         }
406
407         reap_threads(&threadMGR);
408         destroy_thread_data(&threadMGR);
409 }
410
411 #define HEXCHAR_TO_INT(c, i) \
412     if (((c) >= '0') && ((c) <= '9')) { \
413         i = (c) - '0'; \
414     } else if (((c) >= 'a') && ((c) <= 'f')) { \
415         i = (c) - 'a' + 10; \
416     } else if (((c) >= 'A') && ((c) <= 'F')) { \
417         i = (c) - 'A' + 10; \
418     } else { \
419         Usage(progName); \
420     }
421
422 int
423 main(int argc, char **argv)
424 {
425         char *               certDir = NULL;
426         char *               progName     = NULL;
427         int                  connections  = 1;
428         char *               cipherString = NULL;
429         char *               respUrl = NULL;
430         char *               respCertName = NULL;
431         SECStatus            secStatus;
432         PLOptState *         optstate;
433         PLOptStatus          status;
434         PRBool               doOcspCheck = PR_FALSE;
435
436         /* Call the NSPR initialization routines */
437         PR_Init( PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
438
439         progName = PORT_Strdup(argv[0]);
440
441         hostName = NULL;
442         optstate = PL_CreateOptState(argc, argv, "C:cd:f:l:n:p:ot:w:");
443         while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
444                 switch(optstate->option) {
445                 case 'C' : cipherString = PL_strdup(optstate->value); break;
446                 case 'c' : dumpChain = PR_TRUE;                       break;
447                 case 'd' : certDir = PL_strdup(optstate->value);      break;
448                 case 'l' : respUrl = PL_strdup(optstate->value);      break;
449                 case 'p' : port = PORT_Atoi(optstate->value);         break;
450                 case 'o' : doOcspCheck = PR_TRUE;                     break;
451                 case 't' : respCertName = PL_strdup(optstate->value); break;
452                 case 'w':
453                            pwdata.source = PW_PLAINTEXT;
454                            pwdata.data = PORT_Strdup(optstate->value);
455                            break;
456
457                 case 'f':
458                            pwdata.source = PW_FROMFILE;
459                            pwdata.data = PORT_Strdup(optstate->value);
460                            break;
461                 case '\0': hostName = PL_strdup(optstate->value);     break;
462                 default  : Usage(progName);
463                 }
464         }
465
466         if (port == 0) {
467                 port = 443;
468         }
469
470         if (port == 0 || hostName == NULL)
471                 Usage(progName);
472
473         if (doOcspCheck &&
474             ((respCertName != NULL && respUrl == NULL) ||
475              (respUrl != NULL && respCertName == NULL))) {
476             SECU_PrintError (progName, "options -l <url> and -t "
477                              "<responder> must be used together");
478             Usage(progName);
479         }
480     
481         PK11_SetPasswordFunc(SECU_GetModulePassword);
482
483         /* Initialize the NSS libraries. */
484         if (certDir) {
485             secStatus = NSS_Init(certDir);
486         } else {
487             secStatus = NSS_NoDB_Init(NULL);
488
489             /* load the builtins */
490             SECMOD_AddNewModule("Builtins",
491                                 DLL_PREFIX"nssckbi."DLL_SUFFIX, 0, 0);
492         }
493         if (secStatus != SECSuccess) {
494                 exitErr("NSS_Init");
495         }
496         SECU_RegisterDynamicOids();
497
498         if (doOcspCheck == PR_TRUE) {
499             SECStatus rv;
500             CERTCertDBHandle *handle = CERT_GetDefaultCertDB();
501             if (handle == NULL) {
502                 SECU_PrintError (progName, "problem getting certdb handle");
503                 goto cleanup;
504             }
505             
506             rv = CERT_EnableOCSPChecking (handle);
507             if (rv != SECSuccess) {
508                 SECU_PrintError (progName, "error enabling OCSP checking");
509                 goto cleanup;
510             }
511
512             if (respUrl != NULL) {
513                 rv = CERT_SetOCSPDefaultResponder (handle, respUrl,
514                                                    respCertName);
515                 if (rv != SECSuccess) {
516                     SECU_PrintError (progName,
517                                      "error setting default responder");
518                     goto cleanup;
519                 }
520                 
521                 rv = CERT_EnableOCSPDefaultResponder (handle);
522                 if (rv != SECSuccess) {
523                     SECU_PrintError (progName,
524                                      "error enabling default responder");
525                     goto cleanup;
526                 }
527             }
528         }
529
530         /* All cipher suites except RSA_NULL_MD5 are enabled by 
531          * Domestic Policy. */
532         NSS_SetDomesticPolicy();
533         SSL_CipherPrefSetDefault(SSL_RSA_WITH_NULL_MD5, PR_TRUE);
534
535         /* all the SSL2 and SSL3 cipher suites are enabled by default. */
536         if (cipherString) {
537             int ndx;
538
539             /* disable all the ciphers, then enable the ones we want. */
540             disableAllSSLCiphers();
541
542             while (0 != (ndx = *cipherString++)) {
543                 int  cipher;
544
545                 if (ndx == ':') {
546                     int ctmp;
547
548                     cipher = 0;
549                     HEXCHAR_TO_INT(*cipherString, ctmp)
550                     cipher |= (ctmp << 12);
551                     cipherString++;
552                     HEXCHAR_TO_INT(*cipherString, ctmp)
553                     cipher |= (ctmp << 8);
554                     cipherString++;
555                     HEXCHAR_TO_INT(*cipherString, ctmp)
556                     cipher |= (ctmp << 4);
557                     cipherString++;
558                     HEXCHAR_TO_INT(*cipherString, ctmp)
559                     cipher |= ctmp;
560                     cipherString++;
561                 } else {
562                     const int *cptr;
563                     if (! isalpha(ndx))
564                         Usage(progName);
565                     cptr = islower(ndx) ? ssl3CipherSuites : ssl2CipherSuites;
566                     for (ndx &= 0x1f; (cipher = *cptr++) != 0 && --ndx > 0; )
567                         /* do nothing */;
568                 }
569                 if (cipher > 0) {
570                     SSL_CipherPrefSetDefault(cipher, PR_TRUE);
571                 } else {
572                     Usage(progName);
573                 }
574             }
575         }
576
577         client_main(port, connections, hostName);
578
579 cleanup:
580         if (doOcspCheck) {
581             CERTCertDBHandle *handle = CERT_GetDefaultCertDB();
582             CERT_DisableOCSPDefaultResponder(handle);        
583             CERT_DisableOCSPChecking (handle);
584         }
585
586         if (NSS_Shutdown() != SECSuccess) {
587             exit(1);
588         }
589
590         PR_Cleanup();
591         PORT_Free(progName);
592         return 0;
593 }
594