[svn] Improve SSL code. Only initialize PRNG when needed.

This commit is contained in:
hniksic 2003-11-06 05:06:59 -08:00
parent 49dfcb6036
commit bc764dbb7c
5 changed files with 91 additions and 107 deletions

View File

@ -1,3 +1,10 @@
2003-11-06 Hrvoje Niksic <hniksic@xemacs.org>
* 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 <hniksic@xemacs.org> 2003-11-06 Hrvoje Niksic <hniksic@xemacs.org>
* connect.c (xclose): Free INFO even if it doesn't provide a * connect.c (xclose): Free INFO even if it doesn't provide a

View File

@ -58,7 +58,9 @@ so, delete this exception statement from your version. */
extern int errno; extern int errno;
#endif #endif
void SSL_CTX *ssl_ctx;
static void
ssl_init_prng (void) ssl_init_prng (void)
{ {
/* It is likely that older versions of OpenSSL will fail on /* 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); unsigned char rnd = random_number (256);
RAND_seed (&rnd, sizeof (rnd)); 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 */ #endif /* SSLEAY_VERSION_NUMBER >= 0x00905100 */
} }
int static int
verify_callback (int ok, X509_STORE_CTX *ctx) verify_callback (int ok, X509_STORE_CTX *ctx)
{ {
char *s, buf[256]; char *s, buf[256];
@ -139,30 +134,40 @@ verify_callback (int ok, X509_STORE_CTX *ctx)
return ok; return ok;
} }
/* pass all ssl errors to DEBUGP /* Print SSL errors. */
returns the number of printed errors */
int void
ssl_printerrors (void) ssl_print_errors (void)
{ {
int ocerr = 0;
unsigned long curerr = 0; unsigned long curerr = 0;
char errbuff[1024]; char errbuff[1024];
xzero (errbuff); xzero (errbuff);
while ((curerr = ERR_get_error ()) != 0) while ((curerr = ERR_get_error ()) != 0)
{ logprintf (LOG_NOTQUIET, "OpenSSL: %s\n",
DEBUGP (("OpenSSL: %s\n", ERR_error_string (curerr, errbuff))); ERR_error_string (curerr, errbuff));
++ocerr;
}
return ocerr;
} }
/* Creates a SSL Context and sets some defaults for it */ /* Creates a SSL Context and sets some defaults for it */
uerr_t uerr_t
init_ssl (SSL_CTX **ctx) ssl_init ()
{ {
SSL_METHOD *meth = NULL; SSL_METHOD *meth = NULL;
int verify; int verify;
int can_validate; 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_library_init ();
SSL_load_error_strings (); SSL_load_error_strings ();
SSLeay_add_all_algorithms (); SSLeay_add_all_algorithms ();
@ -184,20 +189,20 @@ init_ssl (SSL_CTX **ctx)
} }
if (meth == NULL) if (meth == NULL)
{ {
ssl_printerrors (); ssl_print_errors ();
return SSLERRCTXCREATE; return SSLERRCTXCREATE;
} }
*ctx = SSL_CTX_new (meth); ssl_ctx = SSL_CTX_new (meth);
if (meth == NULL) if (meth == NULL)
{ {
ssl_printerrors (); ssl_print_errors ();
return SSLERRCTXCREATE; return SSLERRCTXCREATE;
} }
/* Can we validate the server Cert ? */ /* Can we validate the server Cert ? */
if (opt.sslcadir != NULL || opt.sslcafile != NULL) 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; can_validate = 1;
} }
else 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) if (opt.sslcertfile != NULL || opt.sslcertkey != NULL)
{ {
@ -239,14 +244,16 @@ init_ssl (SSL_CTX **ctx)
if (opt.sslcertfile == NULL) if (opt.sslcertfile == NULL)
opt.sslcertfile = opt.sslcertkey; 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; 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; return SSLERRCERTKEY;
} }
} }
@ -254,28 +261,30 @@ init_ssl (SSL_CTX **ctx)
return 0; /* Succeded */ return 0; /* Succeded */
} }
static static int
int ssl_read (int fd, char *buf, int bufsize, void *ctx) ssl_read (int fd, char *buf, int bufsize, void *ctx)
{ {
int res; int ret;
SSL *ssl = (SSL *) ctx; SSL *ssl = (SSL *) ctx;
/* #### Does SSL_read actually set EINTR? */
do do
res = SSL_read (ssl, buf, bufsize); ret = SSL_read (ssl, buf, bufsize);
while (res == -1 && errno == EINTR); while (ret == -1
return res; && SSL_get_error (ssl, ret) == SSL_ERROR_SYSCALL
&& errno == EINTR);
return ret;
} }
static int static int
ssl_write (int fd, char *buf, int bufsize, void *ctx) ssl_write (int fd, char *buf, int bufsize, void *ctx)
{ {
int res = 0; int ret = 0;
SSL *ssl = (SSL *) ctx; SSL *ssl = (SSL *) ctx;
/* #### Does SSL_write actually set EINTR? */
do do
res = SSL_write (ssl, buf, bufsize); ret = SSL_write (ssl, buf, bufsize);
while (res == -1 && errno == EINTR); while (ret == -1
return res; && SSL_get_error (ssl, ret) == SSL_ERROR_SYSCALL
&& errno == EINTR);
return ret;
} }
static int static int
@ -312,9 +321,12 @@ ssl_close (int fd, void *ctx)
/* Sets up a SSL structure and performs the handshake on fd. */ /* Sets up a SSL structure and performs the handshake on fd. */
SSL * 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) if (!ssl)
goto err; goto err;
if (!SSL_set_fd (ssl, fd)) if (!SSL_set_fd (ssl, fd))
@ -331,14 +343,8 @@ connect_ssl (int fd, SSL_CTX *ctx)
return ssl; return ssl;
err: err:
ssl_printerrors (); ssl_print_errors ();
if (ssl) if (ssl)
SSL_free (ssl); SSL_free (ssl);
return NULL; return NULL;
} }
void
free_ssl_ctx (SSL_CTX * ctx)
{
SSL_CTX_free (ctx);
}

