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

Maxim Dounin mdounin at mdounin.ru
Tue Jul 22 14:52:52 UTC 2014


Hello!

On Tue, Jul 22, 2014 at 03:16:35PM +0400, Dmitrii Pichulin wrote:

> # HG changeset patch
> # User Dmitrii Pichulin <pdn at cryptopro.ru>
> # Date 1406021876 -14400
> #      Tue Jul 22 13:37:56 2014 +0400
> # Node ID 638389b21e0e1522ed8b8205012f5af562dc50c7
> # Parent  63d7d69d0fe48e030ff9fc520c7036dbd1ebc13f
> allow to use engine keyform for server private key

The patch is built against an old version, and there are 
conflicting changes in nginx 1.7.3.

> 
> diff -r 63d7d69d0fe4 -r 638389b21e0e src/event/ngx_event_openssl.c
> --- a/src/event/ngx_event_openssl.c	Fri Jun 20 12:55:41 2014 +0400
> +++ b/src/event/ngx_event_openssl.c	Tue Jul 22 13:37:56 2014 +0400
> @@ -257,11 +257,31 @@
>  
>  ngx_int_t
>  ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert,
> -    ngx_str_t *key)
> +    ngx_str_t *key, ngx_str_t *keyform, ngx_str_t *engine)
>  {
> -    BIO     *bio;
> -    X509    *x509;
> -    u_long   n;
> +    BIO        *bio;
> +    X509       *x509;
> +    u_long      n;
> +    ngx_uint_t  ssl_use_engine_keyform = 0;
> +
> +    if (keyform->len) {
> +
> +        if (ngx_strcmp(keyform->data, "ENGINE") == 0) {
> +            ssl_use_engine_keyform = 1;
> +
> +        } else if (ngx_strcmp(keyform->data, "PEM") != 0) {
> +            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
> +                               "invalid parameter: %V", keyform);
> +            return NGX_ERROR;
> +        }
> +    }
> +
> +    if (ssl_use_engine_keyform && engine->len == 0) {
> +            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
> +                             "no \"ssl_certificate_engine\" is defined "
> +                             "while \"ssl_certificate_keyform\" is \"ENGINE\"");
> +            return NGX_ERROR;
> +    }
>  
>      if (ngx_conf_full_name(cf->cycle, cert, 1) != NGX_OK) {
>          return NGX_ERROR;

As previously suggested, it should be "engine=" parameter of the 
ssl_certificate_key directive and/or some specific path prefix to 
load a key from an engine (like "engine:<foo>:<keyid>" instead of 
a file name), see the thread here:

http://mailman.nginx.org/pipermail/nginx-devel/2014-March/005114.html

There is no need to introduce such a number of directives - there 
is no real need for this, and it's confusing for users.

> @@ -344,17 +364,51 @@
>  
>      BIO_free(bio);
>  
> -    if (ngx_conf_full_name(cf->cycle, key, 1) != NGX_OK) {
> -        return NGX_ERROR;
> -    }
> -
> -    if (SSL_CTX_use_PrivateKey_file(ssl->ctx, (char *) key->data,
> -                                    SSL_FILETYPE_PEM)
> -        == 0)
> -    {
> -        ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
> -                      "SSL_CTX_use_PrivateKey_file(\"%s\") failed", key->data);
> -        return NGX_ERROR;
> +    if (ssl_use_engine_keyform) {
> +        EVP_PKEY   *pkey;
> +        ENGINE     *e;
> +

Please define all variables at function start.

> +        e = ENGINE_by_id((const char *) engine->data);

There is no need to use "const" in the cast.

> +
> +        if (e == NULL) {
> +            ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
> +                          "ENGINE_by_id(\"%s\") failed", engine->data);
> +            return NGX_ERROR;
> +        }
> +
> +        pkey = ENGINE_load_private_key(e, (const char *)key->data, 0, 0);

Style: there should be a space between "(const char *)" and 
"key->data".  (Also, there is no need to use "const" in the cast.)

> +
> +        ENGINE_free(e);
> +
> +        if (!pkey) {
> +            ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
> +                          "ENGINE_load_private_key(\"%s\") failed", key->data);
> +            return NGX_ERROR;
> +        }

Error stack may be changed by the ENGINE_free().

Additinally, it looks like ENGINE_free() can return errors, and it 
may be a good idea to check them.

> +
> +        if (SSL_CTX_use_PrivateKey(ssl->ctx, pkey) == 0) {
> +            ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
> +                       "SSL_CTX_use_PrivateKey_file(\"%s\") failed", key->data);

Style: it may be a good idea to break the line into two here.

> +            EVP_PKEY_free(pkey);
> +            return NGX_ERROR;
> +        }
> +
> +        EVP_PKEY_free(pkey);
> +
> +    } else {

It should be better to just return here and hence avoid 
indentation changes on the default code path.

> +
> +        if (ngx_conf_full_name(cf->cycle, key, 1) != NGX_OK) {
> +            return NGX_ERROR;
> +        }
> +
> +        if (SSL_CTX_use_PrivateKey_file(ssl->ctx, 
> +                                        (char *) key->data, SSL_FILETYPE_PEM)
> +            == 0)
> +        {
> +            ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
> +                       "SSL_CTX_use_PrivateKey_file(\"%s\") failed", key->data);
> +            return NGX_ERROR;
> +        }
>      }
>  
>      return NGX_OK;

[...]

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



More information about the nginx-devel mailing list