Add support for the Provider API while continuing to support the existing
Engine API on distros shipping older releases of OpenSSL.

This is based on similar work contributed by Jan Stancek updating Linux
to use the Provider interface.

    commit 558bdc45dfb2669e1741384a0c80be9c82fa052c
    Author: Jan Stancek <[email protected]>
    Date:   Fri Sep 20 19:52:48 2024 +0300

        sign-file,extract-cert: use pkcs11 provider for OPENSSL MAJOR >= 3

Tested-by: Enric Balletbo i Serra <[email protected]>
Tested-by: Mark Kettenis <[email protected]>
Signed-off-by: Eddie Kovsky <[email protected]>
---
 lib/aes/aes-encrypt.c |   4 +-
 lib/rsa/rsa-sign.c    | 102 +++++++++++++++++++++++++++++++++++++++---
 2 files changed, 100 insertions(+), 6 deletions(-)

diff --git a/lib/aes/aes-encrypt.c b/lib/aes/aes-encrypt.c
index def33a3b3248..0cb2221df800 100644
--- a/lib/aes/aes-encrypt.c
+++ b/lib/aes/aes-encrypt.c
@@ -16,7 +16,9 @@
 #include <openssl/err.h>
 #include <openssl/ssl.h>
 #include <openssl/evp.h>
-#include <openssl/engine.h>
+#if !defined(OPENSSL_NO_ENGINE) && !defined(OPENSSL_NO_DEPRECATED_3_0)
+# include <openssl/engine.h>
+#endif
 #include <uboot_aes.h>
 
 #if OPENSSL_VERSION_NUMBER >= 0x10000000L
diff --git a/lib/rsa/rsa-sign.c b/lib/rsa/rsa-sign.c
index 0e38c9e802fd..361ed0647bc6 100644
--- a/lib/rsa/rsa-sign.c
+++ b/lib/rsa/rsa-sign.c
@@ -19,7 +19,47 @@
 #include <openssl/err.h>
 #include <openssl/ssl.h>
 #include <openssl/evp.h>
