Bug Summary

File:s/cmd/selfserv/selfserv.c
Warning:line 2299, 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-19/lib/clang/19 -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/Linux6.12_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-19/lib/clang/19/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 -fskip-odr-check-in-gmf -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2025-01-06-222215-268153-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, mlkem768x25519\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 /* Set PR_SockOpt_Linger because it helps prevent a server bind issue
1754 * after clean shutdown . See bug 331413 .
1755 */
1756 opt.option = PR_SockOpt_Linger;
1757 opt.value.linger.polarity = PR_TRUE1;
1758 opt.value.linger.linger = PR_SecondsToInterval(1);
1759 prStatus = PR_SetSocketOption(listen_sock, &opt);
1760 if (prStatus < 0) {
1761 PR_Close(listen_sock);
1762 errExit("PR_SetSocketOption(PR_SockOpt_Linger)");
1763 }
1764
1765 prStatus = PR_Bind(listen_sock, &addr);
1766 if (prStatus < 0) {
1767 PR_Close(listen_sock);
1768 errExit("PR_Bind");
1769 }
1770
1771 prStatus = PR_Listen(listen_sock, listenQueueDepth);
1772 if (prStatus < 0) {
1773 PR_Close(listen_sock);
1774 errExit("PR_Listen");
1775 }
1776 return listen_sock;
1777}
1778
1779PRInt32 PR_CALLBACK
1780logWritev(
1781 PRFileDesc *fd,
1782 const PRIOVec *iov,
1783 PRInt32 size,
1784 PRIntervalTime timeout)
1785{
1786 PRInt32 rv = (fd->lower->methods->writev)(fd->lower, iov, size,
1787 timeout);
1788 /* Add the amount written, but not if there's an error */
1789 if (rv > 0)
1790 PR_ATOMIC_ADD(&loggerBytesTCP, rv)__sync_add_and_fetch(&loggerBytesTCP, rv);
1791 return rv;
1792}
1793
1794PRInt32 PR_CALLBACK
1795logWrite(
1796 PRFileDesc *fd,
1797 const void *buf,
1798 PRInt32 amount)
1799{
1800 PRInt32 rv = (fd->lower->methods->write)(fd->lower, buf, amount);
1801 /* Add the amount written, but not if there's an error */
1802 if (rv > 0)
1803 PR_ATOMIC_ADD(&loggerBytesTCP, rv)__sync_add_and_fetch(&loggerBytesTCP, rv);
1804
1805 return rv;
1806}
1807
1808PRInt32 PR_CALLBACK
1809logSend(
1810 PRFileDesc *fd,
1811 const void *buf,
1812 PRInt32 amount,
1813 PRIntn flags,
1814 PRIntervalTime timeout)
1815{
1816 PRInt32 rv = (fd->lower->methods->send)(fd->lower, buf, amount,
1817 flags, timeout);
1818 /* Add the amount written, but not if there's an error */
1819 if (rv > 0)
1820 PR_ATOMIC_ADD(&loggerBytesTCP, rv)__sync_add_and_fetch(&loggerBytesTCP, rv);
1821 return rv;
1822}
1823
1824void
1825initLoggingLayer(void)
1826{
1827 /* get a new layer ID */
1828 log_layer_id = PR_GetUniqueIdentity("Selfserv Logging");
1829 if (log_layer_id == PR_INVALID_IO_LAYER(PRDescIdentity)-1)
1830 errExit("PR_GetUniqueIdentity");
1831
1832 /* setup the default IO methods with my custom write methods */
1833 memcpy(&loggingMethods, PR_GetDefaultIOMethods(), sizeof(PRIOMethods));
1834 loggingMethods.writev = logWritev;
1835 loggingMethods.write = logWrite;
1836 loggingMethods.send = logSend;
1837}
1838
1839void
1840handshakeCallback(PRFileDesc *fd, void *client_data)
1841{
1842 const char *handshakeName = (const char *)client_data;
1843 if (handshakeName && !failedToNegotiateName) {
1844 SECItem *hostInfo = SSL_GetNegotiatedHostInfo(fd);
1845 if (!hostInfo || PORT_Strncmpstrncmp(handshakeName, (char *)hostInfo->data,
1846 hostInfo->len)) {
1847 failedToNegotiateName = PR_TRUE1;
1848 }
1849 if (hostInfo) {
1850 SECITEM_FreeItemSECITEM_FreeItem_Util(hostInfo, PR_TRUE1);
1851 }
1852 }
1853 if (enabledExporters) {
1854 SECStatus rv = exportKeyingMaterials(fd, enabledExporters, enabledExporterCount);
1855 if (rv != SECSuccess) {
1856 PRErrorCode err = PR_GetError();
1857 fprintf(stderrstderr,
1858 "couldn't export keying material: %s\n",
1859 SECU_Strerror(err)PR_ErrorToString((err), 0));
1860 }
1861 }
1862}
1863
1864static SECStatus
1865importPsk(PRFileDesc *model_sock)
1866{
1867 SECU_PrintAsHex(stdoutstdout, &psk, "Using External PSK", 0);
1868 PK11SlotInfo *slot = NULL((void*)0);
1869 PK11SymKey *symKey = NULL((void*)0);
1870 slot = PK11_GetInternalSlot();
1871 if (!slot) {
1872 errWarn("PK11_GetInternalSlot failed");
1873 return SECFailure;
1874 }
1875 symKey = PK11_ImportSymKey(slot, CKM_HKDF_KEY_GEN0x0000402cUL, PK11_OriginUnwrap,
1876 CKA_DERIVE0x0000010CUL, &psk, NULL((void*)0));
1877 PK11_FreeSlot(slot);
1878 if (!symKey) {
1879 errWarn("PK11_ImportSymKey failed\n");
1880 return SECFailure;
1881 }
1882
1883 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)
1884 (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)
1885 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)
;
1886 PK11_FreeSymKey(symKey);
1887 return rv;
1888}
1889
1890static SECStatus
1891configureEchWithPublicName(PRFileDesc *model_sock, const char *public_name)
1892{
1893 SECStatus rv;
1894
1895#define OID_LEN65 65
1896 unsigned char paramBuf[OID_LEN65];
1897 SECItem ecParams = { siBuffer, paramBuf, sizeof(paramBuf) };
1898 SECKEYPublicKey *pubKey = NULL((void*)0);
1899 SECKEYPrivateKey *privKey = NULL((void*)0);
1900 SECOidData *oidData;
1901 char *echConfigBase64 = NULL((void*)0);
1902 PRUint8 configId = 0;
1903 PRUint8 configBuf[1000];
1904 unsigned int len = 0;
1905 HpkeSymmetricSuite echCipherSuite = { HpkeKdfHkdfSha256,
1906 HpkeAeadChaCha20Poly1305 };
1907
1908 PK11SlotInfo *slot = PK11_GetInternalKeySlot();
1909 if (!slot) {
1910 errWarn("PK11_GetInternalKeySlot failed");
1911 return SECFailure;
1912 }
1913
1914 if (PK11_GenerateRandom(&configId, sizeof(configId)) != SECSuccess) {
1915 errWarn("Failed to generate random configId");
1916 goto loser;
1917 }
1918
1919 oidData = SECOID_FindOIDByTagSECOID_FindOIDByTag_Util(SEC_OID_CURVE25519);
1920 if (oidData && (2 + oidData->oid.len) < sizeof(paramBuf)) {
1921 ecParams.data[0] = SEC_ASN1_OBJECT_ID0x06;
1922 ecParams.data[1] = oidData->oid.len;
1923 memcpy(ecParams.data + 2, oidData->oid.data, oidData->oid.len);
1924 ecParams.len = oidData->oid.len + 2;
1925 } else {
1926 errWarn("SECOID_FindOIDByTag failed");
1927 goto loser;
1928 }
1929 privKey = PK11_GenerateKeyPair(slot, CKM_EC_KEY_PAIR_GEN0x00001040UL, &ecParams,
1930 &pubKey, PR_FALSE0, PR_FALSE0, NULL((void*)0));
1931 if (!privKey || !pubKey) {
1932 errWarn("Failed to generate ECH keypair");
1933 goto loser;
1934 }
1935
1936 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)
1937 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)
1938 &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)
1939 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)
;
1940 if (rv != SECSuccess) {
1941 errWarn("SSL_EncodeEchConfigId failed");
1942 goto loser;
1943 }
1944
1945 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)
;
1946 if (rv != SECSuccess) {
1947 errWarn("SSL_SetServerEchConfigs failed");
1948 goto loser;
1949 }
1950
1951 SECItem echConfigItem = { siBuffer, configBuf, len };
1952 echConfigBase64 = NSSBase64_EncodeItemNSSBase64_EncodeItem_Util(NULL((void*)0), NULL((void*)0), 0, &echConfigItem);
1953 if (!echConfigBase64) {
1954 errWarn("NSSBase64_EncodeItem failed");
1955 goto loser;
1956 }
1957
1958 // Remove the newline characters that NSSBase64_EncodeItem unhelpfully inserts.
1959 char *newline = strstr(echConfigBase64, "\r\n");
1960 if (newline) {
1961 memmove(newline, newline + 2, strlen(newline + 2) + 1);
1962 }
1963
1964 printf("%s\n", echConfigBase64);
1965 PORT_FreePORT_Free_Util(echConfigBase64);
1966 SECKEY_DestroyPrivateKey(privKey);
1967 SECKEY_DestroyPublicKey(pubKey);
1968 PK11_FreeSlot(slot);
1969 return SECSuccess;
1970
1971loser:
1972 PORT_FreePORT_Free_Util(echConfigBase64);
1973 SECKEY_DestroyPrivateKey(privKey);
1974 SECKEY_DestroyPublicKey(pubKey);
1975 PK11_FreeSlot(slot);
1976 return SECFailure;
1977}
1978
1979static SECStatus
1980configureEchWithData(PRFileDesc *model_sock)
1981{
1982 /* The input should be a Base64-encoded ECHKey struct:
1983 * struct {
1984 * opaque pkcs8_ech_keypair<0..2^16-1>;
1985 * ECHConfigs configs<0..2^16>; // draft-ietf-tls-esni-09
1986 * } ECHKey;
1987 *
1988 * This is not a standardized format, rather it's designed for
1989 * interoperability with https://github.com/xvzcf/tls-interop-runner.
1990 * It is the user's responsibility to ensure that the PKCS8 keypair
1991 * corresponds to the public key embedded in the ECHConfigs.
1992 */
1993
1994#define REMAINING_BYTES(rdr, buf)buf->len - (rdr - buf->data) \
1995 buf->len - (rdr - buf->data)
1996
1997 SECStatus rv;
1998 size_t len;
1999 unsigned char *reader;
2000 PK11SlotInfo *slot = NULL((void*)0);
2001 SECItem *decoded = NULL((void*)0);
2002 SECKEYPublicKey *pk = NULL((void*)0);
2003 SECKEYPrivateKey *sk = NULL((void*)0);
2004 SECItem pkcs8Key = { siBuffer, NULL((void*)0), 0 };
2005
2006 decoded = NSSBase64_DecodeBufferNSSBase64_DecodeBuffer_Util(NULL((void*)0), NULL((void*)0), echParamsStr, PORT_Strlen(echParamsStr)strlen(echParamsStr));
2007 if (!decoded || decoded->len < 2) {
2008 errWarn("Couldn't decode ECHParams");
2009 goto loser;
2010 };
2011 reader = decoded->data;
2012
2013 len = (*(reader++) << 8);
2014 len |= *(reader++);
2015 if (len > (REMAINING_BYTES(reader, decoded)decoded->len - (reader - decoded->data) - 2)) {
2016 errWarn("Bad ECHParams encoding");
2017 goto loser;
2018 }
2019 pkcs8Key.data = reader;
2020 pkcs8Key.len = len;
2021 reader += len;
2022
2023 /* Convert the key bytes to key handles */
2024 slot = PK11_GetInternalKeySlot();
2025 rv = PK11_ImportDERPrivateKeyInfoAndReturnKey(
2026 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));
2027 if (rv != SECSuccess || !sk) {
2028 errWarn("ECH key import failed");
2029 goto loser;
2030 }
2031 pk = SECKEY_ConvertToPublicKey(sk);
2032 if (!pk) {
2033 errWarn("ECH key conversion failed");
2034 goto loser;
2035 }
2036
2037 /* Remainder is the ECHConfigs. */
2038 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)
2039 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)
;
2040 if (rv != SECSuccess) {
2041 errWarn("SSL_SetServerEchConfigs failed");
2042 goto loser;
2043 }
2044
2045 PK11_FreeSlot(slot);
2046 SECKEY_DestroyPrivateKey(sk);
2047 SECKEY_DestroyPublicKey(pk);
2048 SECITEM_FreeItemSECITEM_FreeItem_Util(decoded, PR_TRUE1);
2049 return SECSuccess;
2050loser:
2051 if (slot) {
2052 PK11_FreeSlot(slot);
2053 }
2054 SECKEY_DestroyPrivateKey(sk);
2055 SECKEY_DestroyPublicKey(pk);
2056 SECITEM_FreeItemSECITEM_FreeItem_Util(decoded, PR_TRUE1);
2057 return SECFailure;
2058}
2059
2060static SECStatus
2061configureEch(PRFileDesc *model_sock)
2062{
2063 if (!PORT_Strncmpstrncmp(echParamsStr, "publicname:", PORT_Strlen("publicname:")strlen("publicname:"))) {
2064 return configureEchWithPublicName(model_sock,
2065 &echParamsStr[PORT_Strlen("publicname:")strlen("publicname:")]);
2066 }
2067 return configureEchWithData(model_sock);
2068}
2069
2070void
2071server_main(
2072 PRFileDesc *listen_sock,
2073 SECKEYPrivateKey **privKey,
2074 CERTCertificate **cert,
2075 const char *expectedHostNameVal)
2076{
2077 int i;
2078 PRFileDesc *model_sock = NULL((void*)0);
2079 int rv;
2080 SECStatus secStatus;
2081
2082 if (useModelSocket) {
2083 model_sock = PR_NewTCPSocket();
2084 if (model_sock == NULL((void*)0)) {
2085 errExit("PR_NewTCPSocket on model socket");
2086 }
2087 model_sock = SSL_ImportFD(NULL((void*)0), model_sock);
2088 if (model_sock == NULL((void*)0)) {
2089 errExit("SSL_ImportFD");
2090 }
2091 } else {
2092 model_sock = listen_sock = SSL_ImportFD(NULL((void*)0), listen_sock);
2093 if (listen_sock == NULL((void*)0)) {
2094 errExit("SSL_ImportFD");
2095 }
2096 }
2097
2098 /* do SSL configuration. */
2099 rv = SSL_OptionSet(model_sock, SSL_SECURITY1, enabledVersions.min != 0);
2100 if (rv < 0) {
2101 errExit("SSL_OptionSet SSL_SECURITY");
2102 }
2103
2104 rv = SSL_VersionRangeSet(model_sock, &enabledVersions);
2105 if (rv != SECSuccess) {
2106 errExit("error setting SSL/TLS version range ");
2107 }
2108
2109 rv = SSL_OptionSet(model_sock, SSL_ROLLBACK_DETECTION14, !disableRollBack);
2110 if (rv != SECSuccess) {
2111 errExit("error enabling RollBack detection ");
2112 }
2113 if (disableLocking) {
2114 rv = SSL_OptionSet(model_sock, SSL_NO_LOCKS17, PR_TRUE1);
2115 if (rv != SECSuccess) {
2116 errExit("error disabling SSL socket locking ");
2117 }
2118 }
2119 if (enableSessionTickets) {
2120 rv = SSL_OptionSet(model_sock, SSL_ENABLE_SESSION_TICKETS18, PR_TRUE1);
2121 if (rv != SECSuccess) {
2122 errExit("error enabling Session Ticket extension ");
2123 }
2124 }
2125
2126 if (virtServerNameIndex > 1) {
2127 rv = SSL_SNISocketConfigHook(model_sock, mySSLSNISocketConfig,
2128 (void *)&virtServerNameArray);
2129 if (rv != SECSuccess) {
2130 errExit("error enabling SNI extension ");
2131 }
2132 }
2133
2134 if (configureDHE > -1) {
2135 rv = SSL_OptionSet(model_sock, SSL_ENABLE_SERVER_DHE29, (configureDHE > 0));
2136 if (rv != SECSuccess) {
2137 errExit("error configuring server side DHE support");
2138 }
2139 rv = SSL_OptionSet(model_sock, SSL_REQUIRE_DH_NAMED_GROUPS32, (configureDHE > 1));
2140 if (rv != SECSuccess) {
2141 errExit("error configuring server side FFDHE support");
2142 }
2143 PORT_Assert(configureDHE <= 2)((configureDHE <= 2)?((void)0):PR_Assert("configureDHE <= 2"
,"selfserv.c",2143))
;
2144 }
2145
2146 if (configureReuseECDHE > -1) {
2147 rv = SSL_OptionSet(model_sock, SSL_REUSE_SERVER_ECDHE_KEY27, (configureReuseECDHE > 0));
2148 if (rv != SECSuccess) {
2149 errExit("error configuring server side reuse of ECDHE key");
2150 }
2151 }
2152
2153 if (configureWeakDHE > -1) {
2154 rv = SSL_EnableWeakDHEPrimeGroup(model_sock, (configureWeakDHE > 0));
2155 if (rv != SECSuccess) {
2156 errExit("error configuring weak DHE prime group");
2157 }
2158 }
2159
2160 if (enableExtendedMasterSecret) {
2161 rv = SSL_OptionSet(model_sock, SSL_ENABLE_EXTENDED_MASTER_SECRET30, PR_TRUE1);
2162 if (rv != SECSuccess) {
2163 errExit("error enabling extended master secret ");
2164 }
2165 }
2166
2167 /* This uses the legacy certificate API. See mySSLSNISocketConfig() for the
2168 * new, prefered API. */
2169 for (i = 0; i < certNicknameIndex; i++) {
2170 if (cert[i] != NULL((void*)0)) {
2171 const SSLExtraServerCertData ocspData = {
2172 ssl_auth_null, NULL((void*)0), certStatus[i], NULL((void*)0), NULL((void*)0), NULL((void*)0)
2173 };
2174
2175 secStatus = SSL_ConfigServerCert(model_sock, cert[i],
2176 privKey[i], &ocspData,
2177 sizeof(ocspData));
2178 if (secStatus != SECSuccess)
2179 errExit("SSL_ConfigServerCert");
2180 }
2181 }
2182
2183 if (bigBuf.data) { /* doing FDX */
2184 rv = SSL_OptionSet(model_sock, SSL_ENABLE_FDX11, 1);
2185 if (rv < 0) {
2186 errExit("SSL_OptionSet SSL_ENABLE_FDX");
2187 }
2188 }
2189
2190 if (NoReuse) {
2191 rv = SSL_OptionSet(model_sock, SSL_NO_CACHE9, 1);
2192 if (rv < 0) {
2193 errExit("SSL_OptionSet SSL_NO_CACHE");
2194 }
2195 }
2196
2197 if (zeroRTT) {
2198 if (enabledVersions.max < SSL_LIBRARY_VERSION_TLS_1_30x0304) {
2199 errExit("You tried enabling 0RTT without enabling TLS 1.3!");
2200 }
2201 rv = SSL_SetAntiReplayContext(model_sock, antiReplay)(SSL_GetExperimentalAPI("SSL_SetAntiReplayContext") ? ((SECStatus
(*) (PRFileDesc * _fd, SSLAntiReplayContext * _ctx))SSL_GetExperimentalAPI
("SSL_SetAntiReplayContext"))(model_sock, antiReplay) : SECFailure
)
;
2202 if (rv != SECSuccess) {
2203 errExit("error configuring anti-replay ");
2204 }
2205 rv = SSL_OptionSet(model_sock, SSL_ENABLE_0RTT_DATA33, PR_TRUE1);
2206 if (rv != SECSuccess) {
2207 errExit("error enabling 0RTT ");
2208 }
2209 }
2210
2211 if (enablePostHandshakeAuth) {
2212 if (enabledVersions.max < SSL_LIBRARY_VERSION_TLS_1_30x0304) {
2213 errExit("You tried enabling post-handshake auth without enabling TLS 1.3!");
2214 }
2215 rv = SSL_OptionSet(model_sock, SSL_ENABLE_POST_HANDSHAKE_AUTH39, PR_TRUE1);
2216 if (rv != SECSuccess) {
2217 errExit("error enabling post-handshake auth");
2218 }
2219 }
2220
2221 if (enableALPN) {
2222 PRUint8 alpnVal[] = { 0x08,
2223 0x68, 0x74, 0x74, 0x70, 0x2f, 0x31, 0x2e, 0x31 };
2224 rv = SSL_OptionSet(model_sock, SSL_ENABLE_ALPN26, PR_TRUE1);
2225 if (rv != SECSuccess) {
2226 errExit("error enabling ALPN");
2227 }
2228
2229 rv = SSL_SetNextProtoNego(model_sock, alpnVal, sizeof(alpnVal));
2230 if (rv != SECSuccess) {
2231 errExit("error enabling ALPN");
2232 }
2233 }
2234
2235 if (enabledGroups) {
2236 rv = SSL_NamedGroupConfig(model_sock, enabledGroups, enabledGroupsCount);
2237 if (rv < 0) {
2238 errExit("SSL_NamedGroupConfig failed");
2239 }
2240 }
2241
2242 if (enabledSigSchemes) {
2243 rv = SSL_SignatureSchemePrefSet(model_sock, enabledSigSchemes, enabledSigSchemeCount);
2244 if (rv < 0) {
2245 errExit("SSL_SignatureSchemePrefSet failed");
2246 }
2247 }
2248
2249 /* This cipher is not on by default. The Acceptance test
2250 * would like it to be. Turn this cipher on.
2251 */
2252
2253 secStatus = SSL_CipherPrefSetDefault(TLS_RSA_WITH_NULL_MD50x0001, PR_TRUE1);
2254 if (secStatus != SECSuccess) {
2255 errExit("SSL_CipherPrefSetDefault:TLS_RSA_WITH_NULL_MD5");
2256 }
2257
2258 if (expectedHostNameVal || enabledExporters) {
2259 SSL_HandshakeCallback(model_sock, handshakeCallback,
2260 (void *)expectedHostNameVal);
2261 }
2262
2263 if (requestCert) {
2264 SSL_AuthCertificateHook(model_sock, mySSLAuthCertificate,
2265 (void *)CERT_GetDefaultCertDB());
2266 if (requestCert <= 2) {
2267 rv = SSL_OptionSet(model_sock, SSL_REQUEST_CERTIFICATE3, 1);
2268 if (rv < 0) {
2269 errExit("first SSL_OptionSet SSL_REQUEST_CERTIFICATE");
2270 }
2271 rv = SSL_OptionSet(model_sock, SSL_REQUIRE_CERTIFICATE10,
2272 (requestCert == 2));
2273 if (rv < 0) {
2274 errExit("first SSL_OptionSet SSL_REQUIRE_CERTIFICATE");
2275 }
2276 }
2277 }
2278
2279 if (psk.data) {
2280 rv = importPsk(model_sock);
2281 if (rv != SECSuccess) {
2282 errExit("importPsk failed");
2283 }
2284 }
2285
2286 if (echParamsStr) {
2287 rv = configureEch(model_sock);
2288 if (rv != SECSuccess) {
2289 errExit("configureEch failed");
2290 }
2291 }
2292
2293 if (MakeCertOK)
2294 SSL_BadCertHook(model_sock, myBadCertHandler, NULL((void*)0));
2295
2296 /* end of ssl configuration. */
2297
2298 /* Now, do the accepting, here in the main thread. */
2299 rv = do_accepts(listen_sock, model_sock);
Value stored to 'rv' is never read
2300
2301 terminateWorkerThreads();
2302
2303 if (useModelSocket && model_sock) {
2304 if (model_sock) {
2305 PR_Close(model_sock);
2306 }
2307 }
2308}
2309
2310SECStatus
2311readBigFile(const char *fileName)
2312{
2313 PRFileInfo info;
2314 PRStatus status;
2315 SECStatus rv = SECFailure;
2316 int count;
2317 int hdrLen;
2318 PRFileDesc *local_file_fd = NULL((void*)0);
2319
2320 status = PR_GetFileInfo(fileName, &info);
2321
2322 if (status == PR_SUCCESS &&
2323 info.type == PR_FILE_FILE &&
2324 info.size > 0 &&
2325 NULL((void*)0) != (local_file_fd = PR_Open(fileName, PR_RDONLY0x01, 0))) {
2326
2327 hdrLen = PORT_Strlen(outHeader)strlen(outHeader);
2328 bigBuf.len = hdrLen + info.size;
2329 bigBuf.data = PORT_MallocPR_Malloc(bigBuf.len + 4095);
2330 if (!bigBuf.data) {
2331 errWarn("PORT_Malloc");
2332 goto done;
2333 }
2334
2335 PORT_Memcpymemcpy(bigBuf.data, outHeader, hdrLen);
2336
2337 count = PR_Read(local_file_fd, bigBuf.data + hdrLen, info.size);
2338 if (count != info.size) {
2339 errWarn("PR_Read local file");
2340 goto done;
2341 }
2342 rv = SECSuccess;
2343 done:
2344 if (local_file_fd) {
2345 PR_Close(local_file_fd);
2346 }
2347 }
2348 return rv;
2349}
2350
2351int numChildren;
2352PRProcess *child[MAX_PROCS25];
2353
2354PRProcess *
2355haveAChild(int argc, char **argv, PRProcessAttr *attr)
2356{
2357 PRProcess *newProcess;
2358
2359 newProcess = PR_CreateProcess(argv[0], argv, NULL((void*)0), attr);
2360 if (!newProcess) {
2361 errWarn("Can't create new process.");
2362 } else {
2363 child[numChildren++] = newProcess;
2364 }
2365 return newProcess;
2366}
2367
2368#ifdef XP_UNIX1
2369void
2370sigusr1_parent_handler(int sig)
2371{
2372 PRProcess *process;
2373 int i;
2374 fprintf(stderrstderr, "SIG_USER: Parent got sig_user, killing children (%d).\n", numChildren);
2375 for (i = 0; i < numChildren; i++) {
2376 process = child[i];
2377 PR_KillProcess(process); /* it would be nice to kill with a sigusr signal */
2378 }
2379}
2380#endif
2381
2382void
2383beAGoodParent(int argc, char **argv, int maxProcs, PRFileDesc *listen_sock)
2384{
2385 PRProcess *newProcess;
2386 PRProcessAttr *attr;
2387 int i;
2388 PRInt32 exitCode;
2389 PRStatus rv;
2390
2391#ifdef XP_UNIX1
2392 struct sigaction act;
2393
2394 /* set up the signal handler */
2395 act.sa_handler__sigaction_handler.sa_handler = sigusr1_parent_handler;
2396 sigemptyset(&act.sa_mask);
2397 act.sa_flags = 0;
2398 if (sigaction(SIGUSR110, &act, NULL((void*)0))) {
2399 fprintf(stderrstderr, "Error installing signal handler.\n");
2400 exit(1);
2401 }
2402#endif
2403
2404 rv = PR_SetFDInheritable(listen_sock, PR_TRUE1);
2405 if (rv != PR_SUCCESS)
2406 errExit("PR_SetFDInheritable");
2407
2408 attr = PR_NewProcessAttr();
2409 if (!attr)
2410 errExit("PR_NewProcessAttr");
2411
2412 rv = PR_ProcessAttrSetInheritableFD(attr, listen_sock, inheritableSockName);
2413 if (rv != PR_SUCCESS)
2414 errExit("PR_ProcessAttrSetInheritableFD");
2415
2416 for (i = 0; i < maxProcs; ++i) {
2417 newProcess = haveAChild(argc, argv, attr);
2418 if (!newProcess)
2419 break;
2420 }
2421
2422 rv = PR_SetFDInheritable(listen_sock, PR_FALSE0);
2423 if (rv != PR_SUCCESS)
2424 errExit("PR_SetFDInheritable");
2425
2426 while (numChildren > 0) {
2427 newProcess = child[numChildren - 1];
2428 PR_WaitProcess(newProcess, &exitCode);
2429 fprintf(stderrstderr, "Child %d exited with exit code %x\n",
2430 numChildren, exitCode);
2431 numChildren--;
2432 }
2433 exit(0);
2434}
2435
2436#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); }
\
2437 if (((c) >= '0') && ((c) <= '9')) { \
2438 i = (c) - '0'; \
2439 } else if (((c) >= 'a') && ((c) <= 'f')) { \
2440 i = (c) - 'a' + 10; \
2441 } else if (((c) >= 'A') && ((c) <= 'F')) { \
2442 i = (c) - 'A' + 10; \
2443 } else if ((c) == '\0') { \
2444 fprintf(stderrstderr, "Invalid length of cipher string (-c :WXYZ).\n"); \
2445 exit(9); \
2446 } else { \
2447 fprintf(stderrstderr, "Non-hex char in cipher string (-c :WXYZ).\n"); \
2448 exit(9); \
2449 }
2450
2451SECStatus
2452enableOCSPStapling(const char *mode)
2453{
2454 if (!strcmp(mode, "good")) {
2455 ocspStaplingMode = osm_good;
2456 return SECSuccess;
2457 }
2458 if (!strcmp(mode, "unknown")) {
2459 ocspStaplingMode = osm_unknown;
2460 return SECSuccess;
2461 }
2462 if (!strcmp(mode, "revoked")) {
2463 ocspStaplingMode = osm_revoked;
2464 return SECSuccess;
2465 }
2466 if (!strcmp(mode, "badsig")) {
2467 ocspStaplingMode = osm_badsig;
2468 return SECSuccess;
2469 }
2470 if (!strcmp(mode, "corrupted")) {
2471 ocspStaplingMode = osm_corrupted;
2472 return SECSuccess;
2473 }
2474 if (!strcmp(mode, "failure")) {
2475 ocspStaplingMode = osm_failure;
2476 return SECSuccess;
2477 }
2478 if (!strcmp(mode, "random")) {
2479 ocspStaplingMode = osm_random;
2480 return SECSuccess;
2481 }
2482 if (!strcmp(mode, "ocsp")) {
2483 ocspStaplingMode = osm_ocsp;
2484 return SECSuccess;
2485 }
2486 return SECFailure;
2487}
2488
2489int
2490main(int argc, char **argv)
2491{
2492 char *progName = NULL((void*)0);
2493 const char *fileName = NULL((void*)0);
2494 char *cipherString = NULL((void*)0);
2495 const char *dir = ".";
2496 char *passwd = NULL((void*)0);
2497 char *pwfile = NULL((void*)0);
2498 const char *pidFile = NULL((void*)0);
2499 char *tmp;
2500 char *envString;
2501 PRFileDesc *listen_sock;
2502 CERTCertificate *cert[MAX_CERT_NICKNAME_ARRAY_INDEX10] = { NULL((void*)0) };
2503 SECKEYPrivateKey *privKey[MAX_CERT_NICKNAME_ARRAY_INDEX10] = { NULL((void*)0) };
2504 int optionsFound = 0;
2505 int maxProcs = 1;
2506 unsigned short port = 0;
2507 SECStatus rv = SECSuccess;
2508 PRStatus prStatus;
2509 PRBool bindOnly = PR_FALSE0;
2510 PRBool useLocalThreads = PR_FALSE0;
2511 PLOptState *optstate;
2512 PLOptStatus status;
2513 PRThread *loggerThread = NULL((void*)0);
2514 PRBool debugCache = PR_FALSE0; /* bug 90518 */
2515 char emptyString[] = { "" };
2516 char *certPrefix = emptyString;
2517 SSL3Statistics *ssl3stats;
2518 PRUint32 i;
2519 secuPWData pwdata = { PW_NONE, 0 };
2520 char *expectedHostNameVal = NULL((void*)0);
2521 PLArenaPool *certStatusArena = NULL((void*)0);
2522
2523 tmp = strrchr(argv[0], '/');
2524 tmp = tmp ? tmp + 1 : argv[0];
2525 progName = strrchr(tmp, '\\');
2526 progName = progName ? progName + 1 : tmp;
2527
2528 PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
2529 SSL_VersionRangeGetSupported(ssl_variant_stream, &enabledVersions);
2530
2531 /* please keep this list of options in ASCII collating sequence.
2532 ** numbers, then capital letters, then lower case, alphabetical.
2533 ** XXX: 'B', and 'q' were used in the past but removed
2534 ** in 3.28, please leave some time before resuing those. */
2535 optstate = PL_CreateOptState(argc, argv,
2536 "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:");
2537 while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
2538 ++optionsFound;
2539 switch (optstate->option) {
2540 case '2':
2541 fileName = optstate->value;
2542 break;
2543
2544 case 'A':
2545 ocspStaplingCA = PORT_StrdupPORT_Strdup_Util(optstate->value);
2546 break;
2547
2548 case 'C':
2549 if (optstate->value)
2550 NumSidCacheEntries = PORT_Atoi(optstate->value)(int)strtol(optstate->value, ((void*)0), 10);
2551 break;
2552
2553 case 'D':
2554 noDelay = PR_TRUE1;
2555 break;
2556
2557 case 'E':
2558 enablePostHandshakeAuth = PR_TRUE1;
2559 break;
2560
2561 case 'H':
2562 configureDHE = (PORT_Atoi(optstate->value)(int)strtol(optstate->value, ((void*)0), 10) != 0);
2563 break;
2564
2565 case 'G':
2566 enableExtendedMasterSecret = PR_TRUE1;
2567 break;
2568
2569 case 'L':
2570 logStats = PR_TRUE1;
2571 if (optstate->value == NULL((void*)0)) {
2572 logPeriod = 30;
2573 } else {
2574 logPeriod = PORT_Atoi(optstate->value)(int)strtol(optstate->value, ((void*)0), 10);
2575 if (logPeriod <= 0)
2576 logPeriod = 30;
2577 }
2578 break;
2579
2580 case 'M':
2581 maxProcs = PORT_Atoi(optstate->value)(int)strtol(optstate->value, ((void*)0), 10);
2582 if (maxProcs < 1)
2583 maxProcs = 1;
2584 if (maxProcs > MAX_PROCS25)
2585 maxProcs = MAX_PROCS25;
2586 break;
2587
2588 case 'N':
2589 NoReuse = PR_TRUE1;
2590 break;
2591
2592 case 'R':
2593 disableRollBack = PR_TRUE1;
2594 break;
2595
2596 case 'S':
2597 if (certNicknameIndex >= MAX_CERT_NICKNAME_ARRAY_INDEX10) {
2598 Usage(progName);
2599 break;
2600 }
2601 certNicknameArray[certNicknameIndex++] = PORT_StrdupPORT_Strdup_Util(optstate->value);
2602 break;
2603
2604 case 'T':
2605 if (enableOCSPStapling(optstate->value) != SECSuccess) {
2606 fprintf(stderrstderr, "Invalid OCSP stapling mode.\n");
2607 fprintf(stderrstderr, "Run '%s -h' for usage information.\n", progName);
2608 exit(53);
2609 }
2610 break;
2611
2612 case 'U':
2613 configureReuseECDHE = (PORT_Atoi(optstate->value)(int)strtol(optstate->value, ((void*)0), 10) != 0);
2614 break;
2615
2616 case 'V':
2617 if (SECU_ParseSSLVersionRangeString(optstate->value,
2618 enabledVersions, &enabledVersions) !=
2619 SECSuccess) {
2620 fprintf(stderrstderr, "Bad version specified.\n");
2621 Usage(progName);
2622 exit(1);
2623 }
2624 break;
2625
2626 case 'W':
2627 configureWeakDHE = (PORT_Atoi(optstate->value)(int)strtol(optstate->value, ((void*)0), 10) != 0);
2628 break;
2629
2630 case 'Y':
2631 PrintCipherUsage(progName);
2632 exit(0);
2633 break;
2634
2635 case 'a':
2636 if (virtServerNameIndex >= MAX_VIRT_SERVER_NAME_ARRAY_INDEX10) {
2637 Usage(progName);
2638 break;
2639 }
2640 virtServerNameArray[virtServerNameIndex++] =
2641 PORT_StrdupPORT_Strdup_Util(optstate->value);
2642 break;
2643
2644 case 'b':
2645 bindOnly = PR_TRUE1;
2646 break;
2647
2648 case 'c':
2649 cipherString = PORT_StrdupPORT_Strdup_Util(optstate->value);
2650 break;
2651
2652 case 'd':
2653 dir = optstate->value;
2654 break;
2655
2656 case 'e':
2657 if (certNicknameIndex >= MAX_CERT_NICKNAME_ARRAY_INDEX10) {
2658 Usage(progName);
2659 break;
2660 }
2661 certNicknameArray[certNicknameIndex++] = PORT_StrdupPORT_Strdup_Util(optstate->value);
2662 break;
2663
2664 case 'f':
2665 pwdata.source = PW_FROMFILE;
2666 pwdata.data = pwfile = PORT_StrdupPORT_Strdup_Util(optstate->value);
2667 break;
2668
2669 case 'g':
2670 testBulk = PR_TRUE1;
2671 testBulkTotal = PORT_Atoi(optstate->value)(int)strtol(optstate->value, ((void*)0), 10);
2672 break;
2673
2674 case 'h':
2675 Usage(progName);
2676 exit(0);
2677 break;
2678
2679 case 'i':
2680 pidFile = optstate->value;
2681 break;
2682
2683 case 'j':
2684 initLoggingLayer();
2685 loggingLayer = PR_TRUE1;
2686 break;
2687
2688 case 'k':
2689 expectedHostNameVal = PORT_StrdupPORT_Strdup_Util(optstate->value);
2690 break;
2691
2692 case 'l':
2693 useLocalThreads = PR_TRUE1;
2694 break;
2695
2696 case 'm':
2697 useModelSocket = PR_TRUE1;
2698 break;
2699
2700 case 'n':
2701 if (certNicknameIndex >= MAX_CERT_NICKNAME_ARRAY_INDEX10) {
2702 Usage(progName);
2703 break;
2704 }
2705 certNicknameArray[certNicknameIndex++] = PORT_StrdupPORT_Strdup_Util(optstate->value);
2706 virtServerNameArray[0] = PORT_StrdupPORT_Strdup_Util(optstate->value);
2707 break;
2708
2709 case 'P':
2710 certPrefix = PORT_StrdupPORT_Strdup_Util(optstate->value);
2711 break;
2712
2713 case 'o':
2714 MakeCertOK = 1;
2715 break;
2716
2717 case 'p':
2718 port = PORT_Atoi(optstate->value)(int)strtol(optstate->value, ((void*)0), 10);
2719 break;
2720
2721 case 'r':
2722 ++requestCert;
2723 break;
2724
2725 case 's':
2726 disableLocking = PR_TRUE1;
2727 break;
2728
2729 case 't':
2730 maxThreads = PORT_Atoi(optstate->value)(int)strtol(optstate->value, ((void*)0), 10);
2731 if (maxThreads > MAX_THREADS4096)
2732 maxThreads = MAX_THREADS4096;
2733 if (maxThreads < MIN_THREADS3)
2734 maxThreads = MIN_THREADS3;
2735 break;
2736
2737 case 'u':
2738 enableSessionTickets = PR_TRUE1;
2739 break;
2740
2741 case 'v':
2742 verbose++;
2743 break;
2744
2745 case 'w':
2746 pwdata.source = PW_PLAINTEXT;
2747 pwdata.data = passwd = PORT_StrdupPORT_Strdup_Util(optstate->value);
2748 break;
2749
2750 case 'y':
2751 debugCache = PR_TRUE1;
2752 break;
2753
2754 case 'Z':
2755 zeroRTT = PR_TRUE1;
2756 break;
2757
2758 case 'z':
2759 rv = readPSK(optstate->value, &psk, &pskLabel);
2760 if (rv != SECSuccess) {
2761 PL_DestroyOptState(optstate);
2762 fprintf(stderrstderr, "Bad PSK specified.\n");
2763 Usage(progName);
2764 exit(1);
2765 }
2766 break;
2767
2768 case 'Q':
2769 enableALPN = PR_TRUE1;
2770 break;
2771
2772 case 'I':
2773 rv = parseGroupList(optstate->value, &enabledGroups, &enabledGroupsCount);
2774 if (rv != SECSuccess) {
2775 PL_DestroyOptState(optstate);
2776 fprintf(stderrstderr, "Bad group specified.\n");
2777 fprintf(stderrstderr, "Run '%s -h' for usage information.\n", progName);
2778 exit(5);
2779 }
2780 break;
2781
2782 case 'J':
2783 rv = parseSigSchemeList(optstate->value, &enabledSigSchemes, &enabledSigSchemeCount);
2784 if (rv != SECSuccess) {
2785 PL_DestroyOptState(optstate);
2786 fprintf(stderrstderr, "Bad signature scheme specified.\n");
2787 fprintf(stderrstderr, "Run '%s -h' for usage information.\n", progName);
2788 exit(5);
2789 }
2790 break;
2791
2792 case 'x':
2793 rv = parseExporters(optstate->value,
2794 &enabledExporters, &enabledExporterCount);
2795 if (rv != SECSuccess) {
2796 PL_DestroyOptState(optstate);
2797 fprintf(stderrstderr, "Bad exporter specified.\n");
2798 fprintf(stderrstderr, "Run '%s -h' for usage information.\n", progName);
2799 exit(5);
2800 }
2801 break;
2802
2803 case 'X':
2804 echParamsStr = PORT_StrdupPORT_Strdup_Util(optstate->value);
2805 if (echParamsStr == NULL((void*)0)) {
2806 PL_DestroyOptState(optstate);
2807 fprintf(stderrstderr, "echParamsStr copy failed.\n");
2808 exit(5);
2809 }
2810 break;
2811 default:
2812 case '?':
2813 fprintf(stderrstderr, "Unrecognized or bad option specified: %c\n", optstate->option);
2814 fprintf(stderrstderr, "Run '%s -h' for usage information.\n", progName);
2815 exit(4);
2816 break;
2817 }
2818 }
2819 PL_DestroyOptState(optstate);
2820 if (status == PL_OPT_BAD) {
2821 fprintf(stderrstderr, "Unrecognized or bad option specified.\n");
2822 fprintf(stderrstderr, "Run '%s -h' for usage information.\n", progName);
2823 exit(5);
2824 }
2825 if (!optionsFound) {
2826 Usage(progName);
2827 exit(51);
2828 }
2829 switch (ocspStaplingMode) {
2830 case osm_good:
2831 case osm_revoked:
2832 case osm_unknown:
2833 case osm_random:
2834 if (!ocspStaplingCA) {
2835 fprintf(stderrstderr, "Selected stapling response requires the -A parameter.\n");
2836 fprintf(stderrstderr, "Run '%s -h' for usage information.\n", progName);
2837 exit(52);
2838 }
2839 break;
2840 default:
2841 break;
2842 }
2843
2844 /* The -b (bindOnly) option is only used by the ssl.sh test
2845 * script on Linux to determine whether a previous selfserv
2846 * process has fully died and freed the port. (Bug 129701)
2847 */
2848 if (bindOnly) {
2849 listen_sock = getBoundListenSocket(port);
2850 if (!listen_sock) {
2851 exit(1);
2852 }
2853 if (listen_sock) {
2854 PR_Close(listen_sock);
2855 }
2856 exit(0);
2857 }
2858
2859 if (certNicknameIndex == 0) {
2860 fprintf(stderrstderr, "Must specify at least one certificate nickname using '-n' (RSA), '-S' (DSA), or 'e' (EC).\n");
2861 fprintf(stderrstderr, "Run '%s -h' for usage information.\n", progName);
2862 exit(6);
2863 }
2864
2865 if (port == 0) {
2866 fprintf(stderrstderr, "Required argument 'port' must be non-zero value\n");
2867 exit(7);
2868 }
2869
2870 if (NoReuse && maxProcs > 1) {
2871 fprintf(stderrstderr, "-M and -N options are mutually exclusive.\n");
2872 exit(14);
2873 }
2874
2875 envString = PR_GetEnvSecure(envVarName);
2876 if (!envString && pidFile) {
2877 FILE *tmpfile = fopen(pidFile, "w+");
2878
2879 if (tmpfile) {
2880 fprintf(tmpfile, "%d", getpid());
2881 fclose(tmpfile);
2882 }
2883 }
2884
2885 /* allocate and initialize app data for bulk encryption testing */
2886 if (testBulk) {
2887 testBulkBuf = PORT_MallocPR_Malloc(testBulkSize);
2888 if (testBulkBuf == NULL((void*)0))
2889 errExit("Out of memory: testBulkBuf");
2890 for (i = 0; i < testBulkSize; i++)
2891 testBulkBuf[i] = i;
2892 }
2893
2894 envString = PR_GetEnvSecure(envVarName);
2895 tmp = PR_GetEnvSecure("TMP");
2896 if (!tmp)
2897 tmp = PR_GetEnvSecure("TMPDIR");
2898 if (!tmp)
2899 tmp = PR_GetEnvSecure("TEMP");
2900
2901 if (envString) {
2902 /* we're one of the children in a multi-process server. */
2903 listen_sock = PR_GetInheritedFD(inheritableSockName);
2904 if (!listen_sock)
2905 errExit("PR_GetInheritedFD");
2906#ifndef WINNT
2907 /* we can't do this on NT because it breaks NSPR and
2908 PR_Accept will fail on the socket in the child process if
2909 the socket state is change to non inheritable
2910 It is however a security issue to leave it accessible,
2911 but it is OK for a test server such as selfserv.
2912 NSPR should fix it eventually . see bugzilla 101617
2913 and 102077
2914 */
2915 prStatus = PR_SetFDInheritable(listen_sock, PR_FALSE0);
2916 if (prStatus != PR_SUCCESS)
2917 errExit("PR_SetFDInheritable");
2918#endif
2919 rv = SSL_InheritMPServerSIDCache(envString);
2920 if (rv != SECSuccess)
2921 errExit("SSL_InheritMPServerSIDCache");
2922 hasSidCache = PR_TRUE1;
2923 /* Call the NSS initialization routines */
2924 rv = NSS_Initialize(dir, certPrefix, certPrefix, SECMOD_DB"secmod.db", NSS_INIT_READONLY0x1);
2925 if (rv != SECSuccess) {
2926 fputs("NSS_Init failed.\n", stderrstderr);
2927 exit(8);
2928 }
2929 } else if (maxProcs > 1) {
2930 /* we're going to be the parent in a multi-process server. */
2931 listen_sock = getBoundListenSocket(port);
2932 rv = SSL_ConfigMPServerSIDCache(NumSidCacheEntries, 0, 0, tmp);
2933 if (rv != SECSuccess)
2934 errExit("SSL_ConfigMPServerSIDCache");
2935 hasSidCache = PR_TRUE1;
2936 beAGoodParent(argc, argv, maxProcs, listen_sock);
2937 exit(99); /* should never get here */
2938 } else {
2939 /* Call the NSS initialization routines */
2940 rv = NSS_Initialize(dir, certPrefix, certPrefix, SECMOD_DB"secmod.db", NSS_INIT_READONLY0x1);
2941 if (rv != SECSuccess) {
2942 fputs("NSS_Init failed.\n", stderrstderr);
2943 exit(8);
2944 }
2945 /* we're an ordinary single process server. */
2946 listen_sock = getBoundListenSocket(port);
2947 prStatus = PR_SetFDInheritable(listen_sock, PR_FALSE0);
2948 if (prStatus != PR_SUCCESS)
2949 errExit("PR_SetFDInheritable");
2950 if (!NoReuse) {
2951 rv = SSL_ConfigServerSessionIDCache(NumSidCacheEntries,
2952 0, 0, tmp);
2953 if (rv != SECSuccess)
2954 errExit("SSL_ConfigServerSessionIDCache");
2955 hasSidCache = PR_TRUE1;
2956 }
2957 }
2958
2959 lm = PR_NewLogModule("TestCase");
2960
2961 if (fileName)
2962 readBigFile(fileName);
2963
2964 /* set our password function */
2965 PK11_SetPasswordFunc(SECU_GetModulePassword);
2966
2967 /* all SSL3 cipher suites are enabled by default. */
2968 if (cipherString) {
2969 char *cstringSaved = cipherString;
2970 int ndx;
2971
2972 /* disable all the ciphers, then enable the ones we want. */
2973 disableAllSSLCiphers();
2974
2975 while (0 != (ndx = *cipherString++)) {
2976 int cipher = 0;
2977
2978 if (ndx == ':') {
2979 int ctmp;
2980
2981 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); }
2982 cipher |= (ctmp << 12);
2983 cipherString++;
2984 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); }
2985 cipher |= (ctmp << 8);
2986 cipherString++;
2987 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); }
2988 cipher |= (ctmp << 4);
2989 cipherString++;
2990 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); }
2991 cipher |= ctmp;
2992 cipherString++;
2993 } else {
2994 if (!isalpha((unsigned char)ndx)((*__ctype_b_loc ())[(int) (((unsigned char)ndx))] & (unsigned
short int) _ISalpha)
) {
2995 fprintf(stderrstderr,
2996 "Non-alphabetic char in cipher string (-c arg).\n");
2997 exit(9);
2998 }
2999 ndx = tolower((unsigned char)ndx) - 'a';
3000 if (ndx < PR_ARRAY_SIZE(ssl3CipherSuites)(sizeof(ssl3CipherSuites)/sizeof((ssl3CipherSuites)[0]))) {
3001 cipher = ssl3CipherSuites[ndx];
3002 }
3003 }
3004 if (cipher > 0) {
3005 rv = SSL_CipherPrefSetDefault(cipher, SSL_ALLOWED1);
3006 if (rv != SECSuccess) {
3007 SECU_PrintError(progName, "SSL_CipherPrefSetDefault()");
3008 exit(9);
3009 }
3010 } else {
3011 fprintf(stderrstderr,
3012 "Invalid cipher specification (-c arg).\n");
3013 exit(9);
3014 }
3015 }
3016 PORT_FreePORT_Free_Util(cstringSaved);
3017 }
3018
3019 certStatusArena = PORT_NewArenaPORT_NewArena_Util(DER_DEFAULT_CHUNKSIZE(2048));
3020 if (!certStatusArena)
3021 errExit("cannot allocate certStatusArena");
3022
3023 for (i = 0; i < certNicknameIndex; i++) {
3024 cert[i] = PK11_FindCertFromNickname(certNicknameArray[i], &pwdata);
3025 if (cert[i] == NULL((void*)0)) {
3026 fprintf(stderrstderr, "selfserv: Can't find certificate %s\n", certNicknameArray[i]);
3027 exit(10);
3028 }
3029 privKey[i] = PK11_FindKeyByAnyCert(cert[i], &pwdata);
3030 if (privKey[i] == NULL((void*)0)) {
3031 fprintf(stderrstderr, "selfserv: Can't find Private Key for cert %s\n",
3032 certNicknameArray[i]);
3033 exit(11);
3034 }
3035 if (privKey[i]->keyType != ecKey)
3036 setupCertStatus(certStatusArena, cert[i], i, &pwdata);
3037 }
3038
3039 if (configureWeakDHE > 0) {
3040 fprintf(stderrstderr, "selfserv: Creating dynamic weak DH parameters\n");
3041 rv = SSL_EnableWeakDHEPrimeGroup(NULL((void*)0), PR_TRUE1);
3042 if (rv != SECSuccess) {
3043 goto cleanup;
3044 }
3045 fprintf(stderrstderr, "selfserv: Done creating dynamic weak DH parameters\n");
3046 }
3047 if (zeroRTT) {
3048 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
)
;
3049 if (rv != SECSuccess) {
3050 errExit("Unable to create anti-replay context for 0-RTT.");
3051 }
3052 }
3053
3054 /* allocate the array of thread slots, and launch the worker threads. */
3055 rv = launch_threads(&jobLoop, 0, 0, useLocalThreads);
3056
3057 if (rv == SECSuccess && logStats) {
3058 loggerThread = PR_CreateThread(PR_SYSTEM_THREAD,
3059 logger, NULL((void*)0), PR_PRIORITY_NORMAL,
3060 useLocalThreads ? PR_LOCAL_THREAD
3061 : PR_GLOBAL_THREAD,
3062 PR_JOINABLE_THREAD, 0);
3063 if (loggerThread == NULL((void*)0)) {
3064 fprintf(stderrstderr, "selfserv: Failed to launch logger thread!\n");
3065 rv = SECFailure;
3066 }
3067 }
3068
3069 if (rv == SECSuccess) {
3070 server_main(listen_sock, privKey, cert,
3071 expectedHostNameVal);
3072 }
3073
3074 VLOG(("selfserv: server_thread: exiting"))do { if (((lm)->level >= (PR_LOG_DEBUG))) { PR_LogPrint
("selfserv: server_thread: exiting"); } } while (0)
;
3075
3076cleanup:
3077 printSSLStatistics();
3078 ssl3stats = SSL_GetStatistics();
3079 if (ssl3stats->hch_sid_ticket_parse_failures != 0) {
3080 fprintf(stderrstderr, "selfserv: Experienced ticket parse failure(s)\n");
3081 exit(1);
3082 }
3083 if (failedToNegotiateName) {
3084 fprintf(stderrstderr, "selfserv: Failed properly negotiate server name\n");
3085 exit(1);
3086 }
3087
3088 {
3089 for (i = 0; i < certNicknameIndex; i++) {
3090 if (cert[i]) {
3091 CERT_DestroyCertificate(cert[i]);
3092 }
3093 if (privKey[i]) {
3094 SECKEY_DestroyPrivateKey(privKey[i]);
3095 }
3096 PORT_FreePORT_Free_Util(certNicknameArray[i]);
3097 }
3098 for (i = 0; virtServerNameArray[i]; i++) {
3099 PORT_FreePORT_Free_Util(virtServerNameArray[i]);
3100 }
3101 }
3102
3103 if (debugCache) {
3104 nss_DumpCertificateCacheInfo();
3105 }
3106 if (expectedHostNameVal) {
3107 PORT_FreePORT_Free_Util(expectedHostNameVal);
3108 }
3109 if (passwd) {
3110 PORT_FreePORT_Free_Util(passwd);
3111 }
3112 if (pwfile) {
3113 PORT_FreePORT_Free_Util(pwfile);
3114 }
3115 if (certPrefix && certPrefix != emptyString) {
3116 PORT_FreePORT_Free_Util(certPrefix);
3117 }
3118
3119 if (hasSidCache) {
3120 SSL_ShutdownServerSessionIDCache();
3121 }
3122 if (certStatusArena) {
3123 PORT_FreeArenaPORT_FreeArena_Util(certStatusArena, PR_FALSE0);
3124 }
3125 if (enabledGroups) {
3126 PORT_FreePORT_Free_Util(enabledGroups);
3127 }
3128 if (antiReplay) {
3129 SSL_ReleaseAntiReplayContext(antiReplay)(SSL_GetExperimentalAPI("SSL_ReleaseAntiReplayContext") ? ((SECStatus
(*) (SSLAntiReplayContext * _ctx))SSL_GetExperimentalAPI("SSL_ReleaseAntiReplayContext"
))(antiReplay) : SECFailure)
;
3130 }
3131 SECITEM_ZfreeItemSECITEM_ZfreeItem_Util(&psk, PR_FALSE0);
3132 SECITEM_ZfreeItemSECITEM_ZfreeItem_Util(&pskLabel, PR_FALSE0);
3133 PORT_FreePORT_Free_Util(echParamsStr);
3134 if (NSS_Shutdown() != SECSuccess) {
3135 SECU_PrintError(progName, "NSS_Shutdown");
3136 if (loggerThread) {
3137 PR_JoinThread(loggerThread);
3138 }
3139 PR_Cleanup();
3140 exit(1);
3141 }
3142 PR_Cleanup();
3143 printf("selfserv: normal termination\n");
3144 return 0;
3145}