Permalink
Browse files

protocols: Add support for server certificate verification

  • Loading branch information...
1 parent eb902c3 commit dd57bf991c9aa1e9ee8721c8c64b2021162c1f1a @bruceg committed Apr 19, 2012
Showing with 61 additions and 3 deletions.
  1. +0 −3 TODO
  2. +8 −0 protocols/protocol.cc
  3. +7 −0 protocols/protocol.h
  4. +46 −0 protocols/tls_gnutls.cc
View
@@ -1,8 +1,5 @@
- Add support for SMTP AUTH CRAM-MD5
-- SSL/TLS support:
- - Add certificate verification unless --ssl-insecure
-
- Convert all proto modules to use timedout reads.
- Add patterns to the remotes file, to allow messages to be delivered to
@@ -51,6 +51,14 @@ cli_option cli_options[] = {
"Connect using SSL (on an alternate port by default)", 0 },
{ 0, "starttls", cli_option::flag, 1, &use_starttls,
"Use STARTTLS command", 0 },
+ { 0, "x509cafile", cli_option::string, 0, &tls_x509cafile,
+ "Certificate authority trust file", DEFAULT_CA_FILE },
+ { 0, "x509crlfile", cli_option::string, 0, &tls_x509crlfile,
+ "Certificate revocation list file", 0 },
+ { 0, "x509fmtder", cli_option::flag, true, &tls_x509derfmt,
+ "X.509 files are in DER format", "PEM format" },
+ { 0, "insecure", cli_option::flag, true, &tls_insecure,
+ "Don't abort if server certificate fails validation", 0 },
#endif
{0, 0, cli_option::flag, 0, 0, 0, 0}
};
@@ -3,6 +3,8 @@
#include "fdbuf/fdbuf.h"
+#define DEFAULT_CA_FILE "/etc/ssl/certs/ca-certificates.crt"
+
extern const int default_port;
extern const int default_ssl_port;
extern void protocol_fail(int e, const char* msg);
@@ -17,11 +19,16 @@ extern int auth_method;
extern int port;
extern int use_ssl;
extern int use_starttls;
+extern int tls_insecure;
extern void protocol_prep(fdibuf& in);
extern void protocol_send(fdibuf& in, fdibuf& netin, fdobuf& netout);
extern void protocol_starttls(fdibuf& netin, fdobuf& netout);
+extern int tls_insecure;
+extern const char* tls_x509cafile;
+extern const char* tls_x509crlfile;
+extern int tls_x509derfmt;
extern void tls_init(const char* remote);
extern void tls_send(fdibuf& in, int fd);
@@ -20,6 +20,7 @@
// <nullmailer-subscribe@lists.untroubled.org>.
#include <config.h>
+#include <unistd.h>
#include "errcodes.h"
#include "mystring/mystring.h"
#include "protocol.h"
@@ -28,6 +29,11 @@
#include "fdbuf/tlsibuf.h"
#include "fdbuf/tlsobuf.h"
+int tls_insecure = false;
+const char* tls_x509cafile = NULL;
+const char* tls_x509crlfile = NULL;
+int tls_x509derfmt = false;
+
static int gnutls_wrap(int ret, const char* msg)
{
if (ret < 0) {
@@ -39,6 +45,33 @@ static int gnutls_wrap(int ret, const char* msg)
return ret;
}
+static int cert_verify_callback(gnutls_session_t session)
+{
+ if (tls_x509cafile != NULL && !tls_insecure) {
+ // Verify the certificate
+ unsigned int status = 0;
+ gnutls_wrap(gnutls_certificate_verify_peers2(session, &status),
+ "Could not verify SSL/TLS certificate");
+ if (status != 0)
+ protocol_fail(ERR_MSG_TEMPFAIL, "Server SSL/TLS certificate is untrusted");
+
+ // Verify the hostname
+ unsigned int cert_list_size = 0;
+ const gnutls_datum_t* cert_list = gnutls_certificate_get_peers(session, &cert_list_size);
+ const char* hostname = (const char*)gnutls_session_get_ptr(session);
+ gnutls_x509_crt_t crt;
+ gnutls_wrap(gnutls_x509_crt_init(&crt),
+ "Error allocating memory");
+ gnutls_wrap(gnutls_x509_crt_import(crt, &cert_list[0], GNUTLS_X509_FMT_DER),
+ "Error decoding SSL/TLS certificate");
+ if (gnutls_x509_crt_check_hostname(crt, hostname) == 0)
+ protocol_fail(ERR_MSG_TEMPFAIL, "Server SSL/TLS certificate does not match hostname");
+ gnutls_x509_crt_deinit(crt);
+ }
+ // All verification errors cause protocol to exit
+ return 0;
+}
+
static gnutls_session_t tls_session;
void tls_init(const char* remote)
@@ -56,6 +89,19 @@ void tls_init(const char* remote)
"Error setting TLS credentials");
gnutls_wrap(gnutls_server_name_set(tls_session, GNUTLS_NAME_DNS, remote, strlen(remote)),
"Error setting TLS server name");
+ gnutls_session_set_ptr(tls_session, (void*)remote);
+ gnutls_certificate_set_verify_function(creds, cert_verify_callback);
+ gnutls_certificate_set_verify_flags(creds, 0);
+
+ gnutls_x509_crt_fmt_t x509fmt = tls_x509derfmt ? GNUTLS_X509_FMT_DER : GNUTLS_X509_FMT_PEM;
+ if (tls_x509cafile == NULL && access(DEFAULT_CA_FILE, R_OK) == 0)
+ tls_x509cafile = DEFAULT_CA_FILE;
+ if (tls_x509cafile != NULL)
+ gnutls_wrap(gnutls_certificate_set_x509_trust_file(creds, tls_x509cafile, x509fmt),
+ "Error loading SSL/TLS X.509 trust file");
+ if (tls_x509crlfile != NULL)
+ gnutls_wrap(gnutls_certificate_set_x509_crl_file(creds, tls_x509crlfile, x509fmt),
+ "Error loading SSL/TLS X.509 CRL file");
}
void tls_send(fdibuf& in, int fd)

0 comments on commit dd57bf9

Please sign in to comment.