-#include <openssl/engine.h>
+#if OPENSSL_VERSION_MAJOR >= 3
+# define USE_PKCS11_PROVIDER
+# include <err.h>
+# include <openssl/provider.h>
+# include <openssl/store.h>
+#else
+# if !defined(OPENSSL_NO_ENGINE) && !defined(OPENSSL_NO_DEPRECATED_3_0)
+#  define USE_PKCS11_ENGINE
+#  include <openssl/engine.h>
+# endif
+#endif
+
+#ifdef USE_PKCS11_PROVIDER
+#define ERR(cond, fmt, ...)                            \
+       do {                                            \
+               bool __cond = (cond);                   \
+               drain_openssl_errors(__LINE__, 0);      \
+               if (__cond) {                           \
+                       errx(1, fmt, ## __VA_ARGS__);   \
+               }                                       \
+       } while (0)
+
+static void drain_openssl_errors(int l, int silent)
+{
+       const char *file;
+       char buf[120];
+       int e, line;
+
+       if (ERR_peek_error() == 0)
+               return;
+       if (!silent)
+               fprintf(stderr, "At line:%d:\n", l);
+
+       while ((e = ERR_peek_error_line(&file, &line))) {
+               ERR_error_string(e, buf);
+               if (!silent)
+                       fprintf(stderr, "- SSL %s: %s:%d\n", buf, file, line);
+               ERR_get_error();
+       }
+}
+#endif
 
 static int rsa_err(const char *msg)
 {
@@ -94,10 +134,11 @@ err_cert:
  *
  * @keydir:    Key prefix
  * @name       Name of key
- * @engine     Engine to use
+ * @engine     Engine to use or NULL when using pkcs11 provider
  * @evpp       Returns EVP_PKEY object, or NULL on failure
  * Return: 0 if ok, -ve on error (in which case *evpp will be set to NULL)
  */
+#ifdef USE_PKCS11_ENGINE
 static int rsa_engine_get_pub_key(const char *keydir, const char *name,
                                  ENGINE *engine, EVP_PKEY **evpp)
 {
@@ -157,21 +198,24 @@ static int rsa_engine_get_pub_key(const char *keydir, 
const char *name,
 
        return 0;
 }
+#endif
 
 /**
  * rsa_get_pub_key() - read a public key
  *
  * @keydir:    Directory containing the key (PEM file) or key prefix (engine)
  * @name       Name of key file (will have a .crt extension)
- * @engine     Engine to use
+ * @engine     Engine to use or NULL when using pkcs11 provider
  * @evpp       Returns EVP_PKEY object, or NULL on failure
  * Return: 0 if ok, -ve on error (in which case *evpp will be set to NULL)
  */
 static int rsa_get_pub_key(const char *keydir, const char *name,
                           ENGINE *engine, EVP_PKEY **evpp)
 {
+#ifdef USE_PKCS11_ENGINE
        if (engine)
                return rsa_engine_get_pub_key(keydir, name, engine, evpp);
+#endif
        return rsa_pem_get_pub_key(keydir, name, evpp);
 }
 
@@ -207,13 +251,44 @@ static int rsa_pem_get_priv_key(const char *keydir, const 
char *name,
                return -ENOENT;
        }
 
+#ifdef USE_PKCS11_PROVIDER
+       EVP_PKEY *private_key = NULL;
+       OSSL_STORE_CTX *store;
+
+       if (!OSSL_PROVIDER_try_load(NULL, "pkcs11", true))
+               ERR(1, "OSSL_PROVIDER_try_load(pkcs11)");
+       if (!OSSL_PROVIDER_try_load(NULL, "default", true))
+               ERR(1, "OSSL_PROVIDER_try_load(default)");
+
+       store = OSSL_STORE_open(path, NULL, NULL, NULL, NULL);
+       ERR(!store, "OSSL_STORE_open");
+
+       while (!OSSL_STORE_eof(store)) {
+               OSSL_STORE_INFO *info = OSSL_STORE_load(store);
+
+               if (!info) {
+                       drain_openssl_errors(__LINE__, 0);
+                       continue;
+               }
+               if (OSSL_STORE_INFO_get_type(info) == OSSL_STORE_INFO_PKEY) {
+                       private_key = OSSL_STORE_INFO_get1_PKEY(info);
+                       ERR(!private_key, "OSSL_STORE_INFO_get1_PKEY");
+               }
+               OSSL_STORE_INFO_free(info);
+               if (private_key)
+                       break;
+       }
+       OSSL_STORE_close(store);
+
+       *evpp = private_key;
+#else
        if (!PEM_read_PrivateKey(f, evpp, NULL, path)) {
                rsa_err("Failure reading private key");
                fclose(f);
                return -EPROTO;
        }
        fclose(f);
-
+#endif
        return 0;
 }
 
@@ -226,6 +301,7 @@ static int rsa_pem_get_priv_key(const char *keydir, const 
char *name,
  * @evpp       Returns EVP_PKEY object, or NULL on failure
  * Return: 0 if ok, -ve on error (in which case *evpp will be set to NULL)
  */
+#ifdef USE_PKCS11_ENGINE
 static int rsa_engine_get_priv_key(const char *keydir, const char *name,
                                   const char *keyfile,
                                   ENGINE *engine, EVP_PKEY **evpp)
@@ -293,22 +369,25 @@ static int rsa_engine_get_priv_key(const char *keydir, 
const char *name,
 
        return 0;
 }
+#endif
 
 /**
  * rsa_get_priv_key() - read a private key
  *
  * @keydir:    Directory containing the key (PEM file) or key prefix (engine)
  * @name       Name of key
- * @engine     Engine to use for signing
+ * @engine     Engine to use or NULL when using pkcs11 provider
  * @evpp       Returns EVP_PKEY object, or NULL on failure
  * Return: 0 if ok, -ve on error (in which case *evpp will be set to NULL)
  */
 static int rsa_get_priv_key(const char *keydir, const char *name,
                            const char *keyfile, ENGINE *engine, EVP_PKEY 
**evpp)
 {
+#ifdef USE_PKCS11_ENGINE
        if (engine)
                return rsa_engine_get_priv_key(keydir, name, keyfile, engine,
                                               evpp);
+#endif
        return rsa_pem_get_priv_key(keydir, name, keyfile, evpp);
 }
 
@@ -325,6 +404,7 @@ static int rsa_init(void)
        return 0;
 }
 
+#ifdef USE_PKCS11_ENGINE
 static int rsa_engine_init(const char *engine_id, ENGINE **pe)
 {
        const char *key_pass;
@@ -380,6 +460,7 @@ static void rsa_engine_remove(ENGINE *e)
                ENGINE_free(e);
        }
 }
+#endif
 
 static int rsa_sign_with_key(EVP_PKEY *pkey, struct padding_algo *padding_algo,
                             struct checksum_algo *checksum_algo,
@@ -480,11 +561,13 @@ int rsa_sign(struct image_sign_info *info,
        if (ret)
                return ret;
 
+#ifdef USE_PKCS11_ENGINE
        if (info->engine_id) {
                ret = rsa_engine_init(info->engine_id, &e);
                if (ret)
                        return ret;
        }
+#endif
 
        ret = rsa_get_priv_key(info->keydir, info->keyname, info->keyfile,
                               e, &pkey);
@@ -496,16 +579,21 @@ int rsa_sign(struct image_sign_info *info,
                goto err_sign;
 
        EVP_PKEY_free(pkey);
+
+#ifdef USE_PKCS11_ENGINE
        if (info->engine_id)
                rsa_engine_remove(e);
+#endif
 
        return ret;
 
 err_sign:
        EVP_PKEY_free(pkey);
 err_priv:
+#ifdef USE_PKCS11_ENGINE
        if (info->engine_id)
                rsa_engine_remove(e);
+#endif
        return ret;
 }
 
@@ -645,11 +733,13 @@ int rsa_add_verify_data(struct image_sign_info *info, 
void *keydest)
        ENGINE *e = NULL;
 
        debug("%s: Getting verification data\n", __func__);
+#ifdef USE_PKCS11_ENGINE
        if (info->engine_id) {
                ret = rsa_engine_init(info->engine_id, &e);
                if (ret)
                        return ret;
        }
+#endif
        ret = rsa_get_pub_key(info->keydir, info->keyname, e, &pkey);
        if (ret)
                goto err_get_pub_key;
@@ -726,8 +816,10 @@ done:
 err_get_params:
        EVP_PKEY_free(pkey);
 err_get_pub_key:
+#ifdef USE_PKCS11_ENGINE
        if (info->engine_id)
                rsa_engine_remove(e);
+#endif
 
        if (ret)
                return ret;
-- 
2.56.0

Reply via email to