~ubuntu-branches/ubuntu/precise/xulrunner-1.9/precise

« back to all changes in this revision

Viewing changes to mozilla/security/nss/cmd/SSLsample/server.c

  • Committer: Bazaar Package Importer
  • Author(s): Alexander Sack
  • Date: 2008-12-16 18:40:18 UTC
  • mfrom: (1.1.15 upstream)
  • Revision ID: james.westby@ubuntu.com-20081216184018-j646ukfhzxnjynix
Tags: 1.9.0.5+nobinonly-0ubuntu1
* new security/stability upstream release v1.9.0.5 (FIREFOX_3_0_5_RELEASE)
  - see USN-690-1
* submit patches upstreamed:
  - bzXXX_plugin_for_mimetype_pref.patch => bz449188_att350098_plugin_for_mimetype_pref.patch
  - update debian/patches/series
* adjust XULFastLoad cache in response to interleaving landing of bmo
  #453545 and #462806
  - update debian/patches/bz368428_attachment_308130.patch

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* ***** BEGIN LICENSE BLOCK *****
2
 
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3
 
 *
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/
8
 
 *
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.
13
 
 *
14
 
 * The Original Code is the Netscape security libraries.
15
 
 *
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.
20
 
 *
21
 
 * Contributor(s):
22
 
 *
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.
34
 
 *
35
 
 * ***** END LICENSE BLOCK ***** */
36
 
 
37
 
/****************************************************************************
38
 
 *  SSL server program listens on a port, accepts client connection, reads  *
39
 
 *  request and responds to it                                              *
40
 
 ****************************************************************************/
41
 
 
42
 
/* Generic header files */
43
 
 
44
 
#include <stdio.h>
45
 
#include <string.h>
46
 
 
47
 
/* NSPR header files */
48
 
 
49
 
#include "nspr.h"
50
 
#include "plgetopt.h"
51
 
#include "prerror.h"
52
 
#include "prnetdb.h"
53
 
 
54
 
/* NSS header files */
55
 
 
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"
64
 
 
65
 
/* Custom header files */
66
 
 
67
 
#include "sslsample.h"
68
 
 
69
 
#ifndef PORT_Sprintf
70
 
#define PORT_Sprintf sprintf
71
 
#endif
72
 
 
73
 
#define REQUEST_CERT_ONCE 1
74
 
#define REQUIRE_CERT_ONCE 2
75
 
#define REQUEST_CERT_ALL  3
76
 
#define REQUIRE_CERT_ALL  4
77
 
 
78
 
/* Global variables */
79
 
GlobalThreadMgr   threadMGR;
80
 
char             *password = NULL;
81
 
CERTCertificate  *cert = NULL;
82
 
SECKEYPrivateKey *privKey = NULL;
83
 
int               stopping;
84
 
 
85
 
static void
86
 
Usage(const char *progName)
87
 
{
88
 
        fprintf(stderr, 
89
 
 
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);
117
 
}
118
 
 
119
 
/* Function:  readDataFromSocket()
120
 
 *
121
 
 * Purpose:  Parse an HTTP request by reading data from a GET or POST.
122
 
 *
123
 
 */
124
 
SECStatus
125
 
readDataFromSocket(PRFileDesc *sslSocket, DataBuffer *buffer, char **fileName)
126
 
{
127
 
        char  *post;
128
 
        int    numBytes = 0;
129
 
        int    newln    = 0;  /* # of consecutive newlns */
130
 
 
131
 
        /* Read data while it comes in from the socket. */
132
 
        while (PR_TRUE) {
133
 
                buffer->index = 0;
134
 
                newln = 0;
135
 
 
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;
142
 
                }
143
 
                buffer->dataEnd = buffer->dataStart + numBytes;
144
 
 
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.
149
 
                 */
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;
156
 
                        }
157
 
                }
158
 
 
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.
161
 
                 */
162
 
                if (newln < 2) 
163
 
                        continue;
164
 
 
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.
169
 
                 */
170
 
                post = PORT_Strstr(buffer->data, "POST ");
171
 
                if (!post || *post != 'P') 
