openssl: Also load EC keys from an ENGINE
authorTobias Brunner <tobias@strongswan.org>
Wed, 6 Sep 2017 08:41:37 +0000 (10:41 +0200)
committerTobias Brunner <tobias@strongswan.org>
Thu, 2 Nov 2017 08:42:52 +0000 (09:42 +0100)
src/libstrongswan/plugins/openssl/openssl_ec_private_key.c
src/libstrongswan/plugins/openssl/openssl_ec_private_key.h
src/libstrongswan/plugins/openssl/openssl_plugin.c
src/libstrongswan/plugins/openssl/openssl_rsa_private_key.c
src/libstrongswan/plugins/openssl/openssl_rsa_private_key.h

index 22bbf6d..d187c06 100644 (file)
@@ -49,6 +49,11 @@ struct private_openssl_ec_private_key_t {
        EC_KEY *ec;
 
        /**
+        * TRUE if the key is from an OpenSSL ENGINE and might not be readable
+        */
+       bool engine;
+
+       /**
         * reference count
         */
        refcount_t ref;
@@ -226,6 +231,11 @@ METHOD(private_key_t, get_encoding, bool,
 {
        u_char *p;
 
+       if (this->engine)
+       {
+               return FALSE;
+       }
+
        switch (type)
        {
                case PRIVKEY_ASN1_DER:
@@ -307,7 +317,7 @@ static private_openssl_ec_private_key_t *create_empty(void)
 /*
  * See header.
  */
-private_key_t *openssl_ec_private_key_create(EVP_PKEY *key)
+private_key_t *openssl_ec_private_key_create(EVP_PKEY *key, bool engine)
 {
        private_openssl_ec_private_key_t *this;
        EC_KEY *ec;
@@ -320,6 +330,7 @@ private_key_t *openssl_ec_private_key_create(EVP_PKEY *key)
        }
        this = create_empty();
        this->ec = ec;
+       this->engine = engine;
        return &this->public.key;
 }
 
index 84314f6..56c59cf 100644 (file)
@@ -67,8 +67,9 @@ openssl_ec_private_key_t *openssl_ec_private_key_load(key_type_t type,
  * Wrap an EVP_PKEY object of type EVP_PKEY_EC
  *
  * @param key          EVP_PKEY_EC key object (adopted)
+ * @param engine       whether the key was loaded via an engine
  * @return                     loaded key, NULL on failure
  */
-private_key_t *openssl_ec_private_key_create(EVP_PKEY *key);
+private_key_t *openssl_ec_private_key_create(EVP_PKEY *key, bool engine);
 
 #endif /** OPENSSL_EC_PRIVATE_KEY_H_ @}*/
index ab73d71..2f05b2b 100644 (file)
@@ -301,11 +301,11 @@ static private_key_t *openssl_private_key_load(key_type_t type, va_list args)
                        {
 #ifndef OPENSSL_NO_RSA
                                case EVP_PKEY_RSA:
-                                       return openssl_rsa_private_key_create(key);
+                                       return openssl_rsa_private_key_create(key, FALSE);
 #endif
 #ifndef OPENSSL_NO_ECDSA
                                case EVP_PKEY_EC:
-                                       return openssl_ec_private_key_create(key);
+                                       return openssl_ec_private_key_create(key, FALSE);
 #endif
                                default:
                                        EVP_PKEY_free(key);
@@ -316,6 +316,152 @@ static private_key_t *openssl_private_key_load(key_type_t type, va_list args)
        return NULL;
 }
 
+#ifndef OPENSSL_NO_ENGINE
+/**
+ * Login to engine with a PIN specified for a keyid
+ */
+static bool login(ENGINE *engine, chunk_t keyid)
+{
+       enumerator_t *enumerator;
+       shared_key_t *shared;
+       identification_t *id;
+       chunk_t key;
+       char pin[64];
+       bool found = FALSE, success = FALSE;
+
+       id = identification_create_from_encoding(ID_KEY_ID, keyid);
+       enumerator = lib->credmgr->create_shared_enumerator(lib->credmgr,
+                                                                                                               SHARED_PIN, id, NULL);
+       while (enumerator->enumerate(enumerator, &shared, NULL, NULL))
+       {
+               found = TRUE;
+               key = shared->get_key(shared);
+               if (snprintf(pin, sizeof(pin),
+                                        "%.*s", (int)key.len, key.ptr) >= sizeof(pin))
+               {
+                       continue;
+               }
+               if (ENGINE_ctrl_cmd_string(engine, "PIN", pin, 0))
+               {
+                       success = TRUE;
+                       break;
+               }
+               else
+               {
+                       DBG1(DBG_CFG, "setting PIN on engine failed");
+               }
+       }
+       enumerator->destroy(enumerator);
+       id->destroy(id);
+       if (!found)
+       {
+               DBG1(DBG_CFG, "no PIN found for %#B", &keyid);
+       }
+       return success;
+}
+#endif /* OPENSSL_NO_ENGINE */
+
+/**
+ * Load private key via engine
+ */
+static private_key_t *openssl_private_key_connect(key_type_t type,
+                                                                                                 va_list args)
+{
+#ifndef OPENSSL_NO_ENGINE
+       char *engine_id = NULL;
+       char keyname[BUF_LEN];
+       chunk_t keyid = chunk_empty;;
+       EVP_PKEY *key;
+       ENGINE *engine;
+       int slot = -1;
+
+       while (TRUE)
+       {
+               switch (va_arg(args, builder_part_t))
+               {
+                       case BUILD_PKCS11_KEYID:
+                               keyid = va_arg(args, chunk_t);
+                               continue;
+                       case BUILD_PKCS11_SLOT:
+                               slot = va_arg(args, int);
+                               continue;
+                       case BUILD_PKCS11_MODULE:
+                               engine_id = va_arg(args, char*);
+                               continue;
+                       case BUILD_END:
+                               break;
+                       default:
+                               return NULL;
+               }
+               break;
+       }
+       if (!keyid.len || keyid.len > 40)
+       {
+               return NULL;
+       }
+
+       memset(keyname, 0, sizeof(keyname));
+       if (slot != -1)
+       {
+               snprintf(keyname, sizeof(keyname), "%d:", slot);
+       }
+       if (sizeof(keyname) - strlen(keyname) <= keyid.len * 4 / 3 + 1)
+       {
+               return NULL;
+       }
+       chunk_to_hex(keyid, keyname + strlen(keyname), FALSE);
+
+       if (!engine_id)
+       {
+               engine_id = lib->settings->get_str(lib->settings,
+                                                       "%s.plugins.openssl.engine_id", "pkcs11", lib->ns);
+       }
+       engine = ENGINE_by_id(engine_id);
+       if (!engine)
+       {
+               DBG2(DBG_LIB, "engine '%s' is not available", engine_id);
+               return NULL;
+       }
+       if (!ENGINE_init(engine))
+       {
+               DBG1(DBG_LIB, "failed to initialize engine '%s'", engine_id);
+               ENGINE_free(engine);
+               return NULL;
+       }
+       if (!login(engine, keyid))
+       {
+               DBG1(DBG_LIB, "login to engine '%s' failed", engine_id);
+               ENGINE_free(engine);
+               return NULL;
+       }
+       key = ENGINE_load_private_key(engine, keyname, NULL, NULL);
+       if (!key)
+       {
+               DBG1(DBG_LIB, "failed to load private key with ID '%s' from "
+                        "engine '%s'", keyname, engine_id);
+               ENGINE_free(engine);
+               return NULL;
+       }
+       ENGINE_free(engine);
+
+       switch (EVP_PKEY_base_id(key))
+       {
+#ifndef OPENSSL_NO_RSA
+               case EVP_PKEY_RSA:
+                       return openssl_rsa_private_key_create(key, TRUE);
+#endif
+#ifndef OPENSSL_NO_ECDSA
+               case EVP_PKEY_EC:
+                       return openssl_ec_private_key_create(key, TRUE);
+#endif
+               default:
+                       EVP_PKEY_free(key);
+                       break;
+       }
+#endif /* OPENSSL_NO_ENGINE */
+       return NULL;
+}
+
 METHOD(plugin_t, get_name, char*,
        private_openssl_plugin_t *this)
 {
@@ -469,8 +615,6 @@ METHOD(plugin_t, get_features, int,
                /* RSA private/public key loading */
                PLUGIN_REGISTER(PRIVKEY, openssl_rsa_private_key_load, TRUE),
                        PLUGIN_PROVIDE(PRIVKEY, KEY_RSA),
-               PLUGIN_REGISTER(PRIVKEY, openssl_rsa_private_key_connect, FALSE),
-                       PLUGIN_PROVIDE(PRIVKEY, KEY_ANY),
                PLUGIN_REGISTER(PRIVKEY_GEN, openssl_rsa_private_key_gen, FALSE),
                        PLUGIN_PROVIDE(PRIVKEY_GEN, KEY_RSA),
                PLUGIN_REGISTER(PUBKEY, openssl_rsa_public_key_load, TRUE),
@@ -554,6 +698,8 @@ METHOD(plugin_t, get_features, int,
                /* generic key loader */
                PLUGIN_REGISTER(PRIVKEY, openssl_private_key_load, TRUE),
                        PLUGIN_PROVIDE(PRIVKEY, KEY_ANY),
+               PLUGIN_REGISTER(PRIVKEY, openssl_private_key_connect, FALSE),
+                       PLUGIN_PROVIDE(PRIVKEY, KEY_ANY),
                PLUGIN_REGISTER(RNG, openssl_rng_create),
                        PLUGIN_PROVIDE(RNG, RNG_STRONG),
                        PLUGIN_PROVIDE(RNG, RNG_WEAK),
index 54ecf25..fd624e6 100644 (file)
@@ -27,9 +27,6 @@
 #include <openssl/bn.h>
 #include <openssl/evp.h>
 #include <openssl/rsa.h>
-#ifndef OPENSSL_NO_ENGINE
-#include <openssl/engine.h>
-#endif /* OPENSSL_NO_ENGINE */
 
 /**
  *  Public exponent to use for key generation.
@@ -386,7 +383,7 @@ error:
 /*
  * See header
  */
-private_key_t *openssl_rsa_private_key_create(EVP_PKEY *key)
+private_key_t *openssl_rsa_private_key_create(EVP_PKEY *key, bool engine)
 {
        private_openssl_rsa_private_key_t *this;
        RSA *rsa;
@@ -399,6 +396,7 @@ private_key_t *openssl_rsa_private_key_create(EVP_PKEY *key)
        }
        this = create_empty();
        this->rsa = rsa;
+       this->engine = engine;
        return &this->public.key;
 }
 
@@ -502,148 +500,4 @@ openssl_rsa_private_key_t *openssl_rsa_private_key_load(key_type_t type,
        return NULL;
 }
 
-#ifndef OPENSSL_NO_ENGINE
-/**
- * Login to engine with a PIN specified for a keyid
- */
-static bool login(ENGINE *engine, chunk_t keyid)
-{
-       enumerator_t *enumerator;
-       shared_key_t *shared;
-       identification_t *id;
-       chunk_t key;
-       char pin[64];
-       bool found = FALSE, success = FALSE;
-
-       id = identification_create_from_encoding(ID_KEY_ID, keyid);
-       enumerator = lib->credmgr->create_shared_enumerator(lib->credmgr,
-                                                                                                               SHARED_PIN, id, NULL);
-       while (enumerator->enumerate(enumerator, &shared, NULL, NULL))
-       {
-               found = TRUE;
-               key = shared->get_key(shared);
-               if (snprintf(pin, sizeof(pin),
-                                        "%.*s", (int)key.len, key.ptr) >= sizeof(pin))
-               {
-                       continue;
-               }
-               if (ENGINE_ctrl_cmd_string(engine, "PIN", pin, 0))
-               {
-                       success = TRUE;
-                       break;
-               }
-               else
-               {
-                       DBG1(DBG_CFG, "setting PIN on engine failed");
-               }
-       }
-       enumerator->destroy(enumerator);
-       id->destroy(id);
-       if (!found)
-       {
-               DBG1(DBG_CFG, "no PIN found for %#B", &keyid);
-       }
-       return success;
-}
-#endif /* OPENSSL_NO_ENGINE */
-
-/*
- * See header.
- */
-openssl_rsa_private_key_t *openssl_rsa_private_key_connect(key_type_t type,
-                                                                                                                  va_list args)
-{
-#ifndef OPENSSL_NO_ENGINE
-       private_openssl_rsa_private_key_t *this;
-       char *engine_id = NULL;
-       char keyname[64];
-       chunk_t keyid = chunk_empty;;
-       EVP_PKEY *key;
-       ENGINE *engine;
-       int slot = -1;
-
-       while (TRUE)
-       {
-               switch (va_arg(args, builder_part_t))
-               {
-                       case BUILD_PKCS11_KEYID:
-                               keyid = va_arg(args, chunk_t);
-                               continue;
-                       case BUILD_PKCS11_SLOT:
-                               slot = va_arg(args, int);
-                               continue;
-                       case BUILD_PKCS11_MODULE:
-                               engine_id = va_arg(args, char*);
-                               continue;
-                       case BUILD_END:
-                               break;
-                       default:
-                               return NULL;
-               }
-               break;
-       }
-       if (!keyid.len || keyid.len > 40)
-       {
-               return NULL;
-       }
-
-       memset(keyname, 0, sizeof(keyname));
-       if (slot != -1)
-       {
-               snprintf(keyname, sizeof(keyname), "%d:", slot);
-       }
-       if (sizeof(keyname) - strlen(keyname) <= keyid.len * 4 / 3 + 1)
-       {
-               return NULL;
-       }
-       chunk_to_hex(keyid, keyname + strlen(keyname), FALSE);
-
-       if (!engine_id)
-       {
-               engine_id = lib->settings->get_str(lib->settings,
-                                                       "%s.plugins.openssl.engine_id", "pkcs11", lib->ns);
-       }
-       engine = ENGINE_by_id(engine_id);
-       if (!engine)
-       {
-               DBG2(DBG_LIB, "engine '%s' is not available", engine_id);
-               return NULL;
-       }
-       if (!ENGINE_init(engine))
-       {
-               DBG1(DBG_LIB, "failed to initialize engine '%s'", engine_id);
-               ENGINE_free(engine);
-               return NULL;
-       }
-       if (!login(engine, keyid))
-       {
-               DBG1(DBG_LIB, "login to engine '%s' failed", engine_id);
-               ENGINE_free(engine);
-               return NULL;
-       }
-       key = ENGINE_load_private_key(engine, keyname, NULL, NULL);
-       if (!key)
-       {
-               DBG1(DBG_LIB, "failed to load private key with ID '%s' from "
-                        "engine '%s'", keyname, engine_id);
-               ENGINE_free(engine);
-               return NULL;
-       }
-       ENGINE_free(engine);
-
-       this = create_empty();
-       this->rsa = EVP_PKEY_get1_RSA(key);
-       this->engine = TRUE;
-       if (!this->rsa)
-       {
-               destroy(this);
-               return NULL;
-       }
-
-       return &this->public;
-#else /* OPENSSL_NO_ENGINE */
-       return NULL;
-#endif /* OPENSSL_NO_ENGINE */
-}
-
 #endif /* OPENSSL_NO_RSA */
index 34ce4c7..783181c 100644 (file)
@@ -67,9 +67,10 @@ openssl_rsa_private_key_t *openssl_rsa_private_key_load(key_type_t type,
  * Wrap an EVP_PKEY object of type EVP_PKEY_RSA
  *
  * @param key          EVP_PKEY_RSA key object (adopted)
+ * @param engine       whether the key was loaded via an engine
  * @return                     loaded key, NULL on failure
  */
-private_key_t *openssl_rsa_private_key_create(EVP_PKEY *key);
+private_key_t *openssl_rsa_private_key_create(EVP_PKEY *key, bool engine);
 
 /**
  * Connect to a RSA private key on a smartcard.