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