bootutil/crypto: Refactor the RSA signature verification and encryption
This patch refactor the RSA operations done by the signature verification
module and by the encrypted images decryption module. Previous solution is
tightly coupled with Mbed TLS, while this patch provides an abstraction of
the RSA functionalities in a dedicated crypto abstraction header, crypto/rsa.h
that supports both Mbed TLS APIs and PSA Crypto APIs. In case of PSA Crypto,
the verification scheme is directly provided by the crypto backend hence it
simplifies the operations done in the image verification module.
Signed-off-by: Antonio de Angelis <Antonio.deAngelis@arm.com>
Change-Id: I973bc3374b62eee2d7717c2368bce7611d37a0c8
diff --git a/boot/bootutil/include/bootutil/crypto/rsa.h b/boot/bootutil/include/bootutil/crypto/rsa.h
new file mode 100644
index 0000000..d00f11c
--- /dev/null
+++ b/boot/bootutil/include/bootutil/crypto/rsa.h
@@ -0,0 +1,356 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Copyright (c) 2023 Arm Limited
+ */
+
+/*
+ * This module provides a thin abstraction over some of the crypto
+ * primitives to make it easier to swap out the used crypto library.
+ *
+ * At this point, the choices are: MCUBOOT_USE_MBED_TLS and
+ * MCUBOOT_USE_PSA_CRYPTO. Note that support for MCUBOOT_USE_PSA_CRYPTO is
+ * still experimental and it might not support all the crypto abstractions
+ * that MCUBOOT_USE_MBED_TLS supports. For this reason, it's allowed to have
+ * both of them defined, and for crypto modules that support both abstractions,
+ * the MCUBOOT_USE_PSA_CRYPTO will take precedence.
+ */
+
+/*
+ * Note: The source file that includes this header should either define one of the
+ * two options BOOTUTIL_CRYPTO_RSA_CRYPT_ENABLED or BOOTUTIL_CRYPTO_RSA_SIGN_ENABLED
+ * This will make the signature functions or encryption functions visible without
+ * generating a "defined but not used" compiler warning
+ */
+
+#ifndef __BOOTUTIL_CRYPTO_RSA_H_
+#define __BOOTUTIL_CRYPTO_RSA_H_
+
+#include "mcuboot_config/mcuboot_config.h"
+
+#if defined(MCUBOOT_USE_PSA_CRYPTO) || defined(MCUBOOT_USE_MBED_TLS)
+#define MCUBOOT_USE_PSA_OR_MBED_TLS
+#endif /* MCUBOOT_USE_PSA_CRYPTO || MCUBOOT_USE_MBED_TLS */
+
+#if (defined(MCUBOOT_USE_PSA_OR_MBED_TLS)) != 1
+ #error "One crypto backend must be defined: either MBED_TLS/PSA_CRYPTO"
+#endif
+
+#if defined(MCUBOOT_USE_PSA_CRYPTO)
+
+#include <psa/crypto.h>
+#include "bootutil/enc_key_public.h"
+
+#elif defined(MCUBOOT_USE_MBED_TLS)
+
+#include "mbedtls/rsa.h"
+#include "mbedtls/version.h"
+#if defined(BOOTUTIL_CRYPTO_RSA_CRYPT_ENABLED)
+#if MBEDTLS_VERSION_NUMBER >= 0x03000000
+#include "rsa_alt_helpers.h"
+#else
+#include "mbedtls/rsa_internal.h"
+#endif
+#endif /* BOOTUTIL_CRYPTO_RSA_CRYPT_ENABLED */
+#include "mbedtls/asn1.h"
+#include "bootutil/crypto/common.h"
+
+#endif /* MCUBOOT_USE_MBED_TLS */
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(MCUBOOT_USE_PSA_CRYPTO)
+
+typedef struct {
+ psa_key_id_t key_id;
+} bootutil_rsa_context;
+
+static inline void bootutil_rsa_init(bootutil_rsa_context *ctx)
+{
+ ctx->key_id = PSA_KEY_ID_NULL;
+}
+
+static inline void bootutil_rsa_drop(bootutil_rsa_context *ctx)
+{
+ if (ctx->key_id != PSA_KEY_ID_NULL) {
+ (void)psa_destroy_key(ctx->key_id);
+ }
+}
+
+#if defined(BOOTUTIL_CRYPTO_RSA_CRYPT_ENABLED)
+static int bootutil_rsa_oaep_decrypt(
+ bootutil_rsa_context *ctx,
+ size_t *olen,
+ const uint8_t *input,
+ uint8_t *output,
+ size_t output_max_len)
+{
+ psa_status_t status = PSA_ERROR_INVALID_ARGUMENT;
+
+ /* Perform an additional defensive check to compare the modulus of the RSA
+ * key to the expected input to the decryption function, i.e. TLV_ENC_RSA_SZ
+ */
+ psa_key_attributes_t key_attr = psa_key_attributes_init();
+ status = psa_get_key_attributes(ctx->key_id, &key_attr);
+ if (status != PSA_SUCCESS) {
+ return -1;
+ }
+ size_t input_size = PSA_BITS_TO_BYTES(psa_get_key_bits(&key_attr));
+ if (input_size != TLV_ENC_RSA_SZ) {
+ return -1;
+ }
+
+ status = psa_asymmetric_decrypt(ctx->key_id, PSA_ALG_RSA_OAEP(PSA_ALG_SHA_256),
+ input, TLV_ENC_RSA_SZ, NULL, 0,
+ output, output_max_len, olen);
+ return (int)status;
+}
+
+/*
+ * Parse a RSA private key with format specified in RFC3447 A.1.2
+ *
+ * The key is meant to be used for OAEP decrypt hence algorithm and usage are hardcoded
+ */
+static int
+bootutil_rsa_parse_private_key(bootutil_rsa_context *ctx, uint8_t **p, uint8_t *end)
+{
+ psa_status_t status = PSA_ERROR_INVALID_ARGUMENT;
+ psa_key_attributes_t key_attributes = psa_key_attributes_init();
+
+ /* Set attributes and import key */
+ psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_DECRYPT);
+ psa_set_key_algorithm(&key_attributes, PSA_ALG_RSA_OAEP(PSA_ALG_SHA_256));
+ psa_set_key_type(&key_attributes, PSA_KEY_TYPE_RSA_KEY_PAIR);
+
+ status = psa_import_key(&key_attributes, *p, (end - *p), &ctx->key_id);
+ return (int)status;
+}
+
+#endif /* BOOTUTIL_CRYPTO_RSA_CRYPT_ENABLED */
+
+#if defined(BOOTUTIL_CRYPTO_RSA_SIGN_ENABLED)
+/*
+ * Parse a RSA public key with format specified in RFC3447 A.1.1
+ *
+ * The key is meant to be used for PSS signature verification hence algorithm and usage are hardcoded
+ */
+static int
+bootutil_rsa_parse_public_key(bootutil_rsa_context *ctx, uint8_t **p, uint8_t *end)
+{
+ psa_status_t status = PSA_ERROR_INVALID_ARGUMENT;
+ psa_key_attributes_t key_attributes = psa_key_attributes_init();
+
+ /* Set attributes and import key */
+ psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_VERIFY_HASH);
+ psa_set_key_algorithm(&key_attributes, PSA_ALG_RSA_PSS(PSA_ALG_SHA_256));
+ psa_set_key_type(&key_attributes, PSA_KEY_TYPE_RSA_PUBLIC_KEY);
+
+ status = psa_import_key(&key_attributes, *p, (end - *p), &ctx->key_id);
+ return (int)status;
+}
+
+/* Get the modulus (N) length in bytes */
+static size_t bootutil_rsa_get_len(const bootutil_rsa_context *ctx)
+{
+ psa_key_attributes_t key_attributes = psa_key_attributes_init();
+ psa_status_t status = psa_get_key_attributes(ctx->key_id, &key_attributes);
+ if (status != PSA_SUCCESS) {
+ return 0;
+ }
+ return PSA_BITS_TO_BYTES(psa_get_key_bits(&key_attributes));
+}
+
+/* PSA Crypto has a dedicated API for RSASSA-PSS verification */
+static inline int bootutil_rsassa_pss_verify(const bootutil_rsa_context *ctx,
+ uint8_t *hash, size_t hlen, uint8_t *sig, size_t slen)
+{
+ return (int) psa_verify_hash(ctx->key_id, PSA_ALG_RSA_PSS(PSA_ALG_SHA_256),
+ hash, hlen, sig, slen);
+}
+#endif /* BOOTUTIL_CRYPTO_RSA_SIGN_ENABLED */
+
+#elif defined(MCUBOOT_USE_MBED_TLS)
+
+typedef mbedtls_rsa_context bootutil_rsa_context;
+
+static inline void bootutil_rsa_init(bootutil_rsa_context *ctx)
+{
+#if MBEDTLS_VERSION_NUMBER >= 0x03000000
+ mbedtls_rsa_init(ctx);
+ mbedtls_rsa_set_padding(ctx, MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA256);
+#else
+ mbedtls_rsa_init(ctx, MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA256);
+#endif
+}
+
+static inline void bootutil_rsa_drop(bootutil_rsa_context *ctx)
+{
+ mbedtls_rsa_free(ctx);
+}
+
+#if defined(BOOTUTIL_CRYPTO_RSA_CRYPT_ENABLED) && (MBEDTLS_VERSION_NUMBER >= 0x03000000)
+static int fake_rng(void *p_rng, unsigned char *output, size_t len);
+#endif /* BOOTUTIL_CRYPTO_RSA_CRYPT_ENABLED && MBEDTLS_VERSION_NUMBER >= 3.0 */
+
+#if defined(BOOTUTIL_CRYPTO_RSA_CRYPT_ENABLED)
+static inline int bootutil_rsa_oaep_decrypt(
+ bootutil_rsa_context *ctx,
+ size_t *olen,
+ const uint8_t *input,
+ uint8_t *output,
+ size_t output_max_len)
+{
+ int rc = -1;
+#if MBEDTLS_VERSION_NUMBER >= 0x03000000
+ rc = mbedtls_rsa_rsaes_oaep_decrypt(ctx, fake_rng, NULL,
+ NULL, 0, olen, input, output, output_max_len);
+#else
+ rc = mbedtls_rsa_rsaes_oaep_decrypt(ctx, NULL, NULL, MBEDTLS_RSA_PRIVATE,
+ NULL, 0, olen, input, output, output_max_len);
+#endif
+ return rc;
+}
+
+/*
+ * Parse a RSA private key with format specified in RFC3447 A.1.2
+ */
+static int
+bootutil_rsa_parse_private_key(bootutil_rsa_context *ctx, uint8_t **p, uint8_t *end)
+{
+ size_t len;
+
+ if (mbedtls_asn1_get_tag(p, end, &len,
+ MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) != 0) {
+ return -1;
+ }
+
+ if (*p + len != end) {
+ return -2;
+ }
+
+ /* Non-optional fields. */
+ if ( /* version */
+ mbedtls_asn1_get_int(p, end, &ctx->MBEDTLS_CONTEXT_MEMBER(ver)) != 0 ||
+ /* public modulus */
+ mbedtls_asn1_get_mpi(p, end, &ctx->MBEDTLS_CONTEXT_MEMBER(N)) != 0 ||
+ /* public exponent */
+ mbedtls_asn1_get_mpi(p, end, &ctx->MBEDTLS_CONTEXT_MEMBER(E)) != 0 ||
+ /* private exponent */
+ mbedtls_asn1_get_mpi(p, end, &ctx->MBEDTLS_CONTEXT_MEMBER(D)) != 0 ||
+ /* primes */
+ mbedtls_asn1_get_mpi(p, end, &ctx->MBEDTLS_CONTEXT_MEMBER(P)) != 0 ||
+ mbedtls_asn1_get_mpi(p, end, &ctx->MBEDTLS_CONTEXT_MEMBER(Q)) != 0) {
+
+ return -3;
+ }
+
+#if !defined(MBEDTLS_RSA_NO_CRT)
+ /*
+ * DP/DQ/QP are only used inside mbedTLS if it was built with the
+ * Chinese Remainder Theorem enabled (default). In case it is disabled
+ * we parse, or if not available, we calculate those values.
+ */
+ if (*p < end) {
+ if ( /* d mod (p-1) and d mod (q-1) */
+ mbedtls_asn1_get_mpi(p, end, &ctx->MBEDTLS_CONTEXT_MEMBER(DP)) != 0 ||
+ mbedtls_asn1_get_mpi(p, end, &ctx->MBEDTLS_CONTEXT_MEMBER(DQ)) != 0 ||
+ /* q ^ (-1) mod p */
+ mbedtls_asn1_get_mpi(p, end, &ctx->MBEDTLS_CONTEXT_MEMBER(QP)) != 0) {
+
+ return -4;
+ }
+ } else {
+ if (mbedtls_rsa_deduce_crt(&ctx->MBEDTLS_CONTEXT_MEMBER(P),
+ &ctx->MBEDTLS_CONTEXT_MEMBER(Q),
+ &ctx->MBEDTLS_CONTEXT_MEMBER(D),
+ &ctx->MBEDTLS_CONTEXT_MEMBER(DP),
+ &ctx->MBEDTLS_CONTEXT_MEMBER(DQ),
+ &ctx->MBEDTLS_CONTEXT_MEMBER(QP)) != 0) {
+ return -5;
+ }
+ }
+#endif /* !MBEDTLS_RSA_NO_CRT */
+
+ ctx->MBEDTLS_CONTEXT_MEMBER(len) = mbedtls_mpi_size(&ctx->MBEDTLS_CONTEXT_MEMBER(N));
+
+ if (mbedtls_rsa_check_privkey(ctx) != 0) {
+ return -6;
+ }
+
+ return 0;
+}
+#endif /* BOOTUTIL_CRYPTO_RSA_CRYPT_ENABLED */
+
+#if defined(BOOTUTIL_CRYPTO_RSA_SIGN_ENABLED)
+/*
+ * Parse a RSA public key with format specified in RFC3447 A.1.1
+ */
+static int
+bootutil_rsa_parse_public_key(bootutil_rsa_context *ctx, uint8_t **p, uint8_t *end)
+{
+ int rc;
+ size_t len;
+
+ if ((rc = mbedtls_asn1_get_tag(p, end, &len,
+ MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
+ return -1;
+ }
+
+ if (*p + len != end) {
+ return -2;
+ }
+
+ if ((rc = mbedtls_asn1_get_mpi(p, end, &ctx->MBEDTLS_CONTEXT_MEMBER(N))) != 0 ||
+ (rc = mbedtls_asn1_get_mpi(p, end, &ctx->MBEDTLS_CONTEXT_MEMBER(E))) != 0) {
+ return -3;
+ }
+
+ ctx->MBEDTLS_CONTEXT_MEMBER(len) = mbedtls_mpi_size(&ctx->MBEDTLS_CONTEXT_MEMBER(N));
+
+ if (*p != end) {
+ return -4;
+ }
+
+ /* The Mbed TLS version is more than 2.6.1 */
+#if MBEDTLS_VERSION_NUMBER > 0x02060100
+ rc = mbedtls_rsa_import(ctx, &ctx->MBEDTLS_CONTEXT_MEMBER(N), NULL,
+ NULL, NULL, &ctx->MBEDTLS_CONTEXT_MEMBER(E));
+ if (rc != 0) {
+ return -5;
+ }
+#endif
+
+ rc = mbedtls_rsa_check_pubkey(ctx);
+ if (rc != 0) {
+ return -6;
+ }
+
+ ctx->MBEDTLS_CONTEXT_MEMBER(len) = mbedtls_mpi_size(&ctx->MBEDTLS_CONTEXT_MEMBER(N));
+
+ return 0;
+}
+
+/* Get the modulus (N) length in bytes */
+static inline size_t bootutil_rsa_get_len(const bootutil_rsa_context *ctx)
+{
+ return mbedtls_rsa_get_len(ctx);
+}
+
+/* Performs modular exponentiation using the public key output = input^E mod N */
+static inline int bootutil_rsa_public(bootutil_rsa_context *ctx, const uint8_t *input, uint8_t *output)
+{
+ return mbedtls_rsa_public(ctx, input, output);
+}
+#endif /* BOOTUTIL_CRYPTO_RSA_SIGN_ENABLED */
+
+#endif /* MCUBOOT_USE_MBED_TLS */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __BOOTUTIL_CRYPTO_RSA_H_ */
diff --git a/boot/bootutil/src/encrypted.c b/boot/bootutil/src/encrypted.c
index fdd9852..82435a4 100644
--- a/boot/bootutil/src/encrypted.c
+++ b/boot/bootutil/src/encrypted.c
@@ -2,7 +2,7 @@
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (c) 2018-2019 JUUL Labs
- * Copyright (c) 2019-2021 Arm Limited
+ * Copyright (c) 2019-2023 Arm Limited
*/
#include "mcuboot_config/mcuboot_config.h"
@@ -13,13 +13,8 @@
#include <string.h>
#if defined(MCUBOOT_ENCRYPT_RSA)
-#include "mbedtls/rsa.h"
-#if MBEDTLS_VERSION_NUMBER >= 0x03000000
-#include "rsa_alt_helpers.h"
-#else
-#include "mbedtls/rsa_internal.h"
-#endif
-#include "mbedtls/asn1.h"
+#define BOOTUTIL_CRYPTO_RSA_CRYPT_ENABLED
+#include "bootutil/crypto/rsa.h"
#endif
#if defined(MCUBOOT_ENCRYPT_KW)
@@ -93,74 +88,6 @@
}
#endif /* MCUBOOT_ENCRYPT_KW */
-#if defined(MCUBOOT_ENCRYPT_RSA)
-static int
-parse_rsa_enckey(mbedtls_rsa_context *ctx, uint8_t **p, uint8_t *end)
-{
- size_t len;
-
- if (mbedtls_asn1_get_tag(p, end, &len,
- MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) != 0) {
- return -1;
- }
-
- if (*p + len != end) {
- return -2;
- }
-
- /* Non-optional fields. */
- if ( /* version */
- mbedtls_asn1_get_int(p, end, &ctx->MBEDTLS_CONTEXT_MEMBER(ver)) != 0 ||
- /* public modulus */
- mbedtls_asn1_get_mpi(p, end, &ctx->MBEDTLS_CONTEXT_MEMBER(N)) != 0 ||
- /* public exponent */
- mbedtls_asn1_get_mpi(p, end, &ctx->MBEDTLS_CONTEXT_MEMBER(E)) != 0 ||
- /* private exponent */
- mbedtls_asn1_get_mpi(p, end, &ctx->MBEDTLS_CONTEXT_MEMBER(D)) != 0 ||
- /* primes */
- mbedtls_asn1_get_mpi(p, end, &ctx->MBEDTLS_CONTEXT_MEMBER(P)) != 0 ||
- mbedtls_asn1_get_mpi(p, end, &ctx->MBEDTLS_CONTEXT_MEMBER(Q)) != 0) {
-
- return -3;
- }
-
-#if !defined(MBEDTLS_RSA_NO_CRT)
- /*
- * DP/DQ/QP are only used inside mbedTLS if it was built with the
- * Chinese Remainder Theorem enabled (default). In case it is disabled
- * we parse, or if not available, we calculate those values.
- */
- if (*p < end) {
- if ( /* d mod (p-1) and d mod (q-1) */
- mbedtls_asn1_get_mpi(p, end, &ctx->MBEDTLS_CONTEXT_MEMBER(DP)) != 0 ||
- mbedtls_asn1_get_mpi(p, end, &ctx->MBEDTLS_CONTEXT_MEMBER(DQ)) != 0 ||
- /* q ^ (-1) mod p */
- mbedtls_asn1_get_mpi(p, end, &ctx->MBEDTLS_CONTEXT_MEMBER(QP)) != 0) {
-
- return -4;
- }
- } else {
- if (mbedtls_rsa_deduce_crt(&ctx->MBEDTLS_CONTEXT_MEMBER(P),
- &ctx->MBEDTLS_CONTEXT_MEMBER(Q),
- &ctx->MBEDTLS_CONTEXT_MEMBER(D),
- &ctx->MBEDTLS_CONTEXT_MEMBER(DP),
- &ctx->MBEDTLS_CONTEXT_MEMBER(DQ),
- &ctx->MBEDTLS_CONTEXT_MEMBER(QP)) != 0) {
- return -5;
- }
- }
-#endif
-
- ctx->MBEDTLS_CONTEXT_MEMBER(len) = mbedtls_mpi_size(&ctx->MBEDTLS_CONTEXT_MEMBER(N));
-
- if (mbedtls_rsa_check_privkey(ctx) != 0) {
- return -6;
- }
-
- return 0;
-}
-#endif
-
#if defined(MCUBOOT_ENCRYPT_EC256)
static const uint8_t ec_pubkey_oid[] = MBEDTLS_OID_EC_ALG_UNRESTRICTED;
static const uint8_t ec_secp256r1_oid[] = MBEDTLS_OID_EC_GRP_SECP256R1;
@@ -460,8 +387,8 @@
"Please fix ECIES-X25519 component indexes");
#endif
-#if defined(MCUBOOT_ENCRYPT_RSA) || \
- (defined(MCUBOOT_ENCRYPT_EC256) && defined(MCUBOOT_USE_MBED_TLS))
+#if ( (defined(MCUBOOT_ENCRYPT_RSA) && defined(MCUBOOT_USE_MBED_TLS) && !defined(MCUBOOT_USE_PSA_CRYPTO)) || \
+ (defined(MCUBOOT_ENCRYPT_EC256) && defined(MCUBOOT_USE_MBED_TLS)) )
#if MBEDTLS_VERSION_NUMBER >= 0x03000000
static int fake_rng(void *p_rng, unsigned char *output, size_t len)
{
@@ -474,9 +401,9 @@
return 0;
}
-#endif
-#endif /* defined(MCUBOOT_ENCRYPT_RSA) ||
- defined(MCUBOOT_ENCRYPT_EC256) && defined(MCUBOOT_USE_MBED_TLS) */
+#endif /* MBEDTLS_VERSION_NUMBER */
+#endif /* (MCUBOOT_ENCRYPT_RSA && MCUBOOT_USE_MBED_TLS && !MCUBOOT_USE_PSA_CRYPTO) ||
+ (MCUBOOT_ENCRYPT_EC256 && MCUBOOT_USE_MBED_TLS) */
/*
* Decrypt an encryption key TLV.
@@ -488,7 +415,7 @@
boot_enc_decrypt(const uint8_t *buf, uint8_t *enckey)
{
#if defined(MCUBOOT_ENCRYPT_RSA)
- mbedtls_rsa_context rsa;
+ bootutil_rsa_context rsa;
uint8_t *cp;
uint8_t *cpend;
size_t olen;
@@ -515,28 +442,22 @@
#if defined(MCUBOOT_ENCRYPT_RSA)
-#if MBEDTLS_VERSION_NUMBER >= 0x03000000
- mbedtls_rsa_init(&rsa);
- mbedtls_rsa_set_padding(&rsa, MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA256);
-#else
- mbedtls_rsa_init(&rsa, MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA256);
-#endif
+ bootutil_rsa_init(&rsa);
cp = (uint8_t *)bootutil_enc_key.key;
cpend = cp + *bootutil_enc_key.len;
- rc = parse_rsa_enckey(&rsa, &cp, cpend);
+ /* The enckey is encrypted through RSA so for decryption we need the private key */
+ rc = bootutil_rsa_parse_private_key(&rsa, &cp, cpend);
if (rc) {
- mbedtls_rsa_free(&rsa);
+ bootutil_rsa_drop(&rsa);
return rc;
}
-#if MBEDTLS_VERSION_NUMBER >= 0x03000000
- rc = mbedtls_rsa_rsaes_oaep_decrypt(&rsa, fake_rng, NULL,
- NULL, 0, &olen, buf, enckey, BOOT_ENC_KEY_SIZE);
-#else
- rc = mbedtls_rsa_rsaes_oaep_decrypt(&rsa, NULL, NULL, MBEDTLS_RSA_PRIVATE,
- NULL, 0, &olen, buf, enckey, BOOT_ENC_KEY_SIZE);
-#endif
- mbedtls_rsa_free(&rsa);
+
+ rc = bootutil_rsa_oaep_decrypt(&rsa, &olen, buf, enckey, BOOT_ENC_KEY_SIZE);
+ bootutil_rsa_drop(&rsa);
+ if (rc) {
+ return rc;
+ }
#endif /* defined(MCUBOOT_ENCRYPT_RSA) */
diff --git a/boot/bootutil/src/image_rsa.c b/boot/bootutil/src/image_rsa.c
index 0e0782b..d3658fb 100644
--- a/boot/bootutil/src/image_rsa.c
+++ b/boot/bootutil/src/image_rsa.c
@@ -3,7 +3,7 @@
*
* Copyright (c) 2017-2018 Linaro LTD
* Copyright (c) 2017-2019 JUUL Labs
- * Copyright (c) 2020-2021 Arm Limited
+ * Copyright (c) 2020-2023 Arm Limited
*
* Original license:
*
@@ -30,20 +30,24 @@
#include "mcuboot_config/mcuboot_config.h"
#ifdef MCUBOOT_SIGN_RSA
-#include "bootutil/sign_key.h"
-#include "bootutil/crypto/sha256.h"
-#include "bootutil/crypto/common.h"
-
-#include "mbedtls/rsa.h"
-#include "mbedtls/asn1.h"
-#include "mbedtls/version.h"
-
#include "bootutil_priv.h"
+#include "bootutil/sign_key.h"
#include "bootutil/fault_injection_hardening.h"
+#define BOOTUTIL_CRYPTO_RSA_SIGN_ENABLED
+#include "bootutil/crypto/rsa.h"
+
+/* PSA Crypto APIs provide an integrated API to perform the verification
+ * while for other crypto backend we need to implement each step at this
+ * abstraction level
+ */
+#if !defined(MCUBOOT_USE_PSA_CRYPTO)
+
+#include "bootutil/crypto/sha256.h"
+
/*
* Constants for this particular constrained implementation of
- * RSA-PSS. In particular, we support RSA 2048, with a SHA256 hash,
+ * RSA-PSS. In particular, we support RSA 2048, with a SHA256 hash,
* and a 32-byte salt. A signature with different parameters will be
* rejected as invalid.
*/
@@ -72,54 +76,6 @@
static const uint8_t pss_zeros[8] = {0};
/*
- * Parse the public key used for signing. Simple RSA format.
- */
-static int
-bootutil_parse_rsakey(mbedtls_rsa_context *ctx, uint8_t **p, uint8_t *end)
-{
- int rc;
- size_t len;
-
- if ((rc = mbedtls_asn1_get_tag(p, end, &len,
- MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
- return -1;
- }
-
- if (*p + len != end) {
- return -2;
- }
-
- if ((rc = mbedtls_asn1_get_mpi(p, end, &ctx->MBEDTLS_CONTEXT_MEMBER(N))) != 0 ||
- (rc = mbedtls_asn1_get_mpi(p, end, &ctx->MBEDTLS_CONTEXT_MEMBER(E))) != 0) {
- return -3;
- }
-
- ctx->MBEDTLS_CONTEXT_MEMBER(len) = mbedtls_mpi_size(&ctx->MBEDTLS_CONTEXT_MEMBER(N));
-
- if (*p != end) {
- return -4;
- }
-
- /* The mbedtls version is more than 2.6.1 */
-#if MBEDTLS_VERSION_NUMBER > 0x02060100
- rc = mbedtls_rsa_import(ctx, &ctx->MBEDTLS_CONTEXT_MEMBER(N), NULL,
- NULL, NULL, &ctx->MBEDTLS_CONTEXT_MEMBER(E));
- if (rc != 0) {
- return -5;
- }
-#endif
-
- rc = mbedtls_rsa_check_pubkey(ctx);
- if (rc != 0) {
- return -6;
- }
-
- ctx->MBEDTLS_CONTEXT_MEMBER(len) = mbedtls_mpi_size(&ctx->MBEDTLS_CONTEXT_MEMBER(N));
-
- return 0;
-}
-
-/*
* Compute the RSA-PSS mask-generation function, MGF1. Assumptions
* are that the mask length will be less than 256 * PSS_HLEN, and
* therefore we never need to increment anything other than the low
@@ -159,11 +115,11 @@
/*
* Validate an RSA signature, using RSA-PSS, as described in PKCS #1
* v2.2, section 9.1.2, with many parameters required to have fixed
- * values.
+ * values. RSASSA-PSS-VERIFY RFC8017 section 8.1.2
*/
static fih_ret
-bootutil_cmp_rsasig(mbedtls_rsa_context *ctx, uint8_t *hash, uint32_t hlen,
- uint8_t *sig)
+bootutil_cmp_rsasig(bootutil_rsa_context *ctx, uint8_t *hash, uint32_t hlen,
+ uint8_t *sig, size_t slen)
{
bootutil_sha256_context shactx;
uint8_t em[MBEDTLS_MPI_MAX_SIZE];
@@ -172,7 +128,8 @@
int i;
FIH_DECLARE(fih_rc, FIH_FAILURE);
- if (ctx->MBEDTLS_CONTEXT_MEMBER(len) != PSS_EMLEN ||
+ /* The caller has already verified that slen == bootutil_rsa_get_len(ctx) */
+ if (slen != PSS_EMLEN ||
PSS_EMLEN > MBEDTLS_MPI_MAX_SIZE) {
goto out;
}
@@ -181,7 +138,8 @@
goto out;
}
- if (mbedtls_rsa_public(ctx, sig, em)) {
+ /* Apply RSAVP1 to produce em = sig^E mod N using the public key */
+ if (bootutil_rsa_public(ctx, sig, em)) {
goto out;
}
@@ -278,34 +236,52 @@
FIH_RET(fih_rc);
}
+#else /* MCUBOOT_USE_PSA_CRYPTO */
+
+static fih_ret
+bootutil_cmp_rsasig(bootutil_rsa_context *ctx, uint8_t *hash, uint32_t hlen,
+ uint8_t *sig, size_t slen)
+{
+ int rc = -1;
+ FIH_DECLARE(fih_rc, FIH_FAILURE);
+
+ /* PSA Crypto APIs allow the verification in a single call */
+ rc = bootutil_rsassa_pss_verify(ctx, hash, hlen, sig, slen);
+
+ fih_rc = fih_ret_encode_zero_equality(rc);
+ if (FIH_NOT_EQ(fih_rc, FIH_SUCCESS)) {
+ FIH_SET(fih_rc, FIH_FAILURE);
+ }
+
+ FIH_RET(fih_rc);
+}
+
+#endif /* MCUBOOT_USE_PSA_CRYPTO */
+
fih_ret
bootutil_verify_sig(uint8_t *hash, uint32_t hlen, uint8_t *sig, size_t slen,
uint8_t key_id)
{
- mbedtls_rsa_context ctx;
+ bootutil_rsa_context ctx;
int rc;
FIH_DECLARE(fih_rc, FIH_FAILURE);
uint8_t *cp;
uint8_t *end;
-#if MBEDTLS_VERSION_NUMBER >= 0x03000000
- mbedtls_rsa_init(&ctx);
-#else
- mbedtls_rsa_init(&ctx, 0, 0);
-#endif
+ bootutil_rsa_init(&ctx);
cp = (uint8_t *)bootutil_keys[key_id].key;
end = cp + *bootutil_keys[key_id].len;
- rc = bootutil_parse_rsakey(&ctx, &cp, end);
- if (rc || slen != ctx.MBEDTLS_CONTEXT_MEMBER(len)) {
- mbedtls_rsa_free(&ctx);
+ /* The key used for signature verification is a public RSA key */
+ rc = bootutil_rsa_parse_public_key(&ctx, &cp, end);
+ if (rc || slen != bootutil_rsa_get_len(&ctx)) {
goto out;
}
- FIH_CALL(bootutil_cmp_rsasig, fih_rc, &ctx, hash, hlen, sig);
+ FIH_CALL(bootutil_cmp_rsasig, fih_rc, &ctx, hash, hlen, sig, slen);
out:
- mbedtls_rsa_free(&ctx);
+ bootutil_rsa_drop(&ctx);
FIH_RET(fih_rc);
}
diff --git a/boot/espressif/include/crypto_config/rsa.cmake b/boot/espressif/include/crypto_config/rsa.cmake
index 01d48f0..ee146cd 100644
--- a/boot/espressif/include/crypto_config/rsa.cmake
+++ b/boot/espressif/include/crypto_config/rsa.cmake
@@ -15,6 +15,7 @@
${MBEDTLS_DIR}/library/rsa.c
${MBEDTLS_DIR}/library/bignum.c
${MBEDTLS_DIR}/library/asn1parse.c
+ ${MBEDTLS_DIR}/library/md.c
${MBEDTLS_DIR}/library/memory_buffer_alloc.c
)
if (DEFINED MBEDTLS_CONFIG_FILE)