From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from phobos.denx.de (phobos.denx.de [85.214.62.61]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 1D4FCC433F5 for ; Tue, 31 May 2022 23:53:43 +0000 (UTC) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id A504882A57; Wed, 1 Jun 2022 01:53:41 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (2048-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.b="hQ0fROYg"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id A221F81970; Wed, 1 Jun 2022 01:53:39 +0200 (CEST) Received: from mail-pl1-x635.google.com (mail-pl1-x635.google.com [IPv6:2607:f8b0:4864:20::635]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id 8BE1A81970 for ; Wed, 1 Jun 2022 01:53:35 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=takahiro.akashi@linaro.org Received: by mail-pl1-x635.google.com with SMTP id n18so192631plg.5 for ; Tue, 31 May 2022 16:53:35 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=date:from:to:cc:subject:message-id:mail-followup-to:references :mime-version:content-disposition:content-transfer-encoding :in-reply-to; bh=k2B81DflhvBwyCmc97k0csjtcfSxAYrUNdtzoIvdg50=; b=hQ0fROYgK80nbpOMLURYkMfEA+WUtmCDoS8DMg8XPdXF6qDkT5M/8HaALnouNerX63 kzwKZxIXTgKF1YgyjPypYiLzCyyCYN+/qjvz4GBS0zzzJJ0Szi0VHXoxypdFlre9m+ZJ blF5VfABipp6NC7XT+6cSZGblWKuKISuhN+yoMmJaQQhPbv1dA7cQ/whS6BjYQAXDVyc 8HzpfdFiYq1orhgdg9PukHwFmOJX8EuRyav9gXjdEFkMuO3oW/zgOOHQWKJ2NRAzkZSY SIDrCrE7t75L1AAhXFXGNKBcYPs3Y+TXg9s6BE88otLaVqyfvdt+24yg+9FaE/jYkzMr CwdA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:date:from:to:cc:subject:message-id :mail-followup-to:references:mime-version:content-disposition :content-transfer-encoding:in-reply-to; bh=k2B81DflhvBwyCmc97k0csjtcfSxAYrUNdtzoIvdg50=; b=7iom7fZDV0RlQnTiCECFIyxj9nYzrDUm5XLR62e+zZox7NXVtHgP7Seso9a7VAKjqt Fr7xXXP2RZqlJh5L5gIWuP8dX2l4kIrQNAnS960pP8OEqsk50IxFIz9eKkj0cDejgZgC pa276y/uIspSs8f6IhR5/7w0nuc+MKv1+TK526jdyc31LUDciAh1WK9YWaTiQsk2h4TY OfOKgBWi+bGQemXUDdy19uBfTsI1OYfXWMVIsPeNfojgHYN1+E56louACjX3h7ITuWiy PBbdUtDITjFOmMlBYYlN6c/XAZClJCb1wEfaj8jbnqTB6dRPdBlFUddJrd1UmZHp+7eZ xnpg== X-Gm-Message-State: AOAM532hZTup32EII8H8+2l8uAPhMV+QQqcedcLbdQ7tmOq42S0QWJ8+ w8FDY5R8OArxBNC0chs3UW2mMw== X-Google-Smtp-Source: ABdhPJyJW1i9eCBm3zpCYiRX24uGaBOMSV6CxK2Peois5FIURwA0tagt1VzgROaLswykSKDWDbYFtw== X-Received: by 2002:a17:90a:778c:b0:1df:56a5:8474 with SMTP id v12-20020a17090a778c00b001df56a58474mr31370983pjk.63.1654041213812; Tue, 31 May 2022 16:53:33 -0700 (PDT) Received: from laputa ([2400:4050:c3e1:100:753f:c927:92c8:dd77]) by smtp.gmail.com with ESMTPSA id a201-20020a621ad2000000b005183c6a21c8sm17554pfa.165.2022.05.31.16.53.32 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 31 May 2022 16:53:33 -0700 (PDT) Date: Wed, 1 Jun 2022 08:53:30 +0900 From: AKASHI Takahiro To: Vincent Stehl?? Cc: u-boot@lists.denx.de, Heinrich Schuchardt Subject: Re: [PATCH 2/2] efi: test/py: authenticate fit capsules Message-ID: <20220531235330.GA42623@laputa> Mail-Followup-To: AKASHI Takahiro , Vincent Stehl?? , u-boot@lists.denx.de, Heinrich Schuchardt References: <20220531075534.1101256-1-vincent.stehle@arm.com> <20220531075534.1101256-2-vincent.stehle@arm.com> MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Disposition: inline Content-Transfer-Encoding: 8bit In-Reply-To: <20220531075534.1101256-2-vincent.stehle@arm.com> X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.39 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.5 at phobos.denx.de X-Virus-Status: Clean On Tue, May 31, 2022 at 09:55:34AM +0200, Vincent Stehl?? wrote: > Add support for the authentication of UEFI capsules containing FIT images. Thank you for adding this enhancement. Sughosh could and should have done it from the beginning. > The authentication code is moved out of the function handling raw images > into a new function efi_firmware_capsule_authenticate(). The special case > for the FMP header coming from edk2 tools is preserved. There is no > functional change for capsules containing raw images. > > The python test for signed capsules with raw images is renamed with no > functional change and a new test is added for signed capsules containing > FIT images. > > This can be tested with sandbox64_defconfig or sandbox_flattree_defconfig, > plus CONFIG_EFI_CAPSULE_AUTHENTICATE=y. I hope that the 'capsule authentication' tests, either FIT or raw, be run in CI loop even if we need end up adding new sandbox config files. -Takahiro Akashi > Signed-off-by: Vincent Stehlé > Cc: Heinrich Schuchardt > --- > lib/efi_loader/efi_firmware.c | 115 +++++++++++------- > test/py/tests/test_efi_capsule/conftest.py | 21 +++- > ...py => test_capsule_firmware_signed_fit.py} | 41 ++++--- > ...py => test_capsule_firmware_signed_raw.py} | 6 +- > 4 files changed, 117 insertions(+), 66 deletions(-) > copy test/py/tests/test_efi_capsule/{test_capsule_firmware_signed.py => test_capsule_firmware_signed_fit.py} (89%) > rename test/py/tests/test_efi_capsule/{test_capsule_firmware_signed.py => test_capsule_firmware_signed_raw.py} (98%) > > diff --git a/lib/efi_loader/efi_firmware.c b/lib/efi_loader/efi_firmware.c > index fe4e084106d..cbe29e90789 100644 > --- a/lib/efi_loader/efi_firmware.c > +++ b/lib/efi_loader/efi_firmware.c > @@ -178,6 +178,70 @@ static efi_status_t efi_fill_image_desc_array( > return EFI_SUCCESS; > } > > +/** > + * efi_firmware_capsule_authenticate - authenticate the capsule if enabled > + * @p_image: Pointer to new image > + * @p_image_size: Pointer to size of new image > + * > + * Authenticate the capsule if authentication is enabled. > + * The image pointer and the image size are updated in case of success. > + * > + * Return: status code > + */ > +static > +efi_status_t efi_firmware_capsule_authenticate(const void **p_image, > + efi_uintn_t *p_image_size) > +{ > + const void *image = *p_image; > + efi_uintn_t image_size = *p_image_size; > + u32 fmp_hdr_signature; > + struct fmp_payload_header *header; > + void *capsule_payload; > + efi_status_t status; > + efi_uintn_t capsule_payload_size; > + > + if (IS_ENABLED(CONFIG_EFI_CAPSULE_AUTHENTICATE)) { > + capsule_payload = NULL; > + capsule_payload_size = 0; > + status = efi_capsule_authenticate(image, image_size, > + &capsule_payload, > + &capsule_payload_size); > + > + if (status == EFI_SECURITY_VIOLATION) { > + printf("Capsule authentication check failed. Aborting update\n"); > + return status; > + } else if (status != EFI_SUCCESS) { > + return status; > + } > + > + debug("Capsule authentication successful\n"); > + image = capsule_payload; > + image_size = capsule_payload_size; > + } else { > + debug("Capsule authentication disabled. "); > + debug("Updating capsule without authenticating.\n"); > + } > + > + fmp_hdr_signature = FMP_PAYLOAD_HDR_SIGNATURE; > + header = (void *)image; > + > + if (!memcmp(&header->signature, &fmp_hdr_signature, > + sizeof(fmp_hdr_signature))) { > + /* > + * When building the capsule with the scripts in > + * edk2, a FMP header is inserted above the capsule > + * payload. Compensate for this header to get the > + * actual payload that is to be updated. > + */ > + image += header->header_size; > + image_size -= header->header_size; > + } > + > + *p_image = image; > + *p_image_size = image_size; > + return EFI_SUCCESS; > +} > + > #ifdef CONFIG_EFI_CAPSULE_FIRMWARE_FIT > /* > * This FIRMWARE_MANAGEMENT_PROTOCOL driver provides a firmware update > @@ -266,12 +330,18 @@ efi_status_t EFIAPI efi_firmware_fit_set_image( > efi_status_t (*progress)(efi_uintn_t completion), > u16 **abort_reason) > { > + efi_status_t status; > + > EFI_ENTRY("%p %d %p %zu %p %p %p\n", this, image_index, image, > image_size, vendor_code, progress, abort_reason); > > if (!image || image_index != 1) > return EFI_EXIT(EFI_INVALID_PARAMETER); > > + status = efi_firmware_capsule_authenticate(&image, &image_size); > + if (status != EFI_SUCCESS) > + return EFI_EXIT(status); > + > if (fit_update(image)) > return EFI_EXIT(EFI_DEVICE_ERROR); > > @@ -372,11 +442,7 @@ efi_status_t EFIAPI efi_firmware_raw_set_image( > efi_status_t (*progress)(efi_uintn_t completion), > u16 **abort_reason) > { > - u32 fmp_hdr_signature; > - struct fmp_payload_header *header; > - void *capsule_payload; > efi_status_t status; > - efi_uintn_t capsule_payload_size; > > EFI_ENTRY("%p %d %p %zu %p %p %p\n", this, image_index, image, > image_size, vendor_code, progress, abort_reason); > @@ -384,44 +450,9 @@ efi_status_t EFIAPI efi_firmware_raw_set_image( > if (!image) > return EFI_EXIT(EFI_INVALID_PARAMETER); > > - /* Authenticate the capsule if authentication enabled */ > - if (IS_ENABLED(CONFIG_EFI_CAPSULE_AUTHENTICATE)) { > - capsule_payload = NULL; > - capsule_payload_size = 0; > - status = efi_capsule_authenticate(image, image_size, > - &capsule_payload, > - &capsule_payload_size); > - > - if (status == EFI_SECURITY_VIOLATION) { > - printf("Capsule authentication check failed. Aborting update\n"); > - return EFI_EXIT(status); > - } else if (status != EFI_SUCCESS) { > - return EFI_EXIT(status); > - } > - > - debug("Capsule authentication successfull\n"); > - image = capsule_payload; > - image_size = capsule_payload_size; > - } else { > - debug("Capsule authentication disabled. "); > - debug("Updating capsule without authenticating.\n"); > - } > - > - fmp_hdr_signature = FMP_PAYLOAD_HDR_SIGNATURE; > - header = (void *)image; > - > - if (!memcmp(&header->signature, &fmp_hdr_signature, > - sizeof(fmp_hdr_signature))) { > - /* > - * When building the capsule with the scripts in > - * edk2, a FMP header is inserted above the capsule > - * payload. Compensate for this header to get the > - * actual payload that is to be updated. > - */ > - image += header->header_size; > - image_size -= header->header_size; > - > - } > + status = efi_firmware_capsule_authenticate(&image, &image_size); > + if (status != EFI_SUCCESS) > + return EFI_EXIT(status); > > if (dfu_write_by_alt(image_index - 1, (void *)image, image_size, > NULL, NULL)) > diff --git a/test/py/tests/test_efi_capsule/conftest.py b/test/py/tests/test_efi_capsule/conftest.py > index 5a8826a5a6b..4879f2b5c24 100644 > --- a/test/py/tests/test_efi_capsule/conftest.py > +++ b/test/py/tests/test_efi_capsule/conftest.py > @@ -97,7 +97,7 @@ def efi_capsule_data(request, u_boot_config): > shell=True) > > if capsule_auth_enabled: > - # firmware signed with proper key > + # raw firmware signed with proper key > check_call('cd %s; ' > '%s/tools/mkeficapsule --index 1 --monotonic-count 1 ' > '--private-key SIGNER.key --certificate SIGNER.crt ' > @@ -105,7 +105,7 @@ def efi_capsule_data(request, u_boot_config): > 'u-boot.bin.new Test11' > % (data_dir, u_boot_config.build_dir), > shell=True) > - # firmware signed with *mal* key > + # raw firmware signed with *mal* key > check_call('cd %s; ' > '%s/tools/mkeficapsule --index 1 --monotonic-count 1 ' > '--private-key SIGNER2.key ' > @@ -114,6 +114,23 @@ def efi_capsule_data(request, u_boot_config): > 'u-boot.bin.new Test12' > % (data_dir, u_boot_config.build_dir), > shell=True) > + # FIT firmware signed with proper key > + check_call('cd %s; ' > + '%s/tools/mkeficapsule --index 1 --monotonic-count 1 ' > + '--private-key SIGNER.key --certificate SIGNER.crt ' > + '--guid 3673B45D-6A7C-46F3-9E60-ADABB03F7937 ' > + 'uboot_bin_env.itb Test13' > + % (data_dir, u_boot_config.build_dir), > + shell=True) > + # FIT firmware signed with *mal* key > + check_call('cd %s; ' > + '%s/tools/mkeficapsule --index 1 --monotonic-count 1 ' > + '--private-key SIGNER2.key ' > + '--certificate SIGNER2.crt ' > + '--guid 3673B45D-6A7C-46F3-9E60-ADABB03F7937 ' > + 'uboot_bin_env.itb Test14' > + % (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_fit.py > similarity index 89% > copy from test/py/tests/test_efi_capsule/test_capsule_firmware_signed.py > copy to test/py/tests/test_efi_capsule/test_capsule_firmware_signed_fit.py > index a0b6a1ac86f..4400b8f1368 100644 > --- a/test/py/tests/test_efi_capsule/test_capsule_firmware_signed.py > +++ b/test/py/tests/test_efi_capsule/test_capsule_firmware_signed_fit.py > @@ -1,19 +1,22 @@ > # SPDX-License-Identifier: GPL-2.0+ > # Copyright (c) 2021, Linaro Limited > -# Author: AKASHI Takahiro > +# Copyright (c) 2022, Arm Limited > +# Author: AKASHI Takahiro , > +# adapted to FIT images by Vincent Stehlé > # > -# U-Boot UEFI: Firmware Update (Signed capsule) Test > +# U-Boot UEFI: Firmware Update (Signed capsule with FIT images) Test > > """ > This test verifies capsule-on-disk firmware update > -with signed capsule files > +with signed capsule files containing FIT images > """ > > import pytest > from capsule_defs import CAPSULE_DATA_DIR, CAPSULE_INSTALL_DIR > > -@pytest.mark.boardspec('sandbox') > -@pytest.mark.buildconfigspec('efi_capsule_firmware_raw') > +@pytest.mark.boardspec('sandbox64') > +@pytest.mark.boardspec('sandbox_flattree') > +@pytest.mark.buildconfigspec('efi_capsule_firmware_fit') > @pytest.mark.buildconfigspec('efi_capsule_authenticate') > @pytest.mark.buildconfigspec('dfu') > @pytest.mark.buildconfigspec('dfu_sf') > @@ -23,11 +26,11 @@ from capsule_defs import CAPSULE_DATA_DIR, CAPSULE_INSTALL_DIR > @pytest.mark.buildconfigspec('cmd_nvedit_efi') > @pytest.mark.buildconfigspec('cmd_sf') > @pytest.mark.slow > -class TestEfiCapsuleFirmwareSigned(object): > +class TestEfiCapsuleFirmwareSignedFit(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 > + Test Case 1 - Update U-Boot on SPI Flash, FIT image format > 0x100000-0x150000: U-Boot binary (but dummy) > > If the capsule is properly signed, the authentication > @@ -57,11 +60,11 @@ class TestEfiCapsuleFirmwareSigned(object): > > # place a capsule file > output = u_boot_console.run_command_list([ > - 'fatload host 0:1 4000000 %s/Test11' % CAPSULE_DATA_DIR, > - 'fatwrite host 0:1 4000000 %s/Test11 $filesize' > + 'fatload host 0:1 4000000 %s/Test13' % CAPSULE_DATA_DIR, > + 'fatwrite host 0:1 4000000 %s/Test13 $filesize' > % CAPSULE_INSTALL_DIR, > 'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR]) > - assert 'Test11' in ''.join(output) > + assert 'Test13' in ''.join(output) > > # reboot > mnt_point = u_boot_config.persistent_data_dir + '/test_efi_capsule' > @@ -81,7 +84,7 @@ class TestEfiCapsuleFirmwareSigned(object): > '0x50000;u-boot-env raw 0x150000 0x200000"', > 'host bind 0 %s' % disk_img, > 'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR]) > - assert 'Test11' in ''.join(output) > + assert 'Test13' in ''.join(output) > > # need to run uefi command to initiate capsule handling > output = u_boot_console.run_command( > @@ -90,7 +93,7 @@ class TestEfiCapsuleFirmwareSigned(object): > output = u_boot_console.run_command_list([ > 'host bind 0 %s' % disk_img, > 'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR]) > - assert 'Test11' not in ''.join(output) > + assert 'Test13' not in ''.join(output) > > output = u_boot_console.run_command_list([ > 'sf probe 0:0', > @@ -101,7 +104,7 @@ class TestEfiCapsuleFirmwareSigned(object): > 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 > + Test Case 2 - Update U-Boot on SPI Flash, FIT image format > 0x100000-0x150000: U-Boot binary (but dummy) > > If the capsule is signed but with an invalid key, > @@ -132,11 +135,11 @@ class TestEfiCapsuleFirmwareSigned(object): > > # place a capsule file > output = u_boot_console.run_command_list([ > - 'fatload host 0:1 4000000 %s/Test12' % CAPSULE_DATA_DIR, > - 'fatwrite host 0:1 4000000 %s/Test12 $filesize' > + 'fatload host 0:1 4000000 %s/Test14' % CAPSULE_DATA_DIR, > + 'fatwrite host 0:1 4000000 %s/Test14 $filesize' > % CAPSULE_INSTALL_DIR, > 'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR]) > - assert 'Test12' in ''.join(output) > + assert 'Test14' in ''.join(output) > > # reboot > mnt_point = u_boot_config.persistent_data_dir + '/test_efi_capsule' > @@ -156,7 +159,7 @@ class TestEfiCapsuleFirmwareSigned(object): > '0x50000;u-boot-env raw 0x150000 0x200000"', > 'host bind 0 %s' % disk_img, > 'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR]) > - assert 'Test12' in ''.join(output) > + assert 'Test14' in ''.join(output) > > # need to run uefi command to initiate capsule handling > output = u_boot_console.run_command( > @@ -166,7 +169,7 @@ class TestEfiCapsuleFirmwareSigned(object): > output = u_boot_console.run_command_list([ > 'host bind 0 %s' % disk_img, > 'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR]) > - assert 'Test12' not in ''.join(output) > + assert 'Test14' not in ''.join(output) > > # TODO: check CapsuleStatus in CapsuleXXXX > > @@ -179,7 +182,7 @@ class TestEfiCapsuleFirmwareSigned(object): > 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 > + Test Case 3 - Update U-Boot on SPI Flash, FIT image format > 0x100000-0x150000: U-Boot binary (but dummy) > > If the capsule is not signed, the authentication > 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_raw.py > similarity index 98% > rename from test/py/tests/test_efi_capsule/test_capsule_firmware_signed.py > rename to test/py/tests/test_efi_capsule/test_capsule_firmware_signed_raw.py > index a0b6a1ac86f..8201a544e0c 100644 > --- a/test/py/tests/test_efi_capsule/test_capsule_firmware_signed.py > +++ b/test/py/tests/test_efi_capsule/test_capsule_firmware_signed_raw.py > @@ -2,11 +2,11 @@ > # Copyright (c) 2021, Linaro Limited > # Author: AKASHI Takahiro > # > -# U-Boot UEFI: Firmware Update (Signed capsule) Test > +# U-Boot UEFI: Firmware Update (Signed capsule with raw images) Test > > """ > This test verifies capsule-on-disk firmware update > -with signed capsule files > +with signed capsule files containing raw images > """ > > import pytest > @@ -23,7 +23,7 @@ from capsule_defs import CAPSULE_DATA_DIR, CAPSULE_INSTALL_DIR > @pytest.mark.buildconfigspec('cmd_nvedit_efi') > @pytest.mark.buildconfigspec('cmd_sf') > @pytest.mark.slow > -class TestEfiCapsuleFirmwareSigned(object): > +class TestEfiCapsuleFirmwareSignedRaw(object): > def test_efi_capsule_auth1( > self, u_boot_config, u_boot_console, efi_capsule_data): > """ > -- > 2.35.1 >