From 6dd6a70c1ed3e32428b7043c0604220d722f53ef Mon Sep 17 00:00:00 2001 From: eric Date: Fri, 14 Dec 2018 09:18:03 +0000 Subject: [PATCH] use new cert helpers for incoming smtp sessions ok gilles@ --- usr.sbin/smtpd/smtp_session.c | 131 +++++++++++++++++++++++++++++----- 1 file changed, 114 insertions(+), 17 deletions(-) diff --git a/usr.sbin/smtpd/smtp_session.c b/usr.sbin/smtpd/smtp_session.c index 322045ebdeb..6928a5ce267 100644 --- a/usr.sbin/smtpd/smtp_session.c +++ b/usr.sbin/smtpd/smtp_session.c @@ -1,4 +1,4 @@ -/* $OpenBSD: smtp_session.c,v 1.374 2018/12/12 21:27:49 gilles Exp $ */ +/* $OpenBSD: smtp_session.c,v 1.375 2018/12/14 09:18:03 eric Exp $ */ /* * Copyright (c) 2008 Gilles Chehade @@ -191,6 +191,10 @@ static void smtp_free(struct smtp_session *, const char *); static const char *smtp_strstate(int); static void smtp_tls_init(struct smtp_session *); static int smtp_verify_certificate(struct smtp_session *); +static void smtp_cert_init(struct smtp_session *); +static void smtp_cert_init_cb(void *, int, const char *, const void *, size_t); +static void smtp_cert_verify(struct smtp_session *); +static void smtp_cert_verify_cb(void *, int); static void smtp_auth_failure_pause(struct smtp_session *); static void smtp_auth_failure_resume(int, short, void *); @@ -1097,20 +1101,7 @@ smtp_io(struct io *io, int evt, void *arg) s->flags |= SF_SECURE; s->helo[0] = '\0'; - if (smtp_verify_certificate(s)) { - io_pause(s->io, IO_IN); - break; - } - - if (s->listener->flags & F_TLS_VERIFY) { - log_info("%016"PRIx64" smtp " - "disconnected address=%s host=%s reason=no-client-cert", - s->id, ss_to_text(&s->ss), s->hostname); - smtp_free(s, "client did not present certificate"); - return; - } - - smtp_tls_verified(s); + smtp_cert_verify(s); break; case IO_DATAIN: @@ -1182,7 +1173,7 @@ smtp_io(struct io *io, int evt, void *arg) /* Wait for the client to start tls */ if (s->state == STATE_TLS) { - smtp_tls_init(s); + smtp_cert_init(s); break; } @@ -1991,7 +1982,7 @@ static void smtp_proceed_connected(struct smtp_session *s) { if (s->listener->flags & F_SMTPS) - smtp_tls_init(s); + smtp_cert_init(s); else smtp_send_banner(s); } @@ -2313,6 +2304,112 @@ smtp_verify_certificate(struct smtp_session *s) return res; } +static void +smtp_cert_init(struct smtp_session *s) +{ + const char *name; + int fallback; + + if (s->listener->pki_name[0]) { + name = s->listener->pki_name; + fallback = 0; + } + else { + name = s->smtpname; + fallback = 1; + } + + if (cert_init(name, fallback, smtp_cert_init_cb, s)) + tree_xset(&wait_ssl_init, s->id, s); +} + +static void +smtp_cert_init_cb(void *arg, int status, const char *name, const void *cert, + size_t cert_len) +{ + struct smtp_session *s = arg; + void *ssl, *ssl_ctx; + + tree_pop(&wait_ssl_init, s->id); + + if (status == CA_FAIL) { + log_info("%016"PRIx64" smtp disconnected address=%s host=%s " + "reason=ca-failure", + s->id, ss_to_text(&s->ss), s->hostname); + smtp_free(s, "CA failure"); + return; + } + + ssl_ctx = dict_get(env->sc_ssl_dict, name); + ssl = ssl_smtp_init(ssl_ctx, s->listener->flags & F_TLS_VERIFY); + io_set_read(s->io); + io_start_tls(s->io, ssl); +} + +static void +smtp_cert_verify(struct smtp_session *s) +{ + const char *name; + int fallback; + + if (s->listener->ca_name[0]) { + name = s->listener->ca_name; + fallback = 0; + } + else { + name = s->smtpname; + fallback = 1; + } + + if (cert_verify(io_ssl(s->io), name, fallback, smtp_cert_verify_cb, s)) { + tree_xset(&wait_ssl_verify, s->id, s); + io_pause(s->io, IO_IN); + } +} + +static void +smtp_cert_verify_cb(void *arg, int status) +{ + struct smtp_session *s = arg; + const char *reason = NULL; + int resume; + + resume = tree_pop(&wait_ssl_verify, s->id) != NULL; + + switch (status) { + case CERT_OK: + reason = "cert-ok"; + s->flags |= SF_VERIFIED; + break; + case CERT_NOCA: + reason = "no-ca"; + break; + case CERT_NOCERT: + reason = "no-client-cert"; + break; + case CERT_INVALID: + reason = "cert-invalid"; + break; + default: + reason = "cert-check-failed"; + break; + } + + log_debug("smtp: %p: smtp_cert_verify_cb: %s", s, reason); + + if (!(s->flags & SF_VERIFIED) && (s->listener->flags & F_TLS_VERIFY)) { + log_info("%016"PRIx64" smtp disconnected address=%s host=%s " + " reason=%s", s->id, ss_to_text(&s->ss), s->hostname, + reason); + smtp_free(s, "SSL certificate check failed"); + return; + } + + smtp_tls_verified(s); + if (resume) + io_resume(s->io, IO_IN); +} + static void smtp_auth_failure_resume(int fd, short event, void *p) { -- 2.20.1