172
 
                        break;
173
 
 
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++;
180
 
                        }
181
 
                }
182
 
 
183
 
                if (newln == 3)
184
 
                        break;
185
 
        }
186
 
 
187
 
        /* Have either (a) a complete get, (b) a complete post, (c) EOF */
188
 
 
189
 
        /*  Execute a "GET " operation. */
190
 
        if (buffer->index > 0 && PORT_Strncmp(buffer->data, "GET ", 4) == 0) {
191
 
                int fnLength;
192
 
 
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';
198
 
        }
199
 
 
200
 
        return SECSuccess;
201
 
}
202
 
 
203
 
/* Function:  authenticateSocket()
204
 
 *
205
 
 * Purpose:  Configure a socket for SSL.
206
 
 *
207
 
 *
208
 
 */
209
 
PRFileDesc * 
210
 
setupSSLSocket(PRFileDesc *tcpSocket, int requestCert)
211
 
{
212
 
        PRFileDesc *sslSocket;
213
 
        SSLKEAType  certKEA;
214
 
        int         certErr = 0;
215
 
        SECStatus   secStatus;
216
 
 
217
 
        /* Set the appropriate flags. */
218
 
 
219
 
        sslSocket = SSL_ImportFD(NULL, tcpSocket);
220
 
        if (sslSocket == NULL) {
221
 
                errWarn("SSL_ImportFD");
222
 
                goto loser;
223
 
        }
224
 
   
225
 
        secStatus = SSL_OptionSet(sslSocket, SSL_SECURITY, PR_TRUE);
226
 
        if (secStatus != SECSuccess) {
227
 
                errWarn("SSL_OptionSet SSL_SECURITY");
228
 
                goto loser;
229
 
        }
230
 
 
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;
235
 
        }
236
 
 
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;
242
 
        }
243
 
 
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;
249
 
        }
250
 
 
251
 
        /* Set the appropriate callback routines. */
252
 
 
253
 
        secStatus = SSL_AuthCertificateHook(sslSocket, myAuthCertificate, 
254
 
                                            CERT_GetDefaultCertDB());
255
 
        if (secStatus != SECSuccess) {
256
 
                errWarn("SSL_AuthCertificateHook");
257
 
                goto loser;
258
 
        }
259
 
 
260
 
        secStatus = SSL_BadCertHook(sslSocket, 
261
 
                                    (SSLBadCertHandler)myBadCertHandler, &certErr);
262
 
        if (secStatus != SECSuccess) {
263
 
                errWarn("SSL_BadCertHook");
264
 
                goto loser;
265
 
        }
266
 
 
267
 
        secStatus = SSL_HandshakeCallback(sslSocket,
268
 
                                          myHandshakeCallback,
269
 
                                                                          NULL);
270
 
        if (secStatus != SECSuccess) {
271
 
                errWarn("SSL_HandshakeCallback");
272
 
                goto loser;
273
 
        }
274
 
 
275
 
        secStatus = SSL_SetPKCS11PinArg(sslSocket, password);
276
 
        if (secStatus != SECSuccess) {
277
 
                errWarn("SSL_HandshakeCallback");
278
 
                goto loser;
279
 
        }
280
 
 
281
 
        certKEA = NSS_FindCertKEAType(cert);
282
 
 
283
 
        secStatus = SSL_ConfigSecureServer(sslSocket, cert, privKey, certKEA);
284
 
        if (secStatus != SECSuccess) {
285
 
                errWarn("SSL_ConfigSecureServer");
286
 
                goto loser;
287
 
        }
288
 
 
289
 
        return sslSocket;
290
 
 
291
 
loser:
292
 
 
293
 
        PR_Close(tcpSocket);
294
 
        return NULL;
295
 
}
296
 
 
297
 
/* Function:  authenticateSocket()
298
 
 *
299
 
 * Purpose:  Perform client authentication on the socket.
300
 
 *
301
 
 */
302
 
SECStatus
303
 
authenticateSocket(PRFileDesc *sslSocket, PRBool requireCert)
304
 
