mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-10 15:14:43 +00:00
Pull request for efi-2022-07-rc3-2
UEFI: * Fix build errors due to - using sed with non-standard extension for regular expression - target architecture not recognized for CROSS_COMPILE=armv7a-* - CONFIG_EVENT not selected * add sha384/512 on certificate revocation Others: * factor out the user input handling in bootmenu command -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEbcT5xx8ppvoGt20zxIHbvCwFGsQFAmJ3Z5kACgkQxIHbvCwF GsRXYA/+KxXQaYm++hkoc+WVyU7CnqQrb6pFkT60taGuqkTORwyPk+faWGZpeewf JuTJ5GssVjS1Vo+rU1zpPJxHLlGz9JGx3txiGadHHnsKVDeQdN6vB2Jb2uIp6xMN Z0LmFroTrNrUO6ymxqm0mi6rc/BV7iBNoR1TWxDOk+l68O3mpgJPnxnG0mxncThN qxas2pVxlt1B60ri3KRdpR9Li2KF36apVsw5J+Pqrrv4MiEAC8Fr/l5TRMiHJoSr /C1j704epoGqQMdpX+xLSykEhpZQ0RkVAUf3hcINPJxYYHRvQ4Qwk17yzqOlX8TV EOWob0v9Tr/wkFDFFBOdTl1ByVixENU/Sk/2F1olN+9nlMLlTrmaDTuNXh6Fv81q 587fZ5bNI56PYmGWRS+p4YvQhKlZxVcpUiKVzopApPx+i0J101TlKs7OenLNKWnC LaWkcly1QH5yaJwTI8qZOnA8tLAfkzPjODQfpnCvsiB7w26ZFBjuaLDgtzkSmLAN 07zHsrygesblmG3EfM7dJlIMNXYNWapZW+7BiTgH/f7KIqocjZt6qGY7sroHk1RY NJWwLCzv5TqoxL+HumDFmCRZbfBJbBeiEKs5x4EfrOeSHrXcuR4QJB0ScDlUtT5l eNp0Sn4lK5EhgXSeraiBkQVmca0rvCGEwbR4bV0832wZL2lqBqk= =Kdu1 -----END PGP SIGNATURE----- Merge tag 'efi-2022-07-rc3-2' of https://source.denx.de/u-boot/custodians/u-boot-efi Pull request for efi-2022-07-rc3-2 UEFI: * Fix build errors due to - using sed with non-standard extension for regular expression - target architecture not recognized for CROSS_COMPILE=armv7a-* - CONFIG_EVENT not selected * add sha384/512 on certificate revocation Others: * factor out the user input handling in bootmenu command
This commit is contained in:
commit
20cd58479f
14 changed files with 388 additions and 171 deletions
4
Makefile
4
Makefile
|
@ -21,7 +21,7 @@ include include/host_arch.h
|
|||
ifeq ("", "$(CROSS_COMPILE)")
|
||||
MK_ARCH="${shell uname -m}"
|
||||
else
|
||||
MK_ARCH="${shell echo $(CROSS_COMPILE) | sed -n 's/^\s*\([^\/]*\/\)*\([^-]*\)-\S*/\2/p'}"
|
||||
MK_ARCH="${shell echo $(CROSS_COMPILE) | sed -n 's/^[[:space:]]*\([^\/]*\/\)*\([^-]*\)-[^[:space:]]*/\2/p'}"
|
||||
endif
|
||||
unexport HOST_ARCH
|
||||
ifeq ("x86_64", $(MK_ARCH))
|
||||
|
@ -30,7 +30,7 @@ else ifneq (,$(findstring $(MK_ARCH), "i386" "i486" "i586" "i686"))
|
|||
export HOST_ARCH=$(HOST_ARCH_X86)
|
||||
else ifneq (,$(findstring $(MK_ARCH), "aarch64" "armv8l"))
|
||||
export HOST_ARCH=$(HOST_ARCH_AARCH64)
|
||||
else ifneq (,$(findstring $(MK_ARCH), "arm" "armv7" "armv7l"))
|
||||
else ifneq (,$(findstring $(MK_ARCH), "arm" "armv7" "armv7a" "armv7l"))
|
||||
export HOST_ARCH=$(HOST_ARCH_ARM)
|
||||
else ifeq ("riscv32", $(MK_ARCH))
|
||||
export HOST_ARCH=$(HOST_ARCH_RISCV32)
|
||||
|
|
141
cmd/bootmenu.c
141
cmd/bootmenu.c
|
@ -51,21 +51,6 @@ struct bootmenu_entry {
|
|||
struct bootmenu_entry *next; /* next menu entry (num+1) */
|
||||
};
|
||||
|
||||
struct bootmenu_data {
|
||||
int delay; /* delay for autoboot */
|
||||
int active; /* active menu entry */
|
||||
int count; /* total count of menu entries */
|
||||
struct bootmenu_entry *first; /* first menu entry */
|
||||
};
|
||||
|
||||
enum bootmenu_key {
|
||||
KEY_NONE = 0,
|
||||
KEY_UP,
|
||||
KEY_DOWN,
|
||||
KEY_SELECT,
|
||||
KEY_QUIT,
|
||||
};
|
||||
|
||||
static char *bootmenu_getoption(unsigned short int n)
|
||||
{
|
||||
char name[MAX_ENV_SIZE];
|
||||
|
@ -97,132 +82,6 @@ static void bootmenu_print_entry(void *data)
|
|||
puts(ANSI_COLOR_RESET);
|
||||
}
|
||||
|
||||
static void bootmenu_autoboot_loop(struct bootmenu_data *menu,
|
||||
enum bootmenu_key *key, int *esc)
|
||||
{
|
||||
int i, c;
|
||||
|
||||
while (menu->delay > 0) {
|
||||
printf(ANSI_CURSOR_POSITION, menu->count + 5, 3);
|
||||
printf("Hit any key to stop autoboot: %d ", menu->delay);
|
||||
for (i = 0; i < 100; ++i) {
|
||||
if (!tstc()) {
|
||||
WATCHDOG_RESET();
|
||||
mdelay(10);
|
||||
continue;
|
||||
}
|
||||
|
||||
menu->delay = -1;
|
||||
c = getchar();
|
||||
|
||||
switch (c) {
|
||||
case '\e':
|
||||
*esc = 1;
|
||||
*key = KEY_NONE;
|
||||
break;
|
||||
case '\r':
|
||||
*key = KEY_SELECT;
|
||||
break;
|
||||
case 0x3: /* ^C */
|
||||
*key = KEY_QUIT;
|
||||
break;
|
||||
default:
|
||||
*key = KEY_NONE;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (menu->delay < 0)
|
||||
break;
|
||||
|
||||
--menu->delay;
|
||||
}
|
||||
|
||||
printf(ANSI_CURSOR_POSITION, menu->count + 5, 1);
|
||||
puts(ANSI_CLEAR_LINE);
|
||||
|
||||
if (menu->delay == 0)
|
||||
*key = KEY_SELECT;
|
||||
}
|
||||
|
||||
static void bootmenu_loop(struct bootmenu_data *menu,
|
||||
enum bootmenu_key *key, int *esc)
|
||||
{
|
||||
int c;
|
||||
|
||||
if (*esc == 1) {
|
||||
if (tstc()) {
|
||||
c = getchar();
|
||||
} else {
|
||||
WATCHDOG_RESET();
|
||||
mdelay(10);
|
||||
if (tstc())
|
||||
c = getchar();
|
||||
else
|
||||
c = '\e';
|
||||
}
|
||||
} else {
|
||||
while (!tstc()) {
|
||||
WATCHDOG_RESET();
|
||||
mdelay(10);
|
||||
}
|
||||
c = getchar();
|
||||
}
|
||||
|
||||
switch (*esc) {
|
||||
case 0:
|
||||
/* First char of ANSI escape sequence '\e' */
|
||||
if (c == '\e') {
|
||||
*esc = 1;
|
||||
*key = KEY_NONE;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
/* Second char of ANSI '[' */
|
||||
if (c == '[') {
|
||||
*esc = 2;
|
||||
*key = KEY_NONE;
|
||||
} else {
|
||||
/* Alone ESC key was pressed */
|
||||
*key = KEY_QUIT;
|
||||
*esc = (c == '\e') ? 1 : 0;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
/* Third char of ANSI (number '1') - optional */
|
||||
if (*esc == 2 && c == '1') {
|
||||
*esc = 3;
|
||||
*key = KEY_NONE;
|
||||
break;
|
||||
}
|
||||
|
||||
*esc = 0;
|
||||
|
||||
/* ANSI 'A' - key up was pressed */
|
||||
if (c == 'A')
|
||||
*key = KEY_UP;
|
||||
/* ANSI 'B' - key down was pressed */
|
||||
else if (c == 'B')
|
||||
*key = KEY_DOWN;
|
||||
/* other key was pressed */
|
||||
else
|
||||
*key = KEY_NONE;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* enter key was pressed */
|
||||
if (c == '\r')
|
||||
*key = KEY_SELECT;
|
||||
|
||||
/* ^C was pressed */
|
||||
if (c == 0x3)
|
||||
*key = KEY_QUIT;
|
||||
}
|
||||
|
||||
static char *bootmenu_choice_entry(void *data)
|
||||
{
|
||||
struct bootmenu_data *menu = data;
|
||||
|
|
128
common/menu.c
128
common/menu.c
|
@ -4,11 +4,14 @@
|
|||
* Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <ansi.h>
|
||||
#include <common.h>
|
||||
#include <cli.h>
|
||||
#include <malloc.h>
|
||||
#include <errno.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/list.h>
|
||||
#include <watchdog.h>
|
||||
|
||||
#include "menu.h"
|
||||
|
||||
|
@ -421,3 +424,128 @@ int menu_destroy(struct menu *m)
|
|||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void bootmenu_autoboot_loop(struct bootmenu_data *menu,
|
||||
enum bootmenu_key *key, int *esc)
|
||||
{
|
||||
int i, c;
|
||||
|
||||
while (menu->delay > 0) {
|
||||
printf(ANSI_CURSOR_POSITION, menu->count + 5, 3);
|
||||
printf("Hit any key to stop autoboot: %d ", menu->delay);
|
||||
for (i = 0; i < 100; ++i) {
|
||||
if (!tstc()) {
|
||||
WATCHDOG_RESET();
|
||||
mdelay(10);
|
||||
continue;
|
||||
}
|
||||
|
||||
menu->delay = -1;
|
||||
c = getchar();
|
||||
|
||||
switch (c) {
|
||||
case '\e':
|
||||
*esc = 1;
|
||||
*key = KEY_NONE;
|
||||
break;
|
||||
case '\r':
|
||||
*key = KEY_SELECT;
|
||||
break;
|
||||
case 0x3: /* ^C */
|
||||
*key = KEY_QUIT;
|
||||
break;
|
||||
default:
|
||||
*key = KEY_NONE;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (menu->delay < 0)
|
||||
break;
|
||||
|
||||
--menu->delay;
|
||||
}
|
||||
|
||||
printf(ANSI_CURSOR_POSITION ANSI_CLEAR_LINE, menu->count + 5, 1);
|
||||
|
||||
if (menu->delay == 0)
|
||||
*key = KEY_SELECT;
|
||||
}
|
||||
|
||||
void bootmenu_loop(struct bootmenu_data *menu,
|
||||
enum bootmenu_key *key, int *esc)
|
||||
{
|
||||
int c;
|
||||
|
||||
if (*esc == 1) {
|
||||
if (tstc()) {
|
||||
c = getchar();
|
||||
} else {
|
||||
WATCHDOG_RESET();
|
||||
mdelay(10);
|
||||
if (tstc())
|
||||
c = getchar();
|
||||
else
|
||||
c = '\e';
|
||||
}
|
||||
} else {
|
||||
while (!tstc()) {
|
||||
WATCHDOG_RESET();
|
||||
mdelay(10);
|
||||
}
|
||||
c = getchar();
|
||||
}
|
||||
|
||||
switch (*esc) {
|
||||
case 0:
|
||||
/* First char of ANSI escape sequence '\e' */
|
||||
if (c == '\e') {
|
||||
*esc = 1;
|
||||
*key = KEY_NONE;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
/* Second char of ANSI '[' */
|
||||
if (c == '[') {
|
||||
*esc = 2;
|
||||
*key = KEY_NONE;
|
||||
} else {
|
||||
/* Alone ESC key was pressed */
|
||||
*key = KEY_QUIT;
|
||||
*esc = (c == '\e') ? 1 : 0;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
/* Third char of ANSI (number '1') - optional */
|
||||
if (*esc == 2 && c == '1') {
|
||||
*esc = 3;
|
||||
*key = KEY_NONE;
|
||||
break;
|
||||
}
|
||||
|
||||
*esc = 0;
|
||||
|
||||
/* ANSI 'A' - key up was pressed */
|
||||
if (c == 'A')
|
||||
*key = KEY_UP;
|
||||
/* ANSI 'B' - key down was pressed */
|
||||
else if (c == 'B')
|
||||
*key = KEY_DOWN;
|
||||
/* other key was pressed */
|
||||
else
|
||||
*key = KEY_NONE;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* enter key was pressed */
|
||||
if (c == '\r')
|
||||
*key = KEY_SELECT;
|
||||
|
||||
/* ^C was pressed */
|
||||
if (c == 0x3)
|
||||
*key = KEY_QUIT;
|
||||
}
|
||||
|
|
|
@ -53,6 +53,10 @@ Parse image file as type.
|
|||
Pass \-h as the image to see the list of supported image type.
|
||||
Without this option image type is autodetected.
|
||||
|
||||
.TP
|
||||
.BI "\-q"
|
||||
Quiet. Don't print the image header on successful verification.
|
||||
|
||||
.P
|
||||
.B Create old legacy image:
|
||||
|
||||
|
@ -91,6 +95,11 @@ List the contents of an image.
|
|||
.BI "\-n [" "image name" "]"
|
||||
Set image name to 'image name'.
|
||||
|
||||
.TP
|
||||
.BI "\-R [" "secondary image name" "]"
|
||||
Some image types support a second image for additional data. For these types,
|
||||
use \-R to specify this second image.
|
||||
|
||||
.TP
|
||||
.BI "\-d [" "image data file" "]"
|
||||
Use image data from 'image data file'.
|
||||
|
@ -99,6 +108,15 @@ Use image data from 'image data file'.
|
|||
.BI "\-x"
|
||||
Set XIP (execute in place) flag.
|
||||
|
||||
.TP
|
||||
.BI "\-s"
|
||||
Create an image with no data. The header will be created, but the image itself
|
||||
will not contain data (such as U-Boot or any specified kernel).
|
||||
|
||||
.TP
|
||||
.BI "\-v"
|
||||
Verbose. Print file names as they are added to the image.
|
||||
|
||||
.P
|
||||
.B Create FIT image:
|
||||
|
||||
|
@ -126,6 +144,11 @@ in each image will be replaced with 'data-offset' and 'data-size' properties.
|
|||
A 'data-offset' of 0 indicates that it starts in the first (4-byte aligned)
|
||||
byte after the FIT.
|
||||
|
||||
.TP
|
||||
.BI "\-B [" "alignment" "]"
|
||||
The alignment, in hexadecimal, that external data will be aligned to. This
|
||||
option only has an effect when \-E is specified.
|
||||
|
||||
.TP
|
||||
.BI "\-f [" "image tree source file" " | " "auto" "]"
|
||||
Image tree source file that describes the structure and contents of the
|
||||
|
@ -161,6 +184,11 @@ the corresponding public key is written into this file for for run-time
|
|||
verification. Typically the file here is the device tree binary used by
|
||||
CONFIG_OF_CONTROL in U-Boot.
|
||||
|
||||
.TP
|
||||
.BI "\-G [" "key_file" "]"
|
||||
Specifies the private key file to use when signing. This option may be used
|
||||
instead of \-k.
|
||||
|
||||
.TP
|
||||
.BI "\-o [" "signing algorithm" "]"
|
||||
Specifies the algorithm to be used for signing a FIT image. The default is
|
||||
|
@ -173,11 +201,17 @@ a 'data-offset' property defining the offset from the end of the FIT, \-p will
|
|||
use 'data-position' as the absolute position from the base of the FIT.
|
||||
|
||||
.TP
|
||||
.BI "\-r
|
||||
.BI "\-r"
|
||||
Specifies that keys used to sign the FIT are required. This means that they
|
||||
must be verified for the image to boot. Without this option, the verification
|
||||
will be optional (useful for testing but not for release).
|
||||
|
||||
.TP
|
||||
.BI "\-N [" "engine" "]"
|
||||
The openssl engine to use when signing and verifying the image. For a complete list of
|
||||
available engines, refer to
|
||||
.BR engine (1).
|
||||
|
||||
.TP
|
||||
.BI "\-t
|
||||
Update the timestamp in the FIT.
|
||||
|
|
|
@ -1873,6 +1873,12 @@ struct efi_system_resource_table {
|
|||
#define EFI_CERT_X509_SHA256_GUID \
|
||||
EFI_GUID(0x3bd2a492, 0x96c0, 0x4079, 0xb4, 0x20, \
|
||||
0xfc, 0xf9, 0x8e, 0xf1, 0x03, 0xed)
|
||||
#define EFI_CERT_X509_SHA384_GUID \
|
||||
EFI_GUID(0x7076876e, 0x80c2, 0x4ee6, \
|
||||
0xaa, 0xd2, 0x28, 0xb3, 0x49, 0xa6, 0x86, 0x5b)
|
||||
#define EFI_CERT_X509_SHA512_GUID \
|
||||
EFI_GUID(0x446dbf63, 0x2502, 0x4cda, \
|
||||
0xbc, 0xfa, 0x24, 0x65, 0xd2, 0xb0, 0xfe, 0x9d)
|
||||
#define EFI_CERT_TYPE_PKCS7_GUID \
|
||||
EFI_GUID(0x4aafd29d, 0x68df, 0x49ee, 0x8a, 0xa9, \
|
||||
0x34, 0x7d, 0x37, 0x56, 0x65, 0xa7)
|
||||
|
|
|
@ -300,6 +300,8 @@ extern const efi_guid_t efi_guid_image_security_database;
|
|||
extern const efi_guid_t efi_guid_sha256;
|
||||
extern const efi_guid_t efi_guid_cert_x509;
|
||||
extern const efi_guid_t efi_guid_cert_x509_sha256;
|
||||
extern const efi_guid_t efi_guid_cert_x509_sha384;
|
||||
extern const efi_guid_t efi_guid_cert_x509_sha512;
|
||||
extern const efi_guid_t efi_guid_cert_type_pkcs7;
|
||||
|
||||
/* GUID of RNG protocol */
|
||||
|
@ -677,6 +679,10 @@ efi_status_t efi_file_size(struct efi_file_handle *fh, efi_uintn_t *size);
|
|||
/* get a device path from a Boot#### option */
|
||||
struct efi_device_path *efi_get_dp_from_boot(const efi_guid_t guid);
|
||||
|
||||
/* get len, string (used in u-boot crypto from a guid */
|
||||
const char *guid_to_sha_str(const efi_guid_t *guid);
|
||||
int algo_to_len(const char *algo);
|
||||
|
||||
/**
|
||||
* efi_size_in_pages() - convert size in bytes to size in pages
|
||||
*
|
||||
|
|
|
@ -35,4 +35,24 @@ int menu_default_choice(struct menu *m, void **choice);
|
|||
*/
|
||||
int menu_show(int bootdelay);
|
||||
|
||||
struct bootmenu_data {
|
||||
int delay; /* delay for autoboot */
|
||||
int active; /* active menu entry */
|
||||
int count; /* total count of menu entries */
|
||||
struct bootmenu_entry *first; /* first menu entry */
|
||||
};
|
||||
|
||||
enum bootmenu_key {
|
||||
KEY_NONE = 0,
|
||||
KEY_UP,
|
||||
KEY_DOWN,
|
||||
KEY_SELECT,
|
||||
KEY_QUIT,
|
||||
};
|
||||
|
||||
void bootmenu_autoboot_loop(struct bootmenu_data *menu,
|
||||
enum bootmenu_key *key, int *esc);
|
||||
void bootmenu_loop(struct bootmenu_data *menu,
|
||||
enum bootmenu_key *key, int *esc);
|
||||
|
||||
#endif /* __MENU_H__ */
|
||||
|
|
|
@ -16,6 +16,7 @@ config EFI_LOADER
|
|||
default y if !ARM || SYS_CPU = armv7 || SYS_CPU = armv8
|
||||
select CHARSET
|
||||
select DM_EVENT
|
||||
select EVENT
|
||||
select EVENT_DYNAMIC
|
||||
select LIB_UUID
|
||||
imply PARTITION_UUIDS
|
||||
|
|
|
@ -92,3 +92,69 @@ err:
|
|||
free(var_value);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const struct guid_to_hash_map {
|
||||
efi_guid_t guid;
|
||||
const char algo[32];
|
||||
u32 bits;
|
||||
} guid_to_hash[] = {
|
||||
{
|
||||
EFI_CERT_X509_SHA256_GUID,
|
||||
"sha256",
|
||||
SHA256_SUM_LEN * 8,
|
||||
},
|
||||
{
|
||||
EFI_CERT_SHA256_GUID,
|
||||
"sha256",
|
||||
SHA256_SUM_LEN * 8,
|
||||
},
|
||||
{
|
||||
EFI_CERT_X509_SHA384_GUID,
|
||||
"sha384",
|
||||
SHA384_SUM_LEN * 8,
|
||||
},
|
||||
{
|
||||
EFI_CERT_X509_SHA512_GUID,
|
||||
"sha512",
|
||||
SHA512_SUM_LEN * 8,
|
||||
},
|
||||
};
|
||||
|
||||
#define MAX_GUID_TO_HASH_COUNT ARRAY_SIZE(guid_to_hash)
|
||||
|
||||
/** guid_to_sha_str - return the sha string e.g "sha256" for a given guid
|
||||
* used on EFI security databases
|
||||
*
|
||||
* @guid: guid to check
|
||||
*
|
||||
* Return: len or 0 if no match is found
|
||||
*/
|
||||
const char *guid_to_sha_str(const efi_guid_t *guid)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < MAX_GUID_TO_HASH_COUNT; i++) {
|
||||
if (!guidcmp(guid, &guid_to_hash[i].guid))
|
||||
return guid_to_hash[i].algo;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** algo_to_len - return the sha size in bytes for a given string
|
||||
*
|
||||
* @algo: string indicating hashing algorithm to check
|
||||
*
|
||||
* Return: length of hash in bytes or 0 if no match is found
|
||||
*/
|
||||
int algo_to_len(const char *algo)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < MAX_GUID_TO_HASH_COUNT; i++) {
|
||||
if (!strcmp(algo, guid_to_hash[i].algo))
|
||||
return guid_to_hash[i].bits / 8;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -24,6 +24,8 @@ const efi_guid_t efi_guid_sha256 = EFI_CERT_SHA256_GUID;
|
|||
const efi_guid_t efi_guid_cert_rsa2048 = EFI_CERT_RSA2048_GUID;
|
||||
const efi_guid_t efi_guid_cert_x509 = EFI_CERT_X509_GUID;
|
||||
const efi_guid_t efi_guid_cert_x509_sha256 = EFI_CERT_X509_SHA256_GUID;
|
||||
const efi_guid_t efi_guid_cert_x509_sha384 = EFI_CERT_X509_SHA384_GUID;
|
||||
const efi_guid_t efi_guid_cert_x509_sha512 = EFI_CERT_X509_SHA512_GUID;
|
||||
const efi_guid_t efi_guid_cert_type_pkcs7 = EFI_CERT_TYPE_PKCS7_GUID;
|
||||
|
||||
static u8 pkcs7_hdr[] = {
|
||||
|
@ -124,23 +126,35 @@ struct pkcs7_message *efi_parse_pkcs7_header(const void *buf,
|
|||
* Return: true on success, false on error
|
||||
*/
|
||||
static bool efi_hash_regions(struct image_region *regs, int count,
|
||||
void **hash, size_t *size)
|
||||
void **hash, const char *hash_algo, int *len)
|
||||
{
|
||||
int ret, hash_len;
|
||||
|
||||
if (!hash_algo)
|
||||
return false;
|
||||
|
||||
hash_len = algo_to_len(hash_algo);
|
||||
if (!hash_len)
|
||||
return false;
|
||||
|
||||
if (!*hash) {
|
||||
*hash = calloc(1, SHA256_SUM_LEN);
|
||||
*hash = calloc(1, hash_len);
|
||||
if (!*hash) {
|
||||
EFI_PRINT("Out of memory\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (size)
|
||||
*size = SHA256_SUM_LEN;
|
||||
|
||||
hash_calculate("sha256", regs, count, *hash);
|
||||
ret = hash_calculate(hash_algo, regs, count, *hash);
|
||||
if (ret)
|
||||
return false;
|
||||
|
||||
if (len)
|
||||
*len = hash_len;
|
||||
#ifdef DEBUG
|
||||
EFI_PRINT("hash calculated:\n");
|
||||
print_hex_dump(" ", DUMP_PREFIX_OFFSET, 16, 1,
|
||||
*hash, SHA256_SUM_LEN, false);
|
||||
*hash, hash_len, false);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
|
@ -190,7 +204,6 @@ bool efi_signature_lookup_digest(struct efi_image_regions *regs,
|
|||
struct efi_signature_store *siglist;
|
||||
struct efi_sig_data *sig_data;
|
||||
void *hash = NULL;
|
||||
size_t size = 0;
|
||||
bool found = false;
|
||||
bool hash_done = false;
|
||||
|
||||
|
@ -200,6 +213,8 @@ bool efi_signature_lookup_digest(struct efi_image_regions *regs,
|
|||
goto out;
|
||||
|
||||
for (siglist = db; siglist; siglist = siglist->next) {
|
||||
int len = 0;
|
||||
const char *hash_algo = NULL;
|
||||
/*
|
||||
* if the hash algorithm is unsupported and we get an entry in
|
||||
* dbx reject the image
|
||||
|
@ -215,8 +230,14 @@ bool efi_signature_lookup_digest(struct efi_image_regions *regs,
|
|||
if (guidcmp(&siglist->sig_type, &efi_guid_sha256))
|
||||
continue;
|
||||
|
||||
hash_algo = guid_to_sha_str(&efi_guid_sha256);
|
||||
/*
|
||||
* We could check size and hash_algo but efi_hash_regions()
|
||||
* will do that for us
|
||||
*/
|
||||
if (!hash_done &&
|
||||
!efi_hash_regions(regs->reg, regs->num, &hash, &size)) {
|
||||
!efi_hash_regions(regs->reg, regs->num, &hash, hash_algo,
|
||||
&len)) {
|
||||
EFI_PRINT("Digesting an image failed\n");
|
||||
break;
|
||||
}
|
||||
|
@ -229,8 +250,8 @@ bool efi_signature_lookup_digest(struct efi_image_regions *regs,
|
|||
print_hex_dump(" ", DUMP_PREFIX_OFFSET, 16, 1,
|
||||
sig_data->data, sig_data->size, false);
|
||||
#endif
|
||||
if (sig_data->size == size &&
|
||||
!memcmp(sig_data->data, hash, size)) {
|
||||
if (sig_data->size == len &&
|
||||
!memcmp(sig_data->data, hash, len)) {
|
||||
found = true;
|
||||
free(hash);
|
||||
goto out;
|
||||
|
@ -263,8 +284,9 @@ static bool efi_lookup_certificate(struct x509_certificate *cert,
|
|||
struct efi_sig_data *sig_data;
|
||||
struct image_region reg[1];
|
||||
void *hash = NULL, *hash_tmp = NULL;
|
||||
size_t size = 0;
|
||||
int len = 0;
|
||||
bool found = false;
|
||||
const char *hash_algo = NULL;
|
||||
|
||||
EFI_PRINT("%s: Enter, %p, %p\n", __func__, cert, db);
|
||||
|
||||
|
@ -278,7 +300,10 @@ static bool efi_lookup_certificate(struct x509_certificate *cert,
|
|||
/* calculate hash of TBSCertificate */
|
||||
reg[0].data = cert->tbs;
|
||||
reg[0].size = cert->tbs_size;
|
||||
if (!efi_hash_regions(reg, 1, &hash, &size))
|
||||
|
||||
/* We just need any sha256 algo to start the matching */
|
||||
hash_algo = guid_to_sha_str(&efi_guid_sha256);
|
||||
if (!efi_hash_regions(reg, 1, &hash, hash_algo, &len))
|
||||
goto out;
|
||||
|
||||
EFI_PRINT("%s: searching for %s\n", __func__, cert->subject);
|
||||
|
@ -300,12 +325,13 @@ static bool efi_lookup_certificate(struct x509_certificate *cert,
|
|||
cert_tmp->subject);
|
||||
reg[0].data = cert_tmp->tbs;
|
||||
reg[0].size = cert_tmp->tbs_size;
|
||||
if (!efi_hash_regions(reg, 1, &hash_tmp, NULL))
|
||||
if (!efi_hash_regions(reg, 1, &hash_tmp, hash_algo,
|
||||
NULL))
|
||||
goto out;
|
||||
|
||||
x509_free_certificate(cert_tmp);
|
||||
|
||||
if (!memcmp(hash, hash_tmp, size)) {
|
||||
if (!memcmp(hash, hash_tmp, len)) {
|
||||
found = true;
|
||||
goto out;
|
||||
}
|
||||
|
@ -400,9 +426,10 @@ static bool efi_signature_check_revocation(struct pkcs7_signed_info *sinfo,
|
|||
struct efi_sig_data *sig_data;
|
||||
struct image_region reg[1];
|
||||
void *hash = NULL;
|
||||
size_t size = 0;
|
||||
int len = 0;
|
||||
time64_t revoc_time;
|
||||
bool revoked = false;
|
||||
const char *hash_algo = NULL;
|
||||
|
||||
EFI_PRINT("%s: Enter, %p, %p, %p\n", __func__, sinfo, cert, dbx);
|
||||
|
||||
|
@ -411,13 +438,14 @@ static bool efi_signature_check_revocation(struct pkcs7_signed_info *sinfo,
|
|||
|
||||
EFI_PRINT("Checking revocation against %s\n", cert->subject);
|
||||
for (siglist = dbx; siglist; siglist = siglist->next) {
|
||||
if (guidcmp(&siglist->sig_type, &efi_guid_cert_x509_sha256))
|
||||
hash_algo = guid_to_sha_str(&siglist->sig_type);
|
||||
if (!hash_algo)
|
||||
continue;
|
||||
|
||||
/* calculate hash of TBSCertificate */
|
||||
reg[0].data = cert->tbs;
|
||||
reg[0].size = cert->tbs_size;
|
||||
if (!efi_hash_regions(reg, 1, &hash, &size))
|
||||
if (!efi_hash_regions(reg, 1, &hash, hash_algo, &len))
|
||||
goto out;
|
||||
|
||||
for (sig_data = siglist->sig_data_list; sig_data;
|
||||
|
@ -429,18 +457,18 @@ static bool efi_signature_check_revocation(struct pkcs7_signed_info *sinfo,
|
|||
* };
|
||||
*/
|
||||
#ifdef DEBUG
|
||||
if (sig_data->size >= size) {
|
||||
if (sig_data->size >= len) {
|
||||
EFI_PRINT("hash in db:\n");
|
||||
print_hex_dump(" ", DUMP_PREFIX_OFFSET,
|
||||
16, 1,
|
||||
sig_data->data, size, false);
|
||||
sig_data->data, len, false);
|
||||
}
|
||||
#endif
|
||||
if ((sig_data->size < size + sizeof(time64_t)) ||
|
||||
memcmp(sig_data->data, hash, size))
|
||||
if ((sig_data->size < len + sizeof(time64_t)) ||
|
||||
memcmp(sig_data->data, hash, len))
|
||||
continue;
|
||||
|
||||
memcpy(&revoc_time, sig_data->data + size,
|
||||
memcpy(&revoc_time, sig_data->data + len,
|
||||
sizeof(revoc_time));
|
||||
EFI_PRINT("revocation time: 0x%llx\n", revoc_time);
|
||||
/*
|
||||
|
@ -500,7 +528,9 @@ bool efi_signature_verify(struct efi_image_regions *regs,
|
|||
*/
|
||||
if (!msg->data &&
|
||||
!efi_hash_regions(regs->reg, regs->num,
|
||||
(void **)&sinfo->sig->digest, NULL)) {
|
||||
(void **)&sinfo->sig->digest,
|
||||
guid_to_sha_str(&efi_guid_sha256),
|
||||
NULL)) {
|
||||
EFI_PRINT("Digesting an image failed\n");
|
||||
goto out;
|
||||
}
|
||||
|
|
|
@ -80,6 +80,12 @@ def efi_boot_env(request, u_boot_config):
|
|||
check_call('cd %s; %scert-to-efi-hash-list -g %s -t 0 -s 256 db.crt dbx_hash.crl; %ssign-efi-sig-list -t "2020-04-05" -c KEK.crt -k KEK.key dbx dbx_hash.crl dbx_hash.auth'
|
||||
% (mnt_point, EFITOOLS_PATH, GUID, EFITOOLS_PATH),
|
||||
shell=True)
|
||||
check_call('cd %s; %scert-to-efi-hash-list -g %s -t 0 -s 384 db.crt dbx_hash384.crl; %ssign-efi-sig-list -t "2020-04-05" -c KEK.crt -k KEK.key dbx dbx_hash384.crl dbx_hash384.auth'
|
||||
% (mnt_point, EFITOOLS_PATH, GUID, EFITOOLS_PATH),
|
||||
shell=True)
|
||||
check_call('cd %s; %scert-to-efi-hash-list -g %s -t 0 -s 512 db.crt dbx_hash512.crl; %ssign-efi-sig-list -t "2020-04-05" -c KEK.crt -k KEK.key dbx dbx_hash512.crl dbx_hash512.auth'
|
||||
% (mnt_point, EFITOOLS_PATH, GUID, EFITOOLS_PATH),
|
||||
shell=True)
|
||||
# dbx_hash1 (digest of TEST_db1 certificate)
|
||||
check_call('cd %s; %scert-to-efi-hash-list -g %s -t 0 -s 256 db1.crt dbx_hash1.crl; %ssign-efi-sig-list -t "2020-04-06" -c KEK.crt -k KEK.key dbx dbx_hash1.crl dbx_hash1.auth'
|
||||
% (mnt_point, EFITOOLS_PATH, GUID, EFITOOLS_PATH),
|
||||
|
|
|
@ -283,3 +283,54 @@ class TestEfiSignedImage(object):
|
|||
'efidebug test bootmgr'])
|
||||
assert '\'HELLO\' failed' in ''.join(output)
|
||||
assert 'efi_start_image() returned: 26' in ''.join(output)
|
||||
|
||||
def test_efi_signed_image_auth7(self, u_boot_console, efi_boot_env):
|
||||
"""
|
||||
Test Case 7 - Reject images based on the sha384/512 of their x509 cert
|
||||
"""
|
||||
# sha384 of an x509 cert in dbx
|
||||
u_boot_console.restart_uboot()
|
||||
disk_img = efi_boot_env
|
||||
with u_boot_console.log.section('Test Case 7a'):
|
||||
output = u_boot_console.run_command_list([
|
||||
'host bind 0 %s' % disk_img,
|
||||
'fatload host 0:1 4000000 db.auth',
|
||||
'setenv -e -nv -bs -rt -at -i 4000000:$filesize db',
|
||||
'fatload host 0:1 4000000 KEK.auth',
|
||||
'setenv -e -nv -bs -rt -at -i 4000000:$filesize KEK',
|
||||
'fatload host 0:1 4000000 PK.auth',
|
||||
'setenv -e -nv -bs -rt -at -i 4000000:$filesize PK',
|
||||
'fatload host 0:1 4000000 db1.auth',
|
||||
'setenv -e -nv -bs -rt -at -a -i 4000000:$filesize db',
|
||||
'fatload host 0:1 4000000 dbx_hash384.auth',
|
||||
'setenv -e -nv -bs -rt -at -i 4000000:$filesize dbx'])
|
||||
assert 'Failed to set EFI variable' not in ''.join(output)
|
||||
output = u_boot_console.run_command_list([
|
||||
'efidebug boot add -b 1 HELLO host 0:1 /helloworld.efi.signed_2sigs -s ""',
|
||||
'efidebug boot next 1',
|
||||
'efidebug test bootmgr'])
|
||||
assert '\'HELLO\' failed' in ''.join(output)
|
||||
assert 'efi_start_image() returned: 26' in ''.join(output)
|
||||
|
||||
# sha512 of an x509 cert in dbx
|
||||
u_boot_console.restart_uboot()
|
||||
with u_boot_console.log.section('Test Case 7b'):
|
||||
output = u_boot_console.run_command_list([
|
||||
'host bind 0 %s' % disk_img,
|
||||
'fatload host 0:1 4000000 db.auth',
|
||||
'setenv -e -nv -bs -rt -at -i 4000000:$filesize db',
|
||||
'fatload host 0:1 4000000 KEK.auth',
|
||||
'setenv -e -nv -bs -rt -at -i 4000000:$filesize KEK',
|
||||
'fatload host 0:1 4000000 PK.auth',
|
||||
'setenv -e -nv -bs -rt -at -i 4000000:$filesize PK',
|
||||
'fatload host 0:1 4000000 db1.auth',
|
||||
'setenv -e -nv -bs -rt -at -a -i 4000000:$filesize db',
|
||||
'fatload host 0:1 4000000 dbx_hash512.auth',
|
||||
'setenv -e -nv -bs -rt -at -i 4000000:$filesize dbx'])
|
||||
assert 'Failed to set EFI variable' not in ''.join(output)
|
||||
output = u_boot_console.run_command_list([
|
||||
'efidebug boot add -b 1 HELLO host 0:1 /helloworld.efi.signed_2sigs -s ""',
|
||||
'efidebug boot next 1',
|
||||
'efidebug test bootmgr'])
|
||||
assert '\'HELLO\' failed' in ''.join(output)
|
||||
assert 'efi_start_image() returned: 26' in ''.join(output)
|
||||
|
|
|
@ -84,7 +84,8 @@ static void usage(const char *msg)
|
|||
fprintf(stderr, "Error: %s\n", msg);
|
||||
fprintf(stderr, "Usage: %s [-T type] -l image\n"
|
||||
" -l ==> list image header information\n"
|
||||
" -T ==> parse image file as 'type'\n",
|
||||
" -T ==> parse image file as 'type'\n"
|
||||
" -q ==> quiet\n",
|
||||
params.cmdname);
|
||||
fprintf(stderr,
|
||||
" %s [-x] -A arch -O os -T type -C comp -a addr -e ep -n name -d data_file[:data_file...] image\n"
|
||||
|
@ -95,8 +96,11 @@ static void usage(const char *msg)
|
|||
" -a ==> set load address to 'addr' (hex)\n"
|
||||
" -e ==> set entry point to 'ep' (hex)\n"
|
||||
" -n ==> set image name to 'name'\n"
|
||||
" -R ==> set second image name to 'name'\n"
|
||||
" -d ==> use image data from 'datafile'\n"
|
||||
" -x ==> set XIP (execute in place)\n",
|
||||
" -x ==> set XIP (execute in place)\n"
|
||||
" -s ==> create an image with no data\n"
|
||||
" -v ==> verbose\n",
|
||||
params.cmdname);
|
||||
fprintf(stderr,
|
||||
" %s [-D dtc_options] [-f fit-image.its|-f auto|-F] [-b <dtb> [-b <dtb>]] [-E] [-B size] [-i <ramdisk.cpio.gz>] fit-image\n"
|
||||
|
@ -107,7 +111,9 @@ static void usage(const char *msg)
|
|||
" -f => input filename for FIT source\n"
|
||||
" -i => input filename for ramdisk file\n"
|
||||
" -E => place data outside of the FIT structure\n"
|
||||
" -B => align size in hex for FIT structure and header\n");
|
||||
" -B => align size in hex for FIT structure and header\n"
|
||||
" -b => append the device tree binary to the FIT\n"
|
||||
" -t => update the timestamp in the FIT\n");
|
||||
#ifdef CONFIG_FIT_SIGNATURE
|
||||
fprintf(stderr,
|
||||
"Signing / verified boot options: [-k keydir] [-K dtb] [ -c <comment>] [-p addr] [-r] [-N engine]\n"
|
||||
|
@ -118,7 +124,8 @@ static void usage(const char *msg)
|
|||
" -F => re-sign existing FIT image\n"
|
||||
" -p => place external data at a static position\n"
|
||||
" -r => mark keys used as 'required' in dtb\n"
|
||||
" -N => openssl engine to use for signing\n");
|
||||
" -N => openssl engine to use for signing\n"
|
||||
" -o => algorithm to use for signing\n");
|
||||
#else
|
||||
fprintf(stderr,
|
||||
"Signing / verified boot not supported (CONFIG_FIT_SIGNATURE undefined)\n");
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
* (C) Copyright 2020-2021 Samuel Holland <samuel@sholland.org>
|
||||
*/
|
||||
|
||||
#define OPENSSL_API_COMPAT 0x10101000L
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
@ -11,6 +13,7 @@
|
|||
#include <string.h>
|
||||
|
||||
#include <openssl/asn1t.h>
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/rsa.h>
|
||||
|
||||
|
|
Loading…
Reference in a new issue