source: rtems/c/src/libnetworking/rtems_webserver/websSSL.c @ 2e7f00fc

4.104.114.84.95
Last change on this file since 2e7f00fc was 2e7f00fc, checked in by Joel Sherrill <joel.sherrill@…>, on 04/11/03 at 16:34:49

2003-04-11 Joel Sherrill <joel@…>

  • rtems_webserver/cgi.c, rtems_webserver/sockGen.c, rtems_webserver/umui.c, rtems_webserver/websSSL.c, rtems_webserver/websSSL.h, rtems_webserver/websda.c, rtems_webserver/websda.h: New files. Not included in previous commit.
  • Property mode set to 100644
File size: 13.9 KB
Line 
1/*
2 * websSSL.c -- SSL envrionment creation
3 *
4 * Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
5 *
6 * See the file "license.txt" for usage and redistribution license requirements
7 *
8 * $Id$
9 */
10
11/******************************** Description *********************************/
12
13/*
14 *      This module implements a patch into SSL implementations for the webs
15 *      module.
16 */
17
18/********************************* Includes ***********************************/
19
20#include        "wsIntrn.h"
21#include        "webs.h"
22#include        "websSSL.h"
23
24/******************************* Definitions **********************************/
25
26#define DEFAULT_CERT_FILE       "./server.pem"
27#define DEFAULT_KEY_FILE        "./certs/cakey.pem"
28#define DEFAULT_CA_FILE         "./certs/cacert.pem"
29#define DEFAULT_CA_PATH         "./certs/"
30#define SSL_PORT                        443
31
32/*
33 *      Define the components of the apps_startup() macro
34 */
35
36#ifdef SIGPIPE
37#define do_pipe_sig()   signal(SIGPIPE,SIG_IGN)
38#else
39#define do_pipe_sig()
40#endif
41
42#ifdef OPENSSL
43#define SSLC_add_all_algorithms()       SSLeay_add_all_algorithms()
44#else
45extern void SSLC_add_all_algorithms(void);
46#endif
47
48/*
49 *      Define the apps_startup() macro
50 */
51
52#  if defined(MSDOS) || defined(WIN16) || defined(WIN32)
53#    ifdef _O_BINARY
54#      define apps_startup() \
55                _fmode=_O_BINARY; do_pipe_sig(); CRYPTO_malloc_init(); \
56                SSLC_add_all_algorithms()
57#    else
58#      define apps_startup() \
59                _fmode=O_BINARY; do_pipe_sig(); CRYPTO_malloc_init(); \
60                SSLC_add_all_algorithms()
61#    endif
62#  else
63#    define apps_startup()      do_pipe_sig(); SSLC_add_all_algorithms();
64#  endif
65
66/*************************** Forward Declarations *****************************/
67
68static int              websSSLSetCertStuff(SSL_CTX *ctx,
69                                                                        char *cert_file,
70                                                                        char *key_file);
71static int              websSSLVerifyCallback(int ok, X509_STORE_CTX *ctx);
72static RSA              *websSSLTempRSACallback(SSL *s, int is_export, int keylength);
73
74static int              websSSLReadEvent (webs_t wp);
75static int              websSSLAccept(int sid, char *ipaddr, int port, int listenSid);
76static void             websSSLSocketEvent(int sid, int mask, int data);
77
78/*********************************** Locals ***********************************/
79
80static int              sslListenSock = -1;                     /* Listen socket */
81static SSL_CTX  *sslctx = NULL;
82
83/******************************************************************************/
84/*
85 *      Start up the SSL Context for the application, and start a listen on the
86 *      SSL port (usually 443, and defined by SSL_PORT)
87 *      Return 0 on success, -1 on failure.
88 */
89
90int websSSLOpen()
91{
92        char            *certFile, *keyFile, *CApath, *CAfile;
93        SSL_METHOD      *meth;
94       
95/*
96 *      Install and initialize the SSL library
97 */
98        apps_startup();
99        trace(7, T("SSL: Initializing SSL\n"));
100
101#ifdef SSLC
102        SSL_library_init();
103#endif
104
105        SSL_load_error_strings();
106
107#ifdef OPENSSL
108        SSLeay_add_ssl_algorithms();
109#endif
110
111/*
112 *      Important!  Enable both SSL versions 2 and 3
113 */
114        meth = SSLv23_server_method();
115        sslctx = SSL_CTX_new(meth);
116
117        a_assert(sslctx);
118
119        if (sslctx == NULL) {
120                trace(2, T("SSL: Unable to create SSL context!\n"));
121                return -1;
122        }
123
124/*
125 *      Adjust some SSL Context variables
126 */
127        SSL_CTX_set_quiet_shutdown(sslctx, 1);
128        SSL_CTX_set_options(sslctx, 0);
129        SSL_CTX_sess_set_cache_size(sslctx, 128);
130
131/*
132 *      Set the certificate verification locations
133 */
134        CApath = DEFAULT_CA_PATH;
135        CAfile = DEFAULT_CA_FILE;
136        if ((!SSL_CTX_load_verify_locations(sslctx, CAfile, CApath)) ||
137                (!SSL_CTX_set_default_verify_paths(sslctx))) {
138                trace(2, T("SSL: Unable to set cert verification locations!\n"));
139                websSSLClose();
140                return -1;
141        }
142
143/*
144 *      Set the certificate and key files for the SSL context
145 */
146        certFile = DEFAULT_CERT_FILE;
147        keyFile = NULL;
148        if (websSSLSetCertStuff(sslctx, certFile, keyFile) != 0) {
149                websSSLClose();
150                return -1;
151        }
152
153/*
154 *      Set the RSA callback for the SSL context
155 */
156        SSL_CTX_set_tmp_rsa_callback(sslctx, websSSLTempRSACallback);
157
158/*
159 *      Set the verification callback for the SSL context
160 */
161        SSL_CTX_set_verify(sslctx, SSL_VERIFY_NONE, websSSLVerifyCallback);
162
163/*
164 *      Set the certificate authority list for the client
165 */
166        SSL_CTX_set_client_CA_list(sslctx, SSL_load_client_CA_file(CAfile));
167
168/*
169 *      Open the socket
170 */
171        sslListenSock = socketOpenConnection(NULL, SSL_PORT,
172                websSSLAccept, SOCKET_BLOCK);
173
174        if (sslListenSock < 0) {
175                trace(2, T("SSL: Unable to open SSL socket on port <%d>!\n"),
176                        SSL_PORT);
177                return -1;
178        }
179
180        return 0;
181}
182
183/******************************************************************************/
184/*
185 *      Return TRUE if websSSL has been opened
186 */
187
188int websSSLIsOpen()
189{
190        return (sslListenSock != -1);
191}
192
193/******************************************************************************/
194/*
195 *      Stops the SSL
196 */
197
198void websSSLClose()
199{
200        trace(7, T("SSL: Closing SSL\n"));
201
202        if (sslctx != NULL) {
203                SSL_CTX_free(sslctx);
204                sslctx = NULL;
205        }
206
207        if (sslListenSock != -1) {
208                socketCloseConnection(sslListenSock);
209                sslListenSock = -1;
210        }
211
212#ifdef SSLC
213        SSL_library_cleanup();
214#endif
215}
216
217/******************************************************************************/
218/*
219 *      Accept a connection
220 */
221
222int websSSLAccept(int sid, char *ipaddr, int port, int listenSid)
223{
224        webs_t  wp;
225        int             wid;
226
227        a_assert(ipaddr && *ipaddr);
228        a_assert(sid >= 0);
229        a_assert(port >= 0);
230
231/*
232 *      Allocate a new handle for this accepted connection. This will allocate
233 *      a webs_t structure in the webs[] list
234 */
235        if ((wid = websAlloc(sid)) < 0) {
236                return -1;
237        }
238        wp = webs[wid];
239        a_assert(wp);
240        wp->listenSid = listenSid;
241
242        ascToUni(wp->ipaddr, ipaddr, min(sizeof(wp->ipaddr), strlen(ipaddr)+1));
243
244/*
245 *      Check if this is a request from a browser on this system. This is useful
246 *      to know for permitting administrative operations only for local access
247 */
248        if (gstrcmp(wp->ipaddr, T("127.0.0.1")) == 0 ||
249                        gstrcmp(wp->ipaddr, websIpaddr) == 0 ||
250                        gstrcmp(wp->ipaddr, websHost) == 0) {
251                wp->flags |= WEBS_LOCAL_REQUEST;
252        }
253/*
254 *      Since the acceptance came in on this channel, it must be secure
255 */
256        wp->flags |= WEBS_SECURE;
257
258/*
259 *      Arrange for websSocketEvent to be called when read data is available
260 */
261        socketCreateHandler(sid, SOCKET_READABLE, websSSLSocketEvent, (int) wp);
262
263/*
264 *      Arrange for a timeout to kill hung requests
265 */
266        wp->timeout = emfSchedCallback(WEBS_TIMEOUT, websTimeout, (void *) wp);
267        trace(8, T("webs: accept request\n"));
268        return 0;
269}
270
271/******************************************************************************/
272/*
273 *      The webs socket handler.  Called in response to I/O. We just pass control
274 *      to the relevant read or write handler. A pointer to the webs structure
275 *      is passed as an (int) in iwp.
276 */
277
278static void websSSLSocketEvent(int sid, int mask, int iwp)
279{
280        webs_t  wp;
281
282        wp = (webs_t) iwp;
283        a_assert(wp);
284
285        if (! websValid(wp)) {
286                return;
287        }
288
289        if (mask & SOCKET_READABLE) {
290                websSSLReadEvent(wp);
291        }
292        if (mask & SOCKET_WRITABLE) {
293                if (wp->writeSocket) {
294                        (*wp->writeSocket)(wp);
295                }
296        }
297}
298
299/******************************************************************************/
300/*
301 *      Handler for SSL Read Events
302 */
303
304static int websSSLReadEvent (webs_t wp)
305{
306        int                     ret, sock;
307        socket_t        *sptr;
308        SSL                     *ssl;
309        BIO                     *bio, *bioSSL, *bioSock;
310#ifdef DEV
311        const char      *ciphers;
312#endif
313
314        a_assert (wp);
315        a_assert(websValid(wp));
316
317        sptr = socketPtr(wp->sid);
318        a_assert(sptr);
319
320        sock = sptr->sock;
321
322/*
323 *      Create a new BIO and SSL session for this web request
324 */
325        bio = BIO_new(BIO_f_buffer());
326        a_assert(bio);
327
328        if (!BIO_set_write_buffer_size(bio, 128)) {
329                return -1;
330        }
331
332        ssl = (SSL *) SSL_new(sslctx);
333        a_assert(ssl);
334
335        if (ssl == NULL) {
336                return -1;
337        }
338
339        SSL_set_session(ssl, NULL);
340
341        bioSSL =  BIO_new(BIO_f_ssl());
342        a_assert(bioSSL);
343
344        bioSock = BIO_new_socket(sock, BIO_NOCLOSE);
345        a_assert(bioSock);
346
347        SSL_set_bio(ssl, bioSock, bioSock);
348        SSL_set_accept_state(ssl);
349
350        ret = BIO_set_ssl(bioSSL, ssl, BIO_CLOSE);
351        BIO_push(bio, bioSSL);
352
353#ifdef DEV
354        ciphers = SSL_get_cipher_list(ssl, 10);
355#endif
356
357/*
358 *      Create the SSL data structure in the wp.
359 */
360#ifdef WEBS_SSL_SUPPORT
361        wp->wsp = balloc(B_L, sizeof(websSSL_t));
362        a_assert (wp->wsp);
363        (wp->wsp)->bio = bio;
364        (wp->wsp)->ssl = ssl;
365#endif
366
367/*
368 *      Call the default Read Event
369 */
370        websReadEvent(wp);
371
372        return ret;
373}
374
375
376/******************************************************************************/
377/*
378 *      SSL Verification Callback
379 */
380
381static int sslVerifyDepth = 0;
382static int sslVerifyError = X509_V_OK;
383
384int websSSLVerifyCallback(int ok, X509_STORE_CTX *ctx)
385{
386        char    buf[256];
387        X509    *errCert;
388        int             err;
389        int             depth;
390
391        errCert =       X509_STORE_CTX_get_current_cert(ctx);
392        err =           X509_STORE_CTX_get_error(ctx);
393        depth =         X509_STORE_CTX_get_error_depth(ctx);
394
395        X509_NAME_oneline(X509_get_subject_name(errCert), buf, 256);
396
397        if (!ok) {
398                if (sslVerifyDepth >= depth)    {
399                        ok = 1;
400                        sslVerifyError = X509_V_OK;
401                } else {
402                        ok=0;
403                        sslVerifyError = X509_V_ERR_CERT_CHAIN_TOO_LONG;
404                }
405        }
406
407        switch (err)    {
408        case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
409#ifdef OPENSSL
410                X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert), buf, 256);
411#endif
412                break;
413
414        case X509_V_ERR_CERT_NOT_YET_VALID:
415        case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
416        case X509_V_ERR_CERT_HAS_EXPIRED:
417        case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
418                break;
419        }
420
421        return ok;
422}
423
424/******************************************************************************/
425/*
426 *      Set the SSL certificate and key for the SSL context
427 */
428
429int websSSLSetCertStuff(SSL_CTX *ctx, char *certFile, char *keyFile)
430{
431        a_assert (ctx);
432        a_assert (certFile);
433
434        if (certFile != NULL) {
435                if (SSL_CTX_use_certificate_file(ctx, certFile,
436                        SSL_FILETYPE_PEM) <= 0) {
437                        trace(2, T("SSL: Unable to set certificate file <%s>\n"),
438                                certFile);
439                        return -1;
440                }
441
442                if (keyFile == NULL) {
443                        keyFile = certFile;
444                }
445
446                if (SSL_CTX_use_PrivateKey_file(ctx, keyFile, SSL_FILETYPE_PEM) <= 0) {
447                        trace(2, T("SSL: Unable to set private key file <%s>\n"),
448                                keyFile);
449                        return -1;
450                }
451
452/*             
453 *              Now we know that a key and cert have been set against
454 *              the SSL context
455 */
456                if (!SSL_CTX_check_private_key(ctx)) {
457                        trace(2, T("SSL: Check of private key file <%s> FAILED!\n"),
458                                keyFile);
459                        return -1;
460                }
461        }
462
463        return 0;
464}
465
466/******************************************************************************/
467/*
468 *      Set certificate file for SSL context
469 */
470
471int websSSLSetCertFile(char_t *certFile)
472{
473        a_assert (sslctx);
474        a_assert (certFile);
475
476        if (sslctx == NULL) {
477                return -1;
478        }
479
480        if (SSL_CTX_use_certificate_file(sslctx, certFile,
481                SSL_FILETYPE_PEM) <= 0) {
482                return -1;
483        }
484/*             
485 *      Confirm that the certificate and the private key jive.
486 */
487        if (!SSL_CTX_check_private_key(sslctx)) {
488                return -1;
489        }
490
491        return 0;
492}
493
494/******************************************************************************/
495/*
496 *      Set key file for SSL context
497 */
498
499int websSSLSetKeyFile(char_t *keyFile)
500{
501        a_assert (sslctx);
502        a_assert (keyFile);
503
504        if (sslctx == NULL) {
505                return -1;
506        }
507
508        if (SSL_CTX_use_PrivateKey_file(sslctx, keyFile, SSL_FILETYPE_PEM) <= 0) {
509                return -1;
510        }
511/*             
512 *      Confirm that the certificate and the private key jive.
513 */
514        if (!SSL_CTX_check_private_key(sslctx)) {
515                return -1;
516        }
517
518        return 0;
519}
520
521#ifdef SSLC
522extern RSA *RSA_new(void);
523#endif
524
525/******************************************************************************/
526/*
527 *      the Temporary RSA callback
528 */
529
530static RSA *websSSLTempRSACallback(SSL *ssl, int isExport, int keyLength)
531{
532        static RSA *rsaTemp = NULL;
533
534        if (rsaTemp == NULL) {
535
536#ifdef OPENSSL
537                rsaTemp = RSA_generate_key(keyLength, RSA_F4, NULL, NULL);
538#endif
539
540#ifdef SSLC
541                rsaTemp = RSA_new();
542#endif
543
544        }
545
546        return rsaTemp;
547}
548
549/******************************************************************************/
550/*
551 *      Free SSL resources
552 */
553
554int websSSLFree(websSSL_t *wsp)
555{
556        if (wsp == NULL) {
557                return -1;
558        }
559
560/*
561 *      Make sure we re-use sessions
562 */
563        if (wsp->ssl != NULL) {
564                SSL_set_shutdown(wsp->ssl, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN);
565        }
566
567        if (wsp->bio != NULL) {
568                BIO_free_all(wsp->bio);
569        }
570
571        bfree(B_L, wsp);
572
573        return 0;
574}
575
576/******************************************************************************/
577/*
578 *      Return Eof for the SSL BIO
579 */
580
581int websSSLEof(websSSL_t *wsp)
582{
583        a_assert(wsp);
584
585        if ((wsp == NULL) || (wsp->bio == NULL)) {
586                return -1;
587        }
588
589        return BIO_eof(wsp->bio);
590}
591
592/******************************************************************************/
593/*
594 *      Perform a read of the SSL BIO
595 */
596
597int websSSLRead(websSSL_t *wsp, char_t *buf, int len)
598{
599        a_assert(wsp);
600        a_assert(buf);
601
602        if ((wsp == NULL) || (wsp->bio == NULL)) {
603                return -1;
604        }
605
606        return BIO_read(wsp->bio, buf, len);
607}
608
609/******************************************************************************/
610/*
611 *      Perform a gets of the SSL BIO, returning an balloc'ed string
612 */
613
614#define BUF_BLOCK 256
615
616int websSSLGets(websSSL_t *wsp, char_t **buf)
617{
618        int             rc,     len, lenBuf;
619        char    c;
620
621        a_assert(wsp);
622        a_assert(buf);
623
624        lenBuf = 0;
625        len = 0;
626
627        if ((wsp == NULL) || (wsp->bio == NULL)) {
628                return -1;
629        }
630
631        while (1) {
632
633                if ((rc = BIO_read(wsp->bio, &c, 1)) < 0) {
634                        return rc;
635                }
636               
637                if (rc == 0) {
638/*
639 *                      If there is a partial line and we are at EOF, pretend we saw a '\n'
640 */
641                        if (len > 0 && BIO_eof(wsp->bio)) {
642                                c = '\n';
643                        } else {
644                                return -1;
645                        }
646                }
647/*
648 *              If a newline is seen, return the data excluding the new line to the
649 *              caller. If carriage return is seen, just eat it.
650 */
651                if (c == '\n') {
652                        if ((len > 0) && (len < lenBuf)) {
653                                (*buf)[len] = 0;
654                        }
655                        return len;
656                } else if (c == '\r') {
657                        continue;
658                }
659/*
660 *              Append character to buf
661 */
662                if (len >= lenBuf) {
663                        lenBuf += BUF_BLOCK;
664                        *buf = brealloc(B_L, *buf, lenBuf);
665                }
666
667                a_assert(*buf);
668                (*buf)[len] = c;
669                len++;
670        }
671}
672
673/******************************************************************************/
674/*
675 *      Perform a write to the SSL BIO
676 */
677
678int websSSLWrite(websSSL_t *wsp, char_t *buf, int len)
679{
680        a_assert(wsp);
681        a_assert(buf);
682
683        if ((wsp == NULL) || (wsp->bio == NULL)) {
684                return -1;
685        }
686
687        return BIO_write(wsp->bio, buf, len);
688}
689
690/******************************************************************************/
691/*
692 *      Perform a flush of the SSL BIO
693 */
694
695int websSSLFlush(websSSL_t *wsp)
696{
697        a_assert(wsp);
698
699        if ((wsp == NULL) || (wsp->bio == NULL)) {
700                return -1;
701        }
702
703        return BIO_flush(wsp->bio);
704}
705
706/******************************************************************************/
Note: See TracBrowser for help on using the repository browser.