security/nss/cmd/vfyserv/vfyserv.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* This Source Code Form is subject to the terms of the Mozilla Public
     2  * License, v. 2.0. If a copy of the MPL was not distributed with this
     3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     5 /****************************************************************************
     6  *  SSL client program that tests  a server for proper operation of SSL2,   *
     7  *  SSL3, and TLS. Test propder certificate installation.                   *
     8  *                                                                          *
     9  *  This code was modified from the SSLSample code also kept in the NSS     *
    10  *  directory.                                                              *
    11  ****************************************************************************/ 
    13 #include <stdio.h>
    14 #include <string.h>
    16 #if defined(XP_UNIX)
    17 #include <unistd.h>
    18 #endif
    20 #include "prerror.h"
    22 #include "pk11func.h"
    23 #include "secmod.h"
    24 #include "secitem.h"
    27 #include <stdlib.h>
    28 #include <errno.h>
    29 #include <fcntl.h>
    30 #include <stdarg.h>
    32 #include "nspr.h"
    33 #include "plgetopt.h"
    34 #include "prio.h"
    35 #include "prnetdb.h"
    36 #include "nss.h"
    37 #include "secutil.h"
    38 #include "ocsp.h"
    40 #include "vfyserv.h"
    42 #define RD_BUF_SIZE (60 * 1024)
    44 extern int ssl2CipherSuites[];
    45 extern int ssl3CipherSuites[];
    47 GlobalThreadMgr threadMGR;
    48 char *certNickname = NULL;
    49 char *hostName = NULL;
    50 secuPWData  pwdata          = { PW_NONE, 0 };
    51 unsigned short port = 0;
    52 PRBool dumpChain;
    54 static void
    55 Usage(const char *progName)
    56 {
    57     PRFileDesc *pr_stderr;
    59     pr_stderr = PR_STDERR;
    61     PR_fprintf(pr_stderr, "Usage:\n"
    62                "   %s  [-c ] [-o] [-p port] [-d dbdir] [-w password] [-f pwfile]\n"
    63                "   \t\t[-C cipher(s)]  [-l <url> -t <nickname> ] hostname",
    64                progName);
    65     PR_fprintf (pr_stderr, "\nWhere:\n");
    66     PR_fprintf (pr_stderr,
    67                 "  %-13s dump server cert chain into files\n",
    68                 "-c");
    69     PR_fprintf (pr_stderr,
    70                 "  %-13s perform server cert OCSP check\n",
    71                 "-o");
    72     PR_fprintf (pr_stderr,
    73                 "  %-13s server port to be used\n",
    74                 "-p");
    75     PR_fprintf (pr_stderr,
    76                 "  %-13s use security databases in \"dbdir\"\n",
    77                 "-d dbdir");
    78     PR_fprintf (pr_stderr,
    79                 "  %-13s key database password\n",
    80                 "-w password");
    81     PR_fprintf (pr_stderr,
    82                 "  %-13s token password file\n",
    83                 "-f pwfile");
    84     PR_fprintf (pr_stderr,
    85                 "  %-13s communication cipher list\n",
    86                 "-C cipher(s)");
    87     PR_fprintf (pr_stderr,
    88                 "  %-13s OCSP responder location. This location is used to\n"
    89                 "  %-13s check  status  of a server  certificate.  If  not \n"
    90                 "  %-13s specified, location  will  be taken  from the AIA\n"
    91                 "  %-13s server certificate extension.\n",
    92                 "-l url", "", "", "");
    93     PR_fprintf (pr_stderr,
    94                 "  %-13s OCSP Trusted Responder Cert nickname\n\n",
    95                 "-t nickname");
    97 	exit(1);
    98 }
   100 PRFileDesc *
   101 setupSSLSocket(PRNetAddr *addr)
   102 {
   103 	PRFileDesc         *tcpSocket;
   104 	PRFileDesc         *sslSocket;
   105 	PRSocketOptionData	socketOption;
   106 	PRStatus            prStatus;
   107 	SECStatus           secStatus;
   110 	tcpSocket = PR_NewTCPSocket();
   111 	if (tcpSocket == NULL) {
   112 		errWarn("PR_NewTCPSocket");
   113 	}
   115 	/* Make the socket blocking. */
   116 	socketOption.option	            = PR_SockOpt_Nonblocking;
   117 	socketOption.value.non_blocking = PR_FALSE;
   119 	prStatus = PR_SetSocketOption(tcpSocket, &socketOption);
   120 	if (prStatus != PR_SUCCESS) {
   121 		errWarn("PR_SetSocketOption");
   122 		goto loser;
   123 	} 
   126 	/* Import the socket into the SSL layer. */
   127 	sslSocket = SSL_ImportFD(NULL, tcpSocket);
   128 	if (!sslSocket) {
   129 		errWarn("SSL_ImportFD");
   130 		goto loser;
   131 	}
   133 	/* Set configuration options. */
   134 	secStatus = SSL_OptionSet(sslSocket, SSL_SECURITY, PR_TRUE);
   135 	if (secStatus != SECSuccess) {
   136 		errWarn("SSL_OptionSet:SSL_SECURITY");
   137 		goto loser;
   138 	}
   140 	secStatus = SSL_OptionSet(sslSocket, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE);
   141 	if (secStatus != SECSuccess) {
   142 		errWarn("SSL_OptionSet:SSL_HANDSHAKE_AS_CLIENT");
   143 		goto loser;
   144 	}
   146 	/* Set SSL callback routines. */
   147 	secStatus = SSL_GetClientAuthDataHook(sslSocket,
   148 	                          (SSLGetClientAuthData)myGetClientAuthData,
   149 	                          (void *)certNickname);
   150 	if (secStatus != SECSuccess) {
   151 		errWarn("SSL_GetClientAuthDataHook");
   152 		goto loser;
   153 	}
   155 	secStatus = SSL_AuthCertificateHook(sslSocket,
   156 	                                   (SSLAuthCertificate)myAuthCertificate,
   157                                        (void *)CERT_GetDefaultCertDB());
   158 	if (secStatus != SECSuccess) {
   159 		errWarn("SSL_AuthCertificateHook");
   160 		goto loser;
   161 	}
   163 	secStatus = SSL_BadCertHook(sslSocket, 
   164 	                           (SSLBadCertHandler)myBadCertHandler, NULL);
   165 	if (secStatus != SECSuccess) {
   166 		errWarn("SSL_BadCertHook");
   167 		goto loser;
   168 	}
   170 	secStatus = SSL_HandshakeCallback(sslSocket, 
   171 	                                  myHandshakeCallback,
   172 	                                  NULL);
   173 	if (secStatus != SECSuccess) {
   174 		errWarn("SSL_HandshakeCallback");
   175 		goto loser;
   176 	}
   178 	return sslSocket;
   180 loser:
   182 	PR_Close(tcpSocket);
   183 	return NULL;
   184 }
   187 const char requestString[] = {"GET /testfile HTTP/1.0\r\n\r\n" };
   189 SECStatus
   190 handle_connection(PRFileDesc *sslSocket, int connection)
   191 {
   192 	int	countRead = 0;
   193 	PRInt32  numBytes;
   194 	char    *readBuffer;
   196 	readBuffer = PORT_Alloc(RD_BUF_SIZE);
   197 	if (!readBuffer) {
   198 		exitErr("PORT_Alloc");
   199 	}
   201 	/* compose the http request here. */
   203 	numBytes = PR_Write(sslSocket, requestString, strlen(requestString));
   204 	if (numBytes <= 0) {
   205 		errWarn("PR_Write");
   206 		PR_Free(readBuffer);
   207 		readBuffer = NULL;
   208 		return SECFailure;
   209 	}
   211 	/* read until EOF */
   212 	while (PR_TRUE) {
   213 		numBytes = PR_Read(sslSocket, readBuffer, RD_BUF_SIZE);
   214 		if (numBytes == 0) {
   215 			break;	/* EOF */
   216 		}
   217 		if (numBytes < 0) {
   218 			errWarn("PR_Read");
   219 			break;
   220 		}
   221 		countRead += numBytes;
   222 	}
   224 	printSecurityInfo(stderr, sslSocket);
   226 	PR_Free(readBuffer);
   227 	readBuffer = NULL;
   229 	/* Caller closes the socket. */
   231 	fprintf(stderr, 
   232 	        "***** Connection %d read %d bytes total.\n", 
   233 	        connection, countRead);
   235 	return SECSuccess;	/* success */
   236 }
   238 #define BYTE(n,i) (((i)>>((n)*8))&0xff)
   240 /* one copy of this function is launched in a separate thread for each
   241 ** connection to be made.
   242 */
   243 SECStatus
   244 do_connects(void *a, int connection)
   245 {
   246 	PRNetAddr  *addr = (PRNetAddr *)a;
   247 	PRFileDesc *sslSocket;
   248 	PRHostEnt   hostEntry;
   249 	char        buffer[PR_NETDB_BUF_SIZE];
   250 	PRStatus    prStatus;
   251 	PRIntn      hostenum;
   252 	PRInt32    ip;
   253 	SECStatus   secStatus;
   255 	/* Set up SSL secure socket. */
   256 	sslSocket = setupSSLSocket(addr);
   257 	if (sslSocket == NULL) {
   258 		errWarn("setupSSLSocket");
   259 		return SECFailure;
   260 	}
   262 	secStatus = SSL_SetPKCS11PinArg(sslSocket, &pwdata);
   263 	if (secStatus != SECSuccess) {
   264 		errWarn("SSL_SetPKCS11PinArg");
   265 		return secStatus;
   266 	}
   268 	secStatus = SSL_SetURL(sslSocket, hostName);
   269 	if (secStatus != SECSuccess) {
   270 		errWarn("SSL_SetURL");
   271 		return secStatus;
   272 	}
   274 	/* Prepare and setup network connection. */
   275 	prStatus = PR_GetHostByName(hostName, buffer, sizeof(buffer), &hostEntry);
   276 	if (prStatus != PR_SUCCESS) {
   277 		errWarn("PR_GetHostByName");
   278 		return SECFailure;
   279 	}
   281 	hostenum = PR_EnumerateHostEnt(0, &hostEntry, port, addr);
   282 	if (hostenum == -1) {
   283 		errWarn("PR_EnumerateHostEnt");
   284 		return SECFailure;
   285 	}
   287  	ip = PR_ntohl(addr->inet.ip);
   288 	fprintf(stderr,
   289 	 	"Connecting to host %s (addr %d.%d.%d.%d) on port %d\n",
   290 			hostName, BYTE(3,ip), BYTE(2,ip), BYTE(1,ip), 
   291 			BYTE(0,ip), PR_ntohs(addr->inet.port)); 
   293 	prStatus = PR_Connect(sslSocket, addr, PR_INTERVAL_NO_TIMEOUT);
   294 	if (prStatus != PR_SUCCESS) {
   295 		errWarn("PR_Connect");
   296 		return SECFailure;
   297 	}
   299 	/* Established SSL connection, ready to send data. */
   300 #if 0
   301 	secStatus = SSL_ForceHandshake(sslSocket);
   302 	if (secStatus != SECSuccess) {
   303 		errWarn("SSL_ForceHandshake");
   304 		return secStatus;
   305 	}
   306 #endif
   308 	secStatus = SSL_ResetHandshake(sslSocket, /* asServer */ PR_FALSE);
   309 	if (secStatus != SECSuccess) {
   310 		errWarn("SSL_ResetHandshake");
   311 		prStatus = PR_Close(sslSocket);
   312 		if (prStatus != PR_SUCCESS) {
   313 			errWarn("PR_Close");
   314 		}
   315 		return secStatus;
   316 	}
   318 	secStatus = handle_connection(sslSocket, connection);
   319 	if (secStatus != SECSuccess) {
   320 		/* error already printed out in handle_connection */
   321 		/* errWarn("handle_connection"); */
   322 		prStatus = PR_Close(sslSocket);
   323 		if (prStatus != PR_SUCCESS) {
   324 			errWarn("PR_Close");
   325 		}
   326 		return secStatus;
   327 	}
   329 	PR_Close(sslSocket);
   330 	return SECSuccess;
   331 }
   333 void
   334 client_main(unsigned short      port, 
   335             int	                connections, 
   336             const char *        hostName)
   337 {
   338 	int			i;
   339 	SECStatus	secStatus;
   340 	PRStatus    prStatus;
   341 	PRInt32     rv;
   342 	PRNetAddr	addr;
   343 	PRHostEnt   hostEntry;
   344 	char        buffer[PR_NETDB_BUF_SIZE];
   346 	/* Setup network connection. */
   347 	prStatus = PR_GetHostByName(hostName, buffer, sizeof(buffer), &hostEntry);
   348 	if (prStatus != PR_SUCCESS) {
   349 		exitErr("PR_GetHostByName");
   350 	}
   352 	rv = PR_EnumerateHostEnt(0, &hostEntry, port, &addr);
   353 	if (rv < 0) {
   354 		exitErr("PR_EnumerateHostEnt");
   355 	}
   357 	secStatus = launch_thread(&threadMGR, do_connects, &addr, 1);
   358 	if (secStatus != SECSuccess) {
   359 		exitErr("launch_thread");
   360 	}
   362 	if (connections > 1) {
   363 		/* wait for the first connection to terminate, then launch the rest. */
   364 		reap_threads(&threadMGR);
   365 		/* Start up the connections */
   366 		for (i = 2; i <= connections; ++i) {
   367 			secStatus = launch_thread(&threadMGR, do_connects, &addr, i);
   368 			if (secStatus != SECSuccess) {
   369 				errWarn("launch_thread");
   370 			}
   371 		}
   372 	}
   374 	reap_threads(&threadMGR);
   375 	destroy_thread_data(&threadMGR);
   376 }
   378 #define HEXCHAR_TO_INT(c, i) \
   379     if (((c) >= '0') && ((c) <= '9')) { \
   380 	i = (c) - '0'; \
   381     } else if (((c) >= 'a') && ((c) <= 'f')) { \
   382 	i = (c) - 'a' + 10; \
   383     } else if (((c) >= 'A') && ((c) <= 'F')) { \
   384 	i = (c) - 'A' + 10; \
   385     } else { \
   386 	Usage(progName); \
   387     }
   389 int
   390 main(int argc, char **argv)
   391 {
   392 	char *               certDir = NULL;
   393 	char *               progName     = NULL;
   394 	int                  connections  = 1;
   395 	char *               cipherString = NULL;
   396 	char *               respUrl = NULL;
   397 	char *               respCertName = NULL;
   398 	SECStatus            secStatus;
   399 	PLOptState *         optstate;
   400 	PLOptStatus          status;
   401 	PRBool               doOcspCheck = PR_FALSE;
   403 	/* Call the NSPR initialization routines */
   404 	PR_Init( PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
   406 	progName = PORT_Strdup(argv[0]);
   408 	hostName = NULL;
   409 	optstate = PL_CreateOptState(argc, argv, "C:cd:f:l:n:p:ot:w:");
   410 	while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
   411 		switch(optstate->option) {
   412 		case 'C' : cipherString = PL_strdup(optstate->value); break;
   413  		case 'c' : dumpChain = PR_TRUE;                       break;
   414 		case 'd' : certDir = PL_strdup(optstate->value);      break;
   415 		case 'l' : respUrl = PL_strdup(optstate->value);      break;
   416 		case 'p' : port = PORT_Atoi(optstate->value);         break;
   417 		case 'o' : doOcspCheck = PR_TRUE;                     break;
   418 		case 't' : respCertName = PL_strdup(optstate->value); break;
   419                 case 'w':
   420                            pwdata.source = PW_PLAINTEXT;
   421                            pwdata.data = PORT_Strdup(optstate->value);
   422                            break;
   424                 case 'f':
   425                            pwdata.source = PW_FROMFILE;
   426                            pwdata.data = PORT_Strdup(optstate->value);
   427                            break;
   428 		case '\0': hostName = PL_strdup(optstate->value);     break;
   429 		default  : Usage(progName);
   430 		}
   431 	}
   433 	if (port == 0) {
   434 		port = 443;
   435 	}
   437 	if (port == 0 || hostName == NULL)
   438 		Usage(progName);
   440         if (doOcspCheck &&
   441             ((respCertName != NULL && respUrl == NULL) ||
   442              (respUrl != NULL && respCertName == NULL))) {
   443 	    SECU_PrintError (progName, "options -l <url> and -t "
   444 	                     "<responder> must be used together");
   445 	    Usage(progName);
   446         }
   448 	PK11_SetPasswordFunc(SECU_GetModulePassword);
   450 	/* Initialize the NSS libraries. */
   451 	if (certDir) {
   452 	    secStatus = NSS_Init(certDir);
   453 	} else {
   454 	    secStatus = NSS_NoDB_Init(NULL);
   456 	    /* load the builtins */
   457 	    SECMOD_AddNewModule("Builtins",
   458 				DLL_PREFIX"nssckbi."DLL_SUFFIX, 0, 0);
   459 	}
   460 	if (secStatus != SECSuccess) {
   461 		exitErr("NSS_Init");
   462 	}
   463 	SECU_RegisterDynamicOids();
   465 	if (doOcspCheck == PR_TRUE) {
   466             SECStatus rv;
   467             CERTCertDBHandle *handle = CERT_GetDefaultCertDB();
   468             if (handle == NULL) {
   469                 SECU_PrintError (progName, "problem getting certdb handle");
   470                 goto cleanup;
   471             }
   473             rv = CERT_EnableOCSPChecking (handle);
   474             if (rv != SECSuccess) {
   475                 SECU_PrintError (progName, "error enabling OCSP checking");
   476                 goto cleanup;
   477             }
   479             if (respUrl != NULL) {
   480                 rv = CERT_SetOCSPDefaultResponder (handle, respUrl,
   481                                                    respCertName);
   482                 if (rv != SECSuccess) {
   483                     SECU_PrintError (progName,
   484                                      "error setting default responder");
   485                     goto cleanup;
   486                 }
   488                 rv = CERT_EnableOCSPDefaultResponder (handle);
   489                 if (rv != SECSuccess) {
   490                     SECU_PrintError (progName,
   491                                      "error enabling default responder");
   492                     goto cleanup;
   493                 }
   494             }
   495 	}
   497 	/* All cipher suites except RSA_NULL_MD5 are enabled by 
   498 	 * Domestic Policy. */
   499 	NSS_SetDomesticPolicy();
   500 	SSL_CipherPrefSetDefault(TLS_RSA_WITH_NULL_MD5, PR_TRUE);
   502 	/* all the SSL2 and SSL3 cipher suites are enabled by default. */
   503 	if (cipherString) {
   504 	    int ndx;
   506 	    /* disable all the ciphers, then enable the ones we want. */
   507 	    disableAllSSLCiphers();
   509 	    while (0 != (ndx = *cipherString++)) {
   510 		int  cipher;
   512 		if (ndx == ':') {
   513 		    int ctmp;
   515 		    cipher = 0;
   516 		    HEXCHAR_TO_INT(*cipherString, ctmp)
   517 		    cipher |= (ctmp << 12);
   518 		    cipherString++;
   519 		    HEXCHAR_TO_INT(*cipherString, ctmp)
   520 		    cipher |= (ctmp << 8);
   521 		    cipherString++;
   522 		    HEXCHAR_TO_INT(*cipherString, ctmp)
   523 		    cipher |= (ctmp << 4);
   524 		    cipherString++;
   525 		    HEXCHAR_TO_INT(*cipherString, ctmp)
   526 		    cipher |= ctmp;
   527 		    cipherString++;
   528 		} else {
   529 		    const int *cptr;
   530 		    if (! isalpha(ndx))
   531 			Usage(progName);
   532 		    cptr = islower(ndx) ? ssl3CipherSuites : ssl2CipherSuites;
   533 		    for (ndx &= 0x1f; (cipher = *cptr++) != 0 && --ndx > 0; )
   534 			/* do nothing */;
   535 		}
   536 		if (cipher > 0) {
   537 		    SSL_CipherPrefSetDefault(cipher, PR_TRUE);
   538 		} else {
   539 		    Usage(progName);
   540 		}
   541 	    }
   542 	}
   544 	client_main(port, connections, hostName);
   546 cleanup:
   547         if (doOcspCheck) {
   548             CERTCertDBHandle *handle = CERT_GetDefaultCertDB();
   549             CERT_DisableOCSPDefaultResponder(handle);        
   550             CERT_DisableOCSPChecking (handle);
   551         }
   553         if (NSS_Shutdown() != SECSuccess) {
   554             exit(1);
   555         }
   557 	PR_Cleanup();
   558 	PORT_Free(progName);
   559 	return 0;
   560 }

mercurial