security/nss/cmd/selfserv/selfserv.c

Wed, 31 Dec 2014 06:55:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:50 +0100
changeset 2
7e26c7da4463
permissions
-rw-r--r--

Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2

     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);
  1009     VLOG(("selfserv: handle_fdx_connection: exiting"));
  1010     return SECSuccess;
  1013 #endif
  1015 static SECItem *lastLoadedCrl = NULL;
  1017 static SECStatus
  1018 reload_crl(PRFileDesc *crlFile)
  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;
  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;
  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;
  1048             crlDer = lastLoadedCrl;
  1049         } else {
  1050             crlDer = NULL;
  1052         lastLoadedCrl = tempItem;
  1055   loser:
  1056     PR_Unlock(lastLoadedCrlLock);
  1057     SECITEM_FreeItem(crlDer, PR_TRUE);
  1058     return rv;
  1061 void stop_server()
  1063     stopping = 1;
  1064     PR_Interrupt(acceptorThread);
  1065     PZ_TraceFlush();
  1068 SECItemArray *
  1069 makeTryLaterOCSPResponse(PLArenaPool *arena)
  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;
  1089 SECItemArray *
  1090 makeCorruptedOCSPResponse(PLArenaPool *arena)
  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;
  1109 SECItemArray *
  1110 makeSignedOCSPResponse(PLArenaPool *arena, ocspStaplingModeType osm,
  1111 		       CERTCertificate *cert, secuPWData *pwdata)
  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;
  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;
  1189 void
  1190 setupCertStatus(PLArenaPool *arena, enum ocspStaplingModeEnum ocspStaplingMode,
  1191 		CERTCertificate *cert, SSLKEAType kea, secuPWData *pwdata)
  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;
  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;
  1230 	if (multiOcspResponses) {
  1231 	   certStatus[kea] = multiOcspResponses;
  1236 int
  1237 handle_connection( 
  1238     PRFileDesc *tcp_sock,
  1239     PRFileDesc *model_sock,
  1240     int         requestCert
  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;
  1281 	rv = SSL_ResetHandshake(ssl_sock, /* asServer */ 1);
  1282 	if (rv != SECSuccess) {
  1283 	    errWarn("SSL_ResetHandshake");
  1284 	    goto cleanup;
  1286     } else {
  1287 	ssl_sock = tcp_sock;
  1290     for (kea = kt_rsa; kea < kt_kea_size; kea++) {
  1291        if (certStatus[kea] != NULL) {
  1292            SSL_SetStapledOCSPResponses(ssl_sock, certStatus[kea], kea);
  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");
  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");
  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);
  1322 	    return SECFailure;
  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;
  1336 	if (rv < 0) {
  1337 	    errWarn("HDX PR_Read");
  1338 	    goto cleanup;
  1340 	/* NULL termination */
  1341 	pBuf[rv] = 0;
  1342 	if (firstTime) {
  1343 	    firstTime = 0;
  1344 	    printSecurityInfo(ssl_sock);
  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;
  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++;
  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;
  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);
  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;
  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;
  1445 		rv = SSL_ReHandshake(ssl_sock, PR_TRUE);
  1446 		if (rv != 0) {
  1447 		    errWarn("SSL_ReHandshake");
  1448 		    break;
  1450 		rv = SSL_ForceHandshake(ssl_sock);
  1451 		if (rv < 0) {
  1452 		    errWarn("SSL_ForceHandshake");
  1453 		    break;
  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;
  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++;
  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;
  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++;
  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++;
  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++;
  1539 	rv = PR_Writev(ssl_sock, iovs, numIOVs, PR_INTERVAL_NO_TIMEOUT);
  1540 	if (rv < 0) {
  1541 	    errWarn("PR_Writev");
  1542 	    break;
  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;
  1554             /* There was a write error, so close this connection. */
  1555             if (bulkSentChunks <= testBulkTotal) {
  1556                 errWarn("PR_Write");
  1558             PR_ATOMIC_DECREMENT(&loggerOps);
  1559             break;
  1561     } while (0);
  1563 cleanup:
  1564     if (ssl_sock) {
  1565         PR_Close(ssl_sock);
  1566     } else if (tcp_sock) {
  1567         PR_Close(tcp_sock);
  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();
  1578     VLOG(("selfserv: handle_connection: exiting"));
  1579     return SECSuccess;	/* success */
  1582 #ifdef XP_UNIX
  1584 void sigusr1_handler(int sig)
  1586     VLOG(("selfserv: sigusr1_handler: stop server"));
  1587     stop_server();
  1590 #endif
  1592 SECStatus
  1593 do_accepts(
  1594     PRFileDesc *listen_sock,
  1595     PRFileDesc *model_sock,
  1596     int         requestCert
  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);
  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");
  1631 	    if (perr == PR_CONNECT_RESET_ERROR) {
  1632 		FPRINTF(stderr, 
  1633 		        "Ignoring PR_CONNECT_RESET_ERROR error - continue\n");
  1634 		continue;
  1636 	    stopping = 1;
  1637 	    break;
  1640         VLOG(("selfserv: do_accept: Got connection\n"));
  1642         if (logStats) {
  1643             PR_ATOMIC_INCREMENT(&loggerOps);
  1646 	PZ_Lock(qLock);
  1647 	while (PR_CLIST_IS_EMPTY(&freeJobs) && !stopping) {
  1648             PZ_WaitCondVar(freeListNotEmptyCv, PR_INTERVAL_NO_TIMEOUT);
  1650 	if (stopping) {
  1651 	    PZ_Unlock(qLock);
  1652             if (tcp_sock) {
  1653 	        PR_Close(tcp_sock);
  1655 	    break;
  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 	*/
  1663 	    JOB * myJob = (JOB *)myLink;
  1664 	    myJob->tcp_sock    = tcp_sock;
  1665 	    myJob->model_sock  = model_sock;
  1666 	    myJob->requestCert = requestCert;
  1669 	PR_APPEND_LINK(myLink, &jobQ);
  1670 	PZ_NotifyCondVar(jobQNotEmptyCv);
  1671 	PZ_Unlock(qLock);
  1674     FPRINTF(stderr, "selfserv: Closing listen socket.\n");
  1675     VLOG(("selfserv: do_accepts: exiting"));
  1676     if (listen_sock) {
  1677         PR_Close(listen_sock);
  1679     return SECSuccess;
  1682 PRFileDesc *
  1683 getBoundListenSocket(unsigned short port)
  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");
  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)");
  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)");
  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)");
  1730 #endif
  1732     prStatus = PR_Bind(listen_sock, &addr);
  1733     if (prStatus < 0) {
  1734         PR_Close(listen_sock);
  1735 	errExit("PR_Bind");
  1738     prStatus = PR_Listen(listen_sock, listenQueueDepth);
  1739     if (prStatus < 0) {
  1740         PR_Close(listen_sock);
  1741 	errExit("PR_Listen");
  1743     return listen_sock;
  1746 PRInt32 PR_CALLBACK 
  1747 logWritev (
  1748     PRFileDesc     *fd,
  1749     const PRIOVec  *iov,
  1750     PRInt32         size, 
  1751     PRIntervalTime  timeout )
  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;
  1761 PRInt32 PR_CALLBACK 
  1762 logWrite (
  1763     PRFileDesc  *fd, 
  1764     const void  *buf, 
  1765     PRInt32      amount)
  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;
  1775 PRInt32 PR_CALLBACK 
  1776 logSend (
  1777     PRFileDesc     *fd, 
  1778     const void     *buf, 
  1779     PRInt32         amount, 
  1780     PRIntn          flags, 
  1781     PRIntervalTime  timeout)
  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;
  1791 void initLoggingLayer(void)
  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;
  1805 void
  1806 handshakeCallback(PRFileDesc *fd, void *client_data)
  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;
  1818 void
  1819 server_main(
  1820     PRFileDesc *        listen_sock,
  1821     int                 requestCert, 
  1822     SECKEYPrivateKey ** privKey,
  1823     CERTCertificate **  cert,
  1824     const char *expectedHostNameVal)
  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");
  1836 	model_sock = SSL_ImportFD(NULL, model_sock);
  1837 	if (model_sock == NULL) {
  1838 	    errExit("SSL_ImportFD");
  1840     } else {
  1841 	model_sock = listen_sock = SSL_ImportFD(NULL, listen_sock);
  1842 	if (listen_sock == NULL) {
  1843 	    errExit("SSL_ImportFD");
  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");
  1854     rv = SSL_VersionRangeSet(model_sock, &enabledVersions);
  1855     if (rv != SECSuccess) {
  1856 	errExit("error setting SSL/TLS version range ");
  1859     rv = SSL_OptionSet(model_sock, SSL_ENABLE_SSL2, enableSSL2);
  1860     if (rv != SECSuccess) {
  1861        errExit("error enabling SSLv2 ");
  1864     rv = SSL_OptionSet(model_sock, SSL_ROLLBACK_DETECTION, !disableRollBack);
  1865     if (rv != SECSuccess) {
  1866 	errExit("error enabling RollBack detection ");
  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 ");
  1874     if (bypassPKCS11) {
  1875        rv = SSL_OptionSet(model_sock, SSL_BYPASS_PKCS11, PR_TRUE);
  1876 	if (rv != SECSuccess) {
  1877 	    errExit("error enabling PKCS11 bypass ");
  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 ");
  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 ");
  1893     if (enableCompression) {
  1894 	rv = SSL_OptionSet(model_sock, SSL_ENABLE_DEFLATE, PR_TRUE);
  1895 	if (rv != SECSuccess) {
  1896 	    errExit("error enabling compression ");
  1900     if (virtServerNameIndex >1) {
  1901         rv = SSL_SNISocketConfigHook(model_sock, mySSLSNISocketConfig,
  1902                                      (void*)&virtServerNameArray);
  1903         if (rv != SECSuccess) {
  1904             errExit("error enabling SNI extension ");
  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");
  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");
  1924     if (NoReuse) {
  1925         rv = SSL_OptionSet(model_sock, SSL_NO_CACHE, 1);
  1926         if (rv < 0) {
  1927             errExit("SSL_OptionSet SSL_NO_CACHE");
  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");
  1940     if (expectedHostNameVal) {
  1941         SSL_HandshakeCallback(model_sock, handshakeCallback,
  1942                               (void*)expectedHostNameVal);
  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");
  1953 	    rv = SSL_OptionSet(model_sock, SSL_REQUIRE_CERTIFICATE, 
  1954 	                    (requestCert == 2));
  1955 	    if (rv < 0) {
  1956 		errExit("first SSL_OptionSet SSL_REQUIRE_CERTIFICATE");
  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);
  1980 SECStatus
  1981 readBigFile(const char * fileName)
  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;
  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;
  2012 	rv = SECSuccess;
  2013 done:
  2014         if (local_file_fd) {
  2015             PR_Close(local_file_fd);
  2018     return rv;
  2021 int          numChildren;
  2022 PRProcess *  child[MAX_PROCS];
  2024 PRProcess *
  2025 haveAChild(int argc, char **argv, PRProcessAttr * attr)
  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;
  2035     return newProcess;
  2038 void
  2039 beAGoodParent(int argc, char **argv, int maxProcs, PRFileDesc * listen_sock)
  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;
  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--;
  2076     exit(0);
  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); \
  2094 SECStatus enableOCSPStapling(const char* mode)
  2096     if (!strcmp(mode, "good")) {
  2097 	ocspStaplingMode = osm_good;
  2098 	return SECSuccess;
  2100     if (!strcmp(mode, "unknown")) {
  2101 	ocspStaplingMode = osm_unknown;
  2102 	return SECSuccess;
  2104     if (!strcmp(mode, "revoked")) {
  2105 	ocspStaplingMode = osm_revoked;
  2106 	return SECSuccess;
  2108     if (!strcmp(mode, "badsig")) {
  2109 	ocspStaplingMode = osm_badsig;
  2110 	return SECSuccess;
  2112     if (!strcmp(mode, "corrupted")) {
  2113 	ocspStaplingMode = osm_corrupted;
  2114 	return SECSuccess;
  2116     if (!strcmp(mode, "failure")) {
  2117 	ocspStaplingMode = osm_failure;
  2118 	return SECSuccess;
  2120     if (!strcmp(mode, "random")) {
  2121 	ocspStaplingMode = osm_random;
  2122 	return SECSuccess;
  2124     if (!strcmp(mode, "ocsp")) {
  2125 	ocspStaplingMode = osm_ocsp;
  2126 	return SECSuccess;
  2128     return SECFailure;
  2131 int
  2132 main(int argc, char **argv)
  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;
  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);
  2226 	    break;
  2228         case 'V': if (SECU_ParseSSLVersionRangeString(optstate->value,
  2229                           enabledVersions, enableSSL2,
  2230                           &enabledVersions, &enableSSL2) != SECSuccess) {
  2231                       Usage(progName);
  2233                   break;
  2235         case 'Y': PrintCipherUsage(progName); exit(0); break;
  2237 	case 'a': if (virtServerNameIndex >= MAX_VIRT_SERVER_NAME_ARRAY_INDEX) {
  2238                       Usage(progName);
  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;
  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);
  2330     if (!optionsFound) {
  2331 	Usage(progName);
  2332 	exit(51);
  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);
  2344 	    break;
  2345 	default:
  2346 	    break;
  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);
  2358         if (listen_sock) {
  2359             PR_Close(listen_sock);
  2361 	exit(0);
  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);
  2375     if (port == 0) {
  2376 	fprintf(stderr, "Required argument 'port' must be non-zero value\n");
  2377 	exit(7);
  2380     if (NoReuse && maxProcs > 1) {
  2381 	fprintf(stderr, "-M and -N options are mutually exclusive.\n");
  2382 	exit(14);
  2385     if (pidFile) {
  2386 	FILE *tmpfile=fopen(pidFile,"w+");
  2388 	if (tmpfile) {
  2389 	    fprintf(tmpfile,"%d",getpid());
  2390 	    fclose(tmpfile);
  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;
  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;
  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);
  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);
  2478     } else {
  2479 	NSS_SetDomesticPolicy();
  2480 	if (disableStepDown) {
  2481 	    rv = disableExportSSLCiphers();
  2482 	    if (rv != SECSuccess) {
  2483 		errExit("error disabling export ciphersuites ");
  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);
  2523 		cptr = islower(ndx) ? ssl3CipherSuites : ssl2CipherSuites;
  2524 		for (ndx &= 0x1f; (cipher = *cptr++) != 0 && --ndx > 0; ) 
  2525 		    /* do nothing */;
  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);
  2538 	PORT_Free(cstringSaved);
  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);		    
  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;
  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;
  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;
  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);
  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);
  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);
  2590 	    fprintf(stderr, "selfserv: %s can%s bypass\n", nickName,
  2591 		    bypassOK ? "" : "not");
  2593 	setupCertStatus(certStatusArena, ocspStaplingMode, cert[kt_rsa], kt_rsa,
  2594 			&pwdata);
  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);
  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);
  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);
  2617 	    fprintf(stderr, "selfserv: %s can%s bypass\n", ecNickName,
  2618 		    bypassOK ? "" : "not");
  2620 	setupCertStatus(certStatusArena, ocspStaplingMode, cert[kt_ecdh], kt_ecdh,
  2621 			&pwdata);
  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;
  2642     if (rv == SECSuccess) {
  2643 	server_main(listen_sock, requestCert, privKey, cert,
  2644                     expectedHostNameVal);
  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);
  2656     if (failedToNegotiateName) {
  2657         fprintf(stderr, "selfserv: Failed properly negotiate server name\n");
  2658         exit(1);
  2662 	int i;
  2663 	for (i=0; i<kt_kea_size; i++) {
  2664 	    if (cert[i]) {
  2665 		CERT_DestroyCertificate(cert[i]);
  2667 	    if (privKey[i]) {
  2668 		SECKEY_DestroyPrivateKey(privKey[i]);
  2671         for (i = 0;virtServerNameArray[i];i++) {
  2672             PORT_Free(virtServerNameArray[i]);
  2676     if (debugCache) {
  2677 	nss_DumpCertificateCacheInfo();
  2679     if (nickName) {
  2680         PORT_Free(nickName);
  2682     if (expectedHostNameVal) {
  2683         PORT_Free(expectedHostNameVal);
  2685     if (passwd) {
  2686         PORT_Free(passwd);
  2688     if (pwfile) {
  2689         PORT_Free(pwfile);
  2691     if (certPrefix && certPrefix != emptyString) {                            
  2692         PORT_Free(certPrefix);
  2694  #ifndef NSS_DISABLE_ECC
  2695     if (ecNickName) {
  2696         PORT_Free(ecNickName);
  2698  #endif
  2700     if (hasSidCache) {
  2701 	SSL_ShutdownServerSessionIDCache();
  2703     if (certStatusArena) {
  2704 	PORT_FreeArena(certStatusArena, PR_FALSE);
  2706     if (NSS_Shutdown() != SECSuccess) {
  2707 	SECU_PrintError(progName, "NSS_Shutdown");
  2708         if (loggerThread) {
  2709             PR_JoinThread(loggerThread);
  2711 	PR_Cleanup();
  2712 	exit(1);
  2714     PR_Cleanup();
  2715     printf("selfserv: normal termination\n");
  2716     return 0;

mercurial