{
305
 
        CERTCertificate *cert;
306
 
        SECStatus secStatus;
307
 
 
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;
315
 
        }
316
 
 
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;
322
 
        }
323
 
 
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;
330
 
        }
331
 
 
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;
337
 
        }
338
 
 
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;
344
 
        }
345
 
 
346
 
        return SECSuccess;
347
 
}
348
 
 
349
 
/* Function:  writeDataToSocket
350
 
 *
351
 
 * Purpose:  Write the client's request back to the socket.  If the client
352
 
 *           requested a file, dump it to the socket.
353
 
 *
354
 
 */
355
 
SECStatus
356
 
writeDataToSocket(PRFileDesc *sslSocket, DataBuffer *buffer, char *fileName)
357
 
{
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>";
367
 
 
368
 
        headerLength = PORT_Strlen(defaultHeader);
369
 
 
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;
375
 
        }
376
 
 
377
 
        if (fileName) {
378
 
                PRFileInfo  info;
379
 
                PRStatus    prStatus;
380
 
 
381
 
                /* Try to open the local file named.    
382
 
                 * If successful, then write it to the client.
383
 
                 */
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;
391
 
                }
392
 
 
393
 
                local_file_fd = PR_Open(fileName, PR_RDONLY, 0);
394
 
                if (local_file_fd == NULL) {
395
 
                        PORT_Free(fileName);
396
 
                        goto writerequest;
397
 
                }
398
 
 
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;
404
 
                }
405
 
 
406
 
                /* Transmit the local file prepended by the default header
407
 
                 * across the socket.
408
 
                 */
409
 
                numBytes = PR_TransmitFile(sslSocket, local_file_fd, 
410
 
                                           defaultHeader, headerLength,
411
 
                                           PR_TRANSMITFILE_KEEP_OPEN,
412
 
                                           PR_INTERVAL_NO_TIMEOUT);
413
 
 
414
 
                /* Error in transmission. */
415
 
                if (numBytes < 0) {
416
 
                        errWarn("PR_TransmitFile");
417
 
                        /*
418
 
                        i = PORT_Strlen(errString);
419
 
                        PORT_Memcpy(buf, errString, i);
420
 
                        */
421
 
                /* Transmitted bytes successfully. */
422
 
                } else {
423
 
                        numBytes -= headerLength;
424
 
                        fprintf(stderr, "PR_TransmitFile wrote %d bytes from %s\n",
425
 
                                numBytes, fileName);
426
 
                }
427
 
 
428
 
                PORT_Free(fileName);
429
 
                PR_Close(local_file_fd);
430
 
        }
431
 
 
432
 
writerequest:
433
 
 
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;
439
 
        }
440
 
 
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;
452
 
                }
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;
461
 
                }
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;
473
 
                        }
474
 
                }
475
 
        }
476
 
 
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;
482
 
        }
483
 
 
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;
489
 
        }
490
 
 
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;
496
 
        }
497
 
 
498
 
        /* Do a nice shutdown if asked. */
499
 
        if (!strncmp(buffer->data, stopCmd, strlen(stopCmd))) {
500
 
                stopping = 1;
501
 
        }
502
 
        return SECSuccess;
503
 
 
504
 
loser:
505
 
 
506
 
        /* Do a nice shutdown if asked. */
507
 
        if (!strncmp(buffer->data, stopCmd, strlen(stopCmd))) {
508
 
                stopping = 1;
509
 
        }
510
 
        return SECFailure;
511
 
}
512
 
 
513
 
/* Function:  int handle_connection()
514
 
 *
515
 
 * Purpose:  Thread to handle a connection to a socket.
516
 
 *
517
 
 */
518
 
SECStatus
519
 
handle_connection(void *tcp_sock, int requestCert)
520
 
{
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;
528
 
 
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;
535
 
 
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);
540
 
 
541
 
        sslSocket = setupSSLSocket(tcpSocket, requestCert);
542
 
        if (sslSocket == NULL) {
543
 
                errWarn("setupSSLSocket");
544
 
                goto cleanup;
545
 
        }
