X-Git-Url: http://git.madism.org/?p=apps%2Fmadmutt.git;a=blobdiff_plain;f=mutt_ssl.c;h=9092c330efc991f6ec5b871781bf28280e5f839a;hp=0ea28c458d6a4898bd2e1a0ac8943d13c0e9b862;hb=afa60149c4d2bb71c8195091d3658b3bdc12d59d;hpb=74a2265af51ce89bca845adc1d68f273c9933c13 diff --git a/mutt_ssl.c b/mutt_ssl.c index 0ea28c4..9092c33 100644 --- a/mutt_ssl.c +++ b/mutt_ssl.c @@ -29,6 +29,7 @@ #include "lib/mem.h" #include "lib/intl.h" #include "lib/str.h" +#include "lib/debug.h" #if OPENSSL_VERSION_NUMBER >= 0x00904000L #define READ_X509_KEY(fp, key) PEM_read_X509(fp, key, NULL, NULL) @@ -86,19 +87,19 @@ int mutt_ssl_starttls (CONNECTION * conn) ssldata = (sslsockdata *) safe_calloc (1, sizeof (sslsockdata)); /* the ssl_use_xxx protocol options don't apply. We must use TLS in TLS. */ if (!(ssldata->ctx = SSL_CTX_new (TLSv1_client_method ()))) { - dprint (1, (debugfile, "mutt_ssl_starttls: Error allocating SSL_CTX\n")); + debug_print (1, ("Error allocating SSL_CTX\n")); goto bail_ssldata; } ssl_get_client_cert (ssldata, conn); if (!(ssldata->ssl = SSL_new (ssldata->ctx))) { - dprint (1, (debugfile, "mutt_ssl_starttls: Error allocating SSL\n")); + debug_print (1, ("Error allocating SSL\n")); goto bail_ctx; } if (SSL_set_fd (ssldata->ssl, conn->fd) != 1) { - dprint (1, (debugfile, "mutt_ssl_starttls: Error setting fd\n")); + debug_print (1, ("Error setting fd\n")); goto bail_ssl; } @@ -342,8 +343,9 @@ 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); @@ -352,6 +354,46 @@ static int ssl_socket_close (CONNECTION * conn) 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; @@ -435,13 +477,13 @@ static int check_certificate_by_signer (X509 * peercert) if (X509_STORE_set_default_paths (ctx)) pass++; else - dprint (2, (debugfile, "X509_STORE_set_default_paths failed\n")); + debug_print (2, ("X509_STORE_set_default_paths failed\n")); } if (X509_STORE_load_locations (ctx, SslCertFile, NULL)) pass++; else - dprint (2, (debugfile, "X509_STORE_load_locations_failed\n")); + debug_print (2, ("X509_STORE_load_locations_failed\n")); if (pass == 0) { /* nothing to do */ @@ -460,7 +502,7 @@ static int check_certificate_by_signer (X509 * peercert) err = X509_STORE_CTX_get_error (&xsc); snprintf (buf, sizeof (buf), "%s (%d)", X509_verify_cert_error_string (err), err); - dprint (2, (debugfile, "X509_verify_cert: %s\n", buf)); + debug_print (2, ("X509_verify_cert: %s\n", buf)); } #endif X509_STORE_CTX_cleanup (&xsc); @@ -479,13 +521,13 @@ static int check_certificate_by_digest (X509 * peercert) /* expiration check */ if (X509_cmp_current_time (X509_get_notBefore (peercert)) >= 0) { - dprint (2, (debugfile, "Server certificate is not yet valid\n")); + debug_print (2, ("Server certificate is not yet valid\n")); mutt_error (_("Server certificate is not yet valid")); mutt_sleep (2); return 0; } if (X509_cmp_current_time (X509_get_notAfter (peercert)) <= 0) { - dprint (2, (debugfile, "Server certificate has expired")); + debug_print (2, ("Server certificate has expired\n")); mutt_error (_("Server certificate has expired")); mutt_sleep (2); return 0; @@ -500,24 +542,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); @@ -535,14 +562,20 @@ 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)) { - dprint (1, (debugfile, "ssl_check_certificate: signer check passed\n")); + debug_print (1, ("signer check passed\n")); return 1; } /* automatic check from user's database */ if (SslCertFile && check_certificate_by_digest (data->cert)) { - dprint (1, (debugfile, "ssl_check_certificate: digest check passed\n")); + debug_print (1, ("digest check passed\n")); return 1; } @@ -589,7 +622,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"); } @@ -632,6 +667,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; } } @@ -643,7 +682,7 @@ static int ssl_check_certificate (sslsockdata * data) static void ssl_get_client_cert (sslsockdata * ssldata, CONNECTION * conn) { if (SslClientCert) { - dprint (2, (debugfile, "Using client certificate %s\n", SslClientCert)); + debug_print (2, ("Using client certificate %s\n", SslClientCert)); SSL_CTX_set_default_passwd_cb_userdata (ssldata->ctx, &conn->account); SSL_CTX_set_default_passwd_cb (ssldata->ctx, ssl_passwd_cb); SSL_CTX_use_certificate_file (ssldata->ctx, SslClientCert, @@ -660,7 +699,7 @@ static int ssl_passwd_cb (char *buf, int size, int rwflag, void *userdata) if (mutt_account_getuser (account)) return 0; - dprint (2, (debugfile, "ssl_passwd_cb: getting password for %s@%s:%u\n", + debug_print (2, ("getting password for %s@%s:%u\n", account->user, account->host, account->port)); if (mutt_account_getpass (account))