nghttpx: Only allow DHE, ECDHE + AEAD ciphers for HTTP/2

Cipher suites are chosen by DHE and ECDHE ciphers + GCM (AEAD).  Now
default cipher list is the one recommended by Mozilla web site.  The
--honor-cipher-order option is removed and now it is always assumed.
This commit is contained in:
Tatsuhiro Tsujikawa 2014-06-10 22:47:22 +09:00
parent 5f5b5378c9
commit 7b0ed5d9bd
5 changed files with 111 additions and 29 deletions

30
mkcipherlist.py Executable file
View File

@ -0,0 +1,30 @@
#!/usr/bin/env python
import re
import sys
import csv
pat = re.compile(r'\ATLS_(?:ECDHE|DHE)_.*_GCM')
ciphers = []
for hl, name, _, _ in csv.reader(sys.stdin):
if not pat.match(name):
continue
high, low = hl.split(',')
id = high + low[2:] + 'u'
ciphers.append((id, name))
print '''\
enum {'''
for id, name in ciphers:
print '{} = {},'.format(name, id)
print '''\
};
'''
for id, name in ciphers:
print '''\
case {}:'''.format(name)

View File

@ -407,7 +407,6 @@ void fill_default_config()
// Default accept() backlog // Default accept() backlog
mod_config()->backlog = -1; mod_config()->backlog = -1;
mod_config()->ciphers = nullptr; mod_config()->ciphers = nullptr;
mod_config()->honor_cipher_order = false;
mod_config()->http2_proxy = false; mod_config()->http2_proxy = false;
mod_config()->http2_bridge = false; mod_config()->http2_bridge = false;
mod_config()->client_proxy = false; mod_config()->client_proxy = false;
@ -616,12 +615,7 @@ Timeout:
SSL/TLS: SSL/TLS:
--ciphers=<SUITE> Set allowed cipher list. The format of the --ciphers=<SUITE> Set allowed cipher list. The format of the
string is described in OpenSSL ciphers(1). If string is described in OpenSSL ciphers(1).
this option is used, --honor-cipher-order is
implicitly enabled.
--honor-cipher-order
Honor server cipher order, giving the ability to
mitigate BEAST attacks.
-k, --insecure -k, --insecure
Don't verify backend server's certificate if -p, Don't verify backend server's certificate if -p,
--client or --http2-bridge are given and --client or --http2-bridge are given and
@ -859,7 +853,6 @@ int main(int argc, char **argv)
{"backend-no-tls", no_argument, &flag, 27}, {"backend-no-tls", no_argument, &flag, 27},
{"frontend-no-tls", no_argument, &flag, 29}, {"frontend-no-tls", no_argument, &flag, 29},
{"backend-tls-sni-field", required_argument, &flag, 31}, {"backend-tls-sni-field", required_argument, &flag, 31},
{"honor-cipher-order", no_argument, &flag, 32},
{"dh-param-file", required_argument, &flag, 33}, {"dh-param-file", required_argument, &flag, 33},
{"read-rate", required_argument, &flag, 34}, {"read-rate", required_argument, &flag, 34},
{"read-burst", required_argument, &flag, 35}, {"read-burst", required_argument, &flag, 35},
@ -1051,10 +1044,6 @@ int main(int argc, char **argv)
// --backend-tls-sni-field // --backend-tls-sni-field
cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_TLS_SNI_FIELD, optarg); cmdcfgs.emplace_back(SHRPX_OPT_BACKEND_TLS_SNI_FIELD, optarg);
break; break;
case 32:
// --honor-cipher-order
cmdcfgs.emplace_back(SHRPX_OPT_HONOR_CIPHER_ORDER, "yes");
break;
case 33: case 33:
// --dh-param-file // --dh-param-file
cmdcfgs.emplace_back(SHRPX_OPT_DH_PARAM_FILE, optarg); cmdcfgs.emplace_back(SHRPX_OPT_DH_PARAM_FILE, optarg);

View File

