server.c
上传用户:lyxiangda
上传日期:2007-01-12
资源大小:3042k
文件大小:22k
源码类别:

CA认证

开发平台:

WINDOWS

  1. /*
  2.  * The contents of this file are subject to the Mozilla Public
  3.  * License Version 1.1 (the "License"); you may not use this file
  4.  * except in compliance with the License. You may obtain a copy of
  5.  * the License at http://www.mozilla.org/MPL/
  6.  * 
  7.  * Software distributed under the License is distributed on an "AS
  8.  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  9.  * implied. See the License for the specific language governing
  10.  * rights and limitations under the License.
  11.  * 
  12.  * The Original Code is the Netscape security libraries.
  13.  * 
  14.  * The Initial Developer of the Original Code is Netscape
  15.  * Communications Corporation.  Portions created by Netscape are 
  16.  * Copyright (C) 1994-2000 Netscape Communications Corporation.  All
  17.  * Rights Reserved.
  18.  * 
  19.  * Contributor(s):
  20.  * 
  21.  * Alternatively, the contents of this file may be used under the
  22.  * terms of the GNU General Public License Version 2 or later (the
  23.  * "GPL"), in which case the provisions of the GPL are applicable 
  24.  * instead of those above.  If you wish to allow use of your 
  25.  * version of this file only under the terms of the GPL and not to
  26.  * allow others to use your version of this file under the MPL,
  27.  * indicate your decision by deleting the provisions above and
  28.  * replace them with the notice and other provisions required by
  29.  * the GPL.  If you do not delete the provisions above, a recipient
  30.  * may use your version of this file under either the MPL or the
  31.  * GPL.
  32.  */
  33. /****************************************************************************
  34.  *  SSL server program listens on a port, accepts client connection, reads  *
  35.  *  request and responds to it                                              *
  36.  ****************************************************************************/
  37. /* Generic header files */
  38. #include <stdio.h>
  39. #include <string.h>
  40. /* NSPR header files */
  41. #include "nspr.h"
  42. #include "plgetopt.h"
  43. #include "prerror.h"
  44. #include "prnetdb.h"
  45. /* NSS header files */
  46. #include "pk11func.h"
  47. #include "secitem.h"
  48. #include "ssl.h"
  49. #include "certt.h"
  50. #include "nss.h"
  51. #include "secrng.h"
  52. #include "secder.h"
  53. #include "key.h"
  54. #include "sslproto.h"
  55. /* Custom header files */
  56. #include "sslsample.h"
  57. #ifndef PORT_Sprintf
  58. #define PORT_Sprintf sprintf
  59. #endif
  60. #define REQUEST_CERT_ONCE 1
  61. #define REQUIRE_CERT_ONCE 2
  62. #define REQUEST_CERT_ALL  3
  63. #define REQUIRE_CERT_ALL  4
  64. /* Global variables */
  65. GlobalThreadMgr   threadMGR;
  66. char             *password = NULL;
  67. CERTCertificate  *cert = NULL;
  68. SECKEYPrivateKey *privKey = NULL;
  69. int               stopping;
  70. static void
  71. Usage(const char *progName)
  72. {
  73. fprintf(stderr, 
  74. "Usage: %s -n rsa_nickname -p port [-3RFrf] [-w password]n"
  75. " [-c ciphers] [-d dbdir] n"
  76. "-3 means disable SSL v3n"
  77. "-r means request certificate on first handshake.n"
  78. "-f means require certificate on first handshake.n"
  79. "-R means request certificate on all handshakes.n"
  80. "-F means require certificate on all handshakes.n"
  81. "-c ciphers   Letter(s) chosen from the following listn"
  82. "A   SSL2 RC4 128 WITH MD5n"
  83. "B   SSL2 RC4 128 EXPORT40 WITH MD5n"
  84. "C   SSL2 RC2 128 CBC WITH MD5n"
  85. "D   SSL2 RC2 128 CBC EXPORT40 WITH MD5n"
  86. "E   SSL2 DES 64 CBC WITH MD5n"
  87. "F   SSL2 DES 192 EDE3 CBC WITH MD5n"
  88. "n"
  89. "a   SSL3 FORTEZZA DMS WITH FORTEZZA CBC SHAn"
  90. "b   SSL3 FORTEZZA DMS WITH RC4 128 SHAn"
  91. "c   SSL3 RSA WITH RC4 128 MD5n"
  92. "d   SSL3 RSA WITH 3DES EDE CBC SHAn"
  93. "e   SSL3 RSA WITH DES CBC SHAn"
  94. "f   SSL3 RSA EXPORT WITH RC4 40 MD5n"
  95. "g   SSL3 RSA EXPORT WITH RC2 CBC 40 MD5n"
  96. "h   SSL3 FORTEZZA DMS WITH NULL SHAn"
  97. "i   SSL3 RSA WITH NULL MD5n"
  98. "j   SSL3 RSA FIPS WITH 3DES EDE CBC SHAn"
  99. "k   SSL3 RSA FIPS WITH DES CBC SHAn"
  100. "l   SSL3 RSA EXPORT WITH DES CBC SHAt(new)n"
  101. "m   SSL3 RSA EXPORT WITH RC4 56 SHAt(new)n",
  102. progName);
  103. exit(1);
  104. }
  105. /* Function:  readDataFromSocket()
  106.  *
  107.  * Purpose:  Parse an HTTP request by reading data from a GET or POST.
  108.  *
  109.  */
  110. SECStatus
  111. readDataFromSocket(PRFileDesc *sslSocket, DataBuffer *buffer, char **fileName)
  112. {
  113. char  *post;
  114. int    numBytes = 0;
  115. int    newln    = 0;  /* # of consecutive newlns */
  116. /* Read data while it comes in from the socket. */
  117. while (PR_TRUE) {
  118. buffer->index = 0;
  119. newln = 0;
  120. /* Read the buffer. */
  121. numBytes = PR_Read(sslSocket, &buffer->data[buffer->index], 
  122.                    buffer->remaining);
  123. if (numBytes <= 0) {
  124. errWarn("PR_Read");
  125. return SECFailure;
  126. }
  127. buffer->dataEnd = buffer->dataStart + numBytes;
  128. /* Parse the input, starting at the beginning of the buffer.
  129.  * Stop when we detect two consecutive n's (or rn's) 
  130.  * as this signifies the end of the GET or POST portion.
  131.  * The posted data follows.
  132.  */
  133. while (buffer->index < buffer->dataEnd && newln < 2) {
  134. int octet = buffer->data[buffer->index++];
  135. if (octet == 'n') {
  136. newln++;
  137. } else if (octet != 'r') {
  138. newln = 0;
  139. }
  140. }
  141. /* Came to the end of the buffer, or second newline.
  142.  * If we didn't get an empty line ("rnrn"), then keep on reading.
  143.  */
  144. if (newln < 2) 
  145. continue;
  146. /* we're at the end of the HTTP request.
  147.  * If the request is a POST, then there will be one more
  148.  * line of data.
  149.  * This parsing is a hack, but ok for SSL test purposes.
  150.  */
  151. post = PORT_Strstr(buffer->data, "POST ");
  152. if (!post || *post != 'P') 
  153. break;
  154. /* It's a post, so look for the next and final CR/LF. */
  155. /* We should parse content length here, but ... */
  156. while (buffer->index < buffer->dataEnd && newln < 3) {
  157. int octet = buffer->data[buffer->index++];
  158. if (octet == 'n') {
  159. newln++;
  160. }
  161. }
  162. if (newln == 3)
  163. break;
  164. }
  165. /* Have either (a) a complete get, (b) a complete post, (c) EOF */
  166. /*  Execute a "GET " operation. */
  167. if (buffer->index > 0 && PORT_Strncmp(buffer->data, "GET ", 4) == 0) {
  168. int fnLength;
  169. /* File name is the part after "GET ". */
  170. fnLength = strcspn(buffer->data + 5, " rn");
  171. *fileName = (char *)PORT_Alloc(fnLength + 1);
  172. PORT_Strncpy(*fileName, buffer->data + 5, fnLength);
  173. (*fileName)[fnLength] = '';
  174. }
  175. return SECSuccess;
  176. }
  177. /* Function:  authenticateSocket()
  178.  *
  179.  * Purpose:  Configure a socket for SSL.
  180.  *
  181.  *
  182.  */
  183. PRFileDesc * 
  184. setupSSLSocket(PRFileDesc *tcpSocket, int requestCert)
  185. {
  186. PRFileDesc *sslSocket;
  187. SSLKEAType  certKEA;
  188. int         certErr = 0;
  189. SECStatus   secStatus;
  190. /* Set the appropriate flags. */
  191. sslSocket = SSL_ImportFD(NULL, tcpSocket);
  192. if (sslSocket == NULL) {
  193. errWarn("SSL_ImportFD");
  194. goto loser;
  195. }
  196.    
  197. secStatus = SSL_Enable(sslSocket, SSL_SECURITY, PR_TRUE);
  198. if (secStatus != SECSuccess) {
  199. errWarn("SSL_Enable SSL_SECURITY");
  200. goto loser;
  201. }
  202. secStatus = SSL_Enable(sslSocket, SSL_HANDSHAKE_AS_SERVER, PR_TRUE);
  203. if (secStatus != SECSuccess) {
  204. errWarn("SSL_Enable:SSL_HANDSHAKE_AS_SERVER");
  205. goto loser;
  206. }
  207. secStatus = SSL_Enable(sslSocket, SSL_REQUEST_CERTIFICATE, 
  208.                        (requestCert >= REQUEST_CERT_ONCE));
  209. if (secStatus != SECSuccess) {
  210. errWarn("SSL_Enable:SSL_REQUEST_CERTIFICATE");
  211. goto loser;
  212. }
  213. secStatus = SSL_Enable(sslSocket, SSL_REQUIRE_CERTIFICATE, 
  214.                        (requestCert == REQUIRE_CERT_ONCE));
  215. if (secStatus != SECSuccess) {
  216. errWarn("SSL_Enable:SSL_REQUIRE_CERTIFICATE");
  217. goto loser;
  218. }
  219. /* Set the appropriate callback routines. */
  220. secStatus = SSL_AuthCertificateHook(sslSocket, myAuthCertificate, 
  221.                                     CERT_GetDefaultCertDB());
  222. if (secStatus != SECSuccess) {
  223. errWarn("SSL_AuthCertificateHook");
  224. goto loser;
  225. }
  226. secStatus = SSL_BadCertHook(sslSocket, 
  227.                             (SSLBadCertHandler)myBadCertHandler, &certErr);
  228. if (secStatus != SECSuccess) {
  229. errWarn("SSL_BadCertHook");
  230. goto loser;
  231. }
  232. secStatus = SSL_HandshakeCallback(sslSocket,
  233.                                  (SSLHandshakeCallback)myHandshakeCallback,
  234.   NULL);
  235. if (secStatus != SECSuccess) {
  236. errWarn("SSL_HandshakeCallback");
  237. goto loser;
  238. }
  239. secStatus = SSL_SetPKCS11PinArg(sslSocket, password);
  240. if (secStatus != SECSuccess) {
  241. errWarn("SSL_HandshakeCallback");
  242. goto loser;
  243. }
  244. certKEA = NSS_FindCertKEAType(cert);
  245. secStatus = SSL_ConfigSecureServer(sslSocket, cert, privKey, certKEA);
  246. if (secStatus != SECSuccess) {
  247. errWarn("SSL_ConfigSecureServer");
  248. goto loser;
  249. }
  250. return sslSocket;
  251. loser:
  252. PR_Close(tcpSocket);
  253. return NULL;
  254. }
  255. /* Function:  authenticateSocket()
  256.  *
  257.  * Purpose:  Perform client authentication on the socket.
  258.  *
  259.  */
  260. SECStatus
  261. authenticateSocket(PRFileDesc *sslSocket, PRBool requireCert)
  262. {
  263. CERTCertificate *cert;
  264. SECStatus secStatus;
  265. /* Returns NULL if client authentication is not enabled or if the
  266.  * client had no certificate. */
  267. cert = SSL_PeerCertificate(sslSocket);
  268. if (cert) {
  269. /* Client had a certificate, so authentication is through. */
  270. CERT_DestroyCertificate(cert);
  271. return SECSuccess;
  272. }
  273. /* Request client to authenticate itself. */
  274. secStatus = SSL_Enable(sslSocket, SSL_REQUEST_CERTIFICATE, PR_TRUE);
  275. if (secStatus != SECSuccess) {
  276. errWarn("SSL_Enable:SSL_REQUEST_CERTIFICATE");
  277. return SECFailure;
  278. }
  279. /* If desired, require client to authenticate itself.  Note
  280.  * SSL_REQUEST_CERTIFICATE must also be on, as above.  */
  281. secStatus = SSL_Enable(sslSocket, SSL_REQUIRE_CERTIFICATE, requireCert);
  282. if (secStatus != SECSuccess) {
  283. errWarn("SSL_Enable:SSL_REQUIRE_CERTIFICATE");
  284. return SECFailure;
  285. }
  286. /* Having changed socket configuration parameters, redo handshake. */
  287. secStatus = SSL_RedoHandshake(sslSocket);
  288. if (secStatus != SECSuccess) {
  289. errWarn("SSL_RedoHandshake");
  290. return SECFailure;
  291. }
  292. /* Force the handshake to complete before moving on. */
  293. secStatus = SSL_ForceHandshake(sslSocket);
  294. if (secStatus != SECSuccess) {
  295. errWarn("SSL_ForceHandshake");
  296. return SECFailure;
  297. }
  298. return SECSuccess;
  299. }
  300. /* Function:  writeDataToSocket
  301.  *
  302.  * Purpose:  Write the client's request back to the socket.  If the client
  303.  *           requested a file, dump it to the socket.
  304.  *
  305.  */
  306. SECStatus
  307. writeDataToSocket(PRFileDesc *sslSocket, DataBuffer *buffer, char *fileName)
  308. {
  309. int headerLength;
  310. int numBytes;
  311. char messageBuffer[120];
  312. PRFileDesc *local_file_fd = NULL;
  313. char header[] = "<html><body><h1>Sample SSL server</h1><br><br>";
  314. char filehd[] = "<h2>The file you requested:</h2><br>";
  315. char reqhd[]  = "<h2>This is your request:</h2><br>";
  316. char link[]   = "Try getting a <a HREF="../testfile">file</a><br>";
  317. char footer[] = "<br><h2>End of request.</h2><br></body></html>";
  318. headerLength = PORT_Strlen(defaultHeader);
  319. /* Write a header to the socket. */
  320. numBytes = PR_Write(sslSocket, header, PORT_Strlen(header));
  321. if (numBytes < 0) {
  322. errWarn("PR_Write");
  323. goto loser;
  324. }
  325. if (fileName) {
  326. PRFileInfo  info;
  327. PRStatus    prStatus;
  328. /* Try to open the local file named.
  329.  * If successful, then write it to the client.
  330.  */
  331. prStatus = PR_GetFileInfo(fileName, &info);
  332. if (prStatus != PR_SUCCESS ||
  333.     info.type != PR_FILE_FILE ||
  334.     info.size < 0) {
  335. PORT_Free(fileName);
  336. /* Maybe a GET not sent from client.c? */
  337. goto writerequest;
  338. return SECSuccess;
  339. }
  340. local_file_fd = PR_Open(fileName, PR_RDONLY, 0);
  341. if (local_file_fd == NULL) {
  342. PORT_Free(fileName);
  343. goto writerequest;
  344. }
  345. /* Write a header to the socket. */
  346. numBytes = PR_Write(sslSocket, filehd, PORT_Strlen(filehd));
  347. if (numBytes < 0) {
  348. errWarn("PR_Write");
  349. goto loser;
  350. }
  351. /* Transmit the local file prepended by the default header
  352.  * across the socket.
  353.  */
  354. numBytes = PR_TransmitFile(sslSocket, local_file_fd, 
  355.                            defaultHeader, headerLength,
  356.                            PR_TRANSMITFILE_KEEP_OPEN,
  357.                            PR_INTERVAL_NO_TIMEOUT);
  358. /* Error in transmission. */
  359. if (numBytes < 0) {
  360. errWarn("PR_TransmitFile");
  361. /*
  362. i = PORT_Strlen(errString);
  363. PORT_Memcpy(buf, errString, i);
  364. */
  365. /* Transmitted bytes successfully. */
  366. } else {
  367. numBytes -= headerLength;
  368. fprintf(stderr, "PR_TransmitFile wrote %d bytes from %sn",
  369.         numBytes, fileName);
  370. }
  371. PORT_Free(fileName);
  372. PR_Close(local_file_fd);
  373. }
  374. writerequest:
  375. /* Write a header to the socket. */
  376. numBytes = PR_Write(sslSocket, reqhd, PORT_Strlen(reqhd));
  377. if (numBytes < 0) {
  378. errWarn("PR_Write");
  379. goto loser;
  380. }
  381. /* Write the buffer data to the socket. */
  382. if (buffer->index <= 0) {
  383. /* Reached the EOF.  Report incomplete transaction to socket. */
  384. PORT_Sprintf(messageBuffer,
  385.              "GET or POST incomplete after %d bytes.rn",
  386.              buffer->dataEnd);
  387. numBytes = PR_Write(sslSocket, messageBuffer, 
  388.                     PORT_Strlen(messageBuffer));
  389. if (numBytes < 0) {
  390. errWarn("PR_Write");
  391. goto loser;
  392. }
  393. } else {
  394. /* Display the buffer data. */
  395. fwrite(buffer->data, 1, buffer->index, stdout);
  396. /* Write the buffer data to the socket. */
  397. numBytes = PR_Write(sslSocket, buffer->data, buffer->index);
  398. if (numBytes < 0) {
  399. errWarn("PR_Write");
  400. goto loser;
  401. }
  402. /* Display security information for the socket. */
  403. printSecurityInfo(sslSocket);
  404. /* Write any discarded data out to the socket. */
  405. if (buffer->index < buffer->dataEnd) {
  406. PORT_Sprintf(buffer->data, "Discarded %d characters.rn", 
  407.              buffer->dataEnd - buffer->index);
  408. numBytes = PR_Write(sslSocket, buffer->data, 
  409.                     PORT_Strlen(buffer->data));
  410. if (numBytes < 0) {
  411. errWarn("PR_Write");
  412. goto loser;
  413. }
  414. }
  415. }
  416. /* Write a footer to the socket. */
  417. numBytes = PR_Write(sslSocket, footer, PORT_Strlen(footer));
  418. if (numBytes < 0) {
  419. errWarn("PR_Write");
  420. goto loser;
  421. }
  422. /* Write a link to the socket. */
  423. numBytes = PR_Write(sslSocket, link, PORT_Strlen(link));
  424. if (numBytes < 0) {
  425. errWarn("PR_Write");
  426. goto loser;
  427. }
  428. /* Complete the HTTP transaction. */
  429. numBytes = PR_Write(sslSocket, "EOFrnrnrn", 9);
  430. if (numBytes < 0) {
  431. errWarn("PR_Write");
  432. goto loser;
  433. }
  434. /* Do a nice shutdown if asked. */
  435. if (!strncmp(buffer->data, stopCmd, strlen(stopCmd))) {
  436. stopping = 1;
  437. }
  438. return SECSuccess;
  439. loser:
  440. /* Do a nice shutdown if asked. */
  441. if (!strncmp(buffer->data, stopCmd, strlen(stopCmd))) {
  442. stopping = 1;
  443. }
  444. return SECFailure;
  445. }
  446. /* Function:  int handle_connection()
  447.  *
  448.  * Purpose:  Thread to handle a connection to a socket.
  449.  *
  450.  */
  451. SECStatus
  452. handle_connection(void *tcp_sock, int requestCert)
  453. {
  454. PRFileDesc *       tcpSocket = (PRFileDesc *)tcp_sock;
  455. PRFileDesc *       sslSocket = NULL;
  456. SECStatus          secStatus = SECFailure;
  457. PRStatus           prStatus;
  458. PRSocketOptionData socketOption;
  459. DataBuffer         buffer;
  460. char *             fileName = NULL;
  461. /* Initialize the data buffer. */
  462. memset(buffer.data, 0, BUFFER_SIZE);
  463. buffer.remaining = BUFFER_SIZE;
  464. buffer.index = 0;
  465. buffer.dataStart = 0;
  466. buffer.dataEnd = 0;
  467. /* Make sure the socket is blocking. */
  468. socketOption.option             = PR_SockOpt_Nonblocking;
  469. socketOption.value.non_blocking = PR_FALSE;
  470. PR_SetSocketOption(tcpSocket, &socketOption);
  471. sslSocket = setupSSLSocket(tcpSocket, requestCert);
  472. if (sslSocket == NULL) {
  473. errWarn("setupSSLSocket");
  474. goto cleanup;
  475. }
  476. secStatus = SSL_ResetHandshake(sslSocket, /* asServer */ PR_TRUE);
  477. if (secStatus != SECSuccess) {
  478. errWarn("SSL_ResetHandshake");
  479. goto cleanup;
  480. }
  481. /* Read data from the socket, parse it for HTTP content.
  482.  * If the user is requesting/requiring authentication, authenticate
  483.  * the socket.  Then write the result back to the socket.  */
  484. fprintf(stdout, "nReading data from socket...nn");
  485. secStatus = readDataFromSocket(sslSocket, &buffer, &fileName);
  486. if (secStatus != SECSuccess) {
  487. goto cleanup;
  488. }
  489. if (requestCert >= REQUEST_CERT_ALL) {
  490. fprintf(stdout, "nAuthentication requested.nn");
  491. secStatus = authenticateSocket(sslSocket, 
  492.                                (requestCert == REQUIRE_CERT_ALL));
  493. if (secStatus != SECSuccess) {
  494. goto cleanup;
  495. }
  496. }
  497. fprintf(stdout, "nWriting data to socket...nn");
  498. secStatus = writeDataToSocket(sslSocket, &buffer, fileName);
  499. cleanup:
  500. /* Close down the socket. */
  501. prStatus = PR_Close(tcpSocket);
  502. if (prStatus != PR_SUCCESS) {
  503. errWarn("PR_Close");
  504. }
  505. return secStatus;
  506. }
  507. /* Function:  int accept_connection()
  508.  *
  509.  * Purpose:  Thread to accept a connection to the socket.
  510.  *
  511.  */
  512. SECStatus
  513. accept_connection(void *listener, int requestCert)
  514. {
  515. PRFileDesc *listenSocket = (PRFileDesc*)listener;
  516. PRNetAddr   addr;
  517. PRStatus    prStatus;
  518. /* XXX need an SSL socket here? */
  519. while (!stopping) {
  520. PRFileDesc *tcpSocket;
  521. SECStatus result;
  522. fprintf(stderr, "nnnAbout to call accept.n");
  523. /* Accept a connection to the socket. */
  524. tcpSocket = PR_Accept(listenSocket, &addr, PR_INTERVAL_NO_TIMEOUT);
  525. if (tcpSocket == NULL) {
  526. errWarn("PR_Accept");
  527. break;
  528. }
  529. /* Accepted the connection, now handle it. */
  530. result = launch_thread(&threadMGR, handle_connection, 
  531.                        tcpSocket, requestCert);
  532. if (result != SECSuccess) {
  533. prStatus = PR_Close(tcpSocket);
  534. if (prStatus != PR_SUCCESS) {
  535. exitErr("PR_Close");
  536. }
  537. break;
  538. }
  539. }
  540. fprintf(stderr, "Closing listen socket.n");
  541. prStatus = PR_Close(listenSocket);
  542. if (prStatus != PR_SUCCESS) {
  543. exitErr("PR_Close");
  544. }
  545. return SECSuccess;
  546. }
  547. /* Function:  void server_main()
  548.  *
  549.  * Purpose:  This is the server's main function.  It configures a socket
  550.  *  and listens to it.
  551.  *
  552.  */
  553. void
  554. server_main(
  555. unsigned short      port, 
  556. int                 requestCert, 
  557. SECKEYPrivateKey *  privKey,
  558. CERTCertificate *   cert, 
  559. PRBool              disableSSL3)
  560. {
  561. SECStatus           secStatus;
  562. PRStatus            prStatus;
  563. PRFileDesc *        listenSocket;
  564. PRNetAddr           addr;
  565. PRSocketOptionData  socketOption;
  566. /* Create a new socket. */
  567. listenSocket = PR_NewTCPSocket();
  568. if (listenSocket == NULL) {
  569. exitErr("PR_NewTCPSocket");
  570. }
  571. /* Set socket to be blocking -
  572.  * on some platforms the default is nonblocking.
  573.  */
  574. socketOption.option = PR_SockOpt_Nonblocking;
  575. socketOption.value.non_blocking = PR_FALSE;
  576. prStatus = PR_SetSocketOption(listenSocket, &socketOption);
  577. if (prStatus != PR_SUCCESS) {
  578. exitErr("PR_SetSocketOption");
  579. }
  580. /* This cipher is not on by default. The Acceptance test
  581.  * would like it to be. Turn this cipher on.
  582.  */
  583. secStatus = SSL_EnableCipher(SSL_RSA_WITH_NULL_MD5, PR_TRUE);
  584. if (secStatus != SECSuccess) {
  585. exitErr("SSL_EnableCipher:SSL_RSA_WITH_NULL_MD5");
  586. }
  587. /* Configure the network connection. */
  588. addr.inet.family = PR_AF_INET;
  589. addr.inet.ip  = PR_INADDR_ANY;
  590. addr.inet.port  = PR_htons(port);
  591. /* Bind the address to the listener socket. */
  592. prStatus = PR_Bind(listenSocket, &addr);
  593. if (prStatus != PR_SUCCESS) {
  594. exitErr("PR_Bind");
  595. }
  596. /* Listen for connection on the socket.  The second argument is
  597.  * the maximum size of the queue for pending connections.
  598.  */
  599. prStatus = PR_Listen(listenSocket, 5);
  600. if (prStatus != PR_SUCCESS) {
  601. exitErr("PR_Listen");
  602. }
  603. /* Launch thread to handle connections to the socket. */
  604. secStatus = launch_thread(&threadMGR, accept_connection, 
  605.                               listenSocket, requestCert);
  606. if (secStatus != SECSuccess) {
  607. PR_Close(listenSocket);
  608. } else {
  609. reap_threads(&threadMGR);
  610. destroy_thread_data(&threadMGR);
  611. }
  612. }
  613. /* Function: int main()
  614.  *
  615.  * Purpose:  Parses command arguments and configures SSL server.
  616.  *
  617.  */
  618. int
  619. main(int argc, char **argv)
  620. {
  621. char *              progName      = NULL;
  622. char *              nickName      = NULL;
  623. char *              cipherString  = NULL;
  624. char *              dir           = ".";
  625. int                 requestCert   = 0;
  626. unsigned short      port          = 0;
  627. SECStatus           secStatus;
  628. PRBool              disableSSL3   = PR_FALSE;
  629. PLOptState *        optstate;
  630. PLOptStatus         status;
  631. /* Zero out the thread manager. */
  632. PORT_Memset(&threadMGR, 0, sizeof(threadMGR));
  633. progName = PL_strdup(argv[0]);
  634. optstate = PL_CreateOptState(argc, argv, "3FRc:d:fp:n:rw:");
  635. while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
  636. switch(optstate->option) {
  637. case '3': disableSSL3 = PR_TRUE;                      break;
  638. case 'F': requestCert = REQUIRE_CERT_ALL;             break;
  639. case 'R': requestCert = REQUEST_CERT_ALL;             break;
  640. case 'c': cipherString = PL_strdup(optstate->value);  break;
  641. case 'd': dir = PL_strdup(optstate->value);           break;
  642. case 'f': requestCert = REQUIRE_CERT_ONCE;            break;
  643. case 'n': nickName = PL_strdup(optstate->value);      break;
  644. case 'p': port = PORT_Atoi(optstate->value);          break;
  645. case 'r': requestCert = REQUEST_CERT_ONCE;            break;
  646. case 'w': password = PL_strdup(optstate->value);      break;
  647. default:
  648. case '?': Usage(progName);
  649. }
  650. }
  651. if (nickName == NULL || port == 0)
  652. Usage(progName);
  653. /* Call the NSPR initialization routines. */
  654. PR_Init( PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
  655. /* Set the cert database password callback. */
  656. PK11_SetPasswordFunc(myPasswd);
  657. /* Initialize NSS. */
  658. secStatus = NSS_Init(dir);
  659. if (secStatus != SECSuccess) {
  660. exitErr("NSS_Init");
  661. }
  662. /* Set the policy for this server (REQUIRED - no default). */
  663. secStatus = NSS_SetDomesticPolicy();
  664. if (secStatus != SECSuccess) {
  665. exitErr("NSS_SetDomesticPolicy");
  666. }
  667. /* XXX keep this? */
  668. /* all the SSL2 and SSL3 cipher suites are enabled by default. */
  669. if (cipherString) {
  670. int ndx;
  671. /* disable all the ciphers, then enable the ones we want. */
  672. disableSSL2Ciphers();
  673. disableSSL3Ciphers();
  674. while (0 != (ndx = *cipherString++)) {
  675. int *cptr;
  676. int  cipher;
  677. if (! isalpha(ndx))
  678. Usage(progName);
  679. cptr = islower(ndx) ? ssl3CipherSuites : ssl2CipherSuites;
  680. for (ndx &= 0x1f; (cipher = *cptr++) != 0 && --ndx > 0; ) 
  681. /* do nothing */;
  682. if (cipher) {
  683. SECStatus status;
  684. status = SSL_CipherPrefSetDefault(cipher, SSL_ALLOWED);
  685. if (status != SECSuccess) 
  686. errWarn("SSL_CipherPrefSetDefault()");
  687. }
  688. }
  689. }
  690. /* Get own certificate and private key. */
  691. cert = PK11_FindCertFromNickname(nickName, password);
  692. if (cert == NULL) {
  693. exitErr("PK11_FindCertFromNickname");
  694. }
  695. privKey = PK11_FindKeyByAnyCert(cert, password);
  696. if (privKey == NULL) {
  697. exitErr("PK11_FindKeyByAnyCert");
  698. }
  699. /* Configure the server's cache for a multi-process application
  700.  * using default timeout values (24 hrs) and directory location (/tmp). 
  701.  */
  702. SSL_ConfigMPServerSIDCache(256, 0, 0, NULL);
  703. /* Launch server. */
  704. server_main(port, requestCert, privKey, cert, disableSSL3);
  705. /* Shutdown NSS and exit NSPR gracefully. */
  706. NSS_Shutdown();
  707. PR_Cleanup();
  708. return 0;
  709. }