Wed, 31 Dec 2014 07:16:47 +0100
Revert simplistic fix pending revisit of Mozilla integration attempt.
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/. */
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>
14 #include "secutil.h"
16 #if defined(XP_UNIX)
17 #include <unistd.h>
18 #endif
20 #if defined(_WINDOWS)
21 #include <process.h> /* for getpid() */
22 #endif
24 #include <signal.h>
25 #include <stdlib.h>
26 #include <errno.h>
27 #include <fcntl.h>
28 #include <stdarg.h>
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 "cert.h"
42 #include "certt.h"
43 #include "ocsp.h"
45 #ifndef PORT_Sprintf
46 #define PORT_Sprintf sprintf
47 #endif
49 #ifndef PORT_Strstr
50 #define PORT_Strstr strstr
51 #endif
53 #ifndef PORT_Malloc
54 #define PORT_Malloc PR_Malloc
55 #endif
57 int NumSidCacheEntries = 1024;
59 static int handle_connection( PRFileDesc *, PRFileDesc *, int );
61 static const char envVarName[] = { SSL_ENV_VAR_NAME };
62 static const char inheritableSockName[] = { "SELFSERV_LISTEN_SOCKET" };
64 #define DEFAULT_BULK_TEST 16384
65 #define MAX_BULK_TEST 1048576 /* 1 MB */
66 static PRBool testBulk;
67 static PRUint32 testBulkSize = DEFAULT_BULK_TEST;
68 static PRUint32 testBulkTotal;
69 static char* testBulkBuf;
70 static PRDescIdentity log_layer_id = PR_INVALID_IO_LAYER;
71 static PRFileDesc *loggingFD;
72 static PRIOMethods loggingMethods;
74 static PRBool logStats;
75 static PRBool loggingLayer;
76 static int logPeriod = 30;
77 static PRUint32 loggerOps;
78 static PRUint32 loggerBytes;
79 static PRUint32 loggerBytesTCP;
80 static PRUint32 bulkSentChunks;
81 static enum ocspStaplingModeEnum {
82 osm_disabled, /* server doesn't support stapling */
83 osm_good, /* supply a signed good status */
84 osm_revoked, /* supply a signed revoked status */
85 osm_unknown, /* supply a signed unknown status */
86 osm_failure, /* supply a unsigned failure status, "try later" */
87 osm_badsig, /* supply a good status response with a bad signature */
88 osm_corrupted, /* supply a corrupted data block as the status */
89 osm_random, /* use a random response for each connection */
90 osm_ocsp /* retrieve ocsp status from external ocsp server,
91 use empty status if server is unavailable */
92 } ocspStaplingMode = osm_disabled;
93 typedef enum ocspStaplingModeEnum ocspStaplingModeType;
94 static char *ocspStaplingCA = NULL;
95 static SECItemArray *certStatus[kt_kea_size] = { NULL };
97 const int ssl2CipherSuites[] = {
98 SSL_EN_RC4_128_WITH_MD5, /* A */
99 SSL_EN_RC4_128_EXPORT40_WITH_MD5, /* B */
100 SSL_EN_RC2_128_CBC_WITH_MD5, /* C */
101 SSL_EN_RC2_128_CBC_EXPORT40_WITH_MD5, /* D */
102 SSL_EN_DES_64_CBC_WITH_MD5, /* E */
103 SSL_EN_DES_192_EDE3_CBC_WITH_MD5, /* F */
104 0
105 };
107 const int ssl3CipherSuites[] = {
108 -1, /* SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA* a */
109 -1, /* SSL_FORTEZZA_DMS_WITH_RC4_128_SHA * b */
110 TLS_RSA_WITH_RC4_128_MD5, /* c */
111 TLS_RSA_WITH_3DES_EDE_CBC_SHA, /* d */
112 TLS_RSA_WITH_DES_CBC_SHA, /* e */
113 TLS_RSA_EXPORT_WITH_RC4_40_MD5, /* f */
114 TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5, /* g */
115 -1, /* SSL_FORTEZZA_DMS_WITH_NULL_SHA, * h */
116 TLS_RSA_WITH_NULL_MD5, /* i */
117 SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA, /* j */
118 SSL_RSA_FIPS_WITH_DES_CBC_SHA, /* k */
119 TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA, /* l */
120 TLS_RSA_EXPORT1024_WITH_RC4_56_SHA, /* m */
121 TLS_RSA_WITH_RC4_128_SHA, /* n */
122 -1, /* TLS_DHE_DSS_WITH_RC4_128_SHA, * o */
123 -1, /* TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, * p */
124 -1, /* TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA, * q */
125 -1, /* TLS_DHE_RSA_WITH_DES_CBC_SHA, * r */
126 -1, /* TLS_DHE_DSS_WITH_DES_CBC_SHA, * s */
127 -1, /* TLS_DHE_DSS_WITH_AES_128_CBC_SHA, * t */
128 -1, /* TLS_DHE_RSA_WITH_AES_128_CBC_SHA, * u */
129 TLS_RSA_WITH_AES_128_CBC_SHA, /* v */
130 -1, /* TLS_DHE_DSS_WITH_AES_256_CBC_SHA, * w */
131 -1, /* TLS_DHE_RSA_WITH_AES_256_CBC_SHA, * x */
132 TLS_RSA_WITH_AES_256_CBC_SHA, /* y */
133 TLS_RSA_WITH_NULL_SHA, /* z */
134 0
135 };
137 /* data and structures for shutdown */
138 static int stopping;
140 static PRBool noDelay;
141 static int requestCert;
142 static int verbose;
143 static SECItem bigBuf;
145 static PRThread * acceptorThread;
147 static PRLogModuleInfo *lm;
149 #define PRINTF if (verbose) printf
150 #define FPRINTF if (verbose) fprintf
151 #define FLUSH if (verbose) { fflush(stdout); fflush(stderr); }
152 #define VLOG(arg) PR_LOG(lm,PR_LOG_DEBUG,arg)
154 static void
155 PrintUsageHeader(const char *progName)
156 {
157 fprintf(stderr,
158 "Usage: %s -n rsa_nickname -p port [-BDENRbjlmrsuvx] [-w password]\n"
159 " [-t threads] [-i pid_file] [-c ciphers] [-Y] [-d dbdir] [-g numblocks]\n"
160 " [-f password_file] [-L [seconds]] [-M maxProcs] [-P dbprefix]\n"
161 " [-V [min-version]:[max-version]] [-a sni_name]\n"
162 " [ T <good|revoked|unknown|badsig|corrupted|none|ocsp>] [-A ca]\n"
163 #ifndef NSS_DISABLE_ECC
164 " [-C SSLCacheEntries] [-e ec_nickname]\n"
165 #else
166 " [-C SSLCacheEntries]\n"
167 #endif /* NSS_DISABLE_ECC */
168 ,progName);
169 }
171 static void
172 PrintParameterUsage()
173 {
174 fputs(
175 "-V [min]:[max] restricts the set of enabled SSL/TLS protocol versions.\n"
176 " All versions are enabled by default.\n"
177 " Possible values for min/max: ssl2 ssl3 tls1.0 tls1.1 tls1.2\n"
178 " Example: \"-V ssl3:\" enables SSL 3 and newer.\n"
179 "-B bypasses the PKCS11 layer for SSL encryption and MACing\n"
180 "-q checks for bypassability\n"
181 "-D means disable Nagle delays in TCP\n"
182 "-E means disable export ciphersuites and SSL step down key gen\n"
183 "-R means disable detection of rollback from TLS to SSL3\n"
184 "-a configure server for SNI.\n"
185 "-k expected name negotiated on server sockets\n"
186 "-b means try binding to the port and exit\n"
187 "-m means test the model-socket feature of SSL_ImportFD.\n"
188 "-r flag is interepreted as follows:\n"
189 " 1 -r means request, not require, cert on initial handshake.\n"
190 " 2 -r's mean request and require, cert on initial handshake.\n"
191 " 3 -r's mean request, not require, cert on second handshake.\n"
192 " 4 -r's mean request and require, cert on second handshake.\n"
193 "-s means disable SSL socket locking for performance\n"
194 "-u means enable Session Ticket extension for TLS.\n"
195 "-v means verbose output\n"
196 "-x means use export policy.\n"
197 "-z means enable compression.\n"
198 "-L seconds means log statistics every 'seconds' seconds (default=30).\n"
199 "-M maxProcs tells how many processes to run in a multi-process server\n"
200 "-N means do NOT use the server session cache. Incompatible with -M.\n"
201 "-t threads -- specify the number of threads to use for connections.\n"
202 "-i pid_file file to write the process id of selfserve\n"
203 "-l means use local threads instead of global threads\n"
204 "-g numblocks means test throughput by sending total numblocks chunks\n"
205 " of size 16kb to the client, 0 means unlimited (default=0)\n"
206 "-j means measure TCP throughput (for use with -g option)\n"
207 "-C SSLCacheEntries sets the maximum number of entries in the SSL\n"
208 " session cache\n"
209 "-T <mode> enable OCSP stapling. Possible modes:\n"
210 " none: don't send cert status (default)\n"
211 " good, revoked, unknown: Include locally signed response. Requires: -A\n"
212 " failure: return a failure response (try later, unsigned)\n"
213 " badsig: use a good status but with an invalid signature\n"
214 " corrupted: stapled cert status is an invalid block of data\n"
215 " random: each connection uses a random status from this list:\n"
216 " good, revoked, unknown, failure, badsig, corrupted\n"
217 " ocsp: fetch from external OCSP server using AIA, or none\n"
218 "-A <ca> Nickname of a CA used to sign a stapled cert status\n"
219 "-c Restrict ciphers\n"
220 "-Y prints cipher values allowed for parameter -c and exits\n"
221 , stderr);
222 }
224 static void
225 Usage(const char *progName)
226 {
227 PrintUsageHeader(progName);
228 PrintParameterUsage();
229 }
231 static void
232 PrintCipherUsage(const char *progName)
233 {
234 PrintUsageHeader(progName);
235 fputs(
236 "-c ciphers Letter(s) chosen from the following list\n"
237 "A SSL2 RC4 128 WITH MD5\n"
238 "B SSL2 RC4 128 EXPORT40 WITH MD5\n"
239 "C SSL2 RC2 128 CBC WITH MD5\n"
240 "D SSL2 RC2 128 CBC EXPORT40 WITH MD5\n"
241 "E SSL2 DES 64 CBC WITH MD5\n"
242 "F SSL2 DES 192 EDE3 CBC WITH MD5\n"
243 "\n"
244 "c SSL3 RSA WITH RC4 128 MD5\n"
245 "d SSL3 RSA WITH 3DES EDE CBC SHA\n"
246 "e SSL3 RSA WITH DES CBC SHA\n"
247 "f SSL3 RSA EXPORT WITH RC4 40 MD5\n"
248 "g SSL3 RSA EXPORT WITH RC2 CBC 40 MD5\n"
249 "i SSL3 RSA WITH NULL MD5\n"
250 "j SSL3 RSA FIPS WITH 3DES EDE CBC SHA\n"
251 "k SSL3 RSA FIPS WITH DES CBC SHA\n"
252 "l SSL3 RSA EXPORT WITH DES CBC SHA\t(new)\n"
253 "m SSL3 RSA EXPORT WITH RC4 56 SHA\t(new)\n"
254 "n SSL3 RSA WITH RC4 128 SHA\n"
255 "v SSL3 RSA WITH AES 128 CBC SHA\n"
256 "y SSL3 RSA WITH AES 256 CBC SHA\n"
257 "z SSL3 RSA WITH NULL SHA\n"
258 "\n"
259 ":WXYZ Use cipher with hex code { 0xWX , 0xYZ } in TLS\n"
260 , stderr);
261 }
263 static const char *
264 errWarn(char * funcString)
265 {
266 PRErrorCode perr = PR_GetError();
267 const char * errString = SECU_Strerror(perr);
269 fprintf(stderr, "selfserv: %s returned error %d:\n%s\n",
270 funcString, perr, errString);
271 return errString;
272 }
274 static void
275 errExit(char * funcString)
276 {
277 errWarn(funcString);
278 exit(3);
279 }
282 /**************************************************************************
283 **
284 ** Routines for disabling SSL ciphers.
285 **
286 **************************************************************************/
288 /* disable all the SSL cipher suites */
289 void
290 disableAllSSLCiphers(void)
291 {
292 const PRUint16 *cipherSuites = SSL_ImplementedCiphers;
293 int i = SSL_NumImplementedCiphers;
294 SECStatus rv;
296 while (--i >= 0) {
297 PRUint16 suite = cipherSuites[i];
298 rv = SSL_CipherPrefSetDefault(suite, PR_FALSE);
299 if (rv != SECSuccess) {
300 printf("SSL_CipherPrefSetDefault rejected suite 0x%04x (i = %d)\n",
301 suite, i);
302 errWarn("SSL_CipherPrefSetDefault");
303 }
304 }
305 }
307 /* disable all the export SSL cipher suites */
308 SECStatus
309 disableExportSSLCiphers(void)
310 {
311 const PRUint16 *cipherSuites = SSL_ImplementedCiphers;
312 int i = SSL_NumImplementedCiphers;
313 SECStatus rv = SECSuccess;
314 SSLCipherSuiteInfo info;
316 while (--i >= 0) {
317 PRUint16 suite = cipherSuites[i];
318 SECStatus status;
319 status = SSL_GetCipherSuiteInfo(suite, &info, sizeof info);
320 if (status != SECSuccess) {
321 printf("SSL_GetCipherSuiteInfo rejected suite 0x%04x (i = %d)\n",
322 suite, i);
323 errWarn("SSL_GetCipherSuiteInfo");
324 rv = SECFailure;
325 continue;
326 }
327 if (info.cipherSuite != suite) {
328 printf(
329 "SSL_GetCipherSuiteInfo returned wrong suite! Wanted 0x%04x, Got 0x%04x\n",
330 suite, i);
331 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
332 rv = SECFailure;
333 continue;
334 }
335 /* should check here that info.length >= offsetof isExportable */
336 if (info.isExportable) {
337 status = SSL_CipherPolicySet(suite, SSL_NOT_ALLOWED);
338 if (status != SECSuccess) {
339 printf("SSL_CipherPolicySet rejected suite 0x%04x (i = %d)\n",
340 suite, i);
341 errWarn("SSL_CipherPolicySet");
342 rv = SECFailure;
343 }
344 }
345 }
346 return rv;
347 }
349 static SECStatus
350 mySSLAuthCertificate(void *arg, PRFileDesc *fd, PRBool checkSig,
351 PRBool isServer)
352 {
353 SECStatus rv;
354 CERTCertificate * peerCert;
356 peerCert = SSL_PeerCertificate(fd);
358 if (peerCert) {
359 PRINTF("selfserv: Subject: %s\nselfserv: Issuer : %s\n",
360 peerCert->subjectName, peerCert->issuerName);
361 CERT_DestroyCertificate(peerCert);
362 }
364 rv = SSL_AuthCertificate(arg, fd, checkSig, isServer);
366 if (rv == SECSuccess) {
367 PRINTF("selfserv: -- SSL3: Certificate Validated.\n");
368 } else {
369 int err = PR_GetError();
370 FPRINTF(stderr, "selfserv: -- SSL3: Certificate Invalid, err %d.\n%s\n",
371 err, SECU_Strerror(err));
372 }
373 FLUSH;
374 return rv;
375 }
377 void
378 printSSLStatistics()
379 {
380 SSL3Statistics * ssl3stats = SSL_GetStatistics();
382 printf(
383 "selfserv: %ld cache hits; %ld cache misses, %ld cache not reusable\n"
384 " %ld stateless resumes, %ld ticket parse failures\n",
385 ssl3stats->hch_sid_cache_hits, ssl3stats->hch_sid_cache_misses,
386 ssl3stats->hch_sid_cache_not_ok, ssl3stats->hch_sid_stateless_resumes,
387 ssl3stats->hch_sid_ticket_parse_failures);
388 }
390 void
391 printSecurityInfo(PRFileDesc *fd)
392 {
393 CERTCertificate * cert = NULL;
394 SECStatus result;
395 SSLChannelInfo channel;
396 SSLCipherSuiteInfo suite;
398 if (verbose)
399 printSSLStatistics();
401 result = SSL_GetChannelInfo(fd, &channel, sizeof channel);
402 if (result == SECSuccess &&
403 channel.length == sizeof channel &&
404 channel.cipherSuite) {
405 result = SSL_GetCipherSuiteInfo(channel.cipherSuite,
406 &suite, sizeof suite);
407 if (result == SECSuccess) {
408 FPRINTF(stderr,
409 "selfserv: SSL version %d.%d using %d-bit %s with %d-bit %s MAC\n",
410 channel.protocolVersion >> 8, channel.protocolVersion & 0xff,
411 suite.effectiveKeyBits, suite.symCipherName,
412 suite.macBits, suite.macAlgorithmName);
413 FPRINTF(stderr,
414 "selfserv: Server Auth: %d-bit %s, Key Exchange: %d-bit %s\n"
415 " Compression: %s\n",
416 channel.authKeyBits, suite.authAlgorithmName,
417 channel.keaKeyBits, suite.keaTypeName,
418 channel.compressionMethodName);
419 }
420 }
421 if (verbose) {
422 SECItem *hostInfo = SSL_GetNegotiatedHostInfo(fd);
423 if (hostInfo) {
424 char namePref[] = "selfserv: Negotiated server name: ";
426 fprintf(stderr, "%s", namePref);
427 fwrite(hostInfo->data, hostInfo->len, 1, stderr);
428 SECITEM_FreeItem(hostInfo, PR_TRUE);
429 hostInfo = NULL;
430 fprintf(stderr, "\n");
431 }
432 }
433 if (requestCert)
434 cert = SSL_PeerCertificate(fd);
435 else
436 cert = SSL_LocalCertificate(fd);
437 if (cert) {
438 char * ip = CERT_NameToAscii(&cert->issuer);
439 char * sp = CERT_NameToAscii(&cert->subject);
440 if (sp) {
441 FPRINTF(stderr, "selfserv: subject DN: %s\n", sp);
442 PORT_Free(sp);
443 }
444 if (ip) {
445 FPRINTF(stderr, "selfserv: issuer DN: %s\n", ip);
446 PORT_Free(ip);
447 }
448 CERT_DestroyCertificate(cert);
449 cert = NULL;
450 }
451 FLUSH;
452 }
454 static int MakeCertOK;
456 static SECStatus
457 myBadCertHandler( void *arg, PRFileDesc *fd)
458 {
459 int err = PR_GetError();
460 if (!MakeCertOK)
461 fprintf(stderr,
462 "selfserv: -- SSL: Client Certificate Invalid, err %d.\n%s\n",
463 err, SECU_Strerror(err));
464 return (MakeCertOK ? SECSuccess : SECFailure);
465 }
467 #define MAX_VIRT_SERVER_NAME_ARRAY_INDEX 10
469 /* Simple SNI socket config function that does not use SSL_ReconfigFD.
470 * Only uses one server name but verifies that the names match. */
471 PRInt32
472 mySSLSNISocketConfig(PRFileDesc *fd, const SECItem *sniNameArr,
473 PRUint32 sniNameArrSize, void *arg)
474 {
475 PRInt32 i = 0;
476 const SECItem *current = sniNameArr;
477 const char **nameArr = (const char**)arg;
478 secuPWData *pwdata;
479 CERTCertificate * cert = NULL;
480 SECKEYPrivateKey * privKey = NULL;
482 PORT_Assert(fd && sniNameArr);
483 if (!fd || !sniNameArr) {
484 return SSL_SNI_SEND_ALERT;
485 }
487 pwdata = SSL_RevealPinArg(fd);
489 for (;current && i < sniNameArrSize;i++) {
490 int j = 0;
491 for (;j < MAX_VIRT_SERVER_NAME_ARRAY_INDEX && nameArr[j];j++) {
492 if (!PORT_Strncmp(nameArr[j],
493 (const char *)current[i].data,
494 current[i].len) &&
495 PORT_Strlen(nameArr[j]) == current[i].len) {
496 const char *nickName = nameArr[j];
497 if (j == 0) {
498 /* default cert */
499 return 0;
500 }
501 /* if pwdata is NULL, then we would not get the key and
502 * return an error status. */
503 cert = PK11_FindCertFromNickname(nickName, &pwdata);
504 if (cert == NULL) {
505 goto loser; /* Send alert */
506 }
507 privKey = PK11_FindKeyByAnyCert(cert, &pwdata);
508 if (privKey == NULL) {
509 goto loser; /* Send alert */
510 }
511 if (SSL_ConfigSecureServer(fd, cert, privKey,
512 kt_rsa) != SECSuccess) {
513 goto loser; /* Send alert */
514 }
515 SECKEY_DestroyPrivateKey(privKey);
516 CERT_DestroyCertificate(cert);
517 return i;
518 }
519 }
520 }
521 loser:
522 if (privKey) {
523 SECKEY_DestroyPrivateKey(privKey);
524 }
525 if (cert) {
526 CERT_DestroyCertificate(cert);
527 }
528 return SSL_SNI_SEND_ALERT;
529 }
532 /**************************************************************************
533 ** Begin thread management routines and data.
534 **************************************************************************/
535 #define MIN_THREADS 3
536 #define DEFAULT_THREADS 8
537 #define MAX_THREADS 4096
538 #define MAX_PROCS 25
539 static int maxThreads = DEFAULT_THREADS;
542 typedef struct jobStr {
543 PRCList link;
544 PRFileDesc *tcp_sock;
545 PRFileDesc *model_sock;
546 int requestCert;
547 } JOB;
549 static PZLock * qLock; /* this lock protects all data immediately below */
550 static PRLock * lastLoadedCrlLock; /* this lock protects lastLoadedCrl variable */
551 static PZCondVar * jobQNotEmptyCv;
552 static PZCondVar * freeListNotEmptyCv;
553 static PZCondVar * threadCountChangeCv;
554 static int threadCount;
555 static PRCList jobQ;
556 static PRCList freeJobs;
557 static JOB *jobTable;
559 SECStatus
560 setupJobs(int maxJobs)
561 {
562 int i;
564 jobTable = (JOB *)PR_Calloc(maxJobs, sizeof(JOB));
565 if (!jobTable)
566 return SECFailure;
568 PR_INIT_CLIST(&jobQ);
569 PR_INIT_CLIST(&freeJobs);
571 for (i = 0; i < maxJobs; ++i) {
572 JOB * pJob = jobTable + i;
573 PR_APPEND_LINK(&pJob->link, &freeJobs);
574 }
575 return SECSuccess;
576 }
578 typedef int startFn(PRFileDesc *a, PRFileDesc *b, int c);
580 typedef enum { rs_idle = 0, rs_running = 1, rs_zombie = 2 } runState;
582 typedef struct perThreadStr {
583 PRFileDesc *a;
584 PRFileDesc *b;
585 int c;
586 int rv;
587 startFn * startFunc;
588 PRThread * prThread;
589 runState state;
590 } perThread;
592 static perThread *threads;
594 void
595 thread_wrapper(void * arg)
596 {
597 perThread * slot = (perThread *)arg;
599 slot->rv = (* slot->startFunc)(slot->a, slot->b, slot->c);
601 /* notify the thread exit handler. */
602 PZ_Lock(qLock);
603 slot->state = rs_zombie;
604 --threadCount;
605 PZ_NotifyAllCondVar(threadCountChangeCv);
606 PZ_Unlock(qLock);
607 }
609 int
610 jobLoop(PRFileDesc *a, PRFileDesc *b, int c)
611 {
612 PRCList * myLink = 0;
613 JOB * myJob;
615 PZ_Lock(qLock);
616 do {
617 myLink = 0;
618 while (PR_CLIST_IS_EMPTY(&jobQ) && !stopping) {
619 PZ_WaitCondVar(jobQNotEmptyCv, PR_INTERVAL_NO_TIMEOUT);
620 }
621 if (!PR_CLIST_IS_EMPTY(&jobQ)) {
622 myLink = PR_LIST_HEAD(&jobQ);
623 PR_REMOVE_AND_INIT_LINK(myLink);
624 }
625 PZ_Unlock(qLock);
626 myJob = (JOB *)myLink;
627 /* myJob will be null when stopping is true and jobQ is empty */
628 if (!myJob)
629 break;
630 handle_connection( myJob->tcp_sock, myJob->model_sock,
631 myJob->requestCert);
632 PZ_Lock(qLock);
633 PR_APPEND_LINK(myLink, &freeJobs);
634 PZ_NotifyCondVar(freeListNotEmptyCv);
635 } while (PR_TRUE);
636 return 0;
637 }
640 SECStatus
641 launch_threads(
642 startFn *startFunc,
643 PRFileDesc *a,
644 PRFileDesc *b,
645 int c,
646 PRBool local)
647 {
648 int i;
649 SECStatus rv = SECSuccess;
651 /* create the thread management serialization structs */
652 qLock = PZ_NewLock(nssILockSelfServ);
653 jobQNotEmptyCv = PZ_NewCondVar(qLock);
654 freeListNotEmptyCv = PZ_NewCondVar(qLock);
655 threadCountChangeCv = PZ_NewCondVar(qLock);
657 /* create monitor for crl reload procedure */
658 lastLoadedCrlLock = PR_NewLock();
660 /* allocate the array of thread slots */
661 threads = PR_Calloc(maxThreads, sizeof(perThread));
662 if ( NULL == threads ) {
663 fprintf(stderr, "Oh Drat! Can't allocate the perThread array\n");
664 return SECFailure;
665 }
666 /* 5 is a little extra, intended to keep the jobQ from underflowing.
667 ** That is, from going empty while not stopping and clients are still
668 ** trying to contact us.
669 */
670 rv = setupJobs(maxThreads + 5);
671 if (rv != SECSuccess)
672 return rv;
674 PZ_Lock(qLock);
675 for (i = 0; i < maxThreads; ++i) {
676 perThread * slot = threads + i;
678 slot->state = rs_running;
679 slot->a = a;
680 slot->b = b;
681 slot->c = c;
682 slot->startFunc = startFunc;
683 slot->prThread = PR_CreateThread(PR_USER_THREAD,
684 thread_wrapper, slot, PR_PRIORITY_NORMAL,
685 (PR_TRUE==local)?PR_LOCAL_THREAD:PR_GLOBAL_THREAD,
686 PR_UNJOINABLE_THREAD, 0);
687 if (slot->prThread == NULL) {
688 printf("selfserv: Failed to launch thread!\n");
689 slot->state = rs_idle;
690 rv = SECFailure;
691 break;
692 }
694 ++threadCount;
695 }
696 PZ_Unlock(qLock);
698 return rv;
699 }
701 #define DESTROY_CONDVAR(name) if (name) { \
702 PZ_DestroyCondVar(name); name = NULL; }
703 #define DESTROY_LOCK(name) if (name) { \
704 PZ_DestroyLock(name); name = NULL; }
707 void
708 terminateWorkerThreads(void)
709 {
710 VLOG(("selfserv: server_thead: waiting on stopping"));
711 PZ_Lock(qLock);
712 PZ_NotifyAllCondVar(jobQNotEmptyCv);
713 while (threadCount > 0) {
714 PZ_WaitCondVar(threadCountChangeCv, PR_INTERVAL_NO_TIMEOUT);
715 }
716 /* The worker threads empty the jobQ before they terminate. */
717 PORT_Assert(PR_CLIST_IS_EMPTY(&jobQ));
718 PZ_Unlock(qLock);
720 DESTROY_CONDVAR(jobQNotEmptyCv);
721 DESTROY_CONDVAR(freeListNotEmptyCv);
722 DESTROY_CONDVAR(threadCountChangeCv);
724 PR_DestroyLock(lastLoadedCrlLock);
725 DESTROY_LOCK(qLock);
726 PR_Free(jobTable);
727 PR_Free(threads);
728 }
730 static void
731 logger(void *arg)
732 {
733 PRFloat64 seconds;
734 PRFloat64 opsPerSec;
735 PRIntervalTime period;
736 PRIntervalTime previousTime;
737 PRIntervalTime latestTime;
738 PRUint32 previousOps;
739 PRUint32 ops;
740 PRIntervalTime logPeriodTicks = PR_TicksPerSecond();
741 PRFloat64 secondsPerTick = 1.0 / (PRFloat64)logPeriodTicks;
742 int iterations = 0;
743 int secondsElapsed = 0;
744 static PRInt64 totalPeriodBytes = 0;
745 static PRInt64 totalPeriodBytesTCP = 0;
747 previousOps = loggerOps;
748 previousTime = PR_IntervalNow();
750 for (;;) {
751 /* OK, implementing a new sleep algorithm here... always sleep
752 * for 1 second but print out info at the user-specified interval.
753 * This way, we don't overflow all of our PR_Atomic* functions and
754 * we don't have to use locks.
755 */
756 PR_Sleep(logPeriodTicks);
757 secondsElapsed++;
758 totalPeriodBytes += PR_ATOMIC_SET(&loggerBytes, 0);
759 totalPeriodBytesTCP += PR_ATOMIC_SET(&loggerBytesTCP, 0);
760 if (secondsElapsed != logPeriod) {
761 continue;
762 }
763 /* when we reach the user-specified logging interval, print out all
764 * data
765 */
766 secondsElapsed = 0;
767 latestTime = PR_IntervalNow();
768 ops = loggerOps;
769 period = latestTime - previousTime;
770 seconds = (PRFloat64) period*secondsPerTick;
771 opsPerSec = (ops - previousOps) / seconds;
773 if (testBulk) {
774 if (iterations == 0) {
775 if (loggingLayer == PR_TRUE) {
776 printf("Conn.--------App Data--------TCP Data\n");
777 } else {
778 printf("Conn.--------App Data\n");
779 }
780 }
781 if (loggingLayer == PR_TRUE) {
782 printf("%4.d %5.3f MB/s %5.3f MB/s\n", ops,
783 totalPeriodBytes / (seconds * 1048576.0),
784 totalPeriodBytesTCP / (seconds * 1048576.0));
785 } else {
786 printf("%4.d %5.3f MB/s\n", ops,
787 totalPeriodBytes / (seconds * 1048576.0));
788 }
789 totalPeriodBytes = 0;
790 totalPeriodBytesTCP = 0;
791 /* Print the "legend" every 20 iterations */
792 iterations = (iterations + 1) % 20;
793 } else {
794 printf("%.2f ops/second, %d threads\n", opsPerSec, threadCount);
795 }
797 fflush(stdout);
798 previousOps = ops;
799 previousTime = latestTime;
800 if (stopping) {
801 break;
802 }
803 }
804 }
807 /**************************************************************************
808 ** End thread management routines.
809 **************************************************************************/
811 PRBool useModelSocket = PR_FALSE;
812 static SSLVersionRange enabledVersions;
813 PRBool enableSSL2 = PR_TRUE;
814 PRBool disableRollBack = PR_FALSE;
815 PRBool NoReuse = PR_FALSE;
816 PRBool hasSidCache = PR_FALSE;
817 PRBool disableStepDown = PR_FALSE;
818 PRBool bypassPKCS11 = PR_FALSE;
819 PRBool disableLocking = PR_FALSE;
820 PRBool testbypass = PR_FALSE;
821 PRBool enableSessionTickets = PR_FALSE;
822 PRBool enableCompression = PR_FALSE;
823 PRBool failedToNegotiateName = PR_FALSE;
824 static char *virtServerNameArray[MAX_VIRT_SERVER_NAME_ARRAY_INDEX];
825 static int virtServerNameIndex = 1;
828 static const char stopCmd[] = { "GET /stop " };
829 static const char getCmd[] = { "GET " };
830 static const char EOFmsg[] = { "EOF\r\n\r\n\r\n" };
831 static const char outHeader[] = {
832 "HTTP/1.0 200 OK\r\n"
833 "Server: Generic Web Server\r\n"
834 "Date: Tue, 26 Aug 1997 22:10:05 GMT\r\n"
835 "Content-type: text/plain\r\n"
836 "\r\n"
837 };
838 static const char crlCacheErr[] = { "CRL ReCache Error: " };
840 PRUint16 cipherlist[100];
841 int nciphers;
843 void
844 savecipher(int c)
845 {
846 if (nciphers < sizeof cipherlist / sizeof (cipherlist[0]))
847 cipherlist[nciphers++] = (PRUint16)c;
848 }
851 #ifdef FULL_DUPLEX_CAPABLE
853 struct lockedVarsStr {
854 PZLock * lock;
855 int count;
856 int waiters;
857 PZCondVar * condVar;
858 };
860 typedef struct lockedVarsStr lockedVars;
862 void
863 lockedVars_Init( lockedVars * lv)
864 {
865 lv->count = 0;
866 lv->waiters = 0;
867 lv->lock = PZ_NewLock(nssILockSelfServ);
868 lv->condVar = PZ_NewCondVar(lv->lock);
869 }
871 void
872 lockedVars_Destroy( lockedVars * lv)
873 {
874 PZ_DestroyCondVar(lv->condVar);
875 lv->condVar = NULL;
877 PZ_DestroyLock(lv->lock);
878 lv->lock = NULL;
879 }
881 void
882 lockedVars_WaitForDone(lockedVars * lv)
883 {
884 PZ_Lock(lv->lock);
885 while (lv->count > 0) {
886 PZ_WaitCondVar(lv->condVar, PR_INTERVAL_NO_TIMEOUT);
887 }
888 PZ_Unlock(lv->lock);
889 }
891 int /* returns count */
892 lockedVars_AddToCount(lockedVars * lv, int addend)
893 {
894 int rv;
896 PZ_Lock(lv->lock);
897 rv = lv->count += addend;
898 if (rv <= 0) {
899 PZ_NotifyCondVar(lv->condVar);
900 }
901 PZ_Unlock(lv->lock);
902 return rv;
903 }
905 int
906 do_writes(
907 PRFileDesc * ssl_sock,
908 PRFileDesc * model_sock,
909 int requestCert
910 )
911 {
912 int sent = 0;
913 int count = 0;
914 lockedVars * lv = (lockedVars *)model_sock;
916 VLOG(("selfserv: do_writes: starting"));
917 while (sent < bigBuf.len) {
919 count = PR_Write(ssl_sock, bigBuf.data + sent, bigBuf.len - sent);
920 if (count < 0) {
921 errWarn("PR_Write bigBuf");
922 break;
923 }
924 FPRINTF(stderr, "selfserv: PR_Write wrote %d bytes from bigBuf\n", count );
925 sent += count;
926 }
927 if (count >= 0) { /* last write didn't fail. */
928 PR_Shutdown(ssl_sock, PR_SHUTDOWN_SEND);
929 }
931 /* notify the reader that we're done. */
932 lockedVars_AddToCount(lv, -1);
933 FLUSH;
934 VLOG(("selfserv: do_writes: exiting"));
935 return (sent < bigBuf.len) ? SECFailure : SECSuccess;
936 }
938 static int
939 handle_fdx_connection(
940 PRFileDesc * tcp_sock,
941 PRFileDesc * model_sock,
942 int requestCert
943 )
944 {
945 PRFileDesc * ssl_sock = NULL;
946 SECStatus result;
947 int firstTime = 1;
948 lockedVars lv;
949 PRSocketOptionData opt;
950 char buf[10240];
953 VLOG(("selfserv: handle_fdx_connection: starting"));
954 opt.option = PR_SockOpt_Nonblocking;
955 opt.value.non_blocking = PR_FALSE;
956 PR_SetSocketOption(tcp_sock, &opt);
958 if (useModelSocket && model_sock) {
959 SECStatus rv;
960 ssl_sock = SSL_ImportFD(model_sock, tcp_sock);
961 if (!ssl_sock) {
962 errWarn("SSL_ImportFD with model");
963 goto cleanup;
964 }
965 rv = SSL_ResetHandshake(ssl_sock, /* asServer */ 1);
966 if (rv != SECSuccess) {
967 errWarn("SSL_ResetHandshake");
968 goto cleanup;
969 }
970 } else {
971 ssl_sock = tcp_sock;
972 }
974 lockedVars_Init(&lv);
975 lockedVars_AddToCount(&lv, 1);
977 /* Attempt to launch the writer thread. */
978 result = launch_thread(do_writes, ssl_sock, (PRFileDesc *)&lv,
979 requestCert);
981 if (result == SECSuccess)
982 do {
983 /* do reads here. */
984 int count;
985 count = PR_Read(ssl_sock, buf, sizeof buf);
986 if (count < 0) {
987 errWarn("FDX PR_Read");
988 break;
989 }
990 FPRINTF(stderr, "selfserv: FDX PR_Read read %d bytes.\n", count );
991 if (firstTime) {
992 firstTime = 0;
993 printSecurityInfo(ssl_sock);
994 }
995 } while (lockedVars_AddToCount(&lv, 0) > 0);
997 /* Wait for writer to finish */
998 lockedVars_WaitForDone(&lv);
999 lockedVars_Destroy(&lv);
1000 FLUSH;
1002 cleanup:
1003 if (ssl_sock) {
1004 PR_Close(ssl_sock);
1005 } else if (tcp_sock) {
1006 PR_Close(tcp_sock);
1007 }
1009 VLOG(("selfserv: handle_fdx_connection: exiting"));
1010 return SECSuccess;
1011 }
1013 #endif
1015 static SECItem *lastLoadedCrl = NULL;
1017 static SECStatus
1018 reload_crl(PRFileDesc *crlFile)
1019 {
1020 SECItem *crlDer;
1021 CERTCertDBHandle *certHandle = CERT_GetDefaultCertDB();
1022 SECStatus rv;
1024 /* Read in the entire file specified with the -f argument */
1025 crlDer = PORT_Malloc(sizeof(SECItem));
1026 if (!crlDer) {
1027 errWarn("Can not allocate memory.");
1028 return SECFailure;
1029 }
1031 rv = SECU_ReadDERFromFile(crlDer, crlFile, PR_FALSE, PR_FALSE);
1032 if (rv != SECSuccess) {
1033 errWarn("Unable to read input file.");
1034 PORT_Free(crlDer);
1035 return SECFailure;
1036 }
1038 PR_Lock(lastLoadedCrlLock);
1039 rv = CERT_CacheCRL(certHandle, crlDer);
1040 if (rv == SECSuccess) {
1041 SECItem *tempItem = crlDer;
1042 if (lastLoadedCrl != NULL) {
1043 rv = CERT_UncacheCRL(certHandle, lastLoadedCrl);
1044 if (rv != SECSuccess) {
1045 errWarn("Unable to uncache crl.");
1046 goto loser;
1047 }
1048 crlDer = lastLoadedCrl;
1049 } else {
1050 crlDer = NULL;
1051 }
1052 lastLoadedCrl = tempItem;
1053 }
1055 loser:
1056 PR_Unlock(lastLoadedCrlLock);
1057 SECITEM_FreeItem(crlDer, PR_TRUE);
1058 return rv;
1059 }
1061 void stop_server()
1062 {
1063 stopping = 1;
1064 PR_Interrupt(acceptorThread);
1065 PZ_TraceFlush();
1066 }
1068 SECItemArray *
1069 makeTryLaterOCSPResponse(PLArenaPool *arena)
1070 {
1071 SECItemArray *result = NULL;
1072 SECItem *ocspResponse = NULL;
1074 ocspResponse = CERT_CreateEncodedOCSPErrorResponse(arena,
1075 SEC_ERROR_OCSP_TRY_SERVER_LATER);
1076 if (!ocspResponse)
1077 errExit("cannot created ocspResponse");
1079 result = SECITEM_AllocArray(arena, NULL, 1);
1080 if (!result)
1081 errExit("cannot allocate multiOcspResponses");
1083 result->items[0].data = ocspResponse->data;
1084 result->items[0].len = ocspResponse->len;
1086 return result;
1087 }
1089 SECItemArray *
1090 makeCorruptedOCSPResponse(PLArenaPool *arena)
1091 {
1092 SECItemArray *result = NULL;
1093 SECItem *ocspResponse = NULL;
1095 ocspResponse = SECITEM_AllocItem(arena, NULL, 1);
1096 if (!ocspResponse)
1097 errExit("cannot created ocspResponse");
1099 result = SECITEM_AllocArray(arena, NULL, 1);
1100 if (!result)
1101 errExit("cannot allocate multiOcspResponses");
1103 result->items[0].data = ocspResponse->data;
1104 result->items[0].len = ocspResponse->len;
1106 return result;
1107 }
1109 SECItemArray *
1110 makeSignedOCSPResponse(PLArenaPool *arena, ocspStaplingModeType osm,
1111 CERTCertificate *cert, secuPWData *pwdata)
1112 {
1113 SECItemArray *result = NULL;
1114 SECItem *ocspResponse = NULL;
1115 CERTOCSPSingleResponse **singleResponses;
1116 CERTOCSPSingleResponse *sr;
1117 CERTOCSPCertID *cid = NULL;
1118 CERTCertificate *ca;
1119 PRTime now = PR_Now();
1120 PRTime nextUpdate;
1122 PORT_Assert(cert != NULL);
1124 ca = CERT_FindCertByNickname(CERT_GetDefaultCertDB(), ocspStaplingCA);
1125 if (!ca)
1126 errExit("cannot find CA");
1128 cid = CERT_CreateOCSPCertID(cert, now);
1129 if (!cid)
1130 errExit("cannot created cid");
1132 nextUpdate = now + 60*60*24 * PR_USEC_PER_SEC; /* plus 1 day */
1134 switch (osm) {
1135 case osm_good:
1136 case osm_badsig:
1137 sr = CERT_CreateOCSPSingleResponseGood(arena, cid, now,
1138 &nextUpdate);
1139 break;
1140 case osm_unknown:
1141 sr = CERT_CreateOCSPSingleResponseUnknown(arena, cid, now,
1142 &nextUpdate);
1143 break;
1144 case osm_revoked:
1145 sr = CERT_CreateOCSPSingleResponseRevoked(arena, cid, now,
1146 &nextUpdate,
1147 now - 60*60*24 * PR_USEC_PER_SEC, /* minus 1 day */
1148 NULL);
1149 break;
1150 default:
1151 PORT_Assert(0);
1152 break;
1153 }
1155 if (!sr)
1156 errExit("cannot create sr");
1158 /* meaning of value 2: one entry + one end marker */
1159 singleResponses = PORT_ArenaNewArray(arena, CERTOCSPSingleResponse*, 2);
1160 if (singleResponses == NULL)
1161 errExit("cannot allocate singleResponses");
1163 singleResponses[0] = sr;
1164 singleResponses[1] = NULL;
1166 ocspResponse = CERT_CreateEncodedOCSPSuccessResponse(arena,
1167 (osm == osm_badsig) ? NULL : ca,
1168 ocspResponderID_byName, now, singleResponses,
1169 &pwdata);
1170 if (!ocspResponse)
1171 errExit("cannot created ocspResponse");
1173 CERT_DestroyCertificate(ca);
1174 ca = NULL;
1176 result = SECITEM_AllocArray(arena, NULL, 1);
1177 if (!result)
1178 errExit("cannot allocate multiOcspResponses");
1180 result->items[0].data = ocspResponse->data;
1181 result->items[0].len = ocspResponse->len;
1183 CERT_DestroyOCSPCertID(cid);
1184 cid = NULL;
1186 return result;
1187 }
1189 void
1190 setupCertStatus(PLArenaPool *arena, enum ocspStaplingModeEnum ocspStaplingMode,
1191 CERTCertificate *cert, SSLKEAType kea, secuPWData *pwdata)
1192 {
1193 if (ocspStaplingMode == osm_random) {
1194 /* 6 different responses */
1195 int r = rand() % 6;
1196 switch (r) {
1197 case 0: ocspStaplingMode = osm_good; break;
1198 case 1: ocspStaplingMode = osm_revoked; break;
1199 case 2: ocspStaplingMode = osm_unknown; break;
1200 case 3: ocspStaplingMode = osm_badsig; break;
1201 case 4: ocspStaplingMode = osm_corrupted; break;
1202 case 5: ocspStaplingMode = osm_failure; break;
1203 default: PORT_Assert(0); break;
1204 }
1205 }
1206 if (ocspStaplingMode != osm_disabled) {
1207 SECItemArray *multiOcspResponses = NULL;
1208 switch (ocspStaplingMode) {
1209 case osm_good:
1210 case osm_revoked:
1211 case osm_unknown:
1212 case osm_badsig:
1213 multiOcspResponses =
1214 makeSignedOCSPResponse(arena, ocspStaplingMode, cert,
1215 pwdata);
1216 break;
1217 case osm_corrupted:
1218 multiOcspResponses = makeCorruptedOCSPResponse(arena);
1219 break;
1220 case osm_failure:
1221 multiOcspResponses = makeTryLaterOCSPResponse(arena);
1222 break;
1223 case osm_ocsp:
1224 errExit("stapling mode \"ocsp\" not implemented");
1225 break;
1226 break;
1227 default:
1228 break;
1229 }
1230 if (multiOcspResponses) {
1231 certStatus[kea] = multiOcspResponses;
1232 }
1233 }
1234 }
1236 int
1237 handle_connection(
1238 PRFileDesc *tcp_sock,
1239 PRFileDesc *model_sock,
1240 int requestCert
1241 )
1242 {
1243 PRFileDesc * ssl_sock = NULL;
1244 PRFileDesc * local_file_fd = NULL;
1245 char * post;
1246 char * pBuf; /* unused space at end of buf */
1247 const char * errString;
1248 PRStatus status;
1249 int bufRem; /* unused bytes at end of buf */
1250 int bufDat; /* characters received in buf */
1251 int newln = 0; /* # of consecutive newlns */
1252 int firstTime = 1;
1253 int reqLen;
1254 int rv;
1255 int numIOVs;
1256 PRSocketOptionData opt;
1257 PRIOVec iovs[16];
1258 char msgBuf[160];
1259 char buf[10240];
1260 char fileName[513];
1261 char proto[128];
1262 PRDescIdentity aboveLayer = PR_INVALID_IO_LAYER;
1263 SSLKEAType kea;
1265 pBuf = buf;
1266 bufRem = sizeof buf;
1268 VLOG(("selfserv: handle_connection: starting"));
1269 opt.option = PR_SockOpt_Nonblocking;
1270 opt.value.non_blocking = PR_FALSE;
1271 PR_SetSocketOption(tcp_sock, &opt);
1273 VLOG(("selfserv: handle_connection: starting\n"));
1274 if (useModelSocket && model_sock) {
1275 SECStatus rv;
1276 ssl_sock = SSL_ImportFD(model_sock, tcp_sock);
1277 if (!ssl_sock) {
1278 errWarn("SSL_ImportFD with model");
1279 goto cleanup;
1280 }
1281 rv = SSL_ResetHandshake(ssl_sock, /* asServer */ 1);
1282 if (rv != SECSuccess) {
1283 errWarn("SSL_ResetHandshake");
1284 goto cleanup;
1285 }
1286 } else {
1287 ssl_sock = tcp_sock;
1288 }
1290 for (kea = kt_rsa; kea < kt_kea_size; kea++) {
1291 if (certStatus[kea] != NULL) {
1292 SSL_SetStapledOCSPResponses(ssl_sock, certStatus[kea], kea);
1293 }
1294 }
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 }
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 }
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 }
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 }
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;
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;
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 */
1391 bufDat = pBuf - buf;
1392 if (bufDat) do { /* just close if no data */
1393 /* Have either (a) a complete get, (b) a complete post, (c) EOF */
1394 if (reqLen > 0 && !strncmp(buf, getCmd, sizeof getCmd - 1)) {
1395 char * fnBegin = buf + 4;
1396 char * fnEnd;
1397 PRFileInfo info;
1398 /* try to open the file named.
1399 * If successful, then write it to the client.
1400 */
1401 fnEnd = strpbrk(fnBegin, " \r\n");
1402 if (fnEnd) {
1403 int fnLen = fnEnd - fnBegin;
1404 if (fnLen < sizeof fileName) {
1405 char *real_fileName = fileName;
1406 char *protoEnd = NULL;
1407 strncpy(fileName, fnBegin, fnLen);
1408 fileName[fnLen] = 0; /* null terminate */
1409 if ((protoEnd = strstr(fileName, "://")) != NULL) {
1410 int protoLen = PR_MIN(protoEnd - fileName, sizeof(proto) - 1);
1411 PL_strncpy(proto, fileName, protoLen);
1412 proto[protoLen] = 0;
1413 real_fileName= protoEnd + 3;
1414 } else {
1415 proto[0] = 0;
1416 }
1417 status = PR_GetFileInfo(real_fileName, &info);
1418 if (status == PR_SUCCESS &&
1419 info.type == PR_FILE_FILE &&
1420 info.size >= 0 ) {
1421 local_file_fd = PR_Open(real_fileName, PR_RDONLY, 0);
1422 }
1423 }
1424 }
1425 }
1426 /* if user has requested client auth in a subsequent handshake,
1427 * do it here.
1428 */
1429 if (requestCert > 2) { /* request cert was 3 or 4 */
1430 CERTCertificate * cert = SSL_PeerCertificate(ssl_sock);
1431 if (cert) {
1432 CERT_DestroyCertificate(cert);
1433 } else {
1434 rv = SSL_OptionSet(ssl_sock, SSL_REQUEST_CERTIFICATE, 1);
1435 if (rv < 0) {
1436 errWarn("second SSL_OptionSet SSL_REQUEST_CERTIFICATE");
1437 break;
1438 }
1439 rv = SSL_OptionSet(ssl_sock, SSL_REQUIRE_CERTIFICATE,
1440 (requestCert == 4));
1441 if (rv < 0) {
1442 errWarn("second SSL_OptionSet SSL_REQUIRE_CERTIFICATE");
1443 break;
1444 }
1445 rv = SSL_ReHandshake(ssl_sock, PR_TRUE);
1446 if (rv != 0) {
1447 errWarn("SSL_ReHandshake");
1448 break;
1449 }
1450 rv = SSL_ForceHandshake(ssl_sock);
1451 if (rv < 0) {
1452 errWarn("SSL_ForceHandshake");
1453 break;
1454 }
1455 }
1456 }
1458 numIOVs = 0;
1460 iovs[numIOVs].iov_base = (char *)outHeader;
1461 iovs[numIOVs].iov_len = (sizeof(outHeader)) - 1;
1462 numIOVs++;
1464 if (local_file_fd) {
1465 PRInt32 bytes;
1466 int errLen;
1467 if (!PL_strlen(proto) || !PL_strcmp(proto, "file")) {
1468 bytes = PR_TransmitFile(ssl_sock, local_file_fd, outHeader,
1469 sizeof outHeader - 1,
1470 PR_TRANSMITFILE_KEEP_OPEN,
1471 PR_INTERVAL_NO_TIMEOUT);
1472 if (bytes >= 0) {
1473 bytes -= sizeof outHeader - 1;
1474 FPRINTF(stderr,
1475 "selfserv: PR_TransmitFile wrote %d bytes from %s\n",
1476 bytes, fileName);
1477 break;
1478 }
1479 errString = errWarn("PR_TransmitFile");
1480 errLen = PORT_Strlen(errString);
1481 errLen = PR_MIN(errLen, sizeof msgBuf - 1);
1482 PORT_Memcpy(msgBuf, errString, errLen);
1483 msgBuf[errLen] = 0;
1485 iovs[numIOVs].iov_base = msgBuf;
1486 iovs[numIOVs].iov_len = PORT_Strlen(msgBuf);
1487 numIOVs++;
1488 }
1489 if (!PL_strcmp(proto, "crl")) {
1490 if (reload_crl(local_file_fd) == SECFailure) {
1491 errString = errWarn("CERT_CacheCRL");
1492 if (!errString)
1493 errString = "Unknow error";
1494 PR_snprintf(msgBuf, sizeof(msgBuf), "%s%s ",
1495 crlCacheErr, errString);
1497 iovs[numIOVs].iov_base = msgBuf;
1498 iovs[numIOVs].iov_len = PORT_Strlen(msgBuf);
1499 numIOVs++;
1500 } else {
1501 FPRINTF(stderr,
1502 "selfserv: CRL %s reloaded.\n",
1503 fileName);
1504 break;
1505 }
1506 }
1507 } else if (reqLen <= 0) { /* hit eof */
1508 PORT_Sprintf(msgBuf, "Get or Post incomplete after %d bytes.\r\n",
1509 bufDat);
1511 iovs[numIOVs].iov_base = msgBuf;
1512 iovs[numIOVs].iov_len = PORT_Strlen(msgBuf);
1513 numIOVs++;
1514 } else if (reqLen < bufDat) {
1515 PORT_Sprintf(msgBuf, "Discarded %d characters.\r\n",
1516 bufDat - reqLen);
1518 iovs[numIOVs].iov_base = msgBuf;
1519 iovs[numIOVs].iov_len = PORT_Strlen(msgBuf);
1520 numIOVs++;
1521 }
1523 if (reqLen > 0) {
1524 if (verbose > 1)
1525 fwrite(buf, 1, reqLen, stdout); /* display it */
1527 iovs[numIOVs].iov_base = buf;
1528 iovs[numIOVs].iov_len = reqLen;
1529 numIOVs++;
1530 }
1532 /* Don't add the EOF if we want to test bulk encryption */
1533 if (!testBulk) {
1534 iovs[numIOVs].iov_base = (char *)EOFmsg;
1535 iovs[numIOVs].iov_len = sizeof EOFmsg - 1;
1536 numIOVs++;
1537 }
1539 rv = PR_Writev(ssl_sock, iovs, numIOVs, PR_INTERVAL_NO_TIMEOUT);
1540 if (rv < 0) {
1541 errWarn("PR_Writev");
1542 break;
1543 }
1545 /* Send testBulkTotal chunks to the client. Unlimited if 0. */
1546 if (testBulk) {
1547 while (0 < (rv = PR_Write(ssl_sock, testBulkBuf, testBulkSize))) {
1548 PR_ATOMIC_ADD(&loggerBytes, rv);
1549 PR_ATOMIC_INCREMENT(&bulkSentChunks);
1550 if ((bulkSentChunks > testBulkTotal) && (testBulkTotal != 0))
1551 break;
1552 }
1554 /* There was a write error, so close this connection. */
1555 if (bulkSentChunks <= testBulkTotal) {
1556 errWarn("PR_Write");
1557 }
1558 PR_ATOMIC_DECREMENT(&loggerOps);
1559 break;
1560 }
1561 } while (0);
1563 cleanup:
1564 if (ssl_sock) {
1565 PR_Close(ssl_sock);
1566 } else if (tcp_sock) {
1567 PR_Close(tcp_sock);
1568 }
1569 if (local_file_fd)
1570 PR_Close(local_file_fd);
1571 VLOG(("selfserv: handle_connection: exiting\n"));
1573 /* do a nice shutdown if asked. */
1574 if (!strncmp(buf, stopCmd, sizeof stopCmd - 1)) {
1575 VLOG(("selfserv: handle_connection: stop command"));
1576 stop_server();
1577 }
1578 VLOG(("selfserv: handle_connection: exiting"));
1579 return SECSuccess; /* success */
1580 }
1582 #ifdef XP_UNIX
1584 void sigusr1_handler(int sig)
1585 {
1586 VLOG(("selfserv: sigusr1_handler: stop server"));
1587 stop_server();
1588 }
1590 #endif
1592 SECStatus
1593 do_accepts(
1594 PRFileDesc *listen_sock,
1595 PRFileDesc *model_sock,
1596 int requestCert
1597 )
1598 {
1599 PRNetAddr addr;
1600 PRErrorCode perr;
1601 #ifdef XP_UNIX
1602 struct sigaction act;
1603 #endif
1605 VLOG(("selfserv: do_accepts: starting"));
1606 PR_SetThreadPriority( PR_GetCurrentThread(), PR_PRIORITY_HIGH);
1608 acceptorThread = PR_GetCurrentThread();
1609 #ifdef XP_UNIX
1610 /* set up the signal handler */
1611 act.sa_handler = sigusr1_handler;
1612 sigemptyset(&act.sa_mask);
1613 act.sa_flags = 0;
1614 if (sigaction(SIGUSR1, &act, NULL)) {
1615 fprintf(stderr, "Error installing signal handler.\n");
1616 exit(1);
1617 }
1618 #endif
1619 while (!stopping) {
1620 PRFileDesc *tcp_sock;
1621 PRCList *myLink;
1623 FPRINTF(stderr, "\n\n\nselfserv: About to call accept.\n");
1624 tcp_sock = PR_Accept(listen_sock, &addr, PR_INTERVAL_NO_TIMEOUT);
1625 if (tcp_sock == NULL) {
1626 perr = PR_GetError();
1627 if ((perr != PR_CONNECT_RESET_ERROR &&
1628 perr != PR_PENDING_INTERRUPT_ERROR) || verbose) {
1629 errWarn("PR_Accept");
1630 }
1631 if (perr == PR_CONNECT_RESET_ERROR) {
1632 FPRINTF(stderr,
1633 "Ignoring PR_CONNECT_RESET_ERROR error - continue\n");
1634 continue;
1635 }
1636 stopping = 1;
1637 break;
1638 }
1640 VLOG(("selfserv: do_accept: Got connection\n"));
1642 if (logStats) {
1643 PR_ATOMIC_INCREMENT(&loggerOps);
1644 }
1646 PZ_Lock(qLock);
1647 while (PR_CLIST_IS_EMPTY(&freeJobs) && !stopping) {
1648 PZ_WaitCondVar(freeListNotEmptyCv, PR_INTERVAL_NO_TIMEOUT);
1649 }
1650 if (stopping) {
1651 PZ_Unlock(qLock);
1652 if (tcp_sock) {
1653 PR_Close(tcp_sock);
1654 }
1655 break;
1656 }
1657 myLink = PR_LIST_HEAD(&freeJobs);
1658 PR_REMOVE_AND_INIT_LINK(myLink);
1659 /* could release qLock here and reaquire it 7 lines below, but
1660 ** why bother for 4 assignment statements?
1661 */
1662 {
1663 JOB * myJob = (JOB *)myLink;
1664 myJob->tcp_sock = tcp_sock;
1665 myJob->model_sock = model_sock;
1666 myJob->requestCert = requestCert;
1667 }
1669 PR_APPEND_LINK(myLink, &jobQ);
1670 PZ_NotifyCondVar(jobQNotEmptyCv);
1671 PZ_Unlock(qLock);
1672 }
1674 FPRINTF(stderr, "selfserv: Closing listen socket.\n");
1675 VLOG(("selfserv: do_accepts: exiting"));
1676 if (listen_sock) {
1677 PR_Close(listen_sock);
1678 }
1679 return SECSuccess;
1680 }
1682 PRFileDesc *
1683 getBoundListenSocket(unsigned short port)
1684 {
1685 PRFileDesc * listen_sock;
1686 int listenQueueDepth = 5 + (2 * maxThreads);
1687 PRStatus prStatus;
1688 PRNetAddr addr;
1689 PRSocketOptionData opt;
1691 addr.inet.family = PR_AF_INET;
1692 addr.inet.ip = PR_INADDR_ANY;
1693 addr.inet.port = PR_htons(port);
1695 listen_sock = PR_NewTCPSocket();
1696 if (listen_sock == NULL) {
1697 errExit("PR_NewTCPSocket");
1698 }
1700 opt.option = PR_SockOpt_Nonblocking;
1701 opt.value.non_blocking = PR_FALSE;
1702 prStatus = PR_SetSocketOption(listen_sock, &opt);
1703 if (prStatus < 0) {
1704 PR_Close(listen_sock);
1705 errExit("PR_SetSocketOption(PR_SockOpt_Nonblocking)");
1706 }
1708 opt.option=PR_SockOpt_Reuseaddr;
1709 opt.value.reuse_addr = PR_TRUE;
1710 prStatus = PR_SetSocketOption(listen_sock, &opt);
1711 if (prStatus < 0) {
1712 PR_Close(listen_sock);
1713 errExit("PR_SetSocketOption(PR_SockOpt_Reuseaddr)");
1714 }
1716 #ifndef WIN95
1717 /* Set PR_SockOpt_Linger because it helps prevent a server bind issue
1718 * after clean shutdown . See bug 331413 .
1719 * Don't do it in the WIN95 build configuration because clean shutdown is
1720 * not implemented, and PR_SockOpt_Linger causes a hang in ssl.sh .
1721 * See bug 332348 */
1722 opt.option=PR_SockOpt_Linger;
1723 opt.value.linger.polarity = PR_TRUE;
1724 opt.value.linger.linger = PR_SecondsToInterval(1);
1725 prStatus = PR_SetSocketOption(listen_sock, &opt);
1726 if (prStatus < 0) {
1727 PR_Close(listen_sock);
1728 errExit("PR_SetSocketOption(PR_SockOpt_Linger)");
1729 }
1730 #endif
1732 prStatus = PR_Bind(listen_sock, &addr);
1733 if (prStatus < 0) {
1734 PR_Close(listen_sock);
1735 errExit("PR_Bind");
1736 }
1738 prStatus = PR_Listen(listen_sock, listenQueueDepth);
1739 if (prStatus < 0) {
1740 PR_Close(listen_sock);
1741 errExit("PR_Listen");
1742 }
1743 return listen_sock;
1744 }
1746 PRInt32 PR_CALLBACK
1747 logWritev (
1748 PRFileDesc *fd,
1749 const PRIOVec *iov,
1750 PRInt32 size,
1751 PRIntervalTime timeout )
1752 {
1753 PRInt32 rv = (fd->lower->methods->writev)(fd->lower, iov, size,
1754 timeout);
1755 /* Add the amount written, but not if there's an error */
1756 if (rv > 0)
1757 PR_ATOMIC_ADD(&loggerBytesTCP, rv);
1758 return rv;
1759 }
1761 PRInt32 PR_CALLBACK
1762 logWrite (
1763 PRFileDesc *fd,
1764 const void *buf,
1765 PRInt32 amount)
1766 {
1767 PRInt32 rv = (fd->lower->methods->write)(fd->lower, buf, amount);
1768 /* Add the amount written, but not if there's an error */
1769 if (rv > 0)
1770 PR_ATOMIC_ADD(&loggerBytesTCP, rv);
1772 return rv;
1773 }
1775 PRInt32 PR_CALLBACK
1776 logSend (
1777 PRFileDesc *fd,
1778 const void *buf,
1779 PRInt32 amount,
1780 PRIntn flags,
1781 PRIntervalTime timeout)
1782 {
1783 PRInt32 rv = (fd->lower->methods->send)(fd->lower, buf, amount,
1784 flags, timeout);
1785 /* Add the amount written, but not if there's an error */
1786 if (rv > 0)
1787 PR_ATOMIC_ADD(&loggerBytesTCP, rv);
1788 return rv;
1789 }
1791 void initLoggingLayer(void)
1792 {
1793 /* get a new layer ID */
1794 log_layer_id = PR_GetUniqueIdentity("Selfserv Logging");
1795 if (log_layer_id == PR_INVALID_IO_LAYER)
1796 errExit("PR_GetUniqueIdentity");
1798 /* setup the default IO methods with my custom write methods */
1799 memcpy(&loggingMethods, PR_GetDefaultIOMethods(), sizeof(PRIOMethods));
1800 loggingMethods.writev = logWritev;
1801 loggingMethods.write = logWrite;
1802 loggingMethods.send = logSend;
1803 }
1805 void
1806 handshakeCallback(PRFileDesc *fd, void *client_data)
1807 {
1808 const char *handshakeName = (const char *)client_data;
1809 if (handshakeName && !failedToNegotiateName) {
1810 SECItem *hostInfo = SSL_GetNegotiatedHostInfo(fd);
1811 if (!hostInfo || PORT_Strncmp(handshakeName, (char*)hostInfo->data,
1812 hostInfo->len)) {
1813 failedToNegotiateName = PR_TRUE;
1814 }
1815 }
1816 }
1818 void
1819 server_main(
1820 PRFileDesc * listen_sock,
1821 int requestCert,
1822 SECKEYPrivateKey ** privKey,
1823 CERTCertificate ** cert,
1824 const char *expectedHostNameVal)
1825 {
1826 PRFileDesc *model_sock = NULL;
1827 int rv;
1828 SSLKEAType kea;
1829 SECStatus secStatus;
1831 if (useModelSocket) {
1832 model_sock = PR_NewTCPSocket();
1833 if (model_sock == NULL) {
1834 errExit("PR_NewTCPSocket on model socket");
1835 }
1836 model_sock = SSL_ImportFD(NULL, model_sock);
1837 if (model_sock == NULL) {
1838 errExit("SSL_ImportFD");
1839 }
1840 } else {
1841 model_sock = listen_sock = SSL_ImportFD(NULL, listen_sock);
1842 if (listen_sock == NULL) {
1843 errExit("SSL_ImportFD");
1844 }
1845 }
1847 /* do SSL configuration. */
1848 rv = SSL_OptionSet(model_sock, SSL_SECURITY,
1849 enableSSL2 || enabledVersions.min != 0);
1850 if (rv < 0) {
1851 errExit("SSL_OptionSet SSL_SECURITY");
1852 }
1854 rv = SSL_VersionRangeSet(model_sock, &enabledVersions);
1855 if (rv != SECSuccess) {
1856 errExit("error setting SSL/TLS version range ");
1857 }
1859 rv = SSL_OptionSet(model_sock, SSL_ENABLE_SSL2, enableSSL2);
1860 if (rv != SECSuccess) {
1861 errExit("error enabling SSLv2 ");
1862 }
1864 rv = SSL_OptionSet(model_sock, SSL_ROLLBACK_DETECTION, !disableRollBack);
1865 if (rv != SECSuccess) {
1866 errExit("error enabling RollBack detection ");
1867 }
1868 if (disableStepDown) {
1869 rv = SSL_OptionSet(model_sock, SSL_NO_STEP_DOWN, PR_TRUE);
1870 if (rv != SECSuccess) {
1871 errExit("error disabling SSL StepDown ");
1872 }
1873 }
1874 if (bypassPKCS11) {
1875 rv = SSL_OptionSet(model_sock, SSL_BYPASS_PKCS11, PR_TRUE);
1876 if (rv != SECSuccess) {
1877 errExit("error enabling PKCS11 bypass ");
1878 }
1879 }
1880 if (disableLocking) {
1881 rv = SSL_OptionSet(model_sock, SSL_NO_LOCKS, PR_TRUE);
1882 if (rv != SECSuccess) {
1883 errExit("error disabling SSL socket locking ");
1884 }
1885 }
1886 if (enableSessionTickets) {
1887 rv = SSL_OptionSet(model_sock, SSL_ENABLE_SESSION_TICKETS, PR_TRUE);
1888 if (rv != SECSuccess) {
1889 errExit("error enabling Session Ticket extension ");
1890 }
1891 }
1893 if (enableCompression) {
1894 rv = SSL_OptionSet(model_sock, SSL_ENABLE_DEFLATE, PR_TRUE);
1895 if (rv != SECSuccess) {
1896 errExit("error enabling compression ");
1897 }
1898 }
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 }
1908 for (kea = kt_rsa; kea < kt_kea_size; kea++) {
1909 if (cert[kea] != NULL) {
1910 secStatus = SSL_ConfigSecureServer(model_sock,
1911 cert[kea], privKey[kea], kea);
1912 if (secStatus != SECSuccess)
1913 errExit("SSL_ConfigSecureServer");
1914 }
1915 }
1917 if (bigBuf.data) { /* doing FDX */
1918 rv = SSL_OptionSet(model_sock, SSL_ENABLE_FDX, 1);
1919 if (rv < 0) {
1920 errExit("SSL_OptionSet SSL_ENABLE_FDX");
1921 }
1922 }
1924 if (NoReuse) {
1925 rv = SSL_OptionSet(model_sock, SSL_NO_CACHE, 1);
1926 if (rv < 0) {
1927 errExit("SSL_OptionSet SSL_NO_CACHE");
1928 }
1929 }
1931 /* This cipher is not on by default. The Acceptance test
1932 * would like it to be. Turn this cipher on.
1933 */
1935 secStatus = SSL_CipherPrefSetDefault( TLS_RSA_WITH_NULL_MD5, PR_TRUE);
1936 if ( secStatus != SECSuccess ) {
1937 errExit("SSL_CipherPrefSetDefault:TLS_RSA_WITH_NULL_MD5");
1938 }
1940 if (expectedHostNameVal) {
1941 SSL_HandshakeCallback(model_sock, handshakeCallback,
1942 (void*)expectedHostNameVal);
1943 }
1945 if (requestCert) {
1946 SSL_AuthCertificateHook(model_sock, mySSLAuthCertificate,
1947 (void *)CERT_GetDefaultCertDB());
1948 if (requestCert <= 2) {
1949 rv = SSL_OptionSet(model_sock, SSL_REQUEST_CERTIFICATE, 1);
1950 if (rv < 0) {
1951 errExit("first SSL_OptionSet SSL_REQUEST_CERTIFICATE");
1952 }
1953 rv = SSL_OptionSet(model_sock, SSL_REQUIRE_CERTIFICATE,
1954 (requestCert == 2));
1955 if (rv < 0) {
1956 errExit("first SSL_OptionSet SSL_REQUIRE_CERTIFICATE");
1957 }
1958 }
1959 }
1961 if (MakeCertOK)
1962 SSL_BadCertHook(model_sock, myBadCertHandler, NULL);
1964 /* end of ssl configuration. */
1967 /* Now, do the accepting, here in the main thread. */
1968 rv = do_accepts(listen_sock, model_sock, requestCert);
1970 terminateWorkerThreads();
1972 if (useModelSocket && model_sock) {
1973 if (model_sock) {
1974 PR_Close(model_sock);
1975 }
1976 }
1978 }
1980 SECStatus
1981 readBigFile(const char * fileName)
1982 {
1983 PRFileInfo info;
1984 PRStatus status;
1985 SECStatus rv = SECFailure;
1986 int count;
1987 int hdrLen;
1988 PRFileDesc *local_file_fd = NULL;
1990 status = PR_GetFileInfo(fileName, &info);
1992 if (status == PR_SUCCESS &&
1993 info.type == PR_FILE_FILE &&
1994 info.size > 0 &&
1995 NULL != (local_file_fd = PR_Open(fileName, PR_RDONLY, 0))) {
1997 hdrLen = PORT_Strlen(outHeader);
1998 bigBuf.len = hdrLen + info.size;
1999 bigBuf.data = PORT_Malloc(bigBuf.len + 4095);
2000 if (!bigBuf.data) {
2001 errWarn("PORT_Malloc");
2002 goto done;
2003 }
2005 PORT_Memcpy(bigBuf.data, outHeader, hdrLen);
2007 count = PR_Read(local_file_fd, bigBuf.data + hdrLen, info.size);
2008 if (count != info.size) {
2009 errWarn("PR_Read local file");
2010 goto done;
2011 }
2012 rv = SECSuccess;
2013 done:
2014 if (local_file_fd) {
2015 PR_Close(local_file_fd);
2016 }
2017 }
2018 return rv;
2019 }
2021 int numChildren;
2022 PRProcess * child[MAX_PROCS];
2024 PRProcess *
2025 haveAChild(int argc, char **argv, PRProcessAttr * attr)
2026 {
2027 PRProcess * newProcess;
2029 newProcess = PR_CreateProcess(argv[0], argv, NULL, attr);
2030 if (!newProcess) {
2031 errWarn("Can't create new process.");
2032 } else {
2033 child[numChildren++] = newProcess;
2034 }
2035 return newProcess;
2036 }
2038 void
2039 beAGoodParent(int argc, char **argv, int maxProcs, PRFileDesc * listen_sock)
2040 {
2041 PRProcess * newProcess;
2042 PRProcessAttr * attr;
2043 int i;
2044 PRInt32 exitCode;
2045 PRStatus rv;
2047 rv = PR_SetFDInheritable(listen_sock, PR_TRUE);
2048 if (rv != PR_SUCCESS)
2049 errExit("PR_SetFDInheritable");
2051 attr = PR_NewProcessAttr();
2052 if (!attr)
2053 errExit("PR_NewProcessAttr");
2055 rv = PR_ProcessAttrSetInheritableFD(attr, listen_sock, inheritableSockName);
2056 if (rv != PR_SUCCESS)
2057 errExit("PR_ProcessAttrSetInheritableFD");
2059 for (i = 0; i < maxProcs; ++i) {
2060 newProcess = haveAChild(argc, argv, attr);
2061 if (!newProcess)
2062 break;
2063 }
2065 rv = PR_SetFDInheritable(listen_sock, PR_FALSE);
2066 if (rv != PR_SUCCESS)
2067 errExit("PR_SetFDInheritable");
2069 while (numChildren > 0) {
2070 newProcess = child[numChildren - 1];
2071 PR_WaitProcess(newProcess, &exitCode);
2072 fprintf(stderr, "Child %d exited with exit code %x\n",
2073 numChildren, exitCode);
2074 numChildren--;
2075 }
2076 exit(0);
2077 }
2079 #define HEXCHAR_TO_INT(c, i) \
2080 if (((c) >= '0') && ((c) <= '9')) { \
2081 i = (c) - '0'; \
2082 } else if (((c) >= 'a') && ((c) <= 'f')) { \
2083 i = (c) - 'a' + 10; \
2084 } else if (((c) >= 'A') && ((c) <= 'F')) { \
2085 i = (c) - 'A' + 10; \
2086 } else if ((c) == '\0') { \
2087 fprintf(stderr, "Invalid length of cipher string (-c :WXYZ).\n"); \
2088 exit(9); \
2089 } else { \
2090 fprintf(stderr, "Non-hex char in cipher string (-c :WXYZ).\n"); \
2091 exit(9); \
2092 }
2094 SECStatus enableOCSPStapling(const char* mode)
2095 {
2096 if (!strcmp(mode, "good")) {
2097 ocspStaplingMode = osm_good;
2098 return SECSuccess;
2099 }
2100 if (!strcmp(mode, "unknown")) {
2101 ocspStaplingMode = osm_unknown;
2102 return SECSuccess;
2103 }
2104 if (!strcmp(mode, "revoked")) {
2105 ocspStaplingMode = osm_revoked;
2106 return SECSuccess;
2107 }
2108 if (!strcmp(mode, "badsig")) {
2109 ocspStaplingMode = osm_badsig;
2110 return SECSuccess;
2111 }
2112 if (!strcmp(mode, "corrupted")) {
2113 ocspStaplingMode = osm_corrupted;
2114 return SECSuccess;
2115 }
2116 if (!strcmp(mode, "failure")) {
2117 ocspStaplingMode = osm_failure;
2118 return SECSuccess;
2119 }
2120 if (!strcmp(mode, "random")) {
2121 ocspStaplingMode = osm_random;
2122 return SECSuccess;
2123 }
2124 if (!strcmp(mode, "ocsp")) {
2125 ocspStaplingMode = osm_ocsp;
2126 return SECSuccess;
2127 }
2128 return SECFailure;
2129 }
2131 int
2132 main(int argc, char **argv)
2133 {
2134 char * progName = NULL;
2135 char * nickName = NULL;
2136 #ifndef NSS_DISABLE_ECC
2137 char * ecNickName = NULL;
2138 #endif
2139 const char * fileName = NULL;
2140 char * cipherString= NULL;
2141 const char * dir = ".";
2142 char * passwd = NULL;
2143 char * pwfile = NULL;
2144 const char * pidFile = NULL;
2145 char * tmp;
2146 char * envString;
2147 PRFileDesc * listen_sock;
2148 CERTCertificate * cert [kt_kea_size] = { NULL };
2149 SECKEYPrivateKey * privKey[kt_kea_size] = { NULL };
2150 int optionsFound = 0;
2151 int maxProcs = 1;
2152 unsigned short port = 0;
2153 SECStatus rv;
2154 PRStatus prStatus;
2155 PRBool bindOnly = PR_FALSE;
2156 PRBool useExportPolicy = PR_FALSE;
2157 PRBool useLocalThreads = PR_FALSE;
2158 PLOptState *optstate;
2159 PLOptStatus status;
2160 PRThread *loggerThread = NULL;
2161 PRBool debugCache = PR_FALSE; /* bug 90518 */
2162 char emptyString[] = { "" };
2163 char* certPrefix = emptyString;
2164 PRUint32 protos = 0;
2165 SSL3Statistics *ssl3stats;
2166 PRUint32 i;
2167 secuPWData pwdata = { PW_NONE, 0 };
2168 char *expectedHostNameVal = NULL;
2169 PLArenaPool *certStatusArena = NULL;
2171 tmp = strrchr(argv[0], '/');
2172 tmp = tmp ? tmp + 1 : argv[0];
2173 progName = strrchr(tmp, '\\');
2174 progName = progName ? progName + 1 : tmp;
2176 PR_Init( PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
2177 SSL_VersionRangeGetSupported(ssl_variant_stream, &enabledVersions);
2179 /* please keep this list of options in ASCII collating sequence.
2180 ** numbers, then capital letters, then lower case, alphabetical.
2181 */
2182 optstate = PL_CreateOptState(argc, argv,
2183 "2:A:BC:DEL:M:NP:RT:V:Ya:bc:d:e:f:g:hi:jk:lmn:op:qrst:uvw:xyz");
2184 while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
2185 ++optionsFound;
2186 switch(optstate->option) {
2187 case '2': fileName = optstate->value; break;
2189 case 'A': ocspStaplingCA = PORT_Strdup(optstate->value); break;
2191 case 'B': bypassPKCS11 = PR_TRUE; break;
2193 case 'C': if (optstate->value) NumSidCacheEntries = PORT_Atoi(optstate->value); break;
2195 case 'D': noDelay = PR_TRUE; break;
2196 case 'E': disableStepDown = PR_TRUE; break;
2198 case 'I': /* reserved for OCSP multi-stapling */ break;
2200 case 'L':
2201 logStats = PR_TRUE;
2202 if (optstate->value == NULL) {
2203 logPeriod = 30;
2204 } else {
2205 logPeriod = PORT_Atoi(optstate->value);
2206 if (logPeriod <= 0) logPeriod = 30;
2207 }
2208 break;
2210 case 'M':
2211 maxProcs = PORT_Atoi(optstate->value);
2212 if (maxProcs < 1) maxProcs = 1;
2213 if (maxProcs > MAX_PROCS) maxProcs = MAX_PROCS;
2214 break;
2216 case 'N': NoReuse = PR_TRUE; break;
2218 case 'R': disableRollBack = PR_TRUE; break;
2220 case 'T':
2221 if (enableOCSPStapling(optstate->value) != SECSuccess) {
2222 fprintf(stderr, "Invalid OCSP stapling mode.\n");
2223 fprintf(stderr, "Run '%s -h' for usage information.\n", progName);
2224 exit(53);
2225 }
2226 break;
2228 case 'V': if (SECU_ParseSSLVersionRangeString(optstate->value,
2229 enabledVersions, enableSSL2,
2230 &enabledVersions, &enableSSL2) != SECSuccess) {
2231 Usage(progName);
2232 }
2233 break;
2235 case 'Y': PrintCipherUsage(progName); exit(0); break;
2237 case 'a': if (virtServerNameIndex >= MAX_VIRT_SERVER_NAME_ARRAY_INDEX) {
2238 Usage(progName);
2239 }
2240 virtServerNameArray[virtServerNameIndex++] =
2241 PORT_Strdup(optstate->value); break;
2243 case 'b': bindOnly = PR_TRUE; break;
2245 case 'c': cipherString = PORT_Strdup(optstate->value); break;
2247 case 'd': dir = optstate->value; break;
2249 #ifndef NSS_DISABLE_ECC
2250 case 'e': ecNickName = PORT_Strdup(optstate->value); break;
2251 #endif /* NSS_DISABLE_ECC */
2253 case 'f':
2254 pwdata.source = PW_FROMFILE;
2255 pwdata.data = pwfile = PORT_Strdup(optstate->value);
2256 break;
2258 case 'g':
2259 testBulk = PR_TRUE;
2260 testBulkTotal = PORT_Atoi(optstate->value);
2261 break;
2263 case 'h': Usage(progName); exit(0); break;
2265 case 'i': pidFile = optstate->value; break;
2267 case 'j':
2268 initLoggingLayer();
2269 loggingLayer = PR_TRUE;
2270 break;
2272 case 'k': expectedHostNameVal = PORT_Strdup(optstate->value);
2273 break;
2275 case 'l': useLocalThreads = PR_TRUE; break;
2277 case 'm': useModelSocket = PR_TRUE; break;
2279 case 'n': nickName = PORT_Strdup(optstate->value);
2280 virtServerNameArray[0] = PORT_Strdup(optstate->value);
2281 break;
2283 case 'P': certPrefix = PORT_Strdup(optstate->value); break;
2285 case 'o': MakeCertOK = 1; break;
2287 case 'p': port = PORT_Atoi(optstate->value); break;
2289 case 'q': testbypass = PR_TRUE; break;
2291 case 'r': ++requestCert; break;
2293 case 's': disableLocking = PR_TRUE; break;
2295 case 't':
2296 maxThreads = PORT_Atoi(optstate->value);
2297 if ( maxThreads > MAX_THREADS ) maxThreads = MAX_THREADS;
2298 if ( maxThreads < MIN_THREADS ) maxThreads = MIN_THREADS;
2299 break;
2301 case 'u': enableSessionTickets = PR_TRUE; break;
2303 case 'v': verbose++; break;
2305 case 'w':
2306 pwdata.source = PW_PLAINTEXT;
2307 pwdata.data = passwd = PORT_Strdup(optstate->value);
2308 break;
2310 case 'x': useExportPolicy = PR_TRUE; break;
2312 case 'y': debugCache = PR_TRUE; break;
2314 case 'z': enableCompression = PR_TRUE; break;
2316 default:
2317 case '?':
2318 fprintf(stderr, "Unrecognized or bad option specified.\n");
2319 fprintf(stderr, "Run '%s -h' for usage information.\n", progName);
2320 exit(4);
2321 break;
2322 }
2323 }
2324 PL_DestroyOptState(optstate);
2325 if (status == PL_OPT_BAD) {
2326 fprintf(stderr, "Unrecognized or bad option specified.\n");
2327 fprintf(stderr, "Run '%s -h' for usage information.\n", progName);
2328 exit(5);
2329 }
2330 if (!optionsFound) {
2331 Usage(progName);
2332 exit(51);
2333 }
2334 switch (ocspStaplingMode) {
2335 case osm_good:
2336 case osm_revoked:
2337 case osm_unknown:
2338 case osm_random:
2339 if (!ocspStaplingCA) {
2340 fprintf(stderr, "Selected stapling response requires the -A parameter.\n");
2341 fprintf(stderr, "Run '%s -h' for usage information.\n", progName);
2342 exit(52);
2343 }
2344 break;
2345 default:
2346 break;
2347 }
2349 /* The -b (bindOnly) option is only used by the ssl.sh test
2350 * script on Linux to determine whether a previous selfserv
2351 * process has fully died and freed the port. (Bug 129701)
2352 */
2353 if (bindOnly) {
2354 listen_sock = getBoundListenSocket(port);
2355 if (!listen_sock) {
2356 exit(1);
2357 }
2358 if (listen_sock) {
2359 PR_Close(listen_sock);
2360 }
2361 exit(0);
2362 }
2364 if ((nickName == NULL)
2365 #ifndef NSS_DISABLE_ECC
2366 && (ecNickName == NULL)
2367 #endif
2368 ) {
2370 fprintf(stderr, "Required arg '-n' (rsa nickname) not supplied.\n");
2371 fprintf(stderr, "Run '%s -h' for usage information.\n", progName);
2372 exit(6);
2373 }
2375 if (port == 0) {
2376 fprintf(stderr, "Required argument 'port' must be non-zero value\n");
2377 exit(7);
2378 }
2380 if (NoReuse && maxProcs > 1) {
2381 fprintf(stderr, "-M and -N options are mutually exclusive.\n");
2382 exit(14);
2383 }
2385 if (pidFile) {
2386 FILE *tmpfile=fopen(pidFile,"w+");
2388 if (tmpfile) {
2389 fprintf(tmpfile,"%d",getpid());
2390 fclose(tmpfile);
2391 }
2392 }
2394 /* allocate and initialize app data for bulk encryption testing */
2395 if (testBulk) {
2396 testBulkBuf = PORT_Malloc(testBulkSize);
2397 if (testBulkBuf == NULL)
2398 errExit("Out of memory: testBulkBuf");
2399 for (i = 0; i < testBulkSize; i++)
2400 testBulkBuf[i] = i;
2401 }
2403 envString = getenv(envVarName);
2404 tmp = getenv("TMP");
2405 if (!tmp)
2406 tmp = getenv("TMPDIR");
2407 if (!tmp)
2408 tmp = getenv("TEMP");
2409 if (envString) {
2410 /* we're one of the children in a multi-process server. */
2411 listen_sock = PR_GetInheritedFD(inheritableSockName);
2412 if (!listen_sock)
2413 errExit("PR_GetInheritedFD");
2414 #ifndef WINNT
2415 /* we can't do this on NT because it breaks NSPR and
2416 PR_Accept will fail on the socket in the child process if
2417 the socket state is change to non inheritable
2418 It is however a security issue to leave it accessible,
2419 but it is OK for a test server such as selfserv.
2420 NSPR should fix it eventually . see bugzilla 101617
2421 and 102077
2422 */
2423 prStatus = PR_SetFDInheritable(listen_sock, PR_FALSE);
2424 if (prStatus != PR_SUCCESS)
2425 errExit("PR_SetFDInheritable");
2426 #endif
2427 rv = SSL_InheritMPServerSIDCache(envString);
2428 if (rv != SECSuccess)
2429 errExit("SSL_InheritMPServerSIDCache");
2430 hasSidCache = PR_TRUE;
2431 } else if (maxProcs > 1) {
2432 /* we're going to be the parent in a multi-process server. */
2433 listen_sock = getBoundListenSocket(port);
2434 rv = SSL_ConfigMPServerSIDCache(NumSidCacheEntries, 0, 0, tmp);
2435 if (rv != SECSuccess)
2436 errExit("SSL_ConfigMPServerSIDCache");
2437 hasSidCache = PR_TRUE;
2438 beAGoodParent(argc, argv, maxProcs, listen_sock);
2439 exit(99); /* should never get here */
2440 } else {
2441 /* we're an ordinary single process server. */
2442 listen_sock = getBoundListenSocket(port);
2443 prStatus = PR_SetFDInheritable(listen_sock, PR_FALSE);
2444 if (prStatus != PR_SUCCESS)
2445 errExit("PR_SetFDInheritable");
2446 if (!NoReuse) {
2447 rv = SSL_ConfigServerSessionIDCache(NumSidCacheEntries,
2448 0, 0, tmp);
2449 if (rv != SECSuccess)
2450 errExit("SSL_ConfigServerSessionIDCache");
2451 hasSidCache = PR_TRUE;
2452 }
2453 }
2455 lm = PR_NewLogModule("TestCase");
2457 if (fileName)
2458 readBigFile(fileName);
2460 /* set our password function */
2461 PK11_SetPasswordFunc(SECU_GetModulePassword);
2463 /* Call the NSS initialization routines */
2464 rv = NSS_Initialize(dir, certPrefix, certPrefix, SECMOD_DB, NSS_INIT_READONLY);
2465 if (rv != SECSuccess) {
2466 fputs("NSS_Init failed.\n", stderr);
2467 exit(8);
2468 }
2470 /* set the policy bits true for all the cipher suites. */
2471 if (useExportPolicy) {
2472 NSS_SetExportPolicy();
2473 if (disableStepDown) {
2474 fputs("selfserv: -x and -E options may not be used together\n",
2475 stderr);
2476 exit(98);
2477 }
2478 } else {
2479 NSS_SetDomesticPolicy();
2480 if (disableStepDown) {
2481 rv = disableExportSSLCiphers();
2482 if (rv != SECSuccess) {
2483 errExit("error disabling export ciphersuites ");
2484 }
2485 }
2486 }
2488 /* all the SSL2 and SSL3 cipher suites are enabled by default. */
2489 if (cipherString) {
2490 char *cstringSaved = cipherString;
2491 int ndx;
2493 /* disable all the ciphers, then enable the ones we want. */
2494 disableAllSSLCiphers();
2496 while (0 != (ndx = *cipherString++)) {
2497 int cipher;
2499 if (ndx == ':') {
2500 int ctmp;
2502 cipher = 0;
2503 HEXCHAR_TO_INT(*cipherString, ctmp)
2504 cipher |= (ctmp << 12);
2505 cipherString++;
2506 HEXCHAR_TO_INT(*cipherString, ctmp)
2507 cipher |= (ctmp << 8);
2508 cipherString++;
2509 HEXCHAR_TO_INT(*cipherString, ctmp)
2510 cipher |= (ctmp << 4);
2511 cipherString++;
2512 HEXCHAR_TO_INT(*cipherString, ctmp)
2513 cipher |= ctmp;
2514 cipherString++;
2515 } else {
2516 const int *cptr;
2518 if (! isalpha(ndx)) {
2519 fprintf(stderr,
2520 "Non-alphabetic char in cipher string (-c arg).\n");
2521 exit(9);
2522 }
2523 cptr = islower(ndx) ? ssl3CipherSuites : ssl2CipherSuites;
2524 for (ndx &= 0x1f; (cipher = *cptr++) != 0 && --ndx > 0; )
2525 /* do nothing */;
2526 }
2527 if (cipher > 0) {
2528 SECStatus status;
2529 status = SSL_CipherPrefSetDefault(cipher, SSL_ALLOWED);
2530 if (status != SECSuccess)
2531 SECU_PrintError(progName, "SSL_CipherPrefSet()");
2532 } else {
2533 fprintf(stderr,
2534 "Invalid cipher specification (-c arg).\n");
2535 exit(9);
2536 }
2537 }
2538 PORT_Free(cstringSaved);
2539 }
2541 if (testbypass) {
2542 const PRUint16 *cipherSuites = SSL_ImplementedCiphers;
2543 int i = SSL_NumImplementedCiphers;
2544 PRBool enabled;
2546 for (i=0; i < SSL_NumImplementedCiphers; i++, cipherSuites++) {
2547 if (SSL_CipherPrefGetDefault(*cipherSuites, &enabled) == SECSuccess
2548 && enabled)
2549 savecipher(*cipherSuites);
2550 }
2551 protos = 0;
2552 if (enabledVersions.min <= SSL_LIBRARY_VERSION_3_0 &&
2553 enabledVersions.max >= SSL_LIBRARY_VERSION_3_0) {
2554 protos |= SSL_CBP_SSL3;
2555 }
2556 if (enabledVersions.min <= SSL_LIBRARY_VERSION_TLS_1_0 &&
2557 enabledVersions.max >= SSL_LIBRARY_VERSION_TLS_1_0) {
2558 protos |= SSL_CBP_TLS1_0;
2559 }
2560 /* TLS 1.1 has the same SSL Bypass mode requirements as TLS 1.0 */
2561 if (enabledVersions.min <= SSL_LIBRARY_VERSION_TLS_1_1 &&
2562 enabledVersions.max >= SSL_LIBRARY_VERSION_TLS_1_1) {
2563 protos |= SSL_CBP_TLS1_0;
2564 }
2565 }
2567 certStatusArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
2568 if (!certStatusArena)
2569 errExit("cannot allocate certStatusArena");
2571 if (nickName) {
2572 cert[kt_rsa] = PK11_FindCertFromNickname(nickName, &pwdata);
2573 if (cert[kt_rsa] == NULL) {
2574 fprintf(stderr, "selfserv: Can't find certificate %s\n", nickName);
2575 exit(10);
2576 }
2577 privKey[kt_rsa] = PK11_FindKeyByAnyCert(cert[kt_rsa], &pwdata);
2578 if (privKey[kt_rsa] == NULL) {
2579 fprintf(stderr, "selfserv: Can't find Private Key for cert %s\n",
2580 nickName);
2581 exit(11);
2582 }
2583 if (testbypass) {
2584 PRBool bypassOK;
2585 if (SSL_CanBypass(cert[kt_rsa], privKey[kt_rsa], protos, cipherlist,
2586 nciphers, &bypassOK, &pwdata) != SECSuccess) {
2587 SECU_PrintError(progName, "Bypass test failed %s\n", nickName);
2588 exit(14);
2589 }
2590 fprintf(stderr, "selfserv: %s can%s bypass\n", nickName,
2591 bypassOK ? "" : "not");
2592 }
2593 setupCertStatus(certStatusArena, ocspStaplingMode, cert[kt_rsa], kt_rsa,
2594 &pwdata);
2595 }
2596 #ifndef NSS_DISABLE_ECC
2597 if (ecNickName) {
2598 cert[kt_ecdh] = PK11_FindCertFromNickname(ecNickName, &pwdata);
2599 if (cert[kt_ecdh] == NULL) {
2600 fprintf(stderr, "selfserv: Can't find certificate %s\n",
2601 ecNickName);
2602 exit(13);
2603 }
2604 privKey[kt_ecdh] = PK11_FindKeyByAnyCert(cert[kt_ecdh], &pwdata);
2605 if (privKey[kt_ecdh] == NULL) {
2606 fprintf(stderr, "selfserv: Can't find Private Key for cert %s\n",
2607 ecNickName);
2608 exit(11);
2609 }
2610 if (testbypass) {
2611 PRBool bypassOK;
2612 if (SSL_CanBypass(cert[kt_ecdh], privKey[kt_ecdh], protos, cipherlist,
2613 nciphers, &bypassOK, &pwdata) != SECSuccess) {
2614 SECU_PrintError(progName, "Bypass test failed %s\n", ecNickName);
2615 exit(15);
2616 }
2617 fprintf(stderr, "selfserv: %s can%s bypass\n", ecNickName,
2618 bypassOK ? "" : "not");
2619 }
2620 setupCertStatus(certStatusArena, ocspStaplingMode, cert[kt_ecdh], kt_ecdh,
2621 &pwdata);
2622 }
2623 #endif /* NSS_DISABLE_ECC */
2625 if (testbypass)
2626 goto cleanup;
2628 /* allocate the array of thread slots, and launch the worker threads. */
2629 rv = launch_threads(&jobLoop, 0, 0, requestCert, useLocalThreads);
2631 if (rv == SECSuccess && logStats) {
2632 loggerThread = PR_CreateThread(PR_SYSTEM_THREAD,
2633 logger, NULL, PR_PRIORITY_NORMAL,
2634 useLocalThreads ? PR_LOCAL_THREAD:PR_GLOBAL_THREAD,
2635 PR_JOINABLE_THREAD, 0);
2636 if (loggerThread == NULL) {
2637 fprintf(stderr, "selfserv: Failed to launch logger thread!\n");
2638 rv = SECFailure;
2639 }
2640 }
2642 if (rv == SECSuccess) {
2643 server_main(listen_sock, requestCert, privKey, cert,
2644 expectedHostNameVal);
2645 }
2647 VLOG(("selfserv: server_thread: exiting"));
2649 cleanup:
2650 printSSLStatistics();
2651 ssl3stats = SSL_GetStatistics();
2652 if (ssl3stats->hch_sid_ticket_parse_failures != 0) {
2653 fprintf(stderr, "selfserv: Experienced ticket parse failure(s)\n");
2654 exit(1);
2655 }
2656 if (failedToNegotiateName) {
2657 fprintf(stderr, "selfserv: Failed properly negotiate server name\n");
2658 exit(1);
2659 }
2661 {
2662 int i;
2663 for (i=0; i<kt_kea_size; i++) {
2664 if (cert[i]) {
2665 CERT_DestroyCertificate(cert[i]);
2666 }
2667 if (privKey[i]) {
2668 SECKEY_DestroyPrivateKey(privKey[i]);
2669 }
2670 }
2671 for (i = 0;virtServerNameArray[i];i++) {
2672 PORT_Free(virtServerNameArray[i]);
2673 }
2674 }
2676 if (debugCache) {
2677 nss_DumpCertificateCacheInfo();
2678 }
2679 if (nickName) {
2680 PORT_Free(nickName);
2681 }
2682 if (expectedHostNameVal) {
2683 PORT_Free(expectedHostNameVal);
2684 }
2685 if (passwd) {
2686 PORT_Free(passwd);
2687 }
2688 if (pwfile) {
2689 PORT_Free(pwfile);
2690 }
2691 if (certPrefix && certPrefix != emptyString) {
2692 PORT_Free(certPrefix);
2693 }
2694 #ifndef NSS_DISABLE_ECC
2695 if (ecNickName) {
2696 PORT_Free(ecNickName);
2697 }
2698 #endif
2700 if (hasSidCache) {
2701 SSL_ShutdownServerSessionIDCache();
2702 }
2703 if (certStatusArena) {
2704 PORT_FreeArena(certStatusArena, PR_FALSE);
2705 }
2706 if (NSS_Shutdown() != SECSuccess) {
2707 SECU_PrintError(progName, "NSS_Shutdown");
2708 if (loggerThread) {
2709 PR_JoinThread(loggerThread);
2710 }
2711 PR_Cleanup();
2712 exit(1);
2713 }
2714 PR_Cleanup();
2715 printf("selfserv: normal termination\n");
2716 return 0;
2717 }