From bc764dbb7c04452a7eae9ff6d010d225ae8a5530 Mon Sep 17 00:00:00 2001 From: hniksic Date: Thu, 6 Nov 2003 05:06:59 -0800 Subject: [PATCH] [svn] Improve SSL code. Only initialize PRNG when needed. --- src/ChangeLog | 7 +++ src/gen_sslfunc.c | 106 ++++++++++++++++++++++++---------------------- src/gen_sslfunc.h | 13 ++---- src/http.c | 62 +++++++++++---------------- src/main.c | 10 ----- 5 files changed, 91 insertions(+), 107 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index dedaeade..c79bc8bc 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,10 @@ +2003-11-06 Hrvoje Niksic + + * gen_sslfunc.c (ssl_read): Implement a more correct check for + EINTR. + (ssl_write): Ditto. + (init_ssl): Use a global SSL context. + 2003-11-06 Hrvoje Niksic * connect.c (xclose): Free INFO even if it doesn't provide a diff --git a/src/gen_sslfunc.c b/src/gen_sslfunc.c index 2fe2e386..26d94b99 100644 --- a/src/gen_sslfunc.c +++ b/src/gen_sslfunc.c @@ -58,7 +58,9 @@ so, delete this exception statement from your version. */ extern int errno; #endif -void +SSL_CTX *ssl_ctx; + +static void ssl_init_prng (void) { /* It is likely that older versions of OpenSSL will fail on @@ -108,17 +110,10 @@ ssl_init_prng (void) unsigned char rnd = random_number (256); RAND_seed (&rnd, sizeof (rnd)); } - - if (RAND_status () == 0) - { - logprintf (LOG_NOTQUIET, - _("Could not seed OpenSSL PRNG; disabling SSL.\n")); - scheme_disable (SCHEME_HTTPS); - } #endif /* SSLEAY_VERSION_NUMBER >= 0x00905100 */ } -int +static int verify_callback (int ok, X509_STORE_CTX *ctx) { char *s, buf[256]; @@ -139,30 +134,40 @@ verify_callback (int ok, X509_STORE_CTX *ctx) return ok; } -/* pass all ssl errors to DEBUGP - returns the number of printed errors */ -int -ssl_printerrors (void) +/* Print SSL errors. */ + +void +ssl_print_errors (void) { - int ocerr = 0; unsigned long curerr = 0; char errbuff[1024]; xzero (errbuff); while ((curerr = ERR_get_error ()) != 0) - { - DEBUGP (("OpenSSL: %s\n", ERR_error_string (curerr, errbuff))); - ++ocerr; - } - return ocerr; + logprintf (LOG_NOTQUIET, "OpenSSL: %s\n", + ERR_error_string (curerr, errbuff)); } /* Creates a SSL Context and sets some defaults for it */ uerr_t -init_ssl (SSL_CTX **ctx) +ssl_init () { SSL_METHOD *meth = NULL; int verify; int can_validate; + + if (ssl_ctx) + return 0; + + /* Init the PRNG. If that fails, bail out. */ + ssl_init_prng (); + if (RAND_status () == 0) + { + logprintf (LOG_NOTQUIET, + _("Could not seed OpenSSL PRNG; disabling SSL.\n")); + scheme_disable (SCHEME_HTTPS); + return SSLERRCTXCREATE; + } + SSL_library_init (); SSL_load_error_strings (); SSLeay_add_all_algorithms (); @@ -184,20 +189,20 @@ init_ssl (SSL_CTX **ctx) } if (meth == NULL) { - ssl_printerrors (); + ssl_print_errors (); return SSLERRCTXCREATE; } - *ctx = SSL_CTX_new (meth); + ssl_ctx = SSL_CTX_new (meth); if (meth == NULL) { - ssl_printerrors (); + ssl_print_errors (); return SSLERRCTXCREATE; } /* Can we validate the server Cert ? */ if (opt.sslcadir != NULL || opt.sslcafile != NULL) { - SSL_CTX_load_verify_locations (*ctx, opt.sslcafile, opt.sslcadir); + SSL_CTX_load_verify_locations (ssl_ctx, opt.sslcafile, opt.sslcadir); can_validate = 1; } else @@ -224,7 +229,7 @@ init_ssl (SSL_CTX **ctx) } } - SSL_CTX_set_verify (*ctx, verify, verify_callback); + SSL_CTX_set_verify (ssl_ctx, verify, verify_callback); if (opt.sslcertfile != NULL || opt.sslcertkey != NULL) { @@ -239,14 +244,16 @@ init_ssl (SSL_CTX **ctx) if (opt.sslcertfile == NULL) opt.sslcertfile = opt.sslcertkey; - if (SSL_CTX_use_certificate_file (*ctx, opt.sslcertfile, ssl_cert_type) <= 0) + if (SSL_CTX_use_certificate_file (ssl_ctx, opt.sslcertfile, + ssl_cert_type) <= 0) { - ssl_printerrors (); + ssl_print_errors (); return SSLERRCERTFILE; } - if (SSL_CTX_use_PrivateKey_file (*ctx, opt.sslcertkey , ssl_cert_type) <= 0) + if (SSL_CTX_use_PrivateKey_file (ssl_ctx, opt.sslcertkey, + ssl_cert_type) <= 0) { - ssl_printerrors (); + ssl_print_errors (); return SSLERRCERTKEY; } } @@ -254,28 +261,30 @@ init_ssl (SSL_CTX **ctx) return 0; /* Succeded */ } -static -int ssl_read (int fd, char *buf, int bufsize, void *ctx) +static int +ssl_read (int fd, char *buf, int bufsize, void *ctx) { - int res; + int ret; SSL *ssl = (SSL *) ctx; - /* #### Does SSL_read actually set EINTR? */ do - res = SSL_read (ssl, buf, bufsize); - while (res == -1 && errno == EINTR); - return res; + ret = SSL_read (ssl, buf, bufsize); + while (ret == -1 + && SSL_get_error (ssl, ret) == SSL_ERROR_SYSCALL + && errno == EINTR); + return ret; } static int ssl_write (int fd, char *buf, int bufsize, void *ctx) { - int res = 0; + int ret = 0; SSL *ssl = (SSL *) ctx; - /* #### Does SSL_write actually set EINTR? */ do - res = SSL_write (ssl, buf, bufsize); - while (res == -1 && errno == EINTR); - return res; + ret = SSL_write (ssl, buf, bufsize); + while (ret == -1 + && SSL_get_error (ssl, ret) == SSL_ERROR_SYSCALL + && errno == EINTR); + return ret; } static int @@ -312,9 +321,12 @@ ssl_close (int fd, void *ctx) /* Sets up a SSL structure and performs the handshake on fd. */ SSL * -connect_ssl (int fd, SSL_CTX *ctx) +ssl_connect (int fd) { - SSL *ssl = SSL_new (ctx); + SSL *ssl; + + assert (ssl_ctx != NULL); + ssl = SSL_new (ssl_ctx); if (!ssl) goto err; if (!SSL_set_fd (ssl, fd)) @@ -331,14 +343,8 @@ connect_ssl (int fd, SSL_CTX *ctx) return ssl; err: - ssl_printerrors (); + ssl_print_errors (); if (ssl) SSL_free (ssl); return NULL; } - -void -free_ssl_ctx (SSL_CTX * ctx) -{ - SSL_CTX_free (ctx); -} diff --git a/src/gen_sslfunc.h b/src/gen_sslfunc.h index ece2249d..a3650d09 100644 --- a/src/gen_sslfunc.h +++ b/src/gen_sslfunc.h @@ -31,16 +31,9 @@ so, delete this exception statement from your version. */ #ifndef GEN_SSLFUNC_H #define GEN_SSLFUNC_H -#ifdef HAVE_SSL -# include -#endif +int ssl_init PARAMS ((void)); -void ssl_init_prng PARAMS ((void)); -int init_ssl PARAMS ((SSL_CTX **)); - -SSL *connect_ssl PARAMS ((int, SSL_CTX *)); -void free_ssl_ctx PARAMS ((SSL_CTX *)); -int verify_callback PARAMS ((int, X509_STORE_CTX *)); -int ssl_printerrors PARAMS ((void)); +int ssl_connect PARAMS ((int)); +int ssl_print_error PARAMS ((void)); #endif /* GEN_SSLFUNC_H */ diff --git a/src/http.c b/src/http.c index d7b66a3a..b6e3a64c 100644 --- a/src/http.c +++ b/src/http.c @@ -583,9 +583,6 @@ gethttp (struct url *u, struct http_stat *hs, int *dt, struct url *proxy) FILE *fp; int auth_tried_already; struct rbuf rbuf; -#ifdef HAVE_SSL - static SSL_CTX *ssl_ctx = NULL; -#endif int using_ssl = 0; char *cookies = NULL; @@ -610,40 +607,31 @@ gethttp (struct url *u, struct http_stat *hs, int *dt, struct url *proxy) long post_data_size = 0; #ifdef HAVE_SSL - /* initialize ssl_ctx on first run */ - if (!ssl_ctx) + /* Initialize the SSL context. After the first run, this is a + no-op. */ + switch (ssl_init ()) { - uerr_t err = init_ssl (&ssl_ctx); - if (err != 0) - { - switch (err) - { - case SSLERRCTXCREATE: - /* this is fatal */ - logprintf (LOG_NOTQUIET, _("Failed to set up an SSL context\n")); - ssl_printerrors (); - return err; - case SSLERRCERTFILE: - /* try without certfile */ - logprintf (LOG_NOTQUIET, - _("Failed to load certificates from %s\n"), - opt.sslcertfile); - ssl_printerrors (); - logprintf (LOG_NOTQUIET, - _("Trying without the specified certificate\n")); - break; - case SSLERRCERTKEY: - logprintf (LOG_NOTQUIET, - _("Failed to get certificate key from %s\n"), - opt.sslcertkey); - ssl_printerrors (); - logprintf (LOG_NOTQUIET, - _("Trying without the specified certificate\n")); - break; - default: - break; - } - } + case SSLERRCTXCREATE: + /* this is fatal */ + logprintf (LOG_NOTQUIET, _("Failed to set up an SSL context\n")); + return SSLERRCTXCREATE; + case SSLERRCERTFILE: + /* try without certfile */ + logprintf (LOG_NOTQUIET, + _("Failed to load certificates from %s\n"), + opt.sslcertfile); + logprintf (LOG_NOTQUIET, + _("Trying without the specified certificate\n")); + break; + case SSLERRCERTKEY: + logprintf (LOG_NOTQUIET, + _("Failed to get certificate key from %s\n"), + opt.sslcertkey); + logprintf (LOG_NOTQUIET, + _("Trying without the specified certificate\n")); + break; + default: + break; } #endif /* HAVE_SSL */ @@ -699,7 +687,7 @@ gethttp (struct url *u, struct http_stat *hs, int *dt, struct url *proxy) #ifdef HAVE_SSL if (conn->scheme == SCHEME_HTTPS) { - if (!connect_ssl (sock, ssl_ctx)) + if (!ssl_connect (sock)) { logputs (LOG_VERBOSE, "\n"); logprintf (LOG_NOTQUIET, diff --git a/src/main.c b/src/main.c index 207654b3..0f93690b 100644 --- a/src/main.c +++ b/src/main.c @@ -65,10 +65,6 @@ extern int errno; #include "progress.h" /* for progress_handle_sigwinch */ #include "convert.h" -#ifdef HAVE_SSL -# include "gen_sslfunc.h" -#endif - /* On GNU system this will include system-wide getopt.h. */ #include "getopt.h" @@ -873,12 +869,6 @@ Can't timestamp and not clobber old files at the same time.\n")); #endif #endif /* HAVE_SIGNAL */ -#ifdef HAVE_SSL - /* Must call this before resolving any URLs because it has the power - to disable `https'. */ - ssl_init_prng (); -#endif - status = RETROK; /* initialize it, just-in-case */ /* Retrieve the URLs from argument list. */ for (t = url; *t; t++)