security/nss/cmd/selfserv/selfserv.c

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/security/nss/cmd/selfserv/selfserv.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,2717 @@
     1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.7 +
     1.8 +/* -r flag is interepreted as follows:
     1.9 + *	1 -r  means request, not require, on initial handshake.
    1.10 + *	2 -r's mean request  and require, on initial handshake.
    1.11 + *	3 -r's mean request, not require, on second handshake.
    1.12 + *	4 -r's mean request  and require, on second handshake.
    1.13 + */
    1.14 +#include <stdio.h>
    1.15 +#include <string.h>
    1.16 +
    1.17 +#include "secutil.h"
    1.18 +
    1.19 +#if defined(XP_UNIX)
    1.20 +#include <unistd.h>
    1.21 +#endif
    1.22 +
    1.23 +#if defined(_WINDOWS)
    1.24 +#include <process.h>	/* for getpid() */
    1.25 +#endif
    1.26 +
    1.27 +#include <signal.h>
    1.28 +#include <stdlib.h>
    1.29 +#include <errno.h>
    1.30 +#include <fcntl.h>
    1.31 +#include <stdarg.h>
    1.32 +
    1.33 +#include "nspr.h"
    1.34 +#include "prio.h"
    1.35 +#include "prerror.h"
    1.36 +#include "prnetdb.h"
    1.37 +#include "prclist.h"
    1.38 +#include "plgetopt.h"
    1.39 +#include "pk11func.h"
    1.40 +#include "secitem.h"
    1.41 +#include "nss.h"
    1.42 +#include "ssl.h"
    1.43 +#include "sslproto.h"
    1.44 +#include "cert.h"
    1.45 +#include "certt.h"
    1.46 +#include "ocsp.h"
    1.47 +
    1.48 +#ifndef PORT_Sprintf
    1.49 +#define PORT_Sprintf sprintf
    1.50 +#endif
    1.51 +
    1.52 +#ifndef PORT_Strstr
    1.53 +#define PORT_Strstr strstr
    1.54 +#endif
    1.55 +
    1.56 +#ifndef PORT_Malloc
    1.57 +#define PORT_Malloc PR_Malloc
    1.58 +#endif
    1.59 +
    1.60 +int NumSidCacheEntries = 1024;
    1.61 +
    1.62 +static int handle_connection( PRFileDesc *, PRFileDesc *, int );
    1.63 +
    1.64 +static const char envVarName[] = { SSL_ENV_VAR_NAME };
    1.65 +static const char inheritableSockName[] = { "SELFSERV_LISTEN_SOCKET" };
    1.66 +
    1.67 +#define DEFAULT_BULK_TEST 16384
    1.68 +#define MAX_BULK_TEST     1048576 /* 1 MB */
    1.69 +static PRBool testBulk;
    1.70 +static PRUint32 testBulkSize       = DEFAULT_BULK_TEST;
    1.71 +static PRUint32 testBulkTotal;
    1.72 +static char* testBulkBuf;
    1.73 +static PRDescIdentity log_layer_id = PR_INVALID_IO_LAYER;
    1.74 +static PRFileDesc *loggingFD;
    1.75 +static PRIOMethods loggingMethods;
    1.76 +
    1.77 +static PRBool logStats;
    1.78 +static PRBool loggingLayer;
    1.79 +static int logPeriod = 30;
    1.80 +static PRUint32 loggerOps;
    1.81 +static PRUint32 loggerBytes;
    1.82 +static PRUint32 loggerBytesTCP;
    1.83 +static PRUint32 bulkSentChunks;
    1.84 +static enum ocspStaplingModeEnum {
    1.85 +    osm_disabled,  /* server doesn't support stapling */
    1.86 +    osm_good,      /* supply a signed good status */
    1.87 +    osm_revoked,   /* supply a signed revoked status */
    1.88 +    osm_unknown,   /* supply a signed unknown status */
    1.89 +    osm_failure,   /* supply a unsigned failure status, "try later" */
    1.90 +    osm_badsig,    /* supply a good status response with a bad signature */
    1.91 +    osm_corrupted, /* supply a corrupted data block as the status */
    1.92 +    osm_random,    /* use a random response for each connection */
    1.93 +    osm_ocsp       /* retrieve ocsp status from external ocsp server,
    1.94 +		      use empty status if server is unavailable */
    1.95 +} ocspStaplingMode = osm_disabled;
    1.96 +typedef enum ocspStaplingModeEnum ocspStaplingModeType;
    1.97 +static char *ocspStaplingCA = NULL;
    1.98 +static SECItemArray *certStatus[kt_kea_size] = { NULL };
    1.99 +
   1.100 +const int ssl2CipherSuites[] = {
   1.101 +    SSL_EN_RC4_128_WITH_MD5,			/* A */
   1.102 +    SSL_EN_RC4_128_EXPORT40_WITH_MD5,		/* B */
   1.103 +    SSL_EN_RC2_128_CBC_WITH_MD5,		/* C */
   1.104 +    SSL_EN_RC2_128_CBC_EXPORT40_WITH_MD5,	/* D */
   1.105 +    SSL_EN_DES_64_CBC_WITH_MD5,			/* E */
   1.106 +    SSL_EN_DES_192_EDE3_CBC_WITH_MD5,		/* F */
   1.107 +    0
   1.108 +};
   1.109 +
   1.110 +const int ssl3CipherSuites[] = {
   1.111 +    -1, /* SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA* a */
   1.112 +    -1, /* SSL_FORTEZZA_DMS_WITH_RC4_128_SHA	 * b */
   1.113 +    TLS_RSA_WITH_RC4_128_MD5,			/* c */
   1.114 +    TLS_RSA_WITH_3DES_EDE_CBC_SHA,		/* d */
   1.115 +    TLS_RSA_WITH_DES_CBC_SHA,			/* e */
   1.116 +    TLS_RSA_EXPORT_WITH_RC4_40_MD5,		/* f */
   1.117 +    TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5,		/* g */
   1.118 +    -1, /* SSL_FORTEZZA_DMS_WITH_NULL_SHA,	 * h */
   1.119 +    TLS_RSA_WITH_NULL_MD5,			/* i */
   1.120 +    SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA,		/* j */
   1.121 +    SSL_RSA_FIPS_WITH_DES_CBC_SHA,		/* k */
   1.122 +    TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA,	/* l */
   1.123 +    TLS_RSA_EXPORT1024_WITH_RC4_56_SHA,	        /* m */
   1.124 +    TLS_RSA_WITH_RC4_128_SHA,			/* n */
   1.125 +    -1, /* TLS_DHE_DSS_WITH_RC4_128_SHA, 	 * o */
   1.126 +    -1, /* TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA,	 * p */
   1.127 +    -1, /* TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA,	 * q */
   1.128 +    -1, /* TLS_DHE_RSA_WITH_DES_CBC_SHA,	 * r */
   1.129 +    -1, /* TLS_DHE_DSS_WITH_DES_CBC_SHA,	 * s */
   1.130 +    -1, /* TLS_DHE_DSS_WITH_AES_128_CBC_SHA,	 * t */
   1.131 +    -1, /* TLS_DHE_RSA_WITH_AES_128_CBC_SHA,	 * u */
   1.132 +    TLS_RSA_WITH_AES_128_CBC_SHA,     	    	/* v */
   1.133 +    -1, /* TLS_DHE_DSS_WITH_AES_256_CBC_SHA,	 * w */
   1.134 +    -1, /* TLS_DHE_RSA_WITH_AES_256_CBC_SHA,	 * x */
   1.135 +    TLS_RSA_WITH_AES_256_CBC_SHA,     	    	/* y */
   1.136 +    TLS_RSA_WITH_NULL_SHA,			/* z */
   1.137 +    0
   1.138 +};
   1.139 +
   1.140 +/* data and structures for shutdown */
   1.141 +static int	stopping;
   1.142 +
   1.143 +static PRBool  noDelay;
   1.144 +static int     requestCert;
   1.145 +static int	verbose;
   1.146 +static SECItem	bigBuf;
   1.147 +
   1.148 +static PRThread * acceptorThread;
   1.149 +
   1.150 +static PRLogModuleInfo *lm;
   1.151 +
   1.152 +#define PRINTF  if (verbose)  printf
   1.153 +#define FPRINTF if (verbose) fprintf
   1.154 +#define FLUSH	if (verbose) { fflush(stdout); fflush(stderr); }
   1.155 +#define VLOG(arg) PR_LOG(lm,PR_LOG_DEBUG,arg)
   1.156 +
   1.157 +static void
   1.158 +PrintUsageHeader(const char *progName)
   1.159 +{
   1.160 +    fprintf(stderr, 
   1.161 +"Usage: %s -n rsa_nickname -p port [-BDENRbjlmrsuvx] [-w password]\n"
   1.162 +"         [-t threads] [-i pid_file] [-c ciphers] [-Y] [-d dbdir] [-g numblocks]\n"
   1.163 +"         [-f password_file] [-L [seconds]] [-M maxProcs] [-P dbprefix]\n"
   1.164 +"         [-V [min-version]:[max-version]] [-a sni_name]\n"
   1.165 +"         [ T <good|revoked|unknown|badsig|corrupted|none|ocsp>] [-A ca]\n"
   1.166 +#ifndef NSS_DISABLE_ECC
   1.167 +"         [-C SSLCacheEntries] [-e ec_nickname]\n"
   1.168 +#else
   1.169 +"         [-C SSLCacheEntries]\n"
   1.170 +#endif /* NSS_DISABLE_ECC */
   1.171 +        ,progName);
   1.172 +}
   1.173 +
   1.174 +static void
   1.175 +PrintParameterUsage()
   1.176 +{
   1.177 +    fputs(
   1.178 +"-V [min]:[max] restricts the set of enabled SSL/TLS protocol versions.\n"
   1.179 +"   All versions are enabled by default.\n"
   1.180 +"   Possible values for min/max: ssl2 ssl3 tls1.0 tls1.1 tls1.2\n"
   1.181 +"   Example: \"-V ssl3:\" enables SSL 3 and newer.\n"
   1.182 +"-B bypasses the PKCS11 layer for SSL encryption and MACing\n"
   1.183 +"-q checks for bypassability\n"
   1.184 +"-D means disable Nagle delays in TCP\n"
   1.185 +"-E means disable export ciphersuites and SSL step down key gen\n"
   1.186 +"-R means disable detection of rollback from TLS to SSL3\n"
   1.187 +"-a configure server for SNI.\n"
   1.188 +"-k expected name negotiated on server sockets\n"
   1.189 +"-b means try binding to the port and exit\n"
   1.190 +"-m means test the model-socket feature of SSL_ImportFD.\n"
   1.191 +"-r flag is interepreted as follows:\n"
   1.192 +"    1 -r  means request, not require, cert on initial handshake.\n"
   1.193 +"    2 -r's mean request  and require, cert on initial handshake.\n"
   1.194 +"    3 -r's mean request, not require, cert on second handshake.\n"
   1.195 +"    4 -r's mean request  and require, cert on second handshake.\n"
   1.196 +"-s means disable SSL socket locking for performance\n"
   1.197 +"-u means enable Session Ticket extension for TLS.\n"
   1.198 +"-v means verbose output\n"
   1.199 +"-x means use export policy.\n"
   1.200 +"-z means enable compression.\n"
   1.201 +"-L seconds means log statistics every 'seconds' seconds (default=30).\n"
   1.202 +"-M maxProcs tells how many processes to run in a multi-process server\n"
   1.203 +"-N means do NOT use the server session cache.  Incompatible with -M.\n"
   1.204 +"-t threads -- specify the number of threads to use for connections.\n"
   1.205 +"-i pid_file file to write the process id of selfserve\n"
   1.206 +"-l means use local threads instead of global threads\n"
   1.207 +"-g numblocks means test throughput by sending total numblocks chunks\n"
   1.208 +"    of size 16kb to the client, 0 means unlimited (default=0)\n"
   1.209 +"-j means measure TCP throughput (for use with -g option)\n"
   1.210 +"-C SSLCacheEntries sets the maximum number of entries in the SSL\n" 
   1.211 +"    session cache\n"
   1.212 +"-T <mode> enable OCSP stapling. Possible modes:\n"
   1.213 +"   none: don't send cert status (default)\n"
   1.214 +"   good, revoked, unknown: Include locally signed response. Requires: -A\n"
   1.215 +"   failure: return a failure response (try later, unsigned)\n"
   1.216 +"   badsig: use a good status but with an invalid signature\n"
   1.217 +"   corrupted: stapled cert status is an invalid block of data\n"
   1.218 +"   random: each connection uses a random status from this list:\n"
   1.219 +"           good, revoked, unknown, failure, badsig, corrupted\n"
   1.220 +"   ocsp: fetch from external OCSP server using AIA, or none\n"
   1.221 +"-A <ca> Nickname of a CA used to sign a stapled cert status\n"
   1.222 +"-c Restrict ciphers\n"
   1.223 +"-Y prints cipher values allowed for parameter -c and exits\n"
   1.224 +    , stderr);
   1.225 +}
   1.226 +
   1.227 +static void
   1.228 +Usage(const char *progName)
   1.229 +{
   1.230 +    PrintUsageHeader(progName);
   1.231 +    PrintParameterUsage();
   1.232 +}
   1.233 +
   1.234 +static void
   1.235 +PrintCipherUsage(const char *progName)
   1.236 +{
   1.237 +    PrintUsageHeader(progName);
   1.238 +    fputs(
   1.239 +"-c ciphers   Letter(s) chosen from the following list\n"
   1.240 +"A    SSL2 RC4 128 WITH MD5\n"
   1.241 +"B    SSL2 RC4 128 EXPORT40 WITH MD5\n"
   1.242 +"C    SSL2 RC2 128 CBC WITH MD5\n"
   1.243 +"D    SSL2 RC2 128 CBC EXPORT40 WITH MD5\n"
   1.244 +"E    SSL2 DES 64 CBC WITH MD5\n"
   1.245 +"F    SSL2 DES 192 EDE3 CBC WITH MD5\n"
   1.246 +"\n"
   1.247 +"c    SSL3 RSA WITH RC4 128 MD5\n"
   1.248 +"d    SSL3 RSA WITH 3DES EDE CBC SHA\n"
   1.249 +"e    SSL3 RSA WITH DES CBC SHA\n"
   1.250 +"f    SSL3 RSA EXPORT WITH RC4 40 MD5\n"
   1.251 +"g    SSL3 RSA EXPORT WITH RC2 CBC 40 MD5\n"
   1.252 +"i    SSL3 RSA WITH NULL MD5\n"
   1.253 +"j    SSL3 RSA FIPS WITH 3DES EDE CBC SHA\n"
   1.254 +"k    SSL3 RSA FIPS WITH DES CBC SHA\n"
   1.255 +"l    SSL3 RSA EXPORT WITH DES CBC SHA\t(new)\n"
   1.256 +"m    SSL3 RSA EXPORT WITH RC4 56 SHA\t(new)\n"
   1.257 +"n    SSL3 RSA WITH RC4 128 SHA\n"
   1.258 +"v    SSL3 RSA WITH AES 128 CBC SHA\n"
   1.259 +"y    SSL3 RSA WITH AES 256 CBC SHA\n"
   1.260 +"z    SSL3 RSA WITH NULL SHA\n"
   1.261 +"\n"
   1.262 +":WXYZ  Use cipher with hex code { 0xWX , 0xYZ } in TLS\n"
   1.263 +    , stderr);
   1.264 +}
   1.265 +
   1.266 +static const char *
   1.267 +errWarn(char * funcString)
   1.268 +{
   1.269 +    PRErrorCode  perr      = PR_GetError();
   1.270 +    const char * errString = SECU_Strerror(perr);
   1.271 +
   1.272 +    fprintf(stderr, "selfserv: %s returned error %d:\n%s\n",
   1.273 +            funcString, perr, errString);
   1.274 +    return errString;
   1.275 +}
   1.276 +
   1.277 +static void
   1.278 +errExit(char * funcString)
   1.279 +{
   1.280 +    errWarn(funcString);
   1.281 +    exit(3);
   1.282 +}
   1.283 +
   1.284 +
   1.285 +/**************************************************************************
   1.286 +** 
   1.287 +** Routines for disabling SSL ciphers.
   1.288 +**
   1.289 +**************************************************************************/
   1.290 +
   1.291 +/* disable all the SSL cipher suites */
   1.292 +void
   1.293 +disableAllSSLCiphers(void)
   1.294 +{
   1.295 +    const PRUint16 *cipherSuites = SSL_ImplementedCiphers;
   1.296 +    int             i            = SSL_NumImplementedCiphers;
   1.297 +    SECStatus       rv;
   1.298 +
   1.299 +    while (--i >= 0) {
   1.300 +	PRUint16 suite = cipherSuites[i];
   1.301 +        rv = SSL_CipherPrefSetDefault(suite, PR_FALSE);
   1.302 +	if (rv != SECSuccess) {
   1.303 +	    printf("SSL_CipherPrefSetDefault rejected suite 0x%04x (i = %d)\n",
   1.304 +	    	   suite, i);
   1.305 +	    errWarn("SSL_CipherPrefSetDefault");
   1.306 +	}
   1.307 +    }
   1.308 +}
   1.309 +
   1.310 +/* disable all the export SSL cipher suites */
   1.311 +SECStatus
   1.312 +disableExportSSLCiphers(void)
   1.313 +{
   1.314 +    const PRUint16 *cipherSuites = SSL_ImplementedCiphers;
   1.315 +    int             i            = SSL_NumImplementedCiphers;
   1.316 +    SECStatus       rv           = SECSuccess;
   1.317 +    SSLCipherSuiteInfo info;
   1.318 +
   1.319 +    while (--i >= 0) {
   1.320 +	PRUint16 suite = cipherSuites[i];
   1.321 +	SECStatus status;
   1.322 +	status = SSL_GetCipherSuiteInfo(suite, &info, sizeof info);
   1.323 +	if (status != SECSuccess) {
   1.324 +	    printf("SSL_GetCipherSuiteInfo rejected suite 0x%04x (i = %d)\n",
   1.325 +		   suite, i);
   1.326 +	    errWarn("SSL_GetCipherSuiteInfo");
   1.327 +	    rv = SECFailure;
   1.328 +	    continue;
   1.329 +	}
   1.330 +	if (info.cipherSuite != suite) {
   1.331 +	    printf(
   1.332 +"SSL_GetCipherSuiteInfo returned wrong suite! Wanted 0x%04x, Got 0x%04x\n",
   1.333 +		   suite, i);
   1.334 +	    PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
   1.335 +	    rv = SECFailure;
   1.336 +	    continue;
   1.337 +	}
   1.338 +	/* should check here that info.length >= offsetof isExportable */
   1.339 +	if (info.isExportable) {
   1.340 +	    status = SSL_CipherPolicySet(suite, SSL_NOT_ALLOWED);
   1.341 +	    if (status != SECSuccess) {
   1.342 +		printf("SSL_CipherPolicySet rejected suite 0x%04x (i = %d)\n",
   1.343 +		       suite, i);
   1.344 +		errWarn("SSL_CipherPolicySet");
   1.345 +		rv = SECFailure;
   1.346 +	    }
   1.347 +	}
   1.348 +    }
   1.349 +    return rv;
   1.350 +}
   1.351 +
   1.352 +static SECStatus
   1.353 +mySSLAuthCertificate(void *arg, PRFileDesc *fd, PRBool checkSig,
   1.354 +		     PRBool isServer)
   1.355 +{
   1.356 +    SECStatus rv;
   1.357 +    CERTCertificate *    peerCert;
   1.358 +
   1.359 +    peerCert = SSL_PeerCertificate(fd);
   1.360 +    
   1.361 +    if (peerCert) {
   1.362 +        PRINTF("selfserv: Subject: %s\nselfserv: Issuer : %s\n",
   1.363 +               peerCert->subjectName, peerCert->issuerName);
   1.364 +        CERT_DestroyCertificate(peerCert);
   1.365 +    }
   1.366 +
   1.367 +    rv = SSL_AuthCertificate(arg, fd, checkSig, isServer);
   1.368 +
   1.369 +    if (rv == SECSuccess) {
   1.370 +	PRINTF("selfserv: -- SSL3: Certificate Validated.\n");
   1.371 +    } else {
   1.372 +    	int err = PR_GetError();
   1.373 +	FPRINTF(stderr, "selfserv: -- SSL3: Certificate Invalid, err %d.\n%s\n", 
   1.374 +                err, SECU_Strerror(err));
   1.375 +    }
   1.376 +    FLUSH;
   1.377 +    return rv;  
   1.378 +}
   1.379 +
   1.380 +void
   1.381 +printSSLStatistics()
   1.382 +{
   1.383 +    SSL3Statistics *  ssl3stats = SSL_GetStatistics();
   1.384 +
   1.385 +    printf(
   1.386 +	"selfserv: %ld cache hits; %ld cache misses, %ld cache not reusable\n"
   1.387 +	"          %ld stateless resumes, %ld ticket parse failures\n",
   1.388 +	ssl3stats->hch_sid_cache_hits, ssl3stats->hch_sid_cache_misses,
   1.389 +	ssl3stats->hch_sid_cache_not_ok, ssl3stats->hch_sid_stateless_resumes,
   1.390 +	ssl3stats->hch_sid_ticket_parse_failures);
   1.391 +}
   1.392 +
   1.393 +void 
   1.394 +printSecurityInfo(PRFileDesc *fd)
   1.395 +{
   1.396 +    CERTCertificate * cert      = NULL;
   1.397 +    SECStatus         result;
   1.398 +    SSLChannelInfo    channel;
   1.399 +    SSLCipherSuiteInfo suite;
   1.400 +
   1.401 +    if (verbose)
   1.402 +	printSSLStatistics();
   1.403 +
   1.404 +    result = SSL_GetChannelInfo(fd, &channel, sizeof channel);
   1.405 +    if (result == SECSuccess && 
   1.406 +        channel.length == sizeof channel && 
   1.407 +	channel.cipherSuite) {
   1.408 +	result = SSL_GetCipherSuiteInfo(channel.cipherSuite, 
   1.409 +					&suite, sizeof suite);
   1.410 +	if (result == SECSuccess) {
   1.411 +	    FPRINTF(stderr, 
   1.412 +	    "selfserv: SSL version %d.%d using %d-bit %s with %d-bit %s MAC\n",
   1.413 +	       channel.protocolVersion >> 8, channel.protocolVersion & 0xff,
   1.414 +	       suite.effectiveKeyBits, suite.symCipherName, 
   1.415 +	       suite.macBits, suite.macAlgorithmName);
   1.416 +	    FPRINTF(stderr, 
   1.417 +	    "selfserv: Server Auth: %d-bit %s, Key Exchange: %d-bit %s\n"
   1.418 +	    "          Compression: %s\n",
   1.419 +	       channel.authKeyBits, suite.authAlgorithmName,
   1.420 +	       channel.keaKeyBits,  suite.keaTypeName,
   1.421 +	       channel.compressionMethodName);
   1.422 +    	}
   1.423 +    }
   1.424 +    if (verbose) {
   1.425 +        SECItem *hostInfo  = SSL_GetNegotiatedHostInfo(fd);
   1.426 +        if (hostInfo) {
   1.427 +            char namePref[] = "selfserv: Negotiated server name: ";
   1.428 +
   1.429 +            fprintf(stderr, "%s", namePref);
   1.430 +            fwrite(hostInfo->data, hostInfo->len, 1, stderr);
   1.431 +            SECITEM_FreeItem(hostInfo, PR_TRUE);
   1.432 +            hostInfo = NULL;
   1.433 +            fprintf(stderr, "\n");
   1.434 +        }
   1.435 +    }
   1.436 +    if (requestCert)
   1.437 +	cert = SSL_PeerCertificate(fd);
   1.438 +    else
   1.439 +	cert = SSL_LocalCertificate(fd);
   1.440 +    if (cert) {
   1.441 +	char * ip = CERT_NameToAscii(&cert->issuer);
   1.442 +	char * sp = CERT_NameToAscii(&cert->subject);
   1.443 +        if (sp) {
   1.444 +	    FPRINTF(stderr, "selfserv: subject DN: %s\n", sp);
   1.445 +	    PORT_Free(sp);
   1.446 +	}
   1.447 +        if (ip) {
   1.448 +	    FPRINTF(stderr, "selfserv: issuer  DN: %s\n", ip);
   1.449 +	    PORT_Free(ip);
   1.450 +	}
   1.451 +	CERT_DestroyCertificate(cert);
   1.452 +	cert = NULL;
   1.453 +    }
   1.454 +    FLUSH;
   1.455 +}
   1.456 +
   1.457 +static int MakeCertOK;
   1.458 +
   1.459 +static SECStatus
   1.460 +myBadCertHandler( void *arg, PRFileDesc *fd)
   1.461 +{
   1.462 +    int err = PR_GetError();
   1.463 +    if (!MakeCertOK)
   1.464 +	fprintf(stderr, 
   1.465 +	    "selfserv: -- SSL: Client Certificate Invalid, err %d.\n%s\n", 
   1.466 +            err, SECU_Strerror(err));
   1.467 +    return (MakeCertOK ? SECSuccess : SECFailure);
   1.468 +}
   1.469 +
   1.470 +#define MAX_VIRT_SERVER_NAME_ARRAY_INDEX  10
   1.471 +
   1.472 +/* Simple SNI socket config function that does not use SSL_ReconfigFD.
   1.473 + * Only uses one server name but verifies that the names match. */
   1.474 +PRInt32 
   1.475 +mySSLSNISocketConfig(PRFileDesc *fd, const SECItem *sniNameArr,
   1.476 +                     PRUint32 sniNameArrSize, void *arg)
   1.477 +{
   1.478 +    PRInt32        i = 0;
   1.479 +    const SECItem *current = sniNameArr;
   1.480 +    const char    **nameArr = (const char**)arg;
   1.481 +    secuPWData *pwdata;
   1.482 +    CERTCertificate *    cert = NULL;
   1.483 +    SECKEYPrivateKey *   privKey = NULL;
   1.484 +
   1.485 +    PORT_Assert(fd && sniNameArr);
   1.486 +    if (!fd || !sniNameArr) {
   1.487 +	return SSL_SNI_SEND_ALERT;
   1.488 +    }
   1.489 +
   1.490 +    pwdata = SSL_RevealPinArg(fd);
   1.491 +
   1.492 +    for (;current && i < sniNameArrSize;i++) {
   1.493 +        int j = 0;
   1.494 +        for (;j < MAX_VIRT_SERVER_NAME_ARRAY_INDEX && nameArr[j];j++) {
   1.495 +            if (!PORT_Strncmp(nameArr[j],
   1.496 +                              (const char *)current[i].data,
   1.497 +                              current[i].len) &&
   1.498 +                PORT_Strlen(nameArr[j]) == current[i].len) {
   1.499 +                const char *nickName = nameArr[j];
   1.500 +                if (j == 0) {
   1.501 +                    /* default cert */
   1.502 +                    return 0;
   1.503 +                }
   1.504 +                /* if pwdata is NULL, then we would not get the key and
   1.505 +                 * return an error status. */
   1.506 +                cert = PK11_FindCertFromNickname(nickName, &pwdata);
   1.507 +                if (cert == NULL) {
   1.508 +                    goto loser; /* Send alert */
   1.509 +                }
   1.510 +                privKey = PK11_FindKeyByAnyCert(cert, &pwdata);
   1.511 +                if (privKey == NULL) {
   1.512 +                    goto loser; /* Send alert */
   1.513 +                }
   1.514 +                if (SSL_ConfigSecureServer(fd, cert, privKey,
   1.515 +                                           kt_rsa) != SECSuccess) {
   1.516 +                    goto loser; /* Send alert */
   1.517 +                }
   1.518 +                SECKEY_DestroyPrivateKey(privKey);
   1.519 +                CERT_DestroyCertificate(cert);
   1.520 +                return i;
   1.521 +            }
   1.522 +        }
   1.523 +    }
   1.524 +loser:
   1.525 +    if (privKey) {
   1.526 +        SECKEY_DestroyPrivateKey(privKey);
   1.527 +    }
   1.528 +    if (cert) {
   1.529 +        CERT_DestroyCertificate(cert);
   1.530 +    }
   1.531 +    return SSL_SNI_SEND_ALERT;
   1.532 +}
   1.533 +
   1.534 +
   1.535 +/**************************************************************************
   1.536 +** Begin thread management routines and data.
   1.537 +**************************************************************************/
   1.538 +#define MIN_THREADS 3
   1.539 +#define DEFAULT_THREADS 8
   1.540 +#define MAX_THREADS 4096
   1.541 +#define MAX_PROCS 25
   1.542 +static int  maxThreads = DEFAULT_THREADS;
   1.543 +
   1.544 +
   1.545 +typedef struct jobStr {
   1.546 +    PRCList     link;
   1.547 +    PRFileDesc *tcp_sock;
   1.548 +    PRFileDesc *model_sock;
   1.549 +    int         requestCert;
   1.550 +} JOB;
   1.551 +
   1.552 +static PZLock    * qLock; /* this lock protects all data immediately below */
   1.553 +static PRLock    * lastLoadedCrlLock; /* this lock protects lastLoadedCrl variable */
   1.554 +static PZCondVar * jobQNotEmptyCv;
   1.555 +static PZCondVar * freeListNotEmptyCv;
   1.556 +static PZCondVar * threadCountChangeCv;
   1.557 +static int  threadCount;
   1.558 +static PRCList  jobQ;
   1.559 +static PRCList  freeJobs;
   1.560 +static JOB *jobTable;
   1.561 +
   1.562 +SECStatus
   1.563 +setupJobs(int maxJobs)
   1.564 +{
   1.565 +    int i;
   1.566 +
   1.567 +    jobTable = (JOB *)PR_Calloc(maxJobs, sizeof(JOB));
   1.568 +    if (!jobTable)
   1.569 +    	return SECFailure;
   1.570 +
   1.571 +    PR_INIT_CLIST(&jobQ);
   1.572 +    PR_INIT_CLIST(&freeJobs);
   1.573 +
   1.574 +    for (i = 0; i < maxJobs; ++i) {
   1.575 +	JOB * pJob = jobTable + i;
   1.576 +	PR_APPEND_LINK(&pJob->link, &freeJobs);
   1.577 +    }
   1.578 +    return SECSuccess;
   1.579 +}
   1.580 +
   1.581 +typedef int startFn(PRFileDesc *a, PRFileDesc *b, int c);
   1.582 +
   1.583 +typedef enum { rs_idle = 0, rs_running = 1, rs_zombie = 2 } runState;
   1.584 +
   1.585 +typedef struct perThreadStr {
   1.586 +    PRFileDesc *a;
   1.587 +    PRFileDesc *b;
   1.588 +    int         c;
   1.589 +    int         rv;
   1.590 +    startFn  *  startFunc;
   1.591 +    PRThread *  prThread;
   1.592 +    runState	state;
   1.593 +} perThread;
   1.594 +
   1.595 +static perThread *threads;
   1.596 +
   1.597 +void
   1.598 +thread_wrapper(void * arg)
   1.599 +{
   1.600 +    perThread * slot = (perThread *)arg;
   1.601 +
   1.602 +    slot->rv = (* slot->startFunc)(slot->a, slot->b, slot->c);
   1.603 +
   1.604 +    /* notify the thread exit handler. */
   1.605 +    PZ_Lock(qLock);
   1.606 +    slot->state = rs_zombie;
   1.607 +    --threadCount;
   1.608 +    PZ_NotifyAllCondVar(threadCountChangeCv);
   1.609 +    PZ_Unlock(qLock);
   1.610 +}
   1.611 +
   1.612 +int 
   1.613 +jobLoop(PRFileDesc *a, PRFileDesc *b, int c)
   1.614 +{
   1.615 +    PRCList * myLink = 0;
   1.616 +    JOB     * myJob;
   1.617 +
   1.618 +    PZ_Lock(qLock);
   1.619 +    do {
   1.620 +	myLink = 0;
   1.621 +	while (PR_CLIST_IS_EMPTY(&jobQ) && !stopping) {
   1.622 +            PZ_WaitCondVar(jobQNotEmptyCv, PR_INTERVAL_NO_TIMEOUT);
   1.623 +	}
   1.624 +	if (!PR_CLIST_IS_EMPTY(&jobQ)) {
   1.625 +	    myLink = PR_LIST_HEAD(&jobQ);
   1.626 +	    PR_REMOVE_AND_INIT_LINK(myLink);
   1.627 +	}
   1.628 +	PZ_Unlock(qLock);
   1.629 +	myJob = (JOB *)myLink;
   1.630 +	/* myJob will be null when stopping is true and jobQ is empty */
   1.631 +	if (!myJob) 
   1.632 +	    break;
   1.633 +	handle_connection( myJob->tcp_sock, myJob->model_sock, 
   1.634 +			   myJob->requestCert);
   1.635 +	PZ_Lock(qLock);
   1.636 +	PR_APPEND_LINK(myLink, &freeJobs);
   1.637 +	PZ_NotifyCondVar(freeListNotEmptyCv);
   1.638 +    } while (PR_TRUE);
   1.639 +    return 0;
   1.640 +}
   1.641 +
   1.642 +
   1.643 +SECStatus
   1.644 +launch_threads(
   1.645 +    startFn    *startFunc,
   1.646 +    PRFileDesc *a,
   1.647 +    PRFileDesc *b,
   1.648 +    int         c,
   1.649 +    PRBool      local)
   1.650 +{
   1.651 +    int i;
   1.652 +    SECStatus rv = SECSuccess;
   1.653 +
   1.654 +    /* create the thread management serialization structs */
   1.655 +    qLock               = PZ_NewLock(nssILockSelfServ);
   1.656 +    jobQNotEmptyCv      = PZ_NewCondVar(qLock);
   1.657 +    freeListNotEmptyCv  = PZ_NewCondVar(qLock);
   1.658 +    threadCountChangeCv = PZ_NewCondVar(qLock);
   1.659 +
   1.660 +    /* create monitor for crl reload procedure */
   1.661 +    lastLoadedCrlLock   = PR_NewLock();
   1.662 +
   1.663 +    /* allocate the array of thread slots */
   1.664 +    threads = PR_Calloc(maxThreads, sizeof(perThread));
   1.665 +    if ( NULL == threads )  {
   1.666 +        fprintf(stderr, "Oh Drat! Can't allocate the perThread array\n");
   1.667 +        return SECFailure;
   1.668 +    }
   1.669 +    /* 5 is a little extra, intended to keep the jobQ from underflowing. 
   1.670 +    ** That is, from going empty while not stopping and clients are still
   1.671 +    ** trying to contact us.
   1.672 +    */
   1.673 +    rv = setupJobs(maxThreads + 5);
   1.674 +    if (rv != SECSuccess)
   1.675 +    	return rv;
   1.676 +
   1.677 +    PZ_Lock(qLock);
   1.678 +    for (i = 0; i < maxThreads; ++i) {
   1.679 +    	perThread * slot = threads + i;
   1.680 +
   1.681 +	slot->state = rs_running;
   1.682 +	slot->a = a;
   1.683 +	slot->b = b;
   1.684 +	slot->c = c;
   1.685 +	slot->startFunc = startFunc;
   1.686 +	slot->prThread = PR_CreateThread(PR_USER_THREAD, 
   1.687 +			thread_wrapper, slot, PR_PRIORITY_NORMAL, 
   1.688 +                        (PR_TRUE==local)?PR_LOCAL_THREAD:PR_GLOBAL_THREAD,
   1.689 +                        PR_UNJOINABLE_THREAD, 0);
   1.690 +	if (slot->prThread == NULL) {
   1.691 +	    printf("selfserv: Failed to launch thread!\n");
   1.692 +	    slot->state = rs_idle;
   1.693 +	    rv = SECFailure;
   1.694 +	    break;
   1.695 +	} 
   1.696 +
   1.697 +	++threadCount;
   1.698 +    }
   1.699 +    PZ_Unlock(qLock); 
   1.700 +
   1.701 +    return rv;
   1.702 +}
   1.703 +
   1.704 +#define DESTROY_CONDVAR(name) if (name) { \
   1.705 +        PZ_DestroyCondVar(name); name = NULL; }
   1.706 +#define DESTROY_LOCK(name) if (name) { \
   1.707 +        PZ_DestroyLock(name); name = NULL; }
   1.708 +	
   1.709 +
   1.710 +void
   1.711 +terminateWorkerThreads(void)
   1.712 +{
   1.713 +    VLOG(("selfserv: server_thead: waiting on stopping"));
   1.714 +    PZ_Lock(qLock);
   1.715 +    PZ_NotifyAllCondVar(jobQNotEmptyCv);
   1.716 +    while (threadCount > 0) {
   1.717 +	PZ_WaitCondVar(threadCountChangeCv, PR_INTERVAL_NO_TIMEOUT);
   1.718 +    }
   1.719 +    /* The worker threads empty the jobQ before they terminate. */
   1.720 +    PORT_Assert(PR_CLIST_IS_EMPTY(&jobQ));
   1.721 +    PZ_Unlock(qLock); 
   1.722 +
   1.723 +    DESTROY_CONDVAR(jobQNotEmptyCv);
   1.724 +    DESTROY_CONDVAR(freeListNotEmptyCv);
   1.725 +    DESTROY_CONDVAR(threadCountChangeCv);
   1.726 +
   1.727 +    PR_DestroyLock(lastLoadedCrlLock);
   1.728 +    DESTROY_LOCK(qLock);
   1.729 +    PR_Free(jobTable);
   1.730 +    PR_Free(threads);
   1.731 +}
   1.732 +
   1.733 +static void 
   1.734 +logger(void *arg)
   1.735 +{
   1.736 +    PRFloat64 seconds;
   1.737 +    PRFloat64 opsPerSec;
   1.738 +    PRIntervalTime period;
   1.739 +    PRIntervalTime previousTime;
   1.740 +    PRIntervalTime latestTime;
   1.741 +    PRUint32 previousOps;
   1.742 +    PRUint32 ops;
   1.743 +    PRIntervalTime logPeriodTicks = PR_TicksPerSecond();
   1.744 +    PRFloat64 secondsPerTick = 1.0 / (PRFloat64)logPeriodTicks;
   1.745 +    int iterations = 0;
   1.746 +    int secondsElapsed = 0;
   1.747 +    static PRInt64 totalPeriodBytes = 0;
   1.748 +    static PRInt64 totalPeriodBytesTCP = 0;
   1.749 +
   1.750 +    previousOps = loggerOps;
   1.751 +    previousTime = PR_IntervalNow();
   1.752 + 
   1.753 +    for (;;) {
   1.754 +        /* OK, implementing a new sleep algorithm here... always sleep 
   1.755 +         * for 1 second but print out info at the user-specified interval.
   1.756 +         * This way, we don't overflow all of our PR_Atomic* functions and 
   1.757 +         * we don't have to use locks. 
   1.758 +         */
   1.759 +        PR_Sleep(logPeriodTicks);
   1.760 +        secondsElapsed++;
   1.761 +        totalPeriodBytes +=  PR_ATOMIC_SET(&loggerBytes, 0);
   1.762 +        totalPeriodBytesTCP += PR_ATOMIC_SET(&loggerBytesTCP, 0);
   1.763 +        if (secondsElapsed != logPeriod) {
   1.764 +            continue;
   1.765 +        }
   1.766 +        /* when we reach the user-specified logging interval, print out all
   1.767 +         * data 
   1.768 +         */
   1.769 +        secondsElapsed = 0;
   1.770 +        latestTime = PR_IntervalNow();
   1.771 +        ops = loggerOps;
   1.772 +        period = latestTime - previousTime;
   1.773 +        seconds = (PRFloat64) period*secondsPerTick;
   1.774 +        opsPerSec = (ops - previousOps) / seconds;
   1.775 +
   1.776 +        if (testBulk) {
   1.777 +            if (iterations == 0) {
   1.778 +                if (loggingLayer == PR_TRUE) {
   1.779 +                    printf("Conn.--------App Data--------TCP Data\n");
   1.780 +                } else {
   1.781 +                    printf("Conn.--------App Data\n");
   1.782 +                }
   1.783 +            }
   1.784 +            if (loggingLayer == PR_TRUE) {
   1.785 +                printf("%4.d       %5.3f MB/s      %5.3f MB/s\n", ops, 
   1.786 +                    totalPeriodBytes / (seconds * 1048576.0), 
   1.787 +                    totalPeriodBytesTCP / (seconds * 1048576.0));
   1.788 +            } else {
   1.789 +                printf("%4.d       %5.3f MB/s\n", ops, 
   1.790 +                    totalPeriodBytes / (seconds * 1048576.0));
   1.791 +            }
   1.792 +            totalPeriodBytes = 0;
   1.793 +            totalPeriodBytesTCP = 0;
   1.794 +            /* Print the "legend" every 20 iterations */
   1.795 +            iterations = (iterations + 1) % 20; 
   1.796 +        } else {
   1.797 +            printf("%.2f ops/second, %d threads\n", opsPerSec, threadCount);
   1.798 +        }
   1.799 +
   1.800 +        fflush(stdout);
   1.801 +        previousOps = ops;
   1.802 +        previousTime = latestTime;
   1.803 +        if (stopping) {
   1.804 +            break;
   1.805 +        }
   1.806 +    }
   1.807 +}
   1.808 +
   1.809 +
   1.810 +/**************************************************************************
   1.811 +** End   thread management routines.
   1.812 +**************************************************************************/
   1.813 +
   1.814 +PRBool useModelSocket  = PR_FALSE;
   1.815 +static SSLVersionRange enabledVersions;
   1.816 +PRBool enableSSL2      = PR_TRUE;
   1.817 +PRBool disableRollBack = PR_FALSE;
   1.818 +PRBool NoReuse         = PR_FALSE;
   1.819 +PRBool hasSidCache     = PR_FALSE;
   1.820 +PRBool disableStepDown = PR_FALSE;
   1.821 +PRBool bypassPKCS11    = PR_FALSE;
   1.822 +PRBool disableLocking  = PR_FALSE;
   1.823 +PRBool testbypass      = PR_FALSE;
   1.824 +PRBool enableSessionTickets = PR_FALSE;
   1.825 +PRBool enableCompression    = PR_FALSE;
   1.826 +PRBool failedToNegotiateName  = PR_FALSE;
   1.827 +static char  *virtServerNameArray[MAX_VIRT_SERVER_NAME_ARRAY_INDEX];
   1.828 +static int                  virtServerNameIndex = 1;
   1.829 +
   1.830 +
   1.831 +static const char stopCmd[] = { "GET /stop " };
   1.832 +static const char getCmd[]  = { "GET " };
   1.833 +static const char EOFmsg[]  = { "EOF\r\n\r\n\r\n" };
   1.834 +static const char outHeader[] = {
   1.835 +    "HTTP/1.0 200 OK\r\n"
   1.836 +    "Server: Generic Web Server\r\n"
   1.837 +    "Date: Tue, 26 Aug 1997 22:10:05 GMT\r\n"
   1.838 +    "Content-type: text/plain\r\n"
   1.839 +    "\r\n"
   1.840 +};
   1.841 +static const char crlCacheErr[]  = { "CRL ReCache Error: " };
   1.842 +
   1.843 +PRUint16 cipherlist[100];
   1.844 +int nciphers;
   1.845 +
   1.846 +void
   1.847 +savecipher(int c)
   1.848 +{
   1.849 +    if (nciphers < sizeof cipherlist / sizeof (cipherlist[0]))
   1.850 +	cipherlist[nciphers++] = (PRUint16)c;
   1.851 +}
   1.852 +
   1.853 +
   1.854 +#ifdef FULL_DUPLEX_CAPABLE
   1.855 +
   1.856 +struct lockedVarsStr {
   1.857 +    PZLock *	lock;
   1.858 +    int		count;
   1.859 +    int		waiters;
   1.860 +    PZCondVar *	condVar;
   1.861 +};
   1.862 +
   1.863 +typedef struct lockedVarsStr lockedVars;
   1.864 +
   1.865 +void 
   1.866 +lockedVars_Init( lockedVars * lv)
   1.867 +{
   1.868 +    lv->count   = 0;
   1.869 +    lv->waiters = 0;
   1.870 +    lv->lock    = PZ_NewLock(nssILockSelfServ);
   1.871 +    lv->condVar = PZ_NewCondVar(lv->lock);
   1.872 +}
   1.873 +
   1.874 +void
   1.875 +lockedVars_Destroy( lockedVars * lv)
   1.876 +{
   1.877 +    PZ_DestroyCondVar(lv->condVar);
   1.878 +    lv->condVar = NULL;
   1.879 +
   1.880 +    PZ_DestroyLock(lv->lock);
   1.881 +    lv->lock = NULL;
   1.882 +}
   1.883 +
   1.884 +void
   1.885 +lockedVars_WaitForDone(lockedVars * lv)
   1.886 +{
   1.887 +    PZ_Lock(lv->lock);
   1.888 +    while (lv->count > 0) {
   1.889 +    	PZ_WaitCondVar(lv->condVar, PR_INTERVAL_NO_TIMEOUT);
   1.890 +    }
   1.891 +    PZ_Unlock(lv->lock);
   1.892 +}
   1.893 +
   1.894 +int	/* returns count */
   1.895 +lockedVars_AddToCount(lockedVars * lv, int addend)
   1.896 +{
   1.897 +    int rv;
   1.898 +
   1.899 +    PZ_Lock(lv->lock);
   1.900 +    rv = lv->count += addend;
   1.901 +    if (rv <= 0) {
   1.902 +	PZ_NotifyCondVar(lv->condVar);
   1.903 +    }
   1.904 +    PZ_Unlock(lv->lock);
   1.905 +    return rv;
   1.906 +}
   1.907 +
   1.908 +int
   1.909 +do_writes(
   1.910 +    PRFileDesc *	ssl_sock,
   1.911 +    PRFileDesc *	model_sock,
   1.912 +    int         	requestCert
   1.913 +    )
   1.914 +{
   1.915 +    int			sent  = 0;
   1.916 +    int 		count = 0;
   1.917 +    lockedVars *	lv = (lockedVars *)model_sock;
   1.918 +
   1.919 +    VLOG(("selfserv: do_writes: starting"));
   1.920 +    while (sent < bigBuf.len) {
   1.921 +
   1.922 +	count = PR_Write(ssl_sock, bigBuf.data + sent, bigBuf.len - sent);
   1.923 +	if (count < 0) {
   1.924 +	    errWarn("PR_Write bigBuf");
   1.925 +	    break;
   1.926 +	}
   1.927 +	FPRINTF(stderr, "selfserv: PR_Write wrote %d bytes from bigBuf\n", count );
   1.928 +	sent += count;
   1.929 +    }
   1.930 +    if (count >= 0) {	/* last write didn't fail. */
   1.931 +    	PR_Shutdown(ssl_sock, PR_SHUTDOWN_SEND);
   1.932 +    }
   1.933 +
   1.934 +    /* notify the reader that we're done. */
   1.935 +    lockedVars_AddToCount(lv, -1);
   1.936 +    FLUSH;
   1.937 +    VLOG(("selfserv: do_writes: exiting"));
   1.938 +    return (sent < bigBuf.len) ? SECFailure : SECSuccess;
   1.939 +}
   1.940 +
   1.941 +static int 
   1.942 +handle_fdx_connection(
   1.943 +    PRFileDesc *       tcp_sock,
   1.944 +    PRFileDesc *       model_sock,
   1.945 +    int                requestCert
   1.946 +    )
   1.947 +{
   1.948 +    PRFileDesc *       ssl_sock	= NULL;
   1.949 +    SECStatus          result;
   1.950 +    int                firstTime = 1;
   1.951 +    lockedVars         lv;
   1.952 +    PRSocketOptionData opt;
   1.953 +    char               buf[10240];
   1.954 +
   1.955 +
   1.956 +    VLOG(("selfserv: handle_fdx_connection: starting"));
   1.957 +    opt.option             = PR_SockOpt_Nonblocking;
   1.958 +    opt.value.non_blocking = PR_FALSE;
   1.959 +    PR_SetSocketOption(tcp_sock, &opt);
   1.960 +
   1.961 +    if (useModelSocket && model_sock) {
   1.962 +	SECStatus rv;
   1.963 +	ssl_sock = SSL_ImportFD(model_sock, tcp_sock);
   1.964 +	if (!ssl_sock) {
   1.965 +	    errWarn("SSL_ImportFD with model");
   1.966 +	    goto cleanup;
   1.967 +	}
   1.968 +	rv = SSL_ResetHandshake(ssl_sock, /* asServer */ 1);
   1.969 +	if (rv != SECSuccess) {
   1.970 +	    errWarn("SSL_ResetHandshake");
   1.971 +	    goto cleanup;
   1.972 +	}
   1.973 +    } else {
   1.974 +	ssl_sock = tcp_sock;
   1.975 +    }
   1.976 +
   1.977 +    lockedVars_Init(&lv);
   1.978 +    lockedVars_AddToCount(&lv, 1);
   1.979 +
   1.980 +    /* Attempt to launch the writer thread. */
   1.981 +    result = launch_thread(do_writes, ssl_sock, (PRFileDesc *)&lv, 
   1.982 +                           requestCert);
   1.983 +
   1.984 +    if (result == SECSuccess) 
   1.985 +      do {
   1.986 +	/* do reads here. */
   1.987 +	int count;
   1.988 +	count = PR_Read(ssl_sock, buf, sizeof buf);
   1.989 +	if (count < 0) {
   1.990 +	    errWarn("FDX PR_Read");
   1.991 +	    break;
   1.992 +	}
   1.993 +	FPRINTF(stderr, "selfserv: FDX PR_Read read %d bytes.\n", count );
   1.994 +	if (firstTime) {
   1.995 +	    firstTime = 0;
   1.996 +	    printSecurityInfo(ssl_sock);
   1.997 +	}
   1.998 +    } while (lockedVars_AddToCount(&lv, 0) > 0);
   1.999 +
  1.1000 +    /* Wait for writer to finish */
  1.1001 +    lockedVars_WaitForDone(&lv);
  1.1002 +    lockedVars_Destroy(&lv);
  1.1003 +    FLUSH;
  1.1004 +
  1.1005 +cleanup:
  1.1006 +    if (ssl_sock) {
  1.1007 +	PR_Close(ssl_sock);
  1.1008 +    } else if (tcp_sock) {
  1.1009 +	PR_Close(tcp_sock);
  1.1010 +    }
  1.1011 +
  1.1012 +    VLOG(("selfserv: handle_fdx_connection: exiting"));
  1.1013 +    return SECSuccess;
  1.1014 +}
  1.1015 +
  1.1016 +#endif
  1.1017 +
  1.1018 +static SECItem *lastLoadedCrl = NULL;
  1.1019 +
  1.1020 +static SECStatus
  1.1021 +reload_crl(PRFileDesc *crlFile)
  1.1022 +{
  1.1023 +    SECItem *crlDer;
  1.1024 +    CERTCertDBHandle *certHandle = CERT_GetDefaultCertDB();
  1.1025 +    SECStatus rv;
  1.1026 +
  1.1027 +    /* Read in the entire file specified with the -f argument */
  1.1028 +    crlDer = PORT_Malloc(sizeof(SECItem));
  1.1029 +    if (!crlDer) {
  1.1030 +        errWarn("Can not allocate memory.");
  1.1031 +        return SECFailure;
  1.1032 +    }
  1.1033 +
  1.1034 +    rv = SECU_ReadDERFromFile(crlDer, crlFile, PR_FALSE, PR_FALSE);
  1.1035 +    if (rv != SECSuccess) {
  1.1036 +        errWarn("Unable to read input file.");
  1.1037 +        PORT_Free(crlDer);
  1.1038 +        return SECFailure;
  1.1039 +    }
  1.1040 +
  1.1041 +    PR_Lock(lastLoadedCrlLock);
  1.1042 +    rv = CERT_CacheCRL(certHandle, crlDer);
  1.1043 +    if (rv == SECSuccess) {
  1.1044 +        SECItem *tempItem = crlDer;
  1.1045 +        if (lastLoadedCrl != NULL) {
  1.1046 +            rv = CERT_UncacheCRL(certHandle, lastLoadedCrl);
  1.1047 +            if (rv != SECSuccess) {
  1.1048 +                errWarn("Unable to uncache crl.");
  1.1049 +                goto loser;
  1.1050 +            }
  1.1051 +            crlDer = lastLoadedCrl;
  1.1052 +        } else {
  1.1053 +            crlDer = NULL;
  1.1054 +        }
  1.1055 +        lastLoadedCrl = tempItem;
  1.1056 +    }
  1.1057 +
  1.1058 +  loser:
  1.1059 +    PR_Unlock(lastLoadedCrlLock);
  1.1060 +    SECITEM_FreeItem(crlDer, PR_TRUE);
  1.1061 +    return rv;
  1.1062 +}
  1.1063 +
  1.1064 +void stop_server()
  1.1065 +{
  1.1066 +    stopping = 1;
  1.1067 +    PR_Interrupt(acceptorThread);
  1.1068 +    PZ_TraceFlush();
  1.1069 +}
  1.1070 +
  1.1071 +SECItemArray *
  1.1072 +makeTryLaterOCSPResponse(PLArenaPool *arena)
  1.1073 +{
  1.1074 +    SECItemArray *result = NULL;
  1.1075 +    SECItem *ocspResponse = NULL;
  1.1076 +
  1.1077 +    ocspResponse = CERT_CreateEncodedOCSPErrorResponse(arena,
  1.1078 +					SEC_ERROR_OCSP_TRY_SERVER_LATER);
  1.1079 +    if (!ocspResponse)
  1.1080 +	errExit("cannot created ocspResponse");
  1.1081 +
  1.1082 +    result = SECITEM_AllocArray(arena, NULL, 1);
  1.1083 +    if (!result)
  1.1084 +	errExit("cannot allocate multiOcspResponses");
  1.1085 +
  1.1086 +    result->items[0].data = ocspResponse->data;
  1.1087 +    result->items[0].len = ocspResponse->len;
  1.1088 +
  1.1089 +    return result;
  1.1090 +}
  1.1091 +
  1.1092 +SECItemArray *
  1.1093 +makeCorruptedOCSPResponse(PLArenaPool *arena)
  1.1094 +{
  1.1095 +    SECItemArray *result = NULL;
  1.1096 +    SECItem *ocspResponse = NULL;
  1.1097 +
  1.1098 +    ocspResponse = SECITEM_AllocItem(arena, NULL, 1);
  1.1099 +    if (!ocspResponse)
  1.1100 +	errExit("cannot created ocspResponse");
  1.1101 +
  1.1102 +    result = SECITEM_AllocArray(arena, NULL, 1);
  1.1103 +    if (!result)
  1.1104 +	errExit("cannot allocate multiOcspResponses");
  1.1105 +
  1.1106 +    result->items[0].data = ocspResponse->data;
  1.1107 +    result->items[0].len = ocspResponse->len;
  1.1108 +
  1.1109 +    return result;
  1.1110 +}
  1.1111 +
  1.1112 +SECItemArray *
  1.1113 +makeSignedOCSPResponse(PLArenaPool *arena, ocspStaplingModeType osm,
  1.1114 +		       CERTCertificate *cert, secuPWData *pwdata)
  1.1115 +{
  1.1116 +    SECItemArray *result = NULL;
  1.1117 +    SECItem *ocspResponse = NULL;
  1.1118 +    CERTOCSPSingleResponse **singleResponses;
  1.1119 +    CERTOCSPSingleResponse *sr;
  1.1120 +    CERTOCSPCertID *cid = NULL;
  1.1121 +    CERTCertificate *ca;
  1.1122 +    PRTime now = PR_Now();
  1.1123 +    PRTime nextUpdate;
  1.1124 +
  1.1125 +    PORT_Assert(cert != NULL);
  1.1126 +
  1.1127 +    ca = CERT_FindCertByNickname(CERT_GetDefaultCertDB(), ocspStaplingCA);
  1.1128 +    if (!ca)
  1.1129 +	errExit("cannot find CA");
  1.1130 +
  1.1131 +    cid = CERT_CreateOCSPCertID(cert, now);
  1.1132 +    if (!cid)
  1.1133 +	errExit("cannot created cid");
  1.1134 +
  1.1135 +    nextUpdate = now + 60*60*24 * PR_USEC_PER_SEC; /* plus 1 day */
  1.1136 +
  1.1137 +    switch (osm) {
  1.1138 +	case osm_good:
  1.1139 +	case osm_badsig:
  1.1140 +	    sr = CERT_CreateOCSPSingleResponseGood(arena, cid, now,
  1.1141 +						   &nextUpdate);
  1.1142 +	    break;
  1.1143 +	case osm_unknown:
  1.1144 +	    sr = CERT_CreateOCSPSingleResponseUnknown(arena, cid, now,
  1.1145 +						      &nextUpdate);
  1.1146 +	    break;
  1.1147 +	case osm_revoked:
  1.1148 +	    sr = CERT_CreateOCSPSingleResponseRevoked(arena, cid, now,
  1.1149 +		&nextUpdate,
  1.1150 +		now - 60*60*24 * PR_USEC_PER_SEC, /* minus 1 day */
  1.1151 +		NULL);
  1.1152 +	    break;
  1.1153 +	default:
  1.1154 +	    PORT_Assert(0);
  1.1155 +	    break;
  1.1156 +    }
  1.1157 +
  1.1158 +    if (!sr)
  1.1159 +	errExit("cannot create sr");
  1.1160 +
  1.1161 +    /* meaning of value 2: one entry + one end marker */
  1.1162 +    singleResponses = PORT_ArenaNewArray(arena, CERTOCSPSingleResponse*, 2);
  1.1163 +    if (singleResponses == NULL)
  1.1164 +	errExit("cannot allocate singleResponses");
  1.1165 +
  1.1166 +    singleResponses[0] = sr;
  1.1167 +    singleResponses[1] = NULL;
  1.1168 +
  1.1169 +    ocspResponse = CERT_CreateEncodedOCSPSuccessResponse(arena,
  1.1170 +			(osm == osm_badsig) ? NULL : ca,
  1.1171 +			ocspResponderID_byName, now, singleResponses,
  1.1172 +			&pwdata);
  1.1173 +    if (!ocspResponse)
  1.1174 +	errExit("cannot created ocspResponse");
  1.1175 +
  1.1176 +    CERT_DestroyCertificate(ca);
  1.1177 +    ca = NULL;
  1.1178 +
  1.1179 +    result = SECITEM_AllocArray(arena, NULL, 1);
  1.1180 +    if (!result)
  1.1181 +	errExit("cannot allocate multiOcspResponses");
  1.1182 +
  1.1183 +    result->items[0].data = ocspResponse->data;
  1.1184 +    result->items[0].len = ocspResponse->len;
  1.1185 +
  1.1186 +    CERT_DestroyOCSPCertID(cid);
  1.1187 +    cid = NULL;
  1.1188 +
  1.1189 +    return result;
  1.1190 +}
  1.1191 +
  1.1192 +void
  1.1193 +setupCertStatus(PLArenaPool *arena, enum ocspStaplingModeEnum ocspStaplingMode,
  1.1194 +		CERTCertificate *cert, SSLKEAType kea, secuPWData *pwdata)
  1.1195 +{
  1.1196 +    if (ocspStaplingMode == osm_random) {
  1.1197 +	/* 6 different responses */
  1.1198 +	int r = rand() % 6;
  1.1199 +	switch (r) {
  1.1200 +	    case 0: ocspStaplingMode = osm_good; break;
  1.1201 +	    case 1: ocspStaplingMode = osm_revoked; break;
  1.1202 +	    case 2: ocspStaplingMode = osm_unknown; break;
  1.1203 +	    case 3: ocspStaplingMode = osm_badsig; break;
  1.1204 +	    case 4: ocspStaplingMode = osm_corrupted; break;
  1.1205 +	    case 5: ocspStaplingMode = osm_failure; break;
  1.1206 +	    default: PORT_Assert(0); break;
  1.1207 +	}
  1.1208 +    }
  1.1209 +    if (ocspStaplingMode != osm_disabled) {
  1.1210 +	SECItemArray *multiOcspResponses = NULL;
  1.1211 +	switch (ocspStaplingMode) {
  1.1212 +	    case osm_good:
  1.1213 +	    case osm_revoked:
  1.1214 +	    case osm_unknown:
  1.1215 +	    case osm_badsig:
  1.1216 +		multiOcspResponses =
  1.1217 +		    makeSignedOCSPResponse(arena, ocspStaplingMode, cert,
  1.1218 +					   pwdata);
  1.1219 +		break;
  1.1220 +	    case osm_corrupted:
  1.1221 +		multiOcspResponses = makeCorruptedOCSPResponse(arena);
  1.1222 +		break;
  1.1223 +	    case osm_failure:
  1.1224 +		multiOcspResponses = makeTryLaterOCSPResponse(arena);
  1.1225 +		break;
  1.1226 +	    case osm_ocsp:
  1.1227 +		errExit("stapling mode \"ocsp\" not implemented");
  1.1228 +		break;
  1.1229 +		break;
  1.1230 +	    default:
  1.1231 +		break;
  1.1232 +	}
  1.1233 +	if (multiOcspResponses) {
  1.1234 +	   certStatus[kea] = multiOcspResponses;
  1.1235 +	}
  1.1236 +   }
  1.1237 +}
  1.1238 +
  1.1239 +int
  1.1240 +handle_connection( 
  1.1241 +    PRFileDesc *tcp_sock,
  1.1242 +    PRFileDesc *model_sock,
  1.1243 +    int         requestCert
  1.1244 +    )
  1.1245 +{
  1.1246 +    PRFileDesc *       ssl_sock = NULL;
  1.1247 +    PRFileDesc *       local_file_fd = NULL;
  1.1248 +    char  *            post;
  1.1249 +    char  *            pBuf;			/* unused space at end of buf */
  1.1250 +    const char *       errString;
  1.1251 +    PRStatus           status;
  1.1252 +    int                bufRem;			/* unused bytes at end of buf */
  1.1253 +    int                bufDat;			/* characters received in buf */
  1.1254 +    int                newln    = 0;		/* # of consecutive newlns */
  1.1255 +    int                firstTime = 1;
  1.1256 +    int                reqLen;
  1.1257 +    int                rv;
  1.1258 +    int                numIOVs;
  1.1259 +    PRSocketOptionData opt;
  1.1260 +    PRIOVec            iovs[16];
  1.1261 +    char               msgBuf[160];
  1.1262 +    char               buf[10240];
  1.1263 +    char               fileName[513];
  1.1264 +    char               proto[128];
  1.1265 +    PRDescIdentity     aboveLayer = PR_INVALID_IO_LAYER;
  1.1266 +    SSLKEAType  kea;
  1.1267 +
  1.1268 +    pBuf   = buf;
  1.1269 +    bufRem = sizeof buf;
  1.1270 +
  1.1271 +    VLOG(("selfserv: handle_connection: starting"));
  1.1272 +    opt.option             = PR_SockOpt_Nonblocking;
  1.1273 +    opt.value.non_blocking = PR_FALSE;
  1.1274 +    PR_SetSocketOption(tcp_sock, &opt);
  1.1275 +
  1.1276 +    VLOG(("selfserv: handle_connection: starting\n"));
  1.1277 +    if (useModelSocket && model_sock) {
  1.1278 +	SECStatus rv;
  1.1279 +	ssl_sock = SSL_ImportFD(model_sock, tcp_sock);
  1.1280 +	if (!ssl_sock) {
  1.1281 +	    errWarn("SSL_ImportFD with model");
  1.1282 +	    goto cleanup;
  1.1283 +	}
  1.1284 +	rv = SSL_ResetHandshake(ssl_sock, /* asServer */ 1);
  1.1285 +	if (rv != SECSuccess) {
  1.1286 +	    errWarn("SSL_ResetHandshake");
  1.1287 +	    goto cleanup;
  1.1288 +	}
  1.1289 +    } else {
  1.1290 +	ssl_sock = tcp_sock;
  1.1291 +    }
  1.1292 +
  1.1293 +    for (kea = kt_rsa; kea < kt_kea_size; kea++) {
  1.1294 +       if (certStatus[kea] != NULL) {
  1.1295 +           SSL_SetStapledOCSPResponses(ssl_sock, certStatus[kea], kea);
  1.1296 +       }
  1.1297 +    }
  1.1298 +
  1.1299 +    if (loggingLayer) {
  1.1300 +        /* find the layer where our new layer is to be pushed */
  1.1301 +        aboveLayer = PR_GetLayersIdentity(ssl_sock->lower);
  1.1302 +        if (aboveLayer == PR_INVALID_IO_LAYER) {
  1.1303 +            errExit("PRGetUniqueIdentity");
  1.1304 +        }
  1.1305 +        /* create the new layer - this is a very cheap operation */
  1.1306 +        loggingFD = PR_CreateIOLayerStub(log_layer_id, &loggingMethods);
  1.1307 +        if (!loggingFD)
  1.1308 +            errExit("PR_CreateIOLayerStub");
  1.1309 +        /* push the layer below ssl but above TCP */
  1.1310 +        rv = PR_PushIOLayer(ssl_sock, aboveLayer, loggingFD);
  1.1311 +        if (rv != PR_SUCCESS) {
  1.1312 +            errExit("PR_PushIOLayer");
  1.1313 +        }
  1.1314 +    }
  1.1315 +
  1.1316 +    if (noDelay) {
  1.1317 +	opt.option         = PR_SockOpt_NoDelay;
  1.1318 +	opt.value.no_delay = PR_TRUE;
  1.1319 +	status = PR_SetSocketOption(ssl_sock, &opt);
  1.1320 +	if (status != PR_SUCCESS) {
  1.1321 +	    errWarn("PR_SetSocketOption(PR_SockOpt_NoDelay, PR_TRUE)");
  1.1322 +            if (ssl_sock) {
  1.1323 +	        PR_Close(ssl_sock);
  1.1324 +            }
  1.1325 +	    return SECFailure;
  1.1326 +	}
  1.1327 +    }
  1.1328 +
  1.1329 +    while (1) {
  1.1330 +	newln = 0;
  1.1331 +	reqLen     = 0;
  1.1332 +	rv = PR_Read(ssl_sock, pBuf, bufRem - 1);
  1.1333 +	if (rv == 0 || 
  1.1334 +	    (rv < 0 && PR_END_OF_FILE_ERROR == PR_GetError())) {
  1.1335 +	    if (verbose)
  1.1336 +		errWarn("HDX PR_Read hit EOF");
  1.1337 +	    break;
  1.1338 +	}
  1.1339 +	if (rv < 0) {
  1.1340 +	    errWarn("HDX PR_Read");
  1.1341 +	    goto cleanup;
  1.1342 +	}
  1.1343 +	/* NULL termination */
  1.1344 +	pBuf[rv] = 0;
  1.1345 +	if (firstTime) {
  1.1346 +	    firstTime = 0;
  1.1347 +	    printSecurityInfo(ssl_sock);
  1.1348 +	}
  1.1349 +
  1.1350 +	pBuf   += rv;
  1.1351 +	bufRem -= rv;
  1.1352 +	bufDat = pBuf - buf;
  1.1353 +	/* Parse the input, starting at the beginning of the buffer.
  1.1354 +	 * Stop when we detect two consecutive \n's (or \r\n's) 
  1.1355 +	 * as this signifies the end of the GET or POST portion.
  1.1356 +	 * The posted data follows.
  1.1357 +	 */
  1.1358 +	while (reqLen < bufDat && newln < 2) {
  1.1359 +	    int octet = buf[reqLen++];
  1.1360 +	    if (octet == '\n') {
  1.1361 +		newln++;
  1.1362 +	    } else if (octet != '\r') {
  1.1363 +		newln = 0;
  1.1364 +	    }
  1.1365 +	}
  1.1366 +
  1.1367 +	/* came to the end of the buffer, or second newln
  1.1368 +	 * If we didn't get an empty line (CRLFCRLF) then keep on reading.
  1.1369 +	 */
  1.1370 +	if (newln < 2) 
  1.1371 +	    continue;
  1.1372 +
  1.1373 +	/* we're at the end of the HTTP request.
  1.1374 +	 * If the request is a POST, then there will be one more
  1.1375 +	 * line of data.
  1.1376 +	 * This parsing is a hack, but ok for SSL test purposes.
  1.1377 +	 */
  1.1378 +	post = PORT_Strstr(buf, "POST ");
  1.1379 +	if (!post || *post != 'P') 
  1.1380 +	    break;
  1.1381 +
  1.1382 +	/* It's a post, so look for the next and final CR/LF. */
  1.1383 +	/* We should parse content length here, but ... */
  1.1384 +	while (reqLen < bufDat && newln < 3) {
  1.1385 +	    int octet = buf[reqLen++];
  1.1386 +	    if (octet == '\n') {
  1.1387 +		newln++;
  1.1388 +	    }
  1.1389 +	}
  1.1390 +	if (newln == 3)
  1.1391 +	    break;
  1.1392 +    } /* read loop */
  1.1393 +
  1.1394 +    bufDat = pBuf - buf;
  1.1395 +    if (bufDat) do {	/* just close if no data */
  1.1396 +	/* Have either (a) a complete get, (b) a complete post, (c) EOF */
  1.1397 +	if (reqLen > 0 && !strncmp(buf, getCmd, sizeof getCmd - 1)) {
  1.1398 +	    char *      fnBegin = buf + 4;
  1.1399 +	    char *      fnEnd;
  1.1400 +	    PRFileInfo  info;
  1.1401 +	    /* try to open the file named.  
  1.1402 +	     * If successful, then write it to the client.
  1.1403 +	     */
  1.1404 +	    fnEnd = strpbrk(fnBegin, " \r\n");
  1.1405 +	    if (fnEnd) {
  1.1406 +		int fnLen = fnEnd - fnBegin;
  1.1407 +		if (fnLen < sizeof fileName) {
  1.1408 +                    char *real_fileName = fileName;
  1.1409 +                    char *protoEnd = NULL;
  1.1410 +                    strncpy(fileName, fnBegin, fnLen);
  1.1411 +                    fileName[fnLen] = 0;	/* null terminate */
  1.1412 +                    if ((protoEnd = strstr(fileName, "://")) != NULL) {
  1.1413 +                        int protoLen = PR_MIN(protoEnd - fileName, sizeof(proto) - 1);
  1.1414 +                        PL_strncpy(proto, fileName, protoLen);
  1.1415 +                        proto[protoLen] = 0;
  1.1416 +                        real_fileName= protoEnd + 3;
  1.1417 +                    } else {
  1.1418 +                        proto[0] = 0;
  1.1419 +                    }
  1.1420 +		    status = PR_GetFileInfo(real_fileName, &info);
  1.1421 +		    if (status == PR_SUCCESS &&
  1.1422 +			info.type == PR_FILE_FILE &&
  1.1423 +			info.size >= 0 ) {
  1.1424 +			local_file_fd = PR_Open(real_fileName, PR_RDONLY, 0);
  1.1425 +		    }
  1.1426 +		}
  1.1427 +	    }
  1.1428 +	}
  1.1429 +	/* if user has requested client auth in a subsequent handshake,
  1.1430 +	 * do it here.
  1.1431 +	 */
  1.1432 +	if (requestCert > 2) { /* request cert was 3 or 4 */
  1.1433 +	    CERTCertificate *  cert =  SSL_PeerCertificate(ssl_sock);
  1.1434 +	    if (cert) {
  1.1435 +		CERT_DestroyCertificate(cert);
  1.1436 +	    } else {
  1.1437 +		rv = SSL_OptionSet(ssl_sock, SSL_REQUEST_CERTIFICATE, 1);
  1.1438 +		if (rv < 0) {
  1.1439 +		    errWarn("second SSL_OptionSet SSL_REQUEST_CERTIFICATE");
  1.1440 +		    break;
  1.1441 +		}
  1.1442 +		rv = SSL_OptionSet(ssl_sock, SSL_REQUIRE_CERTIFICATE, 
  1.1443 +				(requestCert == 4));
  1.1444 +		if (rv < 0) {
  1.1445 +		    errWarn("second SSL_OptionSet SSL_REQUIRE_CERTIFICATE");
  1.1446 +		    break;
  1.1447 +		}
  1.1448 +		rv = SSL_ReHandshake(ssl_sock, PR_TRUE);
  1.1449 +		if (rv != 0) {
  1.1450 +		    errWarn("SSL_ReHandshake");
  1.1451 +		    break;
  1.1452 +		}
  1.1453 +		rv = SSL_ForceHandshake(ssl_sock);
  1.1454 +		if (rv < 0) {
  1.1455 +		    errWarn("SSL_ForceHandshake");
  1.1456 +		    break;
  1.1457 +		}
  1.1458 +	    }
  1.1459 +	}
  1.1460 +
  1.1461 +	numIOVs = 0;
  1.1462 +
  1.1463 +	iovs[numIOVs].iov_base = (char *)outHeader;
  1.1464 +	iovs[numIOVs].iov_len  = (sizeof(outHeader)) - 1;
  1.1465 +	numIOVs++;
  1.1466 +
  1.1467 +	if (local_file_fd) {
  1.1468 +	    PRInt32     bytes;
  1.1469 +	    int         errLen;
  1.1470 +	    if (!PL_strlen(proto) || !PL_strcmp(proto, "file")) {
  1.1471 +                bytes = PR_TransmitFile(ssl_sock, local_file_fd, outHeader,
  1.1472 +                                        sizeof outHeader - 1,
  1.1473 +                                        PR_TRANSMITFILE_KEEP_OPEN,
  1.1474 +                                        PR_INTERVAL_NO_TIMEOUT);
  1.1475 +                if (bytes >= 0) {
  1.1476 +                    bytes -= sizeof outHeader - 1;
  1.1477 +                    FPRINTF(stderr, 
  1.1478 +                            "selfserv: PR_TransmitFile wrote %d bytes from %s\n",
  1.1479 +                            bytes, fileName);
  1.1480 +                    break;
  1.1481 +                }
  1.1482 +                errString = errWarn("PR_TransmitFile");
  1.1483 +                errLen = PORT_Strlen(errString);
  1.1484 +                errLen = PR_MIN(errLen, sizeof msgBuf - 1);
  1.1485 +                PORT_Memcpy(msgBuf, errString, errLen);
  1.1486 +                msgBuf[errLen] = 0;
  1.1487 +                
  1.1488 +                iovs[numIOVs].iov_base = msgBuf;
  1.1489 +                iovs[numIOVs].iov_len  = PORT_Strlen(msgBuf);
  1.1490 +                numIOVs++;
  1.1491 +            }
  1.1492 +            if (!PL_strcmp(proto, "crl")) {
  1.1493 +                if (reload_crl(local_file_fd) == SECFailure) {
  1.1494 +                    errString = errWarn("CERT_CacheCRL");
  1.1495 +                    if (!errString)
  1.1496 +                        errString = "Unknow error";
  1.1497 +                    PR_snprintf(msgBuf, sizeof(msgBuf), "%s%s ",
  1.1498 +                                crlCacheErr, errString);
  1.1499 +                    
  1.1500 +                    iovs[numIOVs].iov_base = msgBuf;
  1.1501 +                    iovs[numIOVs].iov_len  = PORT_Strlen(msgBuf);
  1.1502 +                    numIOVs++;
  1.1503 +                } else {
  1.1504 +                    FPRINTF(stderr, 
  1.1505 +                            "selfserv: CRL %s reloaded.\n",
  1.1506 +                            fileName);
  1.1507 +                    break;
  1.1508 +                }
  1.1509 +            }
  1.1510 +	} else if (reqLen <= 0) {	/* hit eof */
  1.1511 +	    PORT_Sprintf(msgBuf, "Get or Post incomplete after %d bytes.\r\n",
  1.1512 +			 bufDat);
  1.1513 +
  1.1514 +	    iovs[numIOVs].iov_base = msgBuf;
  1.1515 +	    iovs[numIOVs].iov_len  = PORT_Strlen(msgBuf);
  1.1516 +	    numIOVs++;
  1.1517 +	} else if (reqLen < bufDat) {
  1.1518 +	    PORT_Sprintf(msgBuf, "Discarded %d characters.\r\n", 
  1.1519 +	                 bufDat - reqLen);
  1.1520 +
  1.1521 +	    iovs[numIOVs].iov_base = msgBuf;
  1.1522 +	    iovs[numIOVs].iov_len  = PORT_Strlen(msgBuf);
  1.1523 +	    numIOVs++;
  1.1524 +	}
  1.1525 +
  1.1526 +	if (reqLen > 0) {
  1.1527 +	    if (verbose > 1) 
  1.1528 +	    	fwrite(buf, 1, reqLen, stdout);	/* display it */
  1.1529 +
  1.1530 +	    iovs[numIOVs].iov_base = buf;
  1.1531 +	    iovs[numIOVs].iov_len  = reqLen;
  1.1532 +	    numIOVs++;
  1.1533 +	}
  1.1534 +
  1.1535 +        /* Don't add the EOF if we want to test bulk encryption */
  1.1536 +        if (!testBulk) {
  1.1537 +            iovs[numIOVs].iov_base = (char *)EOFmsg;
  1.1538 +            iovs[numIOVs].iov_len  = sizeof EOFmsg - 1;
  1.1539 +            numIOVs++;
  1.1540 +        }
  1.1541 +
  1.1542 +	rv = PR_Writev(ssl_sock, iovs, numIOVs, PR_INTERVAL_NO_TIMEOUT);
  1.1543 +	if (rv < 0) {
  1.1544 +	    errWarn("PR_Writev");
  1.1545 +	    break;
  1.1546 +	}
  1.1547 +
  1.1548 +        /* Send testBulkTotal chunks to the client. Unlimited if 0. */
  1.1549 +        if (testBulk) {
  1.1550 +            while (0 < (rv = PR_Write(ssl_sock, testBulkBuf, testBulkSize))) {
  1.1551 +                PR_ATOMIC_ADD(&loggerBytes, rv);
  1.1552 +                PR_ATOMIC_INCREMENT(&bulkSentChunks);
  1.1553 +                if ((bulkSentChunks > testBulkTotal) && (testBulkTotal != 0))
  1.1554 +                    break;
  1.1555 +            }
  1.1556 +
  1.1557 +            /* There was a write error, so close this connection. */
  1.1558 +            if (bulkSentChunks <= testBulkTotal) {
  1.1559 +                errWarn("PR_Write");
  1.1560 +            }
  1.1561 +            PR_ATOMIC_DECREMENT(&loggerOps);
  1.1562 +            break;
  1.1563 +        }
  1.1564 +    } while (0);
  1.1565 +
  1.1566 +cleanup:
  1.1567 +    if (ssl_sock) {
  1.1568 +        PR_Close(ssl_sock);
  1.1569 +    } else if (tcp_sock) {
  1.1570 +        PR_Close(tcp_sock);
  1.1571 +    }
  1.1572 +    if (local_file_fd)
  1.1573 +	PR_Close(local_file_fd);
  1.1574 +    VLOG(("selfserv: handle_connection: exiting\n"));
  1.1575 +
  1.1576 +    /* do a nice shutdown if asked. */
  1.1577 +    if (!strncmp(buf, stopCmd, sizeof stopCmd - 1)) {
  1.1578 +        VLOG(("selfserv: handle_connection: stop command"));
  1.1579 +        stop_server();
  1.1580 +    }
  1.1581 +    VLOG(("selfserv: handle_connection: exiting"));
  1.1582 +    return SECSuccess;	/* success */
  1.1583 +}
  1.1584 +
  1.1585 +#ifdef XP_UNIX
  1.1586 +
  1.1587 +void sigusr1_handler(int sig)
  1.1588 +{
  1.1589 +    VLOG(("selfserv: sigusr1_handler: stop server"));
  1.1590 +    stop_server();
  1.1591 +}
  1.1592 +
  1.1593 +#endif
  1.1594 +
  1.1595 +SECStatus
  1.1596 +do_accepts(
  1.1597 +    PRFileDesc *listen_sock,
  1.1598 +    PRFileDesc *model_sock,
  1.1599 +    int         requestCert
  1.1600 +    )
  1.1601 +{
  1.1602 +    PRNetAddr   addr;
  1.1603 +    PRErrorCode  perr;
  1.1604 +#ifdef XP_UNIX
  1.1605 +    struct sigaction act;
  1.1606 +#endif
  1.1607 +
  1.1608 +    VLOG(("selfserv: do_accepts: starting"));
  1.1609 +    PR_SetThreadPriority( PR_GetCurrentThread(), PR_PRIORITY_HIGH);
  1.1610 +
  1.1611 +    acceptorThread = PR_GetCurrentThread();
  1.1612 +#ifdef XP_UNIX
  1.1613 +    /* set up the signal handler */
  1.1614 +    act.sa_handler = sigusr1_handler;
  1.1615 +    sigemptyset(&act.sa_mask);
  1.1616 +    act.sa_flags = 0;
  1.1617 +    if (sigaction(SIGUSR1, &act, NULL)) {
  1.1618 +        fprintf(stderr, "Error installing signal handler.\n");
  1.1619 +        exit(1);
  1.1620 +    }
  1.1621 +#endif
  1.1622 +    while (!stopping) {
  1.1623 +	PRFileDesc *tcp_sock;
  1.1624 +	PRCList    *myLink;
  1.1625 +
  1.1626 +	FPRINTF(stderr, "\n\n\nselfserv: About to call accept.\n");
  1.1627 +	tcp_sock = PR_Accept(listen_sock, &addr, PR_INTERVAL_NO_TIMEOUT);
  1.1628 +	if (tcp_sock == NULL) {
  1.1629 +    	    perr      = PR_GetError();
  1.1630 +	    if ((perr != PR_CONNECT_RESET_ERROR &&
  1.1631 +	         perr != PR_PENDING_INTERRUPT_ERROR) || verbose) {
  1.1632 +		errWarn("PR_Accept");
  1.1633 +	    } 
  1.1634 +	    if (perr == PR_CONNECT_RESET_ERROR) {
  1.1635 +		FPRINTF(stderr, 
  1.1636 +		        "Ignoring PR_CONNECT_RESET_ERROR error - continue\n");
  1.1637 +		continue;
  1.1638 +	    }
  1.1639 +	    stopping = 1;
  1.1640 +	    break;
  1.1641 +	}
  1.1642 +
  1.1643 +        VLOG(("selfserv: do_accept: Got connection\n"));
  1.1644 +
  1.1645 +        if (logStats) {
  1.1646 +            PR_ATOMIC_INCREMENT(&loggerOps);
  1.1647 +        }
  1.1648 +
  1.1649 +	PZ_Lock(qLock);
  1.1650 +	while (PR_CLIST_IS_EMPTY(&freeJobs) && !stopping) {
  1.1651 +            PZ_WaitCondVar(freeListNotEmptyCv, PR_INTERVAL_NO_TIMEOUT);
  1.1652 +	}
  1.1653 +	if (stopping) {
  1.1654 +	    PZ_Unlock(qLock);
  1.1655 +            if (tcp_sock) {
  1.1656 +	        PR_Close(tcp_sock);
  1.1657 +            }
  1.1658 +	    break;
  1.1659 +	}
  1.1660 +	myLink = PR_LIST_HEAD(&freeJobs);
  1.1661 +	PR_REMOVE_AND_INIT_LINK(myLink);
  1.1662 +	/* could release qLock here and reaquire it 7 lines below, but 
  1.1663 +	** why bother for 4 assignment statements? 
  1.1664 +	*/
  1.1665 +	{
  1.1666 +	    JOB * myJob = (JOB *)myLink;
  1.1667 +	    myJob->tcp_sock    = tcp_sock;
  1.1668 +	    myJob->model_sock  = model_sock;
  1.1669 +	    myJob->requestCert = requestCert;
  1.1670 +	}
  1.1671 +
  1.1672 +	PR_APPEND_LINK(myLink, &jobQ);
  1.1673 +	PZ_NotifyCondVar(jobQNotEmptyCv);
  1.1674 +	PZ_Unlock(qLock);
  1.1675 +    }
  1.1676 +
  1.1677 +    FPRINTF(stderr, "selfserv: Closing listen socket.\n");
  1.1678 +    VLOG(("selfserv: do_accepts: exiting"));
  1.1679 +    if (listen_sock) {
  1.1680 +        PR_Close(listen_sock);
  1.1681 +    }
  1.1682 +    return SECSuccess;
  1.1683 +}
  1.1684 +
  1.1685 +PRFileDesc *
  1.1686 +getBoundListenSocket(unsigned short port)
  1.1687 +{
  1.1688 +    PRFileDesc *       listen_sock;
  1.1689 +    int                listenQueueDepth = 5 + (2 * maxThreads);
  1.1690 +    PRStatus	       prStatus;
  1.1691 +    PRNetAddr          addr;
  1.1692 +    PRSocketOptionData opt;
  1.1693 +
  1.1694 +    addr.inet.family = PR_AF_INET;
  1.1695 +    addr.inet.ip     = PR_INADDR_ANY;
  1.1696 +    addr.inet.port   = PR_htons(port);
  1.1697 +
  1.1698 +    listen_sock = PR_NewTCPSocket();
  1.1699 +    if (listen_sock == NULL) {
  1.1700 +	errExit("PR_NewTCPSocket");
  1.1701 +    }
  1.1702 +
  1.1703 +    opt.option = PR_SockOpt_Nonblocking;
  1.1704 +    opt.value.non_blocking = PR_FALSE;
  1.1705 +    prStatus = PR_SetSocketOption(listen_sock, &opt);
  1.1706 +    if (prStatus < 0) {
  1.1707 +        PR_Close(listen_sock);
  1.1708 +	errExit("PR_SetSocketOption(PR_SockOpt_Nonblocking)");
  1.1709 +    }
  1.1710 +
  1.1711 +    opt.option=PR_SockOpt_Reuseaddr;
  1.1712 +    opt.value.reuse_addr = PR_TRUE;
  1.1713 +    prStatus = PR_SetSocketOption(listen_sock, &opt);
  1.1714 +    if (prStatus < 0) {
  1.1715 +        PR_Close(listen_sock);
  1.1716 +	errExit("PR_SetSocketOption(PR_SockOpt_Reuseaddr)");
  1.1717 +    }
  1.1718 +
  1.1719 +#ifndef WIN95
  1.1720 +    /* Set PR_SockOpt_Linger because it helps prevent a server bind issue
  1.1721 +     * after clean shutdown . See bug 331413 .
  1.1722 +     * Don't do it in the WIN95 build configuration because clean shutdown is
  1.1723 +     * not implemented, and PR_SockOpt_Linger causes a hang in ssl.sh .
  1.1724 +     * See bug 332348 */
  1.1725 +    opt.option=PR_SockOpt_Linger;
  1.1726 +    opt.value.linger.polarity = PR_TRUE;
  1.1727 +    opt.value.linger.linger = PR_SecondsToInterval(1);
  1.1728 +    prStatus = PR_SetSocketOption(listen_sock, &opt);
  1.1729 +    if (prStatus < 0) {
  1.1730 +        PR_Close(listen_sock);
  1.1731 +        errExit("PR_SetSocketOption(PR_SockOpt_Linger)");
  1.1732 +    }
  1.1733 +#endif
  1.1734 +
  1.1735 +    prStatus = PR_Bind(listen_sock, &addr);
  1.1736 +    if (prStatus < 0) {
  1.1737 +        PR_Close(listen_sock);
  1.1738 +	errExit("PR_Bind");
  1.1739 +    }
  1.1740 +
  1.1741 +    prStatus = PR_Listen(listen_sock, listenQueueDepth);
  1.1742 +    if (prStatus < 0) {
  1.1743 +        PR_Close(listen_sock);
  1.1744 +	errExit("PR_Listen");
  1.1745 +    }
  1.1746 +    return listen_sock;
  1.1747 +}
  1.1748 +
  1.1749 +PRInt32 PR_CALLBACK 
  1.1750 +logWritev (
  1.1751 +    PRFileDesc     *fd,
  1.1752 +    const PRIOVec  *iov,
  1.1753 +    PRInt32         size, 
  1.1754 +    PRIntervalTime  timeout )
  1.1755 +{
  1.1756 +    PRInt32 rv = (fd->lower->methods->writev)(fd->lower, iov, size, 
  1.1757 +        timeout);
  1.1758 +    /* Add the amount written, but not if there's an error */
  1.1759 +    if (rv > 0) 
  1.1760 +        PR_ATOMIC_ADD(&loggerBytesTCP, rv);
  1.1761 +    return rv;
  1.1762 +}
  1.1763 +    
  1.1764 +PRInt32 PR_CALLBACK 
  1.1765 +logWrite (
  1.1766 +    PRFileDesc  *fd, 
  1.1767 +    const void  *buf, 
  1.1768 +    PRInt32      amount)
  1.1769 +{   
  1.1770 +    PRInt32 rv = (fd->lower->methods->write)(fd->lower, buf, amount);
  1.1771 +    /* Add the amount written, but not if there's an error */
  1.1772 +    if (rv > 0) 
  1.1773 +        PR_ATOMIC_ADD(&loggerBytesTCP, rv);
  1.1774 +    
  1.1775 +    return rv;
  1.1776 +}
  1.1777 +
  1.1778 +PRInt32 PR_CALLBACK 
  1.1779 +logSend (
  1.1780 +    PRFileDesc     *fd, 
  1.1781 +    const void     *buf, 
  1.1782 +    PRInt32         amount, 
  1.1783 +    PRIntn          flags, 
  1.1784 +    PRIntervalTime  timeout)
  1.1785 +{
  1.1786 +    PRInt32 rv = (fd->lower->methods->send)(fd->lower, buf, amount, 
  1.1787 +        flags, timeout);
  1.1788 +    /* Add the amount written, but not if there's an error */
  1.1789 +    if (rv > 0) 
  1.1790 +        PR_ATOMIC_ADD(&loggerBytesTCP, rv);
  1.1791 +    return rv;
  1.1792 +}
  1.1793 + 
  1.1794 +void initLoggingLayer(void)
  1.1795 +{   
  1.1796 +    /* get a new layer ID */
  1.1797 +    log_layer_id = PR_GetUniqueIdentity("Selfserv Logging");
  1.1798 +    if (log_layer_id == PR_INVALID_IO_LAYER)
  1.1799 +        errExit("PR_GetUniqueIdentity");
  1.1800 +    
  1.1801 +    /* setup the default IO methods with my custom write methods */
  1.1802 +    memcpy(&loggingMethods, PR_GetDefaultIOMethods(), sizeof(PRIOMethods));
  1.1803 +    loggingMethods.writev = logWritev;
  1.1804 +    loggingMethods.write  = logWrite;
  1.1805 +    loggingMethods.send   = logSend;
  1.1806 +}
  1.1807 +
  1.1808 +void
  1.1809 +handshakeCallback(PRFileDesc *fd, void *client_data)
  1.1810 +{
  1.1811 +    const char *handshakeName = (const char *)client_data;
  1.1812 +    if (handshakeName && !failedToNegotiateName) {
  1.1813 +        SECItem *hostInfo  = SSL_GetNegotiatedHostInfo(fd);
  1.1814 +        if (!hostInfo || PORT_Strncmp(handshakeName, (char*)hostInfo->data,
  1.1815 +                                      hostInfo->len)) {
  1.1816 +            failedToNegotiateName = PR_TRUE;
  1.1817 +        }
  1.1818 +    }
  1.1819 +}
  1.1820 +
  1.1821 +void
  1.1822 +server_main(
  1.1823 +    PRFileDesc *        listen_sock,
  1.1824 +    int                 requestCert, 
  1.1825 +    SECKEYPrivateKey ** privKey,
  1.1826 +    CERTCertificate **  cert,
  1.1827 +    const char *expectedHostNameVal)
  1.1828 +{
  1.1829 +    PRFileDesc *model_sock	= NULL;
  1.1830 +    int         rv;
  1.1831 +    SSLKEAType  kea;
  1.1832 +    SECStatus	secStatus;
  1.1833 +
  1.1834 +    if (useModelSocket) {
  1.1835 +    	model_sock = PR_NewTCPSocket();
  1.1836 +	if (model_sock == NULL) {
  1.1837 +	    errExit("PR_NewTCPSocket on model socket");
  1.1838 +	}
  1.1839 +	model_sock = SSL_ImportFD(NULL, model_sock);
  1.1840 +	if (model_sock == NULL) {
  1.1841 +	    errExit("SSL_ImportFD");
  1.1842 +	}
  1.1843 +    } else {
  1.1844 +	model_sock = listen_sock = SSL_ImportFD(NULL, listen_sock);
  1.1845 +	if (listen_sock == NULL) {
  1.1846 +	    errExit("SSL_ImportFD");
  1.1847 +	}
  1.1848 +    }
  1.1849 +
  1.1850 +    /* do SSL configuration. */
  1.1851 +    rv = SSL_OptionSet(model_sock, SSL_SECURITY, 
  1.1852 +                       enableSSL2 || enabledVersions.min != 0);
  1.1853 +    if (rv < 0) {
  1.1854 +	errExit("SSL_OptionSet SSL_SECURITY");
  1.1855 +    }
  1.1856 +
  1.1857 +    rv = SSL_VersionRangeSet(model_sock, &enabledVersions);
  1.1858 +    if (rv != SECSuccess) {
  1.1859 +	errExit("error setting SSL/TLS version range ");
  1.1860 +    }
  1.1861 +
  1.1862 +    rv = SSL_OptionSet(model_sock, SSL_ENABLE_SSL2, enableSSL2);
  1.1863 +    if (rv != SECSuccess) {
  1.1864 +       errExit("error enabling SSLv2 ");
  1.1865 +    }
  1.1866 +
  1.1867 +    rv = SSL_OptionSet(model_sock, SSL_ROLLBACK_DETECTION, !disableRollBack);
  1.1868 +    if (rv != SECSuccess) {
  1.1869 +	errExit("error enabling RollBack detection ");
  1.1870 +    }
  1.1871 +    if (disableStepDown) {
  1.1872 +	rv = SSL_OptionSet(model_sock, SSL_NO_STEP_DOWN, PR_TRUE);
  1.1873 +	if (rv != SECSuccess) {
  1.1874 +	    errExit("error disabling SSL StepDown ");
  1.1875 +	}
  1.1876 +    }
  1.1877 +    if (bypassPKCS11) {
  1.1878 +       rv = SSL_OptionSet(model_sock, SSL_BYPASS_PKCS11, PR_TRUE);
  1.1879 +	if (rv != SECSuccess) {
  1.1880 +	    errExit("error enabling PKCS11 bypass ");
  1.1881 +	}
  1.1882 +    }
  1.1883 +    if (disableLocking) {
  1.1884 +       rv = SSL_OptionSet(model_sock, SSL_NO_LOCKS, PR_TRUE);
  1.1885 +	if (rv != SECSuccess) {
  1.1886 +	    errExit("error disabling SSL socket locking ");
  1.1887 +	}
  1.1888 +    } 
  1.1889 +    if (enableSessionTickets) {
  1.1890 +	rv = SSL_OptionSet(model_sock, SSL_ENABLE_SESSION_TICKETS, PR_TRUE);
  1.1891 +	if (rv != SECSuccess) {
  1.1892 +	    errExit("error enabling Session Ticket extension ");
  1.1893 +	}
  1.1894 +    }
  1.1895 +
  1.1896 +    if (enableCompression) {
  1.1897 +	rv = SSL_OptionSet(model_sock, SSL_ENABLE_DEFLATE, PR_TRUE);
  1.1898 +	if (rv != SECSuccess) {
  1.1899 +	    errExit("error enabling compression ");
  1.1900 +	}
  1.1901 +    }
  1.1902 +
  1.1903 +    if (virtServerNameIndex >1) {
  1.1904 +        rv = SSL_SNISocketConfigHook(model_sock, mySSLSNISocketConfig,
  1.1905 +                                     (void*)&virtServerNameArray);
  1.1906 +        if (rv != SECSuccess) {
  1.1907 +            errExit("error enabling SNI extension ");
  1.1908 +        }
  1.1909 +    }
  1.1910 +
  1.1911 +    for (kea = kt_rsa; kea < kt_kea_size; kea++) {
  1.1912 +	if (cert[kea] != NULL) {
  1.1913 +	    secStatus = SSL_ConfigSecureServer(model_sock, 
  1.1914 +	    		cert[kea], privKey[kea], kea);
  1.1915 +	    if (secStatus != SECSuccess)
  1.1916 +		errExit("SSL_ConfigSecureServer");
  1.1917 +	}
  1.1918 +    }
  1.1919 +
  1.1920 +    if (bigBuf.data) { /* doing FDX */
  1.1921 +	rv = SSL_OptionSet(model_sock, SSL_ENABLE_FDX, 1);
  1.1922 +	if (rv < 0) {
  1.1923 +	    errExit("SSL_OptionSet SSL_ENABLE_FDX");
  1.1924 +	}
  1.1925 +    }
  1.1926 +
  1.1927 +    if (NoReuse) {
  1.1928 +        rv = SSL_OptionSet(model_sock, SSL_NO_CACHE, 1);
  1.1929 +        if (rv < 0) {
  1.1930 +            errExit("SSL_OptionSet SSL_NO_CACHE");
  1.1931 +        }
  1.1932 +    }
  1.1933 +
  1.1934 +    /* This cipher is not on by default. The Acceptance test
  1.1935 +     * would like it to be. Turn this cipher on.
  1.1936 +     */
  1.1937 +
  1.1938 +    secStatus = SSL_CipherPrefSetDefault( TLS_RSA_WITH_NULL_MD5, PR_TRUE);
  1.1939 +    if ( secStatus != SECSuccess ) {
  1.1940 +	errExit("SSL_CipherPrefSetDefault:TLS_RSA_WITH_NULL_MD5");
  1.1941 +    }
  1.1942 +
  1.1943 +    if (expectedHostNameVal) {
  1.1944 +        SSL_HandshakeCallback(model_sock, handshakeCallback,
  1.1945 +                              (void*)expectedHostNameVal);
  1.1946 +    }
  1.1947 +
  1.1948 +    if (requestCert) {
  1.1949 +	SSL_AuthCertificateHook(model_sock, mySSLAuthCertificate, 
  1.1950 +	                        (void *)CERT_GetDefaultCertDB());
  1.1951 +	if (requestCert <= 2) { 
  1.1952 +	    rv = SSL_OptionSet(model_sock, SSL_REQUEST_CERTIFICATE, 1);
  1.1953 +	    if (rv < 0) {
  1.1954 +		errExit("first SSL_OptionSet SSL_REQUEST_CERTIFICATE");
  1.1955 +	    }
  1.1956 +	    rv = SSL_OptionSet(model_sock, SSL_REQUIRE_CERTIFICATE, 
  1.1957 +	                    (requestCert == 2));
  1.1958 +	    if (rv < 0) {
  1.1959 +		errExit("first SSL_OptionSet SSL_REQUIRE_CERTIFICATE");
  1.1960 +	    }
  1.1961 +	}
  1.1962 +    }
  1.1963 +
  1.1964 +    if (MakeCertOK)
  1.1965 +	SSL_BadCertHook(model_sock, myBadCertHandler, NULL);
  1.1966 +
  1.1967 +    /* end of ssl configuration. */
  1.1968 +
  1.1969 +
  1.1970 +    /* Now, do the accepting, here in the main thread. */
  1.1971 +    rv = do_accepts(listen_sock, model_sock, requestCert);
  1.1972 +
  1.1973 +    terminateWorkerThreads();
  1.1974 +
  1.1975 +    if (useModelSocket && model_sock) {
  1.1976 +        if (model_sock) {
  1.1977 +            PR_Close(model_sock);
  1.1978 +        }
  1.1979 +    }
  1.1980 +
  1.1981 +}
  1.1982 +
  1.1983 +SECStatus
  1.1984 +readBigFile(const char * fileName)
  1.1985 +{
  1.1986 +    PRFileInfo  info;
  1.1987 +    PRStatus	status;
  1.1988 +    SECStatus	rv	= SECFailure;
  1.1989 +    int		count;
  1.1990 +    int		hdrLen;
  1.1991 +    PRFileDesc *local_file_fd = NULL;
  1.1992 +
  1.1993 +    status = PR_GetFileInfo(fileName, &info);
  1.1994 +
  1.1995 +    if (status == PR_SUCCESS &&
  1.1996 +	info.type == PR_FILE_FILE &&
  1.1997 +	info.size > 0 &&
  1.1998 +	NULL != (local_file_fd = PR_Open(fileName, PR_RDONLY, 0))) {
  1.1999 +
  1.2000 +	hdrLen      = PORT_Strlen(outHeader);
  1.2001 +	bigBuf.len  = hdrLen + info.size;
  1.2002 +	bigBuf.data = PORT_Malloc(bigBuf.len + 4095);
  1.2003 +	if (!bigBuf.data) {
  1.2004 +	    errWarn("PORT_Malloc");
  1.2005 +	    goto done;
  1.2006 +	}
  1.2007 +
  1.2008 +	PORT_Memcpy(bigBuf.data, outHeader, hdrLen);
  1.2009 +
  1.2010 +	count = PR_Read(local_file_fd, bigBuf.data + hdrLen, info.size);
  1.2011 +	if (count != info.size) {
  1.2012 +	    errWarn("PR_Read local file");
  1.2013 +	    goto done;
  1.2014 +	}
  1.2015 +	rv = SECSuccess;
  1.2016 +done:
  1.2017 +        if (local_file_fd) {
  1.2018 +            PR_Close(local_file_fd);
  1.2019 +        }
  1.2020 +    }
  1.2021 +    return rv;
  1.2022 +}
  1.2023 +
  1.2024 +int          numChildren;
  1.2025 +PRProcess *  child[MAX_PROCS];
  1.2026 +
  1.2027 +PRProcess *
  1.2028 +haveAChild(int argc, char **argv, PRProcessAttr * attr)
  1.2029 +{
  1.2030 +    PRProcess *  newProcess;
  1.2031 +
  1.2032 +    newProcess = PR_CreateProcess(argv[0], argv, NULL, attr);
  1.2033 +    if (!newProcess) {
  1.2034 +	errWarn("Can't create new process.");
  1.2035 +    } else {
  1.2036 +	child[numChildren++] = newProcess;
  1.2037 +    }
  1.2038 +    return newProcess;
  1.2039 +}
  1.2040 +
  1.2041 +void
  1.2042 +beAGoodParent(int argc, char **argv, int maxProcs, PRFileDesc * listen_sock)
  1.2043 +{
  1.2044 +    PRProcess *     newProcess;
  1.2045 +    PRProcessAttr * attr;
  1.2046 +    int             i;
  1.2047 +    PRInt32         exitCode;
  1.2048 +    PRStatus        rv;
  1.2049 +
  1.2050 +    rv = PR_SetFDInheritable(listen_sock, PR_TRUE);
  1.2051 +    if (rv != PR_SUCCESS)
  1.2052 +	errExit("PR_SetFDInheritable");
  1.2053 +
  1.2054 +    attr = PR_NewProcessAttr();
  1.2055 +    if (!attr)
  1.2056 +	errExit("PR_NewProcessAttr");
  1.2057 +
  1.2058 +    rv = PR_ProcessAttrSetInheritableFD(attr, listen_sock, inheritableSockName);
  1.2059 +    if (rv != PR_SUCCESS)
  1.2060 +	errExit("PR_ProcessAttrSetInheritableFD");
  1.2061 +
  1.2062 +    for (i = 0; i < maxProcs; ++i) {
  1.2063 +	newProcess = haveAChild(argc, argv, attr);
  1.2064 +	if (!newProcess) 
  1.2065 +	    break;
  1.2066 +    }
  1.2067 +
  1.2068 +    rv = PR_SetFDInheritable(listen_sock, PR_FALSE);
  1.2069 +    if (rv != PR_SUCCESS)
  1.2070 +	errExit("PR_SetFDInheritable");
  1.2071 +
  1.2072 +    while (numChildren > 0) {
  1.2073 +	newProcess = child[numChildren - 1];
  1.2074 +	PR_WaitProcess(newProcess, &exitCode);
  1.2075 +	fprintf(stderr, "Child %d exited with exit code %x\n", 
  1.2076 +		numChildren, exitCode);
  1.2077 +	numChildren--;
  1.2078 +    }
  1.2079 +    exit(0);
  1.2080 +}
  1.2081 +
  1.2082 +#define HEXCHAR_TO_INT(c, i) \
  1.2083 +    if (((c) >= '0') && ((c) <= '9')) { \
  1.2084 +	i = (c) - '0'; \
  1.2085 +    } else if (((c) >= 'a') && ((c) <= 'f')) { \
  1.2086 +	i = (c) - 'a' + 10; \
  1.2087 +    } else if (((c) >= 'A') && ((c) <= 'F')) { \
  1.2088 +	i = (c) - 'A' + 10; \
  1.2089 +    } else if ((c) == '\0') { \
  1.2090 +	fprintf(stderr, "Invalid length of cipher string (-c :WXYZ).\n"); \
  1.2091 +	exit(9); \
  1.2092 +    } else { \
  1.2093 +	fprintf(stderr, "Non-hex char in cipher string (-c :WXYZ).\n"); \
  1.2094 +	exit(9); \
  1.2095 +    } 
  1.2096 +
  1.2097 +SECStatus enableOCSPStapling(const char* mode)
  1.2098 +{
  1.2099 +    if (!strcmp(mode, "good")) {
  1.2100 +	ocspStaplingMode = osm_good;
  1.2101 +	return SECSuccess;
  1.2102 +    }
  1.2103 +    if (!strcmp(mode, "unknown")) {
  1.2104 +	ocspStaplingMode = osm_unknown;
  1.2105 +	return SECSuccess;
  1.2106 +    }
  1.2107 +    if (!strcmp(mode, "revoked")) {
  1.2108 +	ocspStaplingMode = osm_revoked;
  1.2109 +	return SECSuccess;
  1.2110 +    }
  1.2111 +    if (!strcmp(mode, "badsig")) {
  1.2112 +	ocspStaplingMode = osm_badsig;
  1.2113 +	return SECSuccess;
  1.2114 +    }
  1.2115 +    if (!strcmp(mode, "corrupted")) {
  1.2116 +	ocspStaplingMode = osm_corrupted;
  1.2117 +	return SECSuccess;
  1.2118 +    }
  1.2119 +    if (!strcmp(mode, "failure")) {
  1.2120 +	ocspStaplingMode = osm_failure;
  1.2121 +	return SECSuccess;
  1.2122 +    }
  1.2123 +    if (!strcmp(mode, "random")) {
  1.2124 +	ocspStaplingMode = osm_random;
  1.2125 +	return SECSuccess;
  1.2126 +    }
  1.2127 +    if (!strcmp(mode, "ocsp")) {
  1.2128 +	ocspStaplingMode = osm_ocsp;
  1.2129 +	return SECSuccess;
  1.2130 +    }
  1.2131 +    return SECFailure;
  1.2132 +}
  1.2133 +
  1.2134 +int
  1.2135 +main(int argc, char **argv)
  1.2136 +{
  1.2137 +    char *               progName    = NULL;
  1.2138 +    char *               nickName    = NULL;
  1.2139 +#ifndef NSS_DISABLE_ECC
  1.2140 +    char *               ecNickName   = NULL;
  1.2141 +#endif
  1.2142 +    const char *         fileName    = NULL;
  1.2143 +    char *               cipherString= NULL;
  1.2144 +    const char *         dir         = ".";
  1.2145 +    char *               passwd      = NULL;
  1.2146 +    char *               pwfile      = NULL;
  1.2147 +    const char *         pidFile     = NULL;
  1.2148 +    char *               tmp;
  1.2149 +    char *               envString;
  1.2150 +    PRFileDesc *         listen_sock;
  1.2151 +    CERTCertificate *    cert   [kt_kea_size] = { NULL };
  1.2152 +    SECKEYPrivateKey *   privKey[kt_kea_size] = { NULL };
  1.2153 +    int                  optionsFound = 0;
  1.2154 +    int                  maxProcs     = 1;
  1.2155 +    unsigned short       port        = 0;
  1.2156 +    SECStatus            rv;
  1.2157 +    PRStatus             prStatus;
  1.2158 +    PRBool               bindOnly = PR_FALSE;
  1.2159 +    PRBool               useExportPolicy = PR_FALSE;
  1.2160 +    PRBool               useLocalThreads = PR_FALSE;
  1.2161 +    PLOptState		*optstate;
  1.2162 +    PLOptStatus          status;
  1.2163 +    PRThread             *loggerThread = NULL;
  1.2164 +    PRBool               debugCache = PR_FALSE; /* bug 90518 */
  1.2165 +    char                 emptyString[] = { "" };
  1.2166 +    char*                certPrefix = emptyString;
  1.2167 +    PRUint32             protos = 0;
  1.2168 +    SSL3Statistics      *ssl3stats;
  1.2169 +    PRUint32             i;
  1.2170 +    secuPWData  pwdata = { PW_NONE, 0 };
  1.2171 +    char                *expectedHostNameVal = NULL;
  1.2172 +    PLArenaPool         *certStatusArena = NULL;
  1.2173 +
  1.2174 +    tmp = strrchr(argv[0], '/');
  1.2175 +    tmp = tmp ? tmp + 1 : argv[0];
  1.2176 +    progName = strrchr(tmp, '\\');
  1.2177 +    progName = progName ? progName + 1 : tmp;
  1.2178 +
  1.2179 +    PR_Init( PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
  1.2180 +    SSL_VersionRangeGetSupported(ssl_variant_stream, &enabledVersions);
  1.2181 +
  1.2182 +    /* please keep this list of options in ASCII collating sequence.
  1.2183 +    ** numbers, then capital letters, then lower case, alphabetical. 
  1.2184 +    */
  1.2185 +    optstate = PL_CreateOptState(argc, argv, 
  1.2186 +        "2:A:BC:DEL:M:NP:RT:V:Ya:bc:d:e:f:g:hi:jk:lmn:op:qrst:uvw:xyz");
  1.2187 +    while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
  1.2188 +	++optionsFound;
  1.2189 +	switch(optstate->option) {
  1.2190 +	case '2': fileName = optstate->value; break;
  1.2191 +
  1.2192 +	case 'A': ocspStaplingCA = PORT_Strdup(optstate->value); break;
  1.2193 +
  1.2194 +	case 'B': bypassPKCS11 = PR_TRUE; break;
  1.2195 +
  1.2196 +        case 'C': if (optstate->value) NumSidCacheEntries = PORT_Atoi(optstate->value); break;
  1.2197 +
  1.2198 +	case 'D': noDelay = PR_TRUE; break;
  1.2199 +	case 'E': disableStepDown = PR_TRUE; break;
  1.2200 +
  1.2201 +	case 'I': /* reserved for OCSP multi-stapling */ break;
  1.2202 +
  1.2203 +        case 'L':
  1.2204 +            logStats = PR_TRUE;
  1.2205 +	    if (optstate->value == NULL) {
  1.2206 +	    	logPeriod = 30;
  1.2207 +	    } else {
  1.2208 +                logPeriod  = PORT_Atoi(optstate->value);
  1.2209 +                if (logPeriod <= 0) logPeriod = 30;
  1.2210 +	    }
  1.2211 +            break;
  1.2212 +
  1.2213 +	case 'M': 
  1.2214 +	    maxProcs = PORT_Atoi(optstate->value); 
  1.2215 +	    if (maxProcs < 1)         maxProcs = 1;
  1.2216 +	    if (maxProcs > MAX_PROCS) maxProcs = MAX_PROCS;
  1.2217 +	    break;
  1.2218 +
  1.2219 +	case 'N': NoReuse = PR_TRUE; break;
  1.2220 +
  1.2221 +	case 'R': disableRollBack = PR_TRUE; break;
  1.2222 +
  1.2223 +	case 'T':
  1.2224 +	    if (enableOCSPStapling(optstate->value) != SECSuccess) {
  1.2225 +		fprintf(stderr, "Invalid OCSP stapling mode.\n");
  1.2226 +		fprintf(stderr, "Run '%s -h' for usage information.\n", progName);
  1.2227 +		exit(53);
  1.2228 +	    }
  1.2229 +	    break;
  1.2230 +
  1.2231 +        case 'V': if (SECU_ParseSSLVersionRangeString(optstate->value,
  1.2232 +                          enabledVersions, enableSSL2,
  1.2233 +                          &enabledVersions, &enableSSL2) != SECSuccess) {
  1.2234 +                      Usage(progName);
  1.2235 +                  }
  1.2236 +                  break;
  1.2237 +
  1.2238 +        case 'Y': PrintCipherUsage(progName); exit(0); break;
  1.2239 +        
  1.2240 +	case 'a': if (virtServerNameIndex >= MAX_VIRT_SERVER_NAME_ARRAY_INDEX) {
  1.2241 +                      Usage(progName);
  1.2242 +                  }
  1.2243 +                  virtServerNameArray[virtServerNameIndex++] =
  1.2244 +                      PORT_Strdup(optstate->value); break;
  1.2245 +
  1.2246 +	case 'b': bindOnly = PR_TRUE; break;
  1.2247 +
  1.2248 +	case 'c': cipherString = PORT_Strdup(optstate->value); break;
  1.2249 +
  1.2250 +	case 'd': dir = optstate->value; break;
  1.2251 +
  1.2252 +#ifndef NSS_DISABLE_ECC
  1.2253 +	case 'e': ecNickName = PORT_Strdup(optstate->value); break;
  1.2254 +#endif /* NSS_DISABLE_ECC */
  1.2255 +
  1.2256 +	case 'f':
  1.2257 +            pwdata.source = PW_FROMFILE;
  1.2258 +            pwdata.data = pwfile = PORT_Strdup(optstate->value);
  1.2259 +            break;
  1.2260 +
  1.2261 +        case 'g': 
  1.2262 +            testBulk = PR_TRUE;
  1.2263 +            testBulkTotal = PORT_Atoi(optstate->value);
  1.2264 +            break;
  1.2265 +
  1.2266 +	case 'h': Usage(progName); exit(0); break;
  1.2267 +
  1.2268 +	case 'i': pidFile = optstate->value; break;
  1.2269 +
  1.2270 +        case 'j': 
  1.2271 +            initLoggingLayer(); 
  1.2272 +            loggingLayer = PR_TRUE;
  1.2273 +            break;
  1.2274 +
  1.2275 +        case 'k': expectedHostNameVal = PORT_Strdup(optstate->value);
  1.2276 +                  break;
  1.2277 +
  1.2278 +        case 'l': useLocalThreads = PR_TRUE; break;
  1.2279 +
  1.2280 +	case 'm': useModelSocket = PR_TRUE; break;
  1.2281 +
  1.2282 +	case 'n': nickName = PORT_Strdup(optstate->value);
  1.2283 +                  virtServerNameArray[0] = PORT_Strdup(optstate->value);
  1.2284 +                  break;
  1.2285 +
  1.2286 +	case 'P': certPrefix = PORT_Strdup(optstate->value); break;
  1.2287 +
  1.2288 +	case 'o': MakeCertOK = 1; break;
  1.2289 +
  1.2290 +	case 'p': port = PORT_Atoi(optstate->value); break;
  1.2291 +
  1.2292 +	case 'q': testbypass = PR_TRUE; break;
  1.2293 +
  1.2294 +	case 'r': ++requestCert; break;
  1.2295 +
  1.2296 +	case 's': disableLocking = PR_TRUE; break;
  1.2297 +
  1.2298 +	case 't':
  1.2299 +	    maxThreads = PORT_Atoi(optstate->value);
  1.2300 +	    if ( maxThreads > MAX_THREADS ) maxThreads = MAX_THREADS;
  1.2301 +	    if ( maxThreads < MIN_THREADS ) maxThreads = MIN_THREADS;
  1.2302 +	    break;
  1.2303 +
  1.2304 +	case 'u': enableSessionTickets = PR_TRUE; break;
  1.2305 +
  1.2306 +	case 'v': verbose++; break;
  1.2307 +
  1.2308 +	case 'w':
  1.2309 +            pwdata.source = PW_PLAINTEXT;
  1.2310 +            pwdata.data = passwd = PORT_Strdup(optstate->value);
  1.2311 +            break;
  1.2312 +
  1.2313 +	case 'x': useExportPolicy = PR_TRUE; break;
  1.2314 +
  1.2315 +	case 'y': debugCache = PR_TRUE; break;
  1.2316 +
  1.2317 +	case 'z': enableCompression = PR_TRUE; break;
  1.2318 +
  1.2319 +	default:
  1.2320 +	case '?':
  1.2321 +	    fprintf(stderr, "Unrecognized or bad option specified.\n");
  1.2322 +	    fprintf(stderr, "Run '%s -h' for usage information.\n", progName);
  1.2323 +	    exit(4);
  1.2324 +	    break;
  1.2325 +	}
  1.2326 +    }
  1.2327 +    PL_DestroyOptState(optstate);
  1.2328 +    if (status == PL_OPT_BAD) {
  1.2329 +	fprintf(stderr, "Unrecognized or bad option specified.\n");
  1.2330 +	fprintf(stderr, "Run '%s -h' for usage information.\n", progName);
  1.2331 +	exit(5);
  1.2332 +    }
  1.2333 +    if (!optionsFound) {
  1.2334 +	Usage(progName);
  1.2335 +	exit(51);
  1.2336 +    }
  1.2337 +    switch (ocspStaplingMode) {
  1.2338 +	case osm_good:
  1.2339 +	case osm_revoked:
  1.2340 +	case osm_unknown:
  1.2341 +	case osm_random:
  1.2342 +	    if (!ocspStaplingCA) {
  1.2343 +		fprintf(stderr, "Selected stapling response requires the -A parameter.\n");
  1.2344 +		fprintf(stderr, "Run '%s -h' for usage information.\n", progName);
  1.2345 +		exit(52);
  1.2346 +	    }
  1.2347 +	    break;
  1.2348 +	default:
  1.2349 +	    break;
  1.2350 +    }
  1.2351 +
  1.2352 +    /* The -b (bindOnly) option is only used by the ssl.sh test
  1.2353 +     * script on Linux to determine whether a previous selfserv
  1.2354 +     * process has fully died and freed the port.  (Bug 129701)
  1.2355 +     */
  1.2356 +    if (bindOnly) {
  1.2357 +	listen_sock = getBoundListenSocket(port);
  1.2358 +	if (!listen_sock) {
  1.2359 +	    exit(1);
  1.2360 +	}
  1.2361 +        if (listen_sock) {
  1.2362 +            PR_Close(listen_sock);
  1.2363 +        }
  1.2364 +	exit(0);
  1.2365 +    }
  1.2366 +
  1.2367 +    if ((nickName == NULL)
  1.2368 + #ifndef NSS_DISABLE_ECC
  1.2369 +						&& (ecNickName == NULL)
  1.2370 + #endif
  1.2371 +    ) {
  1.2372 +
  1.2373 +	fprintf(stderr, "Required arg '-n' (rsa nickname) not supplied.\n");
  1.2374 +	fprintf(stderr, "Run '%s -h' for usage information.\n", progName);
  1.2375 +        exit(6);
  1.2376 +    }
  1.2377 +
  1.2378 +    if (port == 0) {
  1.2379 +	fprintf(stderr, "Required argument 'port' must be non-zero value\n");
  1.2380 +	exit(7);
  1.2381 +    }
  1.2382 +
  1.2383 +    if (NoReuse && maxProcs > 1) {
  1.2384 +	fprintf(stderr, "-M and -N options are mutually exclusive.\n");
  1.2385 +	exit(14);
  1.2386 +    }
  1.2387 +
  1.2388 +    if (pidFile) {
  1.2389 +	FILE *tmpfile=fopen(pidFile,"w+");
  1.2390 +
  1.2391 +	if (tmpfile) {
  1.2392 +	    fprintf(tmpfile,"%d",getpid());
  1.2393 +	    fclose(tmpfile);
  1.2394 +	}
  1.2395 +    }
  1.2396 +
  1.2397 +    /* allocate and initialize app data for bulk encryption testing */
  1.2398 +    if (testBulk) {
  1.2399 +        testBulkBuf = PORT_Malloc(testBulkSize);
  1.2400 +        if (testBulkBuf == NULL)
  1.2401 +            errExit("Out of memory: testBulkBuf");
  1.2402 +        for (i = 0; i < testBulkSize; i++)
  1.2403 +            testBulkBuf[i] = i;
  1.2404 +    }
  1.2405 +
  1.2406 +    envString = getenv(envVarName);
  1.2407 +    tmp = getenv("TMP");
  1.2408 +    if (!tmp)
  1.2409 +	tmp = getenv("TMPDIR");
  1.2410 +    if (!tmp)
  1.2411 +	tmp = getenv("TEMP");
  1.2412 +    if (envString) {
  1.2413 +	/* we're one of the children in a multi-process server. */
  1.2414 +	listen_sock = PR_GetInheritedFD(inheritableSockName);
  1.2415 +	if (!listen_sock)
  1.2416 +	    errExit("PR_GetInheritedFD");
  1.2417 +#ifndef WINNT
  1.2418 +	/* we can't do this on NT because it breaks NSPR and
  1.2419 +	PR_Accept will fail on the socket in the child process if
  1.2420 +	the socket state is change to non inheritable
  1.2421 +	It is however a security issue to leave it accessible,
  1.2422 +	but it is OK for a test server such as selfserv.
  1.2423 +	NSPR should fix it eventually . see bugzilla 101617
  1.2424 +	and 102077
  1.2425 +	*/
  1.2426 +	prStatus = PR_SetFDInheritable(listen_sock, PR_FALSE);
  1.2427 +	if (prStatus != PR_SUCCESS)
  1.2428 +	    errExit("PR_SetFDInheritable");
  1.2429 +#endif
  1.2430 +	rv = SSL_InheritMPServerSIDCache(envString);
  1.2431 +	if (rv != SECSuccess)
  1.2432 +	    errExit("SSL_InheritMPServerSIDCache");
  1.2433 +    	hasSidCache = PR_TRUE;
  1.2434 +    } else if (maxProcs > 1) {
  1.2435 +	/* we're going to be the parent in a multi-process server.  */
  1.2436 +	listen_sock = getBoundListenSocket(port);
  1.2437 +	rv = SSL_ConfigMPServerSIDCache(NumSidCacheEntries, 0, 0, tmp);
  1.2438 +	if (rv != SECSuccess)
  1.2439 +	    errExit("SSL_ConfigMPServerSIDCache");
  1.2440 +    	hasSidCache = PR_TRUE;
  1.2441 +	beAGoodParent(argc, argv, maxProcs, listen_sock);
  1.2442 +	exit(99); /* should never get here */
  1.2443 +    } else {
  1.2444 +	/* we're an ordinary single process server. */
  1.2445 +	listen_sock = getBoundListenSocket(port);
  1.2446 +	prStatus = PR_SetFDInheritable(listen_sock, PR_FALSE);
  1.2447 +	if (prStatus != PR_SUCCESS)
  1.2448 +	    errExit("PR_SetFDInheritable");
  1.2449 +	if (!NoReuse) {
  1.2450 +	    rv = SSL_ConfigServerSessionIDCache(NumSidCacheEntries, 
  1.2451 +	                                        0, 0, tmp);
  1.2452 +	    if (rv != SECSuccess)
  1.2453 +		errExit("SSL_ConfigServerSessionIDCache");
  1.2454 +	    hasSidCache = PR_TRUE;
  1.2455 +	}
  1.2456 +    }
  1.2457 +
  1.2458 +    lm = PR_NewLogModule("TestCase");
  1.2459 +
  1.2460 +    if (fileName)
  1.2461 +    	readBigFile(fileName);
  1.2462 +
  1.2463 +    /* set our password function */
  1.2464 +    PK11_SetPasswordFunc(SECU_GetModulePassword);
  1.2465 +
  1.2466 +    /* Call the NSS initialization routines */
  1.2467 +    rv = NSS_Initialize(dir, certPrefix, certPrefix, SECMOD_DB, NSS_INIT_READONLY);
  1.2468 +    if (rv != SECSuccess) {
  1.2469 +    	fputs("NSS_Init failed.\n", stderr);
  1.2470 +		exit(8);
  1.2471 +    }
  1.2472 +
  1.2473 +    /* set the policy bits true for all the cipher suites. */
  1.2474 +    if (useExportPolicy) {
  1.2475 +	NSS_SetExportPolicy();
  1.2476 +	if (disableStepDown) {
  1.2477 +	    fputs("selfserv: -x and -E options may not be used together\n", 
  1.2478 +	          stderr);
  1.2479 +	    exit(98);
  1.2480 +	}
  1.2481 +    } else {
  1.2482 +	NSS_SetDomesticPolicy();
  1.2483 +	if (disableStepDown) {
  1.2484 +	    rv = disableExportSSLCiphers();
  1.2485 +	    if (rv != SECSuccess) {
  1.2486 +		errExit("error disabling export ciphersuites ");
  1.2487 +	    }
  1.2488 +    	}
  1.2489 +    }
  1.2490 +
  1.2491 +    /* all the SSL2 and SSL3 cipher suites are enabled by default. */
  1.2492 +    if (cipherString) {
  1.2493 +    	char *cstringSaved = cipherString;
  1.2494 +    	int ndx;
  1.2495 +
  1.2496 +	/* disable all the ciphers, then enable the ones we want. */
  1.2497 +	disableAllSSLCiphers();
  1.2498 +
  1.2499 +	while (0 != (ndx = *cipherString++)) {
  1.2500 +	    int  cipher;
  1.2501 +
  1.2502 +	    if (ndx == ':') {
  1.2503 +		int ctmp;
  1.2504 +
  1.2505 +		cipher = 0;
  1.2506 +		HEXCHAR_TO_INT(*cipherString, ctmp)
  1.2507 +		cipher |= (ctmp << 12);
  1.2508 +		cipherString++;
  1.2509 +		HEXCHAR_TO_INT(*cipherString, ctmp)
  1.2510 +		cipher |= (ctmp << 8);
  1.2511 +		cipherString++;
  1.2512 +		HEXCHAR_TO_INT(*cipherString, ctmp)
  1.2513 +		cipher |= (ctmp << 4);
  1.2514 +		cipherString++;
  1.2515 +		HEXCHAR_TO_INT(*cipherString, ctmp)
  1.2516 +		cipher |= ctmp;
  1.2517 +		cipherString++;
  1.2518 +	    } else {
  1.2519 +		const int *cptr;
  1.2520 +
  1.2521 +		if (! isalpha(ndx)) {
  1.2522 +		    fprintf(stderr, 
  1.2523 +			    "Non-alphabetic char in cipher string (-c arg).\n");
  1.2524 +		    exit(9);
  1.2525 +		}
  1.2526 +		cptr = islower(ndx) ? ssl3CipherSuites : ssl2CipherSuites;
  1.2527 +		for (ndx &= 0x1f; (cipher = *cptr++) != 0 && --ndx > 0; ) 
  1.2528 +		    /* do nothing */;
  1.2529 +	    }
  1.2530 +	    if (cipher > 0) {
  1.2531 +		SECStatus status;
  1.2532 +		status = SSL_CipherPrefSetDefault(cipher, SSL_ALLOWED);
  1.2533 +		if (status != SECSuccess) 
  1.2534 +		    SECU_PrintError(progName, "SSL_CipherPrefSet()");
  1.2535 +	    } else {
  1.2536 +		fprintf(stderr, 
  1.2537 +			"Invalid cipher specification (-c arg).\n");
  1.2538 +		exit(9);
  1.2539 +	    }
  1.2540 +	}
  1.2541 +	PORT_Free(cstringSaved);
  1.2542 +    }
  1.2543 +
  1.2544 +    if (testbypass) {
  1.2545 +	const PRUint16 *cipherSuites = SSL_ImplementedCiphers;
  1.2546 +	int             i            = SSL_NumImplementedCiphers;
  1.2547 +	PRBool		enabled;
  1.2548 +
  1.2549 +	for (i=0; i < SSL_NumImplementedCiphers; i++, cipherSuites++) {
  1.2550 +	    if (SSL_CipherPrefGetDefault(*cipherSuites, &enabled) == SECSuccess
  1.2551 +				    && enabled)
  1.2552 +		savecipher(*cipherSuites);		    
  1.2553 +	}
  1.2554 +        protos = 0;
  1.2555 +        if (enabledVersions.min <= SSL_LIBRARY_VERSION_3_0 &&
  1.2556 +            enabledVersions.max >= SSL_LIBRARY_VERSION_3_0) {
  1.2557 +            protos |= SSL_CBP_SSL3;
  1.2558 +        }
  1.2559 +        if (enabledVersions.min <= SSL_LIBRARY_VERSION_TLS_1_0 &&
  1.2560 +            enabledVersions.max >= SSL_LIBRARY_VERSION_TLS_1_0) {
  1.2561 +            protos |= SSL_CBP_TLS1_0;
  1.2562 +        }
  1.2563 +        /* TLS 1.1 has the same SSL Bypass mode requirements as TLS 1.0 */
  1.2564 +        if (enabledVersions.min <= SSL_LIBRARY_VERSION_TLS_1_1 &&
  1.2565 +            enabledVersions.max >= SSL_LIBRARY_VERSION_TLS_1_1) {
  1.2566 +            protos |= SSL_CBP_TLS1_0;
  1.2567 +        }
  1.2568 +    }
  1.2569 +
  1.2570 +    certStatusArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1.2571 +    if (!certStatusArena)
  1.2572 +	errExit("cannot allocate certStatusArena");
  1.2573 +
  1.2574 +    if (nickName) {
  1.2575 +	cert[kt_rsa] = PK11_FindCertFromNickname(nickName, &pwdata);
  1.2576 +	if (cert[kt_rsa] == NULL) {
  1.2577 +	    fprintf(stderr, "selfserv: Can't find certificate %s\n", nickName);
  1.2578 +	    exit(10);
  1.2579 +	}
  1.2580 +	privKey[kt_rsa] = PK11_FindKeyByAnyCert(cert[kt_rsa], &pwdata);
  1.2581 +	if (privKey[kt_rsa] == NULL) {
  1.2582 +	    fprintf(stderr, "selfserv: Can't find Private Key for cert %s\n", 
  1.2583 +	            nickName);
  1.2584 +	    exit(11);
  1.2585 +	}
  1.2586 +	if (testbypass) {
  1.2587 +	    PRBool bypassOK;
  1.2588 +	    if (SSL_CanBypass(cert[kt_rsa], privKey[kt_rsa], protos, cipherlist, 
  1.2589 +	                      nciphers, &bypassOK, &pwdata) != SECSuccess) {
  1.2590 +		SECU_PrintError(progName, "Bypass test failed %s\n", nickName);
  1.2591 +		exit(14);
  1.2592 +	    }
  1.2593 +	    fprintf(stderr, "selfserv: %s can%s bypass\n", nickName,
  1.2594 +		    bypassOK ? "" : "not");
  1.2595 +	}
  1.2596 +	setupCertStatus(certStatusArena, ocspStaplingMode, cert[kt_rsa], kt_rsa,
  1.2597 +			&pwdata);
  1.2598 +    }
  1.2599 +#ifndef NSS_DISABLE_ECC
  1.2600 +    if (ecNickName) {
  1.2601 +	cert[kt_ecdh] = PK11_FindCertFromNickname(ecNickName, &pwdata);
  1.2602 +	if (cert[kt_ecdh] == NULL) {
  1.2603 +	    fprintf(stderr, "selfserv: Can't find certificate %s\n",
  1.2604 +		    ecNickName);
  1.2605 +	    exit(13);
  1.2606 +	}
  1.2607 +	privKey[kt_ecdh] = PK11_FindKeyByAnyCert(cert[kt_ecdh], &pwdata);
  1.2608 +	if (privKey[kt_ecdh] == NULL) {
  1.2609 +	    fprintf(stderr, "selfserv: Can't find Private Key for cert %s\n", 
  1.2610 +	            ecNickName);
  1.2611 +	    exit(11);
  1.2612 +	}	    
  1.2613 +	if (testbypass) {
  1.2614 +	    PRBool bypassOK;
  1.2615 +	    if (SSL_CanBypass(cert[kt_ecdh], privKey[kt_ecdh], protos, cipherlist,
  1.2616 +			      nciphers, &bypassOK, &pwdata) != SECSuccess) {
  1.2617 +		SECU_PrintError(progName, "Bypass test failed %s\n", ecNickName);
  1.2618 +		exit(15);
  1.2619 +	    }
  1.2620 +	    fprintf(stderr, "selfserv: %s can%s bypass\n", ecNickName,
  1.2621 +		    bypassOK ? "" : "not");
  1.2622 +	}
  1.2623 +	setupCertStatus(certStatusArena, ocspStaplingMode, cert[kt_ecdh], kt_ecdh,
  1.2624 +			&pwdata);
  1.2625 +    }
  1.2626 +#endif /* NSS_DISABLE_ECC */
  1.2627 +
  1.2628 +    if (testbypass)
  1.2629 +	goto cleanup;
  1.2630 +
  1.2631 +/* allocate the array of thread slots, and launch the worker threads. */
  1.2632 +    rv = launch_threads(&jobLoop, 0, 0, requestCert, useLocalThreads);
  1.2633 +
  1.2634 +    if (rv == SECSuccess && logStats) {
  1.2635 +	loggerThread = PR_CreateThread(PR_SYSTEM_THREAD, 
  1.2636 +			logger, NULL, PR_PRIORITY_NORMAL, 
  1.2637 +                        useLocalThreads ? PR_LOCAL_THREAD:PR_GLOBAL_THREAD,
  1.2638 +                        PR_JOINABLE_THREAD, 0);
  1.2639 +	if (loggerThread == NULL) {
  1.2640 +	    fprintf(stderr, "selfserv: Failed to launch logger thread!\n");
  1.2641 +	    rv = SECFailure;
  1.2642 +	} 
  1.2643 +    }
  1.2644 +
  1.2645 +    if (rv == SECSuccess) {
  1.2646 +	server_main(listen_sock, requestCert, privKey, cert,
  1.2647 +                    expectedHostNameVal);
  1.2648 +    }
  1.2649 +
  1.2650 +    VLOG(("selfserv: server_thread: exiting"));
  1.2651 +
  1.2652 +cleanup:
  1.2653 +    printSSLStatistics();
  1.2654 +    ssl3stats = SSL_GetStatistics();
  1.2655 +    if (ssl3stats->hch_sid_ticket_parse_failures != 0) {
  1.2656 +	fprintf(stderr, "selfserv: Experienced ticket parse failure(s)\n");
  1.2657 +	exit(1);
  1.2658 +    }
  1.2659 +    if (failedToNegotiateName) {
  1.2660 +        fprintf(stderr, "selfserv: Failed properly negotiate server name\n");
  1.2661 +        exit(1);
  1.2662 +    }
  1.2663 +
  1.2664 +    {
  1.2665 +	int i;
  1.2666 +	for (i=0; i<kt_kea_size; i++) {
  1.2667 +	    if (cert[i]) {
  1.2668 +		CERT_DestroyCertificate(cert[i]);
  1.2669 +	    }
  1.2670 +	    if (privKey[i]) {
  1.2671 +		SECKEY_DestroyPrivateKey(privKey[i]);
  1.2672 +	    }
  1.2673 +	}
  1.2674 +        for (i = 0;virtServerNameArray[i];i++) {
  1.2675 +            PORT_Free(virtServerNameArray[i]);
  1.2676 +        }
  1.2677 +    }
  1.2678 +
  1.2679 +    if (debugCache) {
  1.2680 +	nss_DumpCertificateCacheInfo();
  1.2681 +    }
  1.2682 +    if (nickName) {
  1.2683 +        PORT_Free(nickName);
  1.2684 +    }
  1.2685 +    if (expectedHostNameVal) {
  1.2686 +        PORT_Free(expectedHostNameVal);
  1.2687 +    }
  1.2688 +    if (passwd) {
  1.2689 +        PORT_Free(passwd);
  1.2690 +    }
  1.2691 +    if (pwfile) {
  1.2692 +        PORT_Free(pwfile);
  1.2693 +    }
  1.2694 +    if (certPrefix && certPrefix != emptyString) {                            
  1.2695 +        PORT_Free(certPrefix);
  1.2696 +    }
  1.2697 + #ifndef NSS_DISABLE_ECC
  1.2698 +    if (ecNickName) {
  1.2699 +        PORT_Free(ecNickName);
  1.2700 +    }
  1.2701 + #endif
  1.2702 +
  1.2703 +    if (hasSidCache) {
  1.2704 +	SSL_ShutdownServerSessionIDCache();
  1.2705 +    }
  1.2706 +    if (certStatusArena) {
  1.2707 +	PORT_FreeArena(certStatusArena, PR_FALSE);
  1.2708 +    }
  1.2709 +    if (NSS_Shutdown() != SECSuccess) {
  1.2710 +	SECU_PrintError(progName, "NSS_Shutdown");
  1.2711 +        if (loggerThread) {
  1.2712 +            PR_JoinThread(loggerThread);
  1.2713 +        }
  1.2714 +	PR_Cleanup();
  1.2715 +	exit(1);
  1.2716 +    }
  1.2717 +    PR_Cleanup();
  1.2718 +    printf("selfserv: normal termination\n");
  1.2719 +    return 0;
  1.2720 +}

mercurial