Bug Summary

File:s/cmd/selfserv/selfserv.c
Warning:line 2303, column 5
Value stored to 'rv' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name selfserv.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/var/lib/jenkins/workspace/nss-scan-build/nss/cmd/selfserv -ffunction-sections -fdata-sections -fcoverage-compilation-dir=/var/lib/jenkins/workspace/nss-scan-build/nss/cmd/selfserv -resource-dir /usr/lib/llvm-18/lib/clang/18 -D HAVE_STRERROR -D LINUX -D linux -D XP_UNIX -D XP_UNIX -D NSPR20 -D DEBUG -U NDEBUG -D _DEFAULT_SOURCE -D _BSD_SOURCE -D _POSIX_SOURCE -D SDB_MEASURE_USE_TEMP_DIR -D _REENTRANT -D DEBUG -U NDEBUG -D _DEFAULT_SOURCE -D _BSD_SOURCE -D _POSIX_SOURCE -D SDB_MEASURE_USE_TEMP_DIR -D _REENTRANT -D NSS_DISABLE_SSE3 -D NSS_NO_INIT_SUPPORT -D USE_UTIL_DIRECTLY -D NO_NSPR_10_SUPPORT -D SSL_DISABLE_DEPRECATED_CIPHER_SUITE_NAMES -I ../../../dist/Linux4.19_x86_64_gcc_glibc_PTH_64_DBG.OBJ/include -I ../../../dist/public/nss -I ../../../dist/private/nss -I ../../../dist/public/seccmd -I ../../../dist/public/dbm -internal-isystem /usr/lib/llvm-18/lib/clang/18/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -std=c99 -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2024-05-18-082241-28900-1 -x c selfserv.c
1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5/* -r flag is interepreted as follows:
6 * 1 -r means request, not require, on initial handshake.
7 * 2 -r's mean request and require, on initial handshake.
8 * 3 -r's mean request, not require, on second handshake.
9 * 4 -r's mean request and require, on second handshake.
10 */
11#include <stdio.h>
12#include <string.h>
13
14#include "secutil.h"
15
16#if defined(XP_UNIX1)
17#include <unistd.h>
18#endif
19
20#if defined(_WINDOWS)
21#include <process.h> /* for getpid() */
22#endif
23
24#include <signal.h>
25#include <stdlib.h>
26#include <errno(*__errno_location ()).h>
27#include <fcntl.h>
28#include <stdarg.h>
29
30#include "nspr.h"
31#include "prio.h"
32#include "prerror.h"
33#include "prnetdb.h"
34#include "prclist.h"
35#include "plgetopt.h"
36#include "pk11func.h"
37#include "secitem.h"
38#include "nss.h"
39#include "ssl.h"
40#include "sslproto.h"
41#include "sslexp.h"
42#include "cert.h"
43#include "certt.h"
44#include "ocsp.h"
45#include "nssb64.h"
46
47#ifndef PORT_Strstrstrstr
48#define PORT_Strstrstrstr strstr
49#endif
50
51#ifndef PORT_MallocPR_Malloc
52#define PORT_MallocPR_Malloc PR_Malloc
53#endif
54
55int NumSidCacheEntries = 1024;
56
57static int handle_connection(PRFileDesc *, PRFileDesc *);
58
59static const char envVarName[] = { SSL_ENV_VAR_NAME"SSL_INHERITANCE" };
60static const char inheritableSockName[] = { "SELFSERV_LISTEN_SOCKET" };
61
62#define MAX_VIRT_SERVER_NAME_ARRAY_INDEX10 10
63#define MAX_CERT_NICKNAME_ARRAY_INDEX10 10
64
65#define DEFAULT_BULK_TEST16384 16384
66#define MAX_BULK_TEST1048576 1048576 /* 1 MB */
67static PRBool testBulk;
68static PRUint32 testBulkSize = DEFAULT_BULK_TEST16384;
69static PRInt32 testBulkTotal;
70static char *testBulkBuf;
71static PRDescIdentity log_layer_id = PR_INVALID_IO_LAYER(PRDescIdentity)-1;
72static PRFileDesc *loggingFD;
73static PRIOMethods loggingMethods;
74
75static PRBool logStats;
76static PRBool loggingLayer;
77static int logPeriod = 30;
78static PRInt32 loggerOps;
79static PRInt32 loggerBytes;
80static PRInt32 loggerBytesTCP;
81static PRInt32 bulkSentChunks;
82static enum ocspStaplingModeEnum {
83 osm_disabled, /* server doesn't support stapling */
84 osm_good, /* supply a signed good status */
85 osm_revoked, /* supply a signed revoked status */
86 osm_unknown, /* supply a signed unknown status */
87 osm_failure, /* supply a unsigned failure status, "try later" */
88 osm_badsig, /* supply a good status response with a bad signature */
89 osm_corrupted, /* supply a corrupted data block as the status */
90 osm_random, /* use a random response for each connection */
91 osm_ocsp /* retrieve ocsp status from external ocsp server,
92 use empty status if server is unavailable */
93} ocspStaplingMode = osm_disabled;
94typedef enum ocspStaplingModeEnum ocspStaplingModeType;
95static char *ocspStaplingCA = NULL((void*)0);
96static SECItemArray *certStatus[MAX_CERT_NICKNAME_ARRAY_INDEX10] = { NULL((void*)0) };
97
98const int ssl3CipherSuites[] = {
99 -1, /* SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA* a */
100 -1, /* SSL_FORTEZZA_DMS_WITH_RC4_128_SHA * b */
101 TLS_RSA_WITH_RC4_128_MD50x0004, /* c */
102 TLS_RSA_WITH_3DES_EDE_CBC_SHA0x000a, /* d */
103 TLS_RSA_WITH_DES_CBC_SHA0x0009, /* e */
104 -1, /* TLS_RSA_EXPORT_WITH_RC4_40_MD5 * f */
105 -1, /* TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 * g */
106 -1, /* SSL_FORTEZZA_DMS_WITH_NULL_SHA * h */
107 TLS_RSA_WITH_NULL_MD50x0001, /* i */
108 -1, /* SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA * j */
109 -1, /* SSL_RSA_FIPS_WITH_DES_CBC_SHA * k */
110 -1, /* TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA * l */
111 -1, /* TLS_RSA_EXPORT1024_WITH_RC4_56_SHA * m */
112 TLS_RSA_WITH_RC4_128_SHA0x0005, /* n */
113 TLS_DHE_DSS_WITH_RC4_128_SHA0x0066, /* o */
114 TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA0x0016, /* p */
115 TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA0x0013, /* q */
116 TLS_DHE_RSA_WITH_DES_CBC_SHA0x0015, /* r */
117 TLS_DHE_DSS_WITH_DES_CBC_SHA0x0012, /* s */
118 TLS_DHE_DSS_WITH_AES_128_CBC_SHA0x0032, /* t */
119 TLS_DHE_RSA_WITH_AES_128_CBC_SHA0x0033, /* u */
120 TLS_RSA_WITH_AES_128_CBC_SHA0x002F, /* v */
121 TLS_DHE_DSS_WITH_AES_256_CBC_SHA0x0038, /* w */
122 TLS_DHE_RSA_WITH_AES_256_CBC_SHA0x0039, /* x */
123 TLS_RSA_WITH_AES_256_CBC_SHA0x0035, /* y */
124 TLS_RSA_WITH_NULL_SHA0x0002, /* z */
125 0
126};
127
128/* data and structures for shutdown */
129static int stopping;
130
131static PRBool noDelay;
132static int requestCert;
133static int verbose;
134static SECItem bigBuf;
135static int configureDHE = -1; /* -1: don't configure, 0 disable, >=1 enable*/
136static int configureReuseECDHE = -1; /* -1: don't configure, 0 refresh, >=1 reuse*/
137static int configureWeakDHE = -1; /* -1: don't configure, 0 disable, >=1 enable*/
138SECItem psk = { siBuffer, NULL((void*)0), 0 };
139SECItem pskLabel = { siBuffer, NULL((void*)0), 0 };
140char *echParamsStr = NULL((void*)0);
141
142static PRThread *acceptorThread;
143
144static PRLogModuleInfo *lm;
145
146#define PRINTFif (verbose) printf \
147 if (verbose) \
148 printf
149#define FPRINTFif (verbose) fprintf \
150 if (verbose) \
151 fprintf
152#define FLUSHif (verbose) { fflush(stdout); fflush(stderr); } \
153 if (verbose) { \
154 fflush(stdoutstdout); \
155 fflush(stderrstderr); \
156 }
157#define VLOG(arg)do { if (((lm)->level >= (PR_LOG_DEBUG))) { PR_LogPrint
arg; } } while (0)
PR_LOG(lm, PR_LOG_DEBUG, arg)do { if (((lm)->level >= (PR_LOG_DEBUG))) { PR_LogPrint
arg; } } while (0)
158
159static void
160PrintUsageHeader(const char *progName)
161{
162 fprintf(stderrstderr,
163 "Usage: %s -n rsa_nickname -p port [-BDENRZbjlmrsuvx] [-w password]\n"
164 " [-t threads] [-i pid_file] [-c ciphers] [-Y] [-d dbdir] [-g numblocks]\n"
165 " [-f password_file] [-L [seconds]] [-M maxProcs] [-P dbprefix]\n"
166 " [-V [min-version]:[max-version]] [-a sni_name]\n"
167 " [ T <good|revoked|unknown|badsig|corrupted|none|ocsp>] [-A ca]\n"
168 " [-C SSLCacheEntries] [-S dsa_nickname] [-Q]\n"
169 " [-I groups] [-J signatureschemes] [-e ec_nickname]\n"
170 " -U [0|1] -H [0|1|2] -W [0|1] [-z externalPsk]\n"
171 "\n",
172 progName);
173}
174
175static void
176PrintParameterUsage()
177{
178 fputs(
179 "-V [min]:[max] restricts the set of enabled SSL/TLS protocol versions.\n"
180 " All versions are enabled by default.\n"
181 " Possible values for min/max: ssl3 tls1.0 tls1.1 tls1.2 tls1.3\n"
182 " Example: \"-V ssl3:\" enables SSL 3 and newer.\n"
183 "-D means disable Nagle delays in TCP\n"
184 "-R means disable detection of rollback from TLS to SSL3\n"
185 "-a configure server for SNI.\n"
186 "-k expected name negotiated on server sockets\n"
187 "-b means try binding to the port and exit\n"
188 "-m means test the model-socket feature of SSL_ImportFD.\n"
189 "-r flag is interepreted as follows:\n"
190 " 1 -r means request, not require, cert on initial handshake.\n"
191 " 2 -r's mean request and require, cert on initial handshake.\n"
192 " 3 -r's mean request, not require, cert on second handshake.\n"
193 " 4 -r's mean request and require, cert on second handshake.\n"
194 "-s means disable SSL socket locking for performance\n"
195 "-u means enable Session Ticket extension for TLS.\n"
196 "-v means verbose output\n"
197 "-L seconds means log statistics every 'seconds' seconds (default=30).\n"
198 "-M maxProcs tells how many processes to run in a multi-process server\n"
199 "-N means do NOT use the server session cache. Incompatible with -M.\n"
200 "-t threads -- specify the number of threads to use for connections.\n"
201 "-i pid_file file to write the process id of selfserve\n"
202 "-l means use local threads instead of global threads\n"
203 "-g numblocks means test throughput by sending total numblocks chunks\n"
204 " of size 16kb to the client, 0 means unlimited (default=0)\n"
205 "-j means measure TCP throughput (for use with -g option)\n"
206 "-C SSLCacheEntries sets the maximum number of entries in the SSL\n"
207 " session cache\n"
208 "-T <mode> enable OCSP stapling. Possible modes:\n"
209 " none: don't send cert status (default)\n"
210 " good, revoked, unknown: Include locally signed response. Requires: -A\n"
211 " failure: return a failure response (try later, unsigned)\n"
212 " badsig: use a good status but with an invalid signature\n"
213 " corrupted: stapled cert status is an invalid block of data\n"
214 " random: each connection uses a random status from this list:\n"
215 " good, revoked, unknown, failure, badsig, corrupted\n"
216 " ocsp: fetch from external OCSP server using AIA, or none\n"
217 "-A <ca> Nickname of a CA used to sign a stapled cert status\n"
218 "-U override default ECDHE ephemeral key reuse, 0: refresh, 1: reuse\n"
219 "-H override default DHE server support, 0: disable, 1: enable, "
220 " 2: require DH named groups [RFC7919]\n"
221 "-W override default DHE server weak parameters support, 0: disable, 1: enable\n"
222 "-c Restrict ciphers\n"
223 "-Y prints cipher values allowed for parameter -c and exits\n"
224 "-G enables the extended master secret extension [RFC7627]\n"
225 "-Q enables ALPN for HTTP/1.1 [RFC7301]\n"
226 "-I comma separated list of enabled groups for TLS key exchange.\n"
227 " The following values are valid:\n"
228 " P256, P384, P521, x25519, FF2048, FF3072, FF4096, FF6144, FF8192,\n"
229 " xyber768d00\n"
230 "-J comma separated list of enabled signature schemes in preference order.\n"
231 " The following values are valid:\n"
232 " rsa_pkcs1_sha1, rsa_pkcs1_sha256, rsa_pkcs1_sha384, rsa_pkcs1_sha512,\n"
233 " ecdsa_sha1, ecdsa_secp256r1_sha256, ecdsa_secp384r1_sha384,\n"
234 " ecdsa_secp521r1_sha512,\n"
235 " rsa_pss_rsae_sha256, rsa_pss_rsae_sha384, rsa_pss_rsae_sha512,\n"
236 " rsa_pss_pss_sha256, rsa_pss_pss_sha384, rsa_pss_pss_sha512,\n"
237 "-Z enable 0-RTT (for TLS 1.3; also use -u)\n"
238 "-E enable post-handshake authentication\n"
239 " (for TLS 1.3; only has an effect with 3 or more -r options)\n"
240 "-x Export and print keying material after successful handshake\n"
241 " The argument is a comma separated list of exporters in the form:\n"
242 " LABEL[:OUTPUT-LENGTH[:CONTEXT]]\n"
243 " where LABEL and CONTEXT can be either a free-form string or\n"
244 " a hex string if it is preceded by \"0x\"; OUTPUT-LENGTH\n"
245 " is a decimal integer.\n"
246 "-z Configure a TLS 1.3 External PSK with the given hex string for a key.\n"
247 " To specify a label, use ':' as a delimiter. For example:\n"
248 " 0xAAAABBBBCCCCDDDD:mylabel. Otherwise, the default label of\n"
249 " 'Client_identity' will be used.\n"
250 "-X Configure the server for ECH via the given <ECHParams>. ECHParams\n"
251 " are expected in one of two formats:\n"
252 " 1. A string containing the ECH public name prefixed by the substring\n"
253 " \"publicname:\". For example, \"publicname:example.com\". In this mode,\n"
254 " an ephemeral ECH keypair is generated and ECHConfigs are printed to stdout.\n"
255 " 2. As a Base64 tuple of <ECHRawPrivateKey> || <ECHConfigs>. In this mode, the\n"
256 " raw private key is used to bootstrap the HPKE context.\n",
257 stderrstderr);
258}
259
260static void
261Usage(const char *progName)
262{
263 PrintUsageHeader(progName);
264 PrintParameterUsage();
265}
266
267static void
268PrintCipherUsage(const char *progName)
269{
270 PrintUsageHeader(progName);
271 fputs(
272 "-c ciphers Letter(s) chosen from the following list\n"
273 "c SSL3 RSA WITH RC4 128 MD5\n"
274 "d SSL3 RSA WITH 3DES EDE CBC SHA\n"
275 "e SSL3 RSA WITH DES CBC SHA\n"
276 "f SSL3 RSA EXPORT WITH RC4 40 MD5\n"
277 "g SSL3 RSA EXPORT WITH RC2 CBC 40 MD5\n"
278 "i SSL3 RSA WITH NULL MD5\n"
279 "j SSL3 RSA FIPS WITH 3DES EDE CBC SHA\n"
280 "k SSL3 RSA FIPS WITH DES CBC SHA\n"
281 "l SSL3 RSA EXPORT WITH DES CBC SHA\t(new)\n"
282 "m SSL3 RSA EXPORT WITH RC4 56 SHA\t(new)\n"
283 "n SSL3 RSA WITH RC4 128 SHA\n"
284 "o TLS_DHE_DSS_WITH_RC4_128_SHA\n"
285 "p TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA\n"
286 "q TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA\n"
287 "r TLS_DHE_RSA_WITH_DES_CBC_SHA\n"
288 "s TLS_DHE_DSS_WITH_DES_CBC_SHA\n"
289 "t TLS_DHE_DSS_WITH_AES_128_CBC_SHA\n"
290 "u TLS_DHE_RSA_WITH_AES_128_CBC_SHA\n"
291 "v SSL3 RSA WITH AES 128 CBC SHA\n"
292 "w TLS_DHE_DSS_WITH_AES_256_CBC_SHA\n"
293 "x TLS_DHE_RSA_WITH_AES_256_CBC_SHA\n"
294 "y SSL3 RSA WITH AES 256 CBC SHA\n"
295 "z SSL3 RSA WITH NULL SHA\n"
296 "\n"
297 ":WXYZ Use cipher with hex code { 0xWX , 0xYZ } in TLS\n",
298 stderrstderr);
299}
300
301static const char *
302errWarn(char *funcString)
303{
304 PRErrorCode perr = PR_GetError();
305 const char *errString = SECU_Strerror(perr)PR_ErrorToString((perr), 0);
306
307 fprintf(stderrstderr, "selfserv: %s returned error %d:\n%s\n",
308 funcString, perr, errString);
309 return errString;
310}
311
312static void
313errExit(char *funcString)
314{
315 errWarn(funcString);
316 exit(3);
317}
318
319/**************************************************************************
320**
321** Routines for disabling SSL ciphers.
322**
323**************************************************************************/
324
325/* disable all the SSL cipher suites */
326void
327disableAllSSLCiphers(void)
328{
329 const PRUint16 *cipherSuites = SSL_ImplementedCiphers;
330 int i = SSL_NumImplementedCiphers;
331 SECStatus rv;
332
333 while (--i >= 0) {
334 PRUint16 suite = cipherSuites[i];
335 rv = SSL_CipherPrefSetDefault(suite, PR_FALSE0);
336 if (rv != SECSuccess) {
337 printf("SSL_CipherPrefSetDefault rejected suite 0x%04x (i = %d)\n",
338 suite, i);
339 errWarn("SSL_CipherPrefSetDefault");
340 }
341 }
342}
343
344static SECStatus
345mySSLAuthCertificate(void *arg, PRFileDesc *fd, PRBool checkSig,
346 PRBool isServer)
347{
348 SECStatus rv;
349 CERTCertificate *peerCert;
350
351 peerCert = SSL_PeerCertificate(fd);
352
353 if (peerCert) {
354 PRINTFif (verbose) printf("selfserv: Subject: %s\nselfserv: Issuer : %s\n",
355 peerCert->subjectName, peerCert->issuerName);
356 CERT_DestroyCertificate(peerCert);
357 }
358
359 rv = SSL_AuthCertificate(arg, fd, checkSig, isServer);
360
361 if (rv == SECSuccess) {
362 PRINTFif (verbose) printf("selfserv: -- SSL3: Certificate Validated.\n");
363 } else {
364 int err = PR_GetError();
365 FPRINTFif (verbose) fprintf(stderrstderr, "selfserv: -- SSL3: Certificate Invalid, err %d.\n%s\n",
366 err, SECU_Strerror(err)PR_ErrorToString((err), 0));
367 }
368 FLUSHif (verbose) { fflush(stdout); fflush(stderr); };
369 return rv;
370}
371
372void
373printSSLStatistics()
374{
375 SSL3Statistics *ssl3stats = SSL_GetStatistics();
376
377 printf(
378 "selfserv: %ld cache hits; %ld cache misses, %ld cache not reusable\n"
379 " %ld stateless resumes, %ld ticket parse failures\n",
380 ssl3stats->hch_sid_cache_hits, ssl3stats->hch_sid_cache_misses,
381 ssl3stats->hch_sid_cache_not_ok, ssl3stats->hch_sid_stateless_resumes,
382 ssl3stats->hch_sid_ticket_parse_failures);
383}
384
385void
386printSecurityInfo(PRFileDesc *fd)
387{
388 CERTCertificate *cert = NULL((void*)0);
389 SECStatus result;
390 SSLChannelInfo channel;
391 SSLCipherSuiteInfo suite;
392
393 if (verbose)
394 printSSLStatistics();
395
396 result = SSL_GetChannelInfo(fd, &channel, sizeof channel);
397 if (result == SECSuccess &&
398 channel.length == sizeof channel &&
399 channel.cipherSuite) {
400 result = SSL_GetCipherSuiteInfo(channel.cipherSuite,
401 &suite, sizeof suite);
402 if (result == SECSuccess) {
403 FPRINTFif (verbose) fprintf(stderrstderr,
404 "selfserv: SSL version %d.%d using %d-bit %s with %d-bit %s MAC%s\n",
405 channel.protocolVersion >> 8, channel.protocolVersion & 0xff,
406 suite.effectiveKeyBits, suite.symCipherName,
407 suite.macBits, suite.macAlgorithmName,
408 channel.isFIPS ? " FIPS" : "");
409 FPRINTFif (verbose) fprintf(stderrstderr,
410 "selfserv: Server Auth: %d-bit %s, Key Exchange: %d-bit %s\n"
411 " Compression: %s, Extended Master Secret: %s\n",
412 channel.authKeyBits, suite.authAlgorithmName,
413 channel.keaKeyBits, suite.keaTypeName,
414 channel.compressionMethodName,
415 channel.extendedMasterSecretUsed ? "Yes" : "No");
416 }
417 }
418 if (verbose) {
419 SECItem *hostInfo = SSL_GetNegotiatedHostInfo(fd);
420 if (hostInfo) {
421 char namePref[] = "selfserv: Negotiated server name: ";
422
423 fprintf(stderrstderr, "%s", namePref);
424 fwrite(hostInfo->data, hostInfo->len, 1, stderrstderr);
425 SECITEM_FreeItemSECITEM_FreeItem_Util(hostInfo, PR_TRUE1);
426 hostInfo = NULL((void*)0);
427 fprintf(stderrstderr, "\n");
428 }
429 }
430 if (requestCert)
431 cert = SSL_PeerCertificate(fd);
432 else
433 cert = SSL_LocalCertificate(fd);
434 if (cert) {
435 char *ip = CERT_NameToAscii(&cert->issuer);
436 char *sp = CERT_NameToAscii(&cert->subject);
437 if (sp) {
438 FPRINTFif (verbose) fprintf(stderrstderr, "selfserv: subject DN: %s\n", sp);
439 PORT_FreePORT_Free_Util(sp);
440 }
441 if (ip) {
442 FPRINTFif (verbose) fprintf(stderrstderr, "selfserv: issuer DN: %s\n", ip);
443 PORT_FreePORT_Free_Util(ip);
444 }
445 CERT_DestroyCertificate(cert);
446 cert = NULL((void*)0);
447 }
448 FLUSHif (verbose) { fflush(stdout); fflush(stderr); };
449}
450
451static int MakeCertOK;
452
453static SECStatus
454myBadCertHandler(void *arg, PRFileDesc *fd)
455{
456 int err = PR_GetError();
457 if (!MakeCertOK)
458 fprintf(stderrstderr,
459 "selfserv: -- SSL: Client Certificate Invalid, err %d.\n%s\n",
460 err, SECU_Strerror(err)PR_ErrorToString((err), 0));
461 return (MakeCertOK ? SECSuccess : SECFailure);
462}
463
464/* Simple SNI socket config function that does not use SSL_ReconfigFD.
465 * Only uses one server name but verifies that the names match. */
466PRInt32
467mySSLSNISocketConfig(PRFileDesc *fd, const SECItem *sniNameArr,
468 PRUint32 sniNameArrSize, void *arg)
469{
470 PRInt32 i = 0;
471 const SECItem *current = sniNameArr;
472 const char **nameArr = (const char **)arg;
473 secuPWData *pwdata;
474 CERTCertificate *cert = NULL((void*)0);
475 SECKEYPrivateKey *privKey = NULL((void*)0);
476
477 PORT_Assert(fd && sniNameArr)((fd && sniNameArr)?((void)0):PR_Assert("fd && sniNameArr"
,"selfserv.c",477))
;
478 if (!fd || !sniNameArr) {
479 return SSL_SNI_SEND_ALERT-2;
480 }
481
482 pwdata = SSL_RevealPinArg(fd);
483
484 for (; current && (PRUint32)i < sniNameArrSize; i++) {
485 unsigned int j = 0;
486 for (; j < MAX_VIRT_SERVER_NAME_ARRAY_INDEX10 && nameArr[j]; j++) {
487 if (!PORT_Strncmpstrncmp(nameArr[j],
488 (const char *)current[i].data,
489 current[i].len) &&
490 PORT_Strlen(nameArr[j])strlen(nameArr[j]) == current[i].len) {
491 const char *nickName = nameArr[j];
492 if (j == 0) {
493 /* default cert */
494 return 0;
495 }
496 /* if pwdata is NULL, then we would not get the key and
497 * return an error status. */
498 cert = PK11_FindCertFromNickname(nickName, &pwdata);
499 if (cert == NULL((void*)0)) {
500 goto loser; /* Send alert */
501 }
502 privKey = PK11_FindKeyByAnyCert(cert, &pwdata);
503 if (privKey == NULL((void*)0)) {
504 goto loser; /* Send alert */
505 }
506 if (SSL_ConfigServerCert(fd, cert, privKey, NULL((void*)0), 0) != SECSuccess) {
507 goto loser; /* Send alert */
508 }
509 SECKEY_DestroyPrivateKey(privKey);
510 CERT_DestroyCertificate(cert);
511 return i;
512 }
513 }
514 }
515loser:
516 if (privKey) {
517 SECKEY_DestroyPrivateKey(privKey);
518 }
519 if (cert) {
520 CERT_DestroyCertificate(cert);
521 }
522 return SSL_SNI_SEND_ALERT-2;
523}
524
525/**************************************************************************
526** Begin thread management routines and data.
527**************************************************************************/
528#define MIN_THREADS3 3
529#define DEFAULT_THREADS8 8
530#define MAX_THREADS4096 4096
531#define MAX_PROCS25 25
532static int maxThreads = DEFAULT_THREADS8;
533
534typedef struct jobStr {
535 PRCList link;
536 PRFileDesc *tcp_sock;
537 PRFileDesc *model_sock;
538} JOB;
539
540static PZLockPRLock *qLock; /* this lock protects all data immediately below */
541static PRLock *lastLoadedCrlLock; /* this lock protects lastLoadedCrl variable */
542static PZCondVarPRCondVar *jobQNotEmptyCv;
543static PZCondVarPRCondVar *freeListNotEmptyCv;
544static PZCondVarPRCondVar *threadCountChangeCv;
545static int threadCount;
546static PRCList jobQ;
547static PRCList freeJobs;
548static JOB *jobTable;
549
550SECStatus
551setupJobs(int maxJobs)
552{
553 int i;
554
555 jobTable = (JOB *)PR_Calloc(maxJobs, sizeof(JOB));
556 if (!jobTable)
557 return SECFailure;
558
559 PR_INIT_CLIST(&jobQ)do { (&jobQ)->next = (&jobQ); (&jobQ)->prev
= (&jobQ); } while (0)
;
560 PR_INIT_CLIST(&freeJobs)do { (&freeJobs)->next = (&freeJobs); (&freeJobs
)->prev = (&freeJobs); } while (0)
;
561
562 for (i = 0; i < maxJobs; ++i) {
563 JOB *pJob = jobTable + i;
564 PR_APPEND_LINK(&pJob->link, &freeJobs)do { (&pJob->link)->next = (&freeJobs); (&pJob
->link)->prev = (&freeJobs)->prev; (&freeJobs
)->prev->next = (&pJob->link); (&freeJobs)->
prev = (&pJob->link); } while (0)
;
565 }
566 return SECSuccess;
567}
568
569typedef int startFn(PRFileDesc *a, PRFileDesc *b);
570
571typedef enum { rs_idle = 0,
572 rs_running = 1,
573 rs_zombie = 2 } runState;
574
575typedef struct perThreadStr {
576 PRFileDesc *a;
577 PRFileDesc *b;
578 int rv;
579 startFn *startFunc;
580 PRThread *prThread;
581 runState state;
582} perThread;
583
584static perThread *threads;
585
586void
587thread_wrapper(void *arg)
588{
589 perThread *slot = (perThread *)arg;
590
591 slot->rv = (*slot->startFunc)(slot->a, slot->b);
592
593 /* notify the thread exit handler. */
594 PZ_Lock(qLock)PR_Lock((qLock));
595 slot->state = rs_zombie;
596 --threadCount;
597 PZ_NotifyAllCondVar(threadCountChangeCv)PR_NotifyAllCondVar((threadCountChangeCv));
598 PZ_Unlock(qLock)PR_Unlock((qLock));
599}
600
601int
602jobLoop(PRFileDesc *a, PRFileDesc *b)
603{
604 PRCList *myLink = 0;
605 JOB *myJob;
606
607 PZ_Lock(qLock)PR_Lock((qLock));
608 do {
609 myLink = 0;
610 while (PR_CLIST_IS_EMPTY(&jobQ)((&jobQ)->next == (&jobQ)) && !stopping) {
611 PZ_WaitCondVar(jobQNotEmptyCv, PR_INTERVAL_NO_TIMEOUT)PR_WaitCondVar((jobQNotEmptyCv), (0xffffffffUL));
612 }
613 if (!PR_CLIST_IS_EMPTY(&jobQ)((&jobQ)->next == (&jobQ))) {
614 myLink = PR_LIST_HEAD(&jobQ)(&jobQ)->next;
615 PR_REMOVE_AND_INIT_LINK(myLink)do { (myLink)->prev->next = (myLink)->next; (myLink)
->next->prev = (myLink)->prev; (myLink)->next = (
myLink); (myLink)->prev = (myLink); } while (0)
;
616 }
617 PZ_Unlock(qLock)PR_Unlock((qLock));
618 myJob = (JOB *)myLink;
619 /* myJob will be null when stopping is true and jobQ is empty */
620 if (!myJob)
621 break;
622 handle_connection(myJob->tcp_sock, myJob->model_sock);
623 PZ_Lock(qLock)PR_Lock((qLock));
624 PR_APPEND_LINK(myLink, &freeJobs)do { (myLink)->next = (&freeJobs); (myLink)->prev =
(&freeJobs)->prev; (&freeJobs)->prev->next =
(myLink); (&freeJobs)->prev = (myLink); } while (0)
;
625 PZ_NotifyCondVar(freeListNotEmptyCv)PR_NotifyCondVar((freeListNotEmptyCv));
626 } while (PR_TRUE1);
627 return 0;
628}
629
630SECStatus
631launch_threads(
632 startFn *startFunc,
633 PRFileDesc *a,
634 PRFileDesc *b,
635 PRBool local)
636{
637 int i;
638 SECStatus rv = SECSuccess;
639
640 /* create the thread management serialization structs */
641 qLock = PZ_NewLock(nssILockSelfServ)PR_NewLock();
642 jobQNotEmptyCv = PZ_NewCondVar(qLock)PR_NewCondVar((qLock));
643 freeListNotEmptyCv = PZ_NewCondVar(qLock)PR_NewCondVar((qLock));
644 threadCountChangeCv = PZ_NewCondVar(qLock)PR_NewCondVar((qLock));
645
646 /* create monitor for crl reload procedure */
647 lastLoadedCrlLock = PR_NewLock();
648
649 /* allocate the array of thread slots */
650 threads = PR_Calloc(maxThreads, sizeof(perThread));
651 if (NULL((void*)0) == threads) {
652 fprintf(stderrstderr, "Oh Drat! Can't allocate the perThread array\n");
653 return SECFailure;
654 }
655 /* 5 is a little extra, intended to keep the jobQ from underflowing.
656 ** That is, from going empty while not stopping and clients are still
657 ** trying to contact us.
658 */
659 rv = setupJobs(maxThreads + 5);
660 if (rv != SECSuccess)
661 return rv;
662
663 PZ_Lock(qLock)PR_Lock((qLock));
664 for (i = 0; i < maxThreads; ++i) {
665 perThread *slot = threads + i;
666
667 slot->state = rs_running;
668 slot->a = a;
669 slot->b = b;
670 slot->startFunc = startFunc;
671 slot->prThread = PR_CreateThread(PR_USER_THREAD,
672 thread_wrapper, slot, PR_PRIORITY_NORMAL,
673 (PR_TRUE1 ==
674 local)
675 ? PR_LOCAL_THREAD
676 : PR_GLOBAL_THREAD,
677 PR_JOINABLE_THREAD, 0);
678 if (slot->prThread == NULL((void*)0)) {
679 printf("selfserv: Failed to launch thread!\n");
680 slot->state = rs_idle;
681 rv = SECFailure;
682 break;
683 }
684
685 ++threadCount;
686 }
687 PZ_Unlock(qLock)PR_Unlock((qLock));
688
689 return rv;
690}
691
692#define DESTROY_CONDVAR(name)if (name) { PR_DestroyCondVar((name)); name = ((void*)0); } \
693 if (name) { \
694 PZ_DestroyCondVar(name)PR_DestroyCondVar((name)); \
695 name = NULL((void*)0); \
696 }
697#define DESTROY_LOCK(name)if (name) { PR_DestroyLock((name)); name = ((void*)0); } \
698 if (name) { \
699 PZ_DestroyLock(name)PR_DestroyLock((name)); \
700 name = NULL((void*)0); \
701 }
702
703void
704terminateWorkerThreads(void)
705{
706 int i;
707
708 VLOG(("selfserv: server_thread: waiting on stopping"))do { if (((lm)->level >= (PR_LOG_DEBUG))) { PR_LogPrint
("selfserv: server_thread: waiting on stopping"); } } while (
0)
;
709 PZ_Lock(qLock)PR_Lock((qLock));
710 PZ_NotifyAllCondVar(jobQNotEmptyCv)PR_NotifyAllCondVar((jobQNotEmptyCv));
711 PZ_Unlock(qLock)PR_Unlock((qLock));
712
713 /* Wait for worker threads to terminate. */
714 for (i = 0; i < maxThreads; ++i) {
715 perThread *slot = threads + i;
716 if (slot->prThread) {
717 PR_JoinThread(slot->prThread);
718 }
719 }
720
721 /* The worker threads empty the jobQ before they terminate. */
722 PZ_Lock(qLock)PR_Lock((qLock));
723 PORT_Assert(threadCount == 0)((threadCount == 0)?((void)0):PR_Assert("threadCount == 0","selfserv.c"
,723))
;
724 PORT_Assert(PR_CLIST_IS_EMPTY(&jobQ))((((&jobQ)->next == (&jobQ)))?((void)0):PR_Assert(
"PR_CLIST_IS_EMPTY(&jobQ)","selfserv.c",724))
;
725 PZ_Unlock(qLock)PR_Unlock((qLock));
726
727 DESTROY_CONDVAR(jobQNotEmptyCv)if (jobQNotEmptyCv) { PR_DestroyCondVar((jobQNotEmptyCv)); jobQNotEmptyCv
= ((void*)0); }
;
728 DESTROY_CONDVAR(freeListNotEmptyCv)if (freeListNotEmptyCv) { PR_DestroyCondVar((freeListNotEmptyCv
)); freeListNotEmptyCv = ((void*)0); }
;
729 DESTROY_CONDVAR(threadCountChangeCv)if (threadCountChangeCv) { PR_DestroyCondVar((threadCountChangeCv
)); threadCountChangeCv = ((void*)0); }
;
730
731 PR_DestroyLock(lastLoadedCrlLock);
732 DESTROY_LOCK(qLock)if (qLock) { PR_DestroyLock((qLock)); qLock = ((void*)0); };
733 PR_Free(jobTable);
734 PR_Free(threads);
735}
736
737static void
738logger(void *arg)
739{
740 PRFloat64 seconds;
741 PRFloat64 opsPerSec;
742 PRIntervalTime period;
743 PRIntervalTime previousTime;
744 PRIntervalTime latestTime;
745 PRInt32 previousOps;
746 PRInt32 ops;
747 PRIntervalTime logPeriodTicks = PR_TicksPerSecond();
748 PRFloat64 secondsPerTick = 1.0 / (PRFloat64)logPeriodTicks;
749 int iterations = 0;
750 int secondsElapsed = 0;
751 static PRInt64 totalPeriodBytes = 0;
752 static PRInt64 totalPeriodBytesTCP = 0;
753
754 previousOps = loggerOps;
755 previousTime = PR_IntervalNow();
756
757 for (;;) {
758 /* OK, implementing a new sleep algorithm here... always sleep
759 * for 1 second but print out info at the user-specified interval.
760 * This way, we don't overflow all of our PR_Atomic* functions and
761 * we don't have to use locks.
762 */
763 PR_Sleep(logPeriodTicks);
764 secondsElapsed++;
765 totalPeriodBytes += PR_ATOMIC_SET(&loggerBytes, 0)__sync_lock_test_and_set(&loggerBytes, 0);
766 totalPeriodBytesTCP += PR_ATOMIC_SET(&loggerBytesTCP, 0)__sync_lock_test_and_set(&loggerBytesTCP, 0);
767 if (secondsElapsed != logPeriod) {
768 continue;
769 }
770 /* when we reach the user-specified logging interval, print out all
771 * data
772 */
773 secondsElapsed = 0;
774 latestTime = PR_IntervalNow();
775 ops = loggerOps;
776 period = latestTime - previousTime;
777 seconds = (PRFloat64)period * secondsPerTick;
778 opsPerSec = (ops - previousOps) / seconds;
779
780 if (testBulk) {
781 if (iterations == 0) {
782 if (loggingLayer == PR_TRUE1) {
783 printf("Conn.--------App Data--------TCP Data\n");
784 } else {
785 printf("Conn.--------App Data\n");
786 }
787 }
788 if (loggingLayer == PR_TRUE1) {
789 printf("%4.d %5.3f MB/s %5.3f MB/s\n", ops,
790 totalPeriodBytes / (seconds * 1048576.0),
791 totalPeriodBytesTCP / (seconds * 1048576.0));
792 } else {
793 printf("%4.d %5.3f MB/s\n", ops,
794 totalPeriodBytes / (seconds * 1048576.0));
795 }
796 totalPeriodBytes = 0;
797 totalPeriodBytesTCP = 0;
798 /* Print the "legend" every 20 iterations */
799 iterations = (iterations + 1) % 20;
800 } else {
801 printf("%.2f ops/second, %d threads\n", opsPerSec, threadCount);
802 }
803
804 fflush(stdoutstdout);
805 previousOps = ops;
806 previousTime = latestTime;
807 if (stopping) {
808 break;
809 }
810 }
811}
812
813/**************************************************************************
814** End thread management routines.
815**************************************************************************/
816
817PRBool useModelSocket = PR_FALSE0;
818static SSLVersionRange enabledVersions;
819PRBool disableRollBack = PR_FALSE0;
820PRBool NoReuse = PR_FALSE0;
821PRBool hasSidCache = PR_FALSE0;
822PRBool disableLocking = PR_FALSE0;
823PRBool enableSessionTickets = PR_FALSE0;
824PRBool failedToNegotiateName = PR_FALSE0;
825PRBool enableExtendedMasterSecret = PR_FALSE0;
826PRBool zeroRTT = PR_FALSE0;
827SSLAntiReplayContext *antiReplay = NULL((void*)0);
828PRBool enableALPN = PR_FALSE0;
829PRBool enablePostHandshakeAuth = PR_FALSE0;
830SSLNamedGroup *enabledGroups = NULL((void*)0);
831unsigned int enabledGroupsCount = 0;
832const SSLSignatureScheme *enabledSigSchemes = NULL((void*)0);
833unsigned int enabledSigSchemeCount = 0;
834const secuExporter *enabledExporters = NULL((void*)0);
835unsigned int enabledExporterCount = 0;
836
837static char *virtServerNameArray[MAX_VIRT_SERVER_NAME_ARRAY_INDEX10];
838static int virtServerNameIndex = 1;
839
840static char *certNicknameArray[MAX_CERT_NICKNAME_ARRAY_INDEX10];
841static int certNicknameIndex = 0;
842
843static const char stopCmd[] = { "GET /stop " };
844static const char getCmd[] = { "GET " };
845static const char EOFmsg[] = { "EOF\r\n\r\n\r\n" };
846static const char outHeader[] = {
847 "HTTP/1.0 200 OK\r\n"
848 "Server: Generic Web Server\r\n"
849 "Date: Tue, 26 Aug 1997 22:10:05 GMT\r\n"
850 "Content-type: text/plain\r\n"
851 "\r\n"
852};
853static const char crlCacheErr[] = { "CRL ReCache Error: " };
854
855PRUint16 cipherlist[100];
856int nciphers;
857
858void
859savecipher(int c)
860{
861 if (nciphers < sizeof cipherlist / sizeof(cipherlist[0]))
862 cipherlist[nciphers++] = (PRUint16)c;
863}
864
865#ifdef FULL_DUPLEX_CAPABLE
866
867struct lockedVarsStr {
868 PZLockPRLock *lock;
869 int count;
870 int waiters;
871 PZCondVarPRCondVar *condVar;
872};
873
874typedef struct lockedVarsStr lockedVars;
875
876void
877lockedVars_Init(lockedVars *lv)
878{
879 lv->count = 0;
880 lv->waiters = 0;
881 lv->lock = PZ_NewLock(nssILockSelfServ)PR_NewLock();
882 lv->condVar = PZ_NewCondVar(lv->lock)PR_NewCondVar((lv->lock));
883}
884
885void
886lockedVars_Destroy(lockedVars *lv)
887{
888 PZ_DestroyCondVar(lv->condVar)PR_DestroyCondVar((lv->condVar));
889 lv->condVar = NULL((void*)0);
890
891 PZ_DestroyLock(lv->lock)PR_DestroyLock((lv->lock));
892 lv->lock = NULL((void*)0);
893}
894
895void
896lockedVars_WaitForDone(lockedVars *lv)
897{
898 PZ_Lock(lv->lock)PR_Lock((lv->lock));
899 while (lv->count > 0) {
900 PZ_WaitCondVar(lv->condVar, PR_INTERVAL_NO_TIMEOUT)PR_WaitCondVar((lv->condVar), (0xffffffffUL));
901 }
902 PZ_Unlock(lv->lock)PR_Unlock((lv->lock));
903}
904
905int /* returns count */
906lockedVars_AddToCount(lockedVars *lv, int addend)
907{
908 int rv;
909
910 PZ_Lock(lv->lock)PR_Lock((lv->lock));
911 rv = lv->count += addend;
912 if (rv <= 0) {
913 PZ_NotifyCondVar(lv->condVar)PR_NotifyCondVar((lv->condVar));
914 }
915 PZ_Unlock(lv->lock)PR_Unlock((lv->lock));
916 return rv;
917}
918
919int
920do_writes(
921 PRFileDesc *ssl_sock,
922 PRFileDesc *model_sock)
923{
924 int sent = 0;
925 int count = 0;
926 lockedVars *lv = (lockedVars *)model_sock;
927
928 VLOG(("selfserv: do_writes: starting"))do { if (((lm)->level >= (PR_LOG_DEBUG))) { PR_LogPrint
("selfserv: do_writes: starting"); } } while (0)
;
929 while (sent < bigBuf.len) {
930
931 count = PR_Write(ssl_sock, bigBuf.data + sent, bigBuf.len - sent);
932 if (count < 0) {
933 errWarn("PR_Write bigBuf");
934 break;
935 }
936 FPRINTFif (verbose) fprintf(stderrstderr, "selfserv: PR_Write wrote %d bytes from bigBuf\n", count);
937 sent += count;
938 }
939 if (count >= 0) { /* last write didn't fail. */
940 PR_Shutdown(ssl_sock, PR_SHUTDOWN_SEND);
941 }
942
943 /* notify the reader that we're done. */
944 lockedVars_AddToCount(lv, -1);
945 FLUSHif (verbose) { fflush(stdout); fflush(stderr); };
946 VLOG(("selfserv: do_writes: exiting"))do { if (((lm)->level >= (PR_LOG_DEBUG))) { PR_LogPrint
("selfserv: do_writes: exiting"); } } while (0)
;
947 return (sent < bigBuf.len) ? SECFailure : SECSuccess;
948}
949
950static int
951handle_fdx_connection(
952 PRFileDesc *tcp_sock,
953 PRFileDesc *model_sock)
954{
955 PRFileDesc *ssl_sock = NULL((void*)0);
956 SECStatus result;
957 int firstTime = 1;
958 lockedVars lv;
959 PRSocketOptionData opt;
960 char buf[10240];
961
962 VLOG(("selfserv: handle_fdx_connection: starting"))do { if (((lm)->level >= (PR_LOG_DEBUG))) { PR_LogPrint
("selfserv: handle_fdx_connection: starting"); } } while (0)
;
963 opt.option = PR_SockOpt_Nonblocking;
964 opt.value.non_blocking = PR_FALSE0;
965 PR_SetSocketOption(tcp_sock, &opt);
966
967 if (useModelSocket && model_sock) {
968 SECStatus rv;
969 ssl_sock = SSL_ImportFD(model_sock, tcp_sock);
970 if (!ssl_sock) {
971 errWarn("SSL_ImportFD with model");
972 goto cleanup;
973 }
974 rv = SSL_ResetHandshake(ssl_sock, /* asServer */ 1);
975 if (rv != SECSuccess) {
976 errWarn("SSL_ResetHandshake");
977 goto cleanup;
978 }
979 } else {
980 ssl_sock = tcp_sock;
981 }
982
983 lockedVars_Init(&lv);
984 lockedVars_AddToCount(&lv, 1);
985
986 /* Attempt to launch the writer thread. */
987 result = launch_thread(do_writes, ssl_sock, (PRFileDesc *)&lv);
988
989 if (result == SECSuccess)
990 do {
991 /* do reads here. */
992 int count;
993 count = PR_Read(ssl_sock, buf, sizeof buf);
994 if (count < 0) {
995 errWarn("FDX PR_Read");
996 break;
997 }
998 FPRINTFif (verbose) fprintf(stderrstderr, "selfserv: FDX PR_Read read %d bytes.\n", count);
999 if (firstTime) {
1000 firstTime = 0;
1001 printSecurityInfo(ssl_sock);
1002 }
1003 } while (lockedVars_AddToCount(&lv, 0) > 0);
1004
1005 /* Wait for writer to finish */
1006 lockedVars_WaitForDone(&lv);
1007 lockedVars_Destroy(&lv);
1008 FLUSHif (verbose) { fflush(stdout); fflush(stderr); };
1009
1010cleanup:
1011 if (ssl_sock) {
1012 PR_Close(ssl_sock);
1013 } else if (tcp_sock) {
1014 PR_Close(tcp_sock);
1015 }
1016
1017 VLOG(("selfserv: handle_fdx_connection: exiting"))do { if (((lm)->level >= (PR_LOG_DEBUG))) { PR_LogPrint
("selfserv: handle_fdx_connection: exiting"); } } while (0)
;
1018 return SECSuccess;
1019}
1020
1021#endif
1022
1023static SECItem *lastLoadedCrl = NULL((void*)0);
1024
1025static SECStatus
1026reload_crl(PRFileDesc *crlFile)
1027{
1028 SECItem *crlDer;
1029 CERTCertDBHandle *certHandle = CERT_GetDefaultCertDB();
1030 SECStatus rv;
1031
1032 /* Read in the entire file specified with the -f argument */
1033 crlDer = PORT_MallocPR_Malloc(sizeof(SECItem));
1034 if (!crlDer) {
1035 errWarn("Can not allocate memory.");
1036 return SECFailure;
1037 }
1038
1039 rv = SECU_ReadDERFromFile(crlDer, crlFile, PR_FALSE0, PR_FALSE0);
1040 if (rv != SECSuccess) {
1041 errWarn("Unable to read input file.");
1042 PORT_FreePORT_Free_Util(crlDer);
1043 return SECFailure;
1044 }
1045
1046 PR_Lock(lastLoadedCrlLock);
1047 rv = CERT_CacheCRL(certHandle, crlDer);
1048 if (rv == SECSuccess) {
1049 SECItem *tempItem = crlDer;
1050 if (lastLoadedCrl != NULL((void*)0)) {
1051 rv = CERT_UncacheCRL(certHandle, lastLoadedCrl);
1052 if (rv != SECSuccess) {
1053 errWarn("Unable to uncache crl.");
1054 goto loser;
1055 }
1056 crlDer = lastLoadedCrl;
1057 } else {
1058 crlDer = NULL((void*)0);
1059 }
1060 lastLoadedCrl = tempItem;
1061 }
1062
1063loser:
1064 PR_Unlock(lastLoadedCrlLock);
1065 SECITEM_FreeItemSECITEM_FreeItem_Util(crlDer, PR_TRUE1);
1066 return rv;
1067}
1068
1069void
1070stop_server()
1071{
1072 stopping = 1;
1073 PR_Interrupt(acceptorThread);
1074 PZ_TraceFlush();
1075}
1076
1077SECItemArray *
1078makeTryLaterOCSPResponse(PLArenaPool *arena)
1079{
1080 SECItemArray *result = NULL((void*)0);
1081 SECItem *ocspResponse = NULL((void*)0);
1082
1083 ocspResponse = CERT_CreateEncodedOCSPErrorResponse(arena,
1084 SEC_ERROR_OCSP_TRY_SERVER_LATER);
1085 if (!ocspResponse)
1086 errExit("cannot created ocspResponse");
1087
1088 result = SECITEM_AllocArray(arena, NULL((void*)0), 1);
1089 if (!result)
1090 errExit("cannot allocate multiOcspResponses");
1091
1092 result->items[0].data = ocspResponse->data;
1093 result->items[0].len = ocspResponse->len;
1094
1095 return result;
1096}
1097
1098SECItemArray *
1099makeCorruptedOCSPResponse(PLArenaPool *arena)
1100{
1101 SECItemArray *result = NULL((void*)0);
1102 SECItem *ocspResponse = NULL((void*)0);
1103
1104 ocspResponse = SECITEM_AllocItemSECITEM_AllocItem_Util(arena, NULL((void*)0), 1);
1105 if (!ocspResponse)
1106 errExit("cannot created ocspResponse");
1107
1108 result = SECITEM_AllocArray(arena, NULL((void*)0), 1);
1109 if (!result)
1110 errExit("cannot allocate multiOcspResponses");
1111
1112 result->items[0].data = ocspResponse->data;
1113 result->items[0].len = ocspResponse->len;
1114
1115 return result;
1116}
1117
1118SECItemArray *
1119makeSignedOCSPResponse(PLArenaPool *arena,
1120 CERTCertificate *cert, secuPWData *pwdata)
1121{
1122 SECItemArray *result = NULL((void*)0);
1123 SECItem *ocspResponse = NULL((void*)0);
1124 CERTOCSPSingleResponse **singleResponses;
1125 CERTOCSPSingleResponse *sr = NULL((void*)0);
1126 CERTOCSPCertID *cid = NULL((void*)0);
1127 CERTCertificate *ca;
1128 PRTime now = PR_Now();
1129 PRTime nextUpdate;
1130
1131 PORT_Assert(cert != NULL)((cert != ((void*)0))?((void)0):PR_Assert("cert != NULL","selfserv.c"
,1131))
;
1132
1133 ca = CERT_FindCertByNickname(CERT_GetDefaultCertDB(), ocspStaplingCA);
1134 if (!ca)
1135 errExit("cannot find CA");
1136
1137 cid = CERT_CreateOCSPCertID(cert, now);
1138 if (!cid)
1139 errExit("cannot created cid");
1140
1141 nextUpdate = now + (PRTime)60 * 60 * 24 * PR_USEC_PER_SEC1000000L; /* plus 1 day */
1142
1143 switch (ocspStaplingMode) {
1144 case osm_good:
1145 case osm_badsig:
1146 sr = CERT_CreateOCSPSingleResponseGood(arena, cid, now,
1147 &nextUpdate);
1148 break;
1149 case osm_unknown:
1150 sr = CERT_CreateOCSPSingleResponseUnknown(arena, cid, now,
1151 &nextUpdate);
1152 break;
1153 case osm_revoked:
1154 sr = CERT_CreateOCSPSingleResponseRevoked(arena, cid, now,
1155 &nextUpdate,
1156 now - (PRTime)60 * 60 * 24 * PR_USEC_PER_SEC1000000L, /* minus 1 day */
1157 NULL((void*)0));
1158 break;
1159 default:
1160 PORT_Assert(0)((0)?((void)0):PR_Assert("0","selfserv.c",1160));
1161 break;
1162 }
1163
1164 if (!sr)
1165 errExit("cannot create sr");
1166
1167 /* meaning of value 2: one entry + one end marker */
1168 singleResponses = PORT_ArenaNewArray(arena, CERTOCSPSingleResponse *, 2)(CERTOCSPSingleResponse * *)PORT_ArenaAlloc_Util(arena, sizeof
(CERTOCSPSingleResponse *) * (2))
;
1169 if (singleResponses == NULL((void*)0))
1170 errExit("cannot allocate singleResponses");
1171
1172 singleResponses[0] = sr;
1173 singleResponses[1] = NULL((void*)0);
1174
1175 ocspResponse = CERT_CreateEncodedOCSPSuccessResponse(arena,
1176 (ocspStaplingMode == osm_badsig)
1177 ? NULL((void*)0)
1178 : ca,
1179 ocspResponderID_byName, now, singleResponses,
1180 &pwdata);
1181 if (!ocspResponse)
1182 errExit("cannot created ocspResponse");
1183
1184 CERT_DestroyCertificate(ca);
1185 ca = NULL((void*)0);
1186
1187 result = SECITEM_AllocArray(arena, NULL((void*)0), 1);
1188 if (!result)
1189 errExit("cannot allocate multiOcspResponses");
1190
1191 result->items[0].data = ocspResponse->data;
1192 result->items[0].len = ocspResponse->len;
1193
1194 CERT_DestroyOCSPCertID(cid);
1195 cid = NULL((void*)0);
1196
1197 return result;
1198}
1199
1200void
1201setupCertStatus(PLArenaPool *arena,
1202 CERTCertificate *cert, int index, secuPWData *pwdata)
1203{
1204 if (ocspStaplingMode == osm_random) {
1205 /* 6 different responses */
1206 int r = rand() % 6;
1207 switch (r) {
1208 case 0:
1209 ocspStaplingMode = osm_good;
1210 break;
1211 case 1:
1212 ocspStaplingMode = osm_revoked;
1213 break;
1214 case 2:
1215 ocspStaplingMode = osm_unknown;
1216 break;
1217 case 3:
1218 ocspStaplingMode = osm_badsig;
1219 break;
1220 case 4:
1221 ocspStaplingMode = osm_corrupted;
1222 break;
1223 case 5:
1224 ocspStaplingMode = osm_failure;
1225 break;
1226 default:
1227 PORT_Assert(0)((0)?((void)0):PR_Assert("0","selfserv.c",1227));
1228 break;
1229 }
1230 }
1231 if (ocspStaplingMode != osm_disabled) {
1232 SECItemArray *multiOcspResponses = NULL((void*)0);
1233 switch (ocspStaplingMode) {
1234 case osm_good:
1235 case osm_revoked:
1236 case osm_unknown:
1237 case osm_badsig:
1238 multiOcspResponses =
1239 makeSignedOCSPResponse(arena, cert,
1240 pwdata);
1241 break;
1242 case osm_corrupted:
1243 multiOcspResponses = makeCorruptedOCSPResponse(arena);
1244 break;
1245 case osm_failure:
1246 multiOcspResponses = makeTryLaterOCSPResponse(arena);
1247 break;
1248 case osm_ocsp:
1249 errExit("stapling mode \"ocsp\" not implemented");
1250 break;
1251 break;
1252 default:
1253 break;
1254 }
1255 if (multiOcspResponses) {
1256 certStatus[index] = multiOcspResponses;
1257 }
1258 }
1259}
1260
1261int
1262handle_connection(PRFileDesc *tcp_sock, PRFileDesc *model_sock)
1263{
1264 PRFileDesc *ssl_sock = NULL((void*)0);
1265 PRFileDesc *local_file_fd = NULL((void*)0);
1266 char *post;
1267 char *pBuf; /* unused space at end of buf */
1268 const char *errString;
1269 PRStatus status;
1270 int bufRem; /* unused bytes at end of buf */
1271 int bufDat; /* characters received in buf */
1272 int newln = 0; /* # of consecutive newlns */
1273 int firstTime = 1;
1274 int reqLen;
1275 int rv;
1276 int numIOVs;
1277 PRSocketOptionData opt;
1278 PRIOVec iovs[16];
1279 char msgBuf[160];
1280 char buf[10240] = { 0 };
1281 char fileName[513];
1282 char proto[128];
1283 PRDescIdentity aboveLayer = PR_INVALID_IO_LAYER(PRDescIdentity)-1;
1284
1285 pBuf = buf;
1286 bufRem = sizeof buf;
1287
1288 VLOG(("selfserv: handle_connection: starting"))do { if (((lm)->level >= (PR_LOG_DEBUG))) { PR_LogPrint
("selfserv: handle_connection: starting"); } } while (0)
;
1289 opt.option = PR_SockOpt_Nonblocking;
1290 opt.value.non_blocking = PR_FALSE0;
1291 PR_SetSocketOption(tcp_sock, &opt);
1292
1293 VLOG(("selfserv: handle_connection: starting\n"))do { if (((lm)->level >= (PR_LOG_DEBUG))) { PR_LogPrint
("selfserv: handle_connection: starting\n"); } } while (0)
;
1294 if (useModelSocket && model_sock) {
1295 ssl_sock = SSL_ImportFD(model_sock, tcp_sock);
1296 if (!ssl_sock) {
1297 errWarn("SSL_ImportFD with model");
1298 goto cleanup;
1299 }
1300 rv = SSL_ResetHandshake(ssl_sock, /* asServer */ 1);
1301 if (rv != SECSuccess) {
1302 errWarn("SSL_ResetHandshake");
1303 goto cleanup;
1304 }
1305 } else {
1306 ssl_sock = tcp_sock;
1307 }
1308
1309 if (loggingLayer) {
1310 /* find the layer where our new layer is to be pushed */
1311 aboveLayer = PR_GetLayersIdentity(ssl_sock->lower);
1312 if (aboveLayer == PR_INVALID_IO_LAYER(PRDescIdentity)-1) {
1313 errExit("PRGetUniqueIdentity");
1314 }
1315 /* create the new layer - this is a very cheap operation */
1316 loggingFD = PR_CreateIOLayerStub(log_layer_id, &loggingMethods);
1317 if (!loggingFD)
1318 errExit("PR_CreateIOLayerStub");
1319 /* push the layer below ssl but above TCP */
1320 rv = PR_PushIOLayer(ssl_sock, aboveLayer, loggingFD);
1321 if (rv != PR_SUCCESS) {
1322 errExit("PR_PushIOLayer");
1323 }
1324 }
1325
1326 if (noDelay) {
1327 opt.option = PR_SockOpt_NoDelay;
1328 opt.value.no_delay = PR_TRUE1;
1329 status = PR_SetSocketOption(ssl_sock, &opt);
1330 if (status != PR_SUCCESS) {
1331 errWarn("PR_SetSocketOption(PR_SockOpt_NoDelay, PR_TRUE)");
1332 if (ssl_sock) {
1333 PR_Close(ssl_sock);
1334 }
1335 return SECFailure;
1336 }
1337 }
1338
1339 while (1) {
1340 newln = 0;
1341 reqLen = 0;
1342 rv = PR_Read(ssl_sock, pBuf, bufRem - 1);
1343 if (rv == 0 ||
1344 (rv < 0 && PR_END_OF_FILE_ERROR(-5938L) == PR_GetError())) {
1345 if (verbose)
1346 errWarn("HDX PR_Read hit EOF");
1347 break;
1348 }
1349 if (rv < 0) {
1350 errWarn("HDX PR_Read");
1351 goto cleanup;
1352 }
1353 /* NULL termination */
1354 pBuf[rv] = 0;
1355 if (firstTime) {
1356 firstTime = 0;
1357 printSecurityInfo(ssl_sock);
1358 }
1359
1360 pBuf += rv;
1361 bufRem -= rv;
1362 bufDat = pBuf - buf;
1363 /* Parse the input, starting at the beginning of the buffer.
1364 * Stop when we detect two consecutive \n's (or \r\n's)
1365 * as this signifies the end of the GET or POST portion.
1366 * The posted data follows.
1367 */
1368 while (reqLen < bufDat && newln < 2) {
1369 int octet = buf[reqLen++];
1370 if (octet == '\n') {
1371 newln++;
1372 } else if (octet != '\r') {
1373 newln = 0;
1374 }
1375 }
1376
1377 /* came to the end of the buffer, or second newln
1378 * If we didn't get an empty line (CRLFCRLF) then keep on reading.
1379 */
1380 if (newln < 2)
1381 continue;
1382
1383 /* we're at the end of the HTTP request.
1384 * If the request is a POST, then there will be one more
1385 * line of data.
1386 * This parsing is a hack, but ok for SSL test purposes.
1387 */
1388 post = PORT_Strstrstrstr(buf, "POST ");
1389 if (!post || *post != 'P')
1390 break;
1391
1392 /* It's a post, so look for the next and final CR/LF. */
1393 /* We should parse content length here, but ... */
1394 while (reqLen < bufDat && newln < 3) {
1395 int octet = buf[reqLen++];
1396 if (octet == '\n') {
1397 newln++;
1398 }
1399 }
1400 if (newln == 3)
1401 break;
1402 } /* read loop */
1403
1404 bufDat = pBuf - buf;
1405 if (bufDat)
1406 do { /* just close if no data */
1407 /* Have either (a) a complete get, (b) a complete post, (c) EOF */
1408 if (reqLen > 0 && !strncmp(buf, getCmd, sizeof getCmd - 1)) {
1409 char *fnBegin = buf + 4;
1410 char *fnEnd;
1411 PRFileInfo info;
1412 /* try to open the file named.
1413 * If successful, then write it to the client.
1414 */
1415 fnEnd = strpbrk(fnBegin, " \r\n");
1416 if (fnEnd) {
1417 int fnLen = fnEnd - fnBegin;
1418 if (fnLen < sizeof fileName) {
1419 char *real_fileName = fileName;
1420 char *protoEnd = NULL((void*)0);
1421 strncpy(fileName, fnBegin, fnLen);
1422 fileName[fnLen] = 0; /* null terminate */
1423 if ((protoEnd = strstr(fileName, "://")) != NULL((void*)0)) {
1424 int protoLen = PR_MIN(protoEnd - fileName, sizeof(proto) - 1)((protoEnd - fileName)<(sizeof(proto) - 1)?(protoEnd - fileName
):(sizeof(proto) - 1))
;
1425 PL_strncpy(proto, fileName, protoLen);
1426 proto[protoLen] = 0;
1427 real_fileName = protoEnd + 3;
1428 } else {
1429 proto[0] = 0;
1430 }
1431 status = PR_GetFileInfo(real_fileName, &info);
1432 if (status == PR_SUCCESS &&
1433 info.type == PR_FILE_FILE &&
1434 info.size >= 0) {
1435 local_file_fd = PR_Open(real_fileName, PR_RDONLY0x01, 0);
1436 }
1437 }
1438 }
1439 }
1440 /* if user has requested client auth in a subsequent handshake,
1441 * do it here.
1442 */
1443 if (requestCert > 2) { /* request cert was 3 or 4 */
1444 CERTCertificate *cert = SSL_PeerCertificate(ssl_sock);
1445 if (cert) {
1446 CERT_DestroyCertificate(cert);
1447 } else {
1448 rv = SSL_OptionSet(ssl_sock, SSL_REQUEST_CERTIFICATE3, 1);
1449 if (rv < 0) {
1450 errWarn("second SSL_OptionSet SSL_REQUEST_CERTIFICATE");
1451 break;
1452 }
1453 rv = SSL_OptionSet(ssl_sock, SSL_REQUIRE_CERTIFICATE10,
1454 (requestCert == 4));
1455 if (rv < 0) {
1456 errWarn("second SSL_OptionSet SSL_REQUIRE_CERTIFICATE");
1457 break;
1458 }
1459 if (enablePostHandshakeAuth) {
1460 rv = SSL_SendCertificateRequest(ssl_sock)(SSL_GetExperimentalAPI("SSL_SendCertificateRequest") ? ((SECStatus
(*) (PRFileDesc * _fd))SSL_GetExperimentalAPI("SSL_SendCertificateRequest"
))(ssl_sock) : SECFailure)
;
1461 if (rv != SECSuccess) {
1462 errWarn("SSL_SendCertificateRequest");
1463 break;
1464 }
1465 rv = SSL_ForceHandshake(ssl_sock);
1466 if (rv != SECSuccess) {
1467 errWarn("SSL_ForceHandshake");
1468 break;
1469 }
1470 } else {
1471 rv = SSL_ReHandshake(ssl_sock, PR_TRUE1);
1472 if (rv != 0) {
1473 errWarn("SSL_ReHandshake");
1474 break;
1475 }
1476 rv = SSL_ForceHandshake(ssl_sock);
1477 if (rv < 0) {
1478 errWarn("SSL_ForceHandshake");
1479 break;
1480 }
1481 }
1482 }
1483 }
1484
1485 numIOVs = 0;
1486
1487 iovs[numIOVs].iov_base = (char *)outHeader;
1488 iovs[numIOVs].iov_len = (sizeof(outHeader)) - 1;
1489 numIOVs++;
1490
1491 if (local_file_fd) {
1492 PRInt32 bytes;
1493 int errLen;
1494 if (!PL_strlen(proto) || !PL_strcmp(proto, "file")) {
1495 bytes = PR_TransmitFile(ssl_sock, local_file_fd, outHeader,
1496 sizeof outHeader - 1,
1497 PR_TRANSMITFILE_KEEP_OPEN,
1498 PR_INTERVAL_NO_TIMEOUT0xffffffffUL);
1499 if (bytes >= 0) {
1500 bytes -= sizeof outHeader - 1;
1501 FPRINTFif (verbose) fprintf(stderrstderr,
1502 "selfserv: PR_TransmitFile wrote %d bytes from %s\n",
1503 bytes, fileName);
1504 break;
1505 }
1506 errString = errWarn("PR_TransmitFile");
1507 errLen = PORT_Strlen(errString)strlen(errString);
1508 errLen = PR_MIN(errLen, sizeof msgBuf - 1)((errLen)<(sizeof msgBuf - 1)?(errLen):(sizeof msgBuf - 1)
)
;
1509 PORT_Memcpymemcpy(msgBuf, errString, errLen);
1510 msgBuf[errLen] = 0;
1511
1512 iovs[numIOVs].iov_base = msgBuf;
1513 iovs[numIOVs].iov_len = PORT_Strlen(msgBuf)strlen(msgBuf);
1514 numIOVs++;
1515 }
1516 if (!PL_strcmp(proto, "crl")) {
1517 if (reload_crl(local_file_fd) == SECFailure) {
1518 errString = errWarn("CERT_CacheCRL");
1519 if (!errString)
1520 errString = "Unknow error";
1521 PR_snprintf(msgBuf, sizeof(msgBuf), "%s%s ",
1522 crlCacheErr, errString);
1523
1524 iovs[numIOVs].iov_base = msgBuf;
1525 iovs[numIOVs].iov_len = PORT_Strlen(msgBuf)strlen(msgBuf);
1526 numIOVs++;
1527 } else {
1528 FPRINTFif (verbose) fprintf(stderrstderr,
1529 "selfserv: CRL %s reloaded.\n",
1530 fileName);
1531 break;
1532 }
1533 }
1534 } else if (reqLen <= 0) { /* hit eof */
1535 snprintf(msgBuf, sizeof(msgBuf), "Get or Post incomplete after %d bytes.\r\n",
1536 bufDat);
1537
1538 iovs[numIOVs].iov_base = msgBuf;
1539 iovs[numIOVs].iov_len = PORT_Strlen(msgBuf)strlen(msgBuf);
1540 numIOVs++;
1541 } else if (reqLen < bufDat) {
1542 snprintf(msgBuf, sizeof(msgBuf), "Discarded %d characters.\r\n",
1543 bufDat - reqLen);
1544
1545 iovs[numIOVs].iov_base = msgBuf;
1546 iovs[numIOVs].iov_len = PORT_Strlen(msgBuf)strlen(msgBuf);
1547 numIOVs++;
1548 }
1549
1550 if (reqLen > 0) {
1551 if (verbose > 1)
1552 fwrite(buf, 1, reqLen, stdoutstdout); /* display it */
1553
1554 iovs[numIOVs].iov_base = buf;
1555 iovs[numIOVs].iov_len = reqLen;
1556 numIOVs++;
1557 }
1558
1559 /* Don't add the EOF if we want to test bulk encryption */
1560 if (!testBulk) {
1561 iovs[numIOVs].iov_base = (char *)EOFmsg;
1562 iovs[numIOVs].iov_len = sizeof EOFmsg - 1;
1563 numIOVs++;
1564 }
1565
1566 rv = PR_Writev(ssl_sock, iovs, numIOVs, PR_INTERVAL_NO_TIMEOUT0xffffffffUL);
1567 if (rv < 0) {
1568 errWarn("PR_Writev");
1569 break;
1570 }
1571
1572 /* Send testBulkTotal chunks to the client. Unlimited if 0. */
1573 if (testBulk) {
1574 while (0 < (rv = PR_Write(ssl_sock, testBulkBuf, testBulkSize))) {
1575 PR_ATOMIC_ADD(&loggerBytes, rv)__sync_add_and_fetch(&loggerBytes, rv);
1576 PR_ATOMIC_INCREMENT(&bulkSentChunks)__sync_add_and_fetch(&bulkSentChunks, 1);
1577 if ((bulkSentChunks > testBulkTotal) && (testBulkTotal != 0))
1578 break;
1579 }
1580
1581 /* There was a write error, so close this connection. */
1582 if (bulkSentChunks <= testBulkTotal) {
1583 errWarn("PR_Write");
1584 }
1585 PR_ATOMIC_DECREMENT(&loggerOps)__sync_sub_and_fetch(&loggerOps, 1);
1586 break;
1587 }
1588 } while (0);
1589
1590cleanup:
1591 if (ssl_sock) {
1592 PR_Close(ssl_sock);
1593 } else if (tcp_sock) {
1594 PR_Close(tcp_sock);
1595 }
1596 if (local_file_fd)
1597 PR_Close(local_file_fd);
1598 VLOG(("selfserv: handle_connection: exiting\n"))do { if (((lm)->level >= (PR_LOG_DEBUG))) { PR_LogPrint
("selfserv: handle_connection: exiting\n"); } } while (0)
;
1599
1600 /* do a nice shutdown if asked. */
1601 if (!strncmp(buf, stopCmd, sizeof stopCmd - 1)) {
1602 VLOG(("selfserv: handle_connection: stop command"))do { if (((lm)->level >= (PR_LOG_DEBUG))) { PR_LogPrint
("selfserv: handle_connection: stop command"); } } while (0)
;
1603 stop_server();
1604 }
1605 VLOG(("selfserv: handle_connection: exiting"))do { if (((lm)->level >= (PR_LOG_DEBUG))) { PR_LogPrint
("selfserv: handle_connection: exiting"); } } while (0)
;
1606 return SECSuccess; /* success */
1607}
1608
1609#ifdef XP_UNIX1
1610
1611void
1612sigusr1_handler(int sig)
1613{
1614 VLOG(("selfserv: sigusr1_handler: stop server"))do { if (((lm)->level >= (PR_LOG_DEBUG))) { PR_LogPrint
("selfserv: sigusr1_handler: stop server"); } } while (0)
;
1615 stop_server();
1616}
1617
1618#endif
1619
1620SECStatus
1621do_accepts(
1622 PRFileDesc *listen_sock,
1623 PRFileDesc *model_sock)
1624{
1625 PRNetAddr addr;
1626 PRErrorCode perr;
1627#ifdef XP_UNIX1
1628 struct sigaction act;
1629#endif
1630
1631 VLOG(("selfserv: do_accepts: starting"))do { if (((lm)->level >= (PR_LOG_DEBUG))) { PR_LogPrint
("selfserv: do_accepts: starting"); } } while (0)
;
1632 PR_SetThreadPriority(PR_GetCurrentThread(), PR_PRIORITY_HIGH);
1633
1634 acceptorThread = PR_GetCurrentThread();
1635#ifdef XP_UNIX1
1636 /* set up the signal handler */
1637 act.sa_handler__sigaction_handler.sa_handler = sigusr1_handler;
1638 sigemptyset(&act.sa_mask);
1639 act.sa_flags = 0;
1640 if (sigaction(SIGUSR110, &act, NULL((void*)0))) {
1641 fprintf(stderrstderr, "Error installing signal handler.\n");
1642 exit(1);
1643 }
1644#endif
1645 while (!stopping) {
1646 PRFileDesc *tcp_sock;
1647 PRCList *myLink;
1648
1649 FPRINTFif (verbose) fprintf(stderrstderr, "\n\n\nselfserv: About to call accept.\n");
1650 tcp_sock = PR_Accept(listen_sock, &addr, PR_INTERVAL_NO_TIMEOUT0xffffffffUL);
1651 if (tcp_sock == NULL((void*)0)) {
1652 perr = PR_GetError();
1653 if ((perr != PR_CONNECT_RESET_ERROR(-5961L) &&
1654 perr != PR_PENDING_INTERRUPT_ERROR(-5993L)) ||
1655 verbose) {
1656 errWarn("PR_Accept");
1657 }
1658 if (perr == PR_CONNECT_RESET_ERROR(-5961L)) {
1659 FPRINTFif (verbose) fprintf(stderrstderr,
1660 "Ignoring PR_CONNECT_RESET_ERROR error - continue\n");
1661 continue;
1662 }
1663 stopping = 1;
1664 break;
1665 }
1666
1667 VLOG(("selfserv: do_accept: Got connection\n"))do { if (((lm)->level >= (PR_LOG_DEBUG))) { PR_LogPrint
("selfserv: do_accept: Got connection\n"); } } while (0)
;
1668
1669 if (logStats) {
1670 PR_ATOMIC_INCREMENT(&loggerOps)__sync_add_and_fetch(&loggerOps, 1);
1671 }
1672
1673 PZ_Lock(qLock)PR_Lock((qLock));
1674 while (PR_CLIST_IS_EMPTY(&freeJobs)((&freeJobs)->next == (&freeJobs)) && !stopping) {
1675 PZ_WaitCondVar(freeListNotEmptyCv, PR_INTERVAL_NO_TIMEOUT)PR_WaitCondVar((freeListNotEmptyCv), (0xffffffffUL));
1676 }
1677 if (stopping) {
1678 PZ_Unlock(qLock)PR_Unlock((qLock));
1679 if (tcp_sock) {
1680 PR_Close(tcp_sock);
1681 }
1682 break;
1683 }
1684 myLink = PR_LIST_HEAD(&freeJobs)(&freeJobs)->next;
1685 PR_REMOVE_AND_INIT_LINK(myLink)do { (myLink)->prev->next = (myLink)->next; (myLink)
->next->prev = (myLink)->prev; (myLink)->next = (
myLink); (myLink)->prev = (myLink); } while (0)
;
1686 /* could release qLock here and reaquire it 7 lines below, but
1687 ** why bother for 4 assignment statements?
1688 */
1689 {
1690 JOB *myJob = (JOB *)myLink;
1691 myJob->tcp_sock = tcp_sock;
1692 myJob->model_sock = model_sock;
1693 }
1694
1695 PR_APPEND_LINK(myLink, &jobQ)do { (myLink)->next = (&jobQ); (myLink)->prev = (&
jobQ)->prev; (&jobQ)->prev->next = (myLink); (&
jobQ)->prev = (myLink); } while (0)
;
1696 PZ_NotifyCondVar(jobQNotEmptyCv)PR_NotifyCondVar((jobQNotEmptyCv));
1697 PZ_Unlock(qLock)PR_Unlock((qLock));
1698 }
1699
1700 FPRINTFif (verbose) fprintf(stderrstderr, "selfserv: Closing listen socket.\n");
1701 VLOG(("selfserv: do_accepts: exiting"))do { if (((lm)->level >= (PR_LOG_DEBUG))) { PR_LogPrint
("selfserv: do_accepts: exiting"); } } while (0)
;
1702 if (listen_sock) {
1703 PR_Close(listen_sock);
1704 }
1705 return SECSuccess;
1706}
1707
1708PRFileDesc *
1709getBoundListenSocket(unsigned short port)
1710{
1711 PRFileDesc *listen_sock = NULL((void*)0);
1712 int listenQueueDepth = 5 + (2 * maxThreads);
1713 PRStatus prStatus;
1714 PRNetAddr addr;
1715 PRSocketOptionData opt;
1716
1717 // We want to listen on the IP family that tstclnt will use.
1718 // tstclnt uses PR_GetPrefLoopbackAddrInfo to decide, if it's
1719 // asked to connect to localhost.
1720
1721 prStatus = PR_GetPrefLoopbackAddrInfo(&addr, port);
1722 if (prStatus == PR_FAILURE) {
1723 addr.inet.family = PR_AF_INET2;
1724 addr.inet.ip = PR_htonl(PR_INADDR_ANY((in_addr_t) 0x00000000));
1725 addr.inet.port = PR_htons(port);
1726 }
1727
1728 if (addr.inet.family == PR_AF_INET610) {
1729 listen_sock = PR_OpenTCPSocket(PR_AF_INET610);
1730 } else if (addr.inet.family == PR_AF_INET2) {
1731 listen_sock = PR_NewTCPSocket();
1732 }
1733 if (listen_sock == NULL((void*)0)) {
1734 errExit("Couldn't create socket");
1735 }
1736
1737 opt.option = PR_SockOpt_Nonblocking;
1738 opt.value.non_blocking = PR_FALSE0;
1739 prStatus = PR_SetSocketOption(listen_sock, &opt);
1740 if (prStatus < 0) {
1741 PR_Close(listen_sock);
1742 errExit("PR_SetSocketOption(PR_SockOpt_Nonblocking)");
1743 }
1744
1745 opt.option = PR_SockOpt_Reuseaddr;
1746 opt.value.reuse_addr = PR_TRUE1;
1747 prStatus = PR_SetSocketOption(listen_sock, &opt);
1748 if (prStatus < 0) {
1749 PR_Close(listen_sock);
1750 errExit("PR_SetSocketOption(PR_SockOpt_Reuseaddr)");
1751 }
1752
1753#ifndef WIN95
1754 /* Set PR_SockOpt_Linger because it helps prevent a server bind issue
1755 * after clean shutdown . See bug 331413 .
1756 * Don't do it in the WIN95 build configuration because clean shutdown is
1757 * not implemented, and PR_SockOpt_Linger causes a hang in ssl.sh .
1758 * See bug 332348 */
1759 opt.option = PR_SockOpt_Linger;
1760 opt.value.linger.polarity = PR_TRUE1;
1761 opt.value.linger.linger = PR_SecondsToInterval(1);
1762 prStatus = PR_SetSocketOption(listen_sock, &opt);
1763 if (prStatus < 0) {
1764 PR_Close(listen_sock);
1765 errExit("PR_SetSocketOption(PR_SockOpt_Linger)");
1766 }
1767#endif
1768
1769 prStatus = PR_Bind(listen_sock, &addr);
1770 if (prStatus < 0) {
1771 PR_Close(listen_sock);
1772 errExit("PR_Bind");
1773 }
1774
1775 prStatus = PR_Listen(listen_sock, listenQueueDepth);
1776 if (prStatus < 0) {
1777 PR_Close(listen_sock);
1778 errExit("PR_Listen");
1779 }
1780 return listen_sock;
1781}
1782
1783PRInt32 PR_CALLBACK
1784logWritev(
1785 PRFileDesc *fd,
1786 const PRIOVec *iov,
1787 PRInt32 size,
1788 PRIntervalTime timeout)
1789{
1790 PRInt32 rv = (fd->lower->methods->writev)(fd->lower, iov, size,
1791 timeout);
1792 /* Add the amount written, but not if there's an error */
1793 if (rv > 0)
1794 PR_ATOMIC_ADD(&loggerBytesTCP, rv)__sync_add_and_fetch(&loggerBytesTCP, rv);
1795 return rv;
1796}
1797
1798PRInt32 PR_CALLBACK
1799logWrite(
1800 PRFileDesc *fd,
1801 const void *buf,
1802 PRInt32 amount)
1803{
1804 PRInt32 rv = (fd->lower->methods->write)(fd->lower, buf, amount);
1805 /* Add the amount written, but not if there's an error */
1806 if (rv > 0)
1807 PR_ATOMIC_ADD(&loggerBytesTCP, rv)__sync_add_and_fetch(&loggerBytesTCP, rv);
1808
1809 return rv;
1810}
1811
1812PRInt32 PR_CALLBACK
1813logSend(
1814 PRFileDesc *fd,
1815 const void *buf,
1816 PRInt32 amount,
1817 PRIntn flags,
1818 PRIntervalTime timeout)
1819{
1820 PRInt32 rv = (fd->lower->methods->send)(fd->lower, buf, amount,
1821 flags, timeout);
1822 /* Add the amount written, but not if there's an error */
1823 if (rv > 0)
1824 PR_ATOMIC_ADD(&loggerBytesTCP, rv)__sync_add_and_fetch(&loggerBytesTCP, rv);
1825 return rv;
1826}
1827
1828void
1829initLoggingLayer(void)
1830{
1831 /* get a new layer ID */
1832 log_layer_id = PR_GetUniqueIdentity("Selfserv Logging");
1833 if (log_layer_id == PR_INVALID_IO_LAYER(PRDescIdentity)-1)
1834 errExit("PR_GetUniqueIdentity");
1835
1836 /* setup the default IO methods with my custom write methods */
1837 memcpy(&loggingMethods, PR_GetDefaultIOMethods(), sizeof(PRIOMethods));
1838 loggingMethods.writev = logWritev;
1839 loggingMethods.write = logWrite;
1840 loggingMethods.send = logSend;
1841}
1842
1843void
1844handshakeCallback(PRFileDesc *fd, void *client_data)
1845{
1846 const char *handshakeName = (const char *)client_data;
1847 if (handshakeName && !failedToNegotiateName) {
1848 SECItem *hostInfo = SSL_GetNegotiatedHostInfo(fd);
1849 if (!hostInfo || PORT_Strncmpstrncmp(handshakeName, (char *)hostInfo->data,
1850 hostInfo->len)) {
1851 failedToNegotiateName = PR_TRUE1;
1852 }
1853 if (hostInfo) {
1854 SECITEM_FreeItemSECITEM_FreeItem_Util(hostInfo, PR_TRUE1);
1855 }
1856 }
1857 if (enabledExporters) {
1858 SECStatus rv = exportKeyingMaterials(fd, enabledExporters, enabledExporterCount);
1859 if (rv != SECSuccess) {
1860 PRErrorCode err = PR_GetError();
1861 fprintf(stderrstderr,
1862 "couldn't export keying material: %s\n",
1863 SECU_Strerror(err)PR_ErrorToString((err), 0));
1864 }
1865 }
1866}
1867
1868static SECStatus
1869importPsk(PRFileDesc *model_sock)
1870{
1871 SECU_PrintAsHex(stdoutstdout, &psk, "Using External PSK", 0);
1872 PK11SlotInfo *slot = NULL((void*)0);
1873 PK11SymKey *symKey = NULL((void*)0);
1874 slot = PK11_GetInternalSlot();
1875 if (!slot) {
1876 errWarn("PK11_GetInternalSlot failed");
1877 return SECFailure;
1878 }
1879 symKey = PK11_ImportSymKey(slot, CKM_HKDF_KEY_GEN0x0000402cUL, PK11_OriginUnwrap,
1880 CKA_DERIVE0x0000010CUL, &psk, NULL((void*)0));
1881 PK11_FreeSlot(slot);
1882 if (!symKey) {
1883 errWarn("PK11_ImportSymKey failed\n");
1884 return SECFailure;
1885 }
1886
1887 SECStatus rv = SSL_AddExternalPsk(model_sock, symKey,(SSL_GetExperimentalAPI("SSL_AddExternalPsk") ? ((SECStatus(*
) (PRFileDesc * _fd, PK11SymKey * _psk, const PRUint8 *_identity
, unsigned int _identityLen, SSLHashType _hash))SSL_GetExperimentalAPI
("SSL_AddExternalPsk"))(model_sock, symKey, (const PRUint8 *)
pskLabel.data, pskLabel.len, ssl_hash_sha256) : SECFailure)
1888 (const PRUint8 *)pskLabel.data,(SSL_GetExperimentalAPI("SSL_AddExternalPsk") ? ((SECStatus(*
) (PRFileDesc * _fd, PK11SymKey * _psk, const PRUint8 *_identity
, unsigned int _identityLen, SSLHashType _hash))SSL_GetExperimentalAPI
("SSL_AddExternalPsk"))(model_sock, symKey, (const PRUint8 *)
pskLabel.data, pskLabel.len, ssl_hash_sha256) : SECFailure)
1889 pskLabel.len, ssl_hash_sha256)(SSL_GetExperimentalAPI("SSL_AddExternalPsk") ? ((SECStatus(*
) (PRFileDesc * _fd, PK11SymKey * _psk, const PRUint8 *_identity
, unsigned int _identityLen, SSLHashType _hash))SSL_GetExperimentalAPI
("SSL_AddExternalPsk"))(model_sock, symKey, (const PRUint8 *)
pskLabel.data, pskLabel.len, ssl_hash_sha256) : SECFailure)
;
1890 PK11_FreeSymKey(symKey);
1891 return rv;
1892}
1893
1894static SECStatus
1895configureEchWithPublicName(PRFileDesc *model_sock, const char *public_name)
1896{
1897 SECStatus rv;
1898
1899#define OID_LEN65 65
1900 unsigned char paramBuf[OID_LEN65];
1901 SECItem ecParams = { siBuffer, paramBuf, sizeof(paramBuf) };
1902 SECKEYPublicKey *pubKey = NULL((void*)0);
1903 SECKEYPrivateKey *privKey = NULL((void*)0);
1904 SECOidData *oidData;
1905 char *echConfigBase64 = NULL((void*)0);
1906 PRUint8 configId = 0;
1907 PRUint8 configBuf[1000];
1908 unsigned int len = 0;
1909 HpkeSymmetricSuite echCipherSuite = { HpkeKdfHkdfSha256,
1910 HpkeAeadChaCha20Poly1305 };
1911
1912 PK11SlotInfo *slot = PK11_GetInternalKeySlot();
1913 if (!slot) {
1914 errWarn("PK11_GetInternalKeySlot failed");
1915 return SECFailure;
1916 }
1917
1918 if (PK11_GenerateRandom(&configId, sizeof(configId)) != SECSuccess) {
1919 errWarn("Failed to generate random configId");
1920 goto loser;
1921 }
1922
1923 oidData = SECOID_FindOIDByTagSECOID_FindOIDByTag_Util(SEC_OID_CURVE25519);
1924 if (oidData && (2 + oidData->oid.len) < sizeof(paramBuf)) {
1925 ecParams.data[0] = SEC_ASN1_OBJECT_ID0x06;
1926 ecParams.data[1] = oidData->oid.len;
1927 memcpy(ecParams.data + 2, oidData->oid.data, oidData->oid.len);
1928 ecParams.len = oidData->oid.len + 2;
1929 } else {
1930 errWarn("SECOID_FindOIDByTag failed");
1931 goto loser;
1932 }
1933 privKey = PK11_GenerateKeyPair(slot, CKM_EC_KEY_PAIR_GEN0x00001040UL, &ecParams,
1934 &pubKey, PR_FALSE0, PR_FALSE0, NULL((void*)0));
1935 if (!privKey || !pubKey) {
1936 errWarn("Failed to generate ECH keypair");
1937 goto loser;
1938 }
1939
1940 rv = SSL_EncodeEchConfigId(configId, public_name, 100,(SSL_GetExperimentalAPI("SSL_EncodeEchConfigId") ? ((SECStatus
(*) (PRUint8 _configId, const char *_publicName, unsigned int
_maxNameLen, HpkeKemId _kemId, const SECKEYPublicKey *_pubKey
, const HpkeSymmetricSuite *_hpkeSuites, unsigned int _hpkeSuiteCount
, PRUint8 *_out, unsigned int *_outlen, unsigned int _maxlen)
)SSL_GetExperimentalAPI("SSL_EncodeEchConfigId"))(configId, public_name
, 100, HpkeDhKemX25519Sha256, pubKey, &echCipherSuite, 1,
configBuf, &len, sizeof(configBuf)) : SECFailure)
1941 HpkeDhKemX25519Sha256, pubKey,(SSL_GetExperimentalAPI("SSL_EncodeEchConfigId") ? ((SECStatus
(*) (PRUint8 _configId, const char *_publicName, unsigned int
_maxNameLen, HpkeKemId _kemId, const SECKEYPublicKey *_pubKey
, const HpkeSymmetricSuite *_hpkeSuites, unsigned int _hpkeSuiteCount
, PRUint8 *_out, unsigned int *_outlen, unsigned int _maxlen)
)SSL_GetExperimentalAPI("SSL_EncodeEchConfigId"))(configId, public_name
, 100, HpkeDhKemX25519Sha256, pubKey, &echCipherSuite, 1,
configBuf, &len, sizeof(configBuf)) : SECFailure)
1942 &echCipherSuite, 1,(SSL_GetExperimentalAPI("SSL_EncodeEchConfigId") ? ((SECStatus
(*) (PRUint8 _configId, const char *_publicName, unsigned int
_maxNameLen, HpkeKemId _kemId, const SECKEYPublicKey *_pubKey
, const HpkeSymmetricSuite *_hpkeSuites, unsigned int _hpkeSuiteCount
, PRUint8 *_out, unsigned int *_outlen, unsigned int _maxlen)
)SSL_GetExperimentalAPI("SSL_EncodeEchConfigId"))(configId, public_name
, 100, HpkeDhKemX25519Sha256, pubKey, &echCipherSuite, 1,
configBuf, &len, sizeof(configBuf)) : SECFailure)
1943 configBuf, &len, sizeof(configBuf))(SSL_GetExperimentalAPI("SSL_EncodeEchConfigId") ? ((SECStatus
(*) (PRUint8 _configId, const char *_publicName, unsigned int
_maxNameLen, HpkeKemId _kemId, const SECKEYPublicKey *_pubKey
, const HpkeSymmetricSuite *_hpkeSuites, unsigned int _hpkeSuiteCount
, PRUint8 *_out, unsigned int *_outlen, unsigned int _maxlen)
)SSL_GetExperimentalAPI("SSL_EncodeEchConfigId"))(configId, public_name
, 100, HpkeDhKemX25519Sha256, pubKey, &echCipherSuite, 1,
configBuf, &len, sizeof(configBuf)) : SECFailure)
;
1944 if (rv != SECSuccess) {
1945 errWarn("SSL_EncodeEchConfigId failed");
1946 goto loser;
1947 }
1948
1949 rv = SSL_SetServerEchConfigs(model_sock, pubKey, privKey, configBuf, len)(SSL_GetExperimentalAPI("SSL_SetServerEchConfigs") ? ((SECStatus
(*) (PRFileDesc * _fd, const SECKEYPublicKey *_pubKey, const SECKEYPrivateKey
*_privKey, const PRUint8 *_record, unsigned int _recordLen))
SSL_GetExperimentalAPI("SSL_SetServerEchConfigs"))(model_sock
, pubKey, privKey, configBuf, len) : SECFailure)
;
1950 if (rv != SECSuccess) {
1951 errWarn("SSL_SetServerEchConfigs failed");
1952 goto loser;
1953 }
1954
1955 SECItem echConfigItem = { siBuffer, configBuf, len };
1956 echConfigBase64 = NSSBase64_EncodeItemNSSBase64_EncodeItem_Util(NULL((void*)0), NULL((void*)0), 0, &echConfigItem);
1957 if (!echConfigBase64) {
1958 errWarn("NSSBase64_EncodeItem failed");
1959 goto loser;
1960 }
1961
1962 // Remove the newline characters that NSSBase64_EncodeItem unhelpfully inserts.
1963 char *newline = strstr(echConfigBase64, "\r\n");
1964 if (newline) {
1965 memmove(newline, newline + 2, strlen(newline + 2) + 1);
1966 }
1967
1968 printf("%s\n", echConfigBase64);
1969 PORT_FreePORT_Free_Util(echConfigBase64);
1970 SECKEY_DestroyPrivateKey(privKey);
1971 SECKEY_DestroyPublicKey(pubKey);
1972 PK11_FreeSlot(slot);
1973 return SECSuccess;
1974
1975loser:
1976 PORT_FreePORT_Free_Util(echConfigBase64);
1977 SECKEY_DestroyPrivateKey(privKey);
1978 SECKEY_DestroyPublicKey(pubKey);
1979 PK11_FreeSlot(slot);
1980 return SECFailure;
1981}
1982
1983static SECStatus
1984configureEchWithData(PRFileDesc *model_sock)
1985{
1986 /* The input should be a Base64-encoded ECHKey struct:
1987 * struct {
1988 * opaque pkcs8_ech_keypair<0..2^16-1>;
1989 * ECHConfigs configs<0..2^16>; // draft-ietf-tls-esni-09
1990 * } ECHKey;
1991 *
1992 * This is not a standardized format, rather it's designed for
1993 * interoperability with https://github.com/xvzcf/tls-interop-runner.
1994 * It is the user's responsibility to ensure that the PKCS8 keypair
1995 * corresponds to the public key embedded in the ECHConfigs.
1996 */
1997
1998#define REMAINING_BYTES(rdr, buf)buf->len - (rdr - buf->data) \
1999 buf->len - (rdr - buf->data)
2000
2001 SECStatus rv;
2002 size_t len;
2003 unsigned char *reader;
2004 PK11SlotInfo *slot = NULL((void*)0);
2005 SECItem *decoded = NULL((void*)0);
2006 SECKEYPublicKey *pk = NULL((void*)0);
2007 SECKEYPrivateKey *sk = NULL((void*)0);
2008 SECItem pkcs8Key = { siBuffer, NULL((void*)0), 0 };
2009
2010 decoded = NSSBase64_DecodeBufferNSSBase64_DecodeBuffer_Util(NULL((void*)0), NULL((void*)0), echParamsStr, PORT_Strlen(echParamsStr)strlen(echParamsStr));
2011 if (!decoded || decoded->len < 2) {
2012 errWarn("Couldn't decode ECHParams");
2013 goto loser;
2014 };
2015 reader = decoded->data;
2016
2017 len = (*(reader++) << 8);
2018 len |= *(reader++);
2019 if (len > (REMAINING_BYTES(reader, decoded)decoded->len - (reader - decoded->data) - 2)) {
2020 errWarn("Bad ECHParams encoding");
2021 goto loser;
2022 }
2023 pkcs8Key.data = reader;
2024 pkcs8Key.len = len;
2025 reader += len;
2026
2027 /* Convert the key bytes to key handles */
2028 slot = PK11_GetInternalKeySlot();
2029 rv = PK11_ImportDERPrivateKeyInfoAndReturnKey(
2030 slot, &pkcs8Key, NULL((void*)0), NULL((void*)0), PR_FALSE0, PR_FALSE0, KU_ALL((0x80) | (0x40) | (0x20) | (0x10) | (0x08) | (0x04) | (0x02)
| (0x01))
, &sk, NULL((void*)0));
2031 if (rv != SECSuccess || !sk) {
2032 errWarn("ECH key import failed");
2033 goto loser;
2034 }
2035 pk = SECKEY_ConvertToPublicKey(sk);
2036 if (!pk) {
2037 errWarn("ECH key conversion failed");
2038 goto loser;
2039 }
2040
2041 /* Remainder is the ECHConfigs. */
2042 rv = SSL_SetServerEchConfigs(model_sock, pk, sk, reader,(SSL_GetExperimentalAPI("SSL_SetServerEchConfigs") ? ((SECStatus
(*) (PRFileDesc * _fd, const SECKEYPublicKey *_pubKey, const SECKEYPrivateKey
*_privKey, const PRUint8 *_record, unsigned int _recordLen))
SSL_GetExperimentalAPI("SSL_SetServerEchConfigs"))(model_sock
, pk, sk, reader, decoded->len - (reader - decoded->data
)) : SECFailure)
2043 REMAINING_BYTES(reader, decoded))(SSL_GetExperimentalAPI("SSL_SetServerEchConfigs") ? ((SECStatus
(*) (PRFileDesc * _fd, const SECKEYPublicKey *_pubKey, const SECKEYPrivateKey
*_privKey, const PRUint8 *_record, unsigned int _recordLen))
SSL_GetExperimentalAPI("SSL_SetServerEchConfigs"))(model_sock
, pk, sk, reader, decoded->len - (reader - decoded->data
)) : SECFailure)
;
2044 if (rv != SECSuccess) {
2045 errWarn("SSL_SetServerEchConfigs failed");
2046 goto loser;
2047 }
2048
2049 PK11_FreeSlot(slot);
2050 SECKEY_DestroyPrivateKey(sk);
2051 SECKEY_DestroyPublicKey(pk);
2052 SECITEM_FreeItemSECITEM_FreeItem_Util(decoded, PR_TRUE1);
2053 return SECSuccess;
2054loser:
2055 if (slot) {
2056 PK11_FreeSlot(slot);
2057 }
2058 SECKEY_DestroyPrivateKey(sk);
2059 SECKEY_DestroyPublicKey(pk);
2060 SECITEM_FreeItemSECITEM_FreeItem_Util(decoded, PR_TRUE1);
2061 return SECFailure;
2062}
2063
2064static SECStatus
2065configureEch(PRFileDesc *model_sock)
2066{
2067 if (!PORT_Strncmpstrncmp(echParamsStr, "publicname:", PORT_Strlen("publicname:")strlen("publicname:"))) {
2068 return configureEchWithPublicName(model_sock,
2069 &echParamsStr[PORT_Strlen("publicname:")strlen("publicname:")]);
2070 }
2071 return configureEchWithData(model_sock);
2072}
2073
2074void
2075server_main(
2076 PRFileDesc *listen_sock,
2077 SECKEYPrivateKey **privKey,
2078 CERTCertificate **cert,
2079 const char *expectedHostNameVal)
2080{
2081 int i;
2082 PRFileDesc *model_sock = NULL((void*)0);
2083 int rv;
2084 SECStatus secStatus;
2085
2086 if (useModelSocket) {
2087 model_sock = PR_NewTCPSocket();
2088 if (model_sock == NULL((void*)0)) {
2089 errExit("PR_NewTCPSocket on model socket");
2090 }
2091 model_sock = SSL_ImportFD(NULL((void*)0), model_sock);
2092 if (model_sock == NULL((void*)0)) {
2093 errExit("SSL_ImportFD");
2094 }
2095 } else {
2096 model_sock = listen_sock = SSL_ImportFD(NULL((void*)0), listen_sock);
2097 if (listen_sock == NULL((void*)0)) {
2098 errExit("SSL_ImportFD");
2099 }
2100 }
2101
2102 /* do SSL configuration. */
2103 rv = SSL_OptionSet(model_sock, SSL_SECURITY1, enabledVersions.min != 0);
2104 if (rv < 0) {
2105 errExit("SSL_OptionSet SSL_SECURITY");
2106 }
2107
2108 rv = SSL_VersionRangeSet(model_sock, &enabledVersions);
2109 if (rv != SECSuccess) {
2110 errExit("error setting SSL/TLS version range ");
2111 }
2112
2113 rv = SSL_OptionSet(model_sock, SSL_ROLLBACK_DETECTION14, !disableRollBack);
2114 if (rv != SECSuccess) {
2115 errExit("error enabling RollBack detection ");
2116 }
2117 if (disableLocking) {
2118 rv = SSL_OptionSet(model_sock, SSL_NO_LOCKS17, PR_TRUE1);
2119 if (rv != SECSuccess) {
2120 errExit("error disabling SSL socket locking ");
2121 }
2122 }
2123 if (enableSessionTickets) {
2124 rv = SSL_OptionSet(model_sock, SSL_ENABLE_SESSION_TICKETS18, PR_TRUE1);
2125 if (rv != SECSuccess) {
2126 errExit("error enabling Session Ticket extension ");
2127 }
2128 }
2129
2130 if (virtServerNameIndex > 1) {
2131 rv = SSL_SNISocketConfigHook(model_sock, mySSLSNISocketConfig,
2132 (void *)&virtServerNameArray);
2133 if (rv != SECSuccess) {
2134 errExit("error enabling SNI extension ");
2135 }
2136 }
2137
2138 if (configureDHE > -1) {
2139 rv = SSL_OptionSet(model_sock, SSL_ENABLE_SERVER_DHE29, (configureDHE > 0));
2140 if (rv != SECSuccess) {
2141 errExit("error configuring server side DHE support");
2142 }
2143 rv = SSL_OptionSet(model_sock, SSL_REQUIRE_DH_NAMED_GROUPS32, (configureDHE > 1));
2144 if (rv != SECSuccess) {
2145 errExit("error configuring server side FFDHE support");
2146 }
2147 PORT_Assert(configureDHE <= 2)((configureDHE <= 2)?((void)0):PR_Assert("configureDHE <= 2"
,"selfserv.c",2147))
;
2148 }
2149
2150 if (configureReuseECDHE > -1) {
2151 rv = SSL_OptionSet(model_sock, SSL_REUSE_SERVER_ECDHE_KEY27, (configureReuseECDHE > 0));
2152 if (rv != SECSuccess) {
2153 errExit("error configuring server side reuse of ECDHE key");
2154 }
2155 }
2156
2157 if (configureWeakDHE > -1) {
2158 rv = SSL_EnableWeakDHEPrimeGroup(model_sock, (configureWeakDHE > 0));
2159 if (rv != SECSuccess) {
2160 errExit("error configuring weak DHE prime group");
2161 }
2162 }
2163
2164 if (enableExtendedMasterSecret) {
2165 rv = SSL_OptionSet(model_sock, SSL_ENABLE_EXTENDED_MASTER_SECRET30, PR_TRUE1);
2166 if (rv != SECSuccess) {
2167 errExit("error enabling extended master secret ");
2168 }
2169 }
2170
2171 /* This uses the legacy certificate API. See mySSLSNISocketConfig() for the
2172 * new, prefered API. */
2173 for (i = 0; i < certNicknameIndex; i++) {
2174 if (cert[i] != NULL((void*)0)) {
2175 const SSLExtraServerCertData ocspData = {
2176 ssl_auth_null, NULL((void*)0), certStatus[i], NULL((void*)0), NULL((void*)0), NULL((void*)0)
2177 };
2178
2179 secStatus = SSL_ConfigServerCert(model_sock, cert[i],
2180 privKey[i], &ocspData,
2181 sizeof(ocspData));
2182 if (secStatus != SECSuccess)
2183 errExit("SSL_ConfigServerCert");
2184 }
2185 }
2186
2187 if (bigBuf.data) { /* doing FDX */
2188 rv = SSL_OptionSet(model_sock, SSL_ENABLE_FDX11, 1);
2189 if (rv < 0) {
2190 errExit("SSL_OptionSet SSL_ENABLE_FDX");
2191 }
2192 }
2193
2194 if (NoReuse) {
2195 rv = SSL_OptionSet(model_sock, SSL_NO_CACHE9, 1);
2196 if (rv < 0) {
2197 errExit("SSL_OptionSet SSL_NO_CACHE");
2198 }
2199 }
2200
2201 if (zeroRTT) {
2202 if (enabledVersions.max < SSL_LIBRARY_VERSION_TLS_1_30x0304) {
2203 errExit("You tried enabling 0RTT without enabling TLS 1.3!");
2204 }
2205 rv = SSL_SetAntiReplayContext(model_sock, antiReplay)(SSL_GetExperimentalAPI("SSL_SetAntiReplayContext") ? ((SECStatus
(*) (PRFileDesc * _fd, SSLAntiReplayContext * _ctx))SSL_GetExperimentalAPI
("SSL_SetAntiReplayContext"))(model_sock, antiReplay) : SECFailure
)
;
2206 if (rv != SECSuccess) {
2207 errExit("error configuring anti-replay ");
2208 }
2209 rv = SSL_OptionSet(model_sock, SSL_ENABLE_0RTT_DATA33, PR_TRUE1);
2210 if (rv != SECSuccess) {
2211 errExit("error enabling 0RTT ");
2212 }
2213 }
2214
2215 if (enablePostHandshakeAuth) {
2216 if (enabledVersions.max < SSL_LIBRARY_VERSION_TLS_1_30x0304) {
2217 errExit("You tried enabling post-handshake auth without enabling TLS 1.3!");
2218 }
2219 rv = SSL_OptionSet(model_sock, SSL_ENABLE_POST_HANDSHAKE_AUTH39, PR_TRUE1);
2220 if (rv != SECSuccess) {
2221 errExit("error enabling post-handshake auth");
2222 }
2223 }
2224
2225 if (enableALPN) {
2226 PRUint8 alpnVal[] = { 0x08,
2227 0x68, 0x74, 0x74, 0x70, 0x2f, 0x31, 0x2e, 0x31 };
2228 rv = SSL_OptionSet(model_sock, SSL_ENABLE_ALPN26, PR_TRUE1);
2229 if (rv != SECSuccess) {
2230 errExit("error enabling ALPN");
2231 }
2232
2233 rv = SSL_SetNextProtoNego(model_sock, alpnVal, sizeof(alpnVal));
2234 if (rv != SECSuccess) {
2235 errExit("error enabling ALPN");
2236 }
2237 }
2238
2239 if (enabledGroups) {
2240 rv = SSL_NamedGroupConfig(model_sock, enabledGroups, enabledGroupsCount);
2241 if (rv < 0) {
2242 errExit("SSL_NamedGroupConfig failed");
2243 }
2244 }
2245
2246 if (enabledSigSchemes) {
2247 rv = SSL_SignatureSchemePrefSet(model_sock, enabledSigSchemes, enabledSigSchemeCount);
2248 if (rv < 0) {
2249 errExit("SSL_SignatureSchemePrefSet failed");
2250 }
2251 }
2252
2253 /* This cipher is not on by default. The Acceptance test
2254 * would like it to be. Turn this cipher on.
2255 */
2256
2257 secStatus = SSL_CipherPrefSetDefault(TLS_RSA_WITH_NULL_MD50x0001, PR_TRUE1);
2258 if (secStatus != SECSuccess) {
2259 errExit("SSL_CipherPrefSetDefault:TLS_RSA_WITH_NULL_MD5");
2260 }
2261
2262 if (expectedHostNameVal || enabledExporters) {
2263 SSL_HandshakeCallback(model_sock, handshakeCallback,
2264 (void *)expectedHostNameVal);
2265 }
2266
2267 if (requestCert) {
2268 SSL_AuthCertificateHook(model_sock, mySSLAuthCertificate,
2269 (void *)CERT_GetDefaultCertDB());
2270 if (requestCert <= 2) {
2271 rv = SSL_OptionSet(model_sock, SSL_REQUEST_CERTIFICATE3, 1);
2272 if (rv < 0) {
2273 errExit("first SSL_OptionSet SSL_REQUEST_CERTIFICATE");
2274 }
2275 rv = SSL_OptionSet(model_sock, SSL_REQUIRE_CERTIFICATE10,
2276 (requestCert == 2));
2277 if (rv < 0) {
2278 errExit("first SSL_OptionSet SSL_REQUIRE_CERTIFICATE");
2279 }
2280 }
2281 }
2282
2283 if (psk.data) {
2284 rv = importPsk(model_sock);
2285 if (rv != SECSuccess) {
2286 errExit("importPsk failed");
2287 }
2288 }
2289
2290 if (echParamsStr) {
2291 rv = configureEch(model_sock);
2292 if (rv != SECSuccess) {
2293 errExit("configureEch failed");
2294 }
2295 }
2296
2297 if (MakeCertOK)
2298 SSL_BadCertHook(model_sock, myBadCertHandler, NULL((void*)0));
2299
2300 /* end of ssl configuration. */
2301
2302 /* Now, do the accepting, here in the main thread. */
2303 rv = do_accepts(listen_sock, model_sock);
Value stored to 'rv' is never read
2304
2305 terminateWorkerThreads();
2306
2307 if (useModelSocket && model_sock) {
2308 if (model_sock) {
2309 PR_Close(model_sock);
2310 }
2311 }
2312}
2313
2314SECStatus
2315readBigFile(const char *fileName)
2316{
2317 PRFileInfo info;
2318 PRStatus status;
2319 SECStatus rv = SECFailure;
2320 int count;
2321 int hdrLen;
2322 PRFileDesc *local_file_fd = NULL((void*)0);
2323
2324 status = PR_GetFileInfo(fileName, &info);
2325
2326 if (status == PR_SUCCESS &&
2327 info.type == PR_FILE_FILE &&
2328 info.size > 0 &&
2329 NULL((void*)0) != (local_file_fd = PR_Open(fileName, PR_RDONLY0x01, 0))) {
2330
2331 hdrLen = PORT_Strlen(outHeader)strlen(outHeader);
2332 bigBuf.len = hdrLen + info.size;
2333 bigBuf.data = PORT_MallocPR_Malloc(bigBuf.len + 4095);
2334 if (!bigBuf.data) {
2335 errWarn("PORT_Malloc");
2336 goto done;
2337 }
2338
2339 PORT_Memcpymemcpy(bigBuf.data, outHeader, hdrLen);
2340
2341 count = PR_Read(local_file_fd, bigBuf.data + hdrLen, info.size);
2342 if (count != info.size) {
2343 errWarn("PR_Read local file");
2344 goto done;
2345 }
2346 rv = SECSuccess;
2347 done:
2348 if (local_file_fd) {
2349 PR_Close(local_file_fd);
2350 }
2351 }
2352 return rv;
2353}
2354
2355int numChildren;
2356PRProcess *child[MAX_PROCS25];
2357
2358PRProcess *
2359haveAChild(int argc, char **argv, PRProcessAttr *attr)
2360{
2361 PRProcess *newProcess;
2362
2363 newProcess = PR_CreateProcess(argv[0], argv, NULL((void*)0), attr);
2364 if (!newProcess) {
2365 errWarn("Can't create new process.");
2366 } else {
2367 child[numChildren++] = newProcess;
2368 }
2369 return newProcess;
2370}
2371
2372#ifdef XP_UNIX1
2373void
2374sigusr1_parent_handler(int sig)
2375{
2376 PRProcess *process;
2377 int i;
2378 fprintf(stderrstderr, "SIG_USER: Parent got sig_user, killing children (%d).\n", numChildren);
2379 for (i = 0; i < numChildren; i++) {
2380 process = child[i];
2381 PR_KillProcess(process); /* it would be nice to kill with a sigusr signal */
2382 }
2383}
2384#endif
2385
2386void
2387beAGoodParent(int argc, char **argv, int maxProcs, PRFileDesc *listen_sock)
2388{
2389 PRProcess *newProcess;
2390 PRProcessAttr *attr;
2391 int i;
2392 PRInt32 exitCode;
2393 PRStatus rv;
2394
2395#ifdef XP_UNIX1
2396 struct sigaction act;
2397
2398 /* set up the signal handler */
2399 act.sa_handler__sigaction_handler.sa_handler = sigusr1_parent_handler;
2400 sigemptyset(&act.sa_mask);
2401 act.sa_flags = 0;
2402 if (sigaction(SIGUSR110, &act, NULL((void*)0))) {
2403 fprintf(stderrstderr, "Error installing signal handler.\n");
2404 exit(1);
2405 }
2406#endif
2407
2408 rv = PR_SetFDInheritable(listen_sock, PR_TRUE1);
2409 if (rv != PR_SUCCESS)
2410 errExit("PR_SetFDInheritable");
2411
2412 attr = PR_NewProcessAttr();
2413 if (!attr)
2414 errExit("PR_NewProcessAttr");
2415
2416 rv = PR_ProcessAttrSetInheritableFD(attr, listen_sock, inheritableSockName);
2417 if (rv != PR_SUCCESS)
2418 errExit("PR_ProcessAttrSetInheritableFD");
2419
2420 for (i = 0; i < maxProcs; ++i) {
2421 newProcess = haveAChild(argc, argv, attr);
2422 if (!newProcess)
2423 break;
2424 }
2425
2426 rv = PR_SetFDInheritable(listen_sock, PR_FALSE0);
2427 if (rv != PR_SUCCESS)
2428 errExit("PR_SetFDInheritable");
2429
2430 while (numChildren > 0) {
2431 newProcess = child[numChildren - 1];
2432 PR_WaitProcess(newProcess, &exitCode);
2433 fprintf(stderrstderr, "Child %d exited with exit code %x\n",
2434 numChildren, exitCode);
2435 numChildren--;
2436 }
2437 exit(0);
2438}
2439
2440#define HEXCHAR_TO_INT(c, i)if (((c) >= '0') && ((c) <= '9')) { i = (c) - '0'
; } else if (((c) >= 'a') && ((c) <= 'f')) { i =
(c) - 'a' + 10; } else if (((c) >= 'A') && ((c) <=
'F')) { i = (c) - 'A' + 10; } else if ((c) == '\0') { fprintf
(stderr, "Invalid length of cipher string (-c :WXYZ).\n"); exit
(9); } else { fprintf(stderr, "Non-hex char in cipher string (-c :WXYZ).\n"
); exit(9); }
\
2441 if (((c) >= '0') && ((c) <= '9')) { \
2442 i = (c) - '0'; \
2443 } else if (((c) >= 'a') && ((c) <= 'f')) { \
2444 i = (c) - 'a' + 10; \
2445 } else if (((c) >= 'A') && ((c) <= 'F')) { \
2446 i = (c) - 'A' + 10; \
2447 } else if ((c) == '\0') { \
2448 fprintf(stderrstderr, "Invalid length of cipher string (-c :WXYZ).\n"); \
2449 exit(9); \
2450 } else { \
2451 fprintf(stderrstderr, "Non-hex char in cipher string (-c :WXYZ).\n"); \
2452 exit(9); \
2453 }
2454
2455SECStatus
2456enableOCSPStapling(const char *mode)
2457{
2458 if (!strcmp(mode, "good")) {
2459 ocspStaplingMode = osm_good;
2460 return SECSuccess;
2461 }
2462 if (!strcmp(mode, "unknown")) {
2463 ocspStaplingMode = osm_unknown;
2464 return SECSuccess;
2465 }
2466 if (!strcmp(mode, "revoked")) {
2467 ocspStaplingMode = osm_revoked;
2468 return SECSuccess;
2469 }
2470 if (!strcmp(mode, "badsig")) {
2471 ocspStaplingMode = osm_badsig;
2472 return SECSuccess;
2473 }
2474 if (!strcmp(mode, "corrupted")) {
2475 ocspStaplingMode = osm_corrupted;
2476 return SECSuccess;
2477 }
2478 if (!strcmp(mode, "failure")) {
2479 ocspStaplingMode = osm_failure;
2480 return SECSuccess;
2481 }
2482 if (!strcmp(mode, "random")) {
2483 ocspStaplingMode = osm_random;
2484 return SECSuccess;
2485 }
2486 if (!strcmp(mode, "ocsp")) {
2487 ocspStaplingMode = osm_ocsp;
2488 return SECSuccess;
2489 }
2490 return SECFailure;
2491}
2492
2493int
2494main(int argc, char **argv)
2495{
2496 char *progName = NULL((void*)0);
2497 const char *fileName = NULL((void*)0);
2498 char *cipherString = NULL((void*)0);
2499 const char *dir = ".";
2500 char *passwd = NULL((void*)0);
2501 char *pwfile = NULL((void*)0);
2502 const char *pidFile = NULL((void*)0);
2503 char *tmp;
2504 char *envString;
2505 PRFileDesc *listen_sock;
2506 CERTCertificate *cert[MAX_CERT_NICKNAME_ARRAY_INDEX10] = { NULL((void*)0) };
2507 SECKEYPrivateKey *privKey[MAX_CERT_NICKNAME_ARRAY_INDEX10] = { NULL((void*)0) };
2508 int optionsFound = 0;
2509 int maxProcs = 1;
2510 unsigned short port = 0;
2511 SECStatus rv = SECSuccess;
2512 PRStatus prStatus;
2513 PRBool bindOnly = PR_FALSE0;
2514 PRBool useLocalThreads = PR_FALSE0;
2515 PLOptState *optstate;
2516 PLOptStatus status;
2517 PRThread *loggerThread = NULL((void*)0);
2518 PRBool debugCache = PR_FALSE0; /* bug 90518 */
2519 char emptyString[] = { "" };
2520 char *certPrefix = emptyString;
2521 SSL3Statistics *ssl3stats;
2522 PRUint32 i;
2523 secuPWData pwdata = { PW_NONE, 0 };
2524 char *expectedHostNameVal = NULL((void*)0);
2525 PLArenaPool *certStatusArena = NULL((void*)0);
2526
2527 tmp = strrchr(argv[0], '/');
2528 tmp = tmp ? tmp + 1 : argv[0];
2529 progName = strrchr(tmp, '\\');
2530 progName = progName ? progName + 1 : tmp;
2531
2532 PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
2533 SSL_VersionRangeGetSupported(ssl_variant_stream, &enabledVersions);
2534
2535 /* please keep this list of options in ASCII collating sequence.
2536 ** numbers, then capital letters, then lower case, alphabetical.
2537 ** XXX: 'B', and 'q' were used in the past but removed
2538 ** in 3.28, please leave some time before resuing those. */
2539 optstate = PL_CreateOptState(argc, argv,
2540 "2:A:C:DEGH:I:J:L:M:NP:QRS:T:U:V:W:X:YZa:bc:d:e:f:g:hi:jk:lmn:op:rst:uvw:x:yz:");
2541 while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
2542 ++optionsFound;
2543 switch (optstate->option) {
2544 case '2':
2545 fileName = optstate->value;
2546 break;
2547
2548 case 'A':
2549 ocspStaplingCA = PORT_StrdupPORT_Strdup_Util(optstate->value);
2550 break;
2551
2552 case 'C':
2553 if (optstate->value)
2554 NumSidCacheEntries = PORT_Atoi(optstate->value)(int)strtol(optstate->value, ((void*)0), 10);
2555 break;
2556
2557 case 'D':
2558 noDelay = PR_TRUE1;
2559 break;
2560
2561 case 'E':
2562 enablePostHandshakeAuth = PR_TRUE1;
2563 break;
2564
2565 case 'H':
2566 configureDHE = (PORT_Atoi(optstate->value)(int)strtol(optstate->value, ((void*)0), 10) != 0);
2567 break;
2568
2569 case 'G':
2570 enableExtendedMasterSecret = PR_TRUE1;
2571 break;
2572
2573 case 'L':
2574 logStats = PR_TRUE1;
2575 if (optstate->value == NULL((void*)0)) {
2576 logPeriod = 30;
2577 } else {
2578 logPeriod = PORT_Atoi(optstate->value)(int)strtol(optstate->value, ((void*)0), 10);
2579 if (logPeriod <= 0)
2580 logPeriod = 30;
2581 }
2582 break;
2583
2584 case 'M':
2585 maxProcs = PORT_Atoi(optstate->value)(int)strtol(optstate->value, ((void*)0), 10);
2586 if (maxProcs < 1)
2587 maxProcs = 1;
2588 if (maxProcs > MAX_PROCS25)
2589 maxProcs = MAX_PROCS25;
2590 break;
2591
2592 case 'N':
2593 NoReuse = PR_TRUE1;
2594 break;
2595
2596 case 'R':
2597 disableRollBack = PR_TRUE1;
2598 break;
2599
2600 case 'S':
2601 if (certNicknameIndex >= MAX_CERT_NICKNAME_ARRAY_INDEX10) {
2602 Usage(progName);
2603 break;
2604 }
2605 certNicknameArray[certNicknameIndex++] = PORT_StrdupPORT_Strdup_Util(optstate->value);
2606 break;
2607
2608 case 'T':
2609 if (enableOCSPStapling(optstate->value) != SECSuccess) {
2610 fprintf(stderrstderr, "Invalid OCSP stapling mode.\n");
2611 fprintf(stderrstderr, "Run '%s -h' for usage information.\n", progName);
2612 exit(53);
2613 }
2614 break;
2615
2616 case 'U':
2617 configureReuseECDHE = (PORT_Atoi(optstate->value)(int)strtol(optstate->value, ((void*)0), 10) != 0);
2618 break;
2619
2620 case 'V':
2621 if (SECU_ParseSSLVersionRangeString(optstate->value,
2622 enabledVersions, &enabledVersions) !=
2623 SECSuccess) {
2624 fprintf(stderrstderr, "Bad version specified.\n");
2625 Usage(progName);
2626 exit(1);
2627 }
2628 break;
2629
2630 case 'W':
2631 configureWeakDHE = (PORT_Atoi(optstate->value)(int)strtol(optstate->value, ((void*)0), 10) != 0);
2632 break;
2633
2634 case 'Y':
2635 PrintCipherUsage(progName);
2636 exit(0);
2637 break;
2638
2639 case 'a':
2640 if (virtServerNameIndex >= MAX_VIRT_SERVER_NAME_ARRAY_INDEX10) {
2641 Usage(progName);
2642 break;
2643 }
2644 virtServerNameArray[virtServerNameIndex++] =
2645 PORT_StrdupPORT_Strdup_Util(optstate->value);
2646 break;
2647
2648 case 'b':
2649 bindOnly = PR_TRUE1;
2650 break;
2651
2652 case 'c':
2653 cipherString = PORT_StrdupPORT_Strdup_Util(optstate->value);
2654 break;
2655
2656 case 'd':
2657 dir = optstate->value;
2658 break;
2659
2660 case 'e':
2661 if (certNicknameIndex >= MAX_CERT_NICKNAME_ARRAY_INDEX10) {
2662 Usage(progName);
2663 break;
2664 }
2665 certNicknameArray[certNicknameIndex++] = PORT_StrdupPORT_Strdup_Util(optstate->value);
2666 break;
2667
2668 case 'f':
2669 pwdata.source = PW_FROMFILE;
2670 pwdata.data = pwfile = PORT_StrdupPORT_Strdup_Util(optstate->value);
2671 break;
2672
2673 case 'g':
2674 testBulk = PR_TRUE1;
2675 testBulkTotal = PORT_Atoi(optstate->value)(int)strtol(optstate->value, ((void*)0), 10);
2676 break;
2677
2678 case 'h':
2679 Usage(progName);
2680 exit(0);
2681 break;
2682
2683 case 'i':
2684 pidFile = optstate->value;
2685 break;
2686
2687 case 'j':
2688 initLoggingLayer();
2689 loggingLayer = PR_TRUE1;
2690 break;
2691
2692 case 'k':
2693 expectedHostNameVal = PORT_StrdupPORT_Strdup_Util(optstate->value);
2694 break;
2695
2696 case 'l':
2697 useLocalThreads = PR_TRUE1;
2698 break;
2699
2700 case 'm':
2701 useModelSocket = PR_TRUE1;
2702 break;
2703
2704 case 'n':
2705 if (certNicknameIndex >= MAX_CERT_NICKNAME_ARRAY_INDEX10) {
2706 Usage(progName);
2707 break;
2708 }
2709 certNicknameArray[certNicknameIndex++] = PORT_StrdupPORT_Strdup_Util(optstate->value);
2710 virtServerNameArray[0] = PORT_StrdupPORT_Strdup_Util(optstate->value);
2711 break;
2712
2713 case 'P':
2714 certPrefix = PORT_StrdupPORT_Strdup_Util(optstate->value);
2715 break;
2716
2717 case 'o':
2718 MakeCertOK = 1;
2719 break;
2720
2721 case 'p':
2722 port = PORT_Atoi(optstate->value)(int)strtol(optstate->value, ((void*)0), 10);
2723 break;
2724
2725 case 'r':
2726 ++requestCert;
2727 break;
2728
2729 case 's':
2730 disableLocking = PR_TRUE1;
2731 break;
2732
2733 case 't':
2734 maxThreads = PORT_Atoi(optstate->value)(int)strtol(optstate->value, ((void*)0), 10);
2735 if (maxThreads > MAX_THREADS4096)
2736 maxThreads = MAX_THREADS4096;
2737 if (maxThreads < MIN_THREADS3)
2738 maxThreads = MIN_THREADS3;
2739 break;
2740
2741 case 'u':
2742 enableSessionTickets = PR_TRUE1;
2743 break;
2744
2745 case 'v':
2746 verbose++;
2747 break;
2748
2749 case 'w':
2750 pwdata.source = PW_PLAINTEXT;
2751 pwdata.data = passwd = PORT_StrdupPORT_Strdup_Util(optstate->value);
2752 break;
2753
2754 case 'y':
2755 debugCache = PR_TRUE1;
2756 break;
2757
2758 case 'Z':
2759 zeroRTT = PR_TRUE1;
2760 break;
2761
2762 case 'z':
2763 rv = readPSK(optstate->value, &psk, &pskLabel);
2764 if (rv != SECSuccess) {
2765 PL_DestroyOptState(optstate);
2766 fprintf(stderrstderr, "Bad PSK specified.\n");
2767 Usage(progName);
2768 exit(1);
2769 }
2770 break;
2771
2772 case 'Q':
2773 enableALPN = PR_TRUE1;
2774 break;
2775
2776 case 'I':
2777 rv = parseGroupList(optstate->value, &enabledGroups, &enabledGroupsCount);
2778 if (rv != SECSuccess) {
2779 PL_DestroyOptState(optstate);
2780 fprintf(stderrstderr, "Bad group specified.\n");
2781 fprintf(stderrstderr, "Run '%s -h' for usage information.\n", progName);
2782 exit(5);
2783 }
2784 break;
2785
2786 case 'J':
2787 rv = parseSigSchemeList(optstate->value, &enabledSigSchemes, &enabledSigSchemeCount);
2788 if (rv != SECSuccess) {
2789 PL_DestroyOptState(optstate);
2790 fprintf(stderrstderr, "Bad signature scheme specified.\n");
2791 fprintf(stderrstderr, "Run '%s -h' for usage information.\n", progName);
2792 exit(5);
2793 }
2794 break;
2795
2796 case 'x':
2797 rv = parseExporters(optstate->value,
2798 &enabledExporters, &enabledExporterCount);
2799 if (rv != SECSuccess) {
2800 PL_DestroyOptState(optstate);
2801 fprintf(stderrstderr, "Bad exporter specified.\n");
2802 fprintf(stderrstderr, "Run '%s -h' for usage information.\n", progName);
2803 exit(5);
2804 }
2805 break;
2806
2807 case 'X':
2808 echParamsStr = PORT_StrdupPORT_Strdup_Util(optstate->value);
2809 if (echParamsStr == NULL((void*)0)) {
2810 PL_DestroyOptState(optstate);
2811 fprintf(stderrstderr, "echParamsStr copy failed.\n");
2812 exit(5);
2813 }
2814 break;
2815 default:
2816 case '?':
2817 fprintf(stderrstderr, "Unrecognized or bad option specified: %c\n", optstate->option);
2818 fprintf(stderrstderr, "Run '%s -h' for usage information.\n", progName);
2819 exit(4);
2820 break;
2821 }
2822 }
2823 PL_DestroyOptState(optstate);
2824 if (status == PL_OPT_BAD) {
2825 fprintf(stderrstderr, "Unrecognized or bad option specified.\n");
2826 fprintf(stderrstderr, "Run '%s -h' for usage information.\n", progName);
2827 exit(5);
2828 }
2829 if (!optionsFound) {
2830 Usage(progName);
2831 exit(51);
2832 }
2833 switch (ocspStaplingMode) {
2834 case osm_good:
2835 case osm_revoked:
2836 case osm_unknown:
2837 case osm_random:
2838 if (!ocspStaplingCA) {
2839 fprintf(stderrstderr, "Selected stapling response requires the -A parameter.\n");
2840 fprintf(stderrstderr, "Run '%s -h' for usage information.\n", progName);
2841 exit(52);
2842 }
2843 break;
2844 default:
2845 break;
2846 }
2847
2848 /* The -b (bindOnly) option is only used by the ssl.sh test
2849 * script on Linux to determine whether a previous selfserv
2850 * process has fully died and freed the port. (Bug 129701)
2851 */
2852 if (bindOnly) {
2853 listen_sock = getBoundListenSocket(port);
2854 if (!listen_sock) {
2855 exit(1);
2856 }
2857 if (listen_sock) {
2858 PR_Close(listen_sock);
2859 }
2860 exit(0);
2861 }
2862
2863 if (certNicknameIndex == 0) {
2864 fprintf(stderrstderr, "Must specify at least one certificate nickname using '-n' (RSA), '-S' (DSA), or 'e' (EC).\n");
2865 fprintf(stderrstderr, "Run '%s -h' for usage information.\n", progName);
2866 exit(6);
2867 }
2868
2869 if (port == 0) {
2870 fprintf(stderrstderr, "Required argument 'port' must be non-zero value\n");
2871 exit(7);
2872 }
2873
2874 if (NoReuse && maxProcs > 1) {
2875 fprintf(stderrstderr, "-M and -N options are mutually exclusive.\n");
2876 exit(14);
2877 }
2878
2879 envString = PR_GetEnvSecure(envVarName);
2880 if (!envString && pidFile) {
2881 FILE *tmpfile = fopen(pidFile, "w+");
2882
2883 if (tmpfile) {
2884 fprintf(tmpfile, "%d", getpid());
2885 fclose(tmpfile);
2886 }
2887 }
2888
2889 /* allocate and initialize app data for bulk encryption testing */
2890 if (testBulk) {
2891 testBulkBuf = PORT_MallocPR_Malloc(testBulkSize);
2892 if (testBulkBuf == NULL((void*)0))
2893 errExit("Out of memory: testBulkBuf");
2894 for (i = 0; i < testBulkSize; i++)
2895 testBulkBuf[i] = i;
2896 }
2897
2898 envString = PR_GetEnvSecure(envVarName);
2899 tmp = PR_GetEnvSecure("TMP");
2900 if (!tmp)
2901 tmp = PR_GetEnvSecure("TMPDIR");
2902 if (!tmp)
2903 tmp = PR_GetEnvSecure("TEMP");
2904
2905 if (envString) {
2906 /* we're one of the children in a multi-process server. */
2907 listen_sock = PR_GetInheritedFD(inheritableSockName);
2908 if (!listen_sock)
2909 errExit("PR_GetInheritedFD");
2910#ifndef WINNT
2911 /* we can't do this on NT because it breaks NSPR and
2912 PR_Accept will fail on the socket in the child process if
2913 the socket state is change to non inheritable
2914 It is however a security issue to leave it accessible,
2915 but it is OK for a test server such as selfserv.
2916 NSPR should fix it eventually . see bugzilla 101617
2917 and 102077
2918 */
2919 prStatus = PR_SetFDInheritable(listen_sock, PR_FALSE0);
2920 if (prStatus != PR_SUCCESS)
2921 errExit("PR_SetFDInheritable");
2922#endif
2923 rv = SSL_InheritMPServerSIDCache(envString);
2924 if (rv != SECSuccess)
2925 errExit("SSL_InheritMPServerSIDCache");
2926 hasSidCache = PR_TRUE1;
2927 /* Call the NSS initialization routines */
2928 rv = NSS_Initialize(dir, certPrefix, certPrefix, SECMOD_DB"secmod.db", NSS_INIT_READONLY0x1);
2929 if (rv != SECSuccess) {
2930 fputs("NSS_Init failed.\n", stderrstderr);
2931 exit(8);
2932 }
2933 } else if (maxProcs > 1) {
2934 /* we're going to be the parent in a multi-process server. */
2935 listen_sock = getBoundListenSocket(port);
2936 rv = SSL_ConfigMPServerSIDCache(NumSidCacheEntries, 0, 0, tmp);
2937 if (rv != SECSuccess)
2938 errExit("SSL_ConfigMPServerSIDCache");
2939 hasSidCache = PR_TRUE1;
2940 beAGoodParent(argc, argv, maxProcs, listen_sock);
2941 exit(99); /* should never get here */
2942 } else {
2943 /* Call the NSS initialization routines */
2944 rv = NSS_Initialize(dir, certPrefix, certPrefix, SECMOD_DB"secmod.db", NSS_INIT_READONLY0x1);
2945 if (rv != SECSuccess) {
2946 fputs("NSS_Init failed.\n", stderrstderr);
2947 exit(8);
2948 }
2949 /* we're an ordinary single process server. */
2950 listen_sock = getBoundListenSocket(port);
2951 prStatus = PR_SetFDInheritable(listen_sock, PR_FALSE0);
2952 if (prStatus != PR_SUCCESS)
2953 errExit("PR_SetFDInheritable");
2954 if (!NoReuse) {
2955 rv = SSL_ConfigServerSessionIDCache(NumSidCacheEntries,
2956 0, 0, tmp);
2957 if (rv != SECSuccess)
2958 errExit("SSL_ConfigServerSessionIDCache");
2959 hasSidCache = PR_TRUE1;
2960 }
2961 }
2962
2963 lm = PR_NewLogModule("TestCase");
2964
2965 if (fileName)
2966 readBigFile(fileName);
2967
2968 /* set our password function */
2969 PK11_SetPasswordFunc(SECU_GetModulePassword);
2970
2971 /* all SSL3 cipher suites are enabled by default. */
2972 if (cipherString) {
2973 char *cstringSaved = cipherString;
2974 int ndx;
2975
2976 /* disable all the ciphers, then enable the ones we want. */
2977 disableAllSSLCiphers();
2978
2979 while (0 != (ndx = *cipherString++)) {
2980 int cipher = 0;
2981
2982 if (ndx == ':') {
2983 int ctmp;
2984
2985 HEXCHAR_TO_INT(*cipherString, ctmp)if (((*cipherString) >= '0') && ((*cipherString) <=
'9')) { ctmp = (*cipherString) - '0'; } else if (((*cipherString
) >= 'a') && ((*cipherString) <= 'f')) { ctmp =
(*cipherString) - 'a' + 10; } else if (((*cipherString) >=
'A') && ((*cipherString) <= 'F')) { ctmp = (*cipherString
) - 'A' + 10; } else if ((*cipherString) == '\0') { fprintf(stderr
, "Invalid length of cipher string (-c :WXYZ).\n"); exit(9); }
else { fprintf(stderr, "Non-hex char in cipher string (-c :WXYZ).\n"
); exit(9); }
2986 cipher |= (ctmp << 12);
2987 cipherString++;
2988 HEXCHAR_TO_INT(*cipherString, ctmp)if (((*cipherString) >= '0') && ((*cipherString) <=
'9')) { ctmp = (*cipherString) - '0'; } else if (((*cipherString
) >= 'a') && ((*cipherString) <= 'f')) { ctmp =
(*cipherString) - 'a' + 10; } else if (((*cipherString) >=
'A') && ((*cipherString) <= 'F')) { ctmp = (*cipherString
) - 'A' + 10; } else if ((*cipherString) == '\0') { fprintf(stderr
, "Invalid length of cipher string (-c :WXYZ).\n"); exit(9); }
else { fprintf(stderr, "Non-hex char in cipher string (-c :WXYZ).\n"
); exit(9); }
2989 cipher |= (ctmp << 8);
2990 cipherString++;
2991 HEXCHAR_TO_INT(*cipherString, ctmp)if (((*cipherString) >= '0') && ((*cipherString) <=
'9')) { ctmp = (*cipherString) - '0'; } else if (((*cipherString
) >= 'a') && ((*cipherString) <= 'f')) { ctmp =
(*cipherString) - 'a' + 10; } else if (((*cipherString) >=
'A') && ((*cipherString) <= 'F')) { ctmp = (*cipherString
) - 'A' + 10; } else if ((*cipherString) == '\0') { fprintf(stderr
, "Invalid length of cipher string (-c :WXYZ).\n"); exit(9); }
else { fprintf(stderr, "Non-hex char in cipher string (-c :WXYZ).\n"
); exit(9); }
2992 cipher |= (ctmp << 4);
2993 cipherString++;
2994 HEXCHAR_TO_INT(*cipherString, ctmp)if (((*cipherString) >= '0') && ((*cipherString) <=
'9')) { ctmp = (*cipherString) - '0'; } else if (((*cipherString
) >= 'a') && ((*cipherString) <= 'f')) { ctmp =
(*cipherString) - 'a' + 10; } else if (((*cipherString) >=
'A') && ((*cipherString) <= 'F')) { ctmp = (*cipherString
) - 'A' + 10; } else if ((*cipherString) == '\0') { fprintf(stderr
, "Invalid length of cipher string (-c :WXYZ).\n"); exit(9); }
else { fprintf(stderr, "Non-hex char in cipher string (-c :WXYZ).\n"
); exit(9); }
2995 cipher |= ctmp;
2996 cipherString++;
2997 } else {
2998 if (!isalpha(ndx)((*__ctype_b_loc ())[(int) ((ndx))] & (unsigned short int
) _ISalpha)
) {
2999 fprintf(stderrstderr,
3000 "Non-alphabetic char in cipher string (-c arg).\n");
3001 exit(9);
3002 }
3003 ndx = tolower(ndx) - 'a';
3004 if (ndx < PR_ARRAY_SIZE(ssl3CipherSuites)(sizeof(ssl3CipherSuites)/sizeof((ssl3CipherSuites)[0]))) {
3005 cipher = ssl3CipherSuites[ndx];
3006 }
3007 }
3008 if (cipher > 0) {
3009 rv = SSL_CipherPrefSetDefault(cipher, SSL_ALLOWED1);
3010 if (rv != SECSuccess) {
3011 SECU_PrintError(progName, "SSL_CipherPrefSetDefault()");
3012 exit(9);
3013 }
3014 } else {
3015 fprintf(stderrstderr,
3016 "Invalid cipher specification (-c arg).\n");
3017 exit(9);
3018 }
3019 }
3020 PORT_FreePORT_Free_Util(cstringSaved);
3021 }
3022
3023 certStatusArena = PORT_NewArenaPORT_NewArena_Util(DER_DEFAULT_CHUNKSIZE(2048));
3024 if (!certStatusArena)
3025 errExit("cannot allocate certStatusArena");
3026
3027 for (i = 0; i < certNicknameIndex; i++) {
3028 cert[i] = PK11_FindCertFromNickname(certNicknameArray[i], &pwdata);
3029 if (cert[i] == NULL((void*)0)) {
3030 fprintf(stderrstderr, "selfserv: Can't find certificate %s\n", certNicknameArray[i]);
3031 exit(10);
3032 }
3033 privKey[i] = PK11_FindKeyByAnyCert(cert[i], &pwdata);
3034 if (privKey[i] == NULL((void*)0)) {
3035 fprintf(stderrstderr, "selfserv: Can't find Private Key for cert %s\n",
3036 certNicknameArray[i]);
3037 exit(11);
3038 }
3039 if (privKey[i]->keyType != ecKey)
3040 setupCertStatus(certStatusArena, cert[i], i, &pwdata);
3041 }
3042
3043 if (configureWeakDHE > 0) {
3044 fprintf(stderrstderr, "selfserv: Creating dynamic weak DH parameters\n");
3045 rv = SSL_EnableWeakDHEPrimeGroup(NULL((void*)0), PR_TRUE1);
3046 if (rv != SECSuccess) {
3047 goto cleanup;
3048 }
3049 fprintf(stderrstderr, "selfserv: Done creating dynamic weak DH parameters\n");
3050 }
3051 if (zeroRTT) {
3052 rv = SSL_CreateAntiReplayContext(PR_Now(), 10L * PR_USEC_PER_SEC, 7, 14, &antiReplay)(SSL_GetExperimentalAPI("SSL_CreateAntiReplayContext") ? ((SECStatus
(*) (PRTime _now, PRTime _window, unsigned int _k, unsigned int
_bits, SSLAntiReplayContext **_ctx))SSL_GetExperimentalAPI("SSL_CreateAntiReplayContext"
))(PR_Now(), 10L * 1000000L, 7, 14, &antiReplay) : SECFailure
)
;
3053 if (rv != SECSuccess) {
3054 errExit("Unable to create anti-replay context for 0-RTT.");
3055 }
3056 }
3057
3058 /* allocate the array of thread slots, and launch the worker threads. */
3059 rv = launch_threads(&jobLoop, 0, 0, useLocalThreads);
3060
3061 if (rv == SECSuccess && logStats) {
3062 loggerThread = PR_CreateThread(PR_SYSTEM_THREAD,
3063 logger, NULL((void*)0), PR_PRIORITY_NORMAL,
3064 useLocalThreads ? PR_LOCAL_THREAD
3065 : PR_GLOBAL_THREAD,
3066 PR_JOINABLE_THREAD, 0);
3067 if (loggerThread == NULL((void*)0)) {
3068 fprintf(stderrstderr, "selfserv: Failed to launch logger thread!\n");
3069 rv = SECFailure;
3070 }
3071 }
3072
3073 if (rv == SECSuccess) {
3074 server_main(listen_sock, privKey, cert,
3075 expectedHostNameVal);
3076 }
3077
3078 VLOG(("selfserv: server_thread: exiting"))do { if (((lm)->level >= (PR_LOG_DEBUG))) { PR_LogPrint
("selfserv: server_thread: exiting"); } } while (0)
;
3079
3080cleanup:
3081 printSSLStatistics();
3082 ssl3stats = SSL_GetStatistics();
3083 if (ssl3stats->hch_sid_ticket_parse_failures != 0) {
3084 fprintf(stderrstderr, "selfserv: Experienced ticket parse failure(s)\n");
3085 exit(1);
3086 }
3087 if (failedToNegotiateName) {
3088 fprintf(stderrstderr, "selfserv: Failed properly negotiate server name\n");
3089 exit(1);
3090 }
3091
3092 {
3093 for (i = 0; i < certNicknameIndex; i++) {
3094 if (cert[i]) {
3095 CERT_DestroyCertificate(cert[i]);
3096 }
3097 if (privKey[i]) {
3098 SECKEY_DestroyPrivateKey(privKey[i]);
3099 }
3100 PORT_FreePORT_Free_Util(certNicknameArray[i]);
3101 }
3102 for (i = 0; virtServerNameArray[i]; i++) {
3103 PORT_FreePORT_Free_Util(virtServerNameArray[i]);
3104 }
3105 }
3106
3107 if (debugCache) {
3108 nss_DumpCertificateCacheInfo();
3109 }
3110 if (expectedHostNameVal) {
3111 PORT_FreePORT_Free_Util(expectedHostNameVal);
3112 }
3113 if (passwd) {
3114 PORT_FreePORT_Free_Util(passwd);
3115 }
3116 if (pwfile) {
3117 PORT_FreePORT_Free_Util(pwfile);
3118 }
3119 if (certPrefix && certPrefix != emptyString) {
3120 PORT_FreePORT_Free_Util(certPrefix);
3121 }
3122
3123 if (hasSidCache) {
3124 SSL_ShutdownServerSessionIDCache();
3125 }
3126 if (certStatusArena) {
3127 PORT_FreeArenaPORT_FreeArena_Util(certStatusArena, PR_FALSE0);
3128 }
3129 if (enabledGroups) {
3130 PORT_FreePORT_Free_Util(enabledGroups);
3131 }
3132 if (antiReplay) {
3133 SSL_ReleaseAntiReplayContext(antiReplay)(SSL_GetExperimentalAPI("SSL_ReleaseAntiReplayContext") ? ((SECStatus
(*) (SSLAntiReplayContext * _ctx))SSL_GetExperimentalAPI("SSL_ReleaseAntiReplayContext"
))(antiReplay) : SECFailure)
;
3134 }
3135 SECITEM_ZfreeItemSECITEM_ZfreeItem_Util(&psk, PR_FALSE0);
3136 SECITEM_ZfreeItemSECITEM_ZfreeItem_Util(&pskLabel, PR_FALSE0);
3137 PORT_FreePORT_Free_Util(echParamsStr);
3138 if (NSS_Shutdown() != SECSuccess) {
3139 SECU_PrintError(progName, "NSS_Shutdown");
3140 if (loggerThread) {
3141 PR_JoinThread(loggerThread);
3142 }
3143 PR_Cleanup();
3144 exit(1);
3145 }
3146 PR_Cleanup();
3147 printf("selfserv: normal termination\n");
3148 return 0;
3149}