diff mbox series

[U-Boot,3/4] rsa: add support of padding pss

Message ID 1538497960-25959-3-git-send-email-philippe.reynes@softathome.com
State Changes Requested
Delegated to: Tom Rini
Headers show
Series [U-Boot,1/4] rsa: use new openssl API to create signature | expand

Commit Message

Philippe REYNES Oct. 2, 2018, 4:32 p.m. UTC
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>
---
 common/image-sig.c   |   4 ++
 include/u-boot/rsa.h |  11 ++++
 lib/rsa/rsa-sign.c   |   8 +++
 lib/rsa/rsa-verify.c | 173 +++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 196 insertions(+)

Comments

Simon Glass Oct. 9, 2018, 4:20 p.m. UTC | #1
Hi Philippe,

On 2 October 2018 at 10:32, Philippe Reynes
<philippe.reynes@softathome.com> wrote:
> 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>
> ---
>  common/image-sig.c   |   4 ++
>  include/u-boot/rsa.h |  11 ++++
>  lib/rsa/rsa-sign.c   |   8 +++
>  lib/rsa/rsa-verify.c | 173 +++++++++++++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 196 insertions(+)

Needs a doc update somewhere.

>
> diff --git a/common/image-sig.c b/common/image-sig.c
> index b7ca657..0aa1f2d 100644
> --- a/common/image-sig.c
> +++ b/common/image-sig.c
> @@ -76,6 +76,10 @@ struct padding_algo padding_algos[] = {
>                 .name = "pkcs-1.5",
>                 .verify = padding_pkcs_15_verify,
>         },
> +       {
> +               .name = "pss",
> +               .verify = padding_pss_verify,
> +       }

I think this feature should be controlled by a new Kconfig option as
it presumably increases code size a bit.

>  };
>
>  struct checksum_algo *image_get_checksum_algo(const char *full_name)
> diff --git a/include/u-boot/rsa.h b/include/u-boot/rsa.h
> index 16b4c4c..6193c10 100644
> --- a/include/u-boot/rsa.h
> +++ b/include/u-boot/rsa.h
> @@ -101,6 +101,10 @@ 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);
> +
> +int padding_pss_verify(struct image_sign_info *info,
> +                      uint8_t *msg, int msg_len,
> +                      const uint8_t *hash, int hash_len);
>  #else
>  static inline int rsa_verify(struct image_sign_info *info,
>                 const struct image_region region[], int region_count,
> @@ -115,6 +119,13 @@ static inline int padding_pkcs_15_verify(struct image_sign_info *info,
>  {
>         return -ENXIO;
>  }
> +
> +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
>
>  #define RSA_DEFAULT_PADDING_NAME               "pkcs-1.5"
> diff --git a/lib/rsa/rsa-sign.c b/lib/rsa/rsa-sign.c
> index 6aa0e2a..13c035e 100644
> --- a/lib/rsa/rsa-sign.c
> +++ b/lib/rsa/rsa-sign.c
> @@ -438,6 +438,14 @@ static int rsa_sign_with_key(RSA *rsa, struct padding_algo *padding_algo,
>                 goto err_sign;
>         }
>
> +       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;
> +               }
> +       }
> +
>         for (i = 0; i < region_count; i++) {
>                 if (!EVP_DigestSignUpdate(context, region[i].data,
>                                           region[i].size)) {
> diff --git a/lib/rsa/rsa-verify.c b/lib/rsa/rsa-verify.c
> index 279a9ba..ca5c1fc 100644
> --- a/lib/rsa/rsa-verify.c
> +++ b/lib/rsa/rsa-verify.c
> @@ -80,6 +80,179 @@ int padding_pkcs_15_verify(struct image_sign_info *info,
>         return 0;
>  }
>
> +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);
> +}
> +
> +int mfg(struct checksum_algo *checksum, uint8_t *seed, int seed_len,
> +       uint8_t *output, int output_len)

What is the name mfg? Can you make this a little longer please? Also,
did you mean to export it or should it be static? Finally, it needs a
function comment somewhere.

> +{
> +       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);

Please put a blank line before the final 'return' in a function.

> +       return ret;
> +}
> +
> +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 */
> +       mfg(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;
> +}
> +
>  /**
>   * rsa_verify_key() - Verify a signature against some data using RSA Key
>   *
> --
> 2.7.4
>

Regards,
Simon
diff mbox series

Patch

diff --git a/common/image-sig.c b/common/image-sig.c
index b7ca657..0aa1f2d 100644
--- a/common/image-sig.c
+++ b/common/image-sig.c
@@ -76,6 +76,10 @@  struct padding_algo padding_algos[] = {
 		.name = "pkcs-1.5",
 		.verify = padding_pkcs_15_verify,
 	},
+	{
+		.name = "pss",
+		.verify = padding_pss_verify,
+	}
 };
 
 struct checksum_algo *image_get_checksum_algo(const char *full_name)
diff --git a/include/u-boot/rsa.h b/include/u-boot/rsa.h
index 16b4c4c..6193c10 100644
--- a/include/u-boot/rsa.h
+++ b/include/u-boot/rsa.h
@@ -101,6 +101,10 @@  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);
+
+int padding_pss_verify(struct image_sign_info *info,
+		       uint8_t *msg, int msg_len,
+		       const uint8_t *hash, int hash_len);
 #else
 static inline int rsa_verify(struct image_sign_info *info,
 		const struct image_region region[], int region_count,
@@ -115,6 +119,13 @@  static inline int padding_pkcs_15_verify(struct image_sign_info *info,
 {
 	return -ENXIO;
 }
+
+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
 
 #define RSA_DEFAULT_PADDING_NAME		"pkcs-1.5"
diff --git a/lib/rsa/rsa-sign.c b/lib/rsa/rsa-sign.c
index 6aa0e2a..13c035e 100644
--- a/lib/rsa/rsa-sign.c
+++ b/lib/rsa/rsa-sign.c
@@ -438,6 +438,14 @@  static int rsa_sign_with_key(RSA *rsa, struct padding_algo *padding_algo,
 		goto err_sign;
 	}
 
+	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;
+		}
+	}
+
 	for (i = 0; i < region_count; i++) {
 		if (!EVP_DigestSignUpdate(context, region[i].data,
 					  region[i].size)) {
diff --git a/lib/rsa/rsa-verify.c b/lib/rsa/rsa-verify.c
index 279a9ba..ca5c1fc 100644
--- a/lib/rsa/rsa-verify.c
+++ b/lib/rsa/rsa-verify.c
@@ -80,6 +80,179 @@  int padding_pkcs_15_verify(struct image_sign_info *info,
 	return 0;
 }
 
+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);
+}
+
+int mfg(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;
+}
+
+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 */
+	mfg(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;
+}
+
 /**
  * rsa_verify_key() - Verify a signature against some data using RSA Key
  *