The patch of Nginx SSL: PEM pass phrase problem

Hi,

If we configured SSL in Nginx and the Private Key files are encrypted,
then the following dialog occurs at Nginx startup time:
Enter PEM pass phrase:

It maybe difficulty for management. Sometimes it’s needed to avoid the
interactive dialogue at startup time.
So I develop the patch for Nginx ssl module. Wish it helpful!

Directive: ssl_pass_phrase_dialog

Description: Type of pass phrase dialog for encrypted private keys
Syntax: ssl_pass_phrase_dialog type
Default: ssl_pass_phrase_dialog builtin
Context: http, server

Usage:

When Nginx starts up it has to read the various Certificate (see
ssl_certificate) and Private Key (see ssl_certificate_key) files of the
SSL-enabled virtual servers. Because for security reasons the Private
Key files are usually encrypted, ngx_ssl module needs to query the
administrator for a Pass Phrase in order to decrypt those files. This
query can be done in two ways which can be configured by type:

  • builtin

    This is the default where an interactive terminal dialog occurs at
    startup time. Here the administrator has to manually enter the Pass
    Phrase for each encrypted Private Key file.

  • exec:/path/to/program

    Here an external program is configured which is called at startup
    for each encrypted Private Key file.

Example:

(1) ssl_pass_phrase_dialog builtin;
The “Enter PEM pass phrase:” will occurs at the Nginx startup time.

(2) ssl_pass_phrase_dialog “exec:/home/ssl_files/ssl_pass_phrase.sh”;
The code of ssl_pass_phrase.sh:
#!/bin/sh
echo “password”

The relevant configuration in Apache is:
http://httpd.apache.org/docs/2.0/mod/mod_ssl.html#sslpassphrasedialog

If more information is needed, please refer to the Nginx HttpSslModule:
http://wiki.nginx.org/HttpSslModule

Patch:

This patch has been tested in nginx-0.8.54.

The download url is :
http://www.cx.com/dl/?sn=f3c7b79133b7

Author:

Hi, there.

it was glad to me at this post, because I have a same problem at now.
but, DL link was broken.

How/Where can I see the patch of this issue?

If anyone have the patch, can u send me email?

thank you.

Posted at Nginx Forum:

I’am very glad that this patch is useful for you.
The below is the patch or the diff. It’s based on the nginx 0.8.54 or
nginx 0.8.55.
Perhaps it also works for other version. Maybe you need to merge it by
hand.

Index: src/http/modules/ngx_http_ssl_module.c

— src/http/modules/ngx_http_ssl_module.c (revision 347)
+++ src/http/modules/ngx_http_ssl_module.c (revision 348)
@@ -14,6 +14,7 @@

#define NGX_DEFAULT_CIPHERS “HIGH:!ADH:!MD5”
+#define PASS_PHRASE_ARG_LEN 255

static ngx_int_t ngx_http_ssl_static_variable(ngx_http_request_t *r,
@@ -31,6 +32,11 @@
static char *ngx_http_ssl_session_cache(ngx_conf_t *cf, ngx_command_t
*cmd,
void *conf);

+static int ngx_enhanced_system(char* cmdstring, char* buf, int len);
+static int ngx_http_ssl_pass_phase_callback(char *buf, int bufsize,

  • int verify, void *srv);
    +static char *ngx_conf_set_pass_phrase_dialog(ngx_conf_t *cf,
  • ngx_command_t *cmd, void *conf);

static ngx_conf_bitmask_t ngx_http_ssl_protocols[] = {
{ ngx_string(“SSLv2”), NGX_SSL_SSLv2 },
@@ -141,6 +147,13 @@
offsetof(ngx_http_ssl_srv_conf_t, crl),
NULL },

  • { ngx_string(“ssl_pass_phrase_dialog”),
  •  NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
    
  •  ngx_conf_set_pass_phrase_dialog,
    
  •  NGX_HTTP_SRV_CONF_OFFSET,
    
  •  offsetof(ngx_http_ssl_srv_conf_t, pass_phrase_conf),
    
  •  NULL },
    
  •  ngx_null_command
    

};

@@ -213,6 +226,124 @@
static ngx_str_t ngx_http_ssl_sess_id_ctx = ngx_string(“HTTP”);

+static char *
+ngx_conf_set_pass_phrase_dialog(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf)
+{

  • char *p = conf;
  • ngx_str_t *field, *value;
  • int len;
  • field = (ngx_str_t *) (p + cmd->offset);
  • if (field->data) {
  •    return "is duplicate";
    
  • }
  • value = cf->args->elts;
  • *field = value[1];
  • if (field->len == 0) {
  •    return NGX_CONF_OK;
    
  • } else if (field->len > PASS_PHRASE_ARG_LEN) {
  •    len = PASS_PHRASE_ARG_LEN;
    
  •    ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
    
  •        "The length of ssl_pass_phrase_dialog argument is more than
    

%d", len);
+

  •    return NGX_CONF_ERROR;
    
  • }
  • return NGX_CONF_OK;
    +}

