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