X-Git-Url: http://git.madism.org/?p=apps%2Fmadmutt.git;a=blobdiff_plain;f=mutt_ssl.c;h=2354cd98d1ff933ed06ac60142ca861f7224905a;hp=83b735b180a01ab4d8fc3e22600dad755df12394;hb=a8808601c98c76ec8344c8e4ba5a607d72c2805e;hpb=96d53ff49c308769efbf708e1e65819077cb7af6 diff --git a/mutt_ssl.c b/mutt_ssl.c index 83b735b..2354cd9 100644 --- a/mutt_ssl.c +++ b/mutt_ssl.c @@ -11,24 +11,25 @@ # include "config.h" #endif +#ifdef USE_SSL + #include #include #include #include -#undef _ - #include +#include +#include +#include + #include "mutt.h" #include "mutt_socket.h" #include "mutt_menu.h" #include "mutt_curses.h" #include "mutt_ssl.h" -#include "lib/mem.h" -#include "lib/intl.h" -#include "lib/str.h" #include "lib/debug.h" #if OPENSSL_VERSION_NUMBER >= 0x00904000L @@ -62,7 +63,7 @@ typedef struct _sslsockdata { } sslsockdata; /* local prototypes */ -int ssl_init (void); +static int ssl_init (void); static int add_entropy (const char *file); static int ssl_socket_read (CONNECTION * conn, char *buf, size_t len); static int ssl_socket_write (CONNECTION * conn, const char *buf, size_t len); @@ -84,7 +85,7 @@ int mutt_ssl_starttls (CONNECTION * conn) if (ssl_init ()) goto bail; - ssldata = (sslsockdata *) safe_calloc (1, sizeof (sslsockdata)); + ssldata = p_new(sslsockdata, 1); /* the ssl_use_xxx protocol options don't apply. We must use TLS in TLS. */ if (!(ssldata->ctx = SSL_CTX_new (TLSv1_client_method ()))) { debug_print (1, ("Error allocating SSL_CTX\n")); @@ -118,11 +119,11 @@ int mutt_ssl_starttls (CONNECTION * conn) return 0; bail_ssl: - FREE (&ssldata->ssl); + p_delete(&ssldata->ssl); bail_ctx: - FREE (&ssldata->ctx); + p_delete(&ssldata->ctx); bail_ssldata: - FREE (&ssldata); + p_delete(&ssldata); bail: return -1; } @@ -137,7 +138,7 @@ bail: * versions also. (That's the reason for the ugly #ifdefs and macros, * otherwise I could have simply #ifdef'd the whole ssl_init funcion) */ -int ssl_init (void) +static int ssl_init (void) { char path[_POSIX_PATH_MAX]; static unsigned char init_complete = 0; @@ -219,7 +220,7 @@ static int ssl_socket_open_err (CONNECTION * conn) } -int ssl_socket_setup (CONNECTION * conn) +int mutt_ssl_socket_setup (CONNECTION * conn) { if (ssl_init () < 0) { conn->conn_open = ssl_socket_open_err; @@ -256,7 +257,7 @@ static int ssl_socket_open (CONNECTION * conn) if (raw_socket_open (conn) < 0) return -1; - data = (sslsockdata *) safe_calloc (1, sizeof (sslsockdata)); + data = p_new(sslsockdata, 1); conn->sockdata = data; data->ctx = SSL_CTX_new (SSLv23_client_method ()); @@ -343,16 +344,57 @@ static int ssl_socket_close (CONNECTION * conn) if (data) { SSL_shutdown (data->ssl); - +#if 0 X509_free (data->cert); +#endif SSL_free (data->ssl); SSL_CTX_free (data->ctx); - FREE (&conn->sockdata); + p_delete(&conn->sockdata); } return raw_socket_close (conn); } +static int compare_certificates (X509 *cert, X509 *peercert, + unsigned char *peermd, + unsigned int peermdlen) { + unsigned char md[EVP_MAX_MD_SIZE]; + unsigned int mdlen; + + /* Avoid CPU-intensive digest calculation if the certificates are + * not even remotely equal. + */ + if (X509_subject_name_cmp (cert, peercert) != 0 || + X509_issuer_name_cmp (cert, peercert) != 0) + return -1; + + if (!X509_digest (cert, EVP_sha1(), md, &mdlen) || peermdlen != mdlen) + return -1; + + if (memcmp(peermd, md, mdlen) != 0) + return -1; + + return 0; +} + +static int check_certificate_cache (X509 *peercert) { + unsigned char peermd[EVP_MAX_MD_SIZE]; + unsigned int peermdlen; + X509 *cert; + LIST *scert; + + if (!X509_digest (peercert, EVP_sha1(), peermd, &peermdlen)) + return 0; + + for (scert = SslSessionCerts; scert; scert = scert->next) { + cert = *(X509**)scert->data; + if (!compare_certificates (cert, peercert, peermd, peermdlen)) { + return 1; + } + } + return 0; +} + static int tls_close (CONNECTION * conn) { int rc; @@ -370,15 +412,15 @@ static char *x509_get_part (char *line, const char *ndx) static char ret[SHORT_STRING]; char *c, *c2; - strfcpy (ret, _("Unknown"), sizeof (ret)); + m_strcpy(ret, sizeof(ret), _("Unknown")); c = strstr (line, ndx); if (c) { - c += mutt_strlen (ndx); + c += m_strlen(ndx); c2 = strchr (c, '/'); if (c2) *c2 = '\0'; - strfcpy (ret, c, sizeof (ret)); + m_strcpy(ret, sizeof(ret), c); if (c2) *c2 = '/'; } @@ -393,14 +435,14 @@ static void x509_fingerprint (char *s, int l, X509 * cert) int j; if (!X509_digest (cert, EVP_md5 (), md, &n)) { - snprintf (s, l, "%s", _("[unable to calculate]")); + m_strcpy(s, l, _("[unable to calculate]")); } else { for (j = 0; j < (int) n; j++) { char ch[8]; - snprintf (ch, 8, "%02X%s", md[j], (j % 2 ? " " : "")); - safe_strcat (s, l, ch); + snprintf(ch, 8, "%02X%s", md[j], (j % 2 ? " " : "")); + m_strcat(s, l, ch); } } } @@ -410,7 +452,7 @@ static char *asn1time_to_string (ASN1_UTCTIME * tm) static char buf[64]; BIO *bio; - strfcpy (buf, _("[invalid date]"), sizeof (buf)); + m_strcpy(buf, sizeof(buf), _("[invalid date]")); bio = BIO_new (BIO_s_mem ()); if (bio) { @@ -501,24 +543,9 @@ static int check_certificate_by_digest (X509 * peercert) } while ((cert = READ_X509_KEY (fp, &cert)) != NULL) { - unsigned char md[EVP_MAX_MD_SIZE]; - unsigned int mdlen; - - /* Avoid CPU-intensive digest calculation if the certificates are - * not even remotely equal. - */ - if (X509_subject_name_cmp (cert, peercert) != 0 || - X509_issuer_name_cmp (cert, peercert) != 0) - continue; - - if (!X509_digest (cert, EVP_sha1 (), md, &mdlen) || peermdlen != mdlen) - continue; - - if (memcmp (peermd, md, mdlen) != 0) - continue; - - pass = 1; - break; + pass = compare_certificates (cert, peercert, peermd, peermdlen) ? 0 : 1; + if (pass) + break; } X509_free (cert); fclose (fp); @@ -536,6 +563,12 @@ static int ssl_check_certificate (sslsockdata * data) FILE *fp; char *name = NULL, *c; + /* check session cache first */ + if (check_certificate_cache (data->cert)) { + debug_print (1, ("ssl_check_certificate: using cached certificate\n")); + return 1; + } + if (check_certificate_by_signer (data->cert)) { debug_print (1, ("signer check passed\n")); return 1; @@ -550,13 +583,13 @@ static int ssl_check_certificate (sslsockdata * data) /* interactive check from user */ menu = mutt_new_menu (); menu->max = 19; - menu->dialog = (char **) safe_calloc (1, menu->max * sizeof (char *)); + menu->dialog = p_new(char *, menu->max); for (i = 0; i < menu->max; i++) - menu->dialog[i] = (char *) safe_calloc (1, SHORT_STRING * sizeof (char)); + menu->dialog[i] = p_new(char, SHORT_STRING); row = 0; - strfcpy (menu->dialog[row], _("This certificate belongs to:"), - SHORT_STRING); + m_strcpy(menu->dialog[row], SHORT_STRING, + _("This certificate belongs to:")); row++; name = X509_NAME_oneline (X509_get_subject_name (data->cert), buf, sizeof (buf)); @@ -566,8 +599,8 @@ static int ssl_check_certificate (sslsockdata * data) } row++; - strfcpy (menu->dialog[row], _("This certificate was issued by:"), - SHORT_STRING); + m_strcpy(menu->dialog[row], SHORT_STRING, + _("This certificate was issued by:")); row++; name = X509_NAME_oneline (X509_get_issuer_name (data->cert), buf, sizeof (buf)); @@ -590,7 +623,9 @@ static int ssl_check_certificate (sslsockdata * data) snprintf (menu->dialog[row++], SHORT_STRING, _("Fingerprint: %s"), buf); menu->title = _("SSL Certificate check"); - if (SslCertFile) { + + if (SslCertFile && X509_cmp_current_time (X509_get_notAfter (data->cert)) >= 0 + && X509_cmp_current_time (X509_get_notBefore (data->cert)) < 0) { menu->prompt = _("(r)eject, accept (o)nce, (a)ccept always"); menu->keys = _("roa"); } @@ -601,9 +636,9 @@ static int ssl_check_certificate (sslsockdata * data) helpstr[0] = '\0'; mutt_make_help (buf, sizeof (buf), _("Exit "), MENU_GENERIC, OP_EXIT); - safe_strcat (helpstr, sizeof (helpstr), buf); + m_strcat(helpstr, sizeof(helpstr), buf); mutt_make_help (buf, sizeof (buf), _("Help"), MENU_GENERIC, OP_HELP); - safe_strcat (helpstr, sizeof (helpstr), buf); + m_strcat(helpstr, sizeof(helpstr), buf); menu->help = helpstr; done = 0; @@ -633,6 +668,10 @@ static int ssl_check_certificate (sslsockdata * data) /* fall through */ case OP_MAX + 2: /* accept once */ done = 2; + /* keep a handle on accepted certificates in case we want to + * open up another connection to the same server in this session */ + SslSessionCerts = mutt_add_list_n (SslSessionCerts, &data->cert, + sizeof (X509 **)); break; } } @@ -669,3 +708,5 @@ static int ssl_passwd_cb (char *buf, int size, int rwflag, void *userdata) return snprintf (buf, size, "%s", account->pass); } + +#endif /* USE_SSL */