Browse Source

[TLS] ALPN h2 policy

HTTP/2 requires that TLS protocol >= TLSv1.2
HTTP/2 requires that TLS record compression be disabled
HTTP/2 requires that TLSv1.2 renegotiation be disabled

HTTP/2 requires that TLS SNI extension be presented with ALPN h2
  (not enforced;
   SNI omitted by client when connecting to IP instead of to name)

RFC 7540 9.2 Use of TLS Features
"Implementations are encouraged to provide defaults that comply,
 but it is recognized that deployments are ultimately responsible
 for compliance."

If TLS record compression or renegotiation are for some reason required
(which is strongly discouraged), then disable HTTP/2 in lighttpd with
  server.feature-flags = ("server.h2proto" => "disable")
master
Glenn Strauss 7 months ago
parent
commit
92d467b45e
  1. 33
      src/mod_gnutls.c
  2. 33
      src/mod_mbedtls.c
  3. 44
      src/mod_nss.c
  4. 37
      src/mod_openssl.c
  5. 34
      src/mod_wolfssl.c

33
src/mod_gnutls.c

@ -1336,6 +1336,28 @@ mod_gnutls_acme_tls_1 (handler_ctx *hctx)
}
static int
mod_gnutls_alpn_h2_policy (handler_ctx * const hctx)
{
/*(currently called after handshake has completed)*/
#if 0 /* SNI omitted by client when connecting to IP instead of to name */
if (buffer_string_is_empty(&hctx->r->uri.authority)) {
log_error(hctx->errh, __FILE__, __LINE__,
"SSL: error ALPN h2 without SNI");
return -1;
}
#endif
if (gnutls_protocol_get_version(hctx->ssl) < GNUTLS_TLS1_2) {
/*(future: if DTLS supported by lighttpd, add DTLS condition)*/
log_error(hctx->errh, __FILE__, __LINE__,
"SSL: error ALPN h2 requires TLSv1.2 or later");
return -1;
}
return 0;
}
enum {
MOD_GNUTLS_ALPN_HTTP11 = 1
,MOD_GNUTLS_ALPN_HTTP10 = 2
@ -2212,7 +2234,12 @@ SETDEFAULTS_FUNC(mod_gnutls_set_defaults)
}
break;
case 5: /* ssl.read-ahead */
break;
case 6: /* ssl.disable-client-renegotiation */
/* (force disabled, the default, if HTTP/2 enabled in server) */
if (srv->srvconf.h2proto)
cpv->v.u = 1; /* disable client renegotiation */
break;
case 7: /* ssl.verifyclient.activate */
case 8: /* ssl.verifyclient.enforce */
break;
@ -2471,7 +2498,11 @@ mod_gnutls_ssl_handshake (handler_ctx *hctx)
hctx->handshake = 1;
#if GNUTLS_VERSION_NUMBER >= 0x030200
if (hctx->alpn == MOD_GNUTLS_ALPN_ACME_TLS_1) {
if (hctx->alpn == MOD_GNUTLS_ALPN_H2) {
if (0 != mod_gnutls_alpn_h2_policy(hctx))
return -1;
}
else if (hctx->alpn == MOD_GNUTLS_ALPN_ACME_TLS_1) {
/* Once TLS handshake is complete, return -1 to result in
* CON_STATE_ERROR so that socket connection is quickly closed */
return -1;

33
src/mod_mbedtls.c

@ -1071,6 +1071,28 @@ mod_mbedtls_acme_tls_1 (handler_ctx *hctx)
#endif
static int
mod_mbedtls_alpn_h2_policy (handler_ctx * const hctx)
{
/*(currently called after handshake has completed)*/
#if 0 /* SNI omitted by client when connecting to IP instead of to name */
if (buffer_string_is_empty(&hctx->r->uri.authority)) {
log_error(hctx->errh, __FILE__, __LINE__,
"SSL: error ALPN h2 without SNI");
return -1;
}
#endif
if (hctx->ssl.major_ver == MBEDTLS_SSL_MAJOR_VERSION_3
&& hctx->ssl.minor_ver < MBEDTLS_SSL_MINOR_VERSION_3) {
log_error(hctx->errh, __FILE__, __LINE__,
"SSL: error ALPN h2 requires TLSv1.2 or later");
return -1;
}
return 0;
}
static int
mod_mbedtls_alpn_selected (handler_ctx * const hctx, const char * const in)
{
@ -1816,7 +1838,12 @@ SETDEFAULTS_FUNC(mod_mbedtls_set_defaults)
}
break;
case 5: /* ssl.read-ahead */
break;
case 6: /* ssl.disable-client-renegotiation */
/* (force disabled, the default, if HTTP/2 enabled in server) */
if (srv->srvconf.h2proto)
cpv->v.u = 1; /* disable client renegotiation */
break;
case 7: /* ssl.verifyclient.activate */
case 8: /* ssl.verifyclient.enforce */
break;
@ -2090,7 +2117,11 @@ mod_mbedtls_ssl_handshake (handler_ctx *hctx)
case 0:
hctx->handshake_done = 1;
#ifdef MBEDTLS_SSL_ALPN
if (hctx->alpn == MOD_MBEDTLS_ALPN_ACME_TLS_1) {
if (hctx->alpn == MOD_MBEDTLS_ALPN_H2) {
if (0 != mod_mbedtls_alpn_h2_policy(hctx))
return -1;
}
else if (hctx->alpn == MOD_MBEDTLS_ALPN_ACME_TLS_1) {
/* Once TLS handshake is complete, return -1 to result in
* CON_STATE_ERROR so that socket connection is quickly closed */
return -1;

44
src/mod_nss.c

@ -1277,6 +1277,36 @@ mod_nss_acme_tls_1 (handler_ctx *hctx)
}
static int
mod_nss_alpn_h2_policy (handler_ctx * const hctx)
{
UNUSED(hctx);
/*(currently called after handshake has completed)*/
#if 0 /* SNI omitted by client when connecting to IP instead of to name */
if (buffer_string_is_empty(&hctx->r->uri.authority)) {
log_error(hctx->errh, __FILE__, __LINE__,
"SSL: error ALPN h2 without SNI");
return -1;
}
#endif
#if 0
/* sanity check; lighttpd defaults to using TLSv1.2 or better */
/* modified from http_cgi_ssl_env(); expensive, so commented out */
/* (quite a bit of work just to get protocol version)
* (could not find better NSS interface) */
SSLChannelInfo inf;
if (SSL_GetChannelInfo(ssl, &inf, sizeof(inf)) < 0
|| inf.protocolVersion < SSL_LIBRARY_VERSION_TLS_1_2) {
log_error(hctx->errh, __FILE__, __LINE__,
"SSL: error ALPN h2 requires TLSv1.2 or later");
return -1;
}
#endif
return 0;
}
enum {
MOD_NSS_ALPN_HTTP11 = 1
,MOD_NSS_ALPN_HTTP10 = 2
@ -1507,6 +1537,9 @@ mod_nss_ssl_conf_cmd (server *srv, plugin_config_socket *s)
switch ((int)(e-v)) {
case 11:
if (buffer_eq_icase_ssn(v, "Compression", 11)) {
/* (force disabled, the default, if HTTP/2 enabled) */
if (srv->srvconf.h2proto)
flag = 0;
s->ssl_compression = flag;
continue;
}
@ -2037,7 +2070,12 @@ SETDEFAULTS_FUNC(mod_nss_set_defaults)
}
break;
case 5: /* ssl.read-ahead */
break;
case 6: /* ssl.disable-client-renegotiation */
/* (force disabled, the default, if HTTP/2 enabled in server) */
if (srv->srvconf.h2proto)
cpv->v.u = 1; /* disable client renegotiation */
break;
case 7: /* ssl.verifyclient.activate */
case 8: /* ssl.verifyclient.enforce */
break;
@ -2257,7 +2295,11 @@ connection_read_cq_ssl (connection *con, chunkqueue *cq, off_t max_bytes)
} while (len > 0);
if (hctx->alpn && hctx->handshake) {
if (hctx->alpn == MOD_NSS_ALPN_ACME_TLS_1) {
if (hctx->alpn == MOD_NSS_ALPN_H2) {
if (0 != mod_nss_alpn_h2_policy(hctx))
return -1;
}
else if (hctx->alpn == MOD_NSS_ALPN_ACME_TLS_1) {
/* Once TLS handshake is complete, return -1 to result in
* CON_STATE_ERROR so that socket connection is quickly closed */
return -1;

37
src/mod_openssl.c

@ -1804,6 +1804,26 @@ mod_openssl_acme_tls_1 (SSL *ssl, handler_ctx *hctx)
return rc;
}
static int
mod_openssl_alpn_h2_policy (handler_ctx * const hctx)
{
/*(currently called after handshake has completed)*/
#if 0 /* SNI omitted by client when connecting to IP instead of to name */
if (buffer_string_is_empty(&hctx->r->uri.authority)) {
log_error(hctx->errh, __FILE__, __LINE__,
"SSL: error ALPN h2 without SNI");
return -1;
}
#endif
if (SSL_version(hctx->ssl) < TLS1_2_VERSION) {
log_error(hctx->errh, __FILE__, __LINE__,
"SSL: error ALPN h2 requires TLSv1.2 or later");
return -1;
}
return 0;
}
/* https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids */
static int
mod_openssl_alpn_select_cb (SSL *ssl, const unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg)
@ -2399,6 +2419,9 @@ network_init_ssl (server *srv, plugin_config_socket *s, plugin_data *p)
if (s->ssl_conf_cmd && s->ssl_conf_cmd->used) {
if (0 != network_openssl_ssl_conf_cmd(srv, s)) return -1;
/* (force compression disabled, the default, if HTTP/2 enabled) */
if (srv->srvconf.h2proto)
SSL_CTX_set_options(s->ssl_ctx, SSL_OP_NO_COMPRESSION);
}
return 0;
@ -2807,7 +2830,12 @@ SETDEFAULTS_FUNC(mod_openssl_set_defaults)
if (0 == i) default_ssl_ca_crl_file = cpv->v.b;
break;
case 5: /* ssl.read-ahead */
break;
case 6: /* ssl.disable-client-renegotiation */
/* (force disabled, the default, if HTTP/2 enabled in server) */
if (srv->srvconf.h2proto)
cpv->v.u = 1; /* disable client renegotiation */
break;
case 7: /* ssl.verifyclient.activate */
case 8: /* ssl.verifyclient.enforce */
break;
@ -3086,7 +3114,11 @@ connection_read_cq_ssl (connection *con, chunkqueue *cq, off_t max_bytes)
#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
if (hctx->alpn) {
if (hctx->alpn == MOD_OPENSSL_ALPN_ACME_TLS_1) {
if (hctx->alpn == MOD_OPENSSL_ALPN_H2) {
if (0 != mod_openssl_alpn_h2_policy(hctx))
return -1;
}
else if (hctx->alpn == MOD_OPENSSL_ALPN_ACME_TLS_1) {
chunkqueue_reset(cq);
/* initiate handshake in order to send ServerHello.
* Once TLS handshake is complete, return -1 to result in
@ -3714,6 +3746,9 @@ mod_openssl_ssl_conf_cmd (server *srv, plugin_config_socket *s)
switch ((int)(e-v)) {
case 11:
if (buffer_eq_icase_ssn(v, "Compression", 11)) {
/* (force disabled, the default, if HTTP/2 enabled) */
if (srv->srvconf.h2proto)
flag = 0;
if (flag)
SSL_CTX_clear_options(s->ssl_ctx,
SSL_OP_NO_COMPRESSION);

34
src/mod_wolfssl.c

@ -1743,6 +1743,26 @@ mod_openssl_acme_tls_1 (SSL *ssl, handler_ctx *hctx)
return rc;
}
static int
mod_openssl_alpn_h2_policy (handler_ctx * const hctx)
{
/*(currently called after handshake has completed)*/
#if 0 /* SNI omitted by client when connecting to IP instead of to name */
if (buffer_string_is_empty(&hctx->r->uri.authority)) {
log_error(hctx->errh, __FILE__, __LINE__,
"SSL: error ALPN h2 without SNI");
return -1;
}
#endif
if (wolfSSL_version(hctx->ssl) < TLS1_2_VERSION) {
log_error(hctx->errh, __FILE__, __LINE__,
"SSL: error ALPN h2 requires TLSv1.2 or later");
return -1;
}
return 0;
}
/* https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids */
static int
mod_openssl_alpn_select_cb (SSL *ssl, const unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg)
@ -2603,7 +2623,12 @@ SETDEFAULTS_FUNC(mod_openssl_set_defaults)
if (0 == i) default_ssl_ca_crl_file = cpv->v.b;
break;
case 5: /* ssl.read-ahead */
break;
case 6: /* ssl.disable-client-renegotiation */
/* (force disabled, the default, if HTTP/2 enabled in server) */
if (srv->srvconf.h2proto)
cpv->v.u = 1; /* disable client renegotiation */
break;
case 7: /* ssl.verifyclient.activate */
case 8: /* ssl.verifyclient.enforce */
break;
@ -2850,7 +2875,11 @@ connection_read_cq_ssl (connection *con, chunkqueue *cq, off_t max_bytes)
#ifdef HAVE_ALPN
#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
if (hctx->alpn) {
if (hctx->alpn == MOD_OPENSSL_ALPN_ACME_TLS_1) {
if (hctx->alpn == MOD_OPENSSL_ALPN_H2) {
if (0 != mod_openssl_alpn_h2_policy(hctx))
return -1;
}
else if (hctx->alpn == MOD_OPENSSL_ALPN_ACME_TLS_1) {
chunkqueue_reset(cq);
/* initiate handshake in order to send ServerHello.
* Once TLS handshake is complete, return -1 to result in
@ -3478,6 +3507,9 @@ mod_openssl_ssl_conf_cmd (server *srv, plugin_config_socket *s)
switch ((int)(e-v)) {
case 11:
if (buffer_eq_icase_ssn(v, "Compression", 11)) {
/* (force disabled, the default, if HTTP/2 enabled) */
if (srv->srvconf.h2proto)
flag = 0;
if (flag)
SSL_CTX_clear_options(s->ssl_ctx,
SSL_OP_NO_COMPRESSION);

Loading…
Cancel
Save