546
 
 
547
 
        secStatus = SSL_ResetHandshake(sslSocket, /* asServer */ PR_TRUE);
548
 
        if (secStatus != SECSuccess) {
549
 
                errWarn("SSL_ResetHandshake");
550
 
                goto cleanup;
551
 
        }
552
 
 
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;
560
 
        }
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;
567
 
                }
568
 
        }
569
 
 
570
 
        fprintf(stdout, "\nWriting data to socket...\n\n");
571
 
        secStatus = writeDataToSocket(sslSocket, &buffer, fileName);
572
 
 
573
 
cleanup:
574
 
 
575
 
        /* Close down the socket. */
576
 
        prStatus = PR_Close(tcpSocket);
577
 
        if (prStatus != PR_SUCCESS) {
578
 
                errWarn("PR_Close");
579
 
        }
580
 
 
581
 
        return secStatus;
582
 
}
583
 
 
584
 
/* Function:  int accept_connection()
585
 
 *
586
 
 * Purpose:  Thread to accept a connection to the socket.
587
 
 *
588
 
 */
589
 
SECStatus
590
 
accept_connection(void *listener, int requestCert)
591
 
{
592
 
        PRFileDesc *listenSocket = (PRFileDesc*)listener;
593
 
        PRNetAddr   addr;
594
 
        PRStatus    prStatus;
595
 
 
596
 
        /* XXX need an SSL socket here? */
597
 
        while (!stopping) {
598
 
                PRFileDesc *tcpSocket;
599
 
                SECStatus       result;
600
 
 
601
 
                fprintf(stderr, "\n\n\nAbout to call accept.\n");
602
 
 
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;
608
 
                }
609
 
 
610
 
                /* Accepted the connection, now handle it. */
611
 
                result = launch_thread(&threadMGR, handle_connection, 
612
 
                                       tcpSocket, requestCert);
613
 
 
614
 
                if (result != SECSuccess) {
615
 
                        prStatus = PR_Close(tcpSocket);
616
 
                        if (prStatus != PR_SUCCESS) {
617
 
                                exitErr("PR_Close");
618
 
                        }
619
 
                        break;
620
 
                }
621
 
        }
622
 
 
623
 
        fprintf(stderr, "Closing listen socket.\n");
624
 
 
625
 
        prStatus = PR_Close(listenSocket);
626
 
        if (prStatus != PR_SUCCESS) {
627
 
                exitErr("PR_Close");
628
 
        }
629
 
        return SECSuccess;
630
 
}
631
 
 
632
 
/* Function:  void server_main()
633
 
 *
634
 
 * Purpose:  This is the server's main function.  It configures a socket
635
 
 *                       and listens to it.
636
 
 *
637
 
 */
638
 
void
639
 
server_main(
640
 
        unsigned short      port, 
641
 
        int                 requestCert, 
642
 
        SECKEYPrivateKey *  privKey,
643
 
        CERTCertificate *   cert, 
644
 
        PRBool              disableSSL3)
645
 
{
646
 
        SECStatus           secStatus;
647
 
        PRStatus            prStatus;
648
 
        PRFileDesc *        listenSocket;
649
 
        PRNetAddr           addr;
650
 
        PRSocketOptionData  socketOption;
651
 
 
652
 
        /* Create a new socket. */
653
 
        listenSocket = PR_NewTCPSocket();
654
 
        if (listenSocket == NULL) {
655
 
                exitErr("PR_NewTCPSocket");
656
 
        }
657
 
 
658
 
        /* Set socket to be blocking -
659
 
         * on some platforms the default is nonblocking.
660
 
         */
661
 
        socketOption.option = PR_SockOpt_Nonblocking;
662
 
        socketOption.value.non_blocking = PR_FALSE;
663
 
 
664
 
        prStatus = PR_SetSocketOption(listenSocket, &socketOption);
665
 
        if (prStatus != PR_SUCCESS) {
666
 
                exitErr("PR_SetSocketOption");
667
 
        }
668
 
 
669
 
        /* This cipher is not on by default. The Acceptance test
670
 
         * would like it to be. Turn this cipher on.
671
 
         */
672
 
        secStatus = SSL_CipherPrefSetDefault(SSL_RSA_WITH_NULL_MD5, PR_TRUE);
673
 
        if (secStatus != SECSuccess) {
674
 
                exitErr("SSL_CipherPrefSetDefault:SSL_RSA_WITH_NULL_MD5");
675
 
        }
676
 
 
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);
681
 
 
682
 
        /* Bind the address to the listener socket. */
