Commit 7ce3065f authored by Tatsuhiro Tsujikawa's avatar Tatsuhiro Tsujikawa

nghttpx: Add --tls-proto-list option to enable SSL/TLS protocol selectively

parent 3e21bed4
...@@ -329,6 +329,10 @@ const char *DEFAULT_NPN_LIST = NGHTTP2_PROTO_VERSION_ID "," ...@@ -329,6 +329,10 @@ const char *DEFAULT_NPN_LIST = NGHTTP2_PROTO_VERSION_ID ","
"http/1.1"; "http/1.1";
} // namespace } // namespace
namespace {
const char *DEFAULT_TLS_PROTO_LIST = "TLSv1.2,TLSv1.1,TLSv1.0";
} // namespace
namespace { namespace {
void fill_default_config() void fill_default_config()
{ {
...@@ -622,6 +626,17 @@ void print_help(std::ostream& out) ...@@ -622,6 +626,17 @@ void print_help(std::ostream& out)
<< " Path to file that contains client\n" << " Path to file that contains client\n"
<< " certificate used in backend client\n" << " certificate used in backend client\n"
<< " authentication.\n" << " authentication.\n"
<< " --tls-proto-list=<LIST>\n"
<< " Comma delimited list of SSL/TLS protocol to\n"
<< " be enabled.\n"
<< " The following protocols are available:\n"
<< " TLSv1.2, TLSv1.1, TLSv1.0, SSLv3\n"
<< " The name matching is done in case-insensitive\n"
<< " manner.\n"
<< " The parameter must be delimited by a single\n"
<< " comma only and any white spaces are treated\n"
<< " as a part of protocol string.\n"
<< " Default: " << DEFAULT_TLS_PROTO_LIST << "\n"
<< "\n" << "\n"
<< " HTTP/2.0 and SPDY:\n" << " HTTP/2.0 and SPDY:\n"
<< " -c, --http2-max-concurrent-streams=<NUM>\n" << " -c, --http2-max-concurrent-streams=<NUM>\n"
...@@ -798,6 +813,7 @@ int main(int argc, char **argv) ...@@ -798,6 +813,7 @@ int main(int argc, char **argv)
{"http2-no-cookie-crumbling", no_argument, &flag, 45}, {"http2-no-cookie-crumbling", no_argument, &flag, 45},
{"frontend-http2-connection-window-bits", required_argument, &flag, 46}, {"frontend-http2-connection-window-bits", required_argument, &flag, 46},
{"backend-http2-connection-window-bits", required_argument, &flag, 47}, {"backend-http2-connection-window-bits", required_argument, &flag, 47},
{"tls-proto-list", required_argument, &flag, 48},
{nullptr, 0, nullptr, 0 } {nullptr, 0, nullptr, 0 }
}; };
...@@ -1049,6 +1065,10 @@ int main(int argc, char **argv) ...@@ -1049,6 +1065,10 @@ int main(int argc, char **argv)
(SHRPX_OPT_BACKEND_HTTP2_CONNECTION_WINDOW_BITS, (SHRPX_OPT_BACKEND_HTTP2_CONNECTION_WINDOW_BITS,
optarg)); optarg));
break; break;
case 48:
// --tls-proto-list
cmdcfgs.push_back(std::make_pair(SHRPX_OPT_TLS_PROTO_LIST, optarg));
break;
default: default:
break; break;
} }
...@@ -1091,6 +1111,10 @@ int main(int argc, char **argv) ...@@ -1091,6 +1111,10 @@ int main(int argc, char **argv)
mod_config()->npn_list = parse_config_str_list(&mod_config()->npn_list_len, mod_config()->npn_list = parse_config_str_list(&mod_config()->npn_list_len,
DEFAULT_NPN_LIST); DEFAULT_NPN_LIST);
} }
if(!get_config()->tls_proto_list) {
mod_config()->tls_proto_list = parse_config_str_list
(&mod_config()->tls_proto_list_len, DEFAULT_TLS_PROTO_LIST);
}
if(!get_config()->subcerts.empty()) { if(!get_config()->subcerts.empty()) {
mod_config()->cert_tree = ssl::cert_lookup_tree_new(); mod_config()->cert_tree = ssl::cert_lookup_tree_new();
......
...@@ -105,6 +105,7 @@ const char SHRPX_OPT_READ_BURST[] = "read-burst"; ...@@ -105,6 +105,7 @@ const char SHRPX_OPT_READ_BURST[] = "read-burst";
const char SHRPX_OPT_WRITE_RATE[] = "write-rate"; const char SHRPX_OPT_WRITE_RATE[] = "write-rate";
const char SHRPX_OPT_WRITE_BURST[] = "write-burst"; const char SHRPX_OPT_WRITE_BURST[] = "write-burst";
const char SHRPX_OPT_NPN_LIST[] = "npn-list"; const char SHRPX_OPT_NPN_LIST[] = "npn-list";
const char SHRPX_OPT_TLS_PROTO_LIST[] = "tls-proto-list";
const char SHRPX_OPT_VERIFY_CLIENT[] = "verify-client"; const char SHRPX_OPT_VERIFY_CLIENT[] = "verify-client";
const char SHRPX_OPT_VERIFY_CLIENT_CACERT[] = "verify-client-cacert"; const char SHRPX_OPT_VERIFY_CLIENT_CACERT[] = "verify-client-cacert";
const char SHRPX_OPT_CLIENT_PRIVATE_KEY_FILE[] = "client-private-key-file"; const char SHRPX_OPT_CLIENT_PRIVATE_KEY_FILE[] = "client-private-key-file";
...@@ -453,6 +454,10 @@ int parse_config(const char *opt, const char *optarg) ...@@ -453,6 +454,10 @@ int parse_config(const char *opt, const char *optarg)
delete [] mod_config()->npn_list; delete [] mod_config()->npn_list;
mod_config()->npn_list = parse_config_str_list(&mod_config()->npn_list_len, mod_config()->npn_list = parse_config_str_list(&mod_config()->npn_list_len,
optarg); optarg);
} else if(util::strieq(opt, SHRPX_OPT_TLS_PROTO_LIST)) {
delete [] mod_config()->tls_proto_list;
mod_config()->tls_proto_list = parse_config_str_list
(&mod_config()->tls_proto_list_len, optarg);
} else if(util::strieq(opt, SHRPX_OPT_VERIFY_CLIENT)) { } else if(util::strieq(opt, SHRPX_OPT_VERIFY_CLIENT)) {
mod_config()->verify_client = util::strieq(optarg, "yes"); mod_config()->verify_client = util::strieq(optarg, "yes");
} else if(util::strieq(opt, SHRPX_OPT_VERIFY_CLIENT_CACERT)) { } else if(util::strieq(opt, SHRPX_OPT_VERIFY_CLIENT_CACERT)) {
......
...@@ -94,6 +94,7 @@ extern const char SHRPX_OPT_READ_BURST[]; ...@@ -94,6 +94,7 @@ extern const char SHRPX_OPT_READ_BURST[];
extern const char SHRPX_OPT_WRITE_RATE[]; extern const char SHRPX_OPT_WRITE_RATE[];
extern const char SHRPX_OPT_WRITE_BURST[]; extern const char SHRPX_OPT_WRITE_BURST[];
extern const char SHRPX_OPT_NPN_LIST[]; extern const char SHRPX_OPT_NPN_LIST[];
extern const char SHRPX_OPT_TLS_PROTO_LIST[];
extern const char SHRPX_OPT_VERIFY_CLIENT[]; extern const char SHRPX_OPT_VERIFY_CLIENT[];
extern const char SHRPX_OPT_VERIFY_CLIENT_CACERT[]; extern const char SHRPX_OPT_VERIFY_CLIENT_CACERT[];
extern const char SHRPX_OPT_CLIENT_PRIVATE_KEY_FILE[]; extern const char SHRPX_OPT_CLIENT_PRIVATE_KEY_FILE[];
...@@ -151,6 +152,9 @@ struct Config { ...@@ -151,6 +152,9 @@ struct Config {
// preference. The each element of this list is a NULL-terminated // preference. The each element of this list is a NULL-terminated
// string. // string.
char **npn_list; char **npn_list;
// list of supported SSL/TLS protocol strings. The each element of
// this list is a NULL-terminated string.
char **tls_proto_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
char *verify_client_cacert; char *verify_client_cacert;
...@@ -173,6 +177,8 @@ struct Config { ...@@ -173,6 +177,8 @@ struct Config {
size_t write_burst; size_t write_burst;
// The number of elements in npn_list // The number of elements in npn_list
size_t npn_list_len; size_t npn_list_len;
// The number of elements in tls_proto_list
size_t tls_proto_list_len;
// downstream protocol; this will be determined by given options. // downstream protocol; this will be determined by given options.
shrpx_proto downstream_proto; shrpx_proto downstream_proto;
int syslog_facility; int syslog_facility;
......
...@@ -149,6 +149,29 @@ int alpn_select_proto_cb(SSL* ssl, ...@@ -149,6 +149,29 @@ int alpn_select_proto_cb(SSL* ssl,
} // namespace } // namespace
#endif // OPENSSL_VERSION_NUMBER >= 0x10002000L #endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
namespace {
const char *names[] = { "TLSv1.2", "TLSv1.1", "TLSv1.0", "SSLv3" };
const size_t namelen = sizeof(names)/sizeof(names[0]);
const long int masks[] = { SSL_OP_NO_TLSv1_2, SSL_OP_NO_TLSv1_1,
SSL_OP_NO_TLSv1, SSL_OP_NO_SSLv3 };
long int create_tls_proto_mask(char **tls_proto_list, size_t len)
{
long int res = 0;
for(size_t i = 0; i < namelen; ++i) {
size_t j;
for(j = 0; j < len; ++j) {
if(strcasecmp(names[i], tls_proto_list[j]) == 0) {
break;
}
}
if(j == len) {
res |= masks[i];
}
}
return res;
}
} // namespace
SSL_CTX* create_ssl_context(const char *private_key_file, SSL_CTX* create_ssl_context(const char *private_key_file,
const char *cert_file) const char *cert_file)
{ {
...@@ -158,11 +181,14 @@ SSL_CTX* create_ssl_context(const char *private_key_file, ...@@ -158,11 +181,14 @@ SSL_CTX* create_ssl_context(const char *private_key_file,
LOG(FATAL) << ERR_error_string(ERR_get_error(), nullptr); LOG(FATAL) << ERR_error_string(ERR_get_error(), nullptr);
DIE(); DIE();
} }
SSL_CTX_set_options(ssl_ctx, SSL_CTX_set_options(ssl_ctx,
SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_COMPRESSION | SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_COMPRESSION |
SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION |
SSL_OP_SINGLE_ECDH_USE | SSL_OP_SINGLE_DH_USE | SSL_OP_SINGLE_ECDH_USE | SSL_OP_SINGLE_DH_USE |
SSL_OP_NO_TICKET); SSL_OP_NO_TICKET |
create_tls_proto_mask(get_config()->tls_proto_list,
get_config()->tls_proto_list_len));
const unsigned char sid_ctx[] = "shrpx"; const unsigned char sid_ctx[] = "shrpx";
SSL_CTX_set_session_id_context(ssl_ctx, sid_ctx, sizeof(sid_ctx)-1); SSL_CTX_set_session_id_context(ssl_ctx, sid_ctx, sizeof(sid_ctx)-1);
...@@ -295,7 +321,9 @@ SSL_CTX* create_ssl_client_context() ...@@ -295,7 +321,9 @@ SSL_CTX* create_ssl_client_context()
} }
SSL_CTX_set_options(ssl_ctx, SSL_CTX_set_options(ssl_ctx,
SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_COMPRESSION | SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_COMPRESSION |
SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION); SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION |
create_tls_proto_mask(get_config()->tls_proto_list,
get_config()->tls_proto_list_len));
if(get_config()->ciphers) { if(get_config()->ciphers) {
if(SSL_CTX_set_cipher_list(ssl_ctx, get_config()->ciphers) == 0) { if(SSL_CTX_set_cipher_list(ssl_ctx, get_config()->ciphers) == 0) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment