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 +}