mirror of
https://github.com/smaeul/u-boot.git
synced 2025-10-17 14:18:14 +01:00
In case Dcache is enabled while the ECDSA authentication function is called via BootROM ROM API, the MMU tables are set up and the BootROM region is not marked as executable, so an attempt to run code from it results in a hang. Mark the BootROM region as executable as suggested by Patrick to prevent the hang. Reviewed-by: Patrice Chotard <patrice.chotard@foss.st.com> Reviewed-by: Patrick Delaunay <patrick.delaunay@foss.st.com> Signed-off-by: Marek Vasut <marex@denx.de>
107 lines
2.8 KiB
C
107 lines
2.8 KiB
C
// SPDX-License-Identifier: GPL-2.0+
|
|
/*
|
|
* STM32MP ECDSA verification via the ROM API
|
|
*
|
|
* Implements ECDSA signature verification via the STM32MP ROM.
|
|
*/
|
|
#include <asm/system.h>
|
|
#include <dm/device.h>
|
|
#include <linux/types.h>
|
|
#include <u-boot/ecdsa.h>
|
|
#include <crypto/ecdsa-uclass.h>
|
|
#include <linux/libfdt.h>
|
|
#include <dm/platdata.h>
|
|
|
|
#define ROM_API_SUCCESS 0x77
|
|
#define ROM_API_ECDSA_ALGO_PRIME_256V1 1
|
|
#define ROM_API_ECDSA_ALGO_BRAINPOOL_256 2
|
|
|
|
#define ROM_API_OFFSET_ECDSA_VERIFY 0x60
|
|
|
|
struct ecdsa_rom_api {
|
|
uint32_t (*ecdsa_verify_signature)(const void *hash, const void *pubkey,
|
|
const void *signature,
|
|
uint32_t ecc_algo);
|
|
};
|
|
|
|
/*
|
|
* Without forcing the ".data" section, this would get saved in ".bss". BSS
|
|
* will be cleared soon after, so it's not suitable.
|
|
*/
|
|
static uintptr_t rom_api_loc __section(".data");
|
|
|
|
/*
|
|
* The ROM gives us the API location in r0 when starting. This is only available
|
|
* during SPL, as there isn't (yet) a mechanism to pass this on to u-boot.
|
|
*/
|
|
void save_boot_params(unsigned long r0, unsigned long r1, unsigned long r2,
|
|
unsigned long r3)
|
|
{
|
|
rom_api_loc = r0;
|
|
save_boot_params_ret();
|
|
}
|
|
|
|
static void stm32mp_rom_get_ecdsa_functions(struct ecdsa_rom_api *rom)
|
|
{
|
|
uintptr_t verify_ptr = rom_api_loc + ROM_API_OFFSET_ECDSA_VERIFY;
|
|
|
|
rom->ecdsa_verify_signature = *(void **)verify_ptr;
|
|
}
|
|
|
|
static int ecdsa_key_algo(const char *curve_name)
|
|
{
|
|
if (!strcmp(curve_name, "prime256v1"))
|
|
return ROM_API_ECDSA_ALGO_PRIME_256V1;
|
|
else if (!strcmp(curve_name, "brainpool256"))
|
|
return ROM_API_ECDSA_ALGO_BRAINPOOL_256;
|
|
else
|
|
return -ENOPROTOOPT;
|
|
}
|
|
|
|
static int romapi_ecdsa_verify(struct udevice *dev,
|
|
const struct ecdsa_public_key *pubkey,
|
|
const void *hash, size_t hash_len,
|
|
const void *signature, size_t sig_len)
|
|
{
|
|
struct ecdsa_rom_api rom;
|
|
uint8_t raw_key[64];
|
|
uint32_t rom_ret;
|
|
int algo;
|
|
|
|
/* The ROM API can only handle 256-bit ECDSA keys. */
|
|
if (sig_len != 64 || hash_len != 32 || pubkey->size_bits != 256)
|
|
return -EINVAL;
|
|
|
|
algo = ecdsa_key_algo(pubkey->curve_name);
|
|
if (algo < 0)
|
|
return algo;
|
|
|
|
/* The ROM API wants the (X, Y) coordinates concatenated. */
|
|
memcpy(raw_key, pubkey->x, 32);
|
|
memcpy(raw_key + 32, pubkey->y, 32);
|
|
|
|
stm32mp_rom_get_ecdsa_functions(&rom);
|
|
|
|
/* Mark BootROM region as executable. */
|
|
mmu_set_region_dcache_behaviour(0, SZ_2M, DCACHE_DEFAULT_OPTION);
|
|
|
|
rom_ret = rom.ecdsa_verify_signature(hash, raw_key, signature, algo);
|
|
|
|
return rom_ret == ROM_API_SUCCESS ? 0 : -EPERM;
|
|
}
|
|
|
|
static const struct ecdsa_ops rom_api_ops = {
|
|
.verify = romapi_ecdsa_verify,
|
|
};
|
|
|
|
U_BOOT_DRIVER(stm32mp_rom_api_ecdsa) = {
|
|
.name = "stm32mp_rom_api_ecdsa",
|
|
.id = UCLASS_ECDSA,
|
|
.ops = &rom_api_ops,
|
|
.flags = DM_FLAG_PRE_RELOC,
|
|
};
|
|
|
|
U_BOOT_DRVINFO(stm32mp_rom_api_ecdsa) = {
|
|
.name = "stm32mp_rom_api_ecdsa",
|
|
};
|