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/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);
}