rsa: Add rsa_verify_openssl() to use openssl for host builds
authorPaul HENRYS <paul.henrys_ext@softathome.com>
Wed, 12 Feb 2025 09:31:21 +0000 (10:31 +0100)
committerTom Rini <trini@konsulko.com>
Fri, 21 Feb 2025 14:34:21 +0000 (08:34 -0600)
rsa_verify_openssl() is used in lib/rsa/rsa-verify.c to authenticate data
when building host tools.

Signed-off-by: Paul HENRYS <paul.henrys_ext@softathome.com>
include/image.h
lib/rsa/rsa-verify.c
tools/image-host.c

index 8a9f779..54b1557 100644 (file)
@@ -1687,6 +1687,24 @@ struct sig_header_s {
  */
 int image_pre_load(ulong addr);
 
+#if defined(USE_HOSTCC)
+/**
+ * rsa_verify_openssl() - Verify a signature against some data with openssl API
+ *
+ * Verify a RSA PKCS1.5/PSS signature against an expected hash.
+ *
+ * @info:              Specifies the key and algorithms
+ * @region:            Pointer to the input data
+ * @region_count:      Number of region
+ * @sig:               Signature
+ * @sig_len:           Number of bytes in the signature
+ * Return: 0 if verified, -ve on error
+ */
+int rsa_verify_openssl(struct image_sign_info *info,
+                      const struct image_region region[], int region_count,
+                      uint8_t *sig, uint sig_len);
+#endif
+
 /**
  * fit_image_verify_required_sigs() - Verify signatures marked as 'required'
  *
index d3b4f71..b74aaf8 100644 (file)
@@ -565,6 +565,11 @@ int rsa_verify(struct image_sign_info *info,
        uint8_t hash[info->crypto->key_len];
        int ret;
 
+#ifdef USE_HOSTCC
+       if (!info->fdt_blob)
+               return rsa_verify_openssl(info, region, region_count, sig, sig_len);
+#endif
+
        /*
         * Verify that the checksum-length does not exceed the
         * rsa-signature-length
index 84095d7..3a64336 100644 (file)
 #include <openssl/evp.h>
 #endif
 
+#if CONFIG_IS_ENABLED(IMAGE_PRE_LOAD)
+#include <openssl/rsa.h>
+#include <openssl/err.h>
+#endif
+
 /**
  * fit_set_hash_value - set hash value in requested has node
  * @fit: pointer to the FIT format image header
@@ -1388,3 +1393,139 @@ int fit_check_sign(const void *fit, const void *key,
        return ret;
 }
 #endif
+
+#if CONFIG_IS_ENABLED(IMAGE_PRE_LOAD)
+/**
+ * rsa_verify_openssl() - Verify a signature against some data with openssl API
+ *
+ * Verify a RSA PKCS1.5/PSS signature against an expected hash.
+ *
+ * @info:              Specifies the key and algorithms
+ * @region:            Pointer to the input data
+ * @region_count:      Number of region
+ * @sig:               Signature
+ * @sig_len:           Number of bytes in the signature
+ * Return: 0 if verified, -ve on error
+ */
+int rsa_verify_openssl(struct image_sign_info *info,
+                      const struct image_region region[], int region_count,
+                      uint8_t *sig, uint sig_len)
+{
+       EVP_PKEY *pkey = NULL;
+       EVP_PKEY_CTX *ckey = NULL;
+       EVP_MD_CTX *ctx = NULL;
+       int pad;
+       int size;
+       int i;
+       int ret = 0;
+
+       if (!info) {
+               fprintf(stderr, "No info provided\n");
+               ret = -EINVAL;
+               goto out;
+       }
+
+       if (!info->key) {
+               fprintf(stderr, "No key provided\n");
+               ret = -EINVAL;
+               goto out;
+       }
+
+       if (!info->checksum) {
+               fprintf(stderr, "No checksum information\n");
+               ret = -EINVAL;
+               goto out;
+       }
+
+       if (!info->padding) {
+               fprintf(stderr, "No padding information\n");
+               ret = -EINVAL;
+               goto out;
+       }
+
+       if (region_count < 1) {
+               fprintf(stderr, "Invalid value for region_count: %d\n", region_count);
+               ret = -EINVAL;
+               goto out;
+       }
+
+       pkey = (EVP_PKEY *)info->key;
+
+       ckey = EVP_PKEY_CTX_new(pkey, NULL);
+       if (!ckey) {
+               ret = -ENOMEM;
+               fprintf(stderr, "EVK key context setup failed: %s\n",
+                       ERR_error_string(ERR_get_error(), NULL));
+               goto out;
+       }
+
+       size = EVP_PKEY_size(pkey);
+       if (size > sig_len) {
+               fprintf(stderr, "Invalid signature size (%d bytes)\n",
+                       size);
+               ret = -EINVAL;
+               goto out;
+       }
+
+       ctx = EVP_MD_CTX_new();
+       if (!ctx) {
+               ret = -ENOMEM;
+               fprintf(stderr, "EVP context creation failed: %s\n",
+                       ERR_error_string(ERR_get_error(), NULL));
+               goto out;
+       }
+       EVP_MD_CTX_init(ctx);
+
+       if (EVP_DigestVerifyInit(ctx, &ckey,
+                                EVP_get_digestbyname(info->checksum->name),
+                                NULL, pkey) <= 0) {
+               ret = -EINVAL;
+               fprintf(stderr, "Verifier setup failed: %s\n",
+                       ERR_error_string(ERR_get_error(), NULL));
+               goto out;
+       }
+
+       if (!strcmp(info->padding->name, "pkcs-1.5")) {
+               pad = RSA_PKCS1_PADDING;
+       } else if (!strcmp(info->padding->name, "pss")) {
+               pad = RSA_PKCS1_PSS_PADDING;
+       } else {
+               ret = -ENOMSG;
+               fprintf(stderr, "Unsupported padding: %s\n",
+                       info->padding->name);
+               goto out;
+       }
+
+       if (EVP_PKEY_CTX_set_rsa_padding(ckey, pad) <= 0) {
+               ret = -EINVAL;
+               fprintf(stderr, "padding setup has failed: %s\n",
+                       ERR_error_string(ERR_get_error(), NULL));
+               goto out;
+       }
+
+       for (i=0 ; i < region_count ; ++i) {
+               if (EVP_DigestVerifyUpdate(ctx, region[i].data,
+                                          region[i].size) <= 0) {
+                       ret = -EINVAL;
+                       fprintf(stderr, "Hashing data failed: %s\n",
+                               ERR_error_string(ERR_get_error(), NULL));
+                       goto out;
+               }
+       }
+
+       if (EVP_DigestVerifyFinal(ctx, sig, sig_len) <= 0) {
+               ret = -EINVAL;
+               fprintf(stderr, "Verifying digest failed: %s\n",
+                       ERR_error_string(ERR_get_error(), NULL));
+               goto out;
+       }
+out:
+       if (ctx)
+               EVP_MD_CTX_free(ctx);
+
+       if (ret)
+               fprintf(stderr, "Failed to verify signature\n");
+
+       return ret;
+}
+#endif