+static int
+ngx_http_ssl_pass_phase_callback(char *buf, int bufsize, int verify,
void *srv)
+{

  • ngx_str_t pass_phase_file;
  • int ret;
  • char cmdline[PASS_PHRASE_ARG_LEN + 1] = {0};
  • ngx_http_ssl_srv_conf_t * conf = srv;
  • /* get the executable file path */
  • pass_phase_file.data = conf->pass_phrase_conf.data + 5;
  • pass_phase_file.len = conf->pass_phrase_conf.len - 5;
  • ngx_memcpy(cmdline, pass_phase_file.data, pass_phase_file.len);
  • cmdline[pass_phase_file.len] = ‘\0’;
  • ret = ngx_enhanced_system(cmdline, buf, bufsize);
  • if (ret != 0) {
  •    return -1;
    
  • }
  • /* To support echo command in Linux, Unix shell */
  • if (buf[strlen(buf) - 1] == ‘\n’) {
  •    buf[strlen(buf) - 1] = '\0';
    
  • }
  • return strlen(buf);
    +}

+/**
+* ngx_enhanced_system()
+*
+* @param[in] cmdstring : External command(executable or shell)
+* @param[out] buf : The buffer to store the result of the external
command.
+* @param[in] len : The length of the buffer.
+*
+* @return 0: success -1: fail
+/
+static int
+ngx_enhanced_system(char
cmdstring, char* buf, int len)
+{

  • int fd[2];
  • pid_t pid;
  • int n, count;
  • memset(buf, 0, len);
  • if (pipe(fd) < 0) {
  •    return -1;
    
  • }
  • if ((pid = fork()) < 0) {
  •    return -1;
    
  • } else if (pid > 0) { /* parent process */
  •    close(fd[1]);        /* close write end */
    
  •    count = 0;
    
  •    while ((n = read(fd[0], buf + count, len)) > 0
    
  •    && count > len) {
    
  •        count += n;
    
  •    }
    
  •    close(fd[0]);
    
  •    if (waitpid(pid, NULL, 0) != pid) {
    
  •        return -1;
    
  •    }
    
  • } else { /* child process */
  •    close(fd[0]);     /* close read end */
    
  •    if (fd[1] != STDOUT_FILENO) {
    
  •        if (dup2(fd[1], STDOUT_FILENO) != STDOUT_FILENO) {
    
  •            return -1;
    
  •        }
    
  •        close(fd[1]);
    
  •    }
    
  •    if (execl("/bin/sh", "sh", "-c", cmdstring, (char*)0) == -1) {
    
  •        return -1;
    
  •    }
    
  • }
  • return 0;
    +}

static ngx_int_t
ngx_http_ssl_static_variable(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
@@ -316,6 +447,8 @@
* sscf->crl = { 0, NULL };
* sscf->ciphers = { 0, NULL };
* sscf->shm_zone = NULL;

  • *
    
  • *     sscf->pass_phrase_conf = { 0, NULL };
    */
    

    sscf->enable = NGX_CONF_UNSET;
    @@ -362,7 +495,9 @@

    ngx_conf_merge_str_value(conf->ciphers, prev->ciphers,
    NGX_DEFAULT_CIPHERS);

  • ngx_conf_merge_str_value(conf->pass_phrase_conf,
    prev->pass_phrase_conf, “builtin”);

  • conf->ssl.log = cf->log;

    if (conf->enable) {
    @@ -401,6 +536,18 @@
    return NGX_CONF_ERROR;
    }

  • if (ngx_strncasecmp(conf->pass_phrase_conf.data, (u_char*)“exec:”,

  1. == 0) {
  •    SSL_CTX_set_default_passwd_cb(conf->ssl.ctx,
    

ngx_http_ssl_pass_phase_callback);
+

  •    SSL_CTX_set_default_passwd_cb_userdata(conf->ssl.ctx, (void
    

*)conf);
+

  • } else if (ngx_strncasecmp(conf->pass_phrase_conf.data,
    (u_char*)“builtin”, 7) != 0) {
  •    ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
    
  •        "The arg of ssl_pass_phrase_dialog directive is incorrect:
    

builtin | exec:path");

  •    return NGX_CONF_ERROR;
    
  • }

#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME

 if (SSL_CTX_set_tlsext_servername_callback(conf->ssl.ctx,

Index: src/http/modules/ngx_http_ssl_module.h

— src/http/modules/ngx_http_ssl_module.h (revision 347)
+++ src/http/modules/ngx_http_ssl_module.h (revision 348)
@@ -41,6 +41,8 @@

 u_char                         *file;
 ngx_uint_t                      line;
  • ngx_str_t pass_phrase_conf;
    } ngx_http_ssl_srv_conf_t;

Posted at Nginx Forum:

thank you for rapid answer.

actually, i use v1.2.0 of nginx version and i’ll try to patch it.
after patching and testing, i’ll post the results.

thank you again for this patch.

best regards.

Posted at Nginx Forum:

Has this patch still not been considered for production?? This is an
important component for key security…
How can we vote on such requests?

Thanks! -Cheers, Peter.

Posted at Nginx Forum:

Good point. Tengine has similar feature:

Maybe Nginx should consider this patch.

2012/8/1 chirho [email protected]:

Hello!

On Thu, May 15, 2014 at 03:59:54PM -0400, pbrunnen wrote:

Has this patch still not been considered for production?? This is an
important component for key security…
How can we vote on such requests?

http://mailman.nginx.org/pipermail/nginx/2014-April/043281.html


Maxim D.
http://nginx.org/