From 28f1acdb6f6404cfffc7158d109e1c460dac8d94 Mon Sep 17 00:00:00 2001 From: Vladimir Homutov Date: Thu, 18 Jun 2020 13:58:46 +0300 Subject: [PATCH] QUIC: added ALPN checks. quic-transport draft 29: section 7: * authenticated negotiation of an application protocol (TLS uses ALPN [RFC7301] for this purpose) ... Endpoints MUST explicitly negotiate an application protocol. This avoids situations where there is a disagreement about the protocol that is in use. section 8.1: When using ALPN, endpoints MUST immediately close a connection (see Section 10.3 of [QUIC-TRANSPORT]) with a no_application_protocol TLS alert (QUIC error code 0x178; see Section 4.10) if an application protocol is not negotiated. Changes in ngx_quic_close_quic() function are required to avoid attempts to generated and send packets without proper keys, what happens in case of failed ALPN check. --- src/event/ngx_event_quic.c | 30 +++++++++++++++++++++++++++--- src/event/ngx_event_quic.h | 5 +++++ 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/src/event/ngx_event_quic.c b/src/event/ngx_event_quic.c index 562a215ea..46827861a 100644 --- a/src/event/ngx_event_quic.c +++ b/src/event/ngx_event_quic.c @@ -393,6 +393,31 @@ ngx_quic_add_handshake_data(ngx_ssl_conn_t *ssl_conn, "quic ngx_quic_add_handshake_data"); if (!qc->client_tp_done) { + /* + * things to do once during handshake: check ALPN and transport + * parameters; we want to break handshake if something is wrong + * here; + */ + +#if defined(TLSEXT_TYPE_application_layer_protocol_negotiation) + { + unsigned int len; + const unsigned char *data; + + SSL_get0_alpn_selected(c->ssl->connection, &data, &len); + + if (len != NGX_QUIC_ALPN_LEN + || ngx_strncmp(data, NGX_QUIC_ALPN_STR, NGX_QUIC_ALPN_LEN) != 0) + { + qc->error = 0x100 + SSL_AD_NO_APPLICATION_PROTOCOL; + qc->error_reason = "unsupported protocol in ALPN extension"; + + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "quic unsupported protocol in ALPN extension"); + return 0; + } + } +#endif SSL_get_peer_quic_transport_params(ssl_conn, &client_params, &client_params_len); @@ -1298,9 +1323,8 @@ ngx_quic_close_quic(ngx_connection_t *c, ngx_int_t rc) qc->error_reason ? qc->error_reason : ""); } - level = (qc->state == ssl_encryption_early_data) - ? ssl_encryption_handshake - : qc->state; + level = c->ssl ? SSL_quic_read_level(c->ssl->connection) + : ssl_encryption_initial; (void) ngx_quic_send_cc(c, level, err, qc->error_ftype, qc->error_reason); diff --git a/src/event/ngx_event_quic.h b/src/event/ngx_event_quic.h index fe67c3e6a..8974a3392 100644 --- a/src/event/ngx_event_quic.h +++ b/src/event/ngx_event_quic.h @@ -18,6 +18,11 @@ #endif #define NGX_QUIC_VERSION (0xff000000 + NGX_QUIC_DRAFT_VERSION) +#define NGX_QUIC_ALPN(s) NGX_QUIC_ALPN_DRAFT(s) +#define NGX_QUIC_ALPN_DRAFT(s) "h3-" #s +#define NGX_QUIC_ALPN_STR NGX_QUIC_ALPN(NGX_QUIC_DRAFT_VERSION) +#define NGX_QUIC_ALPN_LEN (sizeof(NGX_QUIC_ALPN_STR) - 1) + #define NGX_QUIC_MAX_SHORT_HEADER 25 /* 1 flags + 20 dcid + 4 pn */ #define NGX_QUIC_MAX_LONG_HEADER 56 /* 1 flags + 4 version + 2 x (1 + 20) s/dcid + 4 pn + 4 len + token len */