Forum: NGINX The patch of Nginx SSL: PEM pass phrase problem

2974d09ac2541e892966b762aad84943?d=identicon&s=25 James_Lee (Guest)
on 2011-09-02 08:03
(Received via mailing list)
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#...

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:
2974d09ac2541e892966b762aad84943?d=identicon&s=25 chirho (Guest)
on 2012-07-30 03:53
(Received via mailing list)
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:
http://forum.nginx.org/read.php?2,214641,229085#msg-229085
2974d09ac2541e892966b762aad84943?d=identicon&s=25 James_Lee (Guest)
on 2012-07-31 16:31
(Received via mailing list)
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:",
5) == 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:
http://forum.nginx.org/read.php?2,214641,229145#msg-229145
2974d09ac2541e892966b762aad84943?d=identicon&s=25 chirho (Guest)
on 2012-08-01 01:12
(Received via mailing list)
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:
http://forum.nginx.org/read.php?2,214641,229161#msg-229161
B2292bc358490b3ae2a4a9caf36e2120?d=identicon&s=25 "姚伟斌" <nbubingo@gmail.com> (Guest)
on 2012-08-01 06:27
(Received via mailing list)
Good point. Tengine has similar feature:
http://tengine.taobao.org/document/http_ssl.html

Maybe Nginx should consider this patch.

2012/8/1 chirho <nginx-forum@nginx.us>:
2974d09ac2541e892966b762aad84943?d=identicon&s=25 pbrunnen (Guest)
on 2014-05-15 22:00
(Received via mailing list)
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:
http://forum.nginx.org/read.php?2,214641,250131#msg-250131
A8108a0961c6087c43cda32c8616dcba?d=identicon&s=25 Maxim Dounin (Guest)
on 2014-05-16 00:02
(Received via mailing list)
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-Apri...

--
Maxim Dounin
http://nginx.org/
Please log in before posting. Registration is free and takes only a minute.
Existing account

NEW: Do you have a Google/GoogleMail, Yahoo or Facebook account? No registration required!
Log in with Google account | Log in with Yahoo account | Log in with Facebook account
No account? Register here.