[PATCH v2 0/9] efi_loader: capsule: improve capsule authentication support

As I proposed and discussed in [1] and [2], I have made a couple of improvements on the current implementation of capsule update in this patch set.
* add signing feature to mkeficapsule * add "--guid" option to mkeficapsule * add man page of mkeficapsule * add pytest for capsule authentication (on sandbox)
NOTE: Due to Ilias's commit[3], we need to have a customized configuration for sandbox to properly set up and run capsule authentication test. See patch#5,#6 and #7.
[1] https://lists.denx.de/pipermail/u-boot/2021-April/447918.html [2] https://lists.denx.de/pipermail/u-boot/2021-July/455292.html [3] commit ddf67daac39d ("efi_capsule: Move signature from DTB to .rodata")
Prerequisite patches ==================== None
Test ==== * locally passed the pytest which is included in this patch series on sandbox built.
Todo ==== * Confirm that the change in .gitlab-ci.yml works. * Azure support(?)
Changes ======= v2 (July 28, 2021) * rebased on v2021.10-rc* * removed dependency on target's configuration * removed fdtsig.sh and others * add man page * update the UEFI document * add dedicate defconfig for testing on sandbox * add gitlab CI support * add "--guid" option to mkeficapsule (yet rather RFC)
Initial release (May 12, 2021) * based on v2021.07-rc2
AKASHI Takahiro (9): tools: mkeficapsule: add firmwware image signing tools: mkeficapsule: add man page doc: update UEFI document for usage of mkeficapsule efi_loader: ease the file path check for public key test/py: efi_capsule: add image authentication test sandbox: add config for efi capsule authentication test GitLab: add a test rule for efi capsule authentication test tools: mkeficapsule: allow for specifying GUID explicitly test/py: efi_capsule: align with the syntax change of mkeficapsule
.gitlab-ci.yml | 6 + MAINTAINERS | 1 + configs/sandbox_capsule_auth_defconfig | 307 +++++++++++++++ doc/develop/uefi/uefi.rst | 31 +- doc/mkeficapsule.1 | 98 +++++ lib/efi_loader/Makefile | 5 +- test/py/tests/test_efi_capsule/SIGNER.crt | 19 + test/py/tests/test_efi_capsule/SIGNER.esl | Bin 0 -> 829 bytes test/py/tests/test_efi_capsule/SIGNER.key | 28 ++ test/py/tests/test_efi_capsule/SIGNER2.crt | 19 + test/py/tests/test_efi_capsule/SIGNER2.key | 28 ++ .../py/tests/test_efi_capsule/capsule_defs.py | 5 + test/py/tests/test_efi_capsule/conftest.py | 39 +- .../test_capsule_firmware_signed.py | 228 +++++++++++ tools/Kconfig | 7 + tools/Makefile | 8 +- tools/mkeficapsule.c | 368 ++++++++++++++++-- 17 files changed, 1129 insertions(+), 68 deletions(-) create mode 100644 configs/sandbox_capsule_auth_defconfig create mode 100644 doc/mkeficapsule.1 create mode 100644 test/py/tests/test_efi_capsule/SIGNER.crt create mode 100644 test/py/tests/test_efi_capsule/SIGNER.esl create mode 100644 test/py/tests/test_efi_capsule/SIGNER.key create mode 100644 test/py/tests/test_efi_capsule/SIGNER2.crt create mode 100644 test/py/tests/test_efi_capsule/SIGNER2.key create mode 100644 test/py/tests/test_efi_capsule/test_capsule_firmware_signed.py

With this enhancement, mkeficapsule will be able to sign a capsule file when it is created. A signature added will be used later in the verification at FMP's SetImage() call.
To do that, We need specify additional command parameters: -monotonic-cout <count> : monotonic count -private-key <private key file> : private key file -certificate <certificate file> : certificate file Only when all of those parameters are given, a signature will be added to a capsule file.
Users are expected to maintain and increment the monotonic count at every time of the update for each firmware image.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org --- tools/Kconfig | 7 + tools/Makefile | 8 +- tools/mkeficapsule.c | 332 +++++++++++++++++++++++++++++++++++++++---- 3 files changed, 316 insertions(+), 31 deletions(-)
diff --git a/tools/Kconfig b/tools/Kconfig index d6f82cd949b5..9a37ed035311 100644 --- a/tools/Kconfig +++ b/tools/Kconfig @@ -20,4 +20,11 @@ config TOOLS_LIBCRYPTO This selection does not affect target features, such as runtime FIT signature verification.
+config TOOLS_MKEFICAPSULE + bool "Build efimkcapsule command" + default y if EFI_CAPSULE_ON_DISK + help + This command allows users to create a UEFI capsule file and, + optionally sign that file. If you want to enable UEFI capsule + update feature on your target, you certainly need this. endmenu diff --git a/tools/Makefile b/tools/Makefile index bae3f95c4995..af8536489652 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -245,8 +245,12 @@ hostprogs-$(CONFIG_MIPS) += mips-relocs hostprogs-$(CONFIG_ASN1_COMPILER) += asn1_compiler HOSTCFLAGS_asn1_compiler.o = -idirafter $(srctree)/include
-mkeficapsule-objs := mkeficapsule.o $(LIBFDT_OBJS) -hostprogs-$(CONFIG_EFI_HAVE_CAPSULE_SUPPORT) += mkeficapsule +HOSTLDLIBS_mkeficapsule += -luuid +ifeq ($(CONFIG_TOOLS_LIBCRYPTO),y) +HOSTLDLIBS_mkeficapsule += \ + $(shell pkg-config --libs libssl libcrypto 2> /dev/null || echo "-lssl -lcrypto") +endif +hostprogs-$(CONFIG_TOOLS_MKEFICAPSULE) += mkeficapsule
# We build some files with extra pedantic flags to try to minimize things # that won't build on some weird host compiler -- though there are lots of diff --git a/tools/mkeficapsule.c b/tools/mkeficapsule.c index 4995ba4e0c2a..798706c7b5f7 100644 --- a/tools/mkeficapsule.c +++ b/tools/mkeficapsule.c @@ -15,6 +15,16 @@ #include <sys/stat.h> #include <sys/types.h>
+#include <linux/kconfig.h> +#ifdef CONFIG_TOOLS_LIBCRYPTO +#include <openssl/asn1.h> +#include <openssl/bio.h> +#include <openssl/evp.h> +#include <openssl/err.h> +#include <openssl/pem.h> +#include <openssl/pkcs7.h> +#endif + typedef __u8 u8; typedef __u16 u16; typedef __u32 u32; @@ -38,12 +48,25 @@ efi_guid_t efi_guid_image_type_uboot_fit = EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID; efi_guid_t efi_guid_image_type_uboot_raw = EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID; +efi_guid_t efi_guid_cert_type_pkcs7 = EFI_CERT_TYPE_PKCS7_GUID; + +#ifdef CONFIG_TOOLS_LIBCRYPTO +static const char *opts_short = "f:r:i:I:v:p:c:m:dh"; +#else +static const char *opts_short = "f:r:i:I:v:h"; +#endif
static struct option options[] = { {"fit", required_argument, NULL, 'f'}, {"raw", required_argument, NULL, 'r'}, {"index", required_argument, NULL, 'i'}, {"instance", required_argument, NULL, 'I'}, +#ifdef CONFIG_TOOLS_LIBCRYPTO + {"private-key", required_argument, NULL, 'p'}, + {"certificate", required_argument, NULL, 'c'}, + {"monotonic-count", required_argument, NULL, 'm'}, + {"dump-sig", no_argument, NULL, 'd'}, +#endif {"help", no_argument, NULL, 'h'}, {NULL, 0, NULL, 0}, }; @@ -57,16 +80,195 @@ static void print_usage(void) "\t-r, --raw <raw image> new raw image file\n" "\t-i, --index <index> update image index\n" "\t-I, --instance <instance> update hardware instance\n" +#ifdef CONFIG_TOOLS_LIBCRYPTO + "\t-p, --private-key <privkey file> private key file\n" + "\t-c, --certificate <cert file> signer's certificate file\n" + "\t-m, --monotonic-count <count> monotonic count\n" + "\t-d, --dump_sig dump signature (*.p7)\n" +#endif "\t-h, --help print a help message\n", tool_name); }
+struct auth_context { + char *key_file; + char *cert_file; + u8 *image_data; + size_t image_size; + struct efi_firmware_image_authentication auth; + u8 *sig_data; + size_t sig_size; +}; + +static int dump_sig; + +#ifdef CONFIG_TOOLS_LIBCRYPTO +static EVP_PKEY *fileio_read_pkey(const char *filename) +{ + EVP_PKEY *key = NULL; + BIO *bio; + + bio = BIO_new_file(filename, "r"); + if (!bio) + goto out; + + key = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL); + +out: + BIO_free_all(bio); + if (!key) { + printf("Can't load key from file '%s'\n", filename); + ERR_print_errors_fp(stderr); + } + + return key; +} + +static X509 *fileio_read_cert(const char *filename) +{ + X509 *cert = NULL; + BIO *bio; + + bio = BIO_new_file(filename, "r"); + if (!bio) + goto out; + + cert = PEM_read_bio_X509(bio, NULL, NULL, NULL); + +out: + BIO_free_all(bio); + if (!cert) { + printf("Can't load certificate from file '%s'\n", filename); + ERR_print_errors_fp(stderr); + } + + return cert; +} + +static int create_auth_data(struct auth_context *ctx) +{ + EVP_PKEY *key = NULL; + X509 *cert = NULL; + BIO *data_bio = NULL; + const EVP_MD *md; + PKCS7 *p7; + int flags, ret = -1; + + OpenSSL_add_all_digests(); + OpenSSL_add_all_ciphers(); + ERR_load_crypto_strings(); + + key = fileio_read_pkey(ctx->key_file); + if (!key) + goto err; + cert = fileio_read_cert(ctx->cert_file); + if (!cert) + goto err; + + /* + * create a BIO, containing: + * * firmware image + * * monotonic count + * in this order! + * See EDK2's FmpAuthenticatedHandlerRsa2048Sha256() + */ + data_bio = BIO_new(BIO_s_mem()); + BIO_write(data_bio, ctx->image_data, ctx->image_size); + BIO_write(data_bio, &ctx->auth.monotonic_count, + sizeof(ctx->auth.monotonic_count)); + + md = EVP_get_digestbyname("SHA256"); + if (!md) + goto err; + + /* create signature */ + /* TODO: maybe add PKCS7_NOATTR and PKCS7_NOSMIMECAP */ + flags = PKCS7_BINARY | PKCS7_DETACHED; + p7 = PKCS7_sign(NULL, NULL, NULL, data_bio, flags | PKCS7_PARTIAL); + if (!p7) + goto err; + if (!PKCS7_sign_add_signer(p7, cert, key, md, flags)) + goto err; + if (!PKCS7_final(p7, data_bio, flags)) + goto err; + + /* convert pkcs7 into DER */ + ctx->sig_data = NULL; + ctx->sig_size = ASN1_item_i2d((ASN1_VALUE *)p7, &ctx->sig_data, + ASN1_ITEM_rptr(PKCS7)); + if (!ctx->sig_size) + goto err; + + /* fill auth_info */ + ctx->auth.auth_info.hdr.dwLength = sizeof(ctx->auth.auth_info) + + ctx->sig_size; + ctx->auth.auth_info.hdr.wRevision = WIN_CERT_REVISION_2_0; + ctx->auth.auth_info.hdr.wCertificateType = WIN_CERT_TYPE_EFI_GUID; + memcpy(&ctx->auth.auth_info.cert_type, &efi_guid_cert_type_pkcs7, + sizeof(efi_guid_cert_type_pkcs7)); + + ret = 0; +err: + BIO_free_all(data_bio); + EVP_PKEY_free(key); + X509_free(cert); + + return ret; +} + +static int dump_signature(const char *path, u8 *signature, size_t sig_size) +{ + char *sig_path; + FILE *f; + size_t size; + int ret = -1; + + sig_path = malloc(strlen(path) + 3 + 1); + if (!sig_path) + return ret; + + sprintf(sig_path, "%s.p7", path); + f = fopen(sig_path, "w"); + if (!f) + goto err; + + size = fwrite(signature, 1, sig_size, f); + if (size == sig_size) + ret = 0; + + fclose(f); +err: + free(sig_path); + return ret; +} + +static void free_sig_data(struct auth_context *ctx) +{ + if (ctx->sig_size) + OPENSSL_free(ctx->sig_data); +} +#else +static int create_auth_data(struct auth_context *ctx) +{ + return 0; +} + +static int dump_signature(const char *path, u8 *signature, size_t sig_size) +{ + return 0; +} + +static void free_sig_data(struct auth_context *ctx) {} +#endif + static int create_fwbin(char *path, char *bin, efi_guid_t *guid, - unsigned long index, unsigned long instance) + unsigned long index, unsigned long instance, + uint64_t mcount, char *privkey_file, char *cert_file) { struct efi_capsule_header header; struct efi_firmware_management_capsule_header capsule; struct efi_firmware_management_capsule_image_header image; + struct auth_context auth_context; FILE *f, *g; struct stat bin_stat; u8 *data; @@ -78,6 +280,7 @@ static int create_fwbin(char *path, char *bin, efi_guid_t *guid, printf("\tbin: %s\n\ttype: %pUl\n", bin, guid); printf("\tindex: %ld\n\tinstance: %ld\n", index, instance); #endif + auth_context.sig_size = 0;
g = fopen(bin, "r"); if (!g) { @@ -93,11 +296,34 @@ static int create_fwbin(char *path, char *bin, efi_guid_t *guid, printf("cannot allocate memory: %zx\n", (size_t)bin_stat.st_size); goto err_1; } - f = fopen(path, "w"); - if (!f) { - printf("cannot open %s\n", path); + + size = fread(data, 1, bin_stat.st_size, g); + if (size < bin_stat.st_size) { + printf("read failed (%zx)\n", size); goto err_2; } + + /* first, calculate signature to determine its size */ + if (privkey_file && cert_file) { + auth_context.key_file = privkey_file; + auth_context.cert_file = cert_file; + auth_context.auth.monotonic_count = mcount; + auth_context.image_data = data; + auth_context.image_size = bin_stat.st_size; + + if (create_auth_data(&auth_context)) { + printf("Signing firmware image failed\n"); + goto err_3; + } + + if (dump_sig && + dump_signature(path, auth_context.sig_data, + auth_context.sig_size)) { + printf("Creating signature file failed\n"); + goto err_3; + } + } + header.capsule_guid = efi_guid_fm_capsule; header.header_size = sizeof(header); /* TODO: The current implementation ignores flags */ @@ -106,11 +332,20 @@ static int create_fwbin(char *path, char *bin, efi_guid_t *guid, + sizeof(capsule) + sizeof(u64) + sizeof(image) + bin_stat.st_size; + if (auth_context.sig_size) + header.capsule_image_size += sizeof(auth_context.auth) + + auth_context.sig_size; + + f = fopen(path, "w"); + if (!f) { + printf("cannot open %s\n", path); + goto err_3; + }
size = fwrite(&header, 1, sizeof(header), f); if (size < sizeof(header)) { printf("write failed (%zx)\n", size); - goto err_3; + goto err_4; }
capsule.version = 0x00000001; @@ -119,13 +354,13 @@ static int create_fwbin(char *path, char *bin, efi_guid_t *guid, size = fwrite(&capsule, 1, sizeof(capsule), f); if (size < (sizeof(capsule))) { printf("write failed (%zx)\n", size); - goto err_3; + goto err_4; } offset = sizeof(capsule) + sizeof(u64); size = fwrite(&offset, 1, sizeof(offset), f); if (size < sizeof(offset)) { printf("write failed (%zx)\n", size); - goto err_3; + goto err_4; }
image.version = 0x00000003; @@ -135,34 +370,53 @@ static int create_fwbin(char *path, char *bin, efi_guid_t *guid, image.reserved[1] = 0; image.reserved[2] = 0; image.update_image_size = bin_stat.st_size; + if (auth_context.sig_size) + image.update_image_size += sizeof(auth_context.auth) + + auth_context.sig_size; image.update_vendor_code_size = 0; /* none */ image.update_hardware_instance = instance; image.image_capsule_support = 0; + if (auth_context.sig_size) + image.image_capsule_support |= CAPSULE_SUPPORT_AUTHENTICATION;
size = fwrite(&image, 1, sizeof(image), f); if (size < sizeof(image)) { printf("write failed (%zx)\n", size); - goto err_3; + goto err_4; } - size = fread(data, 1, bin_stat.st_size, g); - if (size < bin_stat.st_size) { - printf("read failed (%zx)\n", size); - goto err_3; + + if (auth_context.sig_size) { + size = fwrite(&auth_context.auth, 1, + sizeof(auth_context.auth), f); + if (size < sizeof(auth_context.auth)) { + printf("write failed (%zx)\n", size); + goto err_4; + } + size = fwrite(auth_context.sig_data, 1, + auth_context.sig_size, f); + if (size < auth_context.sig_size) { + printf("write failed (%zx)\n", size); + goto err_4; + } } + size = fwrite(data, 1, bin_stat.st_size, f); if (size < bin_stat.st_size) { printf("write failed (%zx)\n", size); - goto err_3; + goto err_4; }
fclose(f); fclose(g); free(data); + free_sig_data(&auth_context);
return 0;
-err_3: +err_4: fclose(f); +err_3: + free_sig_data(&auth_context); err_2: free(data); err_1: @@ -171,23 +425,25 @@ err_1: return -1; }
-/* - * Usage: - * $ mkeficapsule -f <firmware binary> <output file> - */ int main(int argc, char **argv) { char *file; efi_guid_t *guid; unsigned long index, instance; + uint64_t mcount; + char *privkey_file, *cert_file; int c, idx;
file = NULL; guid = NULL; index = 0; instance = 0; + mcount = 0; + privkey_file = NULL; + cert_file = NULL; + dump_sig = 0; for (;;) { - c = getopt_long(argc, argv, "f:r:i:I:v:h", options, &idx); + c = getopt_long(argc, argv, opts_short, options, &idx); if (c == -1) break;
@@ -214,26 +470,44 @@ int main(int argc, char **argv) case 'I': instance = strtoul(optarg, NULL, 0); break; +#ifdef CONFIG_TOOLS_LIBCRYPTO + case 'p': + if (privkey_file) { + printf("Private Key already specified\n"); + return -1; + } + privkey_file = optarg; + break; + case 'c': + if (cert_file) { + printf("Certificate file already specified\n"); + return -1; + } + cert_file = optarg; + break; + case 'm': + mcount = strtoul(optarg, NULL, 0); + break; + case 'd': + dump_sig = 1; + break; +#endif /* CONFIG_TOOLS_LIBCRYPTO */ case 'h': print_usage(); return 0; } }
- /* need an output file */ - if (argc != optind + 1) { + /* check necessary parameters */ + if ((argc != optind + 1) || !file || + ((privkey_file && !cert_file) || + (!privkey_file && cert_file))) { print_usage(); exit(EXIT_FAILURE); }
- /* need a fit image file or raw image file */ - if (!file) { - print_usage(); - exit(EXIT_SUCCESS); - } - - if (create_fwbin(argv[optind], file, guid, index, instance) - < 0) { + if (create_fwbin(argv[optind], file, guid, index, instance, + mcount, privkey_file, cert_file) < 0) { printf("Creating firmware capsule failed\n"); exit(EXIT_FAILURE); }

Hi,
I've tested this update on the DeveloperBox platform.
Tested-by: Masami Hiramatsu masami.hiramatsu@linaro.org
Thank you,
2021年7月27日(火) 18:12 AKASHI Takahiro takahiro.akashi@linaro.org:
With this enhancement, mkeficapsule will be able to sign a capsule file when it is created. A signature added will be used later in the verification at FMP's SetImage() call.
To do that, We need specify additional command parameters: -monotonic-cout <count> : monotonic count -private-key <private key file> : private key file -certificate <certificate file> : certificate file Only when all of those parameters are given, a signature will be added to a capsule file.
Users are expected to maintain and increment the monotonic count at every time of the update for each firmware image.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org
tools/Kconfig | 7 + tools/Makefile | 8 +- tools/mkeficapsule.c | 332 +++++++++++++++++++++++++++++++++++++++---- 3 files changed, 316 insertions(+), 31 deletions(-)
diff --git a/tools/Kconfig b/tools/Kconfig index d6f82cd949b5..9a37ed035311 100644 --- a/tools/Kconfig +++ b/tools/Kconfig @@ -20,4 +20,11 @@ config TOOLS_LIBCRYPTO This selection does not affect target features, such as runtime FIT signature verification.
+config TOOLS_MKEFICAPSULE
bool "Build efimkcapsule command"
default y if EFI_CAPSULE_ON_DISK
help
This command allows users to create a UEFI capsule file and,
optionally sign that file. If you want to enable UEFI capsule
update feature on your target, you certainly need this.
endmenu diff --git a/tools/Makefile b/tools/Makefile index bae3f95c4995..af8536489652 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -245,8 +245,12 @@ hostprogs-$(CONFIG_MIPS) += mips-relocs hostprogs-$(CONFIG_ASN1_COMPILER) += asn1_compiler HOSTCFLAGS_asn1_compiler.o = -idirafter $(srctree)/include
-mkeficapsule-objs := mkeficapsule.o $(LIBFDT_OBJS) -hostprogs-$(CONFIG_EFI_HAVE_CAPSULE_SUPPORT) += mkeficapsule +HOSTLDLIBS_mkeficapsule += -luuid +ifeq ($(CONFIG_TOOLS_LIBCRYPTO),y) +HOSTLDLIBS_mkeficapsule += \
$(shell pkg-config --libs libssl libcrypto 2> /dev/null || echo "-lssl -lcrypto")
+endif +hostprogs-$(CONFIG_TOOLS_MKEFICAPSULE) += mkeficapsule
# We build some files with extra pedantic flags to try to minimize things # that won't build on some weird host compiler -- though there are lots of diff --git a/tools/mkeficapsule.c b/tools/mkeficapsule.c index 4995ba4e0c2a..798706c7b5f7 100644 --- a/tools/mkeficapsule.c +++ b/tools/mkeficapsule.c @@ -15,6 +15,16 @@ #include <sys/stat.h> #include <sys/types.h>
+#include <linux/kconfig.h> +#ifdef CONFIG_TOOLS_LIBCRYPTO +#include <openssl/asn1.h> +#include <openssl/bio.h> +#include <openssl/evp.h> +#include <openssl/err.h> +#include <openssl/pem.h> +#include <openssl/pkcs7.h> +#endif
typedef __u8 u8; typedef __u16 u16; typedef __u32 u32; @@ -38,12 +48,25 @@ efi_guid_t efi_guid_image_type_uboot_fit = EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID; efi_guid_t efi_guid_image_type_uboot_raw = EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID; +efi_guid_t efi_guid_cert_type_pkcs7 = EFI_CERT_TYPE_PKCS7_GUID;
+#ifdef CONFIG_TOOLS_LIBCRYPTO +static const char *opts_short = "f:r:i:I:v:p:c:m:dh"; +#else +static const char *opts_short = "f:r:i:I:v:h"; +#endif
static struct option options[] = { {"fit", required_argument, NULL, 'f'}, {"raw", required_argument, NULL, 'r'}, {"index", required_argument, NULL, 'i'}, {"instance", required_argument, NULL, 'I'}, +#ifdef CONFIG_TOOLS_LIBCRYPTO
{"private-key", required_argument, NULL, 'p'},
{"certificate", required_argument, NULL, 'c'},
{"monotonic-count", required_argument, NULL, 'm'},
{"dump-sig", no_argument, NULL, 'd'},
+#endif {"help", no_argument, NULL, 'h'}, {NULL, 0, NULL, 0}, }; @@ -57,16 +80,195 @@ static void print_usage(void) "\t-r, --raw <raw image> new raw image file\n" "\t-i, --index <index> update image index\n" "\t-I, --instance <instance> update hardware instance\n" +#ifdef CONFIG_TOOLS_LIBCRYPTO
"\t-p, --private-key <privkey file> private key file\n"
"\t-c, --certificate <cert file> signer's certificate file\n"
"\t-m, --monotonic-count <count> monotonic count\n"
"\t-d, --dump_sig dump signature (*.p7)\n"
+#endif "\t-h, --help print a help message\n", tool_name); }
+struct auth_context {
char *key_file;
char *cert_file;
u8 *image_data;
size_t image_size;
struct efi_firmware_image_authentication auth;
u8 *sig_data;
size_t sig_size;
+};
+static int dump_sig;
+#ifdef CONFIG_TOOLS_LIBCRYPTO +static EVP_PKEY *fileio_read_pkey(const char *filename) +{
EVP_PKEY *key = NULL;
BIO *bio;
bio = BIO_new_file(filename, "r");
if (!bio)
goto out;
key = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
+out:
BIO_free_all(bio);
if (!key) {
printf("Can't load key from file '%s'\n", filename);
ERR_print_errors_fp(stderr);
}
return key;
+}
+static X509 *fileio_read_cert(const char *filename) +{
X509 *cert = NULL;
BIO *bio;
bio = BIO_new_file(filename, "r");
if (!bio)
goto out;
cert = PEM_read_bio_X509(bio, NULL, NULL, NULL);
+out:
BIO_free_all(bio);
if (!cert) {
printf("Can't load certificate from file '%s'\n", filename);
ERR_print_errors_fp(stderr);
}
return cert;
+}
+static int create_auth_data(struct auth_context *ctx) +{
EVP_PKEY *key = NULL;
X509 *cert = NULL;
BIO *data_bio = NULL;
const EVP_MD *md;
PKCS7 *p7;
int flags, ret = -1;
OpenSSL_add_all_digests();
OpenSSL_add_all_ciphers();
ERR_load_crypto_strings();
key = fileio_read_pkey(ctx->key_file);
if (!key)
goto err;
cert = fileio_read_cert(ctx->cert_file);
if (!cert)
goto err;
/*
* create a BIO, containing:
* * firmware image
* * monotonic count
* in this order!
* See EDK2's FmpAuthenticatedHandlerRsa2048Sha256()
*/
data_bio = BIO_new(BIO_s_mem());
BIO_write(data_bio, ctx->image_data, ctx->image_size);
BIO_write(data_bio, &ctx->auth.monotonic_count,
sizeof(ctx->auth.monotonic_count));
md = EVP_get_digestbyname("SHA256");
if (!md)
goto err;
/* create signature */
/* TODO: maybe add PKCS7_NOATTR and PKCS7_NOSMIMECAP */
flags = PKCS7_BINARY | PKCS7_DETACHED;
p7 = PKCS7_sign(NULL, NULL, NULL, data_bio, flags | PKCS7_PARTIAL);
if (!p7)
goto err;
if (!PKCS7_sign_add_signer(p7, cert, key, md, flags))
goto err;
if (!PKCS7_final(p7, data_bio, flags))
goto err;
/* convert pkcs7 into DER */
ctx->sig_data = NULL;
ctx->sig_size = ASN1_item_i2d((ASN1_VALUE *)p7, &ctx->sig_data,
ASN1_ITEM_rptr(PKCS7));
if (!ctx->sig_size)
goto err;
/* fill auth_info */
ctx->auth.auth_info.hdr.dwLength = sizeof(ctx->auth.auth_info)
+ ctx->sig_size;
ctx->auth.auth_info.hdr.wRevision = WIN_CERT_REVISION_2_0;
ctx->auth.auth_info.hdr.wCertificateType = WIN_CERT_TYPE_EFI_GUID;
memcpy(&ctx->auth.auth_info.cert_type, &efi_guid_cert_type_pkcs7,
sizeof(efi_guid_cert_type_pkcs7));
ret = 0;
+err:
BIO_free_all(data_bio);
EVP_PKEY_free(key);
X509_free(cert);
return ret;
+}
+static int dump_signature(const char *path, u8 *signature, size_t sig_size) +{
char *sig_path;
FILE *f;
size_t size;
int ret = -1;
sig_path = malloc(strlen(path) + 3 + 1);
if (!sig_path)
return ret;
sprintf(sig_path, "%s.p7", path);
f = fopen(sig_path, "w");
if (!f)
goto err;
size = fwrite(signature, 1, sig_size, f);
if (size == sig_size)
ret = 0;
fclose(f);
+err:
free(sig_path);
return ret;
+}
+static void free_sig_data(struct auth_context *ctx) +{
if (ctx->sig_size)
OPENSSL_free(ctx->sig_data);
+} +#else +static int create_auth_data(struct auth_context *ctx) +{
return 0;
+}
+static int dump_signature(const char *path, u8 *signature, size_t sig_size) +{
return 0;
+}
+static void free_sig_data(struct auth_context *ctx) {} +#endif
static int create_fwbin(char *path, char *bin, efi_guid_t *guid,
unsigned long index, unsigned long instance)
unsigned long index, unsigned long instance,
uint64_t mcount, char *privkey_file, char *cert_file)
{ struct efi_capsule_header header; struct efi_firmware_management_capsule_header capsule; struct efi_firmware_management_capsule_image_header image;
struct auth_context auth_context; FILE *f, *g; struct stat bin_stat; u8 *data;
@@ -78,6 +280,7 @@ static int create_fwbin(char *path, char *bin, efi_guid_t *guid, printf("\tbin: %s\n\ttype: %pUl\n", bin, guid); printf("\tindex: %ld\n\tinstance: %ld\n", index, instance); #endif
auth_context.sig_size = 0; g = fopen(bin, "r"); if (!g) {
@@ -93,11 +296,34 @@ static int create_fwbin(char *path, char *bin, efi_guid_t *guid, printf("cannot allocate memory: %zx\n", (size_t)bin_stat.st_size); goto err_1; }
f = fopen(path, "w");
if (!f) {
printf("cannot open %s\n", path);
size = fread(data, 1, bin_stat.st_size, g);
if (size < bin_stat.st_size) {
printf("read failed (%zx)\n", size); goto err_2; }
/* first, calculate signature to determine its size */
if (privkey_file && cert_file) {
auth_context.key_file = privkey_file;
auth_context.cert_file = cert_file;
auth_context.auth.monotonic_count = mcount;
auth_context.image_data = data;
auth_context.image_size = bin_stat.st_size;
if (create_auth_data(&auth_context)) {
printf("Signing firmware image failed\n");
goto err_3;
}
if (dump_sig &&
dump_signature(path, auth_context.sig_data,
auth_context.sig_size)) {
printf("Creating signature file failed\n");
goto err_3;
}
}
header.capsule_guid = efi_guid_fm_capsule; header.header_size = sizeof(header); /* TODO: The current implementation ignores flags */
@@ -106,11 +332,20 @@ static int create_fwbin(char *path, char *bin, efi_guid_t *guid, + sizeof(capsule) + sizeof(u64) + sizeof(image) + bin_stat.st_size;
if (auth_context.sig_size)
header.capsule_image_size += sizeof(auth_context.auth)
+ auth_context.sig_size;
f = fopen(path, "w");
if (!f) {
printf("cannot open %s\n", path);
goto err_3;
} size = fwrite(&header, 1, sizeof(header), f); if (size < sizeof(header)) { printf("write failed (%zx)\n", size);
goto err_3;
goto err_4; } capsule.version = 0x00000001;
@@ -119,13 +354,13 @@ static int create_fwbin(char *path, char *bin, efi_guid_t *guid, size = fwrite(&capsule, 1, sizeof(capsule), f); if (size < (sizeof(capsule))) { printf("write failed (%zx)\n", size);
goto err_3;
goto err_4; } offset = sizeof(capsule) + sizeof(u64); size = fwrite(&offset, 1, sizeof(offset), f); if (size < sizeof(offset)) { printf("write failed (%zx)\n", size);
goto err_3;
goto err_4; } image.version = 0x00000003;
@@ -135,34 +370,53 @@ static int create_fwbin(char *path, char *bin, efi_guid_t *guid, image.reserved[1] = 0; image.reserved[2] = 0; image.update_image_size = bin_stat.st_size;
if (auth_context.sig_size)
image.update_image_size += sizeof(auth_context.auth)
+ auth_context.sig_size; image.update_vendor_code_size = 0; /* none */ image.update_hardware_instance = instance; image.image_capsule_support = 0;
if (auth_context.sig_size)
image.image_capsule_support |= CAPSULE_SUPPORT_AUTHENTICATION; size = fwrite(&image, 1, sizeof(image), f); if (size < sizeof(image)) { printf("write failed (%zx)\n", size);
goto err_3;
goto err_4; }
size = fread(data, 1, bin_stat.st_size, g);
if (size < bin_stat.st_size) {
printf("read failed (%zx)\n", size);
goto err_3;
if (auth_context.sig_size) {
size = fwrite(&auth_context.auth, 1,
sizeof(auth_context.auth), f);
if (size < sizeof(auth_context.auth)) {
printf("write failed (%zx)\n", size);
goto err_4;
}
size = fwrite(auth_context.sig_data, 1,
auth_context.sig_size, f);
if (size < auth_context.sig_size) {
printf("write failed (%zx)\n", size);
goto err_4;
} }
size = fwrite(data, 1, bin_stat.st_size, f); if (size < bin_stat.st_size) { printf("write failed (%zx)\n", size);
goto err_3;
goto err_4; } fclose(f); fclose(g); free(data);
free_sig_data(&auth_context); return 0;
-err_3: +err_4: fclose(f); +err_3:
free_sig_data(&auth_context);
err_2: free(data); err_1: @@ -171,23 +425,25 @@ err_1: return -1; }
-/*
- Usage:
- $ mkeficapsule -f <firmware binary> <output file>
- */
int main(int argc, char **argv) { char *file; efi_guid_t *guid; unsigned long index, instance;
uint64_t mcount;
char *privkey_file, *cert_file; int c, idx; file = NULL; guid = NULL; index = 0; instance = 0;
mcount = 0;
privkey_file = NULL;
cert_file = NULL;
dump_sig = 0; for (;;) {
c = getopt_long(argc, argv, "f:r:i:I:v:h", options, &idx);
c = getopt_long(argc, argv, opts_short, options, &idx); if (c == -1) break;
@@ -214,26 +470,44 @@ int main(int argc, char **argv) case 'I': instance = strtoul(optarg, NULL, 0); break; +#ifdef CONFIG_TOOLS_LIBCRYPTO
case 'p':
if (privkey_file) {
printf("Private Key already specified\n");
return -1;
}
privkey_file = optarg;
break;
case 'c':
if (cert_file) {
printf("Certificate file already specified\n");
return -1;
}
cert_file = optarg;
break;
case 'm':
mcount = strtoul(optarg, NULL, 0);
break;
case 'd':
dump_sig = 1;
break;
+#endif /* CONFIG_TOOLS_LIBCRYPTO */ case 'h': print_usage(); return 0; } }
/* need an output file */
if (argc != optind + 1) {
/* check necessary parameters */
if ((argc != optind + 1) || !file ||
((privkey_file && !cert_file) ||
(!privkey_file && cert_file))) { print_usage(); exit(EXIT_FAILURE); }
/* need a fit image file or raw image file */
if (!file) {
print_usage();
exit(EXIT_SUCCESS);
}
if (create_fwbin(argv[optind], file, guid, index, instance)
< 0) {
if (create_fwbin(argv[optind], file, guid, index, instance,
mcount, privkey_file, cert_file) < 0) { printf("Creating firmware capsule failed\n"); exit(EXIT_FAILURE); }
-- 2.31.0

On 7/27/21 11:10 AM, AKASHI Takahiro wrote:
With this enhancement, mkeficapsule will be able to sign a capsule file when it is created. A signature added will be used later in the verification at FMP's SetImage() call.
To do that, We need specify additional command parameters: -monotonic-cout <count> : monotonic count -private-key <private key file> : private key file -certificate <certificate file> : certificate file Only when all of those parameters are given, a signature will be added to a capsule file.
Users are expected to maintain and increment the monotonic count at every time of the update for each firmware image.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org
tools/Kconfig | 7 + tools/Makefile | 8 +- tools/mkeficapsule.c | 332 +++++++++++++++++++++++++++++++++++++++---- 3 files changed, 316 insertions(+), 31 deletions(-)
diff --git a/tools/Kconfig b/tools/Kconfig index d6f82cd949b5..9a37ed035311 100644 --- a/tools/Kconfig +++ b/tools/Kconfig @@ -20,4 +20,11 @@ config TOOLS_LIBCRYPTO This selection does not affect target features, such as runtime FIT signature verification.
+config TOOLS_MKEFICAPSULE
- bool "Build efimkcapsule command"
- default y if EFI_CAPSULE_ON_DISK
- help
This command allows users to create a UEFI capsule file and,
optionally sign that file. If you want to enable UEFI capsule
endmenuupdate feature on your target, you certainly need this.
diff --git a/tools/Makefile b/tools/Makefile index bae3f95c4995..af8536489652 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -245,8 +245,12 @@ hostprogs-$(CONFIG_MIPS) += mips-relocs hostprogs-$(CONFIG_ASN1_COMPILER) += asn1_compiler HOSTCFLAGS_asn1_compiler.o = -idirafter $(srctree)/include
-mkeficapsule-objs := mkeficapsule.o $(LIBFDT_OBJS) -hostprogs-$(CONFIG_EFI_HAVE_CAPSULE_SUPPORT) += mkeficapsule +HOSTLDLIBS_mkeficapsule += -luuid +ifeq ($(CONFIG_TOOLS_LIBCRYPTO),y) +HOSTLDLIBS_mkeficapsule += \
- $(shell pkg-config --libs libssl libcrypto 2> /dev/null || echo "-lssl -lcrypto")
Please, add package pkg-config to the build dependencies enumerated in doc/build/gcc.rst.
+endif +hostprogs-$(CONFIG_TOOLS_MKEFICAPSULE) += mkeficapsule
# We build some files with extra pedantic flags to try to minimize things # that won't build on some weird host compiler -- though there are lots of diff --git a/tools/mkeficapsule.c b/tools/mkeficapsule.c index 4995ba4e0c2a..798706c7b5f7 100644 --- a/tools/mkeficapsule.c +++ b/tools/mkeficapsule.c @@ -15,6 +15,16 @@ #include <sys/stat.h> #include <sys/types.h>
+#include <linux/kconfig.h> +#ifdef CONFIG_TOOLS_LIBCRYPTO +#include <openssl/asn1.h> +#include <openssl/bio.h> +#include <openssl/evp.h> +#include <openssl/err.h> +#include <openssl/pem.h> +#include <openssl/pkcs7.h> +#endif
- typedef __u8 u8; typedef __u16 u16; typedef __u32 u32;
@@ -38,12 +48,25 @@ efi_guid_t efi_guid_image_type_uboot_fit = EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID; efi_guid_t efi_guid_image_type_uboot_raw = EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID; +efi_guid_t efi_guid_cert_type_pkcs7 = EFI_CERT_TYPE_PKCS7_GUID;
+#ifdef CONFIG_TOOLS_LIBCRYPTO +static const char *opts_short = "f:r:i:I:v:p:c:m:dh"; +#else +static const char *opts_short = "f:r:i:I:v:h"; +#endif
static struct option options[] = { {"fit", required_argument, NULL, 'f'}, {"raw", required_argument, NULL, 'r'}, {"index", required_argument, NULL, 'i'}, {"instance", required_argument, NULL, 'I'}, +#ifdef CONFIG_TOOLS_LIBCRYPTO
- {"private-key", required_argument, NULL, 'p'},
- {"certificate", required_argument, NULL, 'c'},
- {"monotonic-count", required_argument, NULL, 'm'},
- {"dump-sig", no_argument, NULL, 'd'},
+#endif {"help", no_argument, NULL, 'h'}, {NULL, 0, NULL, 0}, }; @@ -57,16 +80,195 @@ static void print_usage(void) "\t-r, --raw <raw image> new raw image file\n" "\t-i, --index <index> update image index\n" "\t-I, --instance <instance> update hardware instance\n" +#ifdef CONFIG_TOOLS_LIBCRYPTO
"\t-p, --private-key <privkey file> private key file\n"
"\t-c, --certificate <cert file> signer's certificate file\n"
"\t-m, --monotonic-count <count> monotonic count\n"
"\t-d, --dump_sig dump signature (*.p7)\n"
+#endif "\t-h, --help print a help message\n", tool_name); }
Please, add Sphinx documentation.
+struct auth_context {
- char *key_file;
- char *cert_file;
- u8 *image_data;
- size_t image_size;
- struct efi_firmware_image_authentication auth;
- u8 *sig_data;
- size_t sig_size;
+};
+static int dump_sig;
+#ifdef CONFIG_TOOLS_LIBCRYPTO +static EVP_PKEY *fileio_read_pkey(const char *filename) +{
- EVP_PKEY *key = NULL;
- BIO *bio;
- bio = BIO_new_file(filename, "r");
- if (!bio)
goto out;
- key = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
+out:
- BIO_free_all(bio);
- if (!key) {
printf("Can't load key from file '%s'\n", filename);
ERR_print_errors_fp(stderr);
- }
- return key;
+}
Please, add Sphinx documentation for all functions.
+static X509 *fileio_read_cert(const char *filename) +{
- X509 *cert = NULL;
- BIO *bio;
- bio = BIO_new_file(filename, "r");
- if (!bio)
goto out;
- cert = PEM_read_bio_X509(bio, NULL, NULL, NULL);
+out:
- BIO_free_all(bio);
- if (!cert) {
printf("Can't load certificate from file '%s'\n", filename);
ERR_print_errors_fp(stderr);
- }
- return cert;
+}
+static int create_auth_data(struct auth_context *ctx) +{
- EVP_PKEY *key = NULL;
- X509 *cert = NULL;
- BIO *data_bio = NULL;
- const EVP_MD *md;
- PKCS7 *p7;
- int flags, ret = -1;
- OpenSSL_add_all_digests();
- OpenSSL_add_all_ciphers();
- ERR_load_crypto_strings();
- key = fileio_read_pkey(ctx->key_file);
- if (!key)
goto err;
- cert = fileio_read_cert(ctx->cert_file);
- if (!cert)
goto err;
- /*
* create a BIO, containing:
* * firmware image
* * monotonic count
* in this order!
* See EDK2's FmpAuthenticatedHandlerRsa2048Sha256()
*/
- data_bio = BIO_new(BIO_s_mem());
- BIO_write(data_bio, ctx->image_data, ctx->image_size);
- BIO_write(data_bio, &ctx->auth.monotonic_count,
sizeof(ctx->auth.monotonic_count));
- md = EVP_get_digestbyname("SHA256");
- if (!md)
goto err;
- /* create signature */
- /* TODO: maybe add PKCS7_NOATTR and PKCS7_NOSMIMECAP */
- flags = PKCS7_BINARY | PKCS7_DETACHED;
- p7 = PKCS7_sign(NULL, NULL, NULL, data_bio, flags | PKCS7_PARTIAL);
- if (!p7)
goto err;
- if (!PKCS7_sign_add_signer(p7, cert, key, md, flags))
goto err;
- if (!PKCS7_final(p7, data_bio, flags))
goto err;
- /* convert pkcs7 into DER */
- ctx->sig_data = NULL;
- ctx->sig_size = ASN1_item_i2d((ASN1_VALUE *)p7, &ctx->sig_data,
ASN1_ITEM_rptr(PKCS7));
- if (!ctx->sig_size)
goto err;
- /* fill auth_info */
- ctx->auth.auth_info.hdr.dwLength = sizeof(ctx->auth.auth_info)
+ ctx->sig_size;
- ctx->auth.auth_info.hdr.wRevision = WIN_CERT_REVISION_2_0;
- ctx->auth.auth_info.hdr.wCertificateType = WIN_CERT_TYPE_EFI_GUID;
- memcpy(&ctx->auth.auth_info.cert_type, &efi_guid_cert_type_pkcs7,
sizeof(efi_guid_cert_type_pkcs7));
- ret = 0;
+err:
- BIO_free_all(data_bio);
- EVP_PKEY_free(key);
- X509_free(cert);
- return ret;
+}
+static int dump_signature(const char *path, u8 *signature, size_t sig_size) +{
- char *sig_path;
- FILE *f;
- size_t size;
- int ret = -1;
- sig_path = malloc(strlen(path) + 3 + 1);
- if (!sig_path)
return ret;
- sprintf(sig_path, "%s.p7", path);
- f = fopen(sig_path, "w");
- if (!f)
goto err;
- size = fwrite(signature, 1, sig_size, f);
- if (size == sig_size)
ret = 0;
- fclose(f);
+err:
- free(sig_path);
- return ret;
+}
+static void free_sig_data(struct auth_context *ctx) +{
- if (ctx->sig_size)
OPENSSL_free(ctx->sig_data);
+} +#else +static int create_auth_data(struct auth_context *ctx) +{
- return 0;
+}
+static int dump_signature(const char *path, u8 *signature, size_t sig_size) +{
- return 0;
+}
+static void free_sig_data(struct auth_context *ctx) {} +#endif
- static int create_fwbin(char *path, char *bin, efi_guid_t *guid,
unsigned long index, unsigned long instance)
unsigned long index, unsigned long instance,
{ struct efi_capsule_header header; struct efi_firmware_management_capsule_header capsule; struct efi_firmware_management_capsule_image_header image;uint64_t mcount, char *privkey_file, char *cert_file)
- struct auth_context auth_context; FILE *f, *g; struct stat bin_stat; u8 *data;
@@ -78,6 +280,7 @@ static int create_fwbin(char *path, char *bin, efi_guid_t *guid, printf("\tbin: %s\n\ttype: %pUl\n", bin, guid); printf("\tindex: %ld\n\tinstance: %ld\n", index, instance);
[tools/mkeficapsule.c:281] (warning) %ld in format string (no. 1) requires 'long' but the argument type is 'unsigned long'.
Best regards
Heinrich
#endif
auth_context.sig_size = 0;
g = fopen(bin, "r"); if (!g) {
@@ -93,11 +296,34 @@ static int create_fwbin(char *path, char *bin, efi_guid_t *guid, printf("cannot allocate memory: %zx\n", (size_t)bin_stat.st_size); goto err_1; }
- f = fopen(path, "w");
- if (!f) {
printf("cannot open %s\n", path);
- size = fread(data, 1, bin_stat.st_size, g);
- if (size < bin_stat.st_size) {
goto err_2; }printf("read failed (%zx)\n", size);
- /* first, calculate signature to determine its size */
- if (privkey_file && cert_file) {
auth_context.key_file = privkey_file;
auth_context.cert_file = cert_file;
auth_context.auth.monotonic_count = mcount;
auth_context.image_data = data;
auth_context.image_size = bin_stat.st_size;
if (create_auth_data(&auth_context)) {
printf("Signing firmware image failed\n");
goto err_3;
}
if (dump_sig &&
dump_signature(path, auth_context.sig_data,
auth_context.sig_size)) {
printf("Creating signature file failed\n");
goto err_3;
}
- }
- header.capsule_guid = efi_guid_fm_capsule; header.header_size = sizeof(header); /* TODO: The current implementation ignores flags */
@@ -106,11 +332,20 @@ static int create_fwbin(char *path, char *bin, efi_guid_t *guid, + sizeof(capsule) + sizeof(u64) + sizeof(image) + bin_stat.st_size;
if (auth_context.sig_size)
header.capsule_image_size += sizeof(auth_context.auth)
+ auth_context.sig_size;
f = fopen(path, "w");
if (!f) {
printf("cannot open %s\n", path);
goto err_3;
}
size = fwrite(&header, 1, sizeof(header), f); if (size < sizeof(header)) { printf("write failed (%zx)\n", size);
goto err_3;
goto err_4;
}
capsule.version = 0x00000001;
@@ -119,13 +354,13 @@ static int create_fwbin(char *path, char *bin, efi_guid_t *guid, size = fwrite(&capsule, 1, sizeof(capsule), f); if (size < (sizeof(capsule))) { printf("write failed (%zx)\n", size);
goto err_3;
} offset = sizeof(capsule) + sizeof(u64); size = fwrite(&offset, 1, sizeof(offset), f); if (size < sizeof(offset)) { printf("write failed (%zx)\n", size);goto err_4;
goto err_3;
goto err_4;
}
image.version = 0x00000003;
@@ -135,34 +370,53 @@ static int create_fwbin(char *path, char *bin, efi_guid_t *guid, image.reserved[1] = 0; image.reserved[2] = 0; image.update_image_size = bin_stat.st_size;
if (auth_context.sig_size)
image.update_image_size += sizeof(auth_context.auth)
+ auth_context.sig_size;
image.update_vendor_code_size = 0; /* none */ image.update_hardware_instance = instance; image.image_capsule_support = 0;
if (auth_context.sig_size)
image.image_capsule_support |= CAPSULE_SUPPORT_AUTHENTICATION;
size = fwrite(&image, 1, sizeof(image), f); if (size < sizeof(image)) { printf("write failed (%zx)\n", size);
goto err_3;
}goto err_4;
- size = fread(data, 1, bin_stat.st_size, g);
- if (size < bin_stat.st_size) {
printf("read failed (%zx)\n", size);
goto err_3;
- if (auth_context.sig_size) {
size = fwrite(&auth_context.auth, 1,
sizeof(auth_context.auth), f);
if (size < sizeof(auth_context.auth)) {
printf("write failed (%zx)\n", size);
goto err_4;
}
size = fwrite(auth_context.sig_data, 1,
auth_context.sig_size, f);
if (size < auth_context.sig_size) {
printf("write failed (%zx)\n", size);
goto err_4;
}}
- size = fwrite(data, 1, bin_stat.st_size, f); if (size < bin_stat.st_size) { printf("write failed (%zx)\n", size);
goto err_3;
goto err_4;
}
fclose(f); fclose(g); free(data);
free_sig_data(&auth_context);
return 0;
-err_3: +err_4: fclose(f); +err_3:
- free_sig_data(&auth_context); err_2: free(data); err_1:
@@ -171,23 +425,25 @@ err_1: return -1; }
-/*
- Usage:
- $ mkeficapsule -f <firmware binary> <output file>
- */ int main(int argc, char **argv) { char *file; efi_guid_t *guid; unsigned long index, instance;
uint64_t mcount;
char *privkey_file, *cert_file; int c, idx;
file = NULL; guid = NULL; index = 0; instance = 0;
mcount = 0;
privkey_file = NULL;
cert_file = NULL;
dump_sig = 0; for (;;) {
c = getopt_long(argc, argv, "f:r:i:I:v:h", options, &idx);
if (c == -1) break;c = getopt_long(argc, argv, opts_short, options, &idx);
@@ -214,26 +470,44 @@ int main(int argc, char **argv) case 'I': instance = strtoul(optarg, NULL, 0); break; +#ifdef CONFIG_TOOLS_LIBCRYPTO
case 'p':
if (privkey_file) {
printf("Private Key already specified\n");
return -1;
}
privkey_file = optarg;
break;
case 'c':
if (cert_file) {
printf("Certificate file already specified\n");
return -1;
}
cert_file = optarg;
break;
case 'm':
mcount = strtoul(optarg, NULL, 0);
break;
case 'd':
dump_sig = 1;
break;
+#endif /* CONFIG_TOOLS_LIBCRYPTO */ case 'h': print_usage(); return 0; } }
- /* need an output file */
- if (argc != optind + 1) {
- /* check necessary parameters */
- if ((argc != optind + 1) || !file ||
((privkey_file && !cert_file) ||
print_usage(); exit(EXIT_FAILURE); }(!privkey_file && cert_file))) {
- /* need a fit image file or raw image file */
- if (!file) {
print_usage();
exit(EXIT_SUCCESS);
- }
- if (create_fwbin(argv[optind], file, guid, index, instance)
< 0) {
- if (create_fwbin(argv[optind], file, guid, index, instance,
printf("Creating firmware capsule failed\n"); exit(EXIT_FAILURE); }mcount, privkey_file, cert_file) < 0) {

Heinrich,
On Sun, Aug 01, 2021 at 11:21:55AM +0200, Heinrich Schuchardt wrote:
On 7/27/21 11:10 AM, AKASHI Takahiro wrote:
With this enhancement, mkeficapsule will be able to sign a capsule file when it is created. A signature added will be used later in the verification at FMP's SetImage() call.
To do that, We need specify additional command parameters: -monotonic-cout <count> : monotonic count -private-key <private key file> : private key file -certificate <certificate file> : certificate file Only when all of those parameters are given, a signature will be added to a capsule file.
Users are expected to maintain and increment the monotonic count at every time of the update for each firmware image.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org
tools/Kconfig | 7 + tools/Makefile | 8 +- tools/mkeficapsule.c | 332 +++++++++++++++++++++++++++++++++++++++---- 3 files changed, 316 insertions(+), 31 deletions(-)
diff --git a/tools/Kconfig b/tools/Kconfig index d6f82cd949b5..9a37ed035311 100644 --- a/tools/Kconfig +++ b/tools/Kconfig @@ -20,4 +20,11 @@ config TOOLS_LIBCRYPTO This selection does not affect target features, such as runtime FIT signature verification.
+config TOOLS_MKEFICAPSULE
- bool "Build efimkcapsule command"
- default y if EFI_CAPSULE_ON_DISK
- help
This command allows users to create a UEFI capsule file and,
optionally sign that file. If you want to enable UEFI capsule
endmenuupdate feature on your target, you certainly need this.
diff --git a/tools/Makefile b/tools/Makefile index bae3f95c4995..af8536489652 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -245,8 +245,12 @@ hostprogs-$(CONFIG_MIPS) += mips-relocs hostprogs-$(CONFIG_ASN1_COMPILER) += asn1_compiler HOSTCFLAGS_asn1_compiler.o = -idirafter $(srctree)/include
-mkeficapsule-objs := mkeficapsule.o $(LIBFDT_OBJS) -hostprogs-$(CONFIG_EFI_HAVE_CAPSULE_SUPPORT) += mkeficapsule +HOSTLDLIBS_mkeficapsule += -luuid +ifeq ($(CONFIG_TOOLS_LIBCRYPTO),y) +HOSTLDLIBS_mkeficapsule += \
- $(shell pkg-config --libs libssl libcrypto 2> /dev/null || echo "-lssl -lcrypto")
Please, add package pkg-config to the build dependencies enumerated in doc/build/gcc.rst.
Already there: libssl-dev
+endif +hostprogs-$(CONFIG_TOOLS_MKEFICAPSULE) += mkeficapsule
# We build some files with extra pedantic flags to try to minimize things # that won't build on some weird host compiler -- though there are lots of diff --git a/tools/mkeficapsule.c b/tools/mkeficapsule.c index 4995ba4e0c2a..798706c7b5f7 100644 --- a/tools/mkeficapsule.c +++ b/tools/mkeficapsule.c @@ -15,6 +15,16 @@ #include <sys/stat.h> #include <sys/types.h>
+#include <linux/kconfig.h> +#ifdef CONFIG_TOOLS_LIBCRYPTO +#include <openssl/asn1.h> +#include <openssl/bio.h> +#include <openssl/evp.h> +#include <openssl/err.h> +#include <openssl/pem.h> +#include <openssl/pkcs7.h> +#endif
- typedef __u8 u8; typedef __u16 u16; typedef __u32 u32;
@@ -38,12 +48,25 @@ efi_guid_t efi_guid_image_type_uboot_fit = EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID; efi_guid_t efi_guid_image_type_uboot_raw = EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID; +efi_guid_t efi_guid_cert_type_pkcs7 = EFI_CERT_TYPE_PKCS7_GUID;
+#ifdef CONFIG_TOOLS_LIBCRYPTO +static const char *opts_short = "f:r:i:I:v:p:c:m:dh"; +#else +static const char *opts_short = "f:r:i:I:v:h"; +#endif
static struct option options[] = { {"fit", required_argument, NULL, 'f'}, {"raw", required_argument, NULL, 'r'}, {"index", required_argument, NULL, 'i'}, {"instance", required_argument, NULL, 'I'}, +#ifdef CONFIG_TOOLS_LIBCRYPTO
- {"private-key", required_argument, NULL, 'p'},
- {"certificate", required_argument, NULL, 'c'},
- {"monotonic-count", required_argument, NULL, 'm'},
- {"dump-sig", no_argument, NULL, 'd'},
+#endif {"help", no_argument, NULL, 'h'}, {NULL, 0, NULL, 0}, }; @@ -57,16 +80,195 @@ static void print_usage(void) "\t-r, --raw <raw image> new raw image file\n" "\t-i, --index <index> update image index\n" "\t-I, --instance <instance> update hardware instance\n" +#ifdef CONFIG_TOOLS_LIBCRYPTO
"\t-p, --private-key <privkey file> private key file\n"
"\t-c, --certificate <cert file> signer's certificate file\n"
"\t-m, --monotonic-count <count> monotonic count\n"
"\t-d, --dump_sig dump signature (*.p7)\n"
+#endif "\t-h, --help print a help message\n", tool_name); }
Please, add Sphinx documentation.
I added the man page. Why need another different format of doc? I think that doc/develop/uefi/uefi.rst gives you an enough introduction to the command. (Although the doc will have to been updated due to the latest change of mkeficapsule syntax that I'm also proposing.)
Actually, there is no sphinx doc for any host tools.
+struct auth_context {
- char *key_file;
- char *cert_file;
- u8 *image_data;
- size_t image_size;
- struct efi_firmware_image_authentication auth;
- u8 *sig_data;
- size_t sig_size;
+};
+static int dump_sig;
+#ifdef CONFIG_TOOLS_LIBCRYPTO +static EVP_PKEY *fileio_read_pkey(const char *filename) +{
- EVP_PKEY *key = NULL;
- BIO *bio;
- bio = BIO_new_file(filename, "r");
- if (!bio)
goto out;
- key = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
+out:
- BIO_free_all(bio);
- if (!key) {
printf("Can't load key from file '%s'\n", filename);
ERR_print_errors_fp(stderr);
- }
- return key;
+}
Please, add Sphinx documentation for all functions.
Yeah, but "all" is a too forcible requirement. There is no source code of host tools to meet the requirement. Actually, most don't have even one description of a function.
I think that, if it is a really required element in the source, it should be explicitly described somewhere under "doc".
+static X509 *fileio_read_cert(const char *filename) +{
- X509 *cert = NULL;
- BIO *bio;
- bio = BIO_new_file(filename, "r");
- if (!bio)
goto out;
- cert = PEM_read_bio_X509(bio, NULL, NULL, NULL);
+out:
- BIO_free_all(bio);
- if (!cert) {
printf("Can't load certificate from file '%s'\n", filename);
ERR_print_errors_fp(stderr);
- }
- return cert;
+}
+static int create_auth_data(struct auth_context *ctx) +{
- EVP_PKEY *key = NULL;
- X509 *cert = NULL;
- BIO *data_bio = NULL;
- const EVP_MD *md;
- PKCS7 *p7;
- int flags, ret = -1;
- OpenSSL_add_all_digests();
- OpenSSL_add_all_ciphers();
- ERR_load_crypto_strings();
- key = fileio_read_pkey(ctx->key_file);
- if (!key)
goto err;
- cert = fileio_read_cert(ctx->cert_file);
- if (!cert)
goto err;
- /*
* create a BIO, containing:
* * firmware image
* * monotonic count
* in this order!
* See EDK2's FmpAuthenticatedHandlerRsa2048Sha256()
*/
- data_bio = BIO_new(BIO_s_mem());
- BIO_write(data_bio, ctx->image_data, ctx->image_size);
- BIO_write(data_bio, &ctx->auth.monotonic_count,
sizeof(ctx->auth.monotonic_count));
- md = EVP_get_digestbyname("SHA256");
- if (!md)
goto err;
- /* create signature */
- /* TODO: maybe add PKCS7_NOATTR and PKCS7_NOSMIMECAP */
- flags = PKCS7_BINARY | PKCS7_DETACHED;
- p7 = PKCS7_sign(NULL, NULL, NULL, data_bio, flags | PKCS7_PARTIAL);
- if (!p7)
goto err;
- if (!PKCS7_sign_add_signer(p7, cert, key, md, flags))
goto err;
- if (!PKCS7_final(p7, data_bio, flags))
goto err;
- /* convert pkcs7 into DER */
- ctx->sig_data = NULL;
- ctx->sig_size = ASN1_item_i2d((ASN1_VALUE *)p7, &ctx->sig_data,
ASN1_ITEM_rptr(PKCS7));
- if (!ctx->sig_size)
goto err;
- /* fill auth_info */
- ctx->auth.auth_info.hdr.dwLength = sizeof(ctx->auth.auth_info)
+ ctx->sig_size;
- ctx->auth.auth_info.hdr.wRevision = WIN_CERT_REVISION_2_0;
- ctx->auth.auth_info.hdr.wCertificateType = WIN_CERT_TYPE_EFI_GUID;
- memcpy(&ctx->auth.auth_info.cert_type, &efi_guid_cert_type_pkcs7,
sizeof(efi_guid_cert_type_pkcs7));
- ret = 0;
+err:
- BIO_free_all(data_bio);
- EVP_PKEY_free(key);
- X509_free(cert);
- return ret;
+}
+static int dump_signature(const char *path, u8 *signature, size_t sig_size) +{
- char *sig_path;
- FILE *f;
- size_t size;
- int ret = -1;
- sig_path = malloc(strlen(path) + 3 + 1);
- if (!sig_path)
return ret;
- sprintf(sig_path, "%s.p7", path);
- f = fopen(sig_path, "w");
- if (!f)
goto err;
- size = fwrite(signature, 1, sig_size, f);
- if (size == sig_size)
ret = 0;
- fclose(f);
+err:
- free(sig_path);
- return ret;
+}
+static void free_sig_data(struct auth_context *ctx) +{
- if (ctx->sig_size)
OPENSSL_free(ctx->sig_data);
+} +#else +static int create_auth_data(struct auth_context *ctx) +{
- return 0;
+}
+static int dump_signature(const char *path, u8 *signature, size_t sig_size) +{
- return 0;
+}
+static void free_sig_data(struct auth_context *ctx) {} +#endif
- static int create_fwbin(char *path, char *bin, efi_guid_t *guid,
unsigned long index, unsigned long instance)
unsigned long index, unsigned long instance,
{ struct efi_capsule_header header; struct efi_firmware_management_capsule_header capsule; struct efi_firmware_management_capsule_image_header image;uint64_t mcount, char *privkey_file, char *cert_file)
- struct auth_context auth_context; FILE *f, *g; struct stat bin_stat; u8 *data;
@@ -78,6 +280,7 @@ static int create_fwbin(char *path, char *bin, efi_guid_t *guid, printf("\tbin: %s\n\ttype: %pUl\n", bin, guid); printf("\tindex: %ld\n\tinstance: %ld\n", index, instance);
[tools/mkeficapsule.c:281] (warning) %ld in format string (no. 1) requires 'long' but the argument type is 'unsigned long'.
Will fix it.
-Takahiro Akashi
Best regards
Heinrich
#endif
auth_context.sig_size = 0;
g = fopen(bin, "r"); if (!g) {
@@ -93,11 +296,34 @@ static int create_fwbin(char *path, char *bin, efi_guid_t *guid, printf("cannot allocate memory: %zx\n", (size_t)bin_stat.st_size); goto err_1; }
- f = fopen(path, "w");
- if (!f) {
printf("cannot open %s\n", path);
- size = fread(data, 1, bin_stat.st_size, g);
- if (size < bin_stat.st_size) {
goto err_2; }printf("read failed (%zx)\n", size);
- /* first, calculate signature to determine its size */
- if (privkey_file && cert_file) {
auth_context.key_file = privkey_file;
auth_context.cert_file = cert_file;
auth_context.auth.monotonic_count = mcount;
auth_context.image_data = data;
auth_context.image_size = bin_stat.st_size;
if (create_auth_data(&auth_context)) {
printf("Signing firmware image failed\n");
goto err_3;
}
if (dump_sig &&
dump_signature(path, auth_context.sig_data,
auth_context.sig_size)) {
printf("Creating signature file failed\n");
goto err_3;
}
- }
- header.capsule_guid = efi_guid_fm_capsule; header.header_size = sizeof(header); /* TODO: The current implementation ignores flags */
@@ -106,11 +332,20 @@ static int create_fwbin(char *path, char *bin, efi_guid_t *guid, + sizeof(capsule) + sizeof(u64) + sizeof(image) + bin_stat.st_size;
if (auth_context.sig_size)
header.capsule_image_size += sizeof(auth_context.auth)
+ auth_context.sig_size;
f = fopen(path, "w");
if (!f) {
printf("cannot open %s\n", path);
goto err_3;
}
size = fwrite(&header, 1, sizeof(header), f); if (size < sizeof(header)) { printf("write failed (%zx)\n", size);
goto err_3;
goto err_4;
}
capsule.version = 0x00000001;
@@ -119,13 +354,13 @@ static int create_fwbin(char *path, char *bin, efi_guid_t *guid, size = fwrite(&capsule, 1, sizeof(capsule), f); if (size < (sizeof(capsule))) { printf("write failed (%zx)\n", size);
goto err_3;
} offset = sizeof(capsule) + sizeof(u64); size = fwrite(&offset, 1, sizeof(offset), f); if (size < sizeof(offset)) { printf("write failed (%zx)\n", size);goto err_4;
goto err_3;
goto err_4;
}
image.version = 0x00000003;
@@ -135,34 +370,53 @@ static int create_fwbin(char *path, char *bin, efi_guid_t *guid, image.reserved[1] = 0; image.reserved[2] = 0; image.update_image_size = bin_stat.st_size;
if (auth_context.sig_size)
image.update_image_size += sizeof(auth_context.auth)
+ auth_context.sig_size;
image.update_vendor_code_size = 0; /* none */ image.update_hardware_instance = instance; image.image_capsule_support = 0;
if (auth_context.sig_size)
image.image_capsule_support |= CAPSULE_SUPPORT_AUTHENTICATION;
size = fwrite(&image, 1, sizeof(image), f); if (size < sizeof(image)) { printf("write failed (%zx)\n", size);
goto err_3;
}goto err_4;
- size = fread(data, 1, bin_stat.st_size, g);
- if (size < bin_stat.st_size) {
printf("read failed (%zx)\n", size);
goto err_3;
- if (auth_context.sig_size) {
size = fwrite(&auth_context.auth, 1,
sizeof(auth_context.auth), f);
if (size < sizeof(auth_context.auth)) {
printf("write failed (%zx)\n", size);
goto err_4;
}
size = fwrite(auth_context.sig_data, 1,
auth_context.sig_size, f);
if (size < auth_context.sig_size) {
printf("write failed (%zx)\n", size);
goto err_4;
}}
- size = fwrite(data, 1, bin_stat.st_size, f); if (size < bin_stat.st_size) { printf("write failed (%zx)\n", size);
goto err_3;
goto err_4;
}
fclose(f); fclose(g); free(data);
free_sig_data(&auth_context);
return 0;
-err_3: +err_4: fclose(f); +err_3:
- free_sig_data(&auth_context); err_2: free(data); err_1:
@@ -171,23 +425,25 @@ err_1: return -1; }
-/*
- Usage:
- $ mkeficapsule -f <firmware binary> <output file>
- */ int main(int argc, char **argv) { char *file; efi_guid_t *guid; unsigned long index, instance;
uint64_t mcount;
char *privkey_file, *cert_file; int c, idx;
file = NULL; guid = NULL; index = 0; instance = 0;
mcount = 0;
privkey_file = NULL;
cert_file = NULL;
dump_sig = 0; for (;;) {
c = getopt_long(argc, argv, "f:r:i:I:v:h", options, &idx);
if (c == -1) break;c = getopt_long(argc, argv, opts_short, options, &idx);
@@ -214,26 +470,44 @@ int main(int argc, char **argv) case 'I': instance = strtoul(optarg, NULL, 0); break; +#ifdef CONFIG_TOOLS_LIBCRYPTO
case 'p':
if (privkey_file) {
printf("Private Key already specified\n");
return -1;
}
privkey_file = optarg;
break;
case 'c':
if (cert_file) {
printf("Certificate file already specified\n");
return -1;
}
cert_file = optarg;
break;
case 'm':
mcount = strtoul(optarg, NULL, 0);
break;
case 'd':
dump_sig = 1;
break;
+#endif /* CONFIG_TOOLS_LIBCRYPTO */ case 'h': print_usage(); return 0; } }
- /* need an output file */
- if (argc != optind + 1) {
- /* check necessary parameters */
- if ((argc != optind + 1) || !file ||
((privkey_file && !cert_file) ||
print_usage(); exit(EXIT_FAILURE); }(!privkey_file && cert_file))) {
- /* need a fit image file or raw image file */
- if (!file) {
print_usage();
exit(EXIT_SUCCESS);
- }
- if (create_fwbin(argv[optind], file, guid, index, instance)
< 0) {
- if (create_fwbin(argv[optind], file, guid, index, instance,
printf("Creating firmware capsule failed\n"); exit(EXIT_FAILURE); }mcount, privkey_file, cert_file) < 0) {

On 8/2/21 5:30 AM, AKASHI Takahiro wrote:
Heinrich,
On Sun, Aug 01, 2021 at 11:21:55AM +0200, Heinrich Schuchardt wrote:
On 7/27/21 11:10 AM, AKASHI Takahiro wrote:
With this enhancement, mkeficapsule will be able to sign a capsule file when it is created. A signature added will be used later in the verification at FMP's SetImage() call.
To do that, We need specify additional command parameters: -monotonic-cout <count> : monotonic count -private-key <private key file> : private key file -certificate <certificate file> : certificate file Only when all of those parameters are given, a signature will be added to a capsule file.
Users are expected to maintain and increment the monotonic count at every time of the update for each firmware image.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org
tools/Kconfig | 7 + tools/Makefile | 8 +- tools/mkeficapsule.c | 332 +++++++++++++++++++++++++++++++++++++++---- 3 files changed, 316 insertions(+), 31 deletions(-)
diff --git a/tools/Kconfig b/tools/Kconfig index d6f82cd949b5..9a37ed035311 100644 --- a/tools/Kconfig +++ b/tools/Kconfig @@ -20,4 +20,11 @@ config TOOLS_LIBCRYPTO This selection does not affect target features, such as runtime FIT signature verification.
+config TOOLS_MKEFICAPSULE
- bool "Build efimkcapsule command"
- default y if EFI_CAPSULE_ON_DISK
- help
This command allows users to create a UEFI capsule file and,
optionally sign that file. If you want to enable UEFI capsule
endmenuupdate feature on your target, you certainly need this.
diff --git a/tools/Makefile b/tools/Makefile index bae3f95c4995..af8536489652 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -245,8 +245,12 @@ hostprogs-$(CONFIG_MIPS) += mips-relocs hostprogs-$(CONFIG_ASN1_COMPILER) += asn1_compiler HOSTCFLAGS_asn1_compiler.o = -idirafter $(srctree)/include
-mkeficapsule-objs := mkeficapsule.o $(LIBFDT_OBJS) -hostprogs-$(CONFIG_EFI_HAVE_CAPSULE_SUPPORT) += mkeficapsule +HOSTLDLIBS_mkeficapsule += -luuid +ifeq ($(CONFIG_TOOLS_LIBCRYPTO),y) +HOSTLDLIBS_mkeficapsule += \
- $(shell pkg-config --libs libssl libcrypto 2> /dev/null || echo "-lssl -lcrypto")
Please, add package pkg-config to the build dependencies enumerated in doc/build/gcc.rst.
Already there: libssl-dev
It is *pkg-config* that is missing.
+endif +hostprogs-$(CONFIG_TOOLS_MKEFICAPSULE) += mkeficapsule
# We build some files with extra pedantic flags to try to minimize things # that won't build on some weird host compiler -- though there are lots of diff --git a/tools/mkeficapsule.c b/tools/mkeficapsule.c index 4995ba4e0c2a..798706c7b5f7 100644 --- a/tools/mkeficapsule.c +++ b/tools/mkeficapsule.c @@ -15,6 +15,16 @@ #include <sys/stat.h> #include <sys/types.h>
+#include <linux/kconfig.h> +#ifdef CONFIG_TOOLS_LIBCRYPTO +#include <openssl/asn1.h> +#include <openssl/bio.h> +#include <openssl/evp.h> +#include <openssl/err.h> +#include <openssl/pem.h> +#include <openssl/pkcs7.h> +#endif
- typedef __u8 u8; typedef __u16 u16; typedef __u32 u32;
@@ -38,12 +48,25 @@ efi_guid_t efi_guid_image_type_uboot_fit = EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID; efi_guid_t efi_guid_image_type_uboot_raw = EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID; +efi_guid_t efi_guid_cert_type_pkcs7 = EFI_CERT_TYPE_PKCS7_GUID;
+#ifdef CONFIG_TOOLS_LIBCRYPTO +static const char *opts_short = "f:r:i:I:v:p:c:m:dh"; +#else +static const char *opts_short = "f:r:i:I:v:h"; +#endif
static struct option options[] = { {"fit", required_argument, NULL, 'f'}, {"raw", required_argument, NULL, 'r'}, {"index", required_argument, NULL, 'i'}, {"instance", required_argument, NULL, 'I'}, +#ifdef CONFIG_TOOLS_LIBCRYPTO
- {"private-key", required_argument, NULL, 'p'},
- {"certificate", required_argument, NULL, 'c'},
- {"monotonic-count", required_argument, NULL, 'm'},
- {"dump-sig", no_argument, NULL, 'd'},
+#endif {"help", no_argument, NULL, 'h'}, {NULL, 0, NULL, 0}, }; @@ -57,16 +80,195 @@ static void print_usage(void) "\t-r, --raw <raw image> new raw image file\n" "\t-i, --index <index> update image index\n" "\t-I, --instance <instance> update hardware instance\n" +#ifdef CONFIG_TOOLS_LIBCRYPTO
"\t-p, --private-key <privkey file> private key file\n"
"\t-c, --certificate <cert file> signer's certificate file\n"
"\t-m, --monotonic-count <count> monotonic count\n"
"\t-d, --dump_sig dump signature (*.p7)\n"
+#endif "\t-h, --help print a help message\n", tool_name); }
Please, add Sphinx documentation.
I added the man page. Why need another different format of doc? I think that doc/develop/uefi/uefi.rst gives you an enough introduction to the command. (Although the doc will have to been updated due to the latest change of mkeficapsule syntax that I'm also proposing.)
Actually, there is no sphinx doc for any host tools.
+struct auth_context {
- char *key_file;
- char *cert_file;
- u8 *image_data;
- size_t image_size;
- struct efi_firmware_image_authentication auth;
- u8 *sig_data;
- size_t sig_size;
+};
+static int dump_sig;
+#ifdef CONFIG_TOOLS_LIBCRYPTO +static EVP_PKEY *fileio_read_pkey(const char *filename) +{
- EVP_PKEY *key = NULL;
- BIO *bio;
- bio = BIO_new_file(filename, "r");
- if (!bio)
goto out;
- key = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
+out:
- BIO_free_all(bio);
- if (!key) {
printf("Can't load key from file '%s'\n", filename);
ERR_print_errors_fp(stderr);
- }
- return key;
+}
Please, add Sphinx documentation for all functions.
Yeah, but "all" is a too forcible requirement. There is no source code of host tools to meet the requirement. Actually, most don't have even one description of a function.
I think that, if it is a really required element in the source, it should be explicitly described somewhere under "doc".
+static X509 *fileio_read_cert(const char *filename) +{
- X509 *cert = NULL;
- BIO *bio;
- bio = BIO_new_file(filename, "r");
- if (!bio)
goto out;
- cert = PEM_read_bio_X509(bio, NULL, NULL, NULL);
+out:
- BIO_free_all(bio);
- if (!cert) {
printf("Can't load certificate from file '%s'\n", filename);
ERR_print_errors_fp(stderr);
- }
- return cert;
+}
+static int create_auth_data(struct auth_context *ctx) +{
- EVP_PKEY *key = NULL;
- X509 *cert = NULL;
- BIO *data_bio = NULL;
- const EVP_MD *md;
- PKCS7 *p7;
- int flags, ret = -1;
- OpenSSL_add_all_digests();
- OpenSSL_add_all_ciphers();
- ERR_load_crypto_strings();
- key = fileio_read_pkey(ctx->key_file);
- if (!key)
goto err;
- cert = fileio_read_cert(ctx->cert_file);
- if (!cert)
goto err;
- /*
* create a BIO, containing:
* * firmware image
* * monotonic count
* in this order!
* See EDK2's FmpAuthenticatedHandlerRsa2048Sha256()
*/
- data_bio = BIO_new(BIO_s_mem());
- BIO_write(data_bio, ctx->image_data, ctx->image_size);
- BIO_write(data_bio, &ctx->auth.monotonic_count,
sizeof(ctx->auth.monotonic_count));
- md = EVP_get_digestbyname("SHA256");
- if (!md)
goto err;
- /* create signature */
- /* TODO: maybe add PKCS7_NOATTR and PKCS7_NOSMIMECAP */
- flags = PKCS7_BINARY | PKCS7_DETACHED;
- p7 = PKCS7_sign(NULL, NULL, NULL, data_bio, flags | PKCS7_PARTIAL);
- if (!p7)
goto err;
- if (!PKCS7_sign_add_signer(p7, cert, key, md, flags))
goto err;
- if (!PKCS7_final(p7, data_bio, flags))
goto err;
- /* convert pkcs7 into DER */
- ctx->sig_data = NULL;
- ctx->sig_size = ASN1_item_i2d((ASN1_VALUE *)p7, &ctx->sig_data,
ASN1_ITEM_rptr(PKCS7));
- if (!ctx->sig_size)
goto err;
- /* fill auth_info */
- ctx->auth.auth_info.hdr.dwLength = sizeof(ctx->auth.auth_info)
+ ctx->sig_size;
- ctx->auth.auth_info.hdr.wRevision = WIN_CERT_REVISION_2_0;
- ctx->auth.auth_info.hdr.wCertificateType = WIN_CERT_TYPE_EFI_GUID;
- memcpy(&ctx->auth.auth_info.cert_type, &efi_guid_cert_type_pkcs7,
sizeof(efi_guid_cert_type_pkcs7));
- ret = 0;
+err:
- BIO_free_all(data_bio);
- EVP_PKEY_free(key);
- X509_free(cert);
- return ret;
+}
+static int dump_signature(const char *path, u8 *signature, size_t sig_size) +{
- char *sig_path;
- FILE *f;
- size_t size;
- int ret = -1;
- sig_path = malloc(strlen(path) + 3 + 1);
- if (!sig_path)
return ret;
- sprintf(sig_path, "%s.p7", path);
- f = fopen(sig_path, "w");
- if (!f)
goto err;
- size = fwrite(signature, 1, sig_size, f);
- if (size == sig_size)
ret = 0;
- fclose(f);
+err:
- free(sig_path);
- return ret;
+}
+static void free_sig_data(struct auth_context *ctx) +{
- if (ctx->sig_size)
OPENSSL_free(ctx->sig_data);
+} +#else +static int create_auth_data(struct auth_context *ctx) +{
- return 0;
+}
+static int dump_signature(const char *path, u8 *signature, size_t sig_size) +{
- return 0;
+}
+static void free_sig_data(struct auth_context *ctx) {} +#endif
- static int create_fwbin(char *path, char *bin, efi_guid_t *guid,
unsigned long index, unsigned long instance)
unsigned long index, unsigned long instance,
{ struct efi_capsule_header header; struct efi_firmware_management_capsule_header capsule; struct efi_firmware_management_capsule_image_header image;uint64_t mcount, char *privkey_file, char *cert_file)
- struct auth_context auth_context; FILE *f, *g; struct stat bin_stat; u8 *data;
@@ -78,6 +280,7 @@ static int create_fwbin(char *path, char *bin, efi_guid_t *guid, printf("\tbin: %s\n\ttype: %pUl\n", bin, guid); printf("\tindex: %ld\n\tinstance: %ld\n", index, instance);
[tools/mkeficapsule.c:281] (warning) %ld in format string (no. 1) requires 'long' but the argument type is 'unsigned long'.
Will fix it.
-Takahiro Akashi
Best regards
Heinrich
#endif
auth_context.sig_size = 0;
g = fopen(bin, "r"); if (!g) {
@@ -93,11 +296,34 @@ static int create_fwbin(char *path, char *bin, efi_guid_t *guid, printf("cannot allocate memory: %zx\n", (size_t)bin_stat.st_size); goto err_1; }
- f = fopen(path, "w");
- if (!f) {
printf("cannot open %s\n", path);
- size = fread(data, 1, bin_stat.st_size, g);
- if (size < bin_stat.st_size) {
}printf("read failed (%zx)\n", size); goto err_2;
- /* first, calculate signature to determine its size */
- if (privkey_file && cert_file) {
auth_context.key_file = privkey_file;
auth_context.cert_file = cert_file;
auth_context.auth.monotonic_count = mcount;
auth_context.image_data = data;
auth_context.image_size = bin_stat.st_size;
if (create_auth_data(&auth_context)) {
printf("Signing firmware image failed\n");
goto err_3;
}
if (dump_sig &&
dump_signature(path, auth_context.sig_data,
auth_context.sig_size)) {
printf("Creating signature file failed\n");
goto err_3;
}
- }
- header.capsule_guid = efi_guid_fm_capsule; header.header_size = sizeof(header); /* TODO: The current implementation ignores flags */
@@ -106,11 +332,20 @@ static int create_fwbin(char *path, char *bin, efi_guid_t *guid, + sizeof(capsule) + sizeof(u64) + sizeof(image) + bin_stat.st_size;
if (auth_context.sig_size)
header.capsule_image_size += sizeof(auth_context.auth)
+ auth_context.sig_size;
f = fopen(path, "w");
if (!f) {
printf("cannot open %s\n", path);
goto err_3;
}
size = fwrite(&header, 1, sizeof(header), f); if (size < sizeof(header)) { printf("write failed (%zx)\n", size);
goto err_3;
goto err_4;
}
capsule.version = 0x00000001;
@@ -119,13 +354,13 @@ static int create_fwbin(char *path, char *bin, efi_guid_t *guid, size = fwrite(&capsule, 1, sizeof(capsule), f); if (size < (sizeof(capsule))) { printf("write failed (%zx)\n", size);
goto err_3;
} offset = sizeof(capsule) + sizeof(u64); size = fwrite(&offset, 1, sizeof(offset), f); if (size < sizeof(offset)) { printf("write failed (%zx)\n", size);goto err_4;
goto err_3;
goto err_4;
}
image.version = 0x00000003;
@@ -135,34 +370,53 @@ static int create_fwbin(char *path, char *bin, efi_guid_t *guid, image.reserved[1] = 0; image.reserved[2] = 0; image.update_image_size = bin_stat.st_size;
if (auth_context.sig_size)
image.update_image_size += sizeof(auth_context.auth)
+ auth_context.sig_size;
image.update_vendor_code_size = 0; /* none */ image.update_hardware_instance = instance; image.image_capsule_support = 0;
if (auth_context.sig_size)
image.image_capsule_support |= CAPSULE_SUPPORT_AUTHENTICATION;
size = fwrite(&image, 1, sizeof(image), f); if (size < sizeof(image)) { printf("write failed (%zx)\n", size);
goto err_3;
}goto err_4;
- size = fread(data, 1, bin_stat.st_size, g);
- if (size < bin_stat.st_size) {
printf("read failed (%zx)\n", size);
goto err_3;
- if (auth_context.sig_size) {
size = fwrite(&auth_context.auth, 1,
sizeof(auth_context.auth), f);
if (size < sizeof(auth_context.auth)) {
printf("write failed (%zx)\n", size);
goto err_4;
}
size = fwrite(auth_context.sig_data, 1,
auth_context.sig_size, f);
if (size < auth_context.sig_size) {
printf("write failed (%zx)\n", size);
goto err_4;
}}
- size = fwrite(data, 1, bin_stat.st_size, f); if (size < bin_stat.st_size) { printf("write failed (%zx)\n", size);
goto err_3;
goto err_4;
}
fclose(f); fclose(g); free(data);
free_sig_data(&auth_context);
return 0;
-err_3: +err_4: fclose(f); +err_3:
- free_sig_data(&auth_context); err_2: free(data); err_1:
@@ -171,23 +425,25 @@ err_1: return -1; }
-/*
- Usage:
- $ mkeficapsule -f <firmware binary> <output file>
- */ int main(int argc, char **argv) { char *file; efi_guid_t *guid; unsigned long index, instance;
uint64_t mcount;
char *privkey_file, *cert_file; int c, idx;
file = NULL; guid = NULL; index = 0; instance = 0;
mcount = 0;
privkey_file = NULL;
cert_file = NULL;
dump_sig = 0; for (;;) {
c = getopt_long(argc, argv, "f:r:i:I:v:h", options, &idx);
c = getopt_long(argc, argv, opts_short, options, &idx); if (c == -1) break;
@@ -214,26 +470,44 @@ int main(int argc, char **argv) case 'I': instance = strtoul(optarg, NULL, 0); break; +#ifdef CONFIG_TOOLS_LIBCRYPTO
case 'p':
if (privkey_file) {
printf("Private Key already specified\n");
return -1;
}
privkey_file = optarg;
break;
case 'c':
if (cert_file) {
printf("Certificate file already specified\n");
return -1;
}
cert_file = optarg;
break;
case 'm':
mcount = strtoul(optarg, NULL, 0);
break;
case 'd':
dump_sig = 1;
break;
+#endif /* CONFIG_TOOLS_LIBCRYPTO */ case 'h': print_usage(); return 0; } }
- /* need an output file */
- if (argc != optind + 1) {
- /* check necessary parameters */
- if ((argc != optind + 1) || !file ||
((privkey_file && !cert_file) ||
}(!privkey_file && cert_file))) { print_usage(); exit(EXIT_FAILURE);
- /* need a fit image file or raw image file */
- if (!file) {
print_usage();
exit(EXIT_SUCCESS);
- }
- if (create_fwbin(argv[optind], file, guid, index, instance)
< 0) {
- if (create_fwbin(argv[optind], file, guid, index, instance,
}mcount, privkey_file, cert_file) < 0) { printf("Creating firmware capsule failed\n"); exit(EXIT_FAILURE);

On Mon, Aug 02, 2021 at 08:18:37AM +0200, Heinrich Schuchardt wrote:
On 8/2/21 5:30 AM, AKASHI Takahiro wrote:
Heinrich,
On Sun, Aug 01, 2021 at 11:21:55AM +0200, Heinrich Schuchardt wrote:
On 7/27/21 11:10 AM, AKASHI Takahiro wrote:
With this enhancement, mkeficapsule will be able to sign a capsule file when it is created. A signature added will be used later in the verification at FMP's SetImage() call.
To do that, We need specify additional command parameters: -monotonic-cout <count> : monotonic count -private-key <private key file> : private key file -certificate <certificate file> : certificate file Only when all of those parameters are given, a signature will be added to a capsule file.
Users are expected to maintain and increment the monotonic count at every time of the update for each firmware image.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org
tools/Kconfig | 7 + tools/Makefile | 8 +- tools/mkeficapsule.c | 332 +++++++++++++++++++++++++++++++++++++++---- 3 files changed, 316 insertions(+), 31 deletions(-)
diff --git a/tools/Kconfig b/tools/Kconfig index d6f82cd949b5..9a37ed035311 100644 --- a/tools/Kconfig +++ b/tools/Kconfig @@ -20,4 +20,11 @@ config TOOLS_LIBCRYPTO This selection does not affect target features, such as runtime FIT signature verification.
+config TOOLS_MKEFICAPSULE
- bool "Build efimkcapsule command"
- default y if EFI_CAPSULE_ON_DISK
- help
This command allows users to create a UEFI capsule file and,
optionally sign that file. If you want to enable UEFI capsule
endmenuupdate feature on your target, you certainly need this.
diff --git a/tools/Makefile b/tools/Makefile index bae3f95c4995..af8536489652 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -245,8 +245,12 @@ hostprogs-$(CONFIG_MIPS) += mips-relocs hostprogs-$(CONFIG_ASN1_COMPILER) += asn1_compiler HOSTCFLAGS_asn1_compiler.o = -idirafter $(srctree)/include
-mkeficapsule-objs := mkeficapsule.o $(LIBFDT_OBJS) -hostprogs-$(CONFIG_EFI_HAVE_CAPSULE_SUPPORT) += mkeficapsule +HOSTLDLIBS_mkeficapsule += -luuid +ifeq ($(CONFIG_TOOLS_LIBCRYPTO),y) +HOSTLDLIBS_mkeficapsule += \
- $(shell pkg-config --libs libssl libcrypto 2> /dev/null || echo "-lssl -lcrypto")
Please, add package pkg-config to the build dependencies enumerated in doc/build/gcc.rst.
Already there: libssl-dev
It is *pkg-config* that is missing.
OK, I see what you mean. But this use is not quite new as the first appearance of pkg-config was found in the commit 4839836a124e Author: Thomas Petazzoni thomas.petazzoni@free-electrons.com Date: Sat May 16 18:36:15 2015 +0200
tools: use pkg-config when available to get SSL flags
So a separate patch would be appropriate.
-Takahiro Akashi
+endif +hostprogs-$(CONFIG_TOOLS_MKEFICAPSULE) += mkeficapsule
# We build some files with extra pedantic flags to try to minimize things # that won't build on some weird host compiler -- though there are lots of diff --git a/tools/mkeficapsule.c b/tools/mkeficapsule.c index 4995ba4e0c2a..798706c7b5f7 100644 --- a/tools/mkeficapsule.c +++ b/tools/mkeficapsule.c @@ -15,6 +15,16 @@ #include <sys/stat.h> #include <sys/types.h>
+#include <linux/kconfig.h> +#ifdef CONFIG_TOOLS_LIBCRYPTO +#include <openssl/asn1.h> +#include <openssl/bio.h> +#include <openssl/evp.h> +#include <openssl/err.h> +#include <openssl/pem.h> +#include <openssl/pkcs7.h> +#endif
- typedef __u8 u8; typedef __u16 u16; typedef __u32 u32;
@@ -38,12 +48,25 @@ efi_guid_t efi_guid_image_type_uboot_fit = EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID; efi_guid_t efi_guid_image_type_uboot_raw = EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID; +efi_guid_t efi_guid_cert_type_pkcs7 = EFI_CERT_TYPE_PKCS7_GUID;
+#ifdef CONFIG_TOOLS_LIBCRYPTO +static const char *opts_short = "f:r:i:I:v:p:c:m:dh"; +#else +static const char *opts_short = "f:r:i:I:v:h"; +#endif
static struct option options[] = { {"fit", required_argument, NULL, 'f'}, {"raw", required_argument, NULL, 'r'}, {"index", required_argument, NULL, 'i'}, {"instance", required_argument, NULL, 'I'}, +#ifdef CONFIG_TOOLS_LIBCRYPTO
- {"private-key", required_argument, NULL, 'p'},
- {"certificate", required_argument, NULL, 'c'},
- {"monotonic-count", required_argument, NULL, 'm'},
- {"dump-sig", no_argument, NULL, 'd'},
+#endif {"help", no_argument, NULL, 'h'}, {NULL, 0, NULL, 0}, }; @@ -57,16 +80,195 @@ static void print_usage(void) "\t-r, --raw <raw image> new raw image file\n" "\t-i, --index <index> update image index\n" "\t-I, --instance <instance> update hardware instance\n" +#ifdef CONFIG_TOOLS_LIBCRYPTO
"\t-p, --private-key <privkey file> private key file\n"
"\t-c, --certificate <cert file> signer's certificate file\n"
"\t-m, --monotonic-count <count> monotonic count\n"
"\t-d, --dump_sig dump signature (*.p7)\n"
+#endif "\t-h, --help print a help message\n", tool_name); }
Please, add Sphinx documentation.
I added the man page. Why need another different format of doc? I think that doc/develop/uefi/uefi.rst gives you an enough introduction to the command. (Although the doc will have to been updated due to the latest change of mkeficapsule syntax that I'm also proposing.)
Actually, there is no sphinx doc for any host tools.
+struct auth_context {
- char *key_file;
- char *cert_file;
- u8 *image_data;
- size_t image_size;
- struct efi_firmware_image_authentication auth;
- u8 *sig_data;
- size_t sig_size;
+};
+static int dump_sig;
+#ifdef CONFIG_TOOLS_LIBCRYPTO +static EVP_PKEY *fileio_read_pkey(const char *filename) +{
- EVP_PKEY *key = NULL;
- BIO *bio;
- bio = BIO_new_file(filename, "r");
- if (!bio)
goto out;
- key = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
+out:
- BIO_free_all(bio);
- if (!key) {
printf("Can't load key from file '%s'\n", filename);
ERR_print_errors_fp(stderr);
- }
- return key;
+}
Please, add Sphinx documentation for all functions.
Yeah, but "all" is a too forcible requirement. There is no source code of host tools to meet the requirement. Actually, most don't have even one description of a function.
I think that, if it is a really required element in the source, it should be explicitly described somewhere under "doc".
+static X509 *fileio_read_cert(const char *filename) +{
- X509 *cert = NULL;
- BIO *bio;
- bio = BIO_new_file(filename, "r");
- if (!bio)
goto out;
- cert = PEM_read_bio_X509(bio, NULL, NULL, NULL);
+out:
- BIO_free_all(bio);
- if (!cert) {
printf("Can't load certificate from file '%s'\n", filename);
ERR_print_errors_fp(stderr);
- }
- return cert;
+}
+static int create_auth_data(struct auth_context *ctx) +{
- EVP_PKEY *key = NULL;
- X509 *cert = NULL;
- BIO *data_bio = NULL;
- const EVP_MD *md;
- PKCS7 *p7;
- int flags, ret = -1;
- OpenSSL_add_all_digests();
- OpenSSL_add_all_ciphers();
- ERR_load_crypto_strings();
- key = fileio_read_pkey(ctx->key_file);
- if (!key)
goto err;
- cert = fileio_read_cert(ctx->cert_file);
- if (!cert)
goto err;
- /*
* create a BIO, containing:
* * firmware image
* * monotonic count
* in this order!
* See EDK2's FmpAuthenticatedHandlerRsa2048Sha256()
*/
- data_bio = BIO_new(BIO_s_mem());
- BIO_write(data_bio, ctx->image_data, ctx->image_size);
- BIO_write(data_bio, &ctx->auth.monotonic_count,
sizeof(ctx->auth.monotonic_count));
- md = EVP_get_digestbyname("SHA256");
- if (!md)
goto err;
- /* create signature */
- /* TODO: maybe add PKCS7_NOATTR and PKCS7_NOSMIMECAP */
- flags = PKCS7_BINARY | PKCS7_DETACHED;
- p7 = PKCS7_sign(NULL, NULL, NULL, data_bio, flags | PKCS7_PARTIAL);
- if (!p7)
goto err;
- if (!PKCS7_sign_add_signer(p7, cert, key, md, flags))
goto err;
- if (!PKCS7_final(p7, data_bio, flags))
goto err;
- /* convert pkcs7 into DER */
- ctx->sig_data = NULL;
- ctx->sig_size = ASN1_item_i2d((ASN1_VALUE *)p7, &ctx->sig_data,
ASN1_ITEM_rptr(PKCS7));
- if (!ctx->sig_size)
goto err;
- /* fill auth_info */
- ctx->auth.auth_info.hdr.dwLength = sizeof(ctx->auth.auth_info)
+ ctx->sig_size;
- ctx->auth.auth_info.hdr.wRevision = WIN_CERT_REVISION_2_0;
- ctx->auth.auth_info.hdr.wCertificateType = WIN_CERT_TYPE_EFI_GUID;
- memcpy(&ctx->auth.auth_info.cert_type, &efi_guid_cert_type_pkcs7,
sizeof(efi_guid_cert_type_pkcs7));
- ret = 0;
+err:
- BIO_free_all(data_bio);
- EVP_PKEY_free(key);
- X509_free(cert);
- return ret;
+}
+static int dump_signature(const char *path, u8 *signature, size_t sig_size) +{
- char *sig_path;
- FILE *f;
- size_t size;
- int ret = -1;
- sig_path = malloc(strlen(path) + 3 + 1);
- if (!sig_path)
return ret;
- sprintf(sig_path, "%s.p7", path);
- f = fopen(sig_path, "w");
- if (!f)
goto err;
- size = fwrite(signature, 1, sig_size, f);
- if (size == sig_size)
ret = 0;
- fclose(f);
+err:
- free(sig_path);
- return ret;
+}
+static void free_sig_data(struct auth_context *ctx) +{
- if (ctx->sig_size)
OPENSSL_free(ctx->sig_data);
+} +#else +static int create_auth_data(struct auth_context *ctx) +{
- return 0;
+}
+static int dump_signature(const char *path, u8 *signature, size_t sig_size) +{
- return 0;
+}
+static void free_sig_data(struct auth_context *ctx) {} +#endif
- static int create_fwbin(char *path, char *bin, efi_guid_t *guid,
unsigned long index, unsigned long instance)
unsigned long index, unsigned long instance,
{ struct efi_capsule_header header; struct efi_firmware_management_capsule_header capsule; struct efi_firmware_management_capsule_image_header image;uint64_t mcount, char *privkey_file, char *cert_file)
- struct auth_context auth_context; FILE *f, *g; struct stat bin_stat; u8 *data;
@@ -78,6 +280,7 @@ static int create_fwbin(char *path, char *bin, efi_guid_t *guid, printf("\tbin: %s\n\ttype: %pUl\n", bin, guid); printf("\tindex: %ld\n\tinstance: %ld\n", index, instance);
[tools/mkeficapsule.c:281] (warning) %ld in format string (no. 1) requires 'long' but the argument type is 'unsigned long'.
Will fix it.
-Takahiro Akashi
Best regards
Heinrich
#endif
auth_context.sig_size = 0;
g = fopen(bin, "r"); if (!g) {
@@ -93,11 +296,34 @@ static int create_fwbin(char *path, char *bin, efi_guid_t *guid, printf("cannot allocate memory: %zx\n", (size_t)bin_stat.st_size); goto err_1; }
- f = fopen(path, "w");
- if (!f) {
printf("cannot open %s\n", path);
- size = fread(data, 1, bin_stat.st_size, g);
- if (size < bin_stat.st_size) {
}printf("read failed (%zx)\n", size); goto err_2;
- /* first, calculate signature to determine its size */
- if (privkey_file && cert_file) {
auth_context.key_file = privkey_file;
auth_context.cert_file = cert_file;
auth_context.auth.monotonic_count = mcount;
auth_context.image_data = data;
auth_context.image_size = bin_stat.st_size;
if (create_auth_data(&auth_context)) {
printf("Signing firmware image failed\n");
goto err_3;
}
if (dump_sig &&
dump_signature(path, auth_context.sig_data,
auth_context.sig_size)) {
printf("Creating signature file failed\n");
goto err_3;
}
- }
- header.capsule_guid = efi_guid_fm_capsule; header.header_size = sizeof(header); /* TODO: The current implementation ignores flags */
@@ -106,11 +332,20 @@ static int create_fwbin(char *path, char *bin, efi_guid_t *guid, + sizeof(capsule) + sizeof(u64) + sizeof(image) + bin_stat.st_size;
if (auth_context.sig_size)
header.capsule_image_size += sizeof(auth_context.auth)
+ auth_context.sig_size;
f = fopen(path, "w");
if (!f) {
printf("cannot open %s\n", path);
goto err_3;
}
size = fwrite(&header, 1, sizeof(header), f); if (size < sizeof(header)) { printf("write failed (%zx)\n", size);
goto err_3;
goto err_4;
}
capsule.version = 0x00000001;
@@ -119,13 +354,13 @@ static int create_fwbin(char *path, char *bin, efi_guid_t *guid, size = fwrite(&capsule, 1, sizeof(capsule), f); if (size < (sizeof(capsule))) { printf("write failed (%zx)\n", size);
goto err_3;
} offset = sizeof(capsule) + sizeof(u64); size = fwrite(&offset, 1, sizeof(offset), f); if (size < sizeof(offset)) { printf("write failed (%zx)\n", size);goto err_4;
goto err_3;
goto err_4;
}
image.version = 0x00000003;
@@ -135,34 +370,53 @@ static int create_fwbin(char *path, char *bin, efi_guid_t *guid, image.reserved[1] = 0; image.reserved[2] = 0; image.update_image_size = bin_stat.st_size;
if (auth_context.sig_size)
image.update_image_size += sizeof(auth_context.auth)
+ auth_context.sig_size;
image.update_vendor_code_size = 0; /* none */ image.update_hardware_instance = instance; image.image_capsule_support = 0;
if (auth_context.sig_size)
image.image_capsule_support |= CAPSULE_SUPPORT_AUTHENTICATION;
size = fwrite(&image, 1, sizeof(image), f); if (size < sizeof(image)) { printf("write failed (%zx)\n", size);
goto err_3;
}goto err_4;
- size = fread(data, 1, bin_stat.st_size, g);
- if (size < bin_stat.st_size) {
printf("read failed (%zx)\n", size);
goto err_3;
- if (auth_context.sig_size) {
size = fwrite(&auth_context.auth, 1,
sizeof(auth_context.auth), f);
if (size < sizeof(auth_context.auth)) {
printf("write failed (%zx)\n", size);
goto err_4;
}
size = fwrite(auth_context.sig_data, 1,
auth_context.sig_size, f);
if (size < auth_context.sig_size) {
printf("write failed (%zx)\n", size);
goto err_4;
}}
- size = fwrite(data, 1, bin_stat.st_size, f); if (size < bin_stat.st_size) { printf("write failed (%zx)\n", size);
goto err_3;
goto err_4;
}
fclose(f); fclose(g); free(data);
free_sig_data(&auth_context);
return 0;
-err_3: +err_4: fclose(f); +err_3:
- free_sig_data(&auth_context); err_2: free(data); err_1:
@@ -171,23 +425,25 @@ err_1: return -1; }
-/*
- Usage:
- $ mkeficapsule -f <firmware binary> <output file>
- */ int main(int argc, char **argv) { char *file; efi_guid_t *guid; unsigned long index, instance;
uint64_t mcount;
char *privkey_file, *cert_file; int c, idx;
file = NULL; guid = NULL; index = 0; instance = 0;
mcount = 0;
privkey_file = NULL;
cert_file = NULL;
dump_sig = 0; for (;;) {
c = getopt_long(argc, argv, "f:r:i:I:v:h", options, &idx);
c = getopt_long(argc, argv, opts_short, options, &idx); if (c == -1) break;
@@ -214,26 +470,44 @@ int main(int argc, char **argv) case 'I': instance = strtoul(optarg, NULL, 0); break; +#ifdef CONFIG_TOOLS_LIBCRYPTO
case 'p':
if (privkey_file) {
printf("Private Key already specified\n");
return -1;
}
privkey_file = optarg;
break;
case 'c':
if (cert_file) {
printf("Certificate file already specified\n");
return -1;
}
cert_file = optarg;
break;
case 'm':
mcount = strtoul(optarg, NULL, 0);
break;
case 'd':
dump_sig = 1;
break;
+#endif /* CONFIG_TOOLS_LIBCRYPTO */ case 'h': print_usage(); return 0; } }
- /* need an output file */
- if (argc != optind + 1) {
- /* check necessary parameters */
- if ((argc != optind + 1) || !file ||
((privkey_file && !cert_file) ||
}(!privkey_file && cert_file))) { print_usage(); exit(EXIT_FAILURE);
- /* need a fit image file or raw image file */
- if (!file) {
print_usage();
exit(EXIT_SUCCESS);
- }
- if (create_fwbin(argv[optind], file, guid, index, instance)
< 0) {
- if (create_fwbin(argv[optind], file, guid, index, instance,
}mcount, privkey_file, cert_file) < 0) { printf("Creating firmware capsule failed\n"); exit(EXIT_FAILURE);

Add a man page for mkeficapsule command.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org --- MAINTAINERS | 1 + doc/mkeficapsule.1 | 91 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 doc/mkeficapsule.1
diff --git a/MAINTAINERS b/MAINTAINERS index ae6c70860d3a..24f52f837066 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -696,6 +696,7 @@ S: Maintained T: git https://source.denx.de/u-boot/custodians/u-boot-efi.git F: doc/api/efi.rst F: doc/develop/uefi/* +F: doc/mkeficapsule.1 F: doc/usage/bootefi.rst F: drivers/rtc/emul_rtc.c F: include/capitalization.h diff --git a/doc/mkeficapsule.1 b/doc/mkeficapsule.1 new file mode 100644 index 000000000000..7c2341160ea4 --- /dev/null +++ b/doc/mkeficapsule.1 @@ -0,0 +1,91 @@ +.TH MAEFICAPSULE 1 "May 2021" + +.SH NAME +mkeficapsule - Generate EFI capsule file for U-Boot + +.SH SYNOPSIS +.B mkeficapsule +.RB [\fIoptions\fP] " \fIcapsule-file\fP" + +.SH "DESCRIPTION" +The +\fBmkeficapsule\fP +command is used to create an EFI capsule file for use with the U-Boot +EFI capsule update. +A capsule file may contain various type of firmware blobs which +are to be applied to the system and must be placed in the specific +directory on the UEFI system partition. An update will be automatically +executed at next reboot. + +Optionally, a capsule file can be signed with a given private key. +In this case, the update will be authenticated by verifying the signature +before applying. + +\fBmkeficapsule\fP supports two different format of image files: +.TP +.I raw image +format is a single binary blob of any type of firmware. + +.TP +.I FIT (Flattened Image Tree) image +format +is the same as used in the new \fIuImage\fP format and allows for +multiple binary blobs in a single capsule file. +This type of image file can be generated by \fBmkimage\fP. + +.SH "OPTIONS" + +.TP +.BI "-f, --fit \fIfit-image-file\fP" +Specify a FIT image file + +.TP +.BI "-r, --raw \fIraw-image-file\fP" +Specify a raw image file + +.TP +.BI "-i, --index \fIindex\fP" +Specify an image index + +.TP +.BI "-I, --instance \fIinstance\fP" +Specify a hardware instance + +.TP +.BI "-h, --help" +Print a help message + +.TP 0 +.B With signing: + +.TP +.BI "-p, --private-key \fIprivate-key-file\fP" +Specify signer's private key file in PEM + +.TP +.BI "-c, --certificate \fIcertificate-file\fP" +Specify signer's certificate file in EFI certificate list format + +.TP +.BI "-m, --monotonic-count \fIcount\fP" +Specify a monotonic count which is set to be monotonically incremented +at every firmware update. + +.TP +.BI "-d, --dump_sig" +Dump signature data into *.p7 file + +.PP +.SH FILES +.TP +.BI "\fI/EFI/UpdateCapsule\fP" +The directory in which all capsule files be placed + +.SH SEE ALSO +.B mkimage + +.SH AUTHORS +Written by AKASHI Takahiro takahiro.akashi@linaro.org + +.SH HOMEPAGE +http://www.denx.de/wiki/U-Boot/WebHome

On 7/27/21 11:10 AM, AKASHI Takahiro wrote:
Add a man page for mkeficapsule command.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org
Reviewed-by: Heinrich Schuchardt xypron.glpk@gmx.de
MAINTAINERS | 1 + doc/mkeficapsule.1 | 91 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 doc/mkeficapsule.1
diff --git a/MAINTAINERS b/MAINTAINERS index ae6c70860d3a..24f52f837066 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -696,6 +696,7 @@ S: Maintained T: git https://source.denx.de/u-boot/custodians/u-boot-efi.git F: doc/api/efi.rst F: doc/develop/uefi/* +F: doc/mkeficapsule.1 F: doc/usage/bootefi.rst F: drivers/rtc/emul_rtc.c F: include/capitalization.h diff --git a/doc/mkeficapsule.1 b/doc/mkeficapsule.1 new file mode 100644 index 000000000000..7c2341160ea4 --- /dev/null +++ b/doc/mkeficapsule.1 @@ -0,0 +1,91 @@ +.TH MAEFICAPSULE 1 "May 2021"
+.SH NAME +mkeficapsule - Generate EFI capsule file for U-Boot
+.SH SYNOPSIS +.B mkeficapsule +.RB [\fIoptions\fP] " \fIcapsule-file\fP"
+.SH "DESCRIPTION" +The +\fBmkeficapsule\fP +command is used to create an EFI capsule file for use with the U-Boot +EFI capsule update. +A capsule file may contain various type of firmware blobs which +are to be applied to the system and must be placed in the specific +directory on the UEFI system partition. An update will be automatically +executed at next reboot.
+Optionally, a capsule file can be signed with a given private key. +In this case, the update will be authenticated by verifying the signature +before applying.
+\fBmkeficapsule\fP supports two different format of image files: +.TP +.I raw image +format is a single binary blob of any type of firmware.
+.TP +.I FIT (Flattened Image Tree) image +format +is the same as used in the new \fIuImage\fP format and allows for +multiple binary blobs in a single capsule file. +This type of image file can be generated by \fBmkimage\fP.
+.SH "OPTIONS"
+.TP +.BI "-f, --fit \fIfit-image-file\fP" +Specify a FIT image file
+.TP +.BI "-r, --raw \fIraw-image-file\fP" +Specify a raw image file
+.TP +.BI "-i, --index \fIindex\fP" +Specify an image index
+.TP +.BI "-I, --instance \fIinstance\fP" +Specify a hardware instance
+.TP +.BI "-h, --help" +Print a help message
+.TP 0 +.B With signing:
+.TP +.BI "-p, --private-key \fIprivate-key-file\fP" +Specify signer's private key file in PEM
+.TP +.BI "-c, --certificate \fIcertificate-file\fP" +Specify signer's certificate file in EFI certificate list format
+.TP +.BI "-m, --monotonic-count \fIcount\fP" +Specify a monotonic count which is set to be monotonically incremented +at every firmware update.
+.TP +.BI "-d, --dump_sig" +Dump signature data into *.p7 file
+.PP +.SH FILES +.TP +.BI "\fI/EFI/UpdateCapsule\fP" +The directory in which all capsule files be placed
+.SH SEE ALSO +.B mkimage
+.SH AUTHORS +Written by AKASHI Takahiro takahiro.akashi@linaro.org
+.SH HOMEPAGE +http://www.denx.de/wiki/U-Boot/WebHome

Now we can use mkeficapsule command instead of EDK-II's script to create a signed capsule file. So update the instruction for capsule authentication.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org --- doc/develop/uefi/uefi.rst | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-)
diff --git a/doc/develop/uefi/uefi.rst b/doc/develop/uefi/uefi.rst index 64fe9346c7f2..5ccb455da984 100644 --- a/doc/develop/uefi/uefi.rst +++ b/doc/develop/uefi/uefi.rst @@ -347,23 +347,20 @@ and used by the steps highlighted below:: -keyout CRT.key -out CRT.crt -nodes -days 365 $ cert-to-efi-sig-list CRT.crt CRT.esl
- $ openssl x509 -in CRT.crt -out CRT.cer -outform DER - $ openssl x509 -inform DER -in CRT.cer -outform PEM -out CRT.pub.pem - - $ openssl pkcs12 -export -out CRT.pfx -inkey CRT.key -in CRT.crt - $ openssl pkcs12 -in CRT.pfx -nodes -out CRT.pem - -The capsule file can be generated by using the GenerateCapsule.py -script in EDKII:: - - $ ./BaseTools/BinWrappers/PosixLike/GenerateCapsule -e -o \ - <capsule_file_name> --monotonic-count <val> --fw-version \ - <val> --lsv <val> --guid \ - e2bb9c06-70e9-4b14-97a3-5a7913176e3f --verbose \ - --update-image-index <val> --signer-private-cert \ - /path/to/CRT.pem --trusted-public-cert \ - /path/to/CRT.pub.pem --other-public-cert /path/to/CRT.pub.pem \ - <u-boot.bin> +The signed capsule file can be generated by using tools/mkeficapsule. +To build this tool, enable:: + + CONFIG_TOOLS_MKEFICAPSULE=y + CONFIG_TOOLS_LIBCRYPTO=y + +To generate and sign the capsule file:: + + $ mkeficapsule --monotonic-count 1 \ + --private-key CRT.key \ + --certificate CRT.crt \ + --index 1 --instance 0 \ + [--fit <FIT image> | --raw <raw image>] \ + <capsule_file_name>
Place the capsule generated in the above step on the EFI System Partition under the EFI/UpdateCapsule directory

On 7/27/21 11:10 AM, AKASHI Takahiro wrote:
Now we can use mkeficapsule command instead of EDK-II's script to create a signed capsule file. So update the instruction for capsule authentication.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org
Acked-by: Heinrich Schuchardt xypron.glpk@gmx.de
doc/develop/uefi/uefi.rst | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-)
diff --git a/doc/develop/uefi/uefi.rst b/doc/develop/uefi/uefi.rst index 64fe9346c7f2..5ccb455da984 100644 --- a/doc/develop/uefi/uefi.rst +++ b/doc/develop/uefi/uefi.rst @@ -347,23 +347,20 @@ and used by the steps highlighted below:: -keyout CRT.key -out CRT.crt -nodes -days 365 $ cert-to-efi-sig-list CRT.crt CRT.esl
$ openssl x509 -in CRT.crt -out CRT.cer -outform DER
$ openssl x509 -inform DER -in CRT.cer -outform PEM -out CRT.pub.pem
$ openssl pkcs12 -export -out CRT.pfx -inkey CRT.key -in CRT.crt
$ openssl pkcs12 -in CRT.pfx -nodes -out CRT.pem
-The capsule file can be generated by using the GenerateCapsule.py -script in EDKII::
- $ ./BaseTools/BinWrappers/PosixLike/GenerateCapsule -e -o \
<capsule_file_name> --monotonic-count <val> --fw-version \
<val> --lsv <val> --guid \
e2bb9c06-70e9-4b14-97a3-5a7913176e3f --verbose \
--update-image-index <val> --signer-private-cert \
/path/to/CRT.pem --trusted-public-cert \
/path/to/CRT.pub.pem --other-public-cert /path/to/CRT.pub.pem \
<u-boot.bin>
+The signed capsule file can be generated by using tools/mkeficapsule. +To build this tool, enable::
- CONFIG_TOOLS_MKEFICAPSULE=y
- CONFIG_TOOLS_LIBCRYPTO=y
+To generate and sign the capsule file::
$ mkeficapsule --monotonic-count 1 \
--private-key CRT.key \
--certificate CRT.crt \
--index 1 --instance 0 \
[--fit <FIT image> | --raw <raw image>] \
<capsule_file_name>
Place the capsule generated in the above step on the EFI System Partition under the EFI/UpdateCapsule directory

The check for CONFIG_EFI_CAPSULE_KEY_PATH: ifeq ("$(wildcard $(EFI_CAPSULE_KEY_PATH))","") does not allow users to specify a relative path for including a public key binary. This is fine for most of all cases, but it will make it difficult to add pytest test cases as pre-created keys/certificates are placed in "test" directory.
So just ease the check, still causing an error if the specified file does not exist at compiling efi_capsule_key.S.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org --- lib/efi_loader/Makefile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index 9b369430e258..fca0da4d131e 100644 --- a/lib/efi_loader/Makefile +++ b/lib/efi_loader/Makefile @@ -21,8 +21,9 @@ targets += helloworld.o endif
ifeq ($(CONFIG_EFI_CAPSULE_AUTHENTICATE),y) -EFI_CAPSULE_KEY_PATH := $(subst $",,$(CONFIG_EFI_CAPSULE_KEY_PATH)) -ifeq ("$(wildcard $(EFI_CAPSULE_KEY_PATH))","") +#EFI_CAPSULE_KEY_PATH := $(subst $",,$(CONFIG_EFI_CAPSULE_KEY_PATH)) +#ifeq ("$(wildcard $(EFI_CAPSULE_KEY_PATH))","") +ifeq ($(CONFIG_EFI_CAPSULE_KEY_PATH),"") $(error .esl cerificate not found. Configure your CONFIG_EFI_CAPSULE_KEY_PATH) endif endif

On 7/27/21 11:10 AM, AKASHI Takahiro wrote:
The check for CONFIG_EFI_CAPSULE_KEY_PATH: ifeq ("$(wildcard $(EFI_CAPSULE_KEY_PATH))","") does not allow users to specify a relative path for including a public key binary. This is fine for most of all cases, but it will make it difficult to add pytest test cases as pre-created keys/certificates are placed in "test" directory.
So just ease the check, still causing an error if the specified file does not exist at compiling efi_capsule_key.S.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org
lib/efi_loader/Makefile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index 9b369430e258..fca0da4d131e 100644 --- a/lib/efi_loader/Makefile +++ b/lib/efi_loader/Makefile @@ -21,8 +21,9 @@ targets += helloworld.o endif
ifeq ($(CONFIG_EFI_CAPSULE_AUTHENTICATE),y) -EFI_CAPSULE_KEY_PATH := $(subst $",,$(CONFIG_EFI_CAPSULE_KEY_PATH)) -ifeq ("$(wildcard $(EFI_CAPSULE_KEY_PATH))","") +#EFI_CAPSULE_KEY_PATH := $(subst $",,$(CONFIG_EFI_CAPSULE_KEY_PATH)) +#ifeq ("$(wildcard $(EFI_CAPSULE_KEY_PATH))","")
Please, remove these two comment lines.
+ifeq ($(CONFIG_EFI_CAPSULE_KEY_PATH),"") $(error .esl cerificate not found. Configure your CONFIG_EFI_CAPSULE_KEY_PATH)
%s/cerificate/certificate/
Best regards
Heinrich
endif endif

On Sun, Aug 01, 2021 at 11:35:15AM +0200, Heinrich Schuchardt wrote:
On 7/27/21 11:10 AM, AKASHI Takahiro wrote:
The check for CONFIG_EFI_CAPSULE_KEY_PATH: ifeq ("$(wildcard $(EFI_CAPSULE_KEY_PATH))","") does not allow users to specify a relative path for including a public key binary. This is fine for most of all cases, but it will make it difficult to add pytest test cases as pre-created keys/certificates are placed in "test" directory.
So just ease the check, still causing an error if the specified file does not exist at compiling efi_capsule_key.S.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org
lib/efi_loader/Makefile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index 9b369430e258..fca0da4d131e 100644 --- a/lib/efi_loader/Makefile +++ b/lib/efi_loader/Makefile @@ -21,8 +21,9 @@ targets += helloworld.o endif
ifeq ($(CONFIG_EFI_CAPSULE_AUTHENTICATE),y) -EFI_CAPSULE_KEY_PATH := $(subst $",,$(CONFIG_EFI_CAPSULE_KEY_PATH)) -ifeq ("$(wildcard $(EFI_CAPSULE_KEY_PATH))","") +#EFI_CAPSULE_KEY_PATH := $(subst $",,$(CONFIG_EFI_CAPSULE_KEY_PATH)) +#ifeq ("$(wildcard $(EFI_CAPSULE_KEY_PATH))","")
Please, remove these two comment lines.
I forgot to do so.
+ifeq ($(CONFIG_EFI_CAPSULE_KEY_PATH),"") $(error .esl cerificate not found. Configure your CONFIG_EFI_CAPSULE_KEY_PATH)
%s/cerificate/certificate/
This misspelling does exist in the original. I won't fix it.
-Takahiro Akashi
Best regards
Heinrich
endif endif

Add a couple of test cases against capsule image authentication for capsule-on-disk, where only a signed capsule file with the verified signature will be applied to the system.
Due to the difficulty of embedding a public key (esl file) in U-Boot binary during pytest setup time, all the keys/certificates are pre-created.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org --- test/py/tests/test_efi_capsule/SIGNER.crt | 19 ++ test/py/tests/test_efi_capsule/SIGNER.esl | Bin 0 -> 829 bytes test/py/tests/test_efi_capsule/SIGNER.key | 28 +++ test/py/tests/test_efi_capsule/SIGNER2.crt | 19 ++ test/py/tests/test_efi_capsule/SIGNER2.key | 28 +++ .../py/tests/test_efi_capsule/capsule_defs.py | 5 + test/py/tests/test_efi_capsule/conftest.py | 35 ++- .../test_capsule_firmware_signed.py | 228 ++++++++++++++++++ 8 files changed, 359 insertions(+), 3 deletions(-) create mode 100644 test/py/tests/test_efi_capsule/SIGNER.crt create mode 100644 test/py/tests/test_efi_capsule/SIGNER.esl create mode 100644 test/py/tests/test_efi_capsule/SIGNER.key create mode 100644 test/py/tests/test_efi_capsule/SIGNER2.crt create mode 100644 test/py/tests/test_efi_capsule/SIGNER2.key create mode 100644 test/py/tests/test_efi_capsule/test_capsule_firmware_signed.py
diff --git a/test/py/tests/test_efi_capsule/SIGNER.crt b/test/py/tests/test_efi_capsule/SIGNER.crt new file mode 100644 index 000000000000..f63ec01d9996 --- /dev/null +++ b/test/py/tests/test_efi_capsule/SIGNER.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDDTCCAfWgAwIBAgIUD96z+lSbhDFN76YoIY2LnDBt1yQwDQYJKoZIhvcNAQEL +BQAwFjEUMBIGA1UEAwwLVEVTVF9TSUdORVIwHhcNMjEwNzI2MDg1MzE1WhcNMjIw +NzI2MDg1MzE1WjAWMRQwEgYDVQQDDAtURVNUX1NJR05FUjCCASIwDQYJKoZIhvcN +AQEBBQADggEPADCCAQoCggEBAMBuazX28i0y4L0loJYJOtlvF5eWb4tbx7zwei5c +KoSzQYixinS10OrVy7y8mELyXOlGOOsM509vzvoia0nffwEPsvTBeS3le2JBz9iN +/+AIo+gUmzgEPQN+jp+s4fi0yzRvq3BgWu1ego2gExxQ7AePQHoSkX8UeC3Kb7SF +a8Kt/TopOupZfEuZ+EtoxPA4JUStFgEUEcRJEfpQqECXV+lKqcyqHc2ZUzMisu+i +5omkneX8sEZdIPFsSGanCyY3F9VjWzIxo60PU2xUBOIcEUg5luR+VXT4090g/yCw +8PSf9rIKgGIQSQKAlUSc7zuXQIdgIMTS1xUpc/Nx+SqWNZECAwEAAaNTMFEwHQYD +VR0OBBYEFHndZVpPrAjc3OD3UZ3xkXQqDOlZMB8GA1UdIwQYMBaAFHndZVpPrAjc +3OD3UZ3xkXQqDOlZMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEB +AG88t6w0qTXE50ltps62f6wtuuZsiX1zj+AluO4E8E3Wi0QsNtT24JdY2P4mAg8y +abYLdgJIldzzsfjWWok9Dfqnx29tqgesKWkgUo16v70i4EVZ9YWGe+CfOK639OxL +4D0XPcU5CUpDrEcnt59wCxQ7IArZzrDxrqigEw5nReejtgQV/mEzvVOzWjLjmngy +SpvrydxYpfSvOJ3KGV9xw3Oa/qO3pS0ZNX9QqZdcC94M0SI6OF635oxJkz6JToYq ++qtv9PZtZnEU/cwzL0nTXMj7yRsP5+2Wre26yT62nKRy9P/3UFwmsJ0OuEmnol5I +141ZGfBYmSQ6EReOwNeK7A0= +-----END CERTIFICATE----- diff --git a/test/py/tests/test_efi_capsule/SIGNER.esl b/test/py/tests/test_efi_capsule/SIGNER.esl new file mode 100644 index 0000000000000000000000000000000000000000..a54536e243d274b74985abbecfe234d14013ef33 GIT binary patch literal 829 zcmZ1&d0^?2Da*aux2_hA(f&|m%gg`<iclKDgOCPI%)ACoj9(WpGchtTiSXas{3~R3 zi=prPWg3dT-E$0bud5jFvT<s)d9;1!Wn|=LWiSvk6fqEDV-96u=HU);4GxJ9_H_4i z4Kk1u=QT1kFgG$YurM_?G>rmsjgYuF^))dnAzQ)7%D~*j$j<<D6&F(zBO}9sylm5N zpLC5L>{VSbjnnF8zWDTM`Q6dS_k5_*i_vP??AWoft7PkiS65H(*)zlGQ_M>@i`P8Q z{qxWLQp)zcU(d+D>C3@N-KW(_j^}Um{(r!+_=U)93l>}Ey1w~q9{$*J+9ZE<K|<8q zxTf9(!ZHDG*!vx-geKODROp_{-_n|WXzgDsO{-UtHQqCScxN2>V4>==R*X?Z@QA12 zuYeT})5BkStvs_z_Uz1HW2H^+7d`7-GWY494Q{atA9Fm?mUF9_i(gHSHZokimOnTr zgyoTppoitOCv~AEKQ7-@_^+_x!<YHrHgPp133xI!Om&&_-g>%2dxFA|OV>p;i$53s z)S6~Gk%^g+fpKxLL7;&wFw|xFSj1RFD(|L7`LE%)bLYYLz_}kMmT2+3j5Lr3Nh`BR z7>G4sSHKTaAk4`4pM}+c8Au@qJ1}N}!OqB#Z?k=k$x72B&pmUOo!eHwMt9e<oX*<f z{s*c%-m!e}z1HobV|L}+gXs}B{;4tX8)a_eE@SeTdgt@TAJ?KfZFzq!Kc1hvihYe{ zrb19})&9Lo4_qU^wzgG2m~XLe`<FM~4{XJ4k6LniIj?b7-#)*9Tf|y{>*l!)AJ?r| zAk3HU`h4*=7SVr+#(RS|M;SeyRbk{c`}N5?5lg?Ux0riMGQRL|@vMJ~w=dO|G_4O< zIX#B^9?wN3D~q`8&w4y3+jaW2Y5iKA|K(e5TA|3_GsgO!mt#)+J}J%r{Oz>0Z+D%v r+csxO(U<?<17g%R%;nqRxqMNa$MxPw$qx}TRjdTX`wm?1dcz9<2x(B#
literal 0 HcmV?d00001
diff --git a/test/py/tests/test_efi_capsule/SIGNER.key b/test/py/tests/test_efi_capsule/SIGNER.key new file mode 100644 index 000000000000..9952647ed74a --- /dev/null +++ b/test/py/tests/test_efi_capsule/SIGNER.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEuwIBADANBgkqhkiG9w0BAQEFAASCBKUwggShAgEAAoIBAQDAbms19vItMuC9 +JaCWCTrZbxeXlm+LW8e88HouXCqEs0GIsYp0tdDq1cu8vJhC8lzpRjjrDOdPb876 +ImtJ338BD7L0wXkt5XtiQc/Yjf/gCKPoFJs4BD0Dfo6frOH4tMs0b6twYFrtXoKN +oBMcUOwHj0B6EpF/FHgtym+0hWvCrf06KTrqWXxLmfhLaMTwOCVErRYBFBHESRH6 +UKhAl1fpSqnMqh3NmVMzIrLvouaJpJ3l/LBGXSDxbEhmpwsmNxfVY1syMaOtD1Ns +VATiHBFIOZbkflV0+NPdIP8gsPD0n/ayCoBiEEkCgJVEnO87l0CHYCDE0tcVKXPz +cfkqljWRAgMBAAECggEAItLYrAdohC105kXs7bn14GtuRYx/2yRc3SBXvBQJzcHy +1h3rBHvytszB9gHbPCJIFh8TJdZL9eAyAKpB6Dh9718773cjyt6AmaN3TaVE7PIj +V1iDTnvV3tAEV3kd27g8Hd0nlUqaqeI0lhSl4LX0QNn3vR+nHOxDY2YDGRQcEDrD +4hlCIGzAfbCW9gINdadQnC6p9NEBbfJ18doCagdn1Q1UYs8YlWwhBK98wXKGsG6T +TUywOWIe6+VJqzSwZn5YkDVD3qD4tToar7T0jrCvZjbTbOsjtinD70c3uBcrK/XN +gpwJfTiDLo1d0tNoWCRUH0myMs1fq3H3SkdfqB1GwQKBgQDrw8FwUc3Q+j8YhR7i +73H/osk3VOZhCPsqbrQThUo5ZV4EXqp9E3PLN5E3suWgfaXVCEI3lHARUyR+J+E/ +evIrUUnkIryLdVOwwEWRonW4cLANjLSzT0eA85CFLXKUaij7Jfon2YNs9CmUARnC +M96T3a89XOezX/SbRVz6X8KslQKBgQDQ8onkHcscHMANIjgxycIgYF+MvxwHRICA +nt3ZSQiGSXJbWK7/sM5yd16ulvsXL7aF9G+q5osOzDWJ0w4SOhqNDfItrFH34Px6 +qEPjq/sAigqqrQls7uu7MHfkE+eEy181CoT9argxo8ifAQDn4YtXBW6L7p6AgaAx +83FAbBcqDQKBgQClHk185534zTqhZqIyF7bEbfL0sJ5EuXCG0E+IGGLafdbxwocu +4A/J9Jnc44sU8srQv1745Bn02EEHpdCIkAfJNL5Ga9mW5k39zTsr+xbtXObAJppr +touCkZLW4vSLYypecsOXYyw7g2kXQgoTTBaHgsv3cvjHVN3QXSz4IVcLXQJ/LBL9 +AyFFtqhZ2mtdbyMfz7SEcyvcvau1b2wTX8IICktz09DhGQ4yffKwBiPS0xE9bwQg +iewXaQeqQ2hBj5ayAw7uBrRSlfbfSwAzUdL1Hyf/GAFn+5JqJxISOAn6zAgaDRYq +90mLkOz7ZI7RohfxTGnY56ttw62UHPU87lneiQKBgHcVituUDJgmbaHXx2IVzKsm +5uDyXUf4S+tY5CZj6WTsb70+q4PYfh1D02nZgxuLNwpwNI0uhLIkLYHcL3poOapC +LCXS8tsexNosmrTmjHFh/uNdKb7bKbMxyzYrr+ADKMclF3CJzKDzLfiIe9Na+bWa +q5/HYNIw5zJyapPksgr4 +-----END PRIVATE KEY----- diff --git a/test/py/tests/test_efi_capsule/SIGNER2.crt b/test/py/tests/test_efi_capsule/SIGNER2.crt new file mode 100644 index 000000000000..8889a3ed930a --- /dev/null +++ b/test/py/tests/test_efi_capsule/SIGNER2.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDDTCCAfWgAwIBAgIUfmZcui7VkJEe9jx25Epo6jJ6l+owDQYJKoZIhvcNAQEL +BQAwFjEUMBIGA1UEAwwLVEVTVF9TSUdORVIwHhcNMjEwNzI2MDg1MzE1WhcNMjIw +NzI2MDg1MzE1WjAWMRQwEgYDVQQDDAtURVNUX1NJR05FUjCCASIwDQYJKoZIhvcN +AQEBBQADggEPADCCAQoCggEBANozXTFKGVx0121MIBoSgxfI8IHcfY32T/LQusse +PaXsm0GaJNwOgEP34u1k0cz466swfBCqTcZRjKuDpcH1sgrF1XaKjxuwYuiJrbsf +ykVesN1z1bIamkFdVR/CBJEwN/epsyCBQCSbcxUwEX+ayq2zp+kSweew1B4i3u8f +nbqFB15Rt+KAzFaBlvOJhmoZP7uYtb8zHa58eteaxQmPFt3v6eEbgOt92oVB8fPQ +JJBuxUAHdimMDQ9mBGUosXR8PFyma5jOiOyY+0oTfig4bRHbGxCGMYyABJDH+j4e +7Zl7lVMsq2fTm/lGONRX2QPLfMO298pz/wundJmYhseibvUCAwEAAaNTMFEwHQYD +VR0OBBYEFDPYxE3oBmU1pWrZpY62JuXgcK5aMB8GA1UdIwQYMBaAFDPYxE3oBmU1 +pWrZpY62JuXgcK5aMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEB +AEtY9QnvTvgmXmep7AMv/T6+GpERvsRdi+Lc+16L7uSCQhouDkeu5/sUHax6icX1 +NyDb3u6tyQhMnm7CD+7Mo74wrZ4vK2SzBoZSBLi+Tyz2ScyysdRIo7O42nxVyWm7 +ifZVfQKvanUjDSxPO89yJDYp0znvVpuZOzYXFHdprHoR5Atkth11HFHzWDzqblKS +sx145wgPZ9bYohuOn1weyORsG9bJcHznPyJ1ceAOFk40bKWWLQtruWIhY4aZIlJN +cDKv92rtgVApaamu+WRC4pzgQMQYKOcnMz4ZKeOKgEajfo6nOUVrvc0IYO6wixvi +V+Msrg5o7ag2SN2AHg5/1/4= +-----END CERTIFICATE----- diff --git a/test/py/tests/test_efi_capsule/SIGNER2.key b/test/py/tests/test_efi_capsule/SIGNER2.key new file mode 100644 index 000000000000..ee467fd9f7a6 --- /dev/null +++ b/test/py/tests/test_efi_capsule/SIGNER2.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDaM10xShlcdNdt +TCAaEoMXyPCB3H2N9k/y0LrLHj2l7JtBmiTcDoBD9+LtZNHM+OurMHwQqk3GUYyr +g6XB9bIKxdV2io8bsGLoia27H8pFXrDdc9WyGppBXVUfwgSRMDf3qbMggUAkm3MV +MBF/msqts6fpEsHnsNQeIt7vH526hQdeUbfigMxWgZbziYZqGT+7mLW/Mx2ufHrX +msUJjxbd7+nhG4DrfdqFQfHz0CSQbsVAB3YpjA0PZgRlKLF0fDxcpmuYzojsmPtK +E34oOG0R2xsQhjGMgASQx/o+Hu2Ze5VTLKtn05v5RjjUV9kDy3zDtvfKc/8Lp3SZ +mIbHom71AgMBAAECggEBAJXskO3bAg364kJg+fWwHo7rLAWuYD54rXojXRVPFAC7 +z/mFVio1dIA/BJcknNr/db5MNBKnUYUgZ005yVy52rl4MTGgBrB5w5wPbWWTdEGx +zEh83KnhiXe8D08g2k6AGRR8b224IUCF5s76FivdScGMHaURlFYDs9t5DkCzMocC +ty0ewHv9aeMSzJl4y+DrRw+NkkAntlAkerCI5PInFtxyOQ6lFIRkMKlBA//VL0QF +B9yGbmfoxlErWCqnj70DTcVO7O2AaijU+FTMRbb/V7r34GPU0Cfeum6gGNOtDkaX +3UnWGR2esiHViMqz8vvEYtVIxHhLTD7INqDlK/yiNEECgYEA+ua1JcHXI2qS3cV/ +BuVvBrd3MzIpZvddCcTdo/B7WT3EoTupEG1gcajrCuNQDtRoizSbMuhCXYoMsktF +wXFoTWoGr8yO7uVU5r2nCXZneprV3kuQmR0qYipN2GTCGSE1rKQI+YXeALPF1qIp +12vUVdzWVDJvlQRMvSTlzpRZQkkCgYEA3qKI1ZsBszKPbnzLX91+ZAZeAwwN/HvS +nrIveJAci/9U2yV2mw3l/Dulc8EkGABs/cMp47toje8DmsSfdu1yIYqpi3MHvefX ++ijc3ry5v28Hia3WP3WPczqhbkT7cco0t8Vwm9w1B+kkreuRCtyoCOLsRauB0CH1 +QJjMtPAth00CgYAKUUhruA/nxe8qLX/uwaqSJSNCuLJZKJzr1OukXTRFVDPsyW5H +XagUpHSd6wEUywlNiClFq6VnAVFKV6wTq101qcGCoy/RhR67qlrfGb5hnVJkJMla +coeWp9SxrFsK+4GgitJPqICbmMju7ZY45JdDvKQXrEdIYnfhY04L86/D+QKBgBxx +nZPU0vnHCuYt0Xn0/XHgEmDHSH4qf7VAxKndl5gXTgsVlTqoIur/39qTIX5jh4lA +RvjOd8Qydj5uwoTaP0ujwJeNYb7UgRZ35AgdCoo3sDnZ2NaQuXwaUIebDpjyIZwd +AI8ZKjlRgxspToWZvWotO8yG5fXmcMQJAZZYXSi9AoGBALfXX/C5ojwms1l+XP+p +FKzOFZ/uEKPfQid+2Sm1BknXXGVbs3zJ4OdonTvhjq+VQvXTW4IvjgY8TpumQZvE +8nb7I8E1B6ajkSvgfetN9jlKM5hzIfJ3Vxx6hMGMab1ySKy3rZGPL706CW2BeMI2 +v2k9P0qWItuE4S7I4hEsovwS +-----END PRIVATE KEY----- diff --git a/test/py/tests/test_efi_capsule/capsule_defs.py b/test/py/tests/test_efi_capsule/capsule_defs.py index 4fd6353c2040..aa9bf5eee3aa 100644 --- a/test/py/tests/test_efi_capsule/capsule_defs.py +++ b/test/py/tests/test_efi_capsule/capsule_defs.py @@ -3,3 +3,8 @@ # Directories CAPSULE_DATA_DIR = '/EFI/CapsuleTestData' CAPSULE_INSTALL_DIR = '/EFI/UpdateCapsule' + +# v1.5.1 or earlier of efitools has a bug in sha256 calculation, and +# you need build a newer version on your own. +# The path must terminate with '/'. +EFITOOLS_PATH = '' diff --git a/test/py/tests/test_efi_capsule/conftest.py b/test/py/tests/test_efi_capsule/conftest.py index 6ad5608cd71c..35cfa5513703 100644 --- a/test/py/tests/test_efi_capsule/conftest.py +++ b/test/py/tests/test_efi_capsule/conftest.py @@ -10,13 +10,13 @@ import pytest from capsule_defs import *
# -# Fixture for UEFI secure boot test +# Fixture for UEFI capsule test #
- @pytest.fixture(scope='session') def efi_capsule_data(request, u_boot_config): - """Set up a file system to be used in UEFI capsule test. + """Set up a file system to be used in UEFI capsule and + authentication test.
Args: request: Pytest request object. @@ -40,6 +40,22 @@ def efi_capsule_data(request, u_boot_config): check_call('mkdir -p %s' % data_dir, shell=True) check_call('mkdir -p %s' % install_dir, shell=True)
+ capsule_auth_enabled = u_boot_config.buildconfig.get( + 'config_efi_capsule_authenticate') + # NOTE: + # private keys (SIGNER?.key) dn certificates (SIGNER?.crt) + # in this pytest directory are created this way: + # Create private key (SIGNER.key) and certificate (SIGNER.crt) + # check_call('cd %s; openssl req -x509 -sha256 -newkey rsa:2048 -subj /CN=TEST_SIGNER/ -keyout SIGNER.key -out SIGNER.crt -nodes -days 365' + # % data_dir, shell=True) + # check_call('cd %s; %scert-to-efi-sig-list SIGNER.crt SIGNER.esl' + # % (data_dir, EFITOOLS_PATH), shell=True) + + # Create *malicious* private key (SIGNER2.key) and certificate + # (SIGNER2.crt) + # check_call('cd %s; openssl req -x509 -sha256 -newkey rsa:2048 -subj /CN=TEST_SIGNER/ -keyout SIGNER2.key -out SIGNER2.crt -nodes -days 365' + # % data_dir, shell=True) + # Create capsule files # two regions: one for u-boot.bin and the other for u-boot.env check_call('cd %s; echo -n u-boot:Old > u-boot.bin.old; echo -n u-boot:New > u-boot.bin.new; echo -n u-boot-env:Old -> u-boot.env.old; echo -n u-boot-env:New > u-boot.env.new' % data_dir, @@ -56,6 +72,19 @@ def efi_capsule_data(request, u_boot_config): check_call('cd %s; %s/tools/mkeficapsule --raw u-boot.bin.new --index 1 Test02' % (data_dir, u_boot_config.build_dir), shell=True) + if capsule_auth_enabled: + # copy keys/certificates + check_call('cp %s/test/py/tests/test_efi_capsule/SIGNER*.* %s' % + (u_boot_config.source_dir, data_dir), + shell=True) + # firmware signed with proper key + check_call('cd %s; %s/tools/mkeficapsule --raw u-boot.bin.new --index 1 --monotonic-count 1 --private-key SIGNER.key --certificate SIGNER.crt Test03' % + (data_dir, u_boot_config.build_dir), + shell=True) + # firmware signed with *mal* key + check_call('cd %s; %s/tools/mkeficapsule --raw u-boot.bin.new --index 1 --monotonic-count 1 --private-key SIGNER2.key --certificate SIGNER2.crt Test04' % + (data_dir, u_boot_config.build_dir), + shell=True)
# Create a disk image with EFI system partition check_call('virt-make-fs --partition=gpt --size=+1M --type=vfat %s %s' % diff --git a/test/py/tests/test_efi_capsule/test_capsule_firmware_signed.py b/test/py/tests/test_efi_capsule/test_capsule_firmware_signed.py new file mode 100644 index 000000000000..8fe93ef424ac --- /dev/null +++ b/test/py/tests/test_efi_capsule/test_capsule_firmware_signed.py @@ -0,0 +1,228 @@ +# SPDX-License-Identifier: GPL-2.0+ +# Copyright (c) 2021, Linaro Limited +# Author: AKASHI Takahiro takahiro.akashi@linaro.org +# +# U-Boot UEFI: Firmware Update (Signed capsule) Test + +""" +This test verifies capsule-on-disk firmware update +with signed capsule files +""" + +from subprocess import check_call, check_output, CalledProcessError +import pytest +from capsule_defs import * + +@pytest.mark.boardspec('sandbox') +@pytest.mark.buildconfigspec('efi_capsule_firmware_raw') +@pytest.mark.buildconfigspec('efi_capsule_authenticate') +@pytest.mark.buildconfigspec('dfu') +@pytest.mark.buildconfigspec('dfu_sf') +@pytest.mark.buildconfigspec('cmd_efidebug') +@pytest.mark.buildconfigspec('cmd_fat') +@pytest.mark.buildconfigspec('cmd_memory') +@pytest.mark.buildconfigspec('cmd_nvedit_efi') +@pytest.mark.buildconfigspec('cmd_sf') +@pytest.mark.slow +class TestEfiCapsuleFirmwareSigned(object): + def test_efi_capsule_auth1( + self, u_boot_config, u_boot_console, efi_capsule_data): + """ + Test Case 1 - Update U-Boot on SPI Flash, raw image format + 0x100000-0x150000: U-Boot binary (but dummy) + + If the capsule is properly signed, the authentication + should pass and the firmware be updated. + """ + disk_img = efi_capsule_data + with u_boot_console.log.section('Test Case 1-a, before reboot'): + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % disk_img, + 'efidebug boot add -b 1 TEST host 0:1 /helloworld.efi', + 'efidebug boot order 1', + 'env set -e -nv -bs -rt OsIndications =0x0000000000000004', + 'env set dfu_alt_info "sf 0:0=u-boot-bin raw 0x100000 0x50000;u-boot-env raw 0x150000 0x200000"', + 'env save']) + + # initialize content + output = u_boot_console.run_command_list([ + 'sf probe 0:0', + 'fatload host 0:1 4000000 %s/u-boot.bin.old' % CAPSULE_DATA_DIR, + 'sf write 4000000 100000 10', + 'sf read 5000000 100000 10', + 'md.b 5000000 10']) + assert 'Old' in ''.join(output) + + # place a capsule file + output = u_boot_console.run_command_list([ + 'fatload host 0:1 4000000 %s/Test03' % CAPSULE_DATA_DIR, + 'fatwrite host 0:1 4000000 %s/Test03 $filesize' % CAPSULE_INSTALL_DIR, + 'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR]) + assert 'Test03' in ''.join(output) + + # reboot + u_boot_console.restart_uboot() + + capsule_early = u_boot_config.buildconfig.get( + 'config_efi_capsule_on_disk_early') + with u_boot_console.log.section('Test Case 1-b, after reboot'): + if not capsule_early: + # make sure that dfu_alt_info exists even persistent variables + # are not available. + output = u_boot_console.run_command_list([ + 'env set dfu_alt_info "sf 0:0=u-boot-bin raw 0x100000 0x50000;u-boot-env raw 0x150000 0x200000"', + 'host bind 0 %s' % disk_img, + 'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR]) + assert 'Test03' in ''.join(output) + + # need to run uefi command to initiate capsule handling + output = u_boot_console.run_command( + 'env print -e Capsule0000') + + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % disk_img, + 'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR]) + assert 'Test03' not in ''.join(output) + + output = u_boot_console.run_command_list([ + 'sf probe 0:0', + 'sf read 4000000 100000 10', + 'md.b 4000000 10']) + assert 'u-boot:New' in ''.join(output) + + def test_efi_capsule_auth2( + self, u_boot_config, u_boot_console, efi_capsule_data): + """ + Test Case 2 - Update U-Boot on SPI Flash, raw image format + 0x100000-0x150000: U-Boot binary (but dummy) + + If the capsule is signed but with an invalid key, + the authentication should fail and the firmware + not be updated. + """ + disk_img = efi_capsule_data + with u_boot_console.log.section('Test Case 2-a, before reboot'): + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % disk_img, + 'efidebug boot add -b 1 TEST host 0:1 /helloworld.efi', + 'efidebug boot order 1', + 'env set -e -nv -bs -rt OsIndications =0x0000000000000004', + 'env set dfu_alt_info "sf 0:0=u-boot-bin raw 0x100000 0x50000;u-boot-env raw 0x150000 0x200000"', + 'env save']) + + # initialize content + output = u_boot_console.run_command_list([ + 'sf probe 0:0', + 'fatload host 0:1 4000000 %s/u-boot.bin.old' % CAPSULE_DATA_DIR, + 'sf write 4000000 100000 10', + 'sf read 5000000 100000 10', + 'md.b 5000000 10']) + assert 'Old' in ''.join(output) + + # place a capsule file + output = u_boot_console.run_command_list([ + 'fatload host 0:1 4000000 %s/Test04' % CAPSULE_DATA_DIR, + 'fatwrite host 0:1 4000000 %s/Test04 $filesize' % CAPSULE_INSTALL_DIR, + 'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR]) + assert 'Test04' in ''.join(output) + + # reboot + u_boot_console.restart_uboot() + + capsule_early = u_boot_config.buildconfig.get( + 'config_efi_capsule_on_disk_early') + with u_boot_console.log.section('Test Case 2-b, after reboot'): + if not capsule_early: + # make sure that dfu_alt_info exists even persistent variables + # are not available. + output = u_boot_console.run_command_list([ + 'env set dfu_alt_info "sf 0:0=u-boot-bin raw 0x100000 0x50000;u-boot-env raw 0x150000 0x200000"', + 'host bind 0 %s' % disk_img, + 'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR]) + assert 'Test04' in ''.join(output) + + # need to run uefi command to initiate capsule handling + output = u_boot_console.run_command( + 'env print -e Capsule0000') + + # deleted any way + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % disk_img, + 'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR]) + assert 'Test04' not in ''.join(output) + + # TODO: check CapsuleStatus in CapsuleXXXX + + output = u_boot_console.run_command_list([ + 'sf probe 0:0', + 'sf read 4000000 100000 10', + 'md.b 4000000 10']) + assert 'u-boot:Old' in ''.join(output) + + def test_efi_capsule_auth3( + self, u_boot_config, u_boot_console, efi_capsule_data): + """ + Test Case 3 - Update U-Boot on SPI Flash, raw image format + 0x100000-0x150000: U-Boot binary (but dummy) + + If the capsule is not signed, the authentication + should fail and the firmware not be updated. + """ + disk_img = efi_capsule_data + with u_boot_console.log.section('Test Case 3-a, before reboot'): + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % disk_img, + 'efidebug boot add -b 1 TEST host 0:1 /helloworld.efi', + 'efidebug boot order 1', + 'env set -e -nv -bs -rt OsIndications =0x0000000000000004', + 'env set dfu_alt_info "sf 0:0=u-boot-bin raw 0x100000 0x50000;u-boot-env raw 0x150000 0x200000"', + 'env save']) + + # initialize content + output = u_boot_console.run_command_list([ + 'sf probe 0:0', + 'fatload host 0:1 4000000 %s/u-boot.bin.old' % CAPSULE_DATA_DIR, + 'sf write 4000000 100000 10', + 'sf read 5000000 100000 10', + 'md.b 5000000 10']) + assert 'Old' in ''.join(output) + + # place a capsule file + output = u_boot_console.run_command_list([ + 'fatload host 0:1 4000000 %s/Test02' % CAPSULE_DATA_DIR, + 'fatwrite host 0:1 4000000 %s/Test02 $filesize' % CAPSULE_INSTALL_DIR, + 'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR]) + assert 'Test02' in ''.join(output) + + # reboot + u_boot_console.restart_uboot() + + capsule_early = u_boot_config.buildconfig.get( + 'config_efi_capsule_on_disk_early') + with u_boot_console.log.section('Test Case 3-b, after reboot'): + if not capsule_early: + # make sure that dfu_alt_info exists even persistent variables + # are not available. + output = u_boot_console.run_command_list([ + 'env set dfu_alt_info "sf 0:0=u-boot-bin raw 0x100000 0x50000;u-boot-env raw 0x150000 0x200000"', + 'host bind 0 %s' % disk_img, + 'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR]) + assert 'Test02' in ''.join(output) + + # need to run uefi command to initiate capsule handling + output = u_boot_console.run_command( + 'env print -e Capsule0000') + + # deleted any way + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % disk_img, + 'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR]) + assert 'Test02' not in ''.join(output) + + # TODO: check CapsuleStatus in CapsuleXXXX + + output = u_boot_console.run_command_list([ + 'sf probe 0:0', + 'sf read 4000000 100000 10', + 'md.b 4000000 10']) + assert 'u-boot:Old' in ''.join(output)

On 7/27/21 11:10 AM, AKASHI Takahiro wrote:
Add a couple of test cases against capsule image authentication for capsule-on-disk, where only a signed capsule file with the verified signature will be applied to the system.
Due to the difficulty of embedding a public key (esl file) in U-Boot binary during pytest setup time, all the keys/certificates are pre-created.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org
Please, check the pylint warnings:
$ pylint test/py/tests/test_efi_capsule/test_capsule_firmware_signed.py ************* Module test_capsule_firmware_signed test/py/tests/test_efi_capsule/test_capsule_firmware_signed.py:44:0: C0301: Line too long (113/100) (line-too-long) test/py/tests/test_efi_capsule/test_capsule_firmware_signed.py:73:0: C0301: Line too long (117/100) (line-too-long) test/py/tests/test_efi_capsule/test_capsule_firmware_signed.py:110:0: C0301: Line too long (113/100) (line-too-long) test/py/tests/test_efi_capsule/test_capsule_firmware_signed.py:139:0: C0301: Line too long (117/100) (line-too-long) test/py/tests/test_efi_capsule/test_capsule_firmware_signed.py:178:0: C0301: Line too long (113/100) (line-too-long) test/py/tests/test_efi_capsule/test_capsule_firmware_signed.py:207:0: C0301: Line too long (117/100) (line-too-long) test/py/tests/test_efi_capsule/test_capsule_firmware_signed.py:154:2: W0511: TODO: check CapsuleStatus in CapsuleXXXX (fixme) test/py/tests/test_efi_capsule/test_capsule_firmware_signed.py:222:2: W0511: TODO: check CapsuleStatus in CapsuleXXXX (fixme) test/py/tests/test_efi_capsule/test_capsule_firmware_signed.py:14:0: W0401: Wildcard import capsule_defs (wildcard-import) test/py/tests/test_efi_capsule/test_capsule_firmware_signed.py:27:0: C0115: Missing class docstring (missing-class-docstring) test/py/tests/test_efi_capsule/test_capsule_firmware_signed.py:27:0: R0205: Class 'TestEfiCapsuleFirmwareSigned' inherits from object, can be safely removed from bases in python3 (useless-object-inheritance) test/py/tests/test_efi_capsule/test_capsule_firmware_signed.py:28:4: R0201: Method could be a function (no-self-use) test/py/tests/test_efi_capsule/test_capsule_firmware_signed.py:93:4: R0201: Method could be a function (no-self-use) test/py/tests/test_efi_capsule/test_capsule_firmware_signed.py:162:4: R0201: Method could be a function (no-self-use) test/py/tests/test_efi_capsule/test_capsule_firmware_signed.py:12:0: W0611: Unused check_call imported from subprocess (unused-import) test/py/tests/test_efi_capsule/test_capsule_firmware_signed.py:12:0: W0611: Unused check_output imported from subprocess (unused-import) test/py/tests/test_efi_capsule/test_capsule_firmware_signed.py:12:0: W0611: Unused CalledProcessError imported from subprocess (unused-import) test/py/tests/test_efi_capsule/test_capsule_firmware_signed.py:14:0: W0614: Unused import EFITOOLS_PATH from wildcard import (unused-wildcard-import)
Best regards
Heinrich
test/py/tests/test_efi_capsule/SIGNER.crt | 19 ++ test/py/tests/test_efi_capsule/SIGNER.esl | Bin 0 -> 829 bytes test/py/tests/test_efi_capsule/SIGNER.key | 28 +++ test/py/tests/test_efi_capsule/SIGNER2.crt | 19 ++ test/py/tests/test_efi_capsule/SIGNER2.key | 28 +++ .../py/tests/test_efi_capsule/capsule_defs.py | 5 + test/py/tests/test_efi_capsule/conftest.py | 35 ++- .../test_capsule_firmware_signed.py | 228 ++++++++++++++++++ 8 files changed, 359 insertions(+), 3 deletions(-) create mode 100644 test/py/tests/test_efi_capsule/SIGNER.crt create mode 100644 test/py/tests/test_efi_capsule/SIGNER.esl create mode 100644 test/py/tests/test_efi_capsule/SIGNER.key create mode 100644 test/py/tests/test_efi_capsule/SIGNER2.crt create mode 100644 test/py/tests/test_efi_capsule/SIGNER2.key create mode 100644 test/py/tests/test_efi_capsule/test_capsule_firmware_signed.py
diff --git a/test/py/tests/test_efi_capsule/SIGNER.crt b/test/py/tests/test_efi_capsule/SIGNER.crt new file mode 100644 index 000000000000..f63ec01d9996 --- /dev/null +++ b/test/py/tests/test_efi_capsule/SIGNER.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDDTCCAfWgAwIBAgIUD96z+lSbhDFN76YoIY2LnDBt1yQwDQYJKoZIhvcNAQEL +BQAwFjEUMBIGA1UEAwwLVEVTVF9TSUdORVIwHhcNMjEwNzI2MDg1MzE1WhcNMjIw +NzI2MDg1MzE1WjAWMRQwEgYDVQQDDAtURVNUX1NJR05FUjCCASIwDQYJKoZIhvcN +AQEBBQADggEPADCCAQoCggEBAMBuazX28i0y4L0loJYJOtlvF5eWb4tbx7zwei5c +KoSzQYixinS10OrVy7y8mELyXOlGOOsM509vzvoia0nffwEPsvTBeS3le2JBz9iN +/+AIo+gUmzgEPQN+jp+s4fi0yzRvq3BgWu1ego2gExxQ7AePQHoSkX8UeC3Kb7SF +a8Kt/TopOupZfEuZ+EtoxPA4JUStFgEUEcRJEfpQqECXV+lKqcyqHc2ZUzMisu+i +5omkneX8sEZdIPFsSGanCyY3F9VjWzIxo60PU2xUBOIcEUg5luR+VXT4090g/yCw +8PSf9rIKgGIQSQKAlUSc7zuXQIdgIMTS1xUpc/Nx+SqWNZECAwEAAaNTMFEwHQYD +VR0OBBYEFHndZVpPrAjc3OD3UZ3xkXQqDOlZMB8GA1UdIwQYMBaAFHndZVpPrAjc +3OD3UZ3xkXQqDOlZMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEB +AG88t6w0qTXE50ltps62f6wtuuZsiX1zj+AluO4E8E3Wi0QsNtT24JdY2P4mAg8y +abYLdgJIldzzsfjWWok9Dfqnx29tqgesKWkgUo16v70i4EVZ9YWGe+CfOK639OxL +4D0XPcU5CUpDrEcnt59wCxQ7IArZzrDxrqigEw5nReejtgQV/mEzvVOzWjLjmngy +SpvrydxYpfSvOJ3KGV9xw3Oa/qO3pS0ZNX9QqZdcC94M0SI6OF635oxJkz6JToYq ++qtv9PZtZnEU/cwzL0nTXMj7yRsP5+2Wre26yT62nKRy9P/3UFwmsJ0OuEmnol5I +141ZGfBYmSQ6EReOwNeK7A0= +-----END CERTIFICATE----- diff --git a/test/py/tests/test_efi_capsule/SIGNER.esl b/test/py/tests/test_efi_capsule/SIGNER.esl new file mode 100644 index 0000000000000000000000000000000000000000..a54536e243d274b74985abbecfe234d14013ef33 GIT binary patch literal 829 zcmZ1&d0^?2Da*aux2_hA(f&|m%gg`<iclKDgOCPI%)ACoj9(WpGchtTiSXas{3~R3 zi=prPWg3dT-E$0bud5jFvT<s)d9;1!Wn|=LWiSvk6fqEDV-96u=HU);4GxJ9_H_4i z4Kk1u=QT1kFgG$YurM_?G>rmsjgYuF^))dnAzQ)7%D~*j$j<<D6&F(zBO}9sylm5N zpLC5L>{VSbjnnF8zWDTM`Q6dS_k5_*i_vP??AWoft7PkiS65H(*)zlGQ_M>@i`P8Q z{qxWLQp)zcU(d+D>C3@N-KW(_j^}Um{(r!+_=U)93l>}Ey1w~q9{$*J+9ZE<K|<8q zxTf9(!ZHDG*!vx-geKODROp_{-_n|WXzgDsO{-UtHQqCScxN2>V4>==R*X?Z@QA12 zuYeT})5BkStvs_z_Uz1HW2H^+7d`7-GWY494Q{atA9Fm?mUF9_i(gHSHZokimOnTr zgyoTppoitOCv~AEKQ7-@_^+_x!<YHrHgPp133xI!Om&&_-g>%2dxFA|OV>p;i$53s z)S6~Gk%^g+fpKxLL7;&wFw|xFSj1RFD(|L7`LE%)bLYYLz_}kMmT2+3j5Lr3Nh`BR z7>G4sSHKTaAk4`4pM}+c8Au@qJ1}N}!OqB#Z?k=k$x72B&pmUOo!eHwMt9e<oX*<f z{s*c%-m!e}z1HobV|L}+gXs}B{;4tX8)a_eE@SeTdgt@TAJ?KfZFzq!Kc1hvihYe{ zrb19})&9Lo4_qU^wzgG2m~XLe`<FM~4{XJ4k6LniIj?b7-#)*9Tf|y{>*l!)AJ?r| zAk3HU`h4*=7SVr+#(RS|M;SeyRbk{c`}N5?5lg?Ux0riMGQRL|@vMJ~w=dO|G_4O< zIX#B^9?wN3D~q`8&w4y3+jaW2Y5iKA|K(e5TA|3_GsgO!mt#)+J}J%r{Oz>0Z+D%v r+csxO(U<?<17g%R%;nqRxqMNa$MxPw$qx}TRjdTX`wm?1dcz9<2x(B#
literal 0 HcmV?d00001
diff --git a/test/py/tests/test_efi_capsule/SIGNER.key b/test/py/tests/test_efi_capsule/SIGNER.key new file mode 100644 index 000000000000..9952647ed74a --- /dev/null +++ b/test/py/tests/test_efi_capsule/SIGNER.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEuwIBADANBgkqhkiG9w0BAQEFAASCBKUwggShAgEAAoIBAQDAbms19vItMuC9 +JaCWCTrZbxeXlm+LW8e88HouXCqEs0GIsYp0tdDq1cu8vJhC8lzpRjjrDOdPb876 +ImtJ338BD7L0wXkt5XtiQc/Yjf/gCKPoFJs4BD0Dfo6frOH4tMs0b6twYFrtXoKN +oBMcUOwHj0B6EpF/FHgtym+0hWvCrf06KTrqWXxLmfhLaMTwOCVErRYBFBHESRH6 +UKhAl1fpSqnMqh3NmVMzIrLvouaJpJ3l/LBGXSDxbEhmpwsmNxfVY1syMaOtD1Ns +VATiHBFIOZbkflV0+NPdIP8gsPD0n/ayCoBiEEkCgJVEnO87l0CHYCDE0tcVKXPz +cfkqljWRAgMBAAECggEAItLYrAdohC105kXs7bn14GtuRYx/2yRc3SBXvBQJzcHy +1h3rBHvytszB9gHbPCJIFh8TJdZL9eAyAKpB6Dh9718773cjyt6AmaN3TaVE7PIj +V1iDTnvV3tAEV3kd27g8Hd0nlUqaqeI0lhSl4LX0QNn3vR+nHOxDY2YDGRQcEDrD +4hlCIGzAfbCW9gINdadQnC6p9NEBbfJ18doCagdn1Q1UYs8YlWwhBK98wXKGsG6T +TUywOWIe6+VJqzSwZn5YkDVD3qD4tToar7T0jrCvZjbTbOsjtinD70c3uBcrK/XN +gpwJfTiDLo1d0tNoWCRUH0myMs1fq3H3SkdfqB1GwQKBgQDrw8FwUc3Q+j8YhR7i +73H/osk3VOZhCPsqbrQThUo5ZV4EXqp9E3PLN5E3suWgfaXVCEI3lHARUyR+J+E/ +evIrUUnkIryLdVOwwEWRonW4cLANjLSzT0eA85CFLXKUaij7Jfon2YNs9CmUARnC +M96T3a89XOezX/SbRVz6X8KslQKBgQDQ8onkHcscHMANIjgxycIgYF+MvxwHRICA +nt3ZSQiGSXJbWK7/sM5yd16ulvsXL7aF9G+q5osOzDWJ0w4SOhqNDfItrFH34Px6 +qEPjq/sAigqqrQls7uu7MHfkE+eEy181CoT9argxo8ifAQDn4YtXBW6L7p6AgaAx +83FAbBcqDQKBgQClHk185534zTqhZqIyF7bEbfL0sJ5EuXCG0E+IGGLafdbxwocu +4A/J9Jnc44sU8srQv1745Bn02EEHpdCIkAfJNL5Ga9mW5k39zTsr+xbtXObAJppr +touCkZLW4vSLYypecsOXYyw7g2kXQgoTTBaHgsv3cvjHVN3QXSz4IVcLXQJ/LBL9 +AyFFtqhZ2mtdbyMfz7SEcyvcvau1b2wTX8IICktz09DhGQ4yffKwBiPS0xE9bwQg +iewXaQeqQ2hBj5ayAw7uBrRSlfbfSwAzUdL1Hyf/GAFn+5JqJxISOAn6zAgaDRYq +90mLkOz7ZI7RohfxTGnY56ttw62UHPU87lneiQKBgHcVituUDJgmbaHXx2IVzKsm +5uDyXUf4S+tY5CZj6WTsb70+q4PYfh1D02nZgxuLNwpwNI0uhLIkLYHcL3poOapC +LCXS8tsexNosmrTmjHFh/uNdKb7bKbMxyzYrr+ADKMclF3CJzKDzLfiIe9Na+bWa +q5/HYNIw5zJyapPksgr4 +-----END PRIVATE KEY----- diff --git a/test/py/tests/test_efi_capsule/SIGNER2.crt b/test/py/tests/test_efi_capsule/SIGNER2.crt new file mode 100644 index 000000000000..8889a3ed930a --- /dev/null +++ b/test/py/tests/test_efi_capsule/SIGNER2.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDDTCCAfWgAwIBAgIUfmZcui7VkJEe9jx25Epo6jJ6l+owDQYJKoZIhvcNAQEL +BQAwFjEUMBIGA1UEAwwLVEVTVF9TSUdORVIwHhcNMjEwNzI2MDg1MzE1WhcNMjIw +NzI2MDg1MzE1WjAWMRQwEgYDVQQDDAtURVNUX1NJR05FUjCCASIwDQYJKoZIhvcN +AQEBBQADggEPADCCAQoCggEBANozXTFKGVx0121MIBoSgxfI8IHcfY32T/LQusse +PaXsm0GaJNwOgEP34u1k0cz466swfBCqTcZRjKuDpcH1sgrF1XaKjxuwYuiJrbsf +ykVesN1z1bIamkFdVR/CBJEwN/epsyCBQCSbcxUwEX+ayq2zp+kSweew1B4i3u8f +nbqFB15Rt+KAzFaBlvOJhmoZP7uYtb8zHa58eteaxQmPFt3v6eEbgOt92oVB8fPQ +JJBuxUAHdimMDQ9mBGUosXR8PFyma5jOiOyY+0oTfig4bRHbGxCGMYyABJDH+j4e +7Zl7lVMsq2fTm/lGONRX2QPLfMO298pz/wundJmYhseibvUCAwEAAaNTMFEwHQYD +VR0OBBYEFDPYxE3oBmU1pWrZpY62JuXgcK5aMB8GA1UdIwQYMBaAFDPYxE3oBmU1 +pWrZpY62JuXgcK5aMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEB +AEtY9QnvTvgmXmep7AMv/T6+GpERvsRdi+Lc+16L7uSCQhouDkeu5/sUHax6icX1 +NyDb3u6tyQhMnm7CD+7Mo74wrZ4vK2SzBoZSBLi+Tyz2ScyysdRIo7O42nxVyWm7 +ifZVfQKvanUjDSxPO89yJDYp0znvVpuZOzYXFHdprHoR5Atkth11HFHzWDzqblKS +sx145wgPZ9bYohuOn1weyORsG9bJcHznPyJ1ceAOFk40bKWWLQtruWIhY4aZIlJN +cDKv92rtgVApaamu+WRC4pzgQMQYKOcnMz4ZKeOKgEajfo6nOUVrvc0IYO6wixvi +V+Msrg5o7ag2SN2AHg5/1/4= +-----END CERTIFICATE----- diff --git a/test/py/tests/test_efi_capsule/SIGNER2.key b/test/py/tests/test_efi_capsule/SIGNER2.key new file mode 100644 index 000000000000..ee467fd9f7a6 --- /dev/null +++ b/test/py/tests/test_efi_capsule/SIGNER2.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDaM10xShlcdNdt +TCAaEoMXyPCB3H2N9k/y0LrLHj2l7JtBmiTcDoBD9+LtZNHM+OurMHwQqk3GUYyr +g6XB9bIKxdV2io8bsGLoia27H8pFXrDdc9WyGppBXVUfwgSRMDf3qbMggUAkm3MV +MBF/msqts6fpEsHnsNQeIt7vH526hQdeUbfigMxWgZbziYZqGT+7mLW/Mx2ufHrX +msUJjxbd7+nhG4DrfdqFQfHz0CSQbsVAB3YpjA0PZgRlKLF0fDxcpmuYzojsmPtK +E34oOG0R2xsQhjGMgASQx/o+Hu2Ze5VTLKtn05v5RjjUV9kDy3zDtvfKc/8Lp3SZ +mIbHom71AgMBAAECggEBAJXskO3bAg364kJg+fWwHo7rLAWuYD54rXojXRVPFAC7 +z/mFVio1dIA/BJcknNr/db5MNBKnUYUgZ005yVy52rl4MTGgBrB5w5wPbWWTdEGx +zEh83KnhiXe8D08g2k6AGRR8b224IUCF5s76FivdScGMHaURlFYDs9t5DkCzMocC +ty0ewHv9aeMSzJl4y+DrRw+NkkAntlAkerCI5PInFtxyOQ6lFIRkMKlBA//VL0QF +B9yGbmfoxlErWCqnj70DTcVO7O2AaijU+FTMRbb/V7r34GPU0Cfeum6gGNOtDkaX +3UnWGR2esiHViMqz8vvEYtVIxHhLTD7INqDlK/yiNEECgYEA+ua1JcHXI2qS3cV/ +BuVvBrd3MzIpZvddCcTdo/B7WT3EoTupEG1gcajrCuNQDtRoizSbMuhCXYoMsktF +wXFoTWoGr8yO7uVU5r2nCXZneprV3kuQmR0qYipN2GTCGSE1rKQI+YXeALPF1qIp +12vUVdzWVDJvlQRMvSTlzpRZQkkCgYEA3qKI1ZsBszKPbnzLX91+ZAZeAwwN/HvS +nrIveJAci/9U2yV2mw3l/Dulc8EkGABs/cMp47toje8DmsSfdu1yIYqpi3MHvefX ++ijc3ry5v28Hia3WP3WPczqhbkT7cco0t8Vwm9w1B+kkreuRCtyoCOLsRauB0CH1 +QJjMtPAth00CgYAKUUhruA/nxe8qLX/uwaqSJSNCuLJZKJzr1OukXTRFVDPsyW5H +XagUpHSd6wEUywlNiClFq6VnAVFKV6wTq101qcGCoy/RhR67qlrfGb5hnVJkJMla +coeWp9SxrFsK+4GgitJPqICbmMju7ZY45JdDvKQXrEdIYnfhY04L86/D+QKBgBxx +nZPU0vnHCuYt0Xn0/XHgEmDHSH4qf7VAxKndl5gXTgsVlTqoIur/39qTIX5jh4lA +RvjOd8Qydj5uwoTaP0ujwJeNYb7UgRZ35AgdCoo3sDnZ2NaQuXwaUIebDpjyIZwd +AI8ZKjlRgxspToWZvWotO8yG5fXmcMQJAZZYXSi9AoGBALfXX/C5ojwms1l+XP+p +FKzOFZ/uEKPfQid+2Sm1BknXXGVbs3zJ4OdonTvhjq+VQvXTW4IvjgY8TpumQZvE +8nb7I8E1B6ajkSvgfetN9jlKM5hzIfJ3Vxx6hMGMab1ySKy3rZGPL706CW2BeMI2 +v2k9P0qWItuE4S7I4hEsovwS +-----END PRIVATE KEY----- diff --git a/test/py/tests/test_efi_capsule/capsule_defs.py b/test/py/tests/test_efi_capsule/capsule_defs.py index 4fd6353c2040..aa9bf5eee3aa 100644 --- a/test/py/tests/test_efi_capsule/capsule_defs.py +++ b/test/py/tests/test_efi_capsule/capsule_defs.py @@ -3,3 +3,8 @@ # Directories CAPSULE_DATA_DIR = '/EFI/CapsuleTestData' CAPSULE_INSTALL_DIR = '/EFI/UpdateCapsule'
+# v1.5.1 or earlier of efitools has a bug in sha256 calculation, and +# you need build a newer version on your own. +# The path must terminate with '/'. +EFITOOLS_PATH = '' diff --git a/test/py/tests/test_efi_capsule/conftest.py b/test/py/tests/test_efi_capsule/conftest.py index 6ad5608cd71c..35cfa5513703 100644 --- a/test/py/tests/test_efi_capsule/conftest.py +++ b/test/py/tests/test_efi_capsule/conftest.py @@ -10,13 +10,13 @@ import pytest from capsule_defs import *
# -# Fixture for UEFI secure boot test +# Fixture for UEFI capsule test #
- @pytest.fixture(scope='session') def efi_capsule_data(request, u_boot_config):
- """Set up a file system to be used in UEFI capsule test.
"""Set up a file system to be used in UEFI capsule and
authentication test. Args: request: Pytest request object.
@@ -40,6 +40,22 @@ def efi_capsule_data(request, u_boot_config): check_call('mkdir -p %s' % data_dir, shell=True) check_call('mkdir -p %s' % install_dir, shell=True)
capsule_auth_enabled = u_boot_config.buildconfig.get(
'config_efi_capsule_authenticate')
# NOTE:
# private keys (SIGNER?.key) dn certificates (SIGNER?.crt)
# in this pytest directory are created this way:
# Create private key (SIGNER.key) and certificate (SIGNER.crt)
# check_call('cd %s; openssl req -x509 -sha256 -newkey rsa:2048 -subj /CN=TEST_SIGNER/ -keyout SIGNER.key -out SIGNER.crt -nodes -days 365'
# % data_dir, shell=True)
# check_call('cd %s; %scert-to-efi-sig-list SIGNER.crt SIGNER.esl'
# % (data_dir, EFITOOLS_PATH), shell=True)
# Create *malicious* private key (SIGNER2.key) and certificate
# (SIGNER2.crt)
# check_call('cd %s; openssl req -x509 -sha256 -newkey rsa:2048 -subj /CN=TEST_SIGNER/ -keyout SIGNER2.key -out SIGNER2.crt -nodes -days 365'
# % data_dir, shell=True)
# Create capsule files # two regions: one for u-boot.bin and the other for u-boot.env check_call('cd %s; echo -n u-boot:Old > u-boot.bin.old; echo -n u-boot:New > u-boot.bin.new; echo -n u-boot-env:Old -> u-boot.env.old; echo -n u-boot-env:New > u-boot.env.new' % data_dir,
@@ -56,6 +72,19 @@ def efi_capsule_data(request, u_boot_config): check_call('cd %s; %s/tools/mkeficapsule --raw u-boot.bin.new --index 1 Test02' % (data_dir, u_boot_config.build_dir), shell=True)
if capsule_auth_enabled:
# copy keys/certificates
check_call('cp %s/test/py/tests/test_efi_capsule/SIGNER*.* %s' %
(u_boot_config.source_dir, data_dir),
shell=True)
# firmware signed with proper key
check_call('cd %s; %s/tools/mkeficapsule --raw u-boot.bin.new --index 1 --monotonic-count 1 --private-key SIGNER.key --certificate SIGNER.crt Test03' %
(data_dir, u_boot_config.build_dir),
shell=True)
# firmware signed with *mal* key
check_call('cd %s; %s/tools/mkeficapsule --raw u-boot.bin.new --index 1 --monotonic-count 1 --private-key SIGNER2.key --certificate SIGNER2.crt Test04' %
(data_dir, u_boot_config.build_dir),
shell=True) # Create a disk image with EFI system partition check_call('virt-make-fs --partition=gpt --size=+1M --type=vfat %s %s' %
diff --git a/test/py/tests/test_efi_capsule/test_capsule_firmware_signed.py b/test/py/tests/test_efi_capsule/test_capsule_firmware_signed.py new file mode 100644 index 000000000000..8fe93ef424ac --- /dev/null +++ b/test/py/tests/test_efi_capsule/test_capsule_firmware_signed.py @@ -0,0 +1,228 @@ +# SPDX-License-Identifier: GPL-2.0+ +# Copyright (c) 2021, Linaro Limited +# Author: AKASHI Takahiro takahiro.akashi@linaro.org +# +# U-Boot UEFI: Firmware Update (Signed capsule) Test
+""" +This test verifies capsule-on-disk firmware update +with signed capsule files +"""
+from subprocess import check_call, check_output, CalledProcessError +import pytest +from capsule_defs import *
+@pytest.mark.boardspec('sandbox') +@pytest.mark.buildconfigspec('efi_capsule_firmware_raw') +@pytest.mark.buildconfigspec('efi_capsule_authenticate') +@pytest.mark.buildconfigspec('dfu') +@pytest.mark.buildconfigspec('dfu_sf') +@pytest.mark.buildconfigspec('cmd_efidebug') +@pytest.mark.buildconfigspec('cmd_fat') +@pytest.mark.buildconfigspec('cmd_memory') +@pytest.mark.buildconfigspec('cmd_nvedit_efi') +@pytest.mark.buildconfigspec('cmd_sf') +@pytest.mark.slow +class TestEfiCapsuleFirmwareSigned(object):
- def test_efi_capsule_auth1(
self, u_boot_config, u_boot_console, efi_capsule_data):
"""
Test Case 1 - Update U-Boot on SPI Flash, raw image format
0x100000-0x150000: U-Boot binary (but dummy)
If the capsule is properly signed, the authentication
should pass and the firmware be updated.
"""
disk_img = efi_capsule_data
with u_boot_console.log.section('Test Case 1-a, before reboot'):
output = u_boot_console.run_command_list([
'host bind 0 %s' % disk_img,
'efidebug boot add -b 1 TEST host 0:1 /helloworld.efi',
'efidebug boot order 1',
'env set -e -nv -bs -rt OsIndications =0x0000000000000004',
'env set dfu_alt_info "sf 0:0=u-boot-bin raw 0x100000 0x50000;u-boot-env raw 0x150000 0x200000"',
'env save'])
# initialize content
output = u_boot_console.run_command_list([
'sf probe 0:0',
'fatload host 0:1 4000000 %s/u-boot.bin.old' % CAPSULE_DATA_DIR,
'sf write 4000000 100000 10',
'sf read 5000000 100000 10',
'md.b 5000000 10'])
assert 'Old' in ''.join(output)
# place a capsule file
output = u_boot_console.run_command_list([
'fatload host 0:1 4000000 %s/Test03' % CAPSULE_DATA_DIR,
'fatwrite host 0:1 4000000 %s/Test03 $filesize' % CAPSULE_INSTALL_DIR,
'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
assert 'Test03' in ''.join(output)
# reboot
u_boot_console.restart_uboot()
capsule_early = u_boot_config.buildconfig.get(
'config_efi_capsule_on_disk_early')
with u_boot_console.log.section('Test Case 1-b, after reboot'):
if not capsule_early:
# make sure that dfu_alt_info exists even persistent variables
# are not available.
output = u_boot_console.run_command_list([
'env set dfu_alt_info "sf 0:0=u-boot-bin raw 0x100000 0x50000;u-boot-env raw 0x150000 0x200000"',
'host bind 0 %s' % disk_img,
'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
assert 'Test03' in ''.join(output)
# need to run uefi command to initiate capsule handling
output = u_boot_console.run_command(
'env print -e Capsule0000')
output = u_boot_console.run_command_list([
'host bind 0 %s' % disk_img,
'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
assert 'Test03' not in ''.join(output)
output = u_boot_console.run_command_list([
'sf probe 0:0',
'sf read 4000000 100000 10',
'md.b 4000000 10'])
assert 'u-boot:New' in ''.join(output)
- def test_efi_capsule_auth2(
self, u_boot_config, u_boot_console, efi_capsule_data):
"""
Test Case 2 - Update U-Boot on SPI Flash, raw image format
0x100000-0x150000: U-Boot binary (but dummy)
If the capsule is signed but with an invalid key,
the authentication should fail and the firmware
not be updated.
"""
disk_img = efi_capsule_data
with u_boot_console.log.section('Test Case 2-a, before reboot'):
output = u_boot_console.run_command_list([
'host bind 0 %s' % disk_img,
'efidebug boot add -b 1 TEST host 0:1 /helloworld.efi',
'efidebug boot order 1',
'env set -e -nv -bs -rt OsIndications =0x0000000000000004',
'env set dfu_alt_info "sf 0:0=u-boot-bin raw 0x100000 0x50000;u-boot-env raw 0x150000 0x200000"',
'env save'])
# initialize content
output = u_boot_console.run_command_list([
'sf probe 0:0',
'fatload host 0:1 4000000 %s/u-boot.bin.old' % CAPSULE_DATA_DIR,
'sf write 4000000 100000 10',
'sf read 5000000 100000 10',
'md.b 5000000 10'])
assert 'Old' in ''.join(output)
# place a capsule file
output = u_boot_console.run_command_list([
'fatload host 0:1 4000000 %s/Test04' % CAPSULE_DATA_DIR,
'fatwrite host 0:1 4000000 %s/Test04 $filesize' % CAPSULE_INSTALL_DIR,
'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
assert 'Test04' in ''.join(output)
# reboot
u_boot_console.restart_uboot()
capsule_early = u_boot_config.buildconfig.get(
'config_efi_capsule_on_disk_early')
with u_boot_console.log.section('Test Case 2-b, after reboot'):
if not capsule_early:
# make sure that dfu_alt_info exists even persistent variables
# are not available.
output = u_boot_console.run_command_list([
'env set dfu_alt_info "sf 0:0=u-boot-bin raw 0x100000 0x50000;u-boot-env raw 0x150000 0x200000"',
'host bind 0 %s' % disk_img,
'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
assert 'Test04' in ''.join(output)
# need to run uefi command to initiate capsule handling
output = u_boot_console.run_command(
'env print -e Capsule0000')
# deleted any way
output = u_boot_console.run_command_list([
'host bind 0 %s' % disk_img,
'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
assert 'Test04' not in ''.join(output)
# TODO: check CapsuleStatus in CapsuleXXXX
output = u_boot_console.run_command_list([
'sf probe 0:0',
'sf read 4000000 100000 10',
'md.b 4000000 10'])
assert 'u-boot:Old' in ''.join(output)
- def test_efi_capsule_auth3(
self, u_boot_config, u_boot_console, efi_capsule_data):
"""
Test Case 3 - Update U-Boot on SPI Flash, raw image format
0x100000-0x150000: U-Boot binary (but dummy)
If the capsule is not signed, the authentication
should fail and the firmware not be updated.
"""
disk_img = efi_capsule_data
with u_boot_console.log.section('Test Case 3-a, before reboot'):
output = u_boot_console.run_command_list([
'host bind 0 %s' % disk_img,
'efidebug boot add -b 1 TEST host 0:1 /helloworld.efi',
'efidebug boot order 1',
'env set -e -nv -bs -rt OsIndications =0x0000000000000004',
'env set dfu_alt_info "sf 0:0=u-boot-bin raw 0x100000 0x50000;u-boot-env raw 0x150000 0x200000"',
'env save'])
# initialize content
output = u_boot_console.run_command_list([
'sf probe 0:0',
'fatload host 0:1 4000000 %s/u-boot.bin.old' % CAPSULE_DATA_DIR,
'sf write 4000000 100000 10',
'sf read 5000000 100000 10',
'md.b 5000000 10'])
assert 'Old' in ''.join(output)
# place a capsule file
output = u_boot_console.run_command_list([
'fatload host 0:1 4000000 %s/Test02' % CAPSULE_DATA_DIR,
'fatwrite host 0:1 4000000 %s/Test02 $filesize' % CAPSULE_INSTALL_DIR,
'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
assert 'Test02' in ''.join(output)
# reboot
u_boot_console.restart_uboot()
capsule_early = u_boot_config.buildconfig.get(
'config_efi_capsule_on_disk_early')
with u_boot_console.log.section('Test Case 3-b, after reboot'):
if not capsule_early:
# make sure that dfu_alt_info exists even persistent variables
# are not available.
output = u_boot_console.run_command_list([
'env set dfu_alt_info "sf 0:0=u-boot-bin raw 0x100000 0x50000;u-boot-env raw 0x150000 0x200000"',
'host bind 0 %s' % disk_img,
'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
assert 'Test02' in ''.join(output)
# need to run uefi command to initiate capsule handling
output = u_boot_console.run_command(
'env print -e Capsule0000')
# deleted any way
output = u_boot_console.run_command_list([
'host bind 0 %s' % disk_img,
'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
assert 'Test02' not in ''.join(output)
# TODO: check CapsuleStatus in CapsuleXXXX
output = u_boot_console.run_command_list([
'sf probe 0:0',
'sf read 4000000 100000 10',
'md.b 4000000 10'])
assert 'u-boot:Old' in ''.join(output)

On Sun, Aug 01, 2021 at 11:38:16AM +0200, Heinrich Schuchardt wrote:
On 7/27/21 11:10 AM, AKASHI Takahiro wrote:
Add a couple of test cases against capsule image authentication for capsule-on-disk, where only a signed capsule file with the verified signature will be applied to the system.
Due to the difficulty of embedding a public key (esl file) in U-Boot binary during pytest setup time, all the keys/certificates are pre-created.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org
Please, check the pylint warnings:
$ pylint test/py/tests/test_efi_capsule/test_capsule_firmware_signed.py ************* Module test_capsule_firmware_signed test/py/tests/test_efi_capsule/test_capsule_firmware_signed.py:44:0: C0301: Line too long (113/100) (line-too-long) test/py/tests/test_efi_capsule/test_capsule_firmware_signed.py:73:0: C0301: Line too long (117/100) (line-too-long) test/py/tests/test_efi_capsule/test_capsule_firmware_signed.py:110:0: C0301: Line too long (113/100) (line-too-long) test/py/tests/test_efi_capsule/test_capsule_firmware_signed.py:139:0: C0301: Line too long (117/100) (line-too-long) test/py/tests/test_efi_capsule/test_capsule_firmware_signed.py:178:0: C0301: Line too long (113/100) (line-too-long) test/py/tests/test_efi_capsule/test_capsule_firmware_signed.py:207:0: C0301: Line too long (117/100) (line-too-long)
As you can see, the line is given as a single "command line" string. Breaking the line into meaningless pieces of strings won't make sense here.
test/py/tests/test_efi_capsule/test_capsule_firmware_signed.py:154:2: W0511: TODO: check CapsuleStatus in CapsuleXXXX (fixme) test/py/tests/test_efi_capsule/test_capsule_firmware_signed.py:222:2: W0511: TODO: check CapsuleStatus in CapsuleXXXX (fixme)
I don't intend to fix those TODOs soon.
test/py/tests/test_efi_capsule/test_capsule_firmware_signed.py:14:0: W0401: Wildcard import capsule_defs (wildcard-import)
Will fix.
test/py/tests/test_efi_capsule/test_capsule_firmware_signed.py:27:0: C0115: Missing class docstring (missing-class-docstring) test/py/tests/test_efi_capsule/test_capsule_firmware_signed.py:27:0: R0205: Class 'TestEfiCapsuleFirmwareSigned' inherits from object, can be safely removed from bases in python3 (useless-object-inheritance) test/py/tests/test_efi_capsule/test_capsule_firmware_signed.py:28:4: R0201: Method could be a function (no-self-use) test/py/tests/test_efi_capsule/test_capsule_firmware_signed.py:93:4: R0201: Method could be a function (no-self-use) test/py/tests/test_efi_capsule/test_capsule_firmware_signed.py:162:4: R0201: Method could be a function (no-self-use)
I would like to maintain the syntax that I use in this file: class TestXXX(): def test_yyy(): ... even though pylint suggests that those changes be safely made.
"class/def" combination will allow us to add more tests cases for different test conditions in the future without modifying the structure of the file.
test/py/tests/test_efi_capsule/test_capsule_firmware_signed.py:12:0: W0611: Unused check_call imported from subprocess (unused-import) test/py/tests/test_efi_capsule/test_capsule_firmware_signed.py:12:0: W0611: Unused check_output imported from subprocess (unused-import) test/py/tests/test_efi_capsule/test_capsule_firmware_signed.py:12:0: W0611: Unused CalledProcessError imported from subprocess (unused-import) test/py/tests/test_efi_capsule/test_capsule_firmware_signed.py:14:0: W0614: Unused import EFITOOLS_PATH from wildcard import (unused-wildcard-import)
Will fix.
-Takahiro Akashi
Best regards
Heinrich
test/py/tests/test_efi_capsule/SIGNER.crt | 19 ++ test/py/tests/test_efi_capsule/SIGNER.esl | Bin 0 -> 829 bytes test/py/tests/test_efi_capsule/SIGNER.key | 28 +++ test/py/tests/test_efi_capsule/SIGNER2.crt | 19 ++ test/py/tests/test_efi_capsule/SIGNER2.key | 28 +++ .../py/tests/test_efi_capsule/capsule_defs.py | 5 + test/py/tests/test_efi_capsule/conftest.py | 35 ++- .../test_capsule_firmware_signed.py | 228 ++++++++++++++++++ 8 files changed, 359 insertions(+), 3 deletions(-) create mode 100644 test/py/tests/test_efi_capsule/SIGNER.crt create mode 100644 test/py/tests/test_efi_capsule/SIGNER.esl create mode 100644 test/py/tests/test_efi_capsule/SIGNER.key create mode 100644 test/py/tests/test_efi_capsule/SIGNER2.crt create mode 100644 test/py/tests/test_efi_capsule/SIGNER2.key create mode 100644 test/py/tests/test_efi_capsule/test_capsule_firmware_signed.py
diff --git a/test/py/tests/test_efi_capsule/SIGNER.crt b/test/py/tests/test_efi_capsule/SIGNER.crt new file mode 100644 index 000000000000..f63ec01d9996 --- /dev/null +++ b/test/py/tests/test_efi_capsule/SIGNER.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDDTCCAfWgAwIBAgIUD96z+lSbhDFN76YoIY2LnDBt1yQwDQYJKoZIhvcNAQEL +BQAwFjEUMBIGA1UEAwwLVEVTVF9TSUdORVIwHhcNMjEwNzI2MDg1MzE1WhcNMjIw +NzI2MDg1MzE1WjAWMRQwEgYDVQQDDAtURVNUX1NJR05FUjCCASIwDQYJKoZIhvcN +AQEBBQADggEPADCCAQoCggEBAMBuazX28i0y4L0loJYJOtlvF5eWb4tbx7zwei5c +KoSzQYixinS10OrVy7y8mELyXOlGOOsM509vzvoia0nffwEPsvTBeS3le2JBz9iN +/+AIo+gUmzgEPQN+jp+s4fi0yzRvq3BgWu1ego2gExxQ7AePQHoSkX8UeC3Kb7SF +a8Kt/TopOupZfEuZ+EtoxPA4JUStFgEUEcRJEfpQqECXV+lKqcyqHc2ZUzMisu+i +5omkneX8sEZdIPFsSGanCyY3F9VjWzIxo60PU2xUBOIcEUg5luR+VXT4090g/yCw +8PSf9rIKgGIQSQKAlUSc7zuXQIdgIMTS1xUpc/Nx+SqWNZECAwEAAaNTMFEwHQYD +VR0OBBYEFHndZVpPrAjc3OD3UZ3xkXQqDOlZMB8GA1UdIwQYMBaAFHndZVpPrAjc +3OD3UZ3xkXQqDOlZMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEB +AG88t6w0qTXE50ltps62f6wtuuZsiX1zj+AluO4E8E3Wi0QsNtT24JdY2P4mAg8y +abYLdgJIldzzsfjWWok9Dfqnx29tqgesKWkgUo16v70i4EVZ9YWGe+CfOK639OxL +4D0XPcU5CUpDrEcnt59wCxQ7IArZzrDxrqigEw5nReejtgQV/mEzvVOzWjLjmngy +SpvrydxYpfSvOJ3KGV9xw3Oa/qO3pS0ZNX9QqZdcC94M0SI6OF635oxJkz6JToYq ++qtv9PZtZnEU/cwzL0nTXMj7yRsP5+2Wre26yT62nKRy9P/3UFwmsJ0OuEmnol5I +141ZGfBYmSQ6EReOwNeK7A0= +-----END CERTIFICATE----- diff --git a/test/py/tests/test_efi_capsule/SIGNER.esl b/test/py/tests/test_efi_capsule/SIGNER.esl new file mode 100644 index 0000000000000000000000000000000000000000..a54536e243d274b74985abbecfe234d14013ef33 GIT binary patch literal 829 zcmZ1&d0^?2Da*aux2_hA(f&|m%gg`<iclKDgOCPI%)ACoj9(WpGchtTiSXas{3~R3 zi=prPWg3dT-E$0bud5jFvT<s)d9;1!Wn|=LWiSvk6fqEDV-96u=HU);4GxJ9_H_4i z4Kk1u=QT1kFgG$YurM_?G>rmsjgYuF^))dnAzQ)7%D~*j$j<<D6&F(zBO}9sylm5N zpLC5L>{VSbjnnF8zWDTM`Q6dS_k5_*i_vP??AWoft7PkiS65H(*)zlGQ_M>@i`P8Q z{qxWLQp)zcU(d+D>C3@N-KW(_j^}Um{(r!+_=U)93l>}Ey1w~q9{$*J+9ZE<K|<8q zxTf9(!ZHDG*!vx-geKODROp_{-_n|WXzgDsO{-UtHQqCScxN2>V4>==R*X?Z@QA12 zuYeT})5BkStvs_z_Uz1HW2H^+7d`7-GWY494Q{atA9Fm?mUF9_i(gHSHZokimOnTr zgyoTppoitOCv~AEKQ7-@_^+_x!<YHrHgPp133xI!Om&&_-g>%2dxFA|OV>p;i$53s z)S6~Gk%^g+fpKxLL7;&wFw|xFSj1RFD(|L7`LE%)bLYYLz_}kMmT2+3j5Lr3Nh`BR z7>G4sSHKTaAk4`4pM}+c8Au@qJ1}N}!OqB#Z?k=k$x72B&pmUOo!eHwMt9e<oX*<f z{s*c%-m!e}z1HobV|L}+gXs}B{;4tX8)a_eE@SeTdgt@TAJ?KfZFzq!Kc1hvihYe{ zrb19})&9Lo4_qU^wzgG2m~XLe`<FM~4{XJ4k6LniIj?b7-#)*9Tf|y{>*l!)AJ?r| zAk3HU`h4*=7SVr+#(RS|M;SeyRbk{c`}N5?5lg?Ux0riMGQRL|@vMJ~w=dO|G_4O< zIX#B^9?wN3D~q`8&w4y3+jaW2Y5iKA|K(e5TA|3_GsgO!mt#)+J}J%r{Oz>0Z+D%v r+csxO(U<?<17g%R%;nqRxqMNa$MxPw$qx}TRjdTX`wm?1dcz9<2x(B#
literal 0 HcmV?d00001
diff --git a/test/py/tests/test_efi_capsule/SIGNER.key b/test/py/tests/test_efi_capsule/SIGNER.key new file mode 100644 index 000000000000..9952647ed74a --- /dev/null +++ b/test/py/tests/test_efi_capsule/SIGNER.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEuwIBADANBgkqhkiG9w0BAQEFAASCBKUwggShAgEAAoIBAQDAbms19vItMuC9 +JaCWCTrZbxeXlm+LW8e88HouXCqEs0GIsYp0tdDq1cu8vJhC8lzpRjjrDOdPb876 +ImtJ338BD7L0wXkt5XtiQc/Yjf/gCKPoFJs4BD0Dfo6frOH4tMs0b6twYFrtXoKN +oBMcUOwHj0B6EpF/FHgtym+0hWvCrf06KTrqWXxLmfhLaMTwOCVErRYBFBHESRH6 +UKhAl1fpSqnMqh3NmVMzIrLvouaJpJ3l/LBGXSDxbEhmpwsmNxfVY1syMaOtD1Ns +VATiHBFIOZbkflV0+NPdIP8gsPD0n/ayCoBiEEkCgJVEnO87l0CHYCDE0tcVKXPz +cfkqljWRAgMBAAECggEAItLYrAdohC105kXs7bn14GtuRYx/2yRc3SBXvBQJzcHy +1h3rBHvytszB9gHbPCJIFh8TJdZL9eAyAKpB6Dh9718773cjyt6AmaN3TaVE7PIj +V1iDTnvV3tAEV3kd27g8Hd0nlUqaqeI0lhSl4LX0QNn3vR+nHOxDY2YDGRQcEDrD +4hlCIGzAfbCW9gINdadQnC6p9NEBbfJ18doCagdn1Q1UYs8YlWwhBK98wXKGsG6T +TUywOWIe6+VJqzSwZn5YkDVD3qD4tToar7T0jrCvZjbTbOsjtinD70c3uBcrK/XN +gpwJfTiDLo1d0tNoWCRUH0myMs1fq3H3SkdfqB1GwQKBgQDrw8FwUc3Q+j8YhR7i +73H/osk3VOZhCPsqbrQThUo5ZV4EXqp9E3PLN5E3suWgfaXVCEI3lHARUyR+J+E/ +evIrUUnkIryLdVOwwEWRonW4cLANjLSzT0eA85CFLXKUaij7Jfon2YNs9CmUARnC +M96T3a89XOezX/SbRVz6X8KslQKBgQDQ8onkHcscHMANIjgxycIgYF+MvxwHRICA +nt3ZSQiGSXJbWK7/sM5yd16ulvsXL7aF9G+q5osOzDWJ0w4SOhqNDfItrFH34Px6 +qEPjq/sAigqqrQls7uu7MHfkE+eEy181CoT9argxo8ifAQDn4YtXBW6L7p6AgaAx +83FAbBcqDQKBgQClHk185534zTqhZqIyF7bEbfL0sJ5EuXCG0E+IGGLafdbxwocu +4A/J9Jnc44sU8srQv1745Bn02EEHpdCIkAfJNL5Ga9mW5k39zTsr+xbtXObAJppr +touCkZLW4vSLYypecsOXYyw7g2kXQgoTTBaHgsv3cvjHVN3QXSz4IVcLXQJ/LBL9 +AyFFtqhZ2mtdbyMfz7SEcyvcvau1b2wTX8IICktz09DhGQ4yffKwBiPS0xE9bwQg +iewXaQeqQ2hBj5ayAw7uBrRSlfbfSwAzUdL1Hyf/GAFn+5JqJxISOAn6zAgaDRYq +90mLkOz7ZI7RohfxTGnY56ttw62UHPU87lneiQKBgHcVituUDJgmbaHXx2IVzKsm +5uDyXUf4S+tY5CZj6WTsb70+q4PYfh1D02nZgxuLNwpwNI0uhLIkLYHcL3poOapC +LCXS8tsexNosmrTmjHFh/uNdKb7bKbMxyzYrr+ADKMclF3CJzKDzLfiIe9Na+bWa +q5/HYNIw5zJyapPksgr4 +-----END PRIVATE KEY----- diff --git a/test/py/tests/test_efi_capsule/SIGNER2.crt b/test/py/tests/test_efi_capsule/SIGNER2.crt new file mode 100644 index 000000000000..8889a3ed930a --- /dev/null +++ b/test/py/tests/test_efi_capsule/SIGNER2.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDDTCCAfWgAwIBAgIUfmZcui7VkJEe9jx25Epo6jJ6l+owDQYJKoZIhvcNAQEL +BQAwFjEUMBIGA1UEAwwLVEVTVF9TSUdORVIwHhcNMjEwNzI2MDg1MzE1WhcNMjIw +NzI2MDg1MzE1WjAWMRQwEgYDVQQDDAtURVNUX1NJR05FUjCCASIwDQYJKoZIhvcN +AQEBBQADggEPADCCAQoCggEBANozXTFKGVx0121MIBoSgxfI8IHcfY32T/LQusse +PaXsm0GaJNwOgEP34u1k0cz466swfBCqTcZRjKuDpcH1sgrF1XaKjxuwYuiJrbsf +ykVesN1z1bIamkFdVR/CBJEwN/epsyCBQCSbcxUwEX+ayq2zp+kSweew1B4i3u8f +nbqFB15Rt+KAzFaBlvOJhmoZP7uYtb8zHa58eteaxQmPFt3v6eEbgOt92oVB8fPQ +JJBuxUAHdimMDQ9mBGUosXR8PFyma5jOiOyY+0oTfig4bRHbGxCGMYyABJDH+j4e +7Zl7lVMsq2fTm/lGONRX2QPLfMO298pz/wundJmYhseibvUCAwEAAaNTMFEwHQYD +VR0OBBYEFDPYxE3oBmU1pWrZpY62JuXgcK5aMB8GA1UdIwQYMBaAFDPYxE3oBmU1 +pWrZpY62JuXgcK5aMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEB +AEtY9QnvTvgmXmep7AMv/T6+GpERvsRdi+Lc+16L7uSCQhouDkeu5/sUHax6icX1 +NyDb3u6tyQhMnm7CD+7Mo74wrZ4vK2SzBoZSBLi+Tyz2ScyysdRIo7O42nxVyWm7 +ifZVfQKvanUjDSxPO89yJDYp0znvVpuZOzYXFHdprHoR5Atkth11HFHzWDzqblKS +sx145wgPZ9bYohuOn1weyORsG9bJcHznPyJ1ceAOFk40bKWWLQtruWIhY4aZIlJN +cDKv92rtgVApaamu+WRC4pzgQMQYKOcnMz4ZKeOKgEajfo6nOUVrvc0IYO6wixvi +V+Msrg5o7ag2SN2AHg5/1/4= +-----END CERTIFICATE----- diff --git a/test/py/tests/test_efi_capsule/SIGNER2.key b/test/py/tests/test_efi_capsule/SIGNER2.key new file mode 100644 index 000000000000..ee467fd9f7a6 --- /dev/null +++ b/test/py/tests/test_efi_capsule/SIGNER2.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDaM10xShlcdNdt +TCAaEoMXyPCB3H2N9k/y0LrLHj2l7JtBmiTcDoBD9+LtZNHM+OurMHwQqk3GUYyr +g6XB9bIKxdV2io8bsGLoia27H8pFXrDdc9WyGppBXVUfwgSRMDf3qbMggUAkm3MV +MBF/msqts6fpEsHnsNQeIt7vH526hQdeUbfigMxWgZbziYZqGT+7mLW/Mx2ufHrX +msUJjxbd7+nhG4DrfdqFQfHz0CSQbsVAB3YpjA0PZgRlKLF0fDxcpmuYzojsmPtK +E34oOG0R2xsQhjGMgASQx/o+Hu2Ze5VTLKtn05v5RjjUV9kDy3zDtvfKc/8Lp3SZ +mIbHom71AgMBAAECggEBAJXskO3bAg364kJg+fWwHo7rLAWuYD54rXojXRVPFAC7 +z/mFVio1dIA/BJcknNr/db5MNBKnUYUgZ005yVy52rl4MTGgBrB5w5wPbWWTdEGx +zEh83KnhiXe8D08g2k6AGRR8b224IUCF5s76FivdScGMHaURlFYDs9t5DkCzMocC +ty0ewHv9aeMSzJl4y+DrRw+NkkAntlAkerCI5PInFtxyOQ6lFIRkMKlBA//VL0QF +B9yGbmfoxlErWCqnj70DTcVO7O2AaijU+FTMRbb/V7r34GPU0Cfeum6gGNOtDkaX +3UnWGR2esiHViMqz8vvEYtVIxHhLTD7INqDlK/yiNEECgYEA+ua1JcHXI2qS3cV/ +BuVvBrd3MzIpZvddCcTdo/B7WT3EoTupEG1gcajrCuNQDtRoizSbMuhCXYoMsktF +wXFoTWoGr8yO7uVU5r2nCXZneprV3kuQmR0qYipN2GTCGSE1rKQI+YXeALPF1qIp +12vUVdzWVDJvlQRMvSTlzpRZQkkCgYEA3qKI1ZsBszKPbnzLX91+ZAZeAwwN/HvS +nrIveJAci/9U2yV2mw3l/Dulc8EkGABs/cMp47toje8DmsSfdu1yIYqpi3MHvefX ++ijc3ry5v28Hia3WP3WPczqhbkT7cco0t8Vwm9w1B+kkreuRCtyoCOLsRauB0CH1 +QJjMtPAth00CgYAKUUhruA/nxe8qLX/uwaqSJSNCuLJZKJzr1OukXTRFVDPsyW5H +XagUpHSd6wEUywlNiClFq6VnAVFKV6wTq101qcGCoy/RhR67qlrfGb5hnVJkJMla +coeWp9SxrFsK+4GgitJPqICbmMju7ZY45JdDvKQXrEdIYnfhY04L86/D+QKBgBxx +nZPU0vnHCuYt0Xn0/XHgEmDHSH4qf7VAxKndl5gXTgsVlTqoIur/39qTIX5jh4lA +RvjOd8Qydj5uwoTaP0ujwJeNYb7UgRZ35AgdCoo3sDnZ2NaQuXwaUIebDpjyIZwd +AI8ZKjlRgxspToWZvWotO8yG5fXmcMQJAZZYXSi9AoGBALfXX/C5ojwms1l+XP+p +FKzOFZ/uEKPfQid+2Sm1BknXXGVbs3zJ4OdonTvhjq+VQvXTW4IvjgY8TpumQZvE +8nb7I8E1B6ajkSvgfetN9jlKM5hzIfJ3Vxx6hMGMab1ySKy3rZGPL706CW2BeMI2 +v2k9P0qWItuE4S7I4hEsovwS +-----END PRIVATE KEY----- diff --git a/test/py/tests/test_efi_capsule/capsule_defs.py b/test/py/tests/test_efi_capsule/capsule_defs.py index 4fd6353c2040..aa9bf5eee3aa 100644 --- a/test/py/tests/test_efi_capsule/capsule_defs.py +++ b/test/py/tests/test_efi_capsule/capsule_defs.py @@ -3,3 +3,8 @@ # Directories CAPSULE_DATA_DIR = '/EFI/CapsuleTestData' CAPSULE_INSTALL_DIR = '/EFI/UpdateCapsule'
+# v1.5.1 or earlier of efitools has a bug in sha256 calculation, and +# you need build a newer version on your own. +# The path must terminate with '/'. +EFITOOLS_PATH = '' diff --git a/test/py/tests/test_efi_capsule/conftest.py b/test/py/tests/test_efi_capsule/conftest.py index 6ad5608cd71c..35cfa5513703 100644 --- a/test/py/tests/test_efi_capsule/conftest.py +++ b/test/py/tests/test_efi_capsule/conftest.py @@ -10,13 +10,13 @@ import pytest from capsule_defs import *
# -# Fixture for UEFI secure boot test +# Fixture for UEFI capsule test #
- @pytest.fixture(scope='session') def efi_capsule_data(request, u_boot_config):
- """Set up a file system to be used in UEFI capsule test.
"""Set up a file system to be used in UEFI capsule and
authentication test. Args: request: Pytest request object.
@@ -40,6 +40,22 @@ def efi_capsule_data(request, u_boot_config): check_call('mkdir -p %s' % data_dir, shell=True) check_call('mkdir -p %s' % install_dir, shell=True)
capsule_auth_enabled = u_boot_config.buildconfig.get(
'config_efi_capsule_authenticate')
# NOTE:
# private keys (SIGNER?.key) dn certificates (SIGNER?.crt)
# in this pytest directory are created this way:
# Create private key (SIGNER.key) and certificate (SIGNER.crt)
# check_call('cd %s; openssl req -x509 -sha256 -newkey rsa:2048 -subj /CN=TEST_SIGNER/ -keyout SIGNER.key -out SIGNER.crt -nodes -days 365'
# % data_dir, shell=True)
# check_call('cd %s; %scert-to-efi-sig-list SIGNER.crt SIGNER.esl'
# % (data_dir, EFITOOLS_PATH), shell=True)
# Create *malicious* private key (SIGNER2.key) and certificate
# (SIGNER2.crt)
# check_call('cd %s; openssl req -x509 -sha256 -newkey rsa:2048 -subj /CN=TEST_SIGNER/ -keyout SIGNER2.key -out SIGNER2.crt -nodes -days 365'
# % data_dir, shell=True)
# Create capsule files # two regions: one for u-boot.bin and the other for u-boot.env check_call('cd %s; echo -n u-boot:Old > u-boot.bin.old; echo -n u-boot:New > u-boot.bin.new; echo -n u-boot-env:Old -> u-boot.env.old; echo -n u-boot-env:New > u-boot.env.new' % data_dir,
@@ -56,6 +72,19 @@ def efi_capsule_data(request, u_boot_config): check_call('cd %s; %s/tools/mkeficapsule --raw u-boot.bin.new --index 1 Test02' % (data_dir, u_boot_config.build_dir), shell=True)
if capsule_auth_enabled:
# copy keys/certificates
check_call('cp %s/test/py/tests/test_efi_capsule/SIGNER*.* %s' %
(u_boot_config.source_dir, data_dir),
shell=True)
# firmware signed with proper key
check_call('cd %s; %s/tools/mkeficapsule --raw u-boot.bin.new --index 1 --monotonic-count 1 --private-key SIGNER.key --certificate SIGNER.crt Test03' %
(data_dir, u_boot_config.build_dir),
shell=True)
# firmware signed with *mal* key
check_call('cd %s; %s/tools/mkeficapsule --raw u-boot.bin.new --index 1 --monotonic-count 1 --private-key SIGNER2.key --certificate SIGNER2.crt Test04' %
(data_dir, u_boot_config.build_dir),
shell=True) # Create a disk image with EFI system partition check_call('virt-make-fs --partition=gpt --size=+1M --type=vfat %s %s' %
diff --git a/test/py/tests/test_efi_capsule/test_capsule_firmware_signed.py b/test/py/tests/test_efi_capsule/test_capsule_firmware_signed.py new file mode 100644 index 000000000000..8fe93ef424ac --- /dev/null +++ b/test/py/tests/test_efi_capsule/test_capsule_firmware_signed.py @@ -0,0 +1,228 @@ +# SPDX-License-Identifier: GPL-2.0+ +# Copyright (c) 2021, Linaro Limited +# Author: AKASHI Takahiro takahiro.akashi@linaro.org +# +# U-Boot UEFI: Firmware Update (Signed capsule) Test
+""" +This test verifies capsule-on-disk firmware update +with signed capsule files +"""
+from subprocess import check_call, check_output, CalledProcessError +import pytest +from capsule_defs import *
+@pytest.mark.boardspec('sandbox') +@pytest.mark.buildconfigspec('efi_capsule_firmware_raw') +@pytest.mark.buildconfigspec('efi_capsule_authenticate') +@pytest.mark.buildconfigspec('dfu') +@pytest.mark.buildconfigspec('dfu_sf') +@pytest.mark.buildconfigspec('cmd_efidebug') +@pytest.mark.buildconfigspec('cmd_fat') +@pytest.mark.buildconfigspec('cmd_memory') +@pytest.mark.buildconfigspec('cmd_nvedit_efi') +@pytest.mark.buildconfigspec('cmd_sf') +@pytest.mark.slow +class TestEfiCapsuleFirmwareSigned(object):
- def test_efi_capsule_auth1(
self, u_boot_config, u_boot_console, efi_capsule_data):
"""
Test Case 1 - Update U-Boot on SPI Flash, raw image format
0x100000-0x150000: U-Boot binary (but dummy)
If the capsule is properly signed, the authentication
should pass and the firmware be updated.
"""
disk_img = efi_capsule_data
with u_boot_console.log.section('Test Case 1-a, before reboot'):
output = u_boot_console.run_command_list([
'host bind 0 %s' % disk_img,
'efidebug boot add -b 1 TEST host 0:1 /helloworld.efi',
'efidebug boot order 1',
'env set -e -nv -bs -rt OsIndications =0x0000000000000004',
'env set dfu_alt_info "sf 0:0=u-boot-bin raw 0x100000 0x50000;u-boot-env raw 0x150000 0x200000"',
'env save'])
# initialize content
output = u_boot_console.run_command_list([
'sf probe 0:0',
'fatload host 0:1 4000000 %s/u-boot.bin.old' % CAPSULE_DATA_DIR,
'sf write 4000000 100000 10',
'sf read 5000000 100000 10',
'md.b 5000000 10'])
assert 'Old' in ''.join(output)
# place a capsule file
output = u_boot_console.run_command_list([
'fatload host 0:1 4000000 %s/Test03' % CAPSULE_DATA_DIR,
'fatwrite host 0:1 4000000 %s/Test03 $filesize' % CAPSULE_INSTALL_DIR,
'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
assert 'Test03' in ''.join(output)
# reboot
u_boot_console.restart_uboot()
capsule_early = u_boot_config.buildconfig.get(
'config_efi_capsule_on_disk_early')
with u_boot_console.log.section('Test Case 1-b, after reboot'):
if not capsule_early:
# make sure that dfu_alt_info exists even persistent variables
# are not available.
output = u_boot_console.run_command_list([
'env set dfu_alt_info "sf 0:0=u-boot-bin raw 0x100000 0x50000;u-boot-env raw 0x150000 0x200000"',
'host bind 0 %s' % disk_img,
'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
assert 'Test03' in ''.join(output)
# need to run uefi command to initiate capsule handling
output = u_boot_console.run_command(
'env print -e Capsule0000')
output = u_boot_console.run_command_list([
'host bind 0 %s' % disk_img,
'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
assert 'Test03' not in ''.join(output)
output = u_boot_console.run_command_list([
'sf probe 0:0',
'sf read 4000000 100000 10',
'md.b 4000000 10'])
assert 'u-boot:New' in ''.join(output)
- def test_efi_capsule_auth2(
self, u_boot_config, u_boot_console, efi_capsule_data):
"""
Test Case 2 - Update U-Boot on SPI Flash, raw image format
0x100000-0x150000: U-Boot binary (but dummy)
If the capsule is signed but with an invalid key,
the authentication should fail and the firmware
not be updated.
"""
disk_img = efi_capsule_data
with u_boot_console.log.section('Test Case 2-a, before reboot'):
output = u_boot_console.run_command_list([
'host bind 0 %s' % disk_img,
'efidebug boot add -b 1 TEST host 0:1 /helloworld.efi',
'efidebug boot order 1',
'env set -e -nv -bs -rt OsIndications =0x0000000000000004',
'env set dfu_alt_info "sf 0:0=u-boot-bin raw 0x100000 0x50000;u-boot-env raw 0x150000 0x200000"',
'env save'])
# initialize content
output = u_boot_console.run_command_list([
'sf probe 0:0',
'fatload host 0:1 4000000 %s/u-boot.bin.old' % CAPSULE_DATA_DIR,
'sf write 4000000 100000 10',
'sf read 5000000 100000 10',
'md.b 5000000 10'])
assert 'Old' in ''.join(output)
# place a capsule file
output = u_boot_console.run_command_list([
'fatload host 0:1 4000000 %s/Test04' % CAPSULE_DATA_DIR,
'fatwrite host 0:1 4000000 %s/Test04 $filesize' % CAPSULE_INSTALL_DIR,
'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
assert 'Test04' in ''.join(output)
# reboot
u_boot_console.restart_uboot()
capsule_early = u_boot_config.buildconfig.get(
'config_efi_capsule_on_disk_early')
with u_boot_console.log.section('Test Case 2-b, after reboot'):
if not capsule_early:
# make sure that dfu_alt_info exists even persistent variables
# are not available.
output = u_boot_console.run_command_list([
'env set dfu_alt_info "sf 0:0=u-boot-bin raw 0x100000 0x50000;u-boot-env raw 0x150000 0x200000"',
'host bind 0 %s' % disk_img,
'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
assert 'Test04' in ''.join(output)
# need to run uefi command to initiate capsule handling
output = u_boot_console.run_command(
'env print -e Capsule0000')
# deleted any way
output = u_boot_console.run_command_list([
'host bind 0 %s' % disk_img,
'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
assert 'Test04' not in ''.join(output)
# TODO: check CapsuleStatus in CapsuleXXXX
output = u_boot_console.run_command_list([
'sf probe 0:0',
'sf read 4000000 100000 10',
'md.b 4000000 10'])
assert 'u-boot:Old' in ''.join(output)
- def test_efi_capsule_auth3(
self, u_boot_config, u_boot_console, efi_capsule_data):
"""
Test Case 3 - Update U-Boot on SPI Flash, raw image format
0x100000-0x150000: U-Boot binary (but dummy)
If the capsule is not signed, the authentication
should fail and the firmware not be updated.
"""
disk_img = efi_capsule_data
with u_boot_console.log.section('Test Case 3-a, before reboot'):
output = u_boot_console.run_command_list([
'host bind 0 %s' % disk_img,
'efidebug boot add -b 1 TEST host 0:1 /helloworld.efi',
'efidebug boot order 1',
'env set -e -nv -bs -rt OsIndications =0x0000000000000004',
'env set dfu_alt_info "sf 0:0=u-boot-bin raw 0x100000 0x50000;u-boot-env raw 0x150000 0x200000"',
'env save'])
# initialize content
output = u_boot_console.run_command_list([
'sf probe 0:0',
'fatload host 0:1 4000000 %s/u-boot.bin.old' % CAPSULE_DATA_DIR,
'sf write 4000000 100000 10',
'sf read 5000000 100000 10',
'md.b 5000000 10'])
assert 'Old' in ''.join(output)
# place a capsule file
output = u_boot_console.run_command_list([
'fatload host 0:1 4000000 %s/Test02' % CAPSULE_DATA_DIR,
'fatwrite host 0:1 4000000 %s/Test02 $filesize' % CAPSULE_INSTALL_DIR,
'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
assert 'Test02' in ''.join(output)
# reboot
u_boot_console.restart_uboot()
capsule_early = u_boot_config.buildconfig.get(
'config_efi_capsule_on_disk_early')
with u_boot_console.log.section('Test Case 3-b, after reboot'):
if not capsule_early:
# make sure that dfu_alt_info exists even persistent variables
# are not available.
output = u_boot_console.run_command_list([
'env set dfu_alt_info "sf 0:0=u-boot-bin raw 0x100000 0x50000;u-boot-env raw 0x150000 0x200000"',
'host bind 0 %s' % disk_img,
'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
assert 'Test02' in ''.join(output)
# need to run uefi command to initiate capsule handling
output = u_boot_console.run_command(
'env print -e Capsule0000')
# deleted any way
output = u_boot_console.run_command_list([
'host bind 0 %s' % disk_img,
'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR])
assert 'Test02' not in ''.join(output)
# TODO: check CapsuleStatus in CapsuleXXXX
output = u_boot_console.run_command_list([
'sf probe 0:0',
'sf read 4000000 100000 10',
'md.b 4000000 10'])
assert 'u-boot:Old' in ''.join(output)

This new configuration, which was derived from sandbox_defconfig, will be used solely to run efi capsule authentication test as the test requires a public key (esl file) to be embedded in U-Boot binary.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org --- configs/sandbox_capsule_auth_defconfig | 307 +++++++++++++++++++++++++ 1 file changed, 307 insertions(+) create mode 100644 configs/sandbox_capsule_auth_defconfig
diff --git a/configs/sandbox_capsule_auth_defconfig b/configs/sandbox_capsule_auth_defconfig new file mode 100644 index 000000000000..8e0ffb1a6995 --- /dev/null +++ b/configs/sandbox_capsule_auth_defconfig @@ -0,0 +1,307 @@ +CONFIG_SYS_TEXT_BASE=0 +CONFIG_NR_DRAM_BANKS=1 +CONFIG_SYS_MEMTEST_START=0x00100000 +CONFIG_SYS_MEMTEST_END=0x00101000 +CONFIG_ENV_SIZE=0x2000 +CONFIG_DEFAULT_DEVICE_TREE="sandbox" +CONFIG_PRE_CON_BUF_ADDR=0xf0000 +CONFIG_BOOTSTAGE_STASH_ADDR=0x0 +CONFIG_DEBUG_UART=y +CONFIG_DISTRO_DEFAULTS=y +CONFIG_FIT=y +CONFIG_FIT_SIGNATURE=y +CONFIG_FIT_RSASSA_PSS=y +CONFIG_FIT_CIPHER=y +CONFIG_FIT_VERBOSE=y +CONFIG_BOOTSTAGE=y +CONFIG_BOOTSTAGE_REPORT=y +CONFIG_BOOTSTAGE_FDT=y +CONFIG_BOOTSTAGE_STASH=y +CONFIG_BOOTSTAGE_STASH_SIZE=0x4096 +CONFIG_CONSOLE_RECORD=y +CONFIG_CONSOLE_RECORD_OUT_SIZE=0x1000 +CONFIG_PRE_CONSOLE_BUFFER=y +CONFIG_LOG=y +CONFIG_DISPLAY_BOARDINFO_LATE=y +CONFIG_MISC_INIT_F=y +CONFIG_STACKPROTECTOR=y +CONFIG_ANDROID_AB=y +CONFIG_CMD_CPU=y +CONFIG_CMD_LICENSE=y +CONFIG_CMD_BOOTZ=y +CONFIG_CMD_BOOTEFI_HELLO=y +CONFIG_CMD_ABOOTIMG=y +# CONFIG_CMD_ELF is not set +CONFIG_CMD_ASKENV=y +CONFIG_CMD_GREPENV=y +CONFIG_CMD_ERASEENV=y +CONFIG_CMD_ENV_CALLBACK=y +CONFIG_CMD_ENV_FLAGS=y +CONFIG_CMD_NVEDIT_EFI=y +CONFIG_CMD_NVEDIT_INFO=y +CONFIG_CMD_NVEDIT_LOAD=y +CONFIG_CMD_NVEDIT_SELECT=y +CONFIG_LOOPW=y +CONFIG_CMD_MD5SUM=y +CONFIG_CMD_MEMINFO=y +CONFIG_CMD_MEM_SEARCH=y +CONFIG_CMD_MX_CYCLIC=y +CONFIG_CMD_MEMTEST=y +CONFIG_CMD_BIND=y +CONFIG_CMD_DEMO=y +CONFIG_CMD_GPIO=y +CONFIG_CMD_PWM=y +CONFIG_CMD_GPT=y +CONFIG_CMD_GPT_RENAME=y +CONFIG_CMD_IDE=y +CONFIG_CMD_I2C=y +CONFIG_CMD_LSBLK=y +CONFIG_CMD_MUX=y +CONFIG_CMD_OSD=y +CONFIG_CMD_PCI=y +CONFIG_CMD_READ=y +CONFIG_CMD_REMOTEPROC=y +CONFIG_CMD_SPI=y +CONFIG_CMD_USB=y +CONFIG_CMD_AXI=y +CONFIG_CMD_AB_SELECT=y +CONFIG_BOOTP_DNS2=y +CONFIG_CMD_PCAP=y +CONFIG_CMD_TFTPPUT=y +CONFIG_CMD_TFTPSRV=y +CONFIG_CMD_RARP=y +CONFIG_CMD_CDP=y +CONFIG_CMD_SNTP=y +CONFIG_CMD_DNS=y +CONFIG_CMD_LINK_LOCAL=y +CONFIG_CMD_ETHSW=y +CONFIG_CMD_BMP=y +CONFIG_CMD_BOOTCOUNT=y +CONFIG_CMD_EFIDEBUG=y +CONFIG_CMD_RTC=y +CONFIG_CMD_TIME=y +CONFIG_CMD_TIMER=y +CONFIG_CMD_SOUND=y +CONFIG_CMD_QFW=y +CONFIG_CMD_PSTORE=y +CONFIG_CMD_PSTORE_MEM_ADDR=0x3000000 +CONFIG_CMD_BOOTSTAGE=y +CONFIG_CMD_PMIC=y +CONFIG_CMD_REGULATOR=y +CONFIG_CMD_AES=y +CONFIG_CMD_TPM=y +CONFIG_CMD_TPM_TEST=y +CONFIG_CMD_BTRFS=y +CONFIG_CMD_CBFS=y +CONFIG_CMD_CRAMFS=y +CONFIG_CMD_EXT4_WRITE=y +CONFIG_CMD_SQUASHFS=y +CONFIG_CMD_MTDPARTS=y +CONFIG_CMD_STACKPROTECTOR_TEST=y +CONFIG_MAC_PARTITION=y +CONFIG_AMIGA_PARTITION=y +CONFIG_OF_CONTROL=y +CONFIG_OF_LIVE=y +CONFIG_OF_HOSTFILE=y +CONFIG_ENV_IS_NOWHERE=y +CONFIG_ENV_IS_IN_EXT4=y +CONFIG_ENV_EXT4_INTERFACE="host" +CONFIG_ENV_EXT4_DEVICE_AND_PART="0:0" +CONFIG_ENV_IMPORT_FDT=y +CONFIG_BOOTP_SEND_HOSTNAME=y +CONFIG_NETCONSOLE=y +CONFIG_IP_DEFRAG=y +CONFIG_DM_DMA=y +CONFIG_REGMAP=y +CONFIG_SYSCON=y +CONFIG_DEVRES=y +CONFIG_DEBUG_DEVRES=y +CONFIG_SIMPLE_PM_BUS=y +CONFIG_ADC=y +CONFIG_ADC_SANDBOX=y +CONFIG_AXI=y +CONFIG_AXI_SANDBOX=y +CONFIG_BOOTCOUNT_LIMIT=y +CONFIG_DM_BOOTCOUNT=y +CONFIG_DM_BOOTCOUNT_RTC=y +CONFIG_DM_BOOTCOUNT_I2C_EEPROM=y +CONFIG_BUTTON=y +CONFIG_BUTTON_ADC=y +CONFIG_BUTTON_GPIO=y +CONFIG_CLK=y +CONFIG_CLK_COMPOSITE_CCF=y +CONFIG_CLK_SCMI=y +CONFIG_CLK_K210=y +CONFIG_CLK_K210_SET_RATE=y +CONFIG_SANDBOX_CLK_CCF=y +CONFIG_CPU=y +CONFIG_DM_DEMO=y +CONFIG_DM_DEMO_SIMPLE=y +CONFIG_DM_DEMO_SHAPE=y +CONFIG_DFU_SF=y +CONFIG_DMA=y +CONFIG_DMA_CHANNELS=y +CONFIG_SANDBOX_DMA=y +CONFIG_FASTBOOT_FLASH=y +CONFIG_FASTBOOT_FLASH_MMC_DEV=0 +CONFIG_GPIO_HOG=y +CONFIG_DM_GPIO_LOOKUP_LABEL=y +CONFIG_PM8916_GPIO=y +CONFIG_SANDBOX_GPIO=y +CONFIG_DM_HWSPINLOCK=y +CONFIG_HWSPINLOCK_SANDBOX=y +CONFIG_I2C_CROS_EC_TUNNEL=y +CONFIG_I2C_CROS_EC_LDO=y +CONFIG_DM_I2C_GPIO=y +CONFIG_SYS_I2C_SANDBOX=y +CONFIG_I2C_MUX=y +CONFIG_SPL_I2C_MUX=y +CONFIG_I2C_ARB_GPIO_CHALLENGE=y +CONFIG_CROS_EC_KEYB=y +CONFIG_I8042_KEYB=y +CONFIG_LED=y +CONFIG_LED_BLINK=y +CONFIG_LED_GPIO=y +CONFIG_DM_MAILBOX=y +CONFIG_SANDBOX_MBOX=y +CONFIG_MISC=y +CONFIG_CROS_EC=y +CONFIG_CROS_EC_I2C=y +CONFIG_CROS_EC_LPC=y +CONFIG_CROS_EC_SANDBOX=y +CONFIG_CROS_EC_SPI=y +CONFIG_P2SB=y +CONFIG_PWRSEQ=y +CONFIG_SPL_PWRSEQ=y +CONFIG_I2C_EEPROM=y +CONFIG_MMC_PCI=y +CONFIG_MMC_SANDBOX=y +CONFIG_MMC_SDHCI=y +CONFIG_MTD=y +CONFIG_SPI_FLASH_SANDBOX=y +CONFIG_SPI_FLASH_ATMEL=y +CONFIG_SPI_FLASH_EON=y +CONFIG_SPI_FLASH_GIGADEVICE=y +CONFIG_SPI_FLASH_MACRONIX=y +CONFIG_SPI_FLASH_SPANSION=y +CONFIG_SPI_FLASH_STMICRO=y +CONFIG_SPI_FLASH_SST=y +CONFIG_SPI_FLASH_WINBOND=y +CONFIG_MULTIPLEXER=y +CONFIG_MUX_MMIO=y +CONFIG_DM_ETH=y +CONFIG_NVME=y +CONFIG_PCI=y +CONFIG_DM_PCI=y +CONFIG_PCI_REGION_MULTI_ENTRY=y +CONFIG_PCI_SANDBOX=y +CONFIG_PHY=y +CONFIG_PHY_SANDBOX=y +CONFIG_PINCTRL=y +CONFIG_PINCONF=y +CONFIG_PINCTRL_SANDBOX=y +CONFIG_PINCTRL_SINGLE=y +CONFIG_POWER_DOMAIN=y +CONFIG_SANDBOX_POWER_DOMAIN=y +CONFIG_DM_PMIC=y +CONFIG_PMIC_ACT8846=y +CONFIG_DM_PMIC_PFUZE100=y +CONFIG_DM_PMIC_MAX77686=y +CONFIG_DM_PMIC_MC34708=y +CONFIG_PMIC_PM8916=y +CONFIG_PMIC_RK8XX=y +CONFIG_PMIC_S2MPS11=y +CONFIG_DM_PMIC_SANDBOX=y +CONFIG_PMIC_S5M8767=y +CONFIG_PMIC_TPS65090=y +CONFIG_DM_REGULATOR=y +CONFIG_REGULATOR_ACT8846=y +CONFIG_DM_REGULATOR_PFUZE100=y +CONFIG_DM_REGULATOR_MAX77686=y +CONFIG_DM_REGULATOR_FIXED=y +CONFIG_REGULATOR_RK8XX=y +CONFIG_REGULATOR_S5M8767=y +CONFIG_DM_REGULATOR_SANDBOX=y +CONFIG_REGULATOR_TPS65090=y +CONFIG_DM_REGULATOR_SCMI=y +CONFIG_DM_PWM=y +CONFIG_PWM_CROS_EC=y +CONFIG_PWM_SANDBOX=y +CONFIG_RAM=y +CONFIG_REMOTEPROC_SANDBOX=y +CONFIG_DM_RESET=y +CONFIG_SANDBOX_RESET=y +CONFIG_RESET_SYSCON=y +CONFIG_RESET_SCMI=y +CONFIG_DM_RNG=y +CONFIG_DM_RTC=y +CONFIG_RTC_RV8803=y +CONFIG_SANDBOX_SERIAL=y +CONFIG_SMEM=y +CONFIG_SANDBOX_SMEM=y +CONFIG_SOUND=y +CONFIG_SOUND_DA7219=y +CONFIG_SOUND_MAX98357A=y +CONFIG_SOUND_SANDBOX=y +CONFIG_SOC_DEVICE=y +CONFIG_SANDBOX_SPI=y +CONFIG_SPMI=y +CONFIG_SPMI_SANDBOX=y +CONFIG_SYSINFO=y +CONFIG_SYSINFO_SANDBOX=y +CONFIG_SYSINFO_GPIO=y +CONFIG_SYSRESET=y +CONFIG_TIMER=y +CONFIG_TIMER_EARLY=y +CONFIG_SANDBOX_TIMER=y +CONFIG_USB=y +CONFIG_DM_USB=y +CONFIG_USB_EMUL=y +CONFIG_USB_KEYBOARD=y +CONFIG_DM_VIDEO=y +CONFIG_VIDEO_COPY=y +CONFIG_CONSOLE_ROTATION=y +CONFIG_CONSOLE_TRUETYPE=y +CONFIG_CONSOLE_TRUETYPE_CANTORAONE=y +CONFIG_VIDEO_SANDBOX_SDL=y +CONFIG_VIDEO_DSI_HOST_SANDBOX=y +CONFIG_OSD=y +CONFIG_SANDBOX_OSD=y +CONFIG_SPLASH_SCREEN_ALIGN=y +CONFIG_VIDEO_BMP_RLE8=y +CONFIG_W1=y +CONFIG_W1_GPIO=y +CONFIG_W1_EEPROM=y +CONFIG_W1_EEPROM_SANDBOX=y +CONFIG_WDT=y +CONFIG_WDT_SANDBOX=y +CONFIG_FS_CBFS=y +CONFIG_FS_CRAMFS=y +CONFIG_CMD_DHRYSTONE=y +CONFIG_TPM=y +CONFIG_LZ4=y +CONFIG_ERRNO_STR=y +CONFIG_EFI_RUNTIME_UPDATE_CAPSULE=y +CONFIG_EFI_CAPSULE_ON_DISK=y +CONFIG_EFI_CAPSULE_FIRMWARE_FIT=y +CONFIG_EFI_CAPSULE_FIRMWARE_RAW=y +CONFIG_EFI_CAPSULE_AUTHENTICATE=y +CONFIG_EFI_CAPSULE_KEY_PATH="../test/py/tests/test_efi_capsule/SIGNER.esl" +CONFIG_EFI_SECURE_BOOT=y +CONFIG_TEST_FDTDEC=y +CONFIG_CRYPT_PW=y +CONFIG_CRYPT_PW_SHA256=y +CONFIG_CRYPT_PW_SHA512=y +CONFIG_AUTOBOOT_KEYED=y +CONFIG_AUTOBOOT_PROMPT="Enter password "a" in %d seconds to stop autoboot\n" +CONFIG_AUTOBOOT_ENCRYPTION=y +CONFIG_AUTOBOOT_STOP_STR_ENABLE=y +CONFIG_AUTOBOOT_STOP_STR_CRYPT="$5$rounds=640000$HrpE65IkB8CM5nCL$BKT3QdF98Bo8fJpTr9tjZLZQyzqPASBY20xuK5Rent9" +CONFIG_AUTOBOOT_NEVER_TIMEOUT=y +CONFIG_AUTOBOOT_SHA256_FALLBACK=y +CONFIG_UNIT_TEST=y +CONFIG_UT_TIME=y +CONFIG_UT_DM=y +CONFIG_DM_REBOOT_MODE=y +CONFIG_DM_REBOOT_MODE_GPIO=y +CONFIG_DM_REBOOT_MODE_RTC=y

On 7/27/21 11:10 AM, AKASHI Takahiro wrote:
This new configuration, which was derived from sandbox_defconfig, will be used solely to run efi capsule authentication test as the test requires a public key (esl file) to be embedded in U-Boot binary.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org
configs/sandbox_capsule_auth_defconfig | 307 +++++++++++++++++++++++++ 1 file changed, 307 insertions(+) create mode 100644 configs/sandbox_capsule_auth_defconfig
diff --git a/configs/sandbox_capsule_auth_defconfig b/configs/sandbox_capsule_auth_defconfig new file mode 100644 index 000000000000..8e0ffb1a6995 --- /dev/null +++ b/configs/sandbox_capsule_auth_defconfig @@ -0,0 +1,307 @@ +CONFIG_SYS_TEXT_BASE=0 +CONFIG_NR_DRAM_BANKS=1 +CONFIG_SYS_MEMTEST_START=0x00100000 +CONFIG_SYS_MEMTEST_END=0x00101000 +CONFIG_ENV_SIZE=0x2000 +CONFIG_DEFAULT_DEVICE_TREE="sandbox" +CONFIG_PRE_CON_BUF_ADDR=0xf0000 +CONFIG_BOOTSTAGE_STASH_ADDR=0x0 +CONFIG_DEBUG_UART=y +CONFIG_DISTRO_DEFAULTS=y +CONFIG_FIT=y +CONFIG_FIT_SIGNATURE=y +CONFIG_FIT_RSASSA_PSS=y +CONFIG_FIT_CIPHER=y +CONFIG_FIT_VERBOSE=y +CONFIG_BOOTSTAGE=y +CONFIG_BOOTSTAGE_REPORT=y +CONFIG_BOOTSTAGE_FDT=y +CONFIG_BOOTSTAGE_STASH=y +CONFIG_BOOTSTAGE_STASH_SIZE=0x4096 +CONFIG_CONSOLE_RECORD=y +CONFIG_CONSOLE_RECORD_OUT_SIZE=0x1000 +CONFIG_PRE_CONSOLE_BUFFER=y +CONFIG_LOG=y +CONFIG_DISPLAY_BOARDINFO_LATE=y +CONFIG_MISC_INIT_F=y +CONFIG_STACKPROTECTOR=y +CONFIG_ANDROID_AB=y +CONFIG_CMD_CPU=y +CONFIG_CMD_LICENSE=y +CONFIG_CMD_BOOTZ=y +CONFIG_CMD_BOOTEFI_HELLO=y +CONFIG_CMD_ABOOTIMG=y +# CONFIG_CMD_ELF is not set +CONFIG_CMD_ASKENV=y +CONFIG_CMD_GREPENV=y +CONFIG_CMD_ERASEENV=y +CONFIG_CMD_ENV_CALLBACK=y +CONFIG_CMD_ENV_FLAGS=y +CONFIG_CMD_NVEDIT_EFI=y +CONFIG_CMD_NVEDIT_INFO=y +CONFIG_CMD_NVEDIT_LOAD=y +CONFIG_CMD_NVEDIT_SELECT=y +CONFIG_LOOPW=y +CONFIG_CMD_MD5SUM=y +CONFIG_CMD_MEMINFO=y +CONFIG_CMD_MEM_SEARCH=y +CONFIG_CMD_MX_CYCLIC=y +CONFIG_CMD_MEMTEST=y +CONFIG_CMD_BIND=y +CONFIG_CMD_DEMO=y +CONFIG_CMD_GPIO=y +CONFIG_CMD_PWM=y +CONFIG_CMD_GPT=y +CONFIG_CMD_GPT_RENAME=y +CONFIG_CMD_IDE=y +CONFIG_CMD_I2C=y +CONFIG_CMD_LSBLK=y +CONFIG_CMD_MUX=y +CONFIG_CMD_OSD=y +CONFIG_CMD_PCI=y +CONFIG_CMD_READ=y +CONFIG_CMD_REMOTEPROC=y +CONFIG_CMD_SPI=y +CONFIG_CMD_USB=y +CONFIG_CMD_AXI=y +CONFIG_CMD_AB_SELECT=y +CONFIG_BOOTP_DNS2=y +CONFIG_CMD_PCAP=y +CONFIG_CMD_TFTPPUT=y +CONFIG_CMD_TFTPSRV=y +CONFIG_CMD_RARP=y +CONFIG_CMD_CDP=y +CONFIG_CMD_SNTP=y +CONFIG_CMD_DNS=y +CONFIG_CMD_LINK_LOCAL=y +CONFIG_CMD_ETHSW=y +CONFIG_CMD_BMP=y +CONFIG_CMD_BOOTCOUNT=y +CONFIG_CMD_EFIDEBUG=y +CONFIG_CMD_RTC=y +CONFIG_CMD_TIME=y +CONFIG_CMD_TIMER=y +CONFIG_CMD_SOUND=y +CONFIG_CMD_QFW=y +CONFIG_CMD_PSTORE=y +CONFIG_CMD_PSTORE_MEM_ADDR=0x3000000 +CONFIG_CMD_BOOTSTAGE=y +CONFIG_CMD_PMIC=y +CONFIG_CMD_REGULATOR=y +CONFIG_CMD_AES=y +CONFIG_CMD_TPM=y +CONFIG_CMD_TPM_TEST=y +CONFIG_CMD_BTRFS=y +CONFIG_CMD_CBFS=y +CONFIG_CMD_CRAMFS=y +CONFIG_CMD_EXT4_WRITE=y +CONFIG_CMD_SQUASHFS=y +CONFIG_CMD_MTDPARTS=y +CONFIG_CMD_STACKPROTECTOR_TEST=y +CONFIG_MAC_PARTITION=y +CONFIG_AMIGA_PARTITION=y +CONFIG_OF_CONTROL=y +CONFIG_OF_LIVE=y +CONFIG_OF_HOSTFILE=y +CONFIG_ENV_IS_NOWHERE=y +CONFIG_ENV_IS_IN_EXT4=y +CONFIG_ENV_EXT4_INTERFACE="host" +CONFIG_ENV_EXT4_DEVICE_AND_PART="0:0" +CONFIG_ENV_IMPORT_FDT=y +CONFIG_BOOTP_SEND_HOSTNAME=y +CONFIG_NETCONSOLE=y +CONFIG_IP_DEFRAG=y +CONFIG_DM_DMA=y +CONFIG_REGMAP=y +CONFIG_SYSCON=y +CONFIG_DEVRES=y +CONFIG_DEBUG_DEVRES=y +CONFIG_SIMPLE_PM_BUS=y +CONFIG_ADC=y +CONFIG_ADC_SANDBOX=y +CONFIG_AXI=y +CONFIG_AXI_SANDBOX=y +CONFIG_BOOTCOUNT_LIMIT=y +CONFIG_DM_BOOTCOUNT=y +CONFIG_DM_BOOTCOUNT_RTC=y +CONFIG_DM_BOOTCOUNT_I2C_EEPROM=y +CONFIG_BUTTON=y +CONFIG_BUTTON_ADC=y +CONFIG_BUTTON_GPIO=y +CONFIG_CLK=y +CONFIG_CLK_COMPOSITE_CCF=y +CONFIG_CLK_SCMI=y +CONFIG_CLK_K210=y +CONFIG_CLK_K210_SET_RATE=y +CONFIG_SANDBOX_CLK_CCF=y +CONFIG_CPU=y +CONFIG_DM_DEMO=y +CONFIG_DM_DEMO_SIMPLE=y +CONFIG_DM_DEMO_SHAPE=y +CONFIG_DFU_SF=y +CONFIG_DMA=y +CONFIG_DMA_CHANNELS=y +CONFIG_SANDBOX_DMA=y +CONFIG_FASTBOOT_FLASH=y +CONFIG_FASTBOOT_FLASH_MMC_DEV=0 +CONFIG_GPIO_HOG=y +CONFIG_DM_GPIO_LOOKUP_LABEL=y +CONFIG_PM8916_GPIO=y +CONFIG_SANDBOX_GPIO=y +CONFIG_DM_HWSPINLOCK=y +CONFIG_HWSPINLOCK_SANDBOX=y +CONFIG_I2C_CROS_EC_TUNNEL=y +CONFIG_I2C_CROS_EC_LDO=y +CONFIG_DM_I2C_GPIO=y +CONFIG_SYS_I2C_SANDBOX=y +CONFIG_I2C_MUX=y +CONFIG_SPL_I2C_MUX=y +CONFIG_I2C_ARB_GPIO_CHALLENGE=y +CONFIG_CROS_EC_KEYB=y +CONFIG_I8042_KEYB=y +CONFIG_LED=y +CONFIG_LED_BLINK=y +CONFIG_LED_GPIO=y +CONFIG_DM_MAILBOX=y +CONFIG_SANDBOX_MBOX=y +CONFIG_MISC=y +CONFIG_CROS_EC=y +CONFIG_CROS_EC_I2C=y +CONFIG_CROS_EC_LPC=y +CONFIG_CROS_EC_SANDBOX=y +CONFIG_CROS_EC_SPI=y +CONFIG_P2SB=y +CONFIG_PWRSEQ=y +CONFIG_SPL_PWRSEQ=y +CONFIG_I2C_EEPROM=y +CONFIG_MMC_PCI=y +CONFIG_MMC_SANDBOX=y +CONFIG_MMC_SDHCI=y +CONFIG_MTD=y +CONFIG_SPI_FLASH_SANDBOX=y +CONFIG_SPI_FLASH_ATMEL=y +CONFIG_SPI_FLASH_EON=y +CONFIG_SPI_FLASH_GIGADEVICE=y +CONFIG_SPI_FLASH_MACRONIX=y +CONFIG_SPI_FLASH_SPANSION=y +CONFIG_SPI_FLASH_STMICRO=y +CONFIG_SPI_FLASH_SST=y +CONFIG_SPI_FLASH_WINBOND=y +CONFIG_MULTIPLEXER=y +CONFIG_MUX_MMIO=y +CONFIG_DM_ETH=y +CONFIG_NVME=y +CONFIG_PCI=y +CONFIG_DM_PCI=y +CONFIG_PCI_REGION_MULTI_ENTRY=y +CONFIG_PCI_SANDBOX=y +CONFIG_PHY=y +CONFIG_PHY_SANDBOX=y +CONFIG_PINCTRL=y +CONFIG_PINCONF=y +CONFIG_PINCTRL_SANDBOX=y +CONFIG_PINCTRL_SINGLE=y +CONFIG_POWER_DOMAIN=y +CONFIG_SANDBOX_POWER_DOMAIN=y +CONFIG_DM_PMIC=y +CONFIG_PMIC_ACT8846=y +CONFIG_DM_PMIC_PFUZE100=y +CONFIG_DM_PMIC_MAX77686=y +CONFIG_DM_PMIC_MC34708=y +CONFIG_PMIC_PM8916=y +CONFIG_PMIC_RK8XX=y +CONFIG_PMIC_S2MPS11=y +CONFIG_DM_PMIC_SANDBOX=y +CONFIG_PMIC_S5M8767=y +CONFIG_PMIC_TPS65090=y +CONFIG_DM_REGULATOR=y +CONFIG_REGULATOR_ACT8846=y +CONFIG_DM_REGULATOR_PFUZE100=y +CONFIG_DM_REGULATOR_MAX77686=y +CONFIG_DM_REGULATOR_FIXED=y +CONFIG_REGULATOR_RK8XX=y +CONFIG_REGULATOR_S5M8767=y +CONFIG_DM_REGULATOR_SANDBOX=y +CONFIG_REGULATOR_TPS65090=y +CONFIG_DM_REGULATOR_SCMI=y +CONFIG_DM_PWM=y +CONFIG_PWM_CROS_EC=y +CONFIG_PWM_SANDBOX=y +CONFIG_RAM=y +CONFIG_REMOTEPROC_SANDBOX=y +CONFIG_DM_RESET=y +CONFIG_SANDBOX_RESET=y +CONFIG_RESET_SYSCON=y +CONFIG_RESET_SCMI=y +CONFIG_DM_RNG=y +CONFIG_DM_RTC=y +CONFIG_RTC_RV8803=y +CONFIG_SANDBOX_SERIAL=y +CONFIG_SMEM=y +CONFIG_SANDBOX_SMEM=y +CONFIG_SOUND=y +CONFIG_SOUND_DA7219=y +CONFIG_SOUND_MAX98357A=y +CONFIG_SOUND_SANDBOX=y +CONFIG_SOC_DEVICE=y +CONFIG_SANDBOX_SPI=y +CONFIG_SPMI=y +CONFIG_SPMI_SANDBOX=y +CONFIG_SYSINFO=y +CONFIG_SYSINFO_SANDBOX=y +CONFIG_SYSINFO_GPIO=y +CONFIG_SYSRESET=y +CONFIG_TIMER=y +CONFIG_TIMER_EARLY=y +CONFIG_SANDBOX_TIMER=y +CONFIG_USB=y +CONFIG_DM_USB=y +CONFIG_USB_EMUL=y +CONFIG_USB_KEYBOARD=y +CONFIG_DM_VIDEO=y +CONFIG_VIDEO_COPY=y +CONFIG_CONSOLE_ROTATION=y +CONFIG_CONSOLE_TRUETYPE=y +CONFIG_CONSOLE_TRUETYPE_CANTORAONE=y +CONFIG_VIDEO_SANDBOX_SDL=y +CONFIG_VIDEO_DSI_HOST_SANDBOX=y +CONFIG_OSD=y +CONFIG_SANDBOX_OSD=y +CONFIG_SPLASH_SCREEN_ALIGN=y +CONFIG_VIDEO_BMP_RLE8=y +CONFIG_W1=y +CONFIG_W1_GPIO=y +CONFIG_W1_EEPROM=y +CONFIG_W1_EEPROM_SANDBOX=y +CONFIG_WDT=y +CONFIG_WDT_SANDBOX=y +CONFIG_FS_CBFS=y +CONFIG_FS_CRAMFS=y +CONFIG_CMD_DHRYSTONE=y +CONFIG_TPM=y +CONFIG_LZ4=y +CONFIG_ERRNO_STR=y +CONFIG_EFI_RUNTIME_UPDATE_CAPSULE=y +CONFIG_EFI_CAPSULE_ON_DISK=y +CONFIG_EFI_CAPSULE_FIRMWARE_FIT=y +CONFIG_EFI_CAPSULE_FIRMWARE_RAW=y +CONFIG_EFI_CAPSULE_AUTHENTICATE=y +CONFIG_EFI_CAPSULE_KEY_PATH="../test/py/tests/test_efi_capsule/SIGNER.esl"
Is this path relative to the build directory?
Will building fail if the build directory is not a direct subdirectory of the source directory?
Best regards
Heinrich
+CONFIG_EFI_SECURE_BOOT=y +CONFIG_TEST_FDTDEC=y +CONFIG_CRYPT_PW=y +CONFIG_CRYPT_PW_SHA256=y +CONFIG_CRYPT_PW_SHA512=y +CONFIG_AUTOBOOT_KEYED=y +CONFIG_AUTOBOOT_PROMPT="Enter password "a" in %d seconds to stop autoboot\n" +CONFIG_AUTOBOOT_ENCRYPTION=y +CONFIG_AUTOBOOT_STOP_STR_ENABLE=y +CONFIG_AUTOBOOT_STOP_STR_CRYPT="$5$rounds=640000$HrpE65IkB8CM5nCL$BKT3QdF98Bo8fJpTr9tjZLZQyzqPASBY20xuK5Rent9" +CONFIG_AUTOBOOT_NEVER_TIMEOUT=y +CONFIG_AUTOBOOT_SHA256_FALLBACK=y +CONFIG_UNIT_TEST=y +CONFIG_UT_TIME=y +CONFIG_UT_DM=y +CONFIG_DM_REBOOT_MODE=y +CONFIG_DM_REBOOT_MODE_GPIO=y +CONFIG_DM_REBOOT_MODE_RTC=y

On Wed, Jul 28, 2021 at 10:21:56PM +0200, Heinrich Schuchardt wrote:
On 7/27/21 11:10 AM, AKASHI Takahiro wrote:
This new configuration, which was derived from sandbox_defconfig, will be used solely to run efi capsule authentication test as the test requires a public key (esl file) to be embedded in U-Boot binary.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org
configs/sandbox_capsule_auth_defconfig | 307 +++++++++++++++++++++++++ 1 file changed, 307 insertions(+) create mode 100644 configs/sandbox_capsule_auth_defconfig
diff --git a/configs/sandbox_capsule_auth_defconfig b/configs/sandbox_capsule_auth_defconfig new file mode 100644 index 000000000000..8e0ffb1a6995 --- /dev/null +++ b/configs/sandbox_capsule_auth_defconfig @@ -0,0 +1,307 @@ +CONFIG_SYS_TEXT_BASE=0 +CONFIG_NR_DRAM_BANKS=1 +CONFIG_SYS_MEMTEST_START=0x00100000 +CONFIG_SYS_MEMTEST_END=0x00101000 +CONFIG_ENV_SIZE=0x2000 +CONFIG_DEFAULT_DEVICE_TREE="sandbox" +CONFIG_PRE_CON_BUF_ADDR=0xf0000 +CONFIG_BOOTSTAGE_STASH_ADDR=0x0 +CONFIG_DEBUG_UART=y +CONFIG_DISTRO_DEFAULTS=y +CONFIG_FIT=y +CONFIG_FIT_SIGNATURE=y +CONFIG_FIT_RSASSA_PSS=y +CONFIG_FIT_CIPHER=y +CONFIG_FIT_VERBOSE=y +CONFIG_BOOTSTAGE=y +CONFIG_BOOTSTAGE_REPORT=y +CONFIG_BOOTSTAGE_FDT=y +CONFIG_BOOTSTAGE_STASH=y +CONFIG_BOOTSTAGE_STASH_SIZE=0x4096 +CONFIG_CONSOLE_RECORD=y +CONFIG_CONSOLE_RECORD_OUT_SIZE=0x1000 +CONFIG_PRE_CONSOLE_BUFFER=y +CONFIG_LOG=y +CONFIG_DISPLAY_BOARDINFO_LATE=y +CONFIG_MISC_INIT_F=y +CONFIG_STACKPROTECTOR=y +CONFIG_ANDROID_AB=y +CONFIG_CMD_CPU=y +CONFIG_CMD_LICENSE=y +CONFIG_CMD_BOOTZ=y +CONFIG_CMD_BOOTEFI_HELLO=y +CONFIG_CMD_ABOOTIMG=y +# CONFIG_CMD_ELF is not set +CONFIG_CMD_ASKENV=y +CONFIG_CMD_GREPENV=y +CONFIG_CMD_ERASEENV=y +CONFIG_CMD_ENV_CALLBACK=y +CONFIG_CMD_ENV_FLAGS=y +CONFIG_CMD_NVEDIT_EFI=y +CONFIG_CMD_NVEDIT_INFO=y +CONFIG_CMD_NVEDIT_LOAD=y +CONFIG_CMD_NVEDIT_SELECT=y +CONFIG_LOOPW=y +CONFIG_CMD_MD5SUM=y +CONFIG_CMD_MEMINFO=y +CONFIG_CMD_MEM_SEARCH=y +CONFIG_CMD_MX_CYCLIC=y +CONFIG_CMD_MEMTEST=y +CONFIG_CMD_BIND=y +CONFIG_CMD_DEMO=y +CONFIG_CMD_GPIO=y +CONFIG_CMD_PWM=y +CONFIG_CMD_GPT=y +CONFIG_CMD_GPT_RENAME=y +CONFIG_CMD_IDE=y +CONFIG_CMD_I2C=y +CONFIG_CMD_LSBLK=y +CONFIG_CMD_MUX=y +CONFIG_CMD_OSD=y +CONFIG_CMD_PCI=y +CONFIG_CMD_READ=y +CONFIG_CMD_REMOTEPROC=y +CONFIG_CMD_SPI=y +CONFIG_CMD_USB=y +CONFIG_CMD_AXI=y +CONFIG_CMD_AB_SELECT=y +CONFIG_BOOTP_DNS2=y +CONFIG_CMD_PCAP=y +CONFIG_CMD_TFTPPUT=y +CONFIG_CMD_TFTPSRV=y +CONFIG_CMD_RARP=y +CONFIG_CMD_CDP=y +CONFIG_CMD_SNTP=y +CONFIG_CMD_DNS=y +CONFIG_CMD_LINK_LOCAL=y +CONFIG_CMD_ETHSW=y +CONFIG_CMD_BMP=y +CONFIG_CMD_BOOTCOUNT=y +CONFIG_CMD_EFIDEBUG=y +CONFIG_CMD_RTC=y +CONFIG_CMD_TIME=y +CONFIG_CMD_TIMER=y +CONFIG_CMD_SOUND=y +CONFIG_CMD_QFW=y +CONFIG_CMD_PSTORE=y +CONFIG_CMD_PSTORE_MEM_ADDR=0x3000000 +CONFIG_CMD_BOOTSTAGE=y +CONFIG_CMD_PMIC=y +CONFIG_CMD_REGULATOR=y +CONFIG_CMD_AES=y +CONFIG_CMD_TPM=y +CONFIG_CMD_TPM_TEST=y +CONFIG_CMD_BTRFS=y +CONFIG_CMD_CBFS=y +CONFIG_CMD_CRAMFS=y +CONFIG_CMD_EXT4_WRITE=y +CONFIG_CMD_SQUASHFS=y +CONFIG_CMD_MTDPARTS=y +CONFIG_CMD_STACKPROTECTOR_TEST=y +CONFIG_MAC_PARTITION=y +CONFIG_AMIGA_PARTITION=y +CONFIG_OF_CONTROL=y +CONFIG_OF_LIVE=y +CONFIG_OF_HOSTFILE=y +CONFIG_ENV_IS_NOWHERE=y +CONFIG_ENV_IS_IN_EXT4=y +CONFIG_ENV_EXT4_INTERFACE="host" +CONFIG_ENV_EXT4_DEVICE_AND_PART="0:0" +CONFIG_ENV_IMPORT_FDT=y +CONFIG_BOOTP_SEND_HOSTNAME=y +CONFIG_NETCONSOLE=y +CONFIG_IP_DEFRAG=y +CONFIG_DM_DMA=y +CONFIG_REGMAP=y +CONFIG_SYSCON=y +CONFIG_DEVRES=y +CONFIG_DEBUG_DEVRES=y +CONFIG_SIMPLE_PM_BUS=y +CONFIG_ADC=y +CONFIG_ADC_SANDBOX=y +CONFIG_AXI=y +CONFIG_AXI_SANDBOX=y +CONFIG_BOOTCOUNT_LIMIT=y +CONFIG_DM_BOOTCOUNT=y +CONFIG_DM_BOOTCOUNT_RTC=y +CONFIG_DM_BOOTCOUNT_I2C_EEPROM=y +CONFIG_BUTTON=y +CONFIG_BUTTON_ADC=y +CONFIG_BUTTON_GPIO=y +CONFIG_CLK=y +CONFIG_CLK_COMPOSITE_CCF=y +CONFIG_CLK_SCMI=y +CONFIG_CLK_K210=y +CONFIG_CLK_K210_SET_RATE=y +CONFIG_SANDBOX_CLK_CCF=y +CONFIG_CPU=y +CONFIG_DM_DEMO=y +CONFIG_DM_DEMO_SIMPLE=y +CONFIG_DM_DEMO_SHAPE=y +CONFIG_DFU_SF=y +CONFIG_DMA=y +CONFIG_DMA_CHANNELS=y +CONFIG_SANDBOX_DMA=y +CONFIG_FASTBOOT_FLASH=y +CONFIG_FASTBOOT_FLASH_MMC_DEV=0 +CONFIG_GPIO_HOG=y +CONFIG_DM_GPIO_LOOKUP_LABEL=y +CONFIG_PM8916_GPIO=y +CONFIG_SANDBOX_GPIO=y +CONFIG_DM_HWSPINLOCK=y +CONFIG_HWSPINLOCK_SANDBOX=y +CONFIG_I2C_CROS_EC_TUNNEL=y +CONFIG_I2C_CROS_EC_LDO=y +CONFIG_DM_I2C_GPIO=y +CONFIG_SYS_I2C_SANDBOX=y +CONFIG_I2C_MUX=y +CONFIG_SPL_I2C_MUX=y +CONFIG_I2C_ARB_GPIO_CHALLENGE=y +CONFIG_CROS_EC_KEYB=y +CONFIG_I8042_KEYB=y +CONFIG_LED=y +CONFIG_LED_BLINK=y +CONFIG_LED_GPIO=y +CONFIG_DM_MAILBOX=y +CONFIG_SANDBOX_MBOX=y +CONFIG_MISC=y +CONFIG_CROS_EC=y +CONFIG_CROS_EC_I2C=y +CONFIG_CROS_EC_LPC=y +CONFIG_CROS_EC_SANDBOX=y +CONFIG_CROS_EC_SPI=y +CONFIG_P2SB=y +CONFIG_PWRSEQ=y +CONFIG_SPL_PWRSEQ=y +CONFIG_I2C_EEPROM=y +CONFIG_MMC_PCI=y +CONFIG_MMC_SANDBOX=y +CONFIG_MMC_SDHCI=y +CONFIG_MTD=y +CONFIG_SPI_FLASH_SANDBOX=y +CONFIG_SPI_FLASH_ATMEL=y +CONFIG_SPI_FLASH_EON=y +CONFIG_SPI_FLASH_GIGADEVICE=y +CONFIG_SPI_FLASH_MACRONIX=y +CONFIG_SPI_FLASH_SPANSION=y +CONFIG_SPI_FLASH_STMICRO=y +CONFIG_SPI_FLASH_SST=y +CONFIG_SPI_FLASH_WINBOND=y +CONFIG_MULTIPLEXER=y +CONFIG_MUX_MMIO=y +CONFIG_DM_ETH=y +CONFIG_NVME=y +CONFIG_PCI=y +CONFIG_DM_PCI=y +CONFIG_PCI_REGION_MULTI_ENTRY=y +CONFIG_PCI_SANDBOX=y +CONFIG_PHY=y +CONFIG_PHY_SANDBOX=y +CONFIG_PINCTRL=y +CONFIG_PINCONF=y +CONFIG_PINCTRL_SANDBOX=y +CONFIG_PINCTRL_SINGLE=y +CONFIG_POWER_DOMAIN=y +CONFIG_SANDBOX_POWER_DOMAIN=y +CONFIG_DM_PMIC=y +CONFIG_PMIC_ACT8846=y +CONFIG_DM_PMIC_PFUZE100=y +CONFIG_DM_PMIC_MAX77686=y +CONFIG_DM_PMIC_MC34708=y +CONFIG_PMIC_PM8916=y +CONFIG_PMIC_RK8XX=y +CONFIG_PMIC_S2MPS11=y +CONFIG_DM_PMIC_SANDBOX=y +CONFIG_PMIC_S5M8767=y +CONFIG_PMIC_TPS65090=y +CONFIG_DM_REGULATOR=y +CONFIG_REGULATOR_ACT8846=y +CONFIG_DM_REGULATOR_PFUZE100=y +CONFIG_DM_REGULATOR_MAX77686=y +CONFIG_DM_REGULATOR_FIXED=y +CONFIG_REGULATOR_RK8XX=y +CONFIG_REGULATOR_S5M8767=y +CONFIG_DM_REGULATOR_SANDBOX=y +CONFIG_REGULATOR_TPS65090=y +CONFIG_DM_REGULATOR_SCMI=y +CONFIG_DM_PWM=y +CONFIG_PWM_CROS_EC=y +CONFIG_PWM_SANDBOX=y +CONFIG_RAM=y +CONFIG_REMOTEPROC_SANDBOX=y +CONFIG_DM_RESET=y +CONFIG_SANDBOX_RESET=y +CONFIG_RESET_SYSCON=y +CONFIG_RESET_SCMI=y +CONFIG_DM_RNG=y +CONFIG_DM_RTC=y +CONFIG_RTC_RV8803=y +CONFIG_SANDBOX_SERIAL=y +CONFIG_SMEM=y +CONFIG_SANDBOX_SMEM=y +CONFIG_SOUND=y +CONFIG_SOUND_DA7219=y +CONFIG_SOUND_MAX98357A=y +CONFIG_SOUND_SANDBOX=y +CONFIG_SOC_DEVICE=y +CONFIG_SANDBOX_SPI=y +CONFIG_SPMI=y +CONFIG_SPMI_SANDBOX=y +CONFIG_SYSINFO=y +CONFIG_SYSINFO_SANDBOX=y +CONFIG_SYSINFO_GPIO=y +CONFIG_SYSRESET=y +CONFIG_TIMER=y +CONFIG_TIMER_EARLY=y +CONFIG_SANDBOX_TIMER=y +CONFIG_USB=y +CONFIG_DM_USB=y +CONFIG_USB_EMUL=y +CONFIG_USB_KEYBOARD=y +CONFIG_DM_VIDEO=y +CONFIG_VIDEO_COPY=y +CONFIG_CONSOLE_ROTATION=y +CONFIG_CONSOLE_TRUETYPE=y +CONFIG_CONSOLE_TRUETYPE_CANTORAONE=y +CONFIG_VIDEO_SANDBOX_SDL=y +CONFIG_VIDEO_DSI_HOST_SANDBOX=y +CONFIG_OSD=y +CONFIG_SANDBOX_OSD=y +CONFIG_SPLASH_SCREEN_ALIGN=y +CONFIG_VIDEO_BMP_RLE8=y +CONFIG_W1=y +CONFIG_W1_GPIO=y +CONFIG_W1_EEPROM=y +CONFIG_W1_EEPROM_SANDBOX=y +CONFIG_WDT=y +CONFIG_WDT_SANDBOX=y +CONFIG_FS_CBFS=y +CONFIG_FS_CRAMFS=y +CONFIG_CMD_DHRYSTONE=y +CONFIG_TPM=y +CONFIG_LZ4=y +CONFIG_ERRNO_STR=y +CONFIG_EFI_RUNTIME_UPDATE_CAPSULE=y +CONFIG_EFI_CAPSULE_ON_DISK=y +CONFIG_EFI_CAPSULE_FIRMWARE_FIT=y +CONFIG_EFI_CAPSULE_FIRMWARE_RAW=y +CONFIG_EFI_CAPSULE_AUTHENTICATE=y +CONFIG_EFI_CAPSULE_KEY_PATH="../test/py/tests/test_efi_capsule/SIGNER.esl"
Is this path relative to the build directory?
No.
Will building fail if the build directory is not a direct subdirectory of the source directory?
No. "incbin" directive in assembly code works with "include directory" paths. As "-Iinclude" is passed on to the assembler, "../" will eventually be able to point to the source directory whatever the build directory is.
-Takahiro Akashi
Best regards
Heinrich
+CONFIG_EFI_SECURE_BOOT=y +CONFIG_TEST_FDTDEC=y +CONFIG_CRYPT_PW=y +CONFIG_CRYPT_PW_SHA256=y +CONFIG_CRYPT_PW_SHA512=y +CONFIG_AUTOBOOT_KEYED=y +CONFIG_AUTOBOOT_PROMPT="Enter password "a" in %d seconds to stop autoboot\n" +CONFIG_AUTOBOOT_ENCRYPTION=y +CONFIG_AUTOBOOT_STOP_STR_ENABLE=y +CONFIG_AUTOBOOT_STOP_STR_CRYPT="$5$rounds=640000$HrpE65IkB8CM5nCL$BKT3QdF98Bo8fJpTr9tjZLZQyzqPASBY20xuK5Rent9" +CONFIG_AUTOBOOT_NEVER_TIMEOUT=y +CONFIG_AUTOBOOT_SHA256_FALLBACK=y +CONFIG_UNIT_TEST=y +CONFIG_UT_TIME=y +CONFIG_UT_DM=y +CONFIG_DM_REBOOT_MODE=y +CONFIG_DM_REBOOT_MODE_GPIO=y +CONFIG_DM_REBOOT_MODE_RTC=y

Hi Takahiro,
On Tue, 27 Jul 2021 at 03:12, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
This new configuration, which was derived from sandbox_defconfig, will be used solely to run efi capsule authentication test as the test requires a public key (esl file) to be embedded in U-Boot binary.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org
configs/sandbox_capsule_auth_defconfig | 307 +++++++++++++++++++++++++ 1 file changed, 307 insertions(+) create mode 100644 configs/sandbox_capsule_auth_defconfig
NAK.
Please just add it to sandbox_defconfig. We sometimes have to create new variants when dealing with actual build variations (e.g. SPL, building without OF_LIVE), but here we should just enable the feature in sandbox_defconfig.
We already covered embedding key in the binary on another thread. Please don't do that. After that debacle I sent a patch explaining this:
http://patchwork.ozlabs.org/project/uboot/patch/20210725164400.468319-3-sjg@...
Regards, Simon

Simon,
On Sat, Jul 31, 2021 at 10:59:32AM -0600, Simon Glass wrote:
Hi Takahiro,
On Tue, 27 Jul 2021 at 03:12, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
This new configuration, which was derived from sandbox_defconfig, will be used solely to run efi capsule authentication test as the test requires a public key (esl file) to be embedded in U-Boot binary.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org
configs/sandbox_capsule_auth_defconfig | 307 +++++++++++++++++++++++++ 1 file changed, 307 insertions(+) create mode 100644 configs/sandbox_capsule_auth_defconfig
NAK.
Please just add it to sandbox_defconfig. We sometimes have to create
Unfortunately, I can't. Look, we now have two tests, test_capsule_firmware.py and test_capsule_firmware_signed.py, and we need U-Boot binaries, respectively, without a key and with a key. A single configuration cannot satisfy both.
new variants when dealing with actual build variations (e.g. SPL, building without OF_LIVE), but here we should just enable the feature in sandbox_defconfig.
We already covered embedding key in the binary on another thread. Please don't do that. After that debacle I sent a patch explaining this:
http://patchwork.ozlabs.org/project/uboot/patch/20210725164400.468319-3-sjg@...
Please discuss and make an agreement with Heinrich. The patch for embedding a key has already been merged in -rc1.
In my personal opinion, neither approaches won't apply to production any way.
-Takahiro Akashi
Regards, Simon

Hi Takahiro,
On Sat, 31 Jul 2021 at 22:29, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
Simon,
On Sat, Jul 31, 2021 at 10:59:32AM -0600, Simon Glass wrote:
Hi Takahiro,
On Tue, 27 Jul 2021 at 03:12, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
This new configuration, which was derived from sandbox_defconfig, will be used solely to run efi capsule authentication test as the test requires a public key (esl file) to be embedded in U-Boot binary.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org
configs/sandbox_capsule_auth_defconfig | 307 +++++++++++++++++++++++++ 1 file changed, 307 insertions(+) create mode 100644 configs/sandbox_capsule_auth_defconfig
NAK.
Please just add it to sandbox_defconfig. We sometimes have to create
Unfortunately, I can't. Look, we now have two tests, test_capsule_firmware.py and test_capsule_firmware_signed.py, and we need U-Boot binaries, respectively, without a key and with a key. A single configuration cannot satisfy both.
new variants when dealing with actual build variations (e.g. SPL, building without OF_LIVE), but here we should just enable the feature in sandbox_defconfig.
We already covered embedding key in the binary on another thread. Please don't do that. After that debacle I sent a patch explaining this:
http://patchwork.ozlabs.org/project/uboot/patch/20210725164400.468319-3-sjg@...
Please discuss and make an agreement with Heinrich. The patch for embedding a key has already been merged in -rc1.
Which patch was that? I thought I pushed back on the one that did that.
In my personal opinion, neither approaches won't apply to production any way.
Regards, Simon

Simon,
On Sun, Aug 01, 2021 at 01:00:20PM -0600, Simon Glass wrote:
Hi Takahiro,
On Sat, 31 Jul 2021 at 22:29, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
Simon,
On Sat, Jul 31, 2021 at 10:59:32AM -0600, Simon Glass wrote:
Hi Takahiro,
On Tue, 27 Jul 2021 at 03:12, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
This new configuration, which was derived from sandbox_defconfig, will be used solely to run efi capsule authentication test as the test requires a public key (esl file) to be embedded in U-Boot binary.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org
configs/sandbox_capsule_auth_defconfig | 307 +++++++++++++++++++++++++ 1 file changed, 307 insertions(+) create mode 100644 configs/sandbox_capsule_auth_defconfig
NAK.
Please just add it to sandbox_defconfig. We sometimes have to create
Unfortunately, I can't. Look, we now have two tests, test_capsule_firmware.py and test_capsule_firmware_signed.py, and we need U-Boot binaries, respectively, without a key and with a key. A single configuration cannot satisfy both.
new variants when dealing with actual build variations (e.g. SPL, building without OF_LIVE), but here we should just enable the feature in sandbox_defconfig.
We already covered embedding key in the binary on another thread. Please don't do that. After that debacle I sent a patch explaining this:
http://patchwork.ozlabs.org/project/uboot/patch/20210725164400.468319-3-sjg@...
Please discuss and make an agreement with Heinrich. The patch for embedding a key has already been merged in -rc1.
Which patch was that? I thought I pushed back on the one that did that.
The commit ddf67daac39d Author: Ilias Apalodimas ilias.apalodimas@linaro.org Date: Sat Jul 17 17:26:44 2021 +0300
efi_capsule: Move signature from DTB to .rodata
-Takahiro Akashi
In my personal opinion, neither approaches won't apply to production any way.
Regards, Simon

Hi Takahiro,
On Sun, 1 Aug 2021 at 16:57, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
Simon,
On Sun, Aug 01, 2021 at 01:00:20PM -0600, Simon Glass wrote:
Hi Takahiro,
On Sat, 31 Jul 2021 at 22:29, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
Simon,
On Sat, Jul 31, 2021 at 10:59:32AM -0600, Simon Glass wrote:
Hi Takahiro,
On Tue, 27 Jul 2021 at 03:12, AKASHI Takahiro takahiro.akashi@linaro.org wrote:
This new configuration, which was derived from sandbox_defconfig, will be used solely to run efi capsule authentication test as the test requires a public key (esl file) to be embedded in U-Boot binary.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org
configs/sandbox_capsule_auth_defconfig | 307 +++++++++++++++++++++++++ 1 file changed, 307 insertions(+) create mode 100644 configs/sandbox_capsule_auth_defconfig
NAK.
Please just add it to sandbox_defconfig. We sometimes have to create
Unfortunately, I can't. Look, we now have two tests, test_capsule_firmware.py and test_capsule_firmware_signed.py, and we need U-Boot binaries, respectively, without a key and with a key. A single configuration cannot satisfy both.
new variants when dealing with actual build variations (e.g. SPL, building without OF_LIVE), but here we should just enable the feature in sandbox_defconfig.
We already covered embedding key in the binary on another thread. Please don't do that. After that debacle I sent a patch explaining this:
http://patchwork.ozlabs.org/project/uboot/patch/20210725164400.468319-3-sjg@...
Please discuss and make an agreement with Heinrich. The patch for embedding a key has already been merged in -rc1.
Which patch was that? I thought I pushed back on the one that did that.
The commit ddf67daac39d Author: Ilias Apalodimas ilias.apalodimas@linaro.org Date: Sat Jul 17 17:26:44 2021 +0300
efi_capsule: Move signature from DTB to .rodata
OK I sent a revert of that as you saw. Then I sent a v2 revert of three patches when you explained that was not enough. I hope we can figure this out quickly.
In my personal opinion, neither approaches won't apply to production any way.
I have not seen any design for how EFI signing would work in production but I am happy to review it. The existing FIT-signing scheme is widely used in production environments. If we use similar processes then we should be OK.
Regards, Simon

To run efi capsule authentication test in CI loop, U-Boot binary must be compiled with an appropriate public key (esl file). Add a rule to build this binary with sandbox_capsule_auth_defconfig and run the test.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org --- .gitlab-ci.yml | 6 ++++++ 1 file changed, 6 insertions(+)
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 86026a15f9da..ed67314fa4ca 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -193,6 +193,12 @@ sandbox_noinst_test.py: TEST_PY_TEST_SPEC: "test_ofplatdata or test_handoff or test_spl" <<: *buildman_and_testpy_dfn
+sandbox_capsule_auth test.py: + variables: + TEST_PY_BD: "sandbox_capsule_auth" + TEST_PY_TEST_SPEC: "test_efi_capsule_signed" + <<: *buildman_and_testpy_dfn + evb-ast2500 test.py: variables: TEST_PY_BD: "evb-ast2500"

The existing options, "--fit" and "--raw," are only used to put a proper GUID in a capsule header, where GUID identifies a particular FMP (Firmware Management Protocol) driver which then would handle the firmware binary in a capsule. In fact, mkeficapsule does the exact same job in creating a capsule file whatever the firmware binary type is.
To prepare for the future extension, the command syntax will be a bit modified to allow users to specify arbitrary GUID for their own FMP driver. OLD: [--fit <image> | --raw <image>] <capsule file> NEW: [--fit | --raw | --guid <guid-string>] <image> <capsule file>
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org --- doc/mkeficapsule.1 | 19 ++++++++++++------ tools/mkeficapsule.c | 46 +++++++++++++++++++++++++++----------------- 2 files changed, 41 insertions(+), 24 deletions(-)
diff --git a/doc/mkeficapsule.1 b/doc/mkeficapsule.1 index 7c2341160ea4..ab2aa3719744 100644 --- a/doc/mkeficapsule.1 +++ b/doc/mkeficapsule.1 @@ -5,7 +5,7 @@ mkeficapsule - Generate EFI capsule file for U-Boot
.SH SYNOPSIS .B mkeficapsule -.RB [\fIoptions\fP] " \fIcapsule-file\fP" +.RB [\fIoptions\fP] " \fIimage-blob\fP \fIcapsule-file\fP"
.SH "DESCRIPTION" The @@ -21,7 +21,7 @@ Optionally, a capsule file can be signed with a given private key. In this case, the update will be authenticated by verifying the signature before applying.
-\fBmkeficapsule\fP supports two different format of image files: +\fBmkeficapsule\fP takes any type of image files, including: .TP .I raw image format is a single binary blob of any type of firmware. @@ -33,15 +33,22 @@ is the same as used in the new \fIuImage\fP format and allows for multiple binary blobs in a single capsule file. This type of image file can be generated by \fBmkimage\fP.
+If you want to use other types than above two, you should explicitly +specify a guid for the FMP driver. + .SH "OPTIONS"
.TP -.BI "-f, --fit \fIfit-image-file\fP" -Specify a FIT image file +.BI "-f, --fit +Indicate that the blob is a FIT image file + +.TP +.BI "-r, --raw +Indicate that the blob is a raw image file
.TP -.BI "-r, --raw \fIraw-image-file\fP" -Specify a raw image file +.BI "-g, --guid \fIguid-string\fP" +Specify guid for image blob type
.TP .BI "-i, --index \fIindex\fP" diff --git a/tools/mkeficapsule.c b/tools/mkeficapsule.c index 798706c7b5f7..8ac1811c68bd 100644 --- a/tools/mkeficapsule.c +++ b/tools/mkeficapsule.c @@ -14,7 +14,7 @@
#include <sys/stat.h> #include <sys/types.h> - +#include <uuid/uuid.h> #include <linux/kconfig.h> #ifdef CONFIG_TOOLS_LIBCRYPTO #include <openssl/asn1.h> @@ -51,14 +51,15 @@ efi_guid_t efi_guid_image_type_uboot_raw = efi_guid_t efi_guid_cert_type_pkcs7 = EFI_CERT_TYPE_PKCS7_GUID;
#ifdef CONFIG_TOOLS_LIBCRYPTO -static const char *opts_short = "f:r:i:I:v:p:c:m:dh"; +static const char *opts_short = "frg:i:I:v:p:c:m:dh"; #else -static const char *opts_short = "f:r:i:I:v:h"; +static const char *opts_short = "frg:i:I:v:h"; #endif
static struct option options[] = { - {"fit", required_argument, NULL, 'f'}, - {"raw", required_argument, NULL, 'r'}, + {"fit", no_argument, NULL, 'f'}, + {"raw", no_argument, NULL, 'r'}, + {"guid", required_argument, NULL, 'g'}, {"index", required_argument, NULL, 'i'}, {"instance", required_argument, NULL, 'I'}, #ifdef CONFIG_TOOLS_LIBCRYPTO @@ -73,11 +74,12 @@ static struct option options[] = {
static void print_usage(void) { - printf("Usage: %s [options] <output file>\n" + printf("Usage: %s [options] <image blob> <output file>\n" "Options:\n"
- "\t-f, --fit <fit image> new FIT image file\n" - "\t-r, --raw <raw image> new raw image file\n" + "\t-f, --fit FIT image type\n" + "\t-r, --raw raw image type\n" + "\t-g, --guid <guid string> guid for image blob type\n" "\t-i, --index <index> update image index\n" "\t-I, --instance <instance> update hardware instance\n" #ifdef CONFIG_TOOLS_LIBCRYPTO @@ -427,14 +429,13 @@ err_1:
int main(int argc, char **argv) { - char *file; efi_guid_t *guid; + unsigned char uuid_buf[16]; unsigned long index, instance; uint64_t mcount; char *privkey_file, *cert_file; int c, idx;
- file = NULL; guid = NULL; index = 0; instance = 0; @@ -449,21 +450,30 @@ int main(int argc, char **argv)
switch (c) { case 'f': - if (file) { - printf("Image already specified\n"); + if (guid) { + printf("Image type already specified\n"); return -1; } - file = optarg; guid = &efi_guid_image_type_uboot_fit; break; case 'r': - if (file) { - printf("Image already specified\n"); + if (guid) { + printf("Image type already specified\n"); return -1; } - file = optarg; guid = &efi_guid_image_type_uboot_raw; break; + case 'g': + if (guid) { + printf("Image type already specified\n"); + return -1; + } + if (uuid_parse(optarg, uuid_buf)) { + printf("Wrong guid format\n"); + return -1; + } + guid = (efi_guid_t *)uuid_buf; + break; case 'i': index = strtoul(optarg, NULL, 0); break; @@ -499,14 +509,14 @@ int main(int argc, char **argv) }
/* check necessary parameters */ - if ((argc != optind + 1) || !file || + if ((argc != optind + 2) || !guid || ((privkey_file && !cert_file) || (!privkey_file && cert_file))) { print_usage(); exit(EXIT_FAILURE); }
- if (create_fwbin(argv[optind], file, guid, index, instance, + if (create_fwbin(argv[argc - 1], argv[argc - 2], guid, index, instance, mcount, privkey_file, cert_file) < 0) { printf("Creating firmware capsule failed\n"); exit(EXIT_FAILURE);

Modify command line arguments at mkeficapsule as the syntax was a bit modified in the previous commit.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org --- test/py/tests/test_efi_capsule/conftest.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/test/py/tests/test_efi_capsule/conftest.py b/test/py/tests/test_efi_capsule/conftest.py index 35cfa5513703..86ace308b3cb 100644 --- a/test/py/tests/test_efi_capsule/conftest.py +++ b/test/py/tests/test_efi_capsule/conftest.py @@ -66,10 +66,10 @@ def efi_capsule_data(request, u_boot_config): check_call('cd %s; %s/tools/mkimage -f uboot_bin_env.its uboot_bin_env.itb' % (data_dir, u_boot_config.build_dir), shell=True) - check_call('cd %s; %s/tools/mkeficapsule --fit uboot_bin_env.itb --index 1 Test01' % + check_call('cd %s; %s/tools/mkeficapsule --index 1 --fit uboot_bin_env.itb Test01' % (data_dir, u_boot_config.build_dir), shell=True) - check_call('cd %s; %s/tools/mkeficapsule --raw u-boot.bin.new --index 1 Test02' % + check_call('cd %s; %s/tools/mkeficapsule --index 1 --raw u-boot.bin.new Test02' % (data_dir, u_boot_config.build_dir), shell=True) if capsule_auth_enabled: @@ -78,11 +78,11 @@ def efi_capsule_data(request, u_boot_config): (u_boot_config.source_dir, data_dir), shell=True) # firmware signed with proper key - check_call('cd %s; %s/tools/mkeficapsule --raw u-boot.bin.new --index 1 --monotonic-count 1 --private-key SIGNER.key --certificate SIGNER.crt Test03' % + check_call('cd %s; %s/tools/mkeficapsule --index 1 --monotonic-count 1 --private-key SIGNER.key --certificate SIGNER.crt --raw u-boot.bin.new Test03' % (data_dir, u_boot_config.build_dir), shell=True) # firmware signed with *mal* key - check_call('cd %s; %s/tools/mkeficapsule --raw u-boot.bin.new --index 1 --monotonic-count 1 --private-key SIGNER2.key --certificate SIGNER2.crt Test04' % + check_call('cd %s; %s/tools/mkeficapsule --index 1 --monotonic-count 1 --private-key SIGNER2.key --certificate SIGNER2.crt --raw u-boot.bin.new Test04' % (data_dir, u_boot_config.build_dir), shell=True)

On 7/27/21 11:10 AM, AKASHI Takahiro wrote:
As I proposed and discussed in [1] and [2], I have made a couple of improvements on the current implementation of capsule update in this patch set.
- add signing feature to mkeficapsule
- add "--guid" option to mkeficapsule
- add man page of mkeficapsule
- add pytest for capsule authentication (on sandbox)
NOTE: Due to Ilias's commit[3], we need to have a customized configuration for sandbox to properly set up and run capsule authentication test. See patch#5,#6 and #7.
[1] https://lists.denx.de/pipermail/u-boot/2021-April/447918.html [2] https://lists.denx.de/pipermail/u-boot/2021-July/455292.html [3] commit ddf67daac39d ("efi_capsule: Move signature from DTB to .rodata")
Dear Takahiro,
thanks for driving this topic. I have finished with my review and will be waiting for v2.
Best regards
Heinrich
Prerequisite patches
None
Test
- locally passed the pytest which is included in this patch series on sandbox built.
Todo
- Confirm that the change in .gitlab-ci.yml works.
- Azure support(?)
Changes
v2 (July 28, 2021)
- rebased on v2021.10-rc*
- removed dependency on target's configuration
- removed fdtsig.sh and others
- add man page
- update the UEFI document
- add dedicate defconfig for testing on sandbox
- add gitlab CI support
- add "--guid" option to mkeficapsule (yet rather RFC)
Initial release (May 12, 2021)
- based on v2021.07-rc2
AKASHI Takahiro (9): tools: mkeficapsule: add firmwware image signing tools: mkeficapsule: add man page doc: update UEFI document for usage of mkeficapsule efi_loader: ease the file path check for public key test/py: efi_capsule: add image authentication test sandbox: add config for efi capsule authentication test GitLab: add a test rule for efi capsule authentication test tools: mkeficapsule: allow for specifying GUID explicitly test/py: efi_capsule: align with the syntax change of mkeficapsule
.gitlab-ci.yml | 6 + MAINTAINERS | 1 + configs/sandbox_capsule_auth_defconfig | 307 +++++++++++++++ doc/develop/uefi/uefi.rst | 31 +- doc/mkeficapsule.1 | 98 +++++ lib/efi_loader/Makefile | 5 +- test/py/tests/test_efi_capsule/SIGNER.crt | 19 + test/py/tests/test_efi_capsule/SIGNER.esl | Bin 0 -> 829 bytes test/py/tests/test_efi_capsule/SIGNER.key | 28 ++ test/py/tests/test_efi_capsule/SIGNER2.crt | 19 + test/py/tests/test_efi_capsule/SIGNER2.key | 28 ++ .../py/tests/test_efi_capsule/capsule_defs.py | 5 + test/py/tests/test_efi_capsule/conftest.py | 39 +- .../test_capsule_firmware_signed.py | 228 +++++++++++ tools/Kconfig | 7 + tools/Makefile | 8 +- tools/mkeficapsule.c | 368 ++++++++++++++++-- 17 files changed, 1129 insertions(+), 68 deletions(-) create mode 100644 configs/sandbox_capsule_auth_defconfig create mode 100644 doc/mkeficapsule.1 create mode 100644 test/py/tests/test_efi_capsule/SIGNER.crt create mode 100644 test/py/tests/test_efi_capsule/SIGNER.esl create mode 100644 test/py/tests/test_efi_capsule/SIGNER.key create mode 100644 test/py/tests/test_efi_capsule/SIGNER2.crt create mode 100644 test/py/tests/test_efi_capsule/SIGNER2.key create mode 100644 test/py/tests/test_efi_capsule/test_capsule_firmware_signed.py

Heinrich,
On Sun, Aug 01, 2021 at 11:40:14AM +0200, Heinrich Schuchardt wrote:
On 7/27/21 11:10 AM, AKASHI Takahiro wrote:
As I proposed and discussed in [1] and [2], I have made a couple of improvements on the current implementation of capsule update in this patch set.
- add signing feature to mkeficapsule
- add "--guid" option to mkeficapsule
- add man page of mkeficapsule
- add pytest for capsule authentication (on sandbox)
NOTE: Due to Ilias's commit[3], we need to have a customized configuration for sandbox to properly set up and run capsule authentication test. See patch#5,#6 and #7.
[1] https://lists.denx.de/pipermail/u-boot/2021-April/447918.html [2] https://lists.denx.de/pipermail/u-boot/2021-July/455292.html [3] commit ddf67daac39d ("efi_capsule: Move signature from DTB to .rodata")
Dear Takahiro,
thanks for driving this topic. I have finished with my review and will be waiting for v2.
Thanks for your review comments.
I'd like to know what's your thought on Patch#8 (and #9) as I have not seen your comment at [2] above. It is more or less an RFC since it breaks the compatibility of command syntax although I believe that the change is quite useful.
-Takahiro Akashi
Best regards
Heinrich
Prerequisite patches
None
Test
- locally passed the pytest which is included in this patch series on sandbox built.
Todo
- Confirm that the change in .gitlab-ci.yml works.
- Azure support(?)
Changes
v2 (July 28, 2021)
- rebased on v2021.10-rc*
- removed dependency on target's configuration
- removed fdtsig.sh and others
- add man page
- update the UEFI document
- add dedicate defconfig for testing on sandbox
- add gitlab CI support
- add "--guid" option to mkeficapsule (yet rather RFC)
Initial release (May 12, 2021)
- based on v2021.07-rc2
AKASHI Takahiro (9): tools: mkeficapsule: add firmwware image signing tools: mkeficapsule: add man page doc: update UEFI document for usage of mkeficapsule efi_loader: ease the file path check for public key test/py: efi_capsule: add image authentication test sandbox: add config for efi capsule authentication test GitLab: add a test rule for efi capsule authentication test tools: mkeficapsule: allow for specifying GUID explicitly test/py: efi_capsule: align with the syntax change of mkeficapsule
.gitlab-ci.yml | 6 + MAINTAINERS | 1 + configs/sandbox_capsule_auth_defconfig | 307 +++++++++++++++ doc/develop/uefi/uefi.rst | 31 +- doc/mkeficapsule.1 | 98 +++++ lib/efi_loader/Makefile | 5 +- test/py/tests/test_efi_capsule/SIGNER.crt | 19 + test/py/tests/test_efi_capsule/SIGNER.esl | Bin 0 -> 829 bytes test/py/tests/test_efi_capsule/SIGNER.key | 28 ++ test/py/tests/test_efi_capsule/SIGNER2.crt | 19 + test/py/tests/test_efi_capsule/SIGNER2.key | 28 ++ .../py/tests/test_efi_capsule/capsule_defs.py | 5 + test/py/tests/test_efi_capsule/conftest.py | 39 +- .../test_capsule_firmware_signed.py | 228 +++++++++++ tools/Kconfig | 7 + tools/Makefile | 8 +- tools/mkeficapsule.c | 368 ++++++++++++++++-- 17 files changed, 1129 insertions(+), 68 deletions(-) create mode 100644 configs/sandbox_capsule_auth_defconfig create mode 100644 doc/mkeficapsule.1 create mode 100644 test/py/tests/test_efi_capsule/SIGNER.crt create mode 100644 test/py/tests/test_efi_capsule/SIGNER.esl create mode 100644 test/py/tests/test_efi_capsule/SIGNER.key create mode 100644 test/py/tests/test_efi_capsule/SIGNER2.crt create mode 100644 test/py/tests/test_efi_capsule/SIGNER2.key create mode 100644 test/py/tests/test_efi_capsule/test_capsule_firmware_signed.py
participants (4)
-
AKASHI Takahiro
-
Heinrich Schuchardt
-
Masami Hiramatsu
-
Simon Glass