View File

@ -31,16 +31,9 @@ so, delete this exception statement from your version. */
#ifndef GEN_SSLFUNC_H #ifndef GEN_SSLFUNC_H
#define GEN_SSLFUNC_H #define GEN_SSLFUNC_H
#ifdef HAVE_SSL int ssl_init PARAMS ((void));
# include <openssl/ssl.h>
#endif
void ssl_init_prng PARAMS ((void)); int ssl_connect PARAMS ((int));
int init_ssl PARAMS ((SSL_CTX **)); int ssl_print_error PARAMS ((void));
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));
#endif /* GEN_SSLFUNC_H */ #endif /* GEN_SSLFUNC_H */

View File

@ -583,9 +583,6 @@ gethttp (struct url *u, struct http_stat *hs, int *dt, struct url *proxy)
FILE *fp; FILE *fp;
int auth_tried_already; int auth_tried_already;
struct rbuf rbuf; struct rbuf rbuf;
#ifdef HAVE_SSL
static SSL_CTX *ssl_ctx = NULL;
#endif
int using_ssl = 0; int using_ssl = 0;
char *cookies = NULL; 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; long post_data_size = 0;
#ifdef HAVE_SSL #ifdef HAVE_SSL
/* initialize ssl_ctx on first run */ /* Initialize the SSL context. After the first run, this is a
if (!ssl_ctx) no-op. */
switch (ssl_init ())
{ {
uerr_t err = init_ssl (&ssl_ctx); case SSLERRCTXCREATE:
if (err != 0) /* this is fatal */
{ logprintf (LOG_NOTQUIET, _("Failed to set up an SSL context\n"));
switch (err) return SSLERRCTXCREATE;
{ case SSLERRCERTFILE:
case SSLERRCTXCREATE: /* try without certfile */
/* this is fatal */ logprintf (LOG_NOTQUIET,
logprintf (LOG_NOTQUIET, _("Failed to set up an SSL context\n")); _("Failed to load certificates from %s\n"),
ssl_printerrors (); opt.sslcertfile);
return err; logprintf (LOG_NOTQUIET,
case SSLERRCERTFILE: _("Trying without the specified certificate\n"));
/* try without certfile */ break;
logprintf (LOG_NOTQUIET, case SSLERRCERTKEY:
_("Failed to load certificates from %s\n"), logprintf (LOG_NOTQUIET,
opt.sslcertfile); _("Failed to get certificate key from %s\n"),
ssl_printerrors (); opt.sslcertkey);
logprintf (LOG_NOTQUIET, logprintf (LOG_NOTQUIET,
_("Trying without the specified certificate\n")); _("Trying without the specified certificate\n"));
break; break;
case SSLERRCERTKEY: default:
logprintf (LOG_NOTQUIET, break;
_("Failed to get certificate key from %s\n"),
opt.sslcertkey);
ssl_printerrors ();
logprintf (LOG_NOTQUIET,
_("Trying without the specified certificate\n"));
break;
default:
break;
}
}
} }
#endif /* HAVE_SSL */ #endif /* HAVE_SSL */
@ -699,7 +687,7 @@ gethttp (struct url *u, struct http_stat *hs, int *dt, struct url *proxy)
#ifdef HAVE_SSL #ifdef HAVE_SSL
if (conn->scheme == SCHEME_HTTPS) if (conn->scheme == SCHEME_HTTPS)
{ {
if (!connect_ssl (sock, ssl_ctx)) if (!ssl_connect (sock))
{ {
logputs (LOG_VERBOSE, "\n"); logputs (LOG_VERBOSE, "\n");
logprintf (LOG_NOTQUIET, logprintf (LOG_NOTQUIET,

View File

@ -65,10 +65,6 @@ extern int errno;
#include "progress.h" /* for progress_handle_sigwinch */ #include "progress.h" /* for progress_handle_sigwinch */
#include "convert.h" #include "convert.h"
#ifdef HAVE_SSL
# include "gen_sslfunc.h"
#endif
/* On GNU system this will include system-wide getopt.h. */ /* On GNU system this will include system-wide getopt.h. */
#include "getopt.h" #include "getopt.h"
@ -873,12 +869,6 @@ Can't timestamp and not clobber old files at the same time.\n"));
#endif #endif
#endif /* HAVE_SIGNAL */ #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 */ status = RETROK; /* initialize it, just-in-case */
/* Retrieve the URLs from argument list. */ /* Retrieve the URLs from argument list. */
for (t = url; *t; t++) for (t = url; *t; t++)