[openssl-dev] [RFC v2 1/2] engine: add new bio based method for loading engine keys

James Bottomley James.Bottomley at HansenPartnership.com
Wed Nov 30 15:26:22 UTC 2016


Some engines have a PEM format for their keys, so add a mechanism
whereby these keys can be read in to EVP_PKEY structures backed by the
engine methods.  The expectation is that each engine that wants to use
this will define its own unique guard tags for the PEM file.

Signed-off-by: James Bottomley <jejb at linux.vnet.ibm.com>
---
 crypto/engine/eng_int.h  |  1 +
 crypto/engine/eng_pkey.c | 38 ++++++++++++++++++++++++++++++++++++++
 crypto/engine/engine.h   | 17 +++++++++++++++++
 3 files changed, 56 insertions(+)

diff --git a/crypto/engine/eng_int.h b/crypto/engine/eng_int.h
index 46f163b..1d182c8 100644
--- a/crypto/engine/eng_int.h
+++ b/crypto/engine/eng_int.h
@@ -197,6 +197,7 @@ struct engine_st {
     ENGINE_CTRL_FUNC_PTR ctrl;
     ENGINE_LOAD_KEY_PTR load_privkey;
     ENGINE_LOAD_KEY_PTR load_pubkey;
+    ENGINE_LOAD_KEY_BIO_PTR load_privkey_bio;
     ENGINE_SSL_CLIENT_CERT_PTR load_ssl_client_cert;
     const ENGINE_CMD_DEFN *cmd_defns;
     int flags;
diff --git a/crypto/engine/eng_pkey.c b/crypto/engine/eng_pkey.c
index 23580d9..0eb7d6e 100644
--- a/crypto/engine/eng_pkey.c
+++ b/crypto/engine/eng_pkey.c
@@ -64,6 +64,13 @@ int ENGINE_set_load_privkey_function(ENGINE *e,
     return 1;
 }
 
+int ENGINE_set_load_privkey_bio_function(ENGINE *e,
+					 ENGINE_LOAD_KEY_BIO_PTR load_f)
+{
+    e->load_privkey_bio = load_f;
+    return 1;
+}
+
 int ENGINE_set_load_pubkey_function(ENGINE *e, ENGINE_LOAD_KEY_PTR loadpub_f)
 {
     e->load_pubkey = loadpub_f;
@@ -88,6 +95,11 @@ ENGINE_LOAD_KEY_PTR ENGINE_get_load_pubkey_function(const ENGINE *e)
     return e->load_pubkey;
 }
 
+ENGINE_LOAD_KEY_BIO_PTR ENGINE_get_load_privkey_bio_function(const ENGINE *e)
+{
+    return e->load_privkey_bio;
+}
+
 ENGINE_SSL_CLIENT_CERT_PTR ENGINE_get_ssl_client_cert_function(const ENGINE
                                                                *e)
 {
@@ -184,3 +196,29 @@ int ENGINE_load_ssl_client_cert(ENGINE *e, SSL *s,
     return e->load_ssl_client_cert(e, s, ca_dn, pcert, ppkey, pother,
                                    ui_method, callback_data);
 }
+
+int ENGINE_find_engine_load_key(ENGINE **e, EVP_PKEY **pkey, BIO *bio,
+                                pem_password_cb *cb, void *cb_data)
+{
+    ENGINE *ep;
+    int ret = 0;
+
+    for (ep = ENGINE_get_first(); ep != NULL; ep = ENGINE_get_next(ep)) {
+        if (!ep->load_privkey_bio)
+            continue;
+        if (ep->load_privkey_bio(ep, pkey, bio, cb, cb_data) == 1) {
+            ret = 1;
+            break;
+        }
+
+	/* reset the bio and clear any error */
+	(void)BIO_reset(bio);
+	ERR_clear_error();
+    }
+    if (e)
+        *e = ep;
+    else if (ep)
+        ENGINE_free(ep);
+
+    return ret;
+}
diff --git a/crypto/engine/engine.h b/crypto/engine/engine.h
index bd7b591..022be41 100644
--- a/crypto/engine/engine.h
+++ b/crypto/engine/engine.h
@@ -97,6 +97,7 @@
 # include <openssl/symhacks.h>
 
 # include <openssl/x509.h>
+# include <openssl/pem.h>
 
 #ifdef  __cplusplus
 extern "C" {
@@ -338,6 +339,11 @@ typedef int (*ENGINE_CTRL_FUNC_PTR) (ENGINE *, int, long, void *,
 typedef EVP_PKEY *(*ENGINE_LOAD_KEY_PTR)(ENGINE *, const char *,
                                          UI_METHOD *ui_method,
                                          void *callback_data);
+
+/* Load key from bio if engine recognises the pem guards */
+typedef int (*ENGINE_LOAD_KEY_BIO_PTR)(ENGINE *, EVP_PKEY **,  BIO *,
+				       pem_password_cb *pwd_callback,
+				       void *callback_data);
 typedef int (*ENGINE_SSL_CLIENT_CERT_PTR) (ENGINE *, SSL *ssl,
                                            STACK_OF(X509_NAME) *ca_dn,
                                            X509 **pcert, EVP_PKEY **pkey,
@@ -565,6 +571,8 @@ int ENGINE_set_finish_function(ENGINE *e, ENGINE_GEN_INT_FUNC_PTR finish_f);
 int ENGINE_set_ctrl_function(ENGINE *e, ENGINE_CTRL_FUNC_PTR ctrl_f);
 int ENGINE_set_load_privkey_function(ENGINE *e,
                                      ENGINE_LOAD_KEY_PTR loadpriv_f);
+int ENGINE_set_load_privkey_bio_function(ENGINE *e,
+					 ENGINE_LOAD_KEY_BIO_PTR loadpriv_f);
 int ENGINE_set_load_pubkey_function(ENGINE *e, ENGINE_LOAD_KEY_PTR loadpub_f);
 int ENGINE_set_load_ssl_client_cert_function(ENGINE *e,
                                              ENGINE_SSL_CLIENT_CERT_PTR
@@ -611,6 +619,7 @@ ENGINE_GEN_INT_FUNC_PTR ENGINE_get_finish_function(const ENGINE *e);
 ENGINE_CTRL_FUNC_PTR ENGINE_get_ctrl_function(const ENGINE *e);
 ENGINE_LOAD_KEY_PTR ENGINE_get_load_privkey_function(const ENGINE *e);
 ENGINE_LOAD_KEY_PTR ENGINE_get_load_pubkey_function(const ENGINE *e);
+ENGINE_LOAD_KEY_BIO_PTR ENGINE_get_load_privkey_bio_function(const ENGINE *e);
 ENGINE_SSL_CLIENT_CERT_PTR ENGINE_get_ssl_client_cert_function(const ENGINE
                                                                *e);
 ENGINE_CIPHERS_PTR ENGINE_get_ciphers(const ENGINE *e);
@@ -671,6 +680,14 @@ int ENGINE_load_ssl_client_cert(ENGINE *e, SSL *s,
                                 UI_METHOD *ui_method, void *callback_data);
 
 /*
+ * Given a bio, this method iterates over all present engines to
+ * see if any can handle it.  It's functionality depends on the engine
+ * implementing e->load_privkey_bio.
+ */
+int ENGINE_find_engine_load_key(ENGINE **e, EVP_PKEY **pkey, BIO *bio,
+                                pem_password_cb *cb, void *cb_data);
+
+/*
  * This returns a pointer for the current ENGINE structure that is (by
  * default) performing any RSA operations. The value returned is an
  * incremented reference, so it should be free'd (ENGINE_finish) before it is
-- 
2.6.6



More information about the openssl-dev mailing list