ALPN: Do not negotiate HTTP/2 unless TLSv1.2 or TLSv1.1 was used
This commit is contained in:
parent
cd69ed20c3
commit
6c66bd5c7c
|
@ -155,6 +155,24 @@ void info_callback(const SSL *ssl, int where, int ret)
|
|||
} // namespace
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
|
||||
namespace {
|
||||
// Returns true if ALPN identifier list |in| of length |inlen|
|
||||
// contains http/1.1.
|
||||
bool check_http1_available_in_alpn_list(const unsigned char *in,
|
||||
unsigned int inlen)
|
||||
{
|
||||
for(unsigned int i = 0; i < inlen; i += 1 + in[i]) {
|
||||
if(in[i] == 8 && i + 1 + in[i] <= inlen &&
|
||||
memcmp("http/1.1", &in[i + 1], in[i]) == 0) {
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
int alpn_select_proto_cb(SSL* ssl,
|
||||
const unsigned char **out,
|
||||
|
@ -164,31 +182,36 @@ int alpn_select_proto_cb(SSL* ssl,
|
|||
{
|
||||
int rv;
|
||||
|
||||
rv = nghttp2_select_next_protocol
|
||||
(const_cast<unsigned char**>(out), outlen, in, inlen);
|
||||
if(check_http2_requirement(ssl)) {
|
||||
|
||||
if(rv == 1) {
|
||||
// HTTP/2 was selected
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
rv = nghttp2_select_next_protocol
|
||||
(const_cast<unsigned char**>(out), outlen, in, inlen);
|
||||
|
||||
if(rv == 1) {
|
||||
// HTTP/2 was selected
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
} else if(check_http1_available_in_alpn_list(in, inlen)) {
|
||||
*out = reinterpret_cast<const unsigned char*>("http/1.1");
|
||||
*outlen = strlen("http/1.1");
|
||||
|
||||
rv = 0;
|
||||
} else {
|
||||
rv = -1;
|
||||
}
|
||||
|
||||
#ifdef HAVE_SPDYLAY
|
||||
rv = spdylay_select_next_protocol
|
||||
(const_cast<unsigned char**>(out), outlen, in, inlen);
|
||||
|
||||
if(rv > 0) {
|
||||
// SPDY was selected
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
#endif // HAVE_SPDYLAY
|
||||
|
||||
if(rv == -1) {
|
||||
// No selection was made
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
return SSL_TLSEXT_ERR_NOACK;
|
||||
}
|
||||
|
||||
// We selected http/1.1
|
||||
return SSL_TLSEXT_ERR_NOACK;
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
} // namespace
|
||||
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
|
||||
|
@ -895,6 +918,26 @@ bool in_proto_list(char **protos, size_t len,
|
|||
return false;
|
||||
}
|
||||
|
||||
bool check_http2_requirement(SSL *ssl)
|
||||
{
|
||||
auto tls_ver = SSL_version(ssl);
|
||||
|
||||
switch(tls_ver) {
|
||||
case TLS1_1_VERSION:
|
||||
case TLS1_2_VERSION:
|
||||
break;
|
||||
default:
|
||||
LOG(INFO) << "TLSv1.2 or TLSv1.1 was not negotiated. "
|
||||
<< "HTTP/2 must not be negotiated.";
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO Figure out that ECDHE or DHE was negotiated and their key
|
||||
// size. SSL_get_server_tmp_key() cannot be used on server side.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace ssl
|
||||
|
||||
} // namespace shrpx
|
||||
|
|
|
@ -129,6 +129,9 @@ int cert_lookup_tree_add_cert_from_file(CertLookupTree *lt, SSL_CTX *ssl_ctx,
|
|||
bool in_proto_list(char **protos, size_t len,
|
||||
const unsigned char *proto, size_t protolen);
|
||||
|
||||
// Returns true if security requirement for HTTP/2 is fulfilled.
|
||||
bool check_http2_requirement(SSL *ssl);
|
||||
|
||||
} // namespace ssl
|
||||
|
||||
} // namespace shrpx
|
||||
|
|
Loading…
Reference in New Issue