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, &params, 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

Reply via email to