diff --git a/src/shrpx.cc b/src/shrpx.cc index 617d997f562d4dd40326627ae6ad5e3d7166182b..202da17ccec1b11afc1c7a13c2f5c1ae9ce8d0c8 100644 --- a/src/shrpx.cc +++ b/src/shrpx.cc @@ -312,6 +312,7 @@ void fill_default_config() set_config_str(&mod_config()->host, "0.0.0.0"); mod_config()->port = 3000; mod_config()->private_key_file = 0; + mod_config()->private_key_passwd = 0; mod_config()->cert_file = 0; // Read timeout for SPDY upstream connection @@ -465,6 +466,11 @@ void print_help(std::ostream& out) << " linked OpenSSL is configured to load system\n" << " wide certificates, they are loaded\n" << " at startup regardless of this option.\n" + << " --private-key-passwd-file=<FILEPATH>\n" + << " Path to file that contains password for the\n" + << " server's private key. If none is given and\n" + << " the private key is password protected it'll\n" + << " be requested interactively." << "\n" << " SPDY:\n" << " -c, --spdy-max-concurrent-streams=<NUM>\n" @@ -566,6 +572,7 @@ int main(int argc, char **argv) {"cacert", required_argument, &flag, 19 }, {"backend-ipv4", no_argument, &flag, 20 }, {"backend-ipv6", no_argument, &flag, 21 }, + {"private-key-passwd-file", required_argument, &flag, 22}, {0, 0, 0, 0 } }; int option_index = 0; @@ -703,6 +710,11 @@ int main(int argc, char **argv) // --backend-ipv6 cmdcfgs.push_back(std::make_pair(SHRPX_OPT_BACKEND_IPV6, "yes")); break; + case 22: + // --private-key-passwd-file + cmdcfgs.push_back(std::make_pair(SHRPX_OPT_PRIVATE_KEY_PASSWD_FILE, + optarg)); + break; default: break; } diff --git a/src/shrpx_config.cc b/src/shrpx_config.cc index 05520b9ddd0c9e6f1fdd7387f5a6be6ebc6e12e5..4cb207807f420edcd146f37f27313f35d5cf463e 100644 --- a/src/shrpx_config.cc +++ b/src/shrpx_config.cc @@ -27,6 +27,9 @@ #include <pwd.h> #include <netdb.h> #include <syslog.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> #include <cstring> #include <cerrno> @@ -41,6 +44,7 @@ using namespace spdylay; 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_BACKEND[] = "backend"; @@ -125,6 +129,41 @@ int split_host_port(char *host, size_t hostlen, uint16_t *port_ptr, } } // namespace +bool is_secure(const char *filename) +{ + struct stat buf; + int rv = stat(filename, &buf); + if (rv == 0) { + if ((buf.st_mode & S_IRWXU) && + !(buf.st_mode & S_IRWXG) && + !(buf.st_mode & S_IRWXO)) { + return true; + } + } + + return false; +} + +std::string read_passwd_from_file(const char *filename) +{ + std::string line; + + if (!is_secure(filename)) { + LOG(ERROR) << "Private key passwd file " << filename + << " has insecure mode."; + return line; + } + + std::ifstream in(filename, std::ios::binary); + if(!in) { + LOG(ERROR) << "Could not open key passwd file " << filename; + return line; + } + + std::getline(in, line); + return line; +} + void set_config_str(char **destp, const char *val) { if(*destp) { @@ -221,6 +260,13 @@ int parse_config(const char *opt, const char *optarg) mod_config()->gid = pwd->pw_gid; } else if(util::strieq(opt, SHRPX_OPT_PRIVATE_KEY_FILE)) { set_config_str(&mod_config()->private_key_file, optarg); + } else if(util::strieq(opt, SHRPX_OPT_PRIVATE_KEY_PASSWD_FILE)) { + std::string passwd = read_passwd_from_file(optarg); + if (passwd.empty()) { + LOG(ERROR) << "Couldn't read key file's passwd from " << optarg; + return -1; + } + 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_SYSLOG)) { diff --git a/src/shrpx_config.h b/src/shrpx_config.h index 275afe2ef29d95242c98dbdf0f78be95afe96765..4301d25a1b1d4b17fede5f1409472bc4267cbb07 100644 --- a/src/shrpx_config.h +++ b/src/shrpx_config.h @@ -36,6 +36,7 @@ namespace shrpx { 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_BACKEND[]; @@ -81,6 +82,7 @@ struct Config { char *host; uint16_t port; char *private_key_file; + char *private_key_passwd; char *cert_file; bool verify_client; const char *server_name; @@ -136,6 +138,9 @@ int parse_config(const char *opt, const char *optarg); // -1. int load_config(const char *filename); +// Read passwd from |filename| +std::string read_passwd_from_file(const char *filename); + // Copies NULL-terminated string |val| to |*destp|. If |*destp| is not // NULL, it is freed before copying. void set_config_str(char **destp, const char *val); diff --git a/src/shrpx_ssl.cc b/src/shrpx_ssl.cc index d556d6d11098923f49085732063b76e16c2e342b..3bdae05ecbb11d3162070b5623d08379cf11f6b9 100644 --- a/src/shrpx_ssl.cc +++ b/src/shrpx_ssl.cc @@ -91,6 +91,22 @@ void set_npn_prefs(unsigned char *out, const char **protos, size_t len) } } // namespace + +static int ssl_pem_passwd_cb(char *buf, int size, int rwflag, void *user_data) +{ + Config *config = (Config *)user_data; + int len = (int)strlen(config->private_key_passwd); + if (size < len + 1) { + LOG(ERROR) << "ssl_pem_passwd_cb: buf is too small " << size; + return 0; + } + + strncpy(buf, config->private_key_passwd, len); + buf[len] = '\0'; + return len; +} + + SSL_CTX* create_ssl_context() { SSL_CTX *ssl_ctx; @@ -118,6 +134,10 @@ SSL_CTX* create_ssl_context() 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); + if (get_config()->private_key_passwd) { + SSL_CTX_set_default_passwd_cb(ssl_ctx, ssl_pem_passwd_cb); + SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, (void *)get_config()); + } if(SSL_CTX_use_PrivateKey_file(ssl_ctx, get_config()->private_key_file, SSL_FILETYPE_PEM) != 1) {