ALPN: Do not negotiate HTTP/2 unless TLSv1.2 or TLSv1.1 was used

This commit is contained in:
Tatsuhiro Tsujikawa 2014-04-26 22:37:48 +09:00
parent cd69ed20c3
commit 6c66bd5c7c
2 changed files with 58 additions and 12 deletions

View File

@ -155,6 +155,24 @@ void info_callback(const SSL *ssl, int where, int ret)
} // namespace } // namespace
#if OPENSSL_VERSION_NUMBER >= 0x10002000L #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 { namespace {
int alpn_select_proto_cb(SSL* ssl, int alpn_select_proto_cb(SSL* ssl,
const unsigned char **out, const unsigned char **out,
@ -164,6 +182,8 @@ int alpn_select_proto_cb(SSL* ssl,
{ {
int rv; int rv;
if(check_http2_requirement(ssl)) {
rv = nghttp2_select_next_protocol rv = nghttp2_select_next_protocol
(const_cast<unsigned char**>(out), outlen, in, inlen); (const_cast<unsigned char**>(out), outlen, in, inlen);
@ -171,24 +191,27 @@ int alpn_select_proto_cb(SSL* ssl,
// HTTP/2 was selected // HTTP/2 was selected
return SSL_TLSEXT_ERR_OK; 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 #ifdef HAVE_SPDYLAY
rv = spdylay_select_next_protocol rv = spdylay_select_next_protocol
(const_cast<unsigned char**>(out), outlen, in, inlen); (const_cast<unsigned char**>(out), outlen, in, inlen);
if(rv > 0) {
// SPDY was selected
return SSL_TLSEXT_ERR_OK;
}
#endif // HAVE_SPDYLAY #endif // HAVE_SPDYLAY
if(rv == -1) { if(rv == -1) {
// No selection was made // No selection was made
return SSL_TLSEXT_ERR_OK; return SSL_TLSEXT_ERR_NOACK;
} }
// We selected http/1.1 // We selected http/1.1
return SSL_TLSEXT_ERR_NOACK; return SSL_TLSEXT_ERR_OK;
} }
} // namespace } // namespace
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L #endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
@ -895,6 +918,26 @@ bool in_proto_list(char **protos, size_t len,
return false; 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 ssl
} // namespace shrpx } // namespace shrpx

View File

@ -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, bool in_proto_list(char **protos, size_t len,
const unsigned char *proto, size_t protolen); 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 ssl
} // namespace shrpx } // namespace shrpx