@ -93,7 +93,6 @@ const char SHRPX_OPT_SYSLOG[] = "syslog";
const char SHRPX_OPT_SYSLOG_FACILITY[] = "syslog-facility"; const char SHRPX_OPT_SYSLOG_FACILITY[] = "syslog-facility";
const char SHRPX_OPT_BACKLOG[] = "backlog"; const char SHRPX_OPT_BACKLOG[] = "backlog";
const char SHRPX_OPT_CIPHERS[] = "ciphers"; const char SHRPX_OPT_CIPHERS[] = "ciphers";
const char SHRPX_OPT_HONOR_CIPHER_ORDER[] = "honor-cipher-order";
const char SHRPX_OPT_CLIENT[] = "client"; const char SHRPX_OPT_CLIENT[] = "client";
const char SHRPX_OPT_INSECURE[] = "insecure"; const char SHRPX_OPT_INSECURE[] = "insecure";
const char SHRPX_OPT_CACERT[] = "cacert"; const char SHRPX_OPT_CACERT[] = "cacert";
@ -572,12 +571,6 @@ int parse_config(const char *opt, const char *optarg)
return 0; return 0;
} }
if(util::strieq(opt, SHRPX_OPT_HONOR_CIPHER_ORDER)) {
mod_config()->honor_cipher_order = util::strieq(optarg, "yes");
return 0;
}
if(util::strieq(opt, SHRPX_OPT_CLIENT)) { if(util::strieq(opt, SHRPX_OPT_CLIENT)) {
mod_config()->client = util::strieq(optarg, "yes"); mod_config()->client = util::strieq(optarg, "yes");

View File

@ -84,7 +84,6 @@ extern const char SHRPX_OPT_SYSLOG[];
extern const char SHRPX_OPT_SYSLOG_FACILITY[]; extern const char SHRPX_OPT_SYSLOG_FACILITY[];
extern const char SHRPX_OPT_BACKLOG[]; extern const char SHRPX_OPT_BACKLOG[];
extern const char SHRPX_OPT_CIPHERS[]; extern const char SHRPX_OPT_CIPHERS[];
extern const char SHRPX_OPT_HONOR_CIPHER_ORDER[];
extern const char SHRPX_OPT_CLIENT[]; extern const char SHRPX_OPT_CLIENT[];
extern const char SHRPX_OPT_INSECURE[]; extern const char SHRPX_OPT_INSECURE[];
extern const char SHRPX_OPT_CACERT[]; extern const char SHRPX_OPT_CACERT[];
@ -245,7 +244,6 @@ struct Config {
bool syslog; bool syslog;
// This member finally decides syslog is used or not // This member finally decides syslog is used or not
bool use_syslog; bool use_syslog;
bool honor_cipher_order;
bool client; bool client;
// true if --client or --client-proxy are enabled. // true if --client or --client-proxy are enabled.
bool client_mode; bool client_mode;

View File

@ -250,14 +250,14 @@ SSL_CTX* create_ssl_context(const char *private_key_file,
const char *ciphers; const char *ciphers;
if(get_config()->ciphers) { if(get_config()->ciphers) {
ciphers = get_config()->ciphers.get(); ciphers = get_config()->ciphers.get();
// If ciphers are given, honor its order unconditionally
SSL_CTX_set_options(ssl_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
} else { } else {
ciphers = "HIGH:!aNULL:!eNULL"; // Recommended general purpose cipher by mozilla.
if(get_config()->honor_cipher_order) { // https://wiki.mozilla.org/Security/Server_Side_TLS
ciphers = "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:ECDHE-RSA-RC4-SHA:ECDHE-ECDSA-RC4-SHA:AES128:AES256:RC4-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!3DES:!MD5:!PSK";
}
SSL_CTX_set_options(ssl_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE); SSL_CTX_set_options(ssl_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
}
}
if(SSL_CTX_set_cipher_list(ssl_ctx, ciphers) == 0) { if(SSL_CTX_set_cipher_list(ssl_ctx, ciphers) == 0) {
LOG(FATAL) << "SSL_CTX_set_cipher_list " << ciphers << " failed: " LOG(FATAL) << "SSL_CTX_set_cipher_list " << ciphers << " failed: "
<< ERR_error_string(ERR_get_error(), nullptr); << ERR_error_string(ERR_get_error(), nullptr);
@ -907,6 +907,40 @@ bool in_proto_list(const std::vector<char*>& protos,
return false; return false;
} }
// This enum was generated by mkcipherlist.py
enum {
TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 = 0x009Eu,
TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 = 0x009Fu,
TLS_DHE_DSS_WITH_AES_128_GCM_SHA256 = 0x00A2u,
TLS_DHE_DSS_WITH_AES_256_GCM_SHA384 = 0x00A3u,
TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 = 0x00AAu,
TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 = 0x00ABu,
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 = 0xC02Bu,
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 = 0xC02Cu,
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 = 0xC02Fu,
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 = 0xC030u,
TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256 = 0xC052u,
TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384 = 0xC053u,
TLS_DHE_DSS_WITH_ARIA_128_GCM_SHA256 = 0xC056u,
TLS_DHE_DSS_WITH_ARIA_256_GCM_SHA384 = 0xC057u,
TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256 = 0xC05Cu,
TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384 = 0xC05Du,
TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256 = 0xC060u,
TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384 = 0xC061u,
TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256 = 0xC06Cu,
TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384 = 0xC06Du,
TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 = 0xC07Cu,
TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 = 0xC07Du,
TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256 = 0xC080u,
TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384 = 0xC081u,
TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 = 0xC086u,
TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 = 0xC087u,
TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 = 0xC08Au,
TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 = 0xC08Bu,
TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256 = 0xC090u,
TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384 = 0xC091u,
};
bool check_http2_requirement(SSL *ssl) bool check_http2_requirement(SSL *ssl)
{ {
auto tls_ver = SSL_version(ssl); auto tls_ver = SSL_version(ssl);
@ -921,8 +955,46 @@ bool check_http2_requirement(SSL *ssl)
return false; return false;
} }
// TODO Figure out that ECDHE or DHE was negotiated and their key auto cipher = SSL_get_current_cipher(ssl);
// size. SSL_get_server_tmp_key() cannot be used on server side.
switch(SSL_CIPHER_get_id(cipher) & 0xffffu) {
// This case labels were generated by mkcipherlist.py
case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:
case TLS_DHE_RSA_WITH_AES_256_GCM_SHA384:
case TLS_DHE_DSS_WITH_AES_128_GCM_SHA256:
case TLS_DHE_DSS_WITH_AES_256_GCM_SHA384:
case TLS_DHE_PSK_WITH_AES_128_GCM_SHA256:
case TLS_DHE_PSK_WITH_AES_256_GCM_SHA384:
case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:
case TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256:
case TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384:
case TLS_DHE_DSS_WITH_ARIA_128_GCM_SHA256:
case TLS_DHE_DSS_WITH_ARIA_256_GCM_SHA384:
case TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256:
case TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384:
case TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256:
case TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384:
case TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256:
case TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384:
case TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256:
case TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384:
case TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256:
case TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384:
case TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256:
case TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384:
case TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256:
case TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384:
case TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256:
case TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384:
break;
default:
return false;
}
// TODO Check number of bits
return true; return true;
} }