]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
rsa: add support of padding pss
authorPhilippe Reynes <philippe.reynes@softathome.com>
Wed, 14 Nov 2018 12:51:01 +0000 (13:51 +0100)
committerTom Rini <trini@konsulko.com>
Mon, 3 Dec 2018 15:44:10 +0000 (10:44 -0500)
We add the support of the padding pss for rsa signature.
This new padding is often recommended instead of pkcs-1.5.

Signed-off-by: Philippe Reynes <philippe.reynes@softathome.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
Kconfig
common/image-sig.c
include/image.h
include/u-boot/rsa.h
lib/rsa/rsa-sign.c
lib/rsa/rsa-verify.c

diff --git a/Kconfig b/Kconfig
index dca9bb4e432929863ae79ab85b5e2f8100cfa16d..31205534941b0835ce24da37f6dfa6e8edc61662 100644 (file)
--- a/Kconfig
+++ b/Kconfig
@@ -290,6 +290,14 @@ config FIT_SIGNATURE_MAX_SIZE
          device memory. Assure this size does not extend past expected storage
          space.
 
+config FIT_ENABLE_RSASSA_PSS_SUPPORT
+       bool "Support rsassa-pss signature scheme of FIT image contents"
+       depends on FIT_SIGNATURE
+       default n
+       help
+         Enable this to support the pss padding algorithm as described
+         in the rfc8017 (https://tools.ietf.org/html/rfc8017).
+
 config FIT_VERBOSE
        bool "Show verbose messages when FIT images fail"
        help
index 3d8281f2faa6d6de24d7f84dc42910595e245be4..4f6b4ec412c30c11989080e7c3e56a61959d572f 100644 (file)
@@ -76,6 +76,12 @@ struct padding_algo padding_algos[] = {
                .name = "pkcs-1.5",
                .verify = padding_pkcs_15_verify,
        },
+#ifdef CONFIG_FIT_ENABLE_RSASSA_PSS_SUPPORT
+       {
+               .name = "pss",
+               .verify = padding_pss_verify,
+       }
+#endif /* CONFIG_FIT_ENABLE_RSASSA_PSS_SUPPORT */
 };
 
 struct checksum_algo *image_get_checksum_algo(const char *full_name)
index e75d1763b5835cfd68599c76834de9260e0064fa..83a2d412c9f4c28fa587523ce469caf07c480700 100644 (file)
@@ -30,6 +30,7 @@ struct fdt_region;
 #define IMAGE_ENABLE_FIT       1
 #define IMAGE_ENABLE_OF_LIBFDT 1
 #define CONFIG_FIT_VERBOSE     1 /* enable fit_format_{error,warning}() */
+#define CONFIG_FIT_ENABLE_RSASSA_PSS_SUPPORT 1
 #define CONFIG_FIT_ENABLE_SHA256_SUPPORT
 #define CONFIG_SHA1
 #define CONFIG_SHA256
