From aea036c9d4be62abe80d2f02372aa0cd49144787 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Fri, 30 Aug 2013 22:07:42 +0900 Subject: [PATCH] nghttpx: Support ECDHE and DHE cipher suites Use --dh-param-file option to specify a file including DH parameters in PEM format. For example, you can create DH parameters with 1024 bit key using following command: $ openssl dhparam -outform PEM -out dhparam.pem 1024 --- src/shrpx.cc | 10 +++++++++- src/shrpx_config.cc | 3 +++ src/shrpx_config.h | 2 ++ src/shrpx_ssl.cc | 34 +++++++++++++++++++++++++++++++++- 4 files changed, 47 insertions(+), 2 deletions(-) diff --git a/src/shrpx.cc b/src/shrpx.cc index 0ae70e92..3a616eb2 100644 --- a/src/shrpx.cc +++ b/src/shrpx.cc @@ -529,6 +529,10 @@ void print_help(std::ostream& out) << " Explicitly set the content of the TLS SNI\n" << " extension. This will default to the backend\n" << " HOST name.\n" + << " --dh-param-file=\n" + << " Path to file that contains DH parameters in\n" + << " PEM format. Without this option, DHE cipher\n" + << " suites are not available." << "\n" << " HTTP/2.0 and SPDY:\n" << " -c, --spdy-max-concurrent-streams=\n" @@ -660,6 +664,7 @@ int main(int argc, char **argv) {"frontend-no-tls", no_argument, &flag, 29}, {"backend-tls-sni-field", required_argument, &flag, 31}, {"honor-cipher-order", no_argument, &flag, 32}, + {"dh-param-file", required_argument, &flag, 33}, {nullptr, 0, nullptr, 0 } }; int option_index = 0; @@ -839,7 +844,10 @@ int main(int argc, char **argv) cmdcfgs.push_back(std::make_pair(SHRPX_OPT_HONOR_CIPHER_ORDER, "yes")); break; - + case 33: + // --dh-param-file + cmdcfgs.push_back(std::make_pair(SHRPX_OPT_DH_PARAM_FILE, optarg)); + break; default: break; } diff --git a/src/shrpx_config.cc b/src/shrpx_config.cc index b7f057fb..e1cf5f59 100644 --- a/src/shrpx_config.cc +++ b/src/shrpx_config.cc @@ -53,6 +53,7 @@ namespace shrpx { const char SHRPX_OPT_PRIVATE_KEY_FILE[] = "private-key-file"; const char SHRPX_OPT_PRIVATE_KEY_PASSWD_FILE[] = "private-key-passwd-file"; const char SHRPX_OPT_CERTIFICATE_FILE[] = "certificate-file"; +const char SHRPX_OPT_DH_PARAM_FILE[] = "dh-param-file"; const char SHRPX_OPT_SUBCERT[] = "subcert"; const char SHRPX_OPT_BACKEND[] = "backend"; @@ -296,6 +297,8 @@ int parse_config(const char *opt, const char *optarg) set_config_str(&mod_config()->private_key_passwd, passwd.c_str()); } else if(util::strieq(opt, SHRPX_OPT_CERTIFICATE_FILE)) { set_config_str(&mod_config()->cert_file, optarg); + } else if(util::strieq(opt, SHRPX_OPT_DH_PARAM_FILE)) { + set_config_str(&mod_config()->dh_param_file, optarg); } else if(util::strieq(opt, SHRPX_OPT_SUBCERT)) { // Private Key file and certificate file separated by ':'. const char *sp = strchr(optarg, ':'); diff --git a/src/shrpx_config.h b/src/shrpx_config.h index d27653e2..c0cd6905 100644 --- a/src/shrpx_config.h +++ b/src/shrpx_config.h @@ -47,6 +47,7 @@ struct CertLookupTree; extern const char SHRPX_OPT_PRIVATE_KEY_FILE[]; extern const char SHRPX_OPT_PRIVATE_KEY_PASSWD_FILE[]; extern const char SHRPX_OPT_CERTIFICATE_FILE[]; +extern const char SHRPX_OPT_DH_PARAM_FILE[]; extern const char SHRPX_OPT_SUBCERT[]; extern const char SHRPX_OPT_BACKEND[]; extern const char SHRPX_OPT_FRONTEND[]; @@ -105,6 +106,7 @@ struct Config { char *private_key_file; char *private_key_passwd; char *cert_file; + char *dh_param_file; SSL_CTX *default_ssl_ctx; ssl::CertLookupTree *cert_tree; bool verify_client; diff --git a/src/shrpx_ssl.cc b/src/shrpx_ssl.cc index 63045fe2..af8dc6a0 100644 --- a/src/shrpx_ssl.cc +++ b/src/shrpx_ssl.cc @@ -138,7 +138,9 @@ SSL_CTX* create_ssl_context(const char *private_key_file, } SSL_CTX_set_options(ssl_ctx, 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_NO_TICKET); const unsigned char sid_ctx[] = "shrpx"; SSL_CTX_set_session_id_context(ssl_ctx, sid_ctx, sizeof(sid_ctx)-1); @@ -155,6 +157,36 @@ SSL_CTX* create_ssl_context(const char *private_key_file, } } + // Use P-256, which is sufficiently secure at the time of this + // writing. + auto ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); + if(ecdh == nullptr) { + LOG(FATAL) << "EC_KEY_new_by_curv_name failed: " + << ERR_error_string(ERR_get_error(), nullptr); + DIE(); + } + SSL_CTX_set_tmp_ecdh(ssl_ctx, ecdh); + EC_KEY_free(ecdh); + + if(get_config()->dh_param_file) { + // Read DH parameters from file + auto bio = BIO_new_file(get_config()->dh_param_file, "r"); + if(bio == nullptr) { + LOG(FATAL) << "BIO_new_file() failed: " + << ERR_error_string(ERR_get_error(), nullptr); + DIE(); + } + auto dh = PEM_read_bio_DHparams(bio, nullptr, nullptr, nullptr); + if(dh == nullptr) { + LOG(FATAL) << "PEM_read_bio_DHparams() failed: " + << ERR_error_string(ERR_get_error(), nullptr); + DIE(); + } + SSL_CTX_set_tmp_dh(ssl_ctx, dh); + DH_free(dh); + BIO_free(bio); + } + SSL_CTX_set_mode(ssl_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE); SSL_CTX_set_mode(ssl_ctx, SSL_MODE_AUTO_RETRY); SSL_CTX_set_mode(ssl_ctx, SSL_MODE_RELEASE_BUFFERS);