~ubuntu-branches/ubuntu/lucid/seamonkey/lucid-security

« back to all changes in this revision

Viewing changes to security/nss-fips/cmd/SSLsample/server.c

  • Committer: Bazaar Package Importer
  • Author(s): Fabien Tassin
  • Date: 2008-07-29 21:29:02 UTC
  • mfrom: (1.1.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20080729212902-spm9kpvchp9udwbw
Tags: 1.1.11+nobinonly-0ubuntu1
* New security upstream release: 1.1.11 (LP: #218534)
  Fixes USN-602-1, USN-619-1, USN-623-1 and USN-629-1
* Refresh diverged patch:
  - update debian/patches/80_security_build.patch
* Fix FTBFS with missing -lfontconfig
  - add debian/patches/11_fix_ftbfs_with_fontconfig.patch
  - update debian/patches/series
* Build with default gcc (hardy: 4.2, intrepid: 4.3)
  - update debian/rules
  - update debian/control

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
                                         (SSLHandshakeCallback)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
}