683
 
        prStatus = PR_Bind(listenSocket, &addr);
684
 
        if (prStatus != PR_SUCCESS) {
685
 
                exitErr("PR_Bind");
686
 
        }
687
 
 
688
 
        /* Listen for connection on the socket.  The second argument is
689
 
         * the maximum size of the queue for pending connections.
690
 
         */
691
 
        prStatus = PR_Listen(listenSocket, 5);
692
 
        if (prStatus != PR_SUCCESS) {
693
 
                exitErr("PR_Listen");
694
 
        }
695
 
 
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);
704
 
        }
705
 
}
706
 
 
707
 
/* Function: int main()
708
 
 *
709
 
 * Purpose:  Parses command arguments and configures SSL server.
710
 
 *
711
 
 */
712
 
int
713
 
main(int argc, char **argv)
714
 
{
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;
725
 
 
726
 
        /* Zero out the thread manager. */
727
 
        PORT_Memset(&threadMGR, 0, sizeof(threadMGR));
728
 
 
729
 
        progName = PL_strdup(argv[0]);
730
 
 
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);
746
 
                }
747
 
        }
748
 
 
749
 
        if (nickName == NULL || port == 0)
750
 
                Usage(progName);
751
 
 
752
 
        /* Call the NSPR initialization routines. */
753
 
        PR_Init( PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
754
 
 
755
 
        /* Set the cert database password callback. */
756
 
        PK11_SetPasswordFunc(myPasswd);
757
 
 
758
 
        /* Initialize NSS. */
759
 
        secStatus = NSS_Init(dir);
760
 
        if (secStatus != SECSuccess) {
761
 
                exitErr("NSS_Init");
762
 
        }
763
 
 
764
 
        /* Set the policy for this server (REQUIRED - no default). */
765
 
        secStatus = NSS_SetDomesticPolicy();
766
 
        if (secStatus != SECSuccess) {
767
 
                exitErr("NSS_SetDomesticPolicy");
768
 
        }
769
 
 
770
 
        /* XXX keep this? */
771
 
        /* all the SSL2 and SSL3 cipher suites are enabled by default. */
772
 
        if (cipherString) {
773
 
            int ndx;
774
 
 
775
 
            /* disable all the ciphers, then enable the ones we want. */
776
 
            disableAllSSLCiphers();
777
 
 
778
 
            while (0 != (ndx = *cipherString++)) {
779
 
                int *cptr;
780
 
                int  cipher;
781
 
 
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()");
792
 
                }
793
 
            }
794
 
        }
795
 
 
796
 
        /* Get own certificate and private key. */
797
 
        cert = PK11_FindCertFromNickname(nickName, password);
798
 
        if (cert == NULL) {
799
 
                exitErr("PK11_FindCertFromNickname");
800
 
        }
801
 
 
802
 
        privKey = PK11_FindKeyByAnyCert(cert, password);
803
 
        if (privKey == NULL) {
804
 
                exitErr("PK11_FindKeyByAnyCert");
805
 
        }
806
 
 
807
 
        /* Configure the server's cache for a multi-process application
808
 
         * using default timeout values (24 hrs) and directory location (/tmp). 
809
 
         */
810
 
        SSL_ConfigMPServerSIDCache(256, 0, 0, NULL);
811
 
 
812
 
        /* Launch server. */
813
 
        server_main(port, requestCert, privKey, cert, disableSSL3);
814
 
 
815
 
        /* Shutdown NSS and exit NSPR gracefully. */
816
 
        if (NSS_Shutdown() != SECSuccess) {
817
 
            exit(1);
818
 
        }
819
 
        PR_Cleanup();
820
 
        return 0;
821
 
}