nghttpx: Don't allow application protocol not listed in --npn-list option

This commit is contained in:
Tatsuhiro Tsujikawa 2014-01-02 00:53:07 +09:00
parent 78e5149495
commit 20877b1107
5 changed files with 41 additions and 8 deletions

View File

@ -602,7 +602,7 @@ void print_help(std::ostream& out)
<< " Path to file that contains DH parameters in\n" << " Path to file that contains DH parameters in\n"
<< " PEM format. Without this option, DHE cipher\n" << " PEM format. Without this option, DHE cipher\n"
<< " suites are not available.\n" << " suites are not available.\n"
<< " --npn-list=<LIST> Comma delimited list of NPN protocol sorted\n" << " --npn-list=<LIST> Comma delimited list of NPN/ALPN protocol sorted\n"
<< " in the order of preference. That means\n" << " in the order of preference. That means\n"
<< " most desirable protocol comes first.\n" << " most desirable protocol comes first.\n"
<< " The parameter must be delimited by a single\n" << " The parameter must be delimited by a single\n"

View File

@ -34,6 +34,7 @@
#include "shrpx_http_downstream_connection.h" #include "shrpx_http_downstream_connection.h"
#include "shrpx_http2_downstream_connection.h" #include "shrpx_http2_downstream_connection.h"
#include "shrpx_accesslog.h" #include "shrpx_accesslog.h"
#include "shrpx_ssl.h"
#ifdef HAVE_SPDYLAY #ifdef HAVE_SPDYLAY
#include "shrpx_spdy_upstream.h" #include "shrpx_spdy_upstream.h"
#endif // HAVE_SPDYLAY #endif // HAVE_SPDYLAY
@ -108,7 +109,10 @@ void upstream_eventcb(bufferevent *bev, short events, void *arg)
if(LOG_ENABLED(INFO)) { if(LOG_ENABLED(INFO)) {
CLOG(INFO, handler) << "SSL/TLS handleshake completed"; CLOG(INFO, handler) << "SSL/TLS handleshake completed";
} }
handler->validate_next_proto(); if(handler->validate_next_proto() != 0) {
delete handler;
return;
}
if(LOG_ENABLED(INFO)) { if(LOG_ENABLED(INFO)) {
if(SSL_session_reused(handler->get_ssl())) { if(SSL_session_reused(handler->get_ssl())) {
CLOG(INFO, handler) << "SSL/TLS session reused"; CLOG(INFO, handler) << "SSL/TLS session reused";
@ -305,6 +309,11 @@ int ClientHandler::validate_next_proto()
std::string proto(next_proto, next_proto+next_proto_len); std::string proto(next_proto, next_proto+next_proto_len);
CLOG(INFO, this) << "The negotiated next protocol: " << proto; CLOG(INFO, this) << "The negotiated next protocol: " << proto;
} }
if(!ssl::in_proto_list(get_config()->npn_list,
get_config()->npn_list_len,
next_proto, next_proto_len)) {
break;
}
if(next_proto_len == NGHTTP2_PROTO_VERSION_ID_LEN && if(next_proto_len == NGHTTP2_PROTO_VERSION_ID_LEN &&
memcmp(NGHTTP2_PROTO_VERSION_ID, next_proto, memcmp(NGHTTP2_PROTO_VERSION_ID, next_proto,
NGHTTP2_PROTO_VERSION_ID_LEN) == 0) { NGHTTP2_PROTO_VERSION_ID_LEN) == 0) {
@ -320,6 +329,10 @@ int ClientHandler::validate_next_proto()
return 0; return 0;
} }
#endif // HAVE_SPDYLAY #endif // HAVE_SPDYLAY
if(next_proto_len == 8 && memcmp("http/1.1", next_proto, 8) == 0) {
upstream_ = util::make_unique<HttpsUpstream>(this);
return 0;
}
} }
break; break;
} }
@ -331,14 +344,15 @@ int ClientHandler::validate_next_proto()
} }
if(!next_proto) { if(!next_proto) {
if(LOG_ENABLED(INFO)) { if(LOG_ENABLED(INFO)) {
CLOG(INFO, this) << "No proto negotiated."; CLOG(INFO, this) << "No protocol negotiated. Fallback to HTTP/1.1";
} }
upstream_ = util::make_unique<HttpsUpstream>(this);
return 0;
} }
if(LOG_ENABLED(INFO)) { if(LOG_ENABLED(INFO)) {
CLOG(INFO, this) << "Use HTTP/1.1"; CLOG(INFO, this) << "The negotiated protocol is not supported";
} }
upstream_ = util::make_unique<HttpsUpstream>(this); return -1;
return 0;
} }
int ClientHandler::on_read() int ClientHandler::on_read()

View File

@ -147,8 +147,9 @@ struct Config {
char *downstream_http_proxy_host; char *downstream_http_proxy_host;
// Rate limit configuration // Rate limit configuration
ev_token_bucket_cfg *rate_limit_cfg; ev_token_bucket_cfg *rate_limit_cfg;
// Comma delimited list of NPN protocol strings in the order of // list of supported NPN/ALPN protocol strings in the order of
// preference. // preference. The each element of this list is a NULL-terminated
// string.
char **npn_list; char **npn_list;
// Path to file containing CA certificate solely used for client // Path to file containing CA certificate solely used for client
// certificate validation // certificate validation

View File

@ -831,6 +831,18 @@ int cert_lookup_tree_add_cert_from_file(CertLookupTree *lt, SSL_CTX *ssl_ctx,
return 0; return 0;
} }
bool in_proto_list(char **protos, size_t len,
const unsigned char *proto, size_t protolen)
{
for(size_t i = 0; i < len; ++i) {
if(strlen(protos[i]) == protolen &&
memcmp(protos[i], proto, protolen) == 0) {
return true;
}
}
return false;
}
} // namespace ssl } // namespace ssl
} // namespace shrpx } // namespace shrpx

View File

@ -126,6 +126,12 @@ SSL_CTX* cert_lookup_tree_lookup(CertLookupTree *lt, const char *hostname,
int cert_lookup_tree_add_cert_from_file(CertLookupTree *lt, SSL_CTX *ssl_ctx, int cert_lookup_tree_add_cert_from_file(CertLookupTree *lt, SSL_CTX *ssl_ctx,
const char *certfile); const char *certfile);
// Returns true if |proto| which has |protolen| bytes is included in
// the protocol list |protos|, which has |len| elements. The format of
// the |protos| is the one used in Config::npn_list.
bool in_proto_list(char **protos, size_t len,
const unsigned char *proto, size_t protolen);
} // namespace ssl } // namespace ssl
} // namespace shrpx } // namespace shrpx