nss: import at 3.0.1 beta 1
[mozilla-nss.git] / security / nss / cmd / SSLsample / server.c
blobbf4c9075b270ef7c1a25d274ccdb6d797a49940b
1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
12 * License.
14 * The Original Code is the Netscape security libraries.
16 * The Initial Developer of the Original Code is
17 * Netscape Communications Corporation.
18 * Portions created by the Initial Developer are Copyright (C) 1994-2000
19 * the Initial Developer. All Rights Reserved.
21 * Contributor(s):
23 * Alternatively, the contents of this file may be used under the terms of
24 * either the GNU General Public License Version 2 or later (the "GPL"), or
25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 * in which case the provisions of the GPL or the LGPL are applicable instead
27 * of those above. If you wish to allow use of your version of this file only
28 * under the terms of either the GPL or the LGPL, and not to allow others to
29 * use your version of this file under the terms of the MPL, indicate your
30 * decision by deleting the provisions above and replace them with the notice
31 * and other provisions required by the GPL or the LGPL. If you do not delete
32 * the provisions above, a recipient may use your version of this file under
33 * the terms of any one of the MPL, the GPL or the LGPL.
35 * ***** END LICENSE BLOCK ***** */
37 /****************************************************************************
38 * SSL server program listens on a port, accepts client connection, reads *
39 * request and responds to it *
40 ****************************************************************************/
42 /* Generic header files */
44 #include <stdio.h>
45 #include <string.h>
47 /* NSPR header files */
49 #include "nspr.h"
50 #include "plgetopt.h"
51 #include "prerror.h"
52 #include "prnetdb.h"
54 /* NSS header files */
56 #include "pk11func.h"
57 #include "secitem.h"
58 #include "ssl.h"
59 #include "certt.h"
60 #include "nss.h"
61 #include "secder.h"
62 #include "key.h"
63 #include "sslproto.h"
65 /* Custom header files */
67 #include "sslsample.h"
69 #ifndef PORT_Sprintf
70 #define PORT_Sprintf sprintf
71 #endif
73 #define REQUEST_CERT_ONCE 1
74 #define REQUIRE_CERT_ONCE 2
75 #define REQUEST_CERT_ALL 3
76 #define REQUIRE_CERT_ALL 4
78 /* Global variables */
79 GlobalThreadMgr threadMGR;
80 char *password = NULL;
81 CERTCertificate *cert = NULL;
82 SECKEYPrivateKey *privKey = NULL;
83 int stopping;
85 static void
86 Usage(const char *progName)
88 fprintf(stderr,
90 "Usage: %s -n rsa_nickname -p port [-3RFrf] [-w password]\n"
91 " [-c ciphers] [-d dbdir] \n"
92 "-3 means disable SSL v3\n"
93 "-r means request certificate on first handshake.\n"
94 "-f means require certificate on first handshake.\n"
95 "-R means request certificate on all handshakes.\n"
96 "-F means require certificate on all handshakes.\n"
97 "-c ciphers Letter(s) chosen from the following list\n"
98 "A SSL2 RC4 128 WITH MD5\n"
99 "B SSL2 RC4 128 EXPORT40 WITH MD5\n"
100 "C SSL2 RC2 128 CBC WITH MD5\n"
101 "D SSL2 RC2 128 CBC EXPORT40 WITH MD5\n"
102 "E SSL2 DES 64 CBC WITH MD5\n"
103 "F SSL2 DES 192 EDE3 CBC WITH MD5\n"
104 "\n"
105 "c SSL3 RSA WITH RC4 128 MD5\n"
106 "d SSL3 RSA WITH 3DES EDE CBC SHA\n"
107 "e SSL3 RSA WITH DES CBC SHA\n"
108 "f SSL3 RSA EXPORT WITH RC4 40 MD5\n"
109 "g SSL3 RSA EXPORT WITH RC2 CBC 40 MD5\n"
110 "i SSL3 RSA WITH NULL MD5\n"
111 "j SSL3 RSA FIPS WITH 3DES EDE CBC SHA\n"
112 "k SSL3 RSA FIPS WITH DES CBC SHA\n"
113 "l SSL3 RSA EXPORT WITH DES CBC SHA\t(new)\n"
114 "m SSL3 RSA EXPORT WITH RC4 56 SHA\t(new)\n",
115 progName);
116 exit(1);
119 /* Function: readDataFromSocket()
121 * Purpose: Parse an HTTP request by reading data from a GET or POST.
124 SECStatus
125 readDataFromSocket(PRFileDesc *sslSocket, DataBuffer *buffer, char **fileName)
127 char *post;
128 int numBytes = 0;
129 int newln = 0; /* # of consecutive newlns */
131 /* Read data while it comes in from the socket. */
132 while (PR_TRUE) {
133 buffer->index = 0;
134 newln = 0;
136 /* Read the buffer. */
137 numBytes = PR_Read(sslSocket, &buffer->data[buffer->index],
138 buffer->remaining);
139 if (numBytes <= 0) {
140 errWarn("PR_Read");
141 return SECFailure;
143 buffer->dataEnd = buffer->dataStart + numBytes;
145 /* Parse the input, starting at the beginning of the buffer.
146 * Stop when we detect two consecutive \n's (or \r\n's)
147 * as this signifies the end of the GET or POST portion.
148 * The posted data follows.
150 while (buffer->index < buffer->dataEnd && newln < 2) {
151 int octet = buffer->data[buffer->index++];
152 if (octet == '\n') {
153 newln++;
154 } else if (octet != '\r') {
155 newln = 0;
159 /* Came to the end of the buffer, or second newline.
160 * If we didn't get an empty line ("\r\n\r\n"), then keep on reading.
162 if (newln < 2)
163 continue;
165 /* we're at the end of the HTTP request.
166 * If the request is a POST, then there will be one more
167 * line of data.
168 * This parsing is a hack, but ok for SSL test purposes.
170 post = PORT_Strstr(buffer->data, "POST ");
171 if (!post || *post != 'P')
172 break;
174 /* It's a post, so look for the next and final CR/LF. */
175 /* We should parse content length here, but ... */
176 while (buffer->index < buffer->dataEnd && newln < 3) {
177 int octet = buffer->data[buffer->index++];
178 if (octet == '\n') {
179 newln++;
183 if (newln == 3)
184 break;
187 /* Have either (a) a complete get, (b) a complete post, (c) EOF */
189 /* Execute a "GET " operation. */
190 if (buffer->index > 0 && PORT_Strncmp(buffer->data, "GET ", 4) == 0) {
191 int fnLength;
193 /* File name is the part after "GET ". */
194 fnLength = strcspn(buffer->data + 5, " \r\n");
195 *fileName = (char *)PORT_Alloc(fnLength + 1);
196 PORT_Strncpy(*fileName, buffer->data + 5, fnLength);
197 (*fileName)[fnLength] = '\0';
200 return SECSuccess;
203 /* Function: authenticateSocket()
205 * Purpose: Configure a socket for SSL.
209 PRFileDesc *
210 setupSSLSocket(PRFileDesc *tcpSocket, int requestCert)
212 PRFileDesc *sslSocket;
213 SSLKEAType certKEA;
214 int certErr = 0;
215 SECStatus secStatus;
217 /* Set the appropriate flags. */
219 sslSocket = SSL_ImportFD(NULL, tcpSocket);
220 if (sslSocket == NULL) {
221 errWarn("SSL_ImportFD");
222 goto loser;
225 secStatus = SSL_OptionSet(sslSocket, SSL_SECURITY, PR_TRUE);
226 if (secStatus != SECSuccess) {
227 errWarn("SSL_OptionSet SSL_SECURITY");
228 goto loser;
231 secStatus = SSL_OptionSet(sslSocket, SSL_HANDSHAKE_AS_SERVER, PR_TRUE);
232 if (secStatus != SECSuccess) {
233 errWarn("SSL_OptionSet:SSL_HANDSHAKE_AS_SERVER");
234 goto loser;
237 secStatus = SSL_OptionSet(sslSocket, SSL_REQUEST_CERTIFICATE,
238 (requestCert >= REQUEST_CERT_ONCE));
239 if (secStatus != SECSuccess) {
240 errWarn("SSL_OptionSet:SSL_REQUEST_CERTIFICATE");
241 goto loser;
244 secStatus = SSL_OptionSet(sslSocket, SSL_REQUIRE_CERTIFICATE,
245 (requestCert == REQUIRE_CERT_ONCE));
246 if (secStatus != SECSuccess) {
247 errWarn("SSL_OptionSet:SSL_REQUIRE_CERTIFICATE");
248 goto loser;
251 /* Set the appropriate callback routines. */
253 secStatus = SSL_AuthCertificateHook(sslSocket, myAuthCertificate,
254 CERT_GetDefaultCertDB());
255 if (secStatus != SECSuccess) {
256 errWarn("SSL_AuthCertificateHook");
257 goto loser;
260 secStatus = SSL_BadCertHook(sslSocket,
261 (SSLBadCertHandler)myBadCertHandler, &certErr);
262 if (secStatus != SECSuccess) {
263 errWarn("SSL_BadCertHook");
264 goto loser;
267 secStatus = SSL_HandshakeCallback(sslSocket,
268 myHandshakeCallback,
269 NULL);
270 if (secStatus != SECSuccess) {
271 errWarn("SSL_HandshakeCallback");
272 goto loser;
275 secStatus = SSL_SetPKCS11PinArg(sslSocket, password);
276 if (secStatus != SECSuccess) {
277 errWarn("SSL_HandshakeCallback");
278 goto loser;
281 certKEA = NSS_FindCertKEAType(cert);
283 secStatus = SSL_ConfigSecureServer(sslSocket, cert, privKey, certKEA);
284 if (secStatus != SECSuccess) {
285 errWarn("SSL_ConfigSecureServer");
286 goto loser;
289 return sslSocket;
291 loser:
293 PR_Close(tcpSocket);
294 return NULL;
297 /* Function: authenticateSocket()
299 * Purpose: Perform client authentication on the socket.
302 SECStatus
303 authenticateSocket(PRFileDesc *sslSocket, PRBool requireCert)
305 CERTCertificate *cert;
306 SECStatus secStatus;
308 /* Returns NULL if client authentication is not enabled or if the
309 * client had no certificate. */
310 cert = SSL_PeerCertificate(sslSocket);
311 if (cert) {
312 /* Client had a certificate, so authentication is through. */
313 CERT_DestroyCertificate(cert);
314 return SECSuccess;
317 /* Request client to authenticate itself. */
318 secStatus = SSL_OptionSet(sslSocket, SSL_REQUEST_CERTIFICATE, PR_TRUE);
319 if (secStatus != SECSuccess) {
320 errWarn("SSL_OptionSet:SSL_REQUEST_CERTIFICATE");
321 return SECFailure;
324 /* If desired, require client to authenticate itself. Note
325 * SSL_REQUEST_CERTIFICATE must also be on, as above. */
326 secStatus = SSL_OptionSet(sslSocket, SSL_REQUIRE_CERTIFICATE, requireCert);
327 if (secStatus != SECSuccess) {
328 errWarn("SSL_OptionSet:SSL_REQUIRE_CERTIFICATE");
329 return SECFailure;
332 /* Having changed socket configuration parameters, redo handshake. */
333 secStatus = SSL_ReHandshake(sslSocket, PR_TRUE);
334 if (secStatus != SECSuccess) {
335 errWarn("SSL_ReHandshake");
336 return SECFailure;
339 /* Force the handshake to complete before moving on. */
340 secStatus = SSL_ForceHandshake(sslSocket);
341 if (secStatus != SECSuccess) {
342 errWarn("SSL_ForceHandshake");
343 return SECFailure;
346 return SECSuccess;
349 /* Function: writeDataToSocket
351 * Purpose: Write the client's request back to the socket. If the client
352 * requested a file, dump it to the socket.
355 SECStatus
356 writeDataToSocket(PRFileDesc *sslSocket, DataBuffer *buffer, char *fileName)
358 int headerLength;
359 int numBytes;
360 char messageBuffer[120];
361 PRFileDesc *local_file_fd = NULL;
362 char header[] = "<html><body><h1>Sample SSL server</h1><br><br>";
363 char filehd[] = "<h2>The file you requested:</h2><br>";
364 char reqhd[] = "<h2>This is your request:</h2><br>";
365 char link[] = "Try getting a <a HREF=\"../testfile\">file</a><br>";
366 char footer[] = "<br><h2>End of request.</h2><br></body></html>";
368 headerLength = PORT_Strlen(defaultHeader);
370 /* Write a header to the socket. */
371 numBytes = PR_Write(sslSocket, header, PORT_Strlen(header));
372 if (numBytes < 0) {
373 errWarn("PR_Write");
374 goto loser;
377 if (fileName) {
378 PRFileInfo info;
379 PRStatus prStatus;
381 /* Try to open the local file named.
382 * If successful, then write it to the client.
384 prStatus = PR_GetFileInfo(fileName, &info);
385 if (prStatus != PR_SUCCESS ||
386 info.type != PR_FILE_FILE ||
387 info.size < 0) {
388 PORT_Free(fileName);
389 /* Maybe a GET not sent from client.c? */
390 goto writerequest;
393 local_file_fd = PR_Open(fileName, PR_RDONLY, 0);
394 if (local_file_fd == NULL) {
395 PORT_Free(fileName);
396 goto writerequest;
399 /* Write a header to the socket. */
400 numBytes = PR_Write(sslSocket, filehd, PORT_Strlen(filehd));
401 if (numBytes < 0) {
402 errWarn("PR_Write");
403 goto loser;
406 /* Transmit the local file prepended by the default header
407 * across the socket.
409 numBytes = PR_TransmitFile(sslSocket, local_file_fd,
410 defaultHeader, headerLength,
411 PR_TRANSMITFILE_KEEP_OPEN,
412 PR_INTERVAL_NO_TIMEOUT);
414 /* Error in transmission. */
415 if (numBytes < 0) {
416 errWarn("PR_TransmitFile");
418 i = PORT_Strlen(errString);
419 PORT_Memcpy(buf, errString, i);
421 /* Transmitted bytes successfully. */
422 } else {
423 numBytes -= headerLength;
424 fprintf(stderr, "PR_TransmitFile wrote %d bytes from %s\n",
425 numBytes, fileName);
428 PORT_Free(fileName);
429 PR_Close(local_file_fd);
432 writerequest:
434 /* Write a header to the socket. */
435 numBytes = PR_Write(sslSocket, reqhd, PORT_Strlen(reqhd));
436 if (numBytes < 0) {
437 errWarn("PR_Write");
438 goto loser;
441 /* Write the buffer data to the socket. */
442 if (buffer->index <= 0) {
443 /* Reached the EOF. Report incomplete transaction to socket. */
444 PORT_Sprintf(messageBuffer,
445 "GET or POST incomplete after %d bytes.\r\n",
446 buffer->dataEnd);
447 numBytes = PR_Write(sslSocket, messageBuffer,
448 PORT_Strlen(messageBuffer));
449 if (numBytes < 0) {
450 errWarn("PR_Write");
451 goto loser;
453 } else {
454 /* Display the buffer data. */
455 fwrite(buffer->data, 1, buffer->index, stdout);
456 /* Write the buffer data to the socket. */
457 numBytes = PR_Write(sslSocket, buffer->data, buffer->index);
458 if (numBytes < 0) {
459 errWarn("PR_Write");
460 goto loser;
462 /* Display security information for the socket. */
463 printSecurityInfo(sslSocket);
464 /* Write any discarded data out to the socket. */
465 if (buffer->index < buffer->dataEnd) {
466 PORT_Sprintf(buffer->data, "Discarded %d characters.\r\n",
467 buffer->dataEnd - buffer->index);
468 numBytes = PR_Write(sslSocket, buffer->data,
469 PORT_Strlen(buffer->data));
470 if (numBytes < 0) {
471 errWarn("PR_Write");
472 goto loser;
477 /* Write a footer to the socket. */
478 numBytes = PR_Write(sslSocket, footer, PORT_Strlen(footer));
479 if (numBytes < 0) {
480 errWarn("PR_Write");
481 goto loser;
484 /* Write a link to the socket. */
485 numBytes = PR_Write(sslSocket, link, PORT_Strlen(link));
486 if (numBytes < 0) {
487 errWarn("PR_Write");
488 goto loser;
491 /* Complete the HTTP transaction. */
492 numBytes = PR_Write(sslSocket, "EOF\r\n\r\n\r\n", 9);
493 if (numBytes < 0) {
494 errWarn("PR_Write");
495 goto loser;
498 /* Do a nice shutdown if asked. */
499 if (!strncmp(buffer->data, stopCmd, strlen(stopCmd))) {
500 stopping = 1;
502 return SECSuccess;
504 loser:
506 /* Do a nice shutdown if asked. */
507 if (!strncmp(buffer->data, stopCmd, strlen(stopCmd))) {
508 stopping = 1;
510 return SECFailure;
513 /* Function: int handle_connection()
515 * Purpose: Thread to handle a connection to a socket.
518 SECStatus
519 handle_connection(void *tcp_sock, int requestCert)
521 PRFileDesc * tcpSocket = (PRFileDesc *)tcp_sock;
522 PRFileDesc * sslSocket = NULL;
523 SECStatus secStatus = SECFailure;
524 PRStatus prStatus;
525 PRSocketOptionData socketOption;
526 DataBuffer buffer;
527 char * fileName = NULL;
529 /* Initialize the data buffer. */
530 memset(buffer.data, 0, BUFFER_SIZE);
531 buffer.remaining = BUFFER_SIZE;
532 buffer.index = 0;
533 buffer.dataStart = 0;
534 buffer.dataEnd = 0;
536 /* Make sure the socket is blocking. */
537 socketOption.option = PR_SockOpt_Nonblocking;
538 socketOption.value.non_blocking = PR_FALSE;
539 PR_SetSocketOption(tcpSocket, &socketOption);
541 sslSocket = setupSSLSocket(tcpSocket, requestCert);
542 if (sslSocket == NULL) {
543 errWarn("setupSSLSocket");
544 goto cleanup;
547 secStatus = SSL_ResetHandshake(sslSocket, /* asServer */ PR_TRUE);
548 if (secStatus != SECSuccess) {
549 errWarn("SSL_ResetHandshake");
550 goto cleanup;
553 /* Read data from the socket, parse it for HTTP content.
554 * If the user is requesting/requiring authentication, authenticate
555 * the socket. Then write the result back to the socket. */
556 fprintf(stdout, "\nReading data from socket...\n\n");
557 secStatus = readDataFromSocket(sslSocket, &buffer, &fileName);
558 if (secStatus != SECSuccess) {
559 goto cleanup;
561 if (requestCert >= REQUEST_CERT_ALL) {
562 fprintf(stdout, "\nAuthentication requested.\n\n");
563 secStatus = authenticateSocket(sslSocket,
564 (requestCert == REQUIRE_CERT_ALL));
565 if (secStatus != SECSuccess) {
566 goto cleanup;
570 fprintf(stdout, "\nWriting data to socket...\n\n");
571 secStatus = writeDataToSocket(sslSocket, &buffer, fileName);
573 cleanup:
575 /* Close down the socket. */
576 prStatus = PR_Close(tcpSocket);
577 if (prStatus != PR_SUCCESS) {
578 errWarn("PR_Close");
581 return secStatus;
584 /* Function: int accept_connection()
586 * Purpose: Thread to accept a connection to the socket.
589 SECStatus
590 accept_connection(void *listener, int requestCert)
592 PRFileDesc *listenSocket = (PRFileDesc*)listener;
593 PRNetAddr addr;
594 PRStatus prStatus;
596 /* XXX need an SSL socket here? */
597 while (!stopping) {
598 PRFileDesc *tcpSocket;
599 SECStatus result;
601 fprintf(stderr, "\n\n\nAbout to call accept.\n");
603 /* Accept a connection to the socket. */
604 tcpSocket = PR_Accept(listenSocket, &addr, PR_INTERVAL_NO_TIMEOUT);
605 if (tcpSocket == NULL) {
606 errWarn("PR_Accept");
607 break;
610 /* Accepted the connection, now handle it. */
611 result = launch_thread(&threadMGR, handle_connection,
612 tcpSocket, requestCert);
614 if (result != SECSuccess) {
615 prStatus = PR_Close(tcpSocket);
616 if (prStatus != PR_SUCCESS) {
617 exitErr("PR_Close");
619 break;
623 fprintf(stderr, "Closing listen socket.\n");
625 prStatus = PR_Close(listenSocket);
626 if (prStatus != PR_SUCCESS) {
627 exitErr("PR_Close");
629 return SECSuccess;
632 /* Function: void server_main()
634 * Purpose: This is the server's main function. It configures a socket
635 * and listens to it.
638 void
639 server_main(
640 unsigned short port,
641 int requestCert,
642 SECKEYPrivateKey * privKey,
643 CERTCertificate * cert,
644 PRBool disableSSL3)
646 SECStatus secStatus;
647 PRStatus prStatus;
648 PRFileDesc * listenSocket;
649 PRNetAddr addr;
650 PRSocketOptionData socketOption;
652 /* Create a new socket. */
653 listenSocket = PR_NewTCPSocket();
654 if (listenSocket == NULL) {
655 exitErr("PR_NewTCPSocket");
658 /* Set socket to be blocking -
659 * on some platforms the default is nonblocking.
661 socketOption.option = PR_SockOpt_Nonblocking;
662 socketOption.value.non_blocking = PR_FALSE;
664 prStatus = PR_SetSocketOption(listenSocket, &socketOption);
665 if (prStatus != PR_SUCCESS) {
666 exitErr("PR_SetSocketOption");
669 /* This cipher is not on by default. The Acceptance test
670 * would like it to be. Turn this cipher on.
672 secStatus = SSL_CipherPrefSetDefault(SSL_RSA_WITH_NULL_MD5, PR_TRUE);
673 if (secStatus != SECSuccess) {
674 exitErr("SSL_CipherPrefSetDefault:SSL_RSA_WITH_NULL_MD5");
677 /* Configure the network connection. */
678 addr.inet.family = PR_AF_INET;
679 addr.inet.ip = PR_INADDR_ANY;
680 addr.inet.port = PR_htons(port);
682 /* Bind the address to the listener socket. */
683 prStatus = PR_Bind(listenSocket, &addr);
684 if (prStatus != PR_SUCCESS) {
685 exitErr("PR_Bind");
688 /* Listen for connection on the socket. The second argument is
689 * the maximum size of the queue for pending connections.
691 prStatus = PR_Listen(listenSocket, 5);
692 if (prStatus != PR_SUCCESS) {
693 exitErr("PR_Listen");
696 /* Launch thread to handle connections to the socket. */
697 secStatus = launch_thread(&threadMGR, accept_connection,
698 listenSocket, requestCert);
699 if (secStatus != SECSuccess) {
700 PR_Close(listenSocket);
701 } else {
702 reap_threads(&threadMGR);
703 destroy_thread_data(&threadMGR);
707 /* Function: int main()
709 * Purpose: Parses command arguments and configures SSL server.
713 main(int argc, char **argv)
715 char * progName = NULL;
716 char * nickName = NULL;
717 char * cipherString = NULL;
718 char * dir = ".";
719 int requestCert = 0;
720 unsigned short port = 0;
721 SECStatus secStatus;
722 PRBool disableSSL3 = PR_FALSE;
723 PLOptState * optstate;
724 PLOptStatus status;
726 /* Zero out the thread manager. */
727 PORT_Memset(&threadMGR, 0, sizeof(threadMGR));
729 progName = PL_strdup(argv[0]);
731 optstate = PL_CreateOptState(argc, argv, "3FRc:d:fp:n:rw:");
732 while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
733 switch(optstate->option) {
734 case '3': disableSSL3 = PR_TRUE; break;
735 case 'F': requestCert = REQUIRE_CERT_ALL; break;
736 case 'R': requestCert = REQUEST_CERT_ALL; break;
737 case 'c': cipherString = PL_strdup(optstate->value); break;
738 case 'd': dir = PL_strdup(optstate->value); break;
739 case 'f': requestCert = REQUIRE_CERT_ONCE; break;
740 case 'n': nickName = PL_strdup(optstate->value); break;
741 case 'p': port = PORT_Atoi(optstate->value); break;
742 case 'r': requestCert = REQUEST_CERT_ONCE; break;
743 case 'w': password = PL_strdup(optstate->value); break;
744 default:
745 case '?': Usage(progName);
749 if (nickName == NULL || port == 0)
750 Usage(progName);
752 /* Call the NSPR initialization routines. */
753 PR_Init( PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
755 /* Set the cert database password callback. */
756 PK11_SetPasswordFunc(myPasswd);
758 /* Initialize NSS. */
759 secStatus = NSS_Init(dir);
760 if (secStatus != SECSuccess) {
761 exitErr("NSS_Init");
764 /* Set the policy for this server (REQUIRED - no default). */
765 secStatus = NSS_SetDomesticPolicy();
766 if (secStatus != SECSuccess) {
767 exitErr("NSS_SetDomesticPolicy");
770 /* XXX keep this? */
771 /* all the SSL2 and SSL3 cipher suites are enabled by default. */
772 if (cipherString) {
773 int ndx;
775 /* disable all the ciphers, then enable the ones we want. */
776 disableAllSSLCiphers();
778 while (0 != (ndx = *cipherString++)) {
779 int *cptr;
780 int cipher;
782 if (! isalpha(ndx))
783 Usage(progName);
784 cptr = islower(ndx) ? ssl3CipherSuites : ssl2CipherSuites;
785 for (ndx &= 0x1f; (cipher = *cptr++) != 0 && --ndx > 0; )
786 /* do nothing */;
787 if (cipher) {
788 SECStatus status;
789 status = SSL_CipherPrefSetDefault(cipher, PR_TRUE);
790 if (status != SECSuccess)
791 errWarn("SSL_CipherPrefSetDefault()");
796 /* Get own certificate and private key. */
797 cert = PK11_FindCertFromNickname(nickName, password);
798 if (cert == NULL) {
799 exitErr("PK11_FindCertFromNickname");
802 privKey = PK11_FindKeyByAnyCert(cert, password);
803 if (privKey == NULL) {
804 exitErr("PK11_FindKeyByAnyCert");
807 /* Configure the server's cache for a multi-process application
808 * using default timeout values (24 hrs) and directory location (/tmp).
810 SSL_ConfigMPServerSIDCache(256, 0, 0, NULL);
812 /* Launch server. */
813 server_main(port, requestCert, privKey, cert, disableSSL3);
815 /* Shutdown NSS and exit NSPR gracefully. */
816 if (NSS_Shutdown() != SECSuccess) {
817 exit(1);
819 PR_Cleanup();
820 return 0;