On Fri, 2015-06-19 at 15:49 +0200, Nikos Mavrogiannopoulos wrote: > Hello, > The attached patch allows loading PKCS #11 URLs in the > ssl_certificate_key.
The attached patch set enhances that support by allowing PKCS #11 URLs in the certificate field as well. As it is now nginx can work with arbitrary hardware security modules using libp11 and engine_pkcs11 from their git repositories. That allows both certificate and key directives to be used with PKCS #11 objects as: ssl_certificate "pkcs11:model=..." ssl_certificate_key "pkcs11:model=" (that simplifies loading of certificates which are stored inside the module). regards, Nikos
# HG changeset patch # User Nikos Mavrogiannopoulos <n...@redhat.com> # Date 1434720898 -7200 # Fri Jun 19 15:34:58 2015 +0200 # Branch pkcs11 # Node ID 0870b441d666234edd95578ae740f24554179b68 # Parent 311d232ad803c8580c498763710005b91d30b748 Allow loading a PKCS #11 URL (RFC7512) from ssl_certificate_key That requires the URL to be quoted because of the ';' chars. Such URLs couldn't be loaded via the current engine interface. That approach also automatically loads the pkcs11 module, and thus requires no changes in openssl global configuration files. diff -r 311d232ad803 -r 0870b441d666 src/event/ngx_event_openssl.c --- a/src/event/ngx_event_openssl.c Tue Jun 16 00:43:00 2015 +0300 +++ b/src/event/ngx_event_openssl.c Fri Jun 19 15:34:58 2015 +0200 @@ -439,6 +439,46 @@ return NGX_OK; + } else if (ngx_strncmp(key->data, "pkcs11:", sizeof("pkcs11:") - 1) == 0) { + ENGINE *engine; + EVP_PKEY *pkey; + + engine = ENGINE_by_id("pkcs11"); + if (engine == NULL) { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "ENGINE_by_id(pkcs11) failed"); + return NGX_ERROR; + } + + if (ENGINE_init(engine) == 0) { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "ENGINE_init(pkcs11) failed"); + ENGINE_free(engine); + return NGX_ERROR; + } + + pkey = ENGINE_load_private_key(engine, (char *) key->data, 0, 0); + + if (pkey == NULL) { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "ENGINE_load_private_key(\"%s\") failed", key->data); + ENGINE_free(engine); + return NGX_ERROR; + } + + ENGINE_free(engine); + + if (SSL_CTX_use_PrivateKey(ssl->ctx, pkey) == 0) { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "SSL_CTX_use_PrivateKey(\"%s\") failed", key->data); + EVP_PKEY_free(pkey); + return NGX_ERROR; + } + + EVP_PKEY_free(pkey); + + return NGX_OK; + } else { #else ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, # HG changeset patch # User Nikos Mavrogiannopoulos <n...@redhat.com> # Date 1436430891 -7200 # Thu Jul 09 10:34:51 2015 +0200 # Branch pkcs11 # Node ID 8ef649e2f701c3ae345d2dacebd3f9d1897f90f2 # Parent 0870b441d666234edd95578ae740f24554179b68 Allow loading a PKCS #11 URL (RFC7512) from ssl_certificate diff -r 0870b441d666 -r 8ef649e2f701 src/event/ngx_event_openssl.c --- a/src/event/ngx_event_openssl.c Fri Jun 19 15:34:58 2015 +0200 +++ b/src/event/ngx_event_openssl.c Thu Jul 09 10:34:51 2015 +0200 @@ -296,47 +296,109 @@ return NGX_OK; } - -ngx_int_t -ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert, - ngx_str_t *key, ngx_array_t *passwords) +static +int load_cert(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert) { BIO *bio; X509 *x509; u_long n; - ngx_str_t *pwd; - ngx_uint_t tries; - - if (ngx_conf_full_name(cf->cycle, cert, 1) != NGX_OK) { - return NGX_ERROR; + +#ifndef OPENSSL_NO_ENGINE + /* Load file from PKCS #11 module when available. + */ + + if (strncmp((char*)cert->data, "pkcs11:", 7) == 0) { + ENGINE *engine; + struct { + const char *cert_id; + X509 *cert; + } params; + params.cert_id = (char*)cert->data; + params.cert = NULL; + + engine = ENGINE_by_id("pkcs11"); + if (engine == NULL) { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "ENGINE_by_id(pkcs11) failed"); + return NGX_ERROR; + } + + if (ENGINE_init(engine) == 0) { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "ENGINE_init(pkcs11) failed"); + ENGINE_free(engine); + return NGX_ERROR; + } + + if (!ENGINE_ctrl_cmd(engine, "LOAD_CERT_CTRL", + 0, ¶ms, NULL, 1)) { + unsigned long err = ERR_get_error(); + + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "ENGINE_ctrl_cmd LOAD_CERT_CTRL (\"%s\") failed: %s", (char*)cert->data, + ERR_error_string(err, NULL)); + ENGINE_finish(engine); + return NGX_ERROR; + } + + ENGINE_finish(engine); + if (!params.cert) { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "ENGINE_ctrl_cmd LOAD_CERT_CTRL did not set cert (\"%s\")", (char*)cert->data); + return NGX_ERROR; + } + + x509 = params.cert; + if (SSL_CTX_use_certificate(ssl->ctx, x509) == 0) { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "SSL_CTX_use_certificate(\"%s\") failed", (char*)cert->data); + X509_free(x509); + return NGX_ERROR; + } + + if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_certificate_index, x509) + == 0) + { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "SSL_CTX_set_ex_data() failed"); + X509_free(x509); + return NGX_ERROR; + } + + X509_free(x509); + + return NGX_OK; } - - /* +#endif + /* Load plain file. + * * we can't use SSL_CTX_use_certificate_chain_file() as it doesn't * allow to access certificate later from SSL_CTX, so we reimplement * it here */ + if (ngx_conf_full_name(cf->cycle, cert, 1) != NGX_OK) { + return NGX_ERROR; + } bio = BIO_new_file((char *) cert->data, "r"); if (bio == NULL) { ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, - "BIO_new_file(\"%s\") failed", cert->data); + "BIO_new_file(\"%s\") failed", (char*)cert->data); return NGX_ERROR; } x509 = PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL); if (x509 == NULL) { ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, - "PEM_read_bio_X509_AUX(\"%s\") failed", cert->data); + "PEM_read_bio_X509_AUX(\"%s\") failed", (char*)cert->data); BIO_free(bio); return NGX_ERROR; } if (SSL_CTX_use_certificate(ssl->ctx, x509) == 0) { ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, - "SSL_CTX_use_certificate(\"%s\") failed", cert->data); + "SSL_CTX_use_certificate(\"%s\") failed", (char*)cert->data); X509_free(x509); - BIO_free(bio); return NGX_ERROR; } @@ -346,7 +408,6 @@ ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "SSL_CTX_set_ex_data() failed"); X509_free(x509); - BIO_free(bio); return NGX_ERROR; } @@ -371,7 +432,7 @@ /* some real error */ ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, - "PEM_read_bio_X509(\"%s\") failed", cert->data); + "PEM_read_bio_X509(\"%s\") failed", (char*)cert->data); BIO_free(bio); return NGX_ERROR; } @@ -379,7 +440,7 @@ if (SSL_CTX_add_extra_chain_cert(ssl->ctx, x509) == 0) { ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "SSL_CTX_add_extra_chain_cert(\"%s\") failed", - cert->data); + (char*)cert->data); X509_free(x509); BIO_free(bio); return NGX_ERROR; @@ -388,8 +449,23 @@ BIO_free(bio); + return NGX_OK; +} + +ngx_int_t +ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert, + ngx_str_t *key, ngx_array_t *passwords) +{ + ngx_str_t *pwd; + ngx_uint_t tries; + + if (load_cert(cf, ssl, cert) != NGX_OK) { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "Load cert (\"%s\") failed", cert->data); + return NGX_ERROR; + } + if (ngx_strncmp(key->data, "engine:", sizeof("engine:") - 1) == 0) { - #ifndef OPENSSL_NO_ENGINE u_char *p, *last; @@ -440,8 +516,8 @@ return NGX_OK; } else if (ngx_strncmp(key->data, "pkcs11:", sizeof("pkcs11:") - 1) == 0) { + EVP_PKEY *pkey; ENGINE *engine; - EVP_PKEY *pkey; engine = ENGINE_by_id("pkcs11"); if (engine == NULL) { @@ -462,10 +538,11 @@ if (pkey == NULL) { ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "ENGINE_load_private_key(\"%s\") failed", key->data); - ENGINE_free(engine); + ENGINE_finish(engine); return NGX_ERROR; } + /* we clear the reference but keep the engine running */ ENGINE_free(engine); if (SSL_CTX_use_PrivateKey(ssl->ctx, pkey) == 0) {
_______________________________________________ nginx-devel mailing list nginx-devel@nginx.org http://mailman.nginx.org/mailman/listinfo/nginx-devel