index 16b4c4caeeac70ac72282909c203414e645f1cfa..2d3024d8b71084d0e2eadcc4fbf9193bfd8a63ec 100644 (file)
@@ -101,6 +101,12 @@ int rsa_verify(struct image_sign_info *info,
 int padding_pkcs_15_verify(struct image_sign_info *info,
                           uint8_t *msg, int msg_len,
                           const uint8_t *hash, int hash_len);
+
+#ifdef CONFIG_FIT_ENABLE_RSASSA_PSS_SUPPORT
+int padding_pss_verify(struct image_sign_info *info,
+                      uint8_t *msg, int msg_len,
+                      const uint8_t *hash, int hash_len);
+#endif /* CONFIG_FIT_ENABLE_RSASSA_PSS_SUPPORT */
 #else
 static inline int rsa_verify(struct image_sign_info *info,
                const struct image_region region[], int region_count,
@@ -115,6 +121,15 @@ static inline int padding_pkcs_15_verify(struct image_sign_info *info,
 {
        return -ENXIO;
 }
+
+#ifdef CONFIG_FIT_ENABLE_RSASSA_PSS_SUPPORT
+static inline int padding_pss_verify(struct image_sign_info *info,
+                                    uint8_t *msg, int msg_len,
+                                    const uint8_t *hash, int hash_len)
+{
+       return -ENXIO;
+}
+#endif /* CONFIG_FIT_ENABLE_RSASSA_PSS_SUPPORT */
 #endif
 
 #define RSA_DEFAULT_PADDING_NAME               "pkcs-1.5"
index 6aa0e2ab5df85649d139c2a7a76eb50536e09832..fb5e07b56d8a4d2e979fc2284190062830200f23 100644 (file)
@@ -438,6 +438,16 @@ static int rsa_sign_with_key(RSA *rsa, struct padding_algo *padding_algo,
                goto err_sign;
        }
 
+#ifdef CONFIG_FIT_ENABLE_RSASSA_PSS_SUPPORT
+       if (padding_algo && !strcmp(padding_algo->name, "pss")) {
+               if (EVP_PKEY_CTX_set_rsa_padding(ckey,
+                                                RSA_PKCS1_PSS_PADDING) <= 0) {
+                       ret = rsa_err("Signer padding setup failed");
+                       goto err_sign;
+               }
+       }
+#endif /* CONFIG_FIT_ENABLE_RSASSA_PSS_SUPPORT */
+
        for (i = 0; i < region_count; i++) {
                if (!EVP_DigestSignUpdate(context, region[i].data,
                                          region[i].size)) {
index 279a9ba4562a74e0bd77c43d5f9d1f2d4a5b209d..9734f6d3bd692451bcf0d91b0d5862ea4d90bbb6 100644 (file)
@@ -80,6 +80,196 @@ int padding_pkcs_15_verify(struct image_sign_info *info,
        return 0;
 }
 
+#ifdef CONFIG_FIT_ENABLE_RSASSA_PSS_SUPPORT
+static void u32_i2osp(uint32_t val, uint8_t *buf)
+{
+       buf[0] = (uint8_t)((val >> 24) & 0xff);
+       buf[1] = (uint8_t)((val >> 16) & 0xff);
+       buf[2] = (uint8_t)((val >>  8) & 0xff);
+       buf[3] = (uint8_t)((val >>  0) & 0xff);
+}
+
+/**
+ * mask_generation_function1() - generate an octet string
+ *
+ * Generate an octet string used to check rsa signature.
+ * It use an input octet string and a hash function.
+ *
+ * @checksum:  A Hash function
+ * @seed:      Specifies an input variable octet string
+ * @seed_len:  Size of the input octet string
+ * @output:    Specifies the output octet string
+ * @output_len:        Size of the output octet string
+ * @return 0 if the octet string was correctly generated, others on error
+ */
+static int mask_generation_function1(struct checksum_algo *checksum,
+                                    uint8_t *seed, int seed_len,
+                                    uint8_t *output, int output_len)
+{
+       struct image_region region[2];
+       int ret = 0, i, i_output = 0, region_count = 2;
+       uint32_t counter = 0;
+       uint8_t buf_counter[4], *tmp;
+       int hash_len = checksum->checksum_len;
+
+       memset(output, 0, output_len);
+
+       region[0].data = seed;
+       region[0].size = seed_len;
+       region[1].data = &buf_counter[0];
+       region[1].size = 4;
+
+       tmp = malloc(hash_len);
+       if (!tmp) {
+               debug("%s: can't allocate array tmp\n", __func__);
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       while (i_output < output_len) {
+               u32_i2osp(counter, &buf_counter[0]);
+
+               ret = checksum->calculate(checksum->name,
+                                         region, region_count,
+                                         tmp);
+               if (ret < 0) {
+                       debug("%s: Error in checksum calculation\n", __func__);
+                       goto out;
+               }
+
+               i = 0;
+               while ((i_output < output_len) && (i < hash_len)) {
+                       output[i_output] = tmp[i];
+                       i_output++;
+                       i++;
+               }
+
+               counter++;
+       }
+
+out:
+       free(tmp);
+
+       return ret;
+}
+
+static int compute_hash_prime(struct checksum_algo *checksum,
+                             uint8_t *pad, int pad_len,
+                             uint8_t *hash, int hash_len,
+                             uint8_t *salt, int salt_len,
+                             uint8_t *hprime)
+{
+       struct image_region region[3];
+       int ret, region_count = 3;
+
+       region[0].data = pad;
+       region[0].size = pad_len;
+       region[1].data = hash;
+       region[1].size = hash_len;
+       region[2].data = salt;
+       region[2].size = salt_len;
+
+       ret = checksum->calculate(checksum->name, region, region_count, hprime);
+       if (ret < 0) {
+               debug("%s: Error in checksum calculation\n", __func__);
+               goto out;
+       }
+
+out:
+       return ret;
+}
+
+int padding_pss_verify(struct image_sign_info *info,
+                      uint8_t *msg, int msg_len,
+                      const uint8_t *hash, int hash_len)
+{
+       uint8_t *masked_db = NULL;
+       int masked_db_len = msg_len - hash_len - 1;
+       uint8_t *h = NULL, *hprime = NULL;
+       int h_len = hash_len;
+       uint8_t *db_mask = NULL;
+       int db_mask_len = masked_db_len;
+       uint8_t *db = NULL, *salt = NULL;
+       int db_len = masked_db_len, salt_len = msg_len - hash_len - 2;
+       uint8_t pad_zero[8] = { 0 };
+       int ret, i, leftmost_bits = 1;
+       uint8_t leftmost_mask;
+       struct checksum_algo *checksum = info->checksum;
+
+       /* first, allocate everything */
+       masked_db = malloc(masked_db_len);
+       h = malloc(h_len);
+       db_mask = malloc(db_mask_len);
+       db = malloc(db_len);
+       salt = malloc(salt_len);
+       hprime = malloc(hash_len);
+       if (!masked_db || !h || !db_mask || !db || !salt || !hprime) {
+               printf("%s: can't allocate some buffer\n", __func__);
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       /* step 4: check if the last byte is 0xbc */
+       if (msg[msg_len - 1] != 0xbc) {
+               printf("%s: invalid pss padding (0xbc is missing)\n", __func__);
+               ret = -EINVAL;
+               goto out;
+       }
+
+       /* step 5 */
+       memcpy(masked_db, msg, masked_db_len);
+       memcpy(h, msg + masked_db_len, h_len);
+
+       /* step 6 */
+       leftmost_mask = (0xff >> (8 - leftmost_bits)) << (8 - leftmost_bits);
+       if (masked_db[0] & leftmost_mask) {
+               printf("%s: invalid pss padding ", __func__);
+               printf("(leftmost bit of maskedDB not zero)\n");
+               ret = -EINVAL;
+               goto out;
+       }
+
+       /* step 7 */
+       mask_generation_function1(checksum, h, h_len, db_mask, db_mask_len);
+
+       /* step 8 */
+       for (i = 0; i < db_len; i++)
+               db[i] = masked_db[i] ^ db_mask[i];
+
+       /* step 9 */
+       db[0] &= 0xff >> leftmost_bits;
+
+       /* step 10 */
+       if (db[0] != 0x01) {
+               printf("%s: invalid pss padding ", __func__);
+               printf("(leftmost byte of db isn't 0x01)\n");
+               ret = EINVAL;
+               goto out;
+       }
+
+       /* step 11 */
+       memcpy(salt, &db[1], salt_len);
+
+       /* step 12 & 13 */
+       compute_hash_prime(checksum, pad_zero, 8,
+                          (uint8_t *)hash, hash_len,
+                          salt, salt_len, hprime);
+
+       /* step 14 */
+       ret = memcmp(h, hprime, hash_len);
+
+out:
+       free(hprime);
+       free(salt);
+       free(db);
+       free(db_mask);
+       free(h);
+       free(masked_db);
+
+       return ret;
+}
+#endif
+
 /**
  * rsa_verify_key() - Verify a signature against some data using RSA Key
  *