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:
Tom Rini 2022-05-08 11:31:48 -04:00
commit 20cd58479f
14 changed files with 388 additions and 171 deletions

View File

@ -21,7 +21,7 @@ include include/host_arch.h
ifeq ("", "$(CROSS_COMPILE)") ifeq ("", "$(CROSS_COMPILE)")
MK_ARCH="${shell uname -m}" MK_ARCH="${shell uname -m}"
else 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 endif
unexport HOST_ARCH unexport HOST_ARCH
ifeq ("x86_64", $(MK_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) export HOST_ARCH=$(HOST_ARCH_X86)
else ifneq (,$(findstring $(MK_ARCH), "aarch64" "armv8l")) else ifneq (,$(findstring $(MK_ARCH), "aarch64" "armv8l"))
export HOST_ARCH=$(HOST_ARCH_AARCH64) 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) export HOST_ARCH=$(HOST_ARCH_ARM)
else ifeq ("riscv32", $(MK_ARCH)) else ifeq ("riscv32", $(MK_ARCH))
export HOST_ARCH=$(HOST_ARCH_RISCV32) export HOST_ARCH=$(HOST_ARCH_RISCV32)

View File

@ -51,21 +51,6 @@ struct bootmenu_entry {
struct bootmenu_entry *next; /* next menu entry (num+1) */ 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) static char *bootmenu_getoption(unsigned short int n)
{ {
char name[MAX_ENV_SIZE]; char name[MAX_ENV_SIZE];
@ -97,132 +82,6 @@ static void bootmenu_print_entry(void *data)
puts(ANSI_COLOR_RESET); 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) static char *bootmenu_choice_entry(void *data)
{ {
struct bootmenu_data *menu = data; struct bootmenu_data *menu = data;

View File

@ -4,11 +4,14 @@
* Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved. * Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved.
*/ */
#include <ansi.h>
#include <common.h> #include <common.h>
#include <cli.h> #include <cli.h>
#include <malloc.h> #include <malloc.h>
#include <errno.h> #include <errno.h>
#include <linux/delay.h>
#include <linux/list.h> #include <linux/list.h>
#include <watchdog.h>
#include "menu.h" #include "menu.h"
@ -421,3 +424,128 @@ int menu_destroy(struct menu *m)
return 1; 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;
}

View File

@ -53,6 +53,10 @@ Parse image file as type.
Pass \-h as the image to see the list of supported image type. Pass \-h as the image to see the list of supported image type.
Without this option image type is autodetected. Without this option image type is autodetected.
.TP
.BI "\-q"
Quiet. Don't print the image header on successful verification.
.P .P
.B Create old legacy image: .B Create old legacy image:
@ -91,6 +95,11 @@ List the contents of an image.
.BI "\-n [" "image name" "]" .BI "\-n [" "image name" "]"
Set image name to '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 .TP
.BI "\-d [" "image data file" "]" .BI "\-d [" "image data file" "]"
Use image data from 'image data file'. Use image data from 'image data file'.
@ -99,6 +108,15 @@ Use image data from 'image data file'.
.BI "\-x" .BI "\-x"
Set XIP (execute in place) flag. 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 .P
.B Create FIT image: .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) A 'data-offset' of 0 indicates that it starts in the first (4-byte aligned)
byte after the FIT. 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 .TP
.BI "\-f [" "image tree source file" " | " "auto" "]" .BI "\-f [" "image tree source file" " | " "auto" "]"
Image tree source file that describes the structure and contents of the 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 verification. Typically the file here is the device tree binary used by
CONFIG_OF_CONTROL in U-Boot. 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 .TP
.BI "\-o [" "signing algorithm" "]" .BI "\-o [" "signing algorithm" "]"
Specifies the algorithm to be used for signing a FIT image. The default is 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. use 'data-position' as the absolute position from the base of the FIT.
.TP .TP
.BI "\-r .BI "\-r"
Specifies that keys used to sign the FIT are required. This means that they 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 must be verified for the image to boot. Without this option, the verification
will be optional (useful for testing but not for release). 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 .TP
.BI "\-t .BI "\-t
Update the timestamp in the FIT. Update the timestamp in the FIT.

View File

@ -1873,6 +1873,12 @@ struct efi_system_resource_table {
#define EFI_CERT_X509_SHA256_GUID \ #define EFI_CERT_X509_SHA256_GUID \
EFI_GUID(0x3bd2a492, 0x96c0, 0x4079, 0xb4, 0x20, \ EFI_GUID(0x3bd2a492, 0x96c0, 0x4079, 0xb4, 0x20, \
0xfc, 0xf9, 0x8e, 0xf1, 0x03, 0xed) 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 \ #define EFI_CERT_TYPE_PKCS7_GUID \
EFI_GUID(0x4aafd29d, 0x68df, 0x49ee, 0x8a, 0xa9, \ EFI_GUID(0x4aafd29d, 0x68df, 0x49ee, 0x8a, 0xa9, \
0x34, 0x7d, 0x37, 0x56, 0x65, 0xa7) 0x34, 0x7d, 0x37, 0x56, 0x65, 0xa7)

View File

@ -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_sha256;
extern const efi_guid_t efi_guid_cert_x509; 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_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; extern const efi_guid_t efi_guid_cert_type_pkcs7;
/* GUID of RNG protocol */ /* 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 */ /* get a device path from a Boot#### option */
struct efi_device_path *efi_get_dp_from_boot(const efi_guid_t guid); 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 * efi_size_in_pages() - convert size in bytes to size in pages
* *

View File

@ -35,4 +35,24 @@ int menu_default_choice(struct menu *m, void **choice);
*/ */
int menu_show(int bootdelay); 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__ */ #endif /* __MENU_H__ */

View File

@ -16,6 +16,7 @@ config EFI_LOADER
default y if !ARM || SYS_CPU = armv7 || SYS_CPU = armv8 default y if !ARM || SYS_CPU = armv7 || SYS_CPU = armv8
select CHARSET select CHARSET
select DM_EVENT select DM_EVENT
select EVENT
select EVENT_DYNAMIC select EVENT_DYNAMIC
select LIB_UUID select LIB_UUID
imply PARTITION_UUIDS imply PARTITION_UUIDS

View File

@ -92,3 +92,69 @@ err:
free(var_value); free(var_value);
return NULL; 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;
}

View File

@ -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_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 = 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_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; const efi_guid_t efi_guid_cert_type_pkcs7 = EFI_CERT_TYPE_PKCS7_GUID;
static u8 pkcs7_hdr[] = { 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 * Return: true on success, false on error
*/ */
static bool efi_hash_regions(struct image_region *regs, int count, 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) { if (!*hash) {
*hash = calloc(1, SHA256_SUM_LEN); *hash = calloc(1, hash_len);
if (!*hash) { if (!*hash) {
EFI_PRINT("Out of memory\n"); EFI_PRINT("Out of memory\n");
return false; 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 #ifdef DEBUG
EFI_PRINT("hash calculated:\n"); EFI_PRINT("hash calculated:\n");
print_hex_dump(" ", DUMP_PREFIX_OFFSET, 16, 1, print_hex_dump(" ", DUMP_PREFIX_OFFSET, 16, 1,
*hash, SHA256_SUM_LEN, false); *hash, hash_len, false);
#endif #endif
return true; return true;
@ -190,7 +204,6 @@ bool efi_signature_lookup_digest(struct efi_image_regions *regs,
struct efi_signature_store *siglist; struct efi_signature_store *siglist;
struct efi_sig_data *sig_data; struct efi_sig_data *sig_data;
void *hash = NULL; void *hash = NULL;
size_t size = 0;
bool found = false; bool found = false;
bool hash_done = false; bool hash_done = false;
@ -200,6 +213,8 @@ bool efi_signature_lookup_digest(struct efi_image_regions *regs,
goto out; goto out;
for (siglist = db; siglist; siglist = siglist->next) { 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 * if the hash algorithm is unsupported and we get an entry in
* dbx reject the image * 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)) if (guidcmp(&siglist->sig_type, &efi_guid_sha256))
continue; 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 && 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"); EFI_PRINT("Digesting an image failed\n");
break; break;
} }
@ -229,8 +250,8 @@ bool efi_signature_lookup_digest(struct efi_image_regions *regs,
print_hex_dump(" ", DUMP_PREFIX_OFFSET, 16, 1, print_hex_dump(" ", DUMP_PREFIX_OFFSET, 16, 1,
sig_data->data, sig_data->size, false); sig_data->data, sig_data->size, false);
#endif #endif
if (sig_data->size == size && if (sig_data->size == len &&
!memcmp(sig_data->data, hash, size)) { !memcmp(sig_data->data, hash, len)) {
found = true; found = true;
free(hash); free(hash);
goto out; goto out;
@ -263,8 +284,9 @@ static bool efi_lookup_certificate(struct x509_certificate *cert,
struct efi_sig_data *sig_data; struct efi_sig_data *sig_data;
struct image_region reg[1]; struct image_region reg[1];
void *hash = NULL, *hash_tmp = NULL; void *hash = NULL, *hash_tmp = NULL;
size_t size = 0; int len = 0;
bool found = false; bool found = false;
const char *hash_algo = NULL;
EFI_PRINT("%s: Enter, %p, %p\n", __func__, cert, db); 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 */ /* calculate hash of TBSCertificate */
reg[0].data = cert->tbs; reg[0].data = cert->tbs;
reg[0].size = cert->tbs_size; 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; goto out;
EFI_PRINT("%s: searching for %s\n", __func__, cert->subject); 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); cert_tmp->subject);
reg[0].data = cert_tmp->tbs; reg[0].data = cert_tmp->tbs;
reg[0].size = cert_tmp->tbs_size; 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; goto out;
x509_free_certificate(cert_tmp); x509_free_certificate(cert_tmp);
if (!memcmp(hash, hash_tmp, size)) { if (!memcmp(hash, hash_tmp, len)) {
found = true; found = true;
goto out; goto out;
} }
@ -400,9 +426,10 @@ static bool efi_signature_check_revocation(struct pkcs7_signed_info *sinfo,
struct efi_sig_data *sig_data; struct efi_sig_data *sig_data;
struct image_region reg[1]; struct image_region reg[1];
void *hash = NULL; void *hash = NULL;
size_t size = 0; int len = 0;
time64_t revoc_time; time64_t revoc_time;
bool revoked = false; bool revoked = false;
const char *hash_algo = NULL;
EFI_PRINT("%s: Enter, %p, %p, %p\n", __func__, sinfo, cert, dbx); 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); EFI_PRINT("Checking revocation against %s\n", cert->subject);
for (siglist = dbx; siglist; siglist = siglist->next) { 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; continue;
/* calculate hash of TBSCertificate */ /* calculate hash of TBSCertificate */
reg[0].data = cert->tbs; reg[0].data = cert->tbs;
reg[0].size = cert->tbs_size; 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; goto out;
for (sig_data = siglist->sig_data_list; sig_data; 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 #ifdef DEBUG
if (sig_data->size >= size) { if (sig_data->size >= len) {
EFI_PRINT("hash in db:\n"); EFI_PRINT("hash in db:\n");
print_hex_dump(" ", DUMP_PREFIX_OFFSET, print_hex_dump(" ", DUMP_PREFIX_OFFSET,
16, 1, 16, 1,
sig_data->data, size, false); sig_data->data, len, false);
} }
#endif #endif
if ((sig_data->size < size + sizeof(time64_t)) || if ((sig_data->size < len + sizeof(time64_t)) ||
memcmp(sig_data->data, hash, size)) memcmp(sig_data->data, hash, len))
continue; continue;
memcpy(&revoc_time, sig_data->data + size, memcpy(&revoc_time, sig_data->data + len,
sizeof(revoc_time)); sizeof(revoc_time));
EFI_PRINT("revocation time: 0x%llx\n", 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 && if (!msg->data &&
!efi_hash_regions(regs->reg, regs->num, !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"); EFI_PRINT("Digesting an image failed\n");
goto out; goto out;
} }

View File

@ -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' 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), % (mnt_point, EFITOOLS_PATH, GUID, EFITOOLS_PATH),
shell=True) 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) # 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' 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), % (mnt_point, EFITOOLS_PATH, GUID, EFITOOLS_PATH),

View File

@ -283,3 +283,54 @@ class TestEfiSignedImage(object):
'efidebug test bootmgr']) 'efidebug test bootmgr'])
assert '\'HELLO\' failed' in ''.join(output) assert '\'HELLO\' failed' in ''.join(output)
assert 'efi_start_image() returned: 26' 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)

View File

@ -84,7 +84,8 @@ static void usage(const char *msg)
fprintf(stderr, "Error: %s\n", msg); fprintf(stderr, "Error: %s\n", msg);
fprintf(stderr, "Usage: %s [-T type] -l image\n" fprintf(stderr, "Usage: %s [-T type] -l image\n"
" -l ==> list image header information\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); params.cmdname);
fprintf(stderr, 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" " %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" " -a ==> set load address to 'addr' (hex)\n"
" -e ==> set entry point to 'ep' (hex)\n" " -e ==> set entry point to 'ep' (hex)\n"
" -n ==> set image name to 'name'\n" " -n ==> set image name to 'name'\n"
" -R ==> set second image name to 'name'\n"
" -d ==> use image data from 'datafile'\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); params.cmdname);
fprintf(stderr, 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" " %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" " -f => input filename for FIT source\n"
" -i => input filename for ramdisk file\n" " -i => input filename for ramdisk file\n"
" -E => place data outside of the FIT structure\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 #ifdef CONFIG_FIT_SIGNATURE
fprintf(stderr, fprintf(stderr,
"Signing / verified boot options: [-k keydir] [-K dtb] [ -c <comment>] [-p addr] [-r] [-N engine]\n" "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" " -F => re-sign existing FIT image\n"
" -p => place external data at a static position\n" " -p => place external data at a static position\n"
" -r => mark keys used as 'required' in dtb\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 #else
fprintf(stderr, fprintf(stderr,
"Signing / verified boot not supported (CONFIG_FIT_SIGNATURE undefined)\n"); "Signing / verified boot not supported (CONFIG_FIT_SIGNATURE undefined)\n");

View File

@ -4,6 +4,8 @@
* (C) Copyright 2020-2021 Samuel Holland <samuel@sholland.org> * (C) Copyright 2020-2021 Samuel Holland <samuel@sholland.org>
*/ */
#define OPENSSL_API_COMPAT 0x10101000L
#include <assert.h> #include <assert.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
@ -11,6 +13,7 @@
#include <string.h> #include <string.h>
#include <openssl/asn1t.h> #include <openssl/asn1t.h>
#include <openssl/bn.h>
#include <openssl/pem.h> #include <openssl/pem.h>
#include <openssl/rsa.h> #include <openssl/rsa.h>