[shrpx] read private key's passwd from a file

This avoids the need to provide the password for your
private key interactively.

It can be used via --private-key-passwd-file or private-key-passwd-file
in the given config file. The first line in the file
(without \n) will be treated as the passwd. There isn't
any validation and all lines after the first one (if any)
are ignored.

The security model behind this is a bit simplistic so I
am open to better ideas. Basically your password file
should be root:root (700) and you *should* drop root
and run as an unprivileged user.

If the file exists and a line can be read then a callback
will be set for the SSL ctxt and it'll feed the passwd
when the private key is read (if password is needed).

If the file exists with the wrong permisions it'll be
logged and ignored.
This commit is contained in:
Raul Gutierrez Segales 2012-12-02 22:33:04 -08:00
parent f97110f092
commit cbf8ccf7d1
4 changed files with 83 additions and 0 deletions

View File

@ -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;
}

View File

@ -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)) {

View File

@ -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);

View File

@ -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) {