Merge patch series "rsa: Add rsa_verify_openssl() to use openssl for host builds"
Paul HENRYS <paul.henrys_ext@softathome.com> says: This serie of patches adds a new tool to authenticate files signed with a preload header. This tool is also used in the tests to actually verify the authenticity of the file signed with such a preload header. Link: https://lore.kernel.org/r/20250224212055.2992852-1-paul.henrys_ext@softathome.com
This commit is contained in:
@@ -3,13 +3,24 @@
|
|||||||
* Copyright (C) 2021 Philippe Reynes <philippe.reynes@softathome.com>
|
* Copyright (C) 2021 Philippe Reynes <philippe.reynes@softathome.com>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#ifdef USE_HOSTCC
|
||||||
|
#include "mkimage.h"
|
||||||
|
#else
|
||||||
#include <asm/global_data.h>
|
#include <asm/global_data.h>
|
||||||
DECLARE_GLOBAL_DATA_PTR;
|
|
||||||
#include <image.h>
|
|
||||||
#include <mapmem.h>
|
#include <mapmem.h>
|
||||||
|
DECLARE_GLOBAL_DATA_PTR;
|
||||||
|
#endif /* !USE_HOSTCC*/
|
||||||
|
|
||||||
|
#include <image.h>
|
||||||
#include <u-boot/sha256.h>
|
#include <u-boot/sha256.h>
|
||||||
|
|
||||||
|
#ifdef USE_HOSTCC
|
||||||
|
/* Define compat stuff for use in tools. */
|
||||||
|
typedef uint8_t u8;
|
||||||
|
typedef uint16_t u16;
|
||||||
|
typedef uint32_t u32;
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Offset of the image
|
* Offset of the image
|
||||||
*
|
*
|
||||||
@@ -17,6 +28,47 @@ DECLARE_GLOBAL_DATA_PTR;
|
|||||||
*/
|
*/
|
||||||
ulong image_load_offset;
|
ulong image_load_offset;
|
||||||
|
|
||||||
|
#ifdef USE_HOSTCC
|
||||||
|
/* Host tools use these implementations to setup information related to the
|
||||||
|
* pre-load signatures
|
||||||
|
*/
|
||||||
|
static struct image_sig_info *host_info;
|
||||||
|
|
||||||
|
#define log_info(fmt, args...) printf(fmt, ##args)
|
||||||
|
#define log_err(fmt, args...) printf(fmt, ##args)
|
||||||
|
|
||||||
|
void image_pre_load_sig_set_info(struct image_sig_info *info)
|
||||||
|
{
|
||||||
|
host_info = info;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function sets a pointer to information for the signature check.
|
||||||
|
* It expects that host_info has been initially provision by the host
|
||||||
|
* application.
|
||||||
|
*
|
||||||
|
* return:
|
||||||
|
* < 0 => an error has occurred
|
||||||
|
* 0 => OK
|
||||||
|
*/
|
||||||
|
static int image_pre_load_sig_setup(struct image_sig_info *info)
|
||||||
|
{
|
||||||
|
if (!info) {
|
||||||
|
log_err("ERROR: info is NULL\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!host_info) {
|
||||||
|
log_err("ERROR: host_info is NULL\n");
|
||||||
|
log_err("ERROR: Set it with image_pre_load_sig_set_info()\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(info, host_info, sizeof(struct image_sig_info));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#else
|
||||||
/*
|
/*
|
||||||
* This function gathers information about the signature check
|
* This function gathers information about the signature check
|
||||||
* that could be done before launching the image.
|
* that could be done before launching the image.
|
||||||
@@ -106,6 +158,7 @@ static int image_pre_load_sig_setup(struct image_sig_info *info)
|
|||||||
out:
|
out:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
#endif /* !USE_HOSTCC */
|
||||||
|
|
||||||
static int image_pre_load_sig_get_magic(ulong addr, u32 *magic)
|
static int image_pre_load_sig_get_magic(ulong addr, u32 *magic)
|
||||||
{
|
{
|
||||||
|
@@ -9,10 +9,11 @@ CONFIG_EFI_LOADER=n
|
|||||||
CONFIG_ANDROID_BOOT_IMAGE=y
|
CONFIG_ANDROID_BOOT_IMAGE=y
|
||||||
CONFIG_TIMESTAMP=y
|
CONFIG_TIMESTAMP=y
|
||||||
CONFIG_FIT=y
|
CONFIG_FIT=y
|
||||||
CONFIG_FIT_SIGNATURE=y
|
|
||||||
CONFIG_BOOTSTD_FULL=n
|
CONFIG_BOOTSTD_FULL=n
|
||||||
CONFIG_BOOTMETH_CROS=n
|
CONFIG_BOOTMETH_CROS=n
|
||||||
CONFIG_BOOTMETH_VBE=n
|
CONFIG_BOOTMETH_VBE=n
|
||||||
|
CONFIG_IMAGE_PRE_LOAD=y
|
||||||
|
CONFIG_IMAGE_PRE_LOAD_SIG=y
|
||||||
CONFIG_USE_BOOTCOMMAND=y
|
CONFIG_USE_BOOTCOMMAND=y
|
||||||
CONFIG_BOOTCOMMAND="run distro_bootcmd"
|
CONFIG_BOOTCOMMAND="run distro_bootcmd"
|
||||||
CONFIG_CMD_BOOTD=n
|
CONFIG_CMD_BOOTD=n
|
||||||
|
@@ -1688,6 +1688,24 @@ struct sig_header_s {
|
|||||||
*/
|
*/
|
||||||
int image_pre_load(ulong addr);
|
int image_pre_load(ulong addr);
|
||||||
|
|
||||||
|
#if defined(USE_HOSTCC)
|
||||||
|
/**
|
||||||
|
* rsa_verify_openssl() - Verify a signature against some data with openssl API
|
||||||
|
*
|
||||||
|
* Verify a RSA PKCS1.5/PSS signature against an expected hash.
|
||||||
|
*
|
||||||
|
* @info: Specifies the key and algorithms
|
||||||
|
* @region: Pointer to the input data
|
||||||
|
* @region_count: Number of region
|
||||||
|
* @sig: Signature
|
||||||
|
* @sig_len: Number of bytes in the signature
|
||||||
|
* Return: 0 if verified, -ve on error
|
||||||
|
*/
|
||||||
|
int rsa_verify_openssl(struct image_sign_info *info,
|
||||||
|
const struct image_region region[], int region_count,
|
||||||
|
uint8_t *sig, uint sig_len);
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fit_image_verify_required_sigs() - Verify signatures marked as 'required'
|
* fit_image_verify_required_sigs() - Verify signatures marked as 'required'
|
||||||
*
|
*
|
||||||
|
@@ -565,6 +565,11 @@ int rsa_verify(struct image_sign_info *info,
|
|||||||
uint8_t hash[info->crypto->key_len];
|
uint8_t hash[info->crypto->key_len];
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
#ifdef USE_HOSTCC
|
||||||
|
if (!info->fdt_blob)
|
||||||
|
return rsa_verify_openssl(info, region, region_count, sig, sig_len);
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Verify that the checksum-length does not exceed the
|
* Verify that the checksum-length does not exceed the
|
||||||
* rsa-signature-length
|
* rsa-signature-length
|
||||||
|
1
tools/.gitignore
vendored
1
tools/.gitignore
vendored
@@ -29,6 +29,7 @@
|
|||||||
/mxsboot
|
/mxsboot
|
||||||
/ncb
|
/ncb
|
||||||
/prelink-riscv
|
/prelink-riscv
|
||||||
|
/preload_check_sign
|
||||||
/printinitialenv
|
/printinitialenv
|
||||||
/proftool
|
/proftool
|
||||||
/relocate-rela
|
/relocate-rela
|
||||||
|
@@ -9,6 +9,11 @@ config MKIMAGE_DTC_PATH
|
|||||||
some cases the system dtc may not support all required features
|
some cases the system dtc may not support all required features
|
||||||
and the path to a different version should be given here.
|
and the path to a different version should be given here.
|
||||||
|
|
||||||
|
config TOOLS_IMAGE_PRE_LOAD
|
||||||
|
def_bool y
|
||||||
|
help
|
||||||
|
Enable pre-load signature support in the tools builds.
|
||||||
|
|
||||||
config TOOLS_CRC16
|
config TOOLS_CRC16
|
||||||
def_bool y
|
def_bool y
|
||||||
help
|
help
|
||||||
|
@@ -66,6 +66,7 @@ mkenvimage-objs := mkenvimage.o os_support.o generated/lib/crc32.o
|
|||||||
hostprogs-y += dumpimage mkimage
|
hostprogs-y += dumpimage mkimage
|
||||||
hostprogs-$(CONFIG_TOOLS_LIBCRYPTO) += fit_info fit_check_sign
|
hostprogs-$(CONFIG_TOOLS_LIBCRYPTO) += fit_info fit_check_sign
|
||||||
hostprogs-$(CONFIG_TOOLS_LIBCRYPTO) += fdt_add_pubkey
|
hostprogs-$(CONFIG_TOOLS_LIBCRYPTO) += fdt_add_pubkey
|
||||||
|
hostprogs-$(CONFIG_TOOLS_LIBCRYPTO) += preload_check_sign
|
||||||
|
|
||||||
ifneq ($(CONFIG_CMD_BOOTEFI_SELFTEST)$(CONFIG_FWU_MDATA_GPT_BLK),)
|
ifneq ($(CONFIG_CMD_BOOTEFI_SELFTEST)$(CONFIG_FWU_MDATA_GPT_BLK),)
|
||||||
hostprogs-y += file2include
|
hostprogs-y += file2include
|
||||||
@@ -89,6 +90,8 @@ ECDSA_OBJS-$(CONFIG_TOOLS_LIBCRYPTO) := $(addprefix generated/lib/ecdsa/, ecdsa-
|
|||||||
AES_OBJS-$(CONFIG_TOOLS_LIBCRYPTO) := $(addprefix generated/lib/aes/, \
|
AES_OBJS-$(CONFIG_TOOLS_LIBCRYPTO) := $(addprefix generated/lib/aes/, \
|
||||||
aes-encrypt.o aes-decrypt.o)
|
aes-encrypt.o aes-decrypt.o)
|
||||||
|
|
||||||
|
PRELOAD_OBJS-$(CONFIG_TOOLS_LIBCRYPTO) := generated/boot/image-pre-load.o
|
||||||
|
|
||||||
# Cryptographic helpers and image types that depend on openssl/libcrypto
|
# Cryptographic helpers and image types that depend on openssl/libcrypto
|
||||||
LIBCRYPTO_OBJS-$(CONFIG_TOOLS_LIBCRYPTO) := \
|
LIBCRYPTO_OBJS-$(CONFIG_TOOLS_LIBCRYPTO) := \
|
||||||
generated/lib/fdt-libcrypto.o \
|
generated/lib/fdt-libcrypto.o \
|
||||||
@@ -158,6 +161,7 @@ fit_info-objs := $(dumpimage-mkimage-objs) fit_info.o
|
|||||||
fit_check_sign-objs := $(dumpimage-mkimage-objs) fit_check_sign.o
|
fit_check_sign-objs := $(dumpimage-mkimage-objs) fit_check_sign.o
|
||||||
fdt_add_pubkey-objs := $(dumpimage-mkimage-objs) fdt_add_pubkey.o
|
fdt_add_pubkey-objs := $(dumpimage-mkimage-objs) fdt_add_pubkey.o
|
||||||
file2include-objs := file2include.o
|
file2include-objs := file2include.o
|
||||||
|
preload_check_sign-objs := $(dumpimage-mkimage-objs) $(PRELOAD_OBJS-y) preload_check_sign.o
|
||||||
|
|
||||||
ifneq ($(CONFIG_MX23)$(CONFIG_MX28)$(CONFIG_TOOLS_LIBCRYPTO),)
|
ifneq ($(CONFIG_MX23)$(CONFIG_MX28)$(CONFIG_TOOLS_LIBCRYPTO),)
|
||||||
# Add CFG_MXS into host CFLAGS, so we can check whether or not register
|
# Add CFG_MXS into host CFLAGS, so we can check whether or not register
|
||||||
@@ -195,6 +199,7 @@ HOSTLDLIBS_dumpimage := $(HOSTLDLIBS_mkimage)
|
|||||||
HOSTLDLIBS_fit_info := $(HOSTLDLIBS_mkimage)
|
HOSTLDLIBS_fit_info := $(HOSTLDLIBS_mkimage)
|
||||||
HOSTLDLIBS_fit_check_sign := $(HOSTLDLIBS_mkimage)
|
HOSTLDLIBS_fit_check_sign := $(HOSTLDLIBS_mkimage)
|
||||||
HOSTLDLIBS_fdt_add_pubkey := $(HOSTLDLIBS_mkimage)
|
HOSTLDLIBS_fdt_add_pubkey := $(HOSTLDLIBS_mkimage)
|
||||||
|
HOSTLDLIBS_preload_check_sign := $(HOSTLDLIBS_mkimage)
|
||||||
|
|
||||||
hostprogs-$(CONFIG_EXYNOS5250) += mkexynosspl
|
hostprogs-$(CONFIG_EXYNOS5250) += mkexynosspl
|
||||||
hostprogs-$(CONFIG_EXYNOS5420) += mkexynosspl
|
hostprogs-$(CONFIG_EXYNOS5420) += mkexynosspl
|
||||||
|
@@ -762,6 +762,16 @@ class TestFunctional(unittest.TestCase):
|
|||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def _CheckPreload(self, image, key, algo="sha256,rsa2048",
|
||||||
|
padding="pkcs-1.5"):
|
||||||
|
try:
|
||||||
|
tools.run('preload_check_sign', '-k', key, '-a', algo, '-p',
|
||||||
|
padding, '-f', image)
|
||||||
|
except:
|
||||||
|
self.fail('Expected image signed with a pre-load')
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
def testRun(self):
|
def testRun(self):
|
||||||
"""Test a basic run with valid args"""
|
"""Test a basic run with valid args"""
|
||||||
result = self._RunBinman('-h')
|
result = self._RunBinman('-h')
|
||||||
@@ -5781,9 +5791,14 @@ fdt fdtmap Extract the devicetree blob from the fdtmap
|
|||||||
data = self._DoReadFileDtb(
|
data = self._DoReadFileDtb(
|
||||||
'230_pre_load.dts', entry_args=entry_args,
|
'230_pre_load.dts', entry_args=entry_args,
|
||||||
extra_indirs=[os.path.join(self._binman_dir, 'test')])[0]
|
extra_indirs=[os.path.join(self._binman_dir, 'test')])[0]
|
||||||
|
|
||||||
|
image_fname = tools.get_output_filename('image.bin')
|
||||||
|
is_signed = self._CheckPreload(image_fname, self.TestFile("dev.key"))
|
||||||
|
|
||||||
self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
|
self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
|
||||||
self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
|
self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
|
||||||
self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
|
self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
|
||||||
|
self.assertEqual(is_signed, True)
|
||||||
|
|
||||||
def testPreLoadNoKey(self):
|
def testPreLoadNoKey(self):
|
||||||
"""Test an image with a pre-load heade0r with missing key"""
|
"""Test an image with a pre-load heade0r with missing key"""
|
||||||
|
@@ -19,6 +19,11 @@
|
|||||||
#include <openssl/evp.h>
|
#include <openssl/evp.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if CONFIG_IS_ENABLED(IMAGE_PRE_LOAD)
|
||||||
|
#include <openssl/rsa.h>
|
||||||
|
#include <openssl/err.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fit_set_hash_value - set hash value in requested has node
|
* fit_set_hash_value - set hash value in requested has node
|
||||||
* @fit: pointer to the FIT format image header
|
* @fit: pointer to the FIT format image header
|
||||||
@@ -1410,3 +1415,139 @@ int fit_check_sign(const void *fit, const void *key,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if CONFIG_IS_ENABLED(IMAGE_PRE_LOAD)
|
||||||
|
/**
|
||||||
|
* rsa_verify_openssl() - Verify a signature against some data with openssl API
|
||||||
|
*
|
||||||
|
* Verify a RSA PKCS1.5/PSS signature against an expected hash.
|
||||||
|
*
|
||||||
|
* @info: Specifies the key and algorithms
|
||||||
|
* @region: Pointer to the input data
|
||||||
|
* @region_count: Number of region
|
||||||
|
* @sig: Signature
|
||||||
|
* @sig_len: Number of bytes in the signature
|
||||||
|
* Return: 0 if verified, -ve on error
|
||||||
|
*/
|
||||||
|
int rsa_verify_openssl(struct image_sign_info *info,
|
||||||
|
const struct image_region region[], int region_count,
|
||||||
|
uint8_t *sig, uint sig_len)
|
||||||
|
{
|
||||||
|
EVP_PKEY *pkey = NULL;
|
||||||
|
EVP_PKEY_CTX *ckey = NULL;
|
||||||
|
EVP_MD_CTX *ctx = NULL;
|
||||||
|
int pad;
|
||||||
|
int size;
|
||||||
|
int i;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (!info) {
|
||||||
|
fprintf(stderr, "No info provided\n");
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!info->key) {
|
||||||
|
fprintf(stderr, "No key provided\n");
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!info->checksum) {
|
||||||
|
fprintf(stderr, "No checksum information\n");
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!info->padding) {
|
||||||
|
fprintf(stderr, "No padding information\n");
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (region_count < 1) {
|
||||||
|
fprintf(stderr, "Invalid value for region_count: %d\n", region_count);
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
pkey = (EVP_PKEY *)info->key;
|
||||||
|
|
||||||
|
ckey = EVP_PKEY_CTX_new(pkey, NULL);
|
||||||
|
if (!ckey) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
fprintf(stderr, "EVK key context setup failed: %s\n",
|
||||||
|
ERR_error_string(ERR_get_error(), NULL));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
size = EVP_PKEY_size(pkey);
|
||||||
|
if (size > sig_len) {
|
||||||
|
fprintf(stderr, "Invalid signature size (%d bytes)\n",
|
||||||
|
size);
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx = EVP_MD_CTX_new();
|
||||||
|
if (!ctx) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
fprintf(stderr, "EVP context creation failed: %s\n",
|
||||||
|
ERR_error_string(ERR_get_error(), NULL));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
EVP_MD_CTX_init(ctx);
|
||||||
|
|
||||||
|
if (EVP_DigestVerifyInit(ctx, &ckey,
|
||||||
|
EVP_get_digestbyname(info->checksum->name),
|
||||||
|
NULL, pkey) <= 0) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
fprintf(stderr, "Verifier setup failed: %s\n",
|
||||||
|
ERR_error_string(ERR_get_error(), NULL));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strcmp(info->padding->name, "pkcs-1.5")) {
|
||||||
|
pad = RSA_PKCS1_PADDING;
|
||||||
|
} else if (!strcmp(info->padding->name, "pss")) {
|
||||||
|
pad = RSA_PKCS1_PSS_PADDING;
|
||||||
|
} else {
|
||||||
|
ret = -ENOMSG;
|
||||||
|
fprintf(stderr, "Unsupported padding: %s\n",
|
||||||
|
info->padding->name);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (EVP_PKEY_CTX_set_rsa_padding(ckey, pad) <= 0) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
fprintf(stderr, "padding setup has failed: %s\n",
|
||||||
|
ERR_error_string(ERR_get_error(), NULL));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i=0 ; i < region_count ; ++i) {
|
||||||
|
if (EVP_DigestVerifyUpdate(ctx, region[i].data,
|
||||||
|
region[i].size) <= 0) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
fprintf(stderr, "Hashing data failed: %s\n",
|
||||||
|
ERR_error_string(ERR_get_error(), NULL));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (EVP_DigestVerifyFinal(ctx, sig, sig_len) <= 0) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
fprintf(stderr, "Verifying digest failed: %s\n",
|
||||||
|
ERR_error_string(ERR_get_error(), NULL));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
if (ctx)
|
||||||
|
EVP_MD_CTX_free(ctx);
|
||||||
|
|
||||||
|
if (ret)
|
||||||
|
fprintf(stderr, "Failed to verify signature\n");
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
@@ -37,6 +37,10 @@ static inline void *map_sysmem(ulong paddr, unsigned long len)
|
|||||||
return (void *)(uintptr_t)paddr;
|
return (void *)(uintptr_t)paddr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void unmap_sysmem(const void *vaddr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
static inline ulong map_to_sysmem(const void *ptr)
|
static inline ulong map_to_sysmem(const void *ptr)
|
||||||
{
|
{
|
||||||
return (ulong)(uintptr_t)ptr;
|
return (ulong)(uintptr_t)ptr;
|
||||||
|
160
tools/preload_check_sign.c
Normal file
160
tools/preload_check_sign.c
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
|
/*
|
||||||
|
* Check a file including a preload header including a signature
|
||||||
|
*
|
||||||
|
* Copyright (c) 2025 Paul HENRYS <paul.henrys_ext@softathome.com>
|
||||||
|
*
|
||||||
|
* Binman makes it possible to generate a preload header signing part or the
|
||||||
|
* complete file. The tool preload_check_sign allows to verify and authenticate
|
||||||
|
* a file starting with a preload header.
|
||||||
|
*/
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <openssl/pem.h>
|
||||||
|
#include <openssl/evp.h>
|
||||||
|
#include <openssl/err.h>
|
||||||
|
#include <image.h>
|
||||||
|
|
||||||
|
extern void image_pre_load_sig_set_info(struct image_sig_info *info);
|
||||||
|
extern int image_pre_load_sig(ulong addr);
|
||||||
|
|
||||||
|
static void usage(char *cmdname)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Usage: %s -f file -k PEM key file\n"
|
||||||
|
" -f ==> set file which should be checked\n"
|
||||||
|
" -k ==> PEM key file\n"
|
||||||
|
" -a ==> algo (default: sha256,rsa2048)\n"
|
||||||
|
" -p ==> padding (default: pkcs-1.5)\n"
|
||||||
|
" -h ==> help\n",
|
||||||
|
cmdname);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
char cmdname[256];
|
||||||
|
char *file = NULL;
|
||||||
|
char *keyfile = NULL;
|
||||||
|
int c;
|
||||||
|
FILE *fp = NULL;
|
||||||
|
FILE *fp_key = NULL;
|
||||||
|
size_t bytes;
|
||||||
|
long filesize;
|
||||||
|
void *buffer = NULL;
|
||||||
|
EVP_PKEY *pkey = NULL;
|
||||||
|
char *algo = "sha256,rsa2048";
|
||||||
|
char *padding = "pkcs-1.5";
|
||||||
|
struct image_sig_info info = {0};
|
||||||
|
|
||||||
|
strncpy(cmdname, *argv, sizeof(cmdname) - 1);
|
||||||
|
cmdname[sizeof(cmdname) - 1] = '\0';
|
||||||
|
while ((c = getopt(argc, argv, "f:k:a:p:h")) != -1)
|
||||||
|
switch (c) {
|
||||||
|
case 'f':
|
||||||
|
file = optarg;
|
||||||
|
break;
|
||||||
|
case 'k':
|
||||||
|
keyfile = optarg;
|
||||||
|
break;
|
||||||
|
case 'a':
|
||||||
|
algo = optarg;
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
padding = optarg;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage(cmdname);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!file) {
|
||||||
|
fprintf(stderr, "%s: Missing file\n", *argv);
|
||||||
|
usage(*argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!keyfile) {
|
||||||
|
fprintf(stderr, "%s: Missing key file\n", *argv);
|
||||||
|
usage(*argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
fp = fopen(file, "r");
|
||||||
|
if (!fp) {
|
||||||
|
fprintf(stderr, "Error opening file: %s\n", file);
|
||||||
|
ret = EXIT_FAILURE;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
fseek(fp, 0, SEEK_END);
|
||||||
|
filesize = ftell(fp);
|
||||||
|
rewind(fp);
|
||||||
|
|
||||||
|
buffer = malloc(filesize);
|
||||||
|
if (!buffer) {
|
||||||
|
fprintf(stderr, "Memory allocation failed");
|
||||||
|
ret = EXIT_FAILURE;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes = fread(buffer, 1, filesize, fp);
|
||||||
|
if (bytes != filesize) {
|
||||||
|
fprintf(stderr, "Error reading file\n");
|
||||||
|
ret = EXIT_FAILURE;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
fp_key = fopen(keyfile, "r");
|
||||||
|
if (!fp_key) {
|
||||||
|
fprintf(stderr, "Error opening file: %s\n", keyfile);
|
||||||
|
ret = EXIT_FAILURE;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Attempt to read the private key */
|
||||||
|
pkey = PEM_read_PrivateKey(fp_key, NULL, NULL, NULL);
|
||||||
|
if (!pkey) {
|
||||||
|
/* If private key reading fails, try reading as a public key */
|
||||||
|
fseek(fp_key, 0, SEEK_SET);
|
||||||
|
pkey = PEM_read_PUBKEY(fp_key, NULL, NULL, NULL);
|
||||||
|
}
|
||||||
|
if (!pkey) {
|
||||||
|
fprintf(stderr, "Unable to retrieve the public key: %s\n",
|
||||||
|
ERR_error_string(ERR_get_error(), NULL));
|
||||||
|
ret = EXIT_FAILURE;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
info.algo_name = algo;
|
||||||
|
info.padding_name = padding;
|
||||||
|
info.key = (uint8_t *)pkey;
|
||||||
|
info.mandatory = 1;
|
||||||
|
info.sig_size = EVP_PKEY_size(pkey);
|
||||||
|
if (info.sig_size < 0) {
|
||||||
|
fprintf(stderr, "Fail to retrieve the signature size: %s\n",
|
||||||
|
ERR_error_string(ERR_get_error(), NULL));
|
||||||
|
ret = EXIT_FAILURE;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compute signature information */
|
||||||
|
info.sig_info.name = info.algo_name;
|
||||||
|
info.sig_info.padding = image_get_padding_algo(info.padding_name);
|
||||||
|
info.sig_info.checksum = image_get_checksum_algo(info.sig_info.name);
|
||||||
|
info.sig_info.crypto = image_get_crypto_algo(info.sig_info.name);
|
||||||
|
info.sig_info.key = info.key;
|
||||||
|
info.sig_info.keylen = info.key_len;
|
||||||
|
|
||||||
|
/* Check the signature */
|
||||||
|
image_pre_load_sig_set_info(&info);
|
||||||
|
ret = image_pre_load_sig((ulong)buffer);
|
||||||
|
out:
|
||||||
|
if (fp)
|
||||||
|
fclose(fp);
|
||||||
|
if (fp_key)
|
||||||
|
fclose(fp_key);
|
||||||
|
if (info.key)
|
||||||
|
EVP_PKEY_free(pkey);
|
||||||
|
free(buffer);
|
||||||
|
|
||||||
|
exit(ret);
|
||||||
|
}
|
Reference in New Issue
Block a user