[PATCH] allow to use engine keyform for server private key

Maxim Dounin mdounin at mdounin.ru
Thu Jul 31 13:49:18 UTC 2014


Hello!

On Wed, Jul 30, 2014 at 07:29:10PM +0400, Dmitrii Pichulin wrote:

> # HG changeset patch
> # User Dmitrii Pichulin
> # Date 1406733892 -14400
> #      Wed Jul 30 19:24:52 2014 +0400
> # Node ID a4c89ae85f45153760637058a75f4338b3974219
> # Parent  4d092aa2f4637ce50284d2accd99a8e91aae2b4c
> allow to use engine keyform for server private key
> 
> diff -r 4d092aa2f463 -r a4c89ae85f45 src/event/ngx_event_openssl.c
> --- a/src/event/ngx_event_openssl.c	Mon Jul 28 12:27:57 2014 -0700
> +++ b/src/event/ngx_event_openssl.c	Wed Jul 30 19:24:52 2014 +0400
> @@ -17,6 +17,11 @@
>      ngx_uint_t  engine;   /* unsigned  engine:1; */
>  } ngx_openssl_conf_t;
>  
> +typedef struct {
> +    const void *password;
> +    const char *prompt_info;
> +} PW_CB_DATA;
> +
>  
>  static int ngx_ssl_password_callback(char *buf, int size, int rwflag,
>      void *userdata);
> @@ -265,11 +270,16 @@
>  ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert,
>      ngx_str_t *key, ngx_array_t *passwords)
>  {
> +    char        *p, *last;
>      BIO         *bio;
>      X509        *x509;
> +    ENGINE      *engine;
> +    EVP_PKEY    *private_key;
> +    PW_CB_DATA   pwd_data;
>      u_long       n;
>      ngx_str_t   *pwd;
>      ngx_uint_t   tries;
> +    u_char       pwd_buf[NGX_SSL_PASSWORD_BUFFER_SIZE];
>  
>      if (ngx_conf_full_name(cf->cycle, cert, 1) != NGX_OK) {
>          return NGX_ERROR;
> @@ -352,6 +362,75 @@
>  
>      BIO_free(bio);
>  
> +    if (ngx_strncmp(key->data, "engine:", sizeof("engine:") - 1) == 0) {
> +
> +        p = (char *) key->data + sizeof("engine:") - 1;
> +        last = ngx_strchr(p, ':');
> +
> +        if (last == NULL) {
> +            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid syntax: %V", key);
> +            return NGX_ERROR;
> +        }
> +
> +        p[last - p] = '\0';
> +
> +        engine = ENGINE_by_id(p);

After Piotr's patch (http://hg.nginx.org/nginx/rev/4d092aa2f463) 
we are able to work with OpenSSL compiled with OPENSSL_NO_ENGINE.
Breaking this wouldn't be a good idea.

> +
> +        if (engine == NULL) {
> +            ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
> +                          "ENGINE_by_id(\"%s\") failed", p);
> +            return NGX_ERROR;
> +        }
> +
> +        p[last - p] = ':';
> +
> +        if (passwords) {
> +            pwd = passwords->elts;
> +
> +            ngx_cpystrn(pwd_buf, pwd->data, pwd->len + 1);
> +
> +            pwd_data.password = pwd_buf;
> +        } else {
> +            pwd_data.password = NULL;
> +        }
> +        pwd_data.prompt_info = NULL;
> +
> +        last++;
> +
> +        private_key = ENGINE_load_private_key(engine, last, 0,
> +                                              (void *) &pwd_data);

I don't see how it's expected to work.  You only pass private data 
for UI callbacks, but not callbacks itself.

Anyway, proper implementation of passing key passwords into an engine 
seems to be rather big, and as per my reading of the code under 
crypto/engine won't work with most of the engines anyway.  It 
might be better idea to don't try to do this for now.

> +
> +        ngx_memzero(pwd_buf, NGX_SSL_PASSWORD_BUFFER_SIZE);
> +
> +        if (private_key == NULL) {
> +            ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
> +                          "ENGINE_load_private_key(\"%s\") failed", last);
> +
> +            if (ENGINE_free(engine) == 0) {
> +                ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
> +                              "ENGINE_free() failed");
> +            }
> +            return NGX_ERROR;
> +        }

The above referenced commit shows that we don't check 
ENGINE_free() return codes, so probably we shouldn't try this here as 
well.

> +
> +        if (ENGINE_free(engine) == 0) {
> +            ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "ENGINE_free() failed");
> +            EVP_PKEY_free(private_key);
> +            return NGX_ERROR;
> +        }
> +
> +        if (SSL_CTX_use_PrivateKey(ssl->ctx, private_key) == 0) {
> +            ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
> +                          "SSL_CTX_use_PrivateKey(\"%s\") failed", last);
> +            EVP_PKEY_free(private_key);
> +            return NGX_ERROR;
> +        }
> +
> +        EVP_PKEY_free(private_key);
> +
> +        return NGX_OK;
> +    }
> +
>      if (ngx_conf_full_name(cf->cycle, key, 1) != NGX_OK) {
>          return NGX_ERROR;
>      }
> 
> _______________________________________________
> nginx-devel mailing list
> nginx-devel at nginx.org
> http://mailman.nginx.org/mailman/listinfo/nginx-devel

-- 
Maxim Dounin
http://nginx.org/



More information about the nginx-devel mailing list