]> git.kaiwu.me - nginx.git/commitdiff
Mail: connections with wrong ALPN protocols are now rejected.
authorVladimir Homutov <vl@nginx.com>
Wed, 20 Oct 2021 06:45:34 +0000 (09:45 +0300)
committerVladimir Homutov <vl@nginx.com>
Wed, 20 Oct 2021 06:45:34 +0000 (09:45 +0300)
This is a recommended behavior by RFC 7301 and is useful
for mitigation of protocol confusion attacks [1].

For POP3 and IMAP protocols IANA-assigned ALPN IDs are used [2].
For the SMTP protocol "smtp" is used.

[1] https://alpaca-attack.com/
[2] https://www.iana.org/assignments/tls-extensiontype-values/

src/mail/ngx_mail.h
src/mail/ngx_mail_imap_module.c
src/mail/ngx_mail_pop3_module.c
src/mail/ngx_mail_smtp_module.c
src/mail/ngx_mail_ssl_module.c

index 21178c3e2d34d5d22bda5ee3d50dfd99b817759a..e0c62b7abfd809f6b36103e2f19ac33e97d37cf0 100644 (file)
@@ -324,6 +324,7 @@ typedef ngx_int_t (*ngx_mail_parse_command_pt)(ngx_mail_session_t *s);
 
 struct ngx_mail_protocol_s {
     ngx_str_t                   name;
+    ngx_str_t                   alpn;
     in_port_t                   port[4];
     ngx_uint_t                  type;
 
index 1f187fdeebc51681d63d02f1db46f93ed27cf431..02c684cd4bb0aeb3b48c87974b5c9d5c6bef524f 100644 (file)
@@ -46,6 +46,7 @@ static ngx_str_t  ngx_mail_imap_auth_methods_names[] = {
 
 static ngx_mail_protocol_t  ngx_mail_imap_protocol = {
     ngx_string("imap"),
+    ngx_string("\x04imap"),
     { 143, 993, 0, 0 },
     NGX_MAIL_IMAP_PROTOCOL,
 
index a673070736af9f2e44db8b78003c027b8b6a60b5..a257b5a7027fedfaa63f91f1bc7eb17d02afbcc8 100644 (file)
@@ -46,6 +46,7 @@ static ngx_str_t  ngx_mail_pop3_auth_methods_names[] = {
 
 static ngx_mail_protocol_t  ngx_mail_pop3_protocol = {
     ngx_string("pop3"),
+    ngx_string("\x04pop3"),
     { 110, 995, 0, 0 },
     NGX_MAIL_POP3_PROTOCOL,
 
index 3b5a2d8f315400987d4fdc73966bed2fdbf32c28..0e05fdc034b20134d07ae2866eaa5d701878b20a 100644 (file)
@@ -39,6 +39,7 @@ static ngx_str_t  ngx_mail_smtp_auth_methods_names[] = {
 
 static ngx_mail_protocol_t  ngx_mail_smtp_protocol = {
     ngx_string("smtp"),
+    ngx_string("\x04smtp"),
     { 25, 465, 587, 0 },
     NGX_MAIL_SMTP_PROTOCOL,
 
index 09cc425d68392ced95716cf42df260603660014a..2a1043e661e54eac04e1f1fd9c93b2d2a56bc1da 100644 (file)
 #define NGX_DEFAULT_ECDH_CURVE  "auto"
 
 
+#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
+static int ngx_mail_ssl_alpn_select(ngx_ssl_conn_t *ssl_conn,
+    const unsigned char **out, unsigned char *outlen,
+    const unsigned char *in, unsigned int inlen, void *arg);
+#endif
+
 static void *ngx_mail_ssl_create_conf(ngx_conf_t *cf);
 static char *ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child);
 
@@ -244,6 +250,54 @@ ngx_module_t  ngx_mail_ssl_module = {
 static ngx_str_t ngx_mail_ssl_sess_id_ctx = ngx_string("MAIL");
 
 
+#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
+
+static int
+ngx_mail_ssl_alpn_select(ngx_ssl_conn_t *ssl_conn, const unsigned char **out,
+    unsigned char *outlen, const unsigned char *in, unsigned int inlen,
+    void *arg)
+{
+    unsigned int               srvlen;
+    unsigned char             *srv;
+    ngx_connection_t          *c;
+    ngx_mail_session_t        *s;
+    ngx_mail_core_srv_conf_t  *cscf;
+#if (NGX_DEBUG)
+    unsigned int               i;
+#endif
+
+    c = ngx_ssl_get_connection(ssl_conn);
+    s = c->data;
+
+#if (NGX_DEBUG)
+    for (i = 0; i < inlen; i += in[i] + 1) {
+        ngx_log_debug2(NGX_LOG_DEBUG_MAIL, c->log, 0,
+                       "SSL ALPN supported by client: %*s",
+                       (size_t) in[i], &in[i + 1]);
+    }
+#endif
+
+    cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
+
+    srv = cscf->protocol->alpn.data;
+    srvlen = cscf->protocol->alpn.len;
+
+    if (SSL_select_next_proto((unsigned char **) out, outlen, srv, srvlen,
+                              in, inlen)
+        != OPENSSL_NPN_NEGOTIATED)
+    {
+        return SSL_TLSEXT_ERR_ALERT_FATAL;
+    }
+
+    ngx_log_debug2(NGX_LOG_DEBUG_MAIL, c->log, 0,
+                   "SSL ALPN selected: %*s", (size_t) *outlen, *out);
+
+    return SSL_TLSEXT_ERR_OK;
+}
+
+#endif
+
+
 static void *
 ngx_mail_ssl_create_conf(ngx_conf_t *cf)
 {
@@ -394,6 +448,10 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child)
     cln->handler = ngx_ssl_cleanup_ctx;
     cln->data = &conf->ssl;
 
+#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
+    SSL_CTX_set_alpn_select_cb(conf->ssl.ctx, ngx_mail_ssl_alpn_select, NULL);
+#endif
+
     if (ngx_ssl_ciphers(cf, &conf->ssl, &conf->ciphers,
                         conf->prefer_server_ciphers)
         != NGX_OK)