From patchwork Wed Dec 18 00:44:57 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: AKASHI Takahiro X-Patchwork-Id: 1211834 X-Patchwork-Delegate: xypron.glpk@gmx.de Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=linaro.org Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.b="CxlF6yfu"; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [IPv6:2a01:238:438b:c500:173d:9f52:ddab:ee01]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 47cx901KxWz9sRl for ; Wed, 18 Dec 2019 11:44:20 +1100 (AEDT) Received: from phobos.denx.de (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 0B86B814EE; Wed, 18 Dec 2019 01:44:08 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=fail (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=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.b="CxlF6yfu"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id C03E7814F4; Wed, 18 Dec 2019 01:44:06 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-0.1 required=5.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,SPF_HELO_NONE,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.2 Received: from mail-pl1-x644.google.com (mail-pl1-x644.google.com [IPv6:2607:f8b0:4864:20::644]) (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 CC1B4814E2 for ; Wed, 18 Dec 2019 01:44:02 +0100 (CET) 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-x644.google.com with SMTP id x17so174235pln.1 for ; Tue, 17 Dec 2019 16:44:02 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=mWQep0Iuau6MvIsaAqXLvNS/kbsgyC5O6EkPQja20xI=; b=CxlF6yfuDYek9ZvtquR9Zg5k1ulS6l78WyQUX6ja//rq1ONjvlSDQ5QA1+3JIt+foe GvdyqDcgtaGIJ2g+Dew+HpcrRCJse0U1MbgSuvJGK6YF4WBsjy9ms82xbYmmB3K6hkwj YzZKduGQcIsTNzMzBc3BbpyefE2lCDRvlC8vWrADfnFgNxhdrsTqcfx8Da1PREibti1o KEbEWqSlcLrSsw4NBwj3VvX3yxz99NlgPw/uir3U9STUDbUCA6wjEJHQoBFfNF4xcNTF 75C7uIoo1STTDsJTHT/D2SY42p/6NQ68q0CO2sR4Wv7ZdSHmsrj/yC89TPKBJxeDM+Qs WDPg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=mWQep0Iuau6MvIsaAqXLvNS/kbsgyC5O6EkPQja20xI=; b=cbjDDrNMPux8AwtKs/V+1DTBHWu56E5mgkBdnNKvYgIhHTfdlx3proa18hsplyUpu/ XDiKRuSDv9ibccDvN2LdBaywgZPjvbVcJkPaMi1s2enHu6DIJ3LQ0HBenQQLv+dWBeB3 qzargxrUBNZ7dIQ6Ap5eRx3SOT+gJX53lDpKis+HKm65Zef+7sIskAbY/v3YbZVC4C2g bBo5JZaQbfzVSA8wWH8LWyX25hmqsEBonmZLeKa9sFxlJ0UjUFKca8eskoYc4xHe1b/A EnrHVuFYb43G4zmU4LDYZfxVE6H/KgdfxbvihRsOqEHamEhhph+S3j8a4pgrSgIYuqyf 2Y+g== X-Gm-Message-State: APjAAAU9CFhglJemtM/5tU8zXWG80wDp9eaYC1M+CtiWoDhw+H+VOu0F K3smYgLX7HoLMIoh8tbQ5yPCIw== X-Google-Smtp-Source: APXvYqxWPaDbmOSAkmQLLN1W++YokbodS5kgALdUDEgQmT5PLSKrTwIAA9kg/7vSaGs54jJAsLGhzw== X-Received: by 2002:a17:902:6a87:: with SMTP id n7mr968745plk.273.1576629840677; Tue, 17 Dec 2019 16:44:00 -0800 (PST) Received: from linaro.org ([121.95.100.191]) by smtp.googlemail.com with ESMTPSA id b2sm4515037pjq.3.2019.12.17.16.43.59 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 17 Dec 2019 16:44:00 -0800 (PST) From: AKASHI Takahiro To: xypron.glpk@gmx.de, agraf@csgraf.de, trini@konsulko.com Subject: [PATCH v4 01/16] include: pe.h: add signature-related definitions Date: Wed, 18 Dec 2019 09:44:57 +0900 Message-Id: <20191218004512.24939-2-takahiro.akashi@linaro.org> X-Mailer: git-send-email 2.24.0 In-Reply-To: <20191218004512.24939-1-takahiro.akashi@linaro.org> References: <20191218004512.24939-1-takahiro.akashi@linaro.org> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.26 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: u-boot@lists.denx.de, mail@patrick-wildt.de Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.101.4 at phobos.denx.de X-Virus-Status: Clean The index (IMAGE_DIRECTORY_ENTRY_SECURITY) in a table points to a region containing authentication information (image's signature) in PE format. WIN_CERTIFICATE structure defines an embedded signature format. Those definitions will be used in my UEFI secure boot patch. Signed-off-by: AKASHI Takahiro Reviewed-by: Heinrich Schuchardt --- include/pe.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/include/pe.h b/include/pe.h index bff3b0aa7a6c..086f2b860e99 100644 --- a/include/pe.h +++ b/include/pe.h @@ -155,6 +155,8 @@ typedef struct _IMAGE_SECTION_HEADER { uint32_t Characteristics; } IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER; +/* Indices for Optional Header Data Directories */ +#define IMAGE_DIRECTORY_ENTRY_SECURITY 4 #define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 typedef struct _IMAGE_BASE_RELOCATION @@ -252,4 +254,20 @@ typedef struct _IMAGE_RELOCATION #define IMAGE_REL_AMD64_PAIR 0x000F #define IMAGE_REL_AMD64_SSPAN32 0x0010 +/* certificate appended to PE image */ +typedef struct _WIN_CERTIFICATE { + uint32_t dwLength; + uint16_t wRevision; + uint16_t wCertificateType; + uint8_t bCertificate[]; +} WIN_CERTIFICATE, *LPWIN_CERTIFICATE; + +/* Definitions for the contents of the certs data block */ +#define WIN_CERT_TYPE_PKCS_SIGNED_DATA 0x0002 +#define WIN_CERT_TYPE_EFI_OKCS115 0x0EF0 +#define WIN_CERT_TYPE_EFI_GUID 0x0EF1 + +#define WIN_CERT_REVISION_1_0 0x0100 +#define WIN_CERT_REVISION_2_0 0x0200 + #endif /* _PE_H */ From patchwork Wed Dec 18 00:44:58 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: AKASHI Takahiro X-Patchwork-Id: 1211835 X-Patchwork-Delegate: xypron.glpk@gmx.de Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=85.214.62.61; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=linaro.org Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.b="wOd3+dqE"; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [85.214.62.61]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 47cx9D50Xcz9sRl for ; Wed, 18 Dec 2019 11:44:32 +1100 (AEDT) Received: from phobos.denx.de (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 7CA5981582; Wed, 18 Dec 2019 01:44:12 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=fail (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=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.b="wOd3+dqE"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id AF25F815D3; Wed, 18 Dec 2019 01:44:08 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-0.1 required=5.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,SPF_HELO_NONE,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.2 Received: from mail-pf1-x442.google.com (mail-pf1-x442.google.com [IPv6:2607:f8b0:4864:20::442]) (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 69198814ED for ; Wed, 18 Dec 2019 01:44:05 +0100 (CET) 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-pf1-x442.google.com with SMTP id d199so186316pfd.11 for ; Tue, 17 Dec 2019 16:44:05 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=OherbPEAzeMyIzJzhUng92q1qgIki6b6p+0pE+AiJ/s=; b=wOd3+dqEi1Hv+mYPt3MPOx4X8YHVp+C/fzJzIjIUDqw73ore7eMYMPPJ3sGwKNAoNj CURmEsX9INAor3MFiuYyy+zUs3RWU55aI0p53H36qjlQwo0HM9IvD8eHAxFp/HwM+rF6 rVjz4MlOZerZyAtKpFIvXuZvnIbQkoeH5q++07l9lsw0CXWdiq1CSGSSsNCqyLnyXccv +IXdSgx9Q1VV7ggVjfqPbCH1zLsysIDT7N6g7KvvJD8J3TmDyDJe79I9SbC1QbLAw3nX V+jDyaxuw5WU1gIbczGEH10wkwGkXhpWl2WP7sK8UpHna9dUtjF8oQ5WSf1JFUXhUb/y cczA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=OherbPEAzeMyIzJzhUng92q1qgIki6b6p+0pE+AiJ/s=; b=Q2dUfD4g/x3B0FiBQ4jG4gIdbSO5TsQlSdF9OU1k6HkdDM1hN+9KbOGq0gdIwL5Qcb 7Wov6MVBBPNB6D5lXmsjrMfOWwNXofP3Hc2L+xVH/fBpqMyv8n2wycDLBy5JOZvGPrk+ kGte7wt/Yh6prvZsVjTSEmXCegM/d4DwfR0zzieoibLM7KhPt/bL/l8CMQhf1x3w3MeA 8pEOuElDB6TenBZhc2hXuSovArInA1+W40Ile0bkrSIN6yEpVTlpmESfKZu2xKPMqE9Q lVki2NgYA5koI6kHqT1LYYu57P3z975Uf1aPBYz7t17RLOV6Z+5IkSAxRCJhFHvC29YO F6+Q== X-Gm-Message-State: APjAAAVfb4E2rdNH46OAWb+n3WU5Gaoz1zv60e1VOScRC2eMoEMISQkD dWSbL3C9+DyW5Lo1M2aGBgw6skEFzXw= X-Google-Smtp-Source: APXvYqzgZE8G2numcQAN1fijr0ZwQw0WaGdIkgxbAMLKGcnQwA8l0cfV97QTQxDCQ3S1QdqpuyLOwg== X-Received: by 2002:a63:4641:: with SMTP id v1mr218392pgk.389.1576629843933; Tue, 17 Dec 2019 16:44:03 -0800 (PST) Received: from linaro.org ([121.95.100.191]) by smtp.googlemail.com with ESMTPSA id u3sm193231pga.72.2019.12.17.16.44.03 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 17 Dec 2019 16:44:03 -0800 (PST) From: AKASHI Takahiro To: xypron.glpk@gmx.de, agraf@csgraf.de, trini@konsulko.com Subject: [PATCH v4 02/16] efi_loader: add CONFIG_EFI_SECURE_BOOT config option Date: Wed, 18 Dec 2019 09:44:58 +0900 Message-Id: <20191218004512.24939-3-takahiro.akashi@linaro.org> X-Mailer: git-send-email 2.24.0 In-Reply-To: <20191218004512.24939-1-takahiro.akashi@linaro.org> References: <20191218004512.24939-1-takahiro.akashi@linaro.org> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.26 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: u-boot@lists.denx.de, mail@patrick-wildt.de Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.101.4 at phobos.denx.de X-Virus-Status: Clean Under this configuration, UEFI secure boot support will be added in later patches. Signed-off-by: AKASHI Takahiro --- lib/efi_loader/Kconfig | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index c7027a967653..d1c092a1d80a 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -115,4 +115,23 @@ config EFI_GRUB_ARM32_WORKAROUND GRUB prior to version 2.04 requires U-Boot to disable caches. This workaround currently is also needed on systems with caches that cannot be managed via CP15. + +config EFI_SECURE_BOOT + bool "Enable EFI secure boot support" + depends on EFI_LOADER + select SHA256 + select RSA + select RSA_VERIFY_WITH_PKEY + select IMAGE_SIGN_INFO + select ASYMMETRIC_KEY_TYPE + select ASYMMETRIC_PUBLIC_KEY_SUBTYPE + select X509_CERTIFICATE_PARSER + select PKCS7_MESSAGE_PARSER + default n + help + Select this option to enable EFI secure boot support. + Once SecureBoot mode is enforced, any EFI binary can run only if + it is signed with a trusted key. To do that, you need to install, + at least, PK, KEK and db. + endif From patchwork Wed Dec 18 00:44:59 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: AKASHI Takahiro X-Patchwork-Id: 1211836 X-Patchwork-Delegate: xypron.glpk@gmx.de Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=85.214.62.61; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=linaro.org Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.b="qxPZARO9"; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [85.214.62.61]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 47cx9N6ySJz9sRl for ; Wed, 18 Dec 2019 11:44:40 +1100 (AEDT) Received: from phobos.denx.de (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id BDCE1814FA; Wed, 18 Dec 2019 01:44:16 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=fail (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=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.b="qxPZARO9"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 9275B81610; Wed, 18 Dec 2019 01:44:14 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-0.1 required=5.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,SPF_HELO_NONE,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.2 Received: from mail-pg1-x542.google.com (mail-pg1-x542.google.com [IPv6:2607:f8b0:4864:20::542]) (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 533C0814F4 for ; Wed, 18 Dec 2019 01:44:09 +0100 (CET) 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-pg1-x542.google.com with SMTP id x8so245400pgk.8 for ; Tue, 17 Dec 2019 16:44:09 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=exaTXT/llrglfKTdfqa4YAAhSHtg49fI33ynWf5Dp2E=; b=qxPZARO9XJFO7E8Q4bDSebzKfIv3a52bxVDR8yk59nOvXPt+aI8dw3aTmUzcBSTYo7 eYkouST5deCAvyCLKiJJE+bBT8vNs/cGNxFtjrrlDidgvlvJ4IxSUXMpBRlkFxZbb7oJ rCFFIVIgshIEmLcsldoGpEYCgW7se2xdo01OIBWoBih9CNNUJSYoj/pP3NxIC/9RJ49q LZAp4gxX2DyHVwPhQTgRB1KN33hVwtlnJ/HNO4sBzHd9b/5hwr4aSF61IB+pQTNiYXbX 0hhI8y4UbAClsJdceigxuMrMAhqMfsfaVgqrg0pbXfX8tfL1GkV3Rl06riPGYPXJIsA5 5kTA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=exaTXT/llrglfKTdfqa4YAAhSHtg49fI33ynWf5Dp2E=; b=cRpt6242x/laGGTqtuyOLKssaVZ/yGl2R0F6Sc2/AYP/0+CE0xmE6k7KbFvLkK3kNC F18t9MDhUSy4MPeyHfbdMjiXP0RJg+5RAWrCQ5PsT0tNYBtif7YbnvEa3A1o4JwJL/lm zPcHkwGp8V3yRygvxZrCa7Q2w361joJgoRTADxfmRkwwB93zjq/Ej4l8XeEvxvypi6QO rWpP1XX6+HZmLcHiDoIsyxc5V8qq+KuIdXP4i6KS7fJv9sHb6DgQUf2HxVfVIsMDkOyr 21ftnD3RSXHMxX3OMiTejxlhyyMiLKe0a0heSnujiVr0UFiI7Qt4ogUzAe6SncMh3DCs A6cw== X-Gm-Message-State: APjAAAVIKpdcMzeEc63dakB9cx9C4SjWWrDhgK89wWPrYatL9DfhHryl X8OGJXcXUU2fnym0B6V8afjzww== X-Google-Smtp-Source: APXvYqwCY+qwqrW+EyH9magkfwS9eehSrEWVmcFv1viYHurIYaeDCVlor3rItt1X2AD4k6OXJ2SAAA== X-Received: by 2002:a63:130a:: with SMTP id i10mr222935pgl.199.1576629847237; Tue, 17 Dec 2019 16:44:07 -0800 (PST) Received: from linaro.org ([121.95.100.191]) by smtp.googlemail.com with ESMTPSA id x33sm187906pga.86.2019.12.17.16.44.06 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 17 Dec 2019 16:44:06 -0800 (PST) From: AKASHI Takahiro To: xypron.glpk@gmx.de, agraf@csgraf.de, trini@konsulko.com Subject: [PATCH v4 03/16] efi_loader: add signature verification functions Date: Wed, 18 Dec 2019 09:44:59 +0900 Message-Id: <20191218004512.24939-4-takahiro.akashi@linaro.org> X-Mailer: git-send-email 2.24.0 In-Reply-To: <20191218004512.24939-1-takahiro.akashi@linaro.org> References: <20191218004512.24939-1-takahiro.akashi@linaro.org> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.26 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: u-boot@lists.denx.de, mail@patrick-wildt.de Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.101.4 at phobos.denx.de X-Virus-Status: Clean In this commit, implemented are a couple of helper functions which will be used to materialize variable authentication as well as image authentication in later patches. Signed-off-by: AKASHI Takahiro --- include/efi_api.h | 87 +++++ include/efi_loader.h | 72 ++++ lib/efi_loader/Makefile | 1 + lib/efi_loader/efi_signature.c | 584 +++++++++++++++++++++++++++++++++ 4 files changed, 744 insertions(+) create mode 100644 lib/efi_loader/efi_signature.c diff --git a/include/efi_api.h b/include/efi_api.h index 22396172e15f..47f24fc90873 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -18,6 +18,7 @@ #include #include +#include #ifdef CONFIG_EFI_LOADER #include @@ -307,6 +308,10 @@ struct efi_runtime_services { EFI_GUID(0x8be4df61, 0x93ca, 0x11d2, 0xaa, 0x0d, \ 0x00, 0xe0, 0x98, 0x03, 0x2b, 0x8c) +#define EFI_IMAGE_SECURITY_DATABASE_GUID \ + EFI_GUID(0xd719b2cb, 0x3d3a, 0x4596, 0xa3, 0xbc, \ + 0xda, 0xd0, 0x0e, 0x67, 0x65, 0x6f) + #define EFI_FDT_GUID \ EFI_GUID(0xb1b621d5, 0xf19c, 0x41a5, \ 0x83, 0x0b, 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0) @@ -1616,4 +1621,86 @@ struct efi_unicode_collation_protocol { #define LOAD_OPTION_CATEGORY_BOOT 0x00000000 #define LOAD_OPTION_CATEGORY_APP 0x00000100 +/* Certificate types in signature database */ +#define EFI_CERT_SHA256_GUID \ + EFI_GUID(0xc1c41626, 0x504c, 0x4092, 0xac, 0xa9, \ + 0x41, 0xf9, 0x36, 0x93, 0x43, 0x28) +#define EFI_CERT_RSA2048_GUID \ + EFI_GUID(0x3c5766e8, 0x269c, 0x4e34, 0xaa, 0x14, \ + 0xed, 0x77, 0x6e, 0x85, 0xb3, 0xb6) +#define EFI_CERT_X509_GUID \ + EFI_GUID(0xa5c059a1, 0x94e4, 0x4aa7, 0x87, 0xb5, \ + 0xab, 0x15, 0x5c, 0x2b, 0xf0, 0x72) +#define EFI_CERT_X509_SHA256_GUID \ + EFI_GUID(0x3bd2a492, 0x96c0, 0x4079, 0xb4, 0x20, \ + 0xfc, 0xf9, 0x8e, 0xf1, 0x03, 0xed) +#define EFI_CERT_TYPE_PKCS7_GUID \ + EFI_GUID(0x4aafd29d, 0x68df, 0x49ee, 0x8a, 0xa9, \ + 0x34, 0x7d, 0x37, 0x56, 0x65, 0xa7) + +/** + * win_certificate_uefi_guid - A certificate that encapsulates + * a GUID-specific signature + * + * @hdr: Windows certificate header + * @cert_type: Certificate type + * @cert_data: Certificate data + */ +struct win_certificate_uefi_guid { + WIN_CERTIFICATE hdr; + efi_guid_t cert_type; + u8 cert_data[]; +} __attribute__((__packed__)); + +/** + * efi_variable_authentication_2 - A time-based authentication method + * descriptor + * + * This structure describes an authentication information for + * a variable with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS + * and should be included as part of a variable's value. + * Only EFI_CERT_TYPE_PKCS7_GUID is accepted. + * + * @time_stamp: Descriptor's time stamp + * @auth_info: Authentication info + */ +struct efi_variable_authentication_2 { + struct efi_time time_stamp; + struct win_certificate_uefi_guid auth_info; +} __attribute__((__packed__)); + +/** + * efi_signature_data - A format of signature + * + * This structure describes a single signature in signature database. + * + * @signature_owner: Signature owner + * @signature_data: Signature data + */ +struct efi_signature_data { + efi_guid_t signature_owner; + u8 signature_data[]; +} __attribute__((__packed__)); + +/** + * efi_signature_list - A format of signature database + * + * This structure describes a list of signatures with the same type. + * An authenticated variable's value is a concatenation of one or more + * efi_signature_list's. + * + * @signature_type: Signature type + * @signature_list_size: Size of signature list + * @signature_header_size: Size of signature header + * @signature_size: Size of signature + */ +struct efi_signature_list { + efi_guid_t signature_type; + u32 signature_list_size; + u32 signature_header_size; + u32 signature_size; +/* u8 signature_header[signature_header_size]; */ +/* struct efi_signature_data signatures[...][signature_size]; */ +} __attribute__((__packed__)); + #endif diff --git a/include/efi_loader.h b/include/efi_loader.h index 381da80cdce0..3ca68f9bbb6e 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -21,6 +21,7 @@ static inline int guidcmp(const void *g1, const void *g2) #if CONFIG_IS_ENABLED(EFI_LOADER) #include +#include /* Maximum number of configuration tables */ #define EFI_MAX_CONFIGURATION_TABLES 16 @@ -169,6 +170,11 @@ extern const efi_guid_t efi_guid_hii_config_routing_protocol; extern const efi_guid_t efi_guid_hii_config_access_protocol; extern const efi_guid_t efi_guid_hii_database_protocol; extern const efi_guid_t efi_guid_hii_string_protocol; +/* GUIDs for authentication */ +extern const efi_guid_t efi_guid_image_security_database; +extern const efi_guid_t efi_guid_sha256; +extern const efi_guid_t efi_guid_cert_x509; +extern const efi_guid_t efi_guid_cert_x509_sha256; extern unsigned int __efi_runtime_start, __efi_runtime_stop; extern unsigned int __efi_runtime_rel_start, __efi_runtime_rel_stop; @@ -650,6 +656,72 @@ void efi_deserialize_load_option(struct efi_load_option *lo, u8 *data); unsigned long efi_serialize_load_option(struct efi_load_option *lo, u8 **data); efi_status_t efi_bootmgr_load(efi_handle_t *handle); +#ifdef CONFIG_EFI_SECURE_BOOT +#include + +/** + * efi_image_regions - A list of memory regions + * + * @max: Maximum number of regions + * @num: Number of regions + * @reg: array of regions + */ +struct efi_image_regions { + int max; + int num; + struct image_region reg[]; +}; + +/** + * efi_sig_data - A decoded data of struct efi_signature_data + * + * This structure represents an internal form of signature in + * signature database. A listed list may represent a signature list. + * + * @next: Pointer to next entry + * @onwer: Signature owner + * @data: Pointer to signature data + * @size: Size of signature data + */ +struct efi_sig_data { + struct efi_sig_data *next; + efi_guid_t owner; + void *data; + size_t size; +}; + +/** + * efi_signature_store - A decoded data of signature database + * + * This structure represents an internal form of signature database. + * + * @next: Pointer to next entry + * @sig_type: Signature type + * @sig_data_list: Pointer to signature list + */ +struct efi_signature_store { + struct efi_signature_store *next; + efi_guid_t sig_type; + struct efi_sig_data *sig_data_list; +}; + +struct x509_certificate; +struct pkcs7_message; + +bool efi_signature_verify_cert(struct x509_certificate *cert, + struct efi_signature_store *dbx); +bool efi_signature_verify_signers(struct pkcs7_message *msg, + struct efi_signature_store *dbx); +bool efi_signature_verify_with_sigdb(struct efi_image_regions *regs, + struct pkcs7_message *msg, + struct efi_signature_store *db, + struct x509_certificate **cert); + +efi_status_t efi_image_region_add(struct efi_image_regions *regs, + const void *start, const void *end, + int nocheck); +#endif /* CONFIG_EFI_SECURE_BOOT */ + #else /* CONFIG_IS_ENABLED(EFI_LOADER) */ /* Without CONFIG_EFI_LOADER we don't have a runtime section, stub it out */ diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index 7db406028618..3ffbfe78a46b 100644 --- a/lib/efi_loader/Makefile +++ b/lib/efi_loader/Makefile @@ -42,3 +42,4 @@ obj-$(CONFIG_PARTITIONS) += efi_disk.o obj-$(CONFIG_NET) += efi_net.o obj-$(CONFIG_GENERATE_ACPI_TABLE) += efi_acpi.o obj-$(CONFIG_GENERATE_SMBIOS_TABLE) += efi_smbios.o +obj-y += efi_signature.o diff --git a/lib/efi_loader/efi_signature.c b/lib/efi_loader/efi_signature.c new file mode 100644 index 000000000000..823d3311e010 --- /dev/null +++ b/lib/efi_loader/efi_signature.c @@ -0,0 +1,584 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2018 Patrick Wildt + * Copyright (c) 2019 Linaro Limited, Author: AKASHI Takahiro + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +/* + * avoid duplicated inclusion: + * #include "../lib/crypto/x509_parser.h" + */ +#include "../lib/crypto/pkcs7_parser.h" + +const efi_guid_t efi_guid_image_security_database = + EFI_IMAGE_SECURITY_DATABASE_GUID; +const efi_guid_t efi_guid_sha256 = EFI_CERT_SHA256_GUID; +const efi_guid_t efi_guid_cert_rsa2048 = EFI_CERT_RSA2048_GUID; +const efi_guid_t efi_guid_cert_x509 = EFI_CERT_X509_GUID; +const efi_guid_t efi_guid_cert_x509_sha256 = EFI_CERT_X509_SHA256_GUID; + +#ifdef CONFIG_EFI_SECURE_BOOT + +/** + * efi_hash_regions - calculate a hash value + * @regs: List of regions + * @hash: Pointer to a pointer to buffer holding a hash value + * @size: Size of buffer to be returned + * + * Calculate a sha256 value of @regs and return a value in @hash. + * + * Return: true on success, false on error + */ +static bool efi_hash_regions(struct efi_image_regions *regs, void **hash, + size_t *size) +{ + *size = 0; + *hash = calloc(1, SHA256_SUM_LEN); + if (!*hash) { + debug("Out of memory\n"); + return false; + } + *size = SHA256_SUM_LEN; + + hash_calculate("sha256", regs->reg, regs->num, *hash); +#ifdef DEBUG + debug("hash calculated:\n"); + print_hex_dump(" ", DUMP_PREFIX_OFFSET, 16, 1, + *hash, SHA256_SUM_LEN, false); +#endif + + return true; +} + +/** + * efi_hash_msg_content - calculate a hash value of contentInfo + * @msg: Signature + * @hash: Pointer to a pointer to buffer holding a hash value + * @size: Size of buffer to be returned + * + * Calculate a sha256 value of contentInfo in @msg and return a value in @hash. + * + * Return: true on success, false on error + */ +static bool efi_hash_msg_content(struct pkcs7_message *msg, void **hash, + size_t *size) +{ + struct image_region regtmp; + + *size = 0; + *hash = calloc(1, SHA256_SUM_LEN); + if (!*hash) { + debug("Out of memory\n"); + free(msg); + return false; + } + *size = SHA256_SUM_LEN; + + regtmp.data = msg->data; + regtmp.size = msg->data_len; + + hash_calculate("sha256", ®tmp, 1, *hash); +#ifdef DEBUG + debug("hash calculated based on contentInfo:\n"); + print_hex_dump(" ", DUMP_PREFIX_OFFSET, 16, 1, + *hash, SHA256_SUM_LEN, false); +#endif + + return true; +} + +/** + * efi_signature_verify - verify a signature with a certificate + * @regs: List of regions to be authenticated + * @signed_info: Pointer to PKCS7's signed_info + * @cert: x509 certificate + * + * Signature pointed to by @signed_info against image pointed to by @regs + * is verified by a certificate pointed to by @cert. + * @signed_info holds a signature, including a message digest which is to be + * compared with a hash value calculated from @regs. + * + * Return: true if signature is verified, false if not + */ +static bool efi_signature_verify(struct efi_image_regions *regs, + struct pkcs7_message *msg, + struct pkcs7_signed_info *ps_info, + struct x509_certificate *cert) +{ + struct image_sign_info info; + struct image_region regtmp[2]; + void *hash; + size_t size; + char c; + bool verified; + + debug("%s: Enter, %p, %p, %p(issuer: %s, subject: %s)\n", __func__, + regs, ps_info, cert, cert->issuer, cert->subject); + + verified = false; + + memset(&info, '\0', sizeof(info)); + info.padding = image_get_padding_algo("pkcs-1.5"); + /* + * Note: image_get_[checksum|crypto]_algo takes an string + * argument like "," + * TODO: support other hash algorithms + */ + if (!strcmp(ps_info->sig->hash_algo, "sha1")) { + info.checksum = image_get_checksum_algo("sha1,rsa2048"); + info.name = "sha1,rsa2048"; + } else if (!strcmp(ps_info->sig->hash_algo, "sha256")) { + info.checksum = image_get_checksum_algo("sha256,rsa2048"); + info.name = "sha256,rsa2048"; + } else { + debug("unknown msg digest algo: %s\n", ps_info->sig->hash_algo); + goto out; + } + info.crypto = image_get_crypto_algo(info.name); + + info.key = cert->pub->key; + info.keylen = cert->pub->keylen; + + /* verify signature */ + debug("%s: crypto: %s, signature len:%x\n", __func__, + info.name, ps_info->sig->s_size); + if (ps_info->aa_set & (1UL << sinfo_has_message_digest)) { + debug("%s: RSA verify authentication attribute\n", __func__); + /* + * NOTE: This path will be executed only for + * PE image authentication + */ + + /* check if hash matches digest first */ + debug("checking msg digest first, len:0x%x\n", + ps_info->msgdigest_len); + +#ifdef DEBUG + debug("hash in database:\n"); + print_hex_dump(" ", DUMP_PREFIX_OFFSET, 16, 1, + ps_info->msgdigest, ps_info->msgdigest_len, + false); +#endif + /* against contentInfo first */ + if ((msg->data && efi_hash_msg_content(msg, &hash, &size)) || + /* for signed image */ + efi_hash_regions(regs, &hash, &size)) { + /* for authenticated variable */ + if (ps_info->msgdigest_len != size || + memcmp(hash, ps_info->msgdigest, size)) { + debug("Digest doesn't match\n"); + free(hash); + goto out; + } + + free(hash); + } else { + debug("Digesting image failed\n"); + goto out; + } + + /* against digest */ + c = 0x31; + regtmp[0].data = &c; + regtmp[0].size = 1; + regtmp[1].data = ps_info->authattrs; + regtmp[1].size = ps_info->authattrs_len; + + if (!rsa_verify(&info, regtmp, 2, + ps_info->sig->s, ps_info->sig->s_size)) + verified = true; + } else { + debug("%s: RSA verify content data\n", __func__); + /* against all data */ + if (!rsa_verify(&info, regs->reg, regs->num, + ps_info->sig->s, ps_info->sig->s_size)) + verified = true; + } + +out: + debug("%s: Exit, verified: %d\n", __func__, verified); + return verified; +} + +/** + * efi_signature_verify_with_list - verify a signature with signature list + * @regs: List of regions to be authenticated + * @msg: Signature + * @signed_info: Pointer to PKCS7's signed_info + * @siglist: Signature list for certificates + * @valid_cert: x509 certificate that verifies this signature + * + * Signature pointed to by @signed_info against image pointed to by @regs + * is verified by signature list pointed to by @siglist. + * Signature database is a simple concatenation of one or more + * signature list(s). + * + * Return: true if signature is verified, false if not + */ +static +bool efi_signature_verify_with_list(struct efi_image_regions *regs, + struct pkcs7_message *msg, + struct pkcs7_signed_info *signed_info, + struct efi_signature_store *siglist, + struct x509_certificate **valid_cert) +{ + struct x509_certificate *cert; + struct efi_sig_data *sig_data; + bool verified = false; + + debug("%s: Enter, %p, %p, %p, %p\n", __func__, + regs, signed_info, siglist, valid_cert); + + if (!signed_info) { + void *hash; + size_t size; + + debug("%s: unsigned image\n", __func__); + /* + * verify based on calculated hash value + * TODO: support other hash algorithms + */ + if (guidcmp(&siglist->sig_type, &efi_guid_sha256)) { + debug("Digest algorithm is not supported: %pUl\n", + &siglist->sig_type); + goto out; + } + + if (!efi_hash_regions(regs, &hash, &size)) { + debug("Digesting unsigned image failed\n"); + goto out; + } + + /* go through the list */ + for (sig_data = siglist->sig_data_list; sig_data; + sig_data = sig_data->next) { +#ifdef DEBUG + debug("Msg digest in database:\n"); + print_hex_dump(" ", DUMP_PREFIX_OFFSET, 16, 1, + sig_data->data, sig_data->size, false); +#endif + if ((sig_data->size == size) && + !memcmp(sig_data->data, hash, size)) { + verified = true; + free(hash); + goto out; + } + } + free(hash); + goto out; + } + + debug("%s: signed image\n", __func__); + if (guidcmp(&siglist->sig_type, &efi_guid_cert_x509)) { + debug("Signature type is not supported: %pUl\n", + &siglist->sig_type); + goto out; + } + + /* go through the list */ + for (sig_data = siglist->sig_data_list; sig_data; + sig_data = sig_data->next) { + /* TODO: support owner check based on policy */ + + cert = x509_cert_parse(sig_data->data, sig_data->size); + if (IS_ERR(cert)) { + debug("Parsing x509 certificate failed\n"); + goto out; + } + + verified = efi_signature_verify(regs, msg, signed_info, cert); + + if (verified) { + if (valid_cert) + *valid_cert = cert; + else + x509_free_certificate(cert); + break; + } else { + x509_free_certificate(cert); + } + } + +out: + debug("%s: Exit, verified: %d\n", __func__, verified); + return verified; +} + +/** + * efi_signature_verify_with_sigdb - verify a signature with db + * @regs: List of regions to be authenticated + * @msg: Signature + * @db: Signature database for trusted certificates + * @cert: x509 certificate that verifies this signature + * + * Signature pointed to by @msg against image pointed to by @regs + * is verified by signature database pointed to by @db. + * + * Return: true if signature is verified, false if not + */ +bool efi_signature_verify_with_sigdb(struct efi_image_regions *regs, + struct pkcs7_message *msg, + struct efi_signature_store *db, + struct x509_certificate **cert) +{ + struct pkcs7_signed_info *info; + struct efi_signature_store *siglist; + bool verified = false; + + debug("%s: Enter, %p, %p, %p, %p\n", __func__, regs, msg, db, cert); + + if (!db) + goto out; + + if (!db->sig_data_list) + goto out; + + /* for unsigned image */ + if (!msg) { + debug("%s: Verify unsigned image with db\n", __func__); + for (siglist = db; siglist; siglist = siglist->next) + if (efi_signature_verify_with_list(regs, NULL, NULL, + siglist, cert)) { + verified = true; + goto out; + } + + goto out; + } + + /* for signed image or variable */ + debug("%s: Verify signed image with db\n", __func__); + for (info = msg->signed_infos; info; info = info->next) { + debug("Signed Info: digest algo: %s, pkey algo: %s\n", + info->sig->hash_algo, info->sig->pkey_algo); + + for (siglist = db; siglist; siglist = siglist->next) { + if (efi_signature_verify_with_list(regs, msg, info, + siglist, cert)) { + verified = true; + goto out; + } + } + } + +out: + debug("%s: Exit, verified: %d\n", __func__, verified); + return verified; +} + +/** + * efi_search_siglist - search signature list for a certificate + * @cert: x509 certificate + * @siglist: Signature list + * @revoc_time: Pointer to buffer for revocation time + * + * Search signature list pointed to by @siglist and find a certificate + * pointed to by @cert. + * If found, revocation time that is specified in signature database is + * returned in @revoc_time. + * + * Return: true if certificate is found, false if not + */ +static bool efi_search_siglist(struct x509_certificate *cert, + struct efi_signature_store *siglist, + time64_t *revoc_time) +{ + struct image_region reg[1]; + void *hash = NULL, *msg = NULL; + struct efi_sig_data *sig_data; + bool found = false; + + /* can be null */ + if (!siglist->sig_data_list) + return false; + + if (guidcmp(&siglist->sig_type, &efi_guid_cert_x509_sha256)) { + /* TODO: other hash algos */ + debug("Certificate's digest type is not supported: %pUl\n", + &siglist->sig_type); + goto out; + } + + /* calculate hash of TBSCertificate */ + msg = calloc(1, SHA256_SUM_LEN); + if (!msg) { + debug("Out of memory\n"); + goto out; + } + + hash = calloc(1, SHA256_SUM_LEN); + if (!hash) { + debug("Out of memory\n"); + goto out; + } + + reg[0].data = cert->tbs; + reg[0].size = cert->tbs_size; + hash_calculate("sha256", reg, 1, msg); + + /* go through signature list */ + for (sig_data = siglist->sig_data_list; sig_data; + sig_data = sig_data->next) { + /* + * struct efi_cert_x509_sha256 { + * u8 tbs_hash[256/8]; + * time64_t revocation_time; + * }; + */ + if ((sig_data->size == SHA256_SUM_LEN) && + !memcmp(sig_data->data, hash, SHA256_SUM_LEN)) { + memcpy(revoc_time, sig_data->data + SHA256_SUM_LEN, + sizeof(*revoc_time)); + found = true; + goto out; + } + } + +out: + free(hash); + free(msg); + + return found; +} + +/** + * efi_signature_verify_cert - verify a certificate with dbx + * @cert: x509 certificate + * @dbx: Signature database + * + * Search signature database pointed to by @dbx and find a certificate + * pointed to by @cert. + * This function is expected to be used against "dbx". + * + * Return: true if a certificate is not rejected, false otherwise. + */ +bool efi_signature_verify_cert(struct x509_certificate *cert, + struct efi_signature_store *dbx) +{ + struct efi_signature_store *siglist; + time64_t revoc_time; + bool found = false; + + debug("%s: Enter, %p, %p\n", __func__, dbx, cert); + + if (!cert) + return false; + + for (siglist = dbx; siglist; siglist = siglist->next) { + if (efi_search_siglist(cert, siglist, &revoc_time)) { + /* TODO */ + /* compare signing time with revocation time */ + + found = true; + break; + } + } + + debug("%s: Exit, verified: %d\n", __func__, !found); + return !found; +} + +/** + * efi_signature_verify_signers - verify signers' certificates with dbx + * @msg: Signature + * @dbx: Signature database + * + * Determine if any of signers' certificates in @msg may be verified + * by any of certificates in signature database pointed to by @dbx. + * This function is expected to be used against "dbx". + * + * Return: true if none of certificates is rejected, false otherwise. + */ +bool efi_signature_verify_signers(struct pkcs7_message *msg, + struct efi_signature_store *dbx) +{ + struct pkcs7_signed_info *info; + bool found = false; + + debug("%s: Enter, %p, %p\n", __func__, msg, dbx); + + if (!msg) + goto out; + + for (info = msg->signed_infos; info; info = info->next) { + if (info->signer && + !efi_signature_verify_cert(info->signer, dbx)) { + found = true; + goto out; + } + } +out: + debug("%s: Exit, verified: %d\n", __func__, !found); + return !found; +} + +/** + * efi_image_region_add - add an entry of region + * @regs: Pointer to array of regions + * @start: Start address of region + * @end: End address of region + * @nocheck: flag against overlapped regions + * + * Take one entry of region [@start, @end] and append it to the list + * pointed to by @regs. If @nocheck is false, overlapping among entries + * will be checked first. + * + * Return: 0 on success, status code (negative) on error + */ +efi_status_t efi_image_region_add(struct efi_image_regions *regs, + const void *start, const void *end, + int nocheck) +{ + struct image_region *reg; + int i, j; + + if (regs->num >= regs->max) { + debug("%s: no more room for regions\n", __func__); + return EFI_OUT_OF_RESOURCES; + } + + if (end < start) + return EFI_INVALID_PARAMETER; + + for (i = 0; i < regs->num; i++) { + reg = ®s->reg[i]; + if (nocheck) + continue; + + if (start > reg->data + reg->size) + continue; + + if ((start >= reg->data && start < reg->data + reg->size) || + (end > reg->data && end < reg->data + reg->size)) { + debug("%s: new region already part of another\n", + __func__); + return EFI_INVALID_PARAMETER; + } + + if (start < reg->data && end < reg->data + reg->size) { + for (j = regs->num - 1; j >= i; j--) + memcpy(®s->reg[j], ®s->reg[j + 1], + sizeof(*reg)); + break; + } + } + + reg = ®s->reg[i]; + reg->data = start; + reg->size = end - start; + regs->num++; + + return EFI_SUCCESS; +} +#endif /* CONFIG_EFI_SECURE_BOOT */ From patchwork Wed Dec 18 00:45:00 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: AKASHI Takahiro X-Patchwork-Id: 1211837 X-Patchwork-Delegate: xypron.glpk@gmx.de Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=85.214.62.61; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=linaro.org Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.b="MICOey1F"; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [85.214.62.61]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 47cx9f3CW0z9sRl for ; Wed, 18 Dec 2019 11:44:54 +1100 (AEDT) Received: from phobos.denx.de (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id D5BD68163F; Wed, 18 Dec 2019 01:44:19 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=fail (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=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.b="MICOey1F"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 3188281610; Wed, 18 Dec 2019 01:44:16 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-0.1 required=5.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,SPF_HELO_NONE,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.2 Received: from mail-pj1-x1029.google.com (mail-pj1-x1029.google.com [IPv6:2607:f8b0:4864:20::1029]) (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 0C86C814FA for ; Wed, 18 Dec 2019 01:44:12 +0100 (CET) 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-pj1-x1029.google.com with SMTP id s94so536381pjc.1 for ; Tue, 17 Dec 2019 16:44:11 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=cIF27sd4xiLTvNRb+s6NDpkCVuSu7t5+mMB61a4BJXI=; b=MICOey1FuaB2r//mZ0SOuDzz4ODKgP7d4Hjg10xbwSXCqH78G2c0APOwIBOd+J81kR hqC9GNEs6Yj3RV0XQLnBFMAYyneoBLCC5zUspIpDfgaZkZuJK/LUkTFSN5DJWXD6aFE4 BYvOQN96mKnKr5WZMIkeg0vn59hg7IV5WyfIq9AidQMc1RyZbmFfx3aXvy6GlbztnT3K bzRUTMoV7BUcX18z/Ul0TYRBtim+08z0zlSsCIMdY64AZuXs5w7YpX9+JkTGYdGf6XGd qaWGwCVX2elRlQM7tgedC9X52nPf8OnfL7f7+PlTWs+Y2OHJORB4zc+JU3dxJhwuaw2D tJww== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=cIF27sd4xiLTvNRb+s6NDpkCVuSu7t5+mMB61a4BJXI=; b=sH159v3tADs87e+Naagw1KR0888B/N6mNU7Jb6MDaK3HBJO3AbUacEHXd2ve4tDCSW Hu0cRuYP8irsgr5UGR4M0l10nY9KbIbb0x5lO3Wn3m1KqKXIfOhkR02+9ibMEkKzpzOs 6iOxvE8wTGhUS4uaE6tCHuC3DfXOXe5YKrj9BcObAfiowj1BYFCLSLPEin4xAk5tITxG i3zy1m+nH9Rh73T1w8BTEuB1MqZL1Ze2Y7SxC54LkfUlFgoOqMi27sLZjmSxzjj+sKu7 Kog5bHOEWsWVr5VXtLuqIbPhr8dkRHBKOFqHvvte057f6seGVUa1tPnReT/762zCog1Q bAOg== X-Gm-Message-State: APjAAAVdKhF31uYPZIhQMvbXc3VWOo5SmMcY1SyE4haUHuByj6BLaxpD jgPjiZTbC61ql0Nyf9NN4+Jdjw== X-Google-Smtp-Source: APXvYqwruxg5bo7PTI+geqShWGjy1SFaYcTBFmouSUEOmWQ1n9Krlrt6+k9t08aDHQtkzVqZ47P8Og== X-Received: by 2002:a17:90a:22e7:: with SMTP id s94mr235571pjc.12.1576629850528; Tue, 17 Dec 2019 16:44:10 -0800 (PST) Received: from linaro.org ([121.95.100.191]) by smtp.googlemail.com with ESMTPSA id q9sm135148pjb.27.2019.12.17.16.44.09 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 17 Dec 2019 16:44:09 -0800 (PST) From: AKASHI Takahiro To: xypron.glpk@gmx.de, agraf@csgraf.de, trini@konsulko.com Subject: [PATCH v4 04/16] efi_loader: add signature database parser Date: Wed, 18 Dec 2019 09:45:00 +0900 Message-Id: <20191218004512.24939-5-takahiro.akashi@linaro.org> X-Mailer: git-send-email 2.24.0 In-Reply-To: <20191218004512.24939-1-takahiro.akashi@linaro.org> References: <20191218004512.24939-1-takahiro.akashi@linaro.org> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.26 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: u-boot@lists.denx.de, mail@patrick-wildt.de Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.101.4 at phobos.denx.de X-Virus-Status: Clean efi_signature_parse_sigdb() is a helper function will be used to parse signature database variable and instantiate a signature store structure in later patches. Signed-off-by: AKASHI Takahiro --- include/efi_loader.h | 3 + lib/efi_loader/efi_signature.c | 226 +++++++++++++++++++++++++++++++++ 2 files changed, 229 insertions(+) diff --git a/include/efi_loader.h b/include/efi_loader.h index 3ca68f9bbb6e..3b3618e0be24 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -720,6 +720,9 @@ bool efi_signature_verify_with_sigdb(struct efi_image_regions *regs, efi_status_t efi_image_region_add(struct efi_image_regions *regs, const void *start, const void *end, int nocheck); + +void efi_sigstore_free(struct efi_signature_store *sigstore); +struct efi_signature_store *efi_sigstore_parse_sigdb(u16 *name); #endif /* CONFIG_EFI_SECURE_BOOT */ #else /* CONFIG_IS_ENABLED(EFI_LOADER) */ diff --git a/lib/efi_loader/efi_signature.c b/lib/efi_loader/efi_signature.c index 823d3311e010..98302e1ab3d3 100644 --- a/lib/efi_loader/efi_signature.c +++ b/lib/efi_loader/efi_signature.c @@ -581,4 +581,230 @@ efi_status_t efi_image_region_add(struct efi_image_regions *regs, return EFI_SUCCESS; } + +/** + * efi_sigstore_free - free signature store + * @sigstore: Pointer to signature store structure + * + * Feee all the memories held in signature store and itself, + * which were allocated by efi_sigstore_parse_sigdb(). + */ +void efi_sigstore_free(struct efi_signature_store *sigstore) +{ + struct efi_signature_store *sigstore_next; + struct efi_sig_data *sig_data, *sig_data_next; + + while (sigstore) { + sigstore_next = sigstore->next; + + sig_data = sigstore->sig_data_list; + while (sig_data) { + sig_data_next = sig_data->next; + free(sig_data->data); + free(sig_data); + sig_data = sig_data_next; + } + + free(sigstore); + sigstore = sigstore_next; + } +} + +/** + * efi_sigstore_parse_siglist - parse a signature list + * @name: Pointer to signature list + * + * Parse signature list and instantiate a signature store structure. + * Signature database is a simple concatenation of one or more + * signature list(s). + * + * Return: Pointer to signature store on success, NULL on error + */ +static struct efi_signature_store * +efi_sigstore_parse_siglist(struct efi_signature_list *esl) +{ + struct efi_signature_store *siglist = NULL; + struct efi_sig_data *sig_data, *sig_data_next; + struct efi_signature_data *esd; + size_t left; + + /* + * UEFI specification defines certificate types: + * for non-signed images, + * EFI_CERT_SHA256_GUID + * EFI_CERT_RSA2048_GUID + * EFI_CERT_RSA2048_SHA256_GUID + * EFI_CERT_SHA1_GUID + * EFI_CERT_RSA2048_SHA_GUID + * EFI_CERT_SHA224_GUID + * EFI_CERT_SHA384_GUID + * EFI_CERT_SHA512_GUID + * + * for signed images, + * EFI_CERT_X509_GUID + * NOTE: Each certificate will normally be in a separate + * EFI_SIGNATURE_LIST as the size may vary depending on + * its algo's. + * + * for timestamp revocation of certificate, + * EFI_CERT_X509_SHA512_GUID + * EFI_CERT_X509_SHA256_GUID + * EFI_CERT_X509_SHA384_GUID + */ + + if (esl->signature_list_size + <= (sizeof(*esl) + esl->signature_header_size)) { + debug("Siglist in wrong format\n"); + return NULL; + } + + /* Create a head */ + siglist = calloc(sizeof(*siglist), 1); + if (!siglist) { + debug("Out of memory\n"); + goto err; + } + memcpy(&siglist->sig_type, &esl->signature_type, sizeof(efi_guid_t)); + + /* Go through the list */ + sig_data_next = NULL; + left = esl->signature_list_size + - (sizeof(*esl) + esl->signature_header_size); + esd = (struct efi_signature_data *) + ((u8 *)esl + sizeof(*esl) + esl->signature_header_size); + + while ((left > 0) && left >= esl->signature_size) { + /* Signature must exist if there is remaining data. */ + if (left < esl->signature_size) { + debug("Certificate is too small\n"); + goto err; + } + + sig_data = calloc(esl->signature_size + - sizeof(esd->signature_owner), 1); + if (!sig_data) { + debug("Out of memory\n"); + goto err; + } + + /* Append signature data */ + memcpy(&sig_data->owner, &esd->signature_owner, + sizeof(efi_guid_t)); + sig_data->size = esl->signature_size + - sizeof(esd->signature_owner); + sig_data->data = malloc(sig_data->size); + if (!sig_data->data) { + debug("Out of memory\n"); + goto err; + } + memcpy(sig_data->data, esd->signature_data, sig_data->size); + + sig_data->next = sig_data_next; + sig_data_next = sig_data; + + /* Next */ + esd = (struct efi_signature_data *) + ((u8 *)esd + esl->signature_size); + left -= esl->signature_size; + } + siglist->sig_data_list = sig_data_next; + + return siglist; + +err: + efi_sigstore_free(siglist); + + return NULL; +} + +/** + * efi_sigstore_parse_sigdb - parse a signature database variable + * @name: Variable's name + * + * Read in a value of signature database variable pointed to by + * @name, parse it and instantiate a signature store structure. + * + * Return: Pointer to signature store on success, NULL on error + */ +struct efi_signature_store *efi_sigstore_parse_sigdb(u16 *name) +{ + struct efi_signature_store *sigstore = NULL, *siglist; + struct efi_signature_list *esl; + const efi_guid_t *vendor; + void *db; + efi_uintn_t db_size; + efi_status_t ret; + + if (!u16_strcmp(name, L"PK") || !u16_strcmp(name, L"KEK")) { + vendor = &efi_global_variable_guid; + } else if (!u16_strcmp(name, L"db") || !u16_strcmp(name, L"dbx")) { + vendor = &efi_guid_image_security_database; + } else { + debug("unknown signature database, %ls\n", name); + return NULL; + } + + /* retrieve variable data */ + db_size = 0; + ret = EFI_CALL(efi_get_variable(name, vendor, NULL, &db_size, NULL)); + if (ret == EFI_NOT_FOUND) { + debug("variable, %ls, not found\n", name); + sigstore = calloc(sizeof(*sigstore), 1); + return sigstore; + } else if (ret != EFI_BUFFER_TOO_SMALL) { + debug("Getting variable, %ls, failed\n", name); + return NULL; + } + + db = malloc(db_size); + if (!db) { + debug("Out of memory\n"); + return NULL; + } + + ret = EFI_CALL(efi_get_variable(name, vendor, NULL, &db_size, db)); + if (ret != EFI_SUCCESS) { + debug("Getting variable, %ls, failed\n", name); + goto err; + } + + /* Parse siglist list */ + esl = db; + while (db_size > 0) { + /* List must exist if there is remaining data. */ + if (db_size < sizeof(*esl)) { + debug("variable, %ls, in wrong format\n", name); + goto err; + } + + if (db_size < esl->signature_list_size) { + debug("variable, %ls, in wrong format\n", name); + goto err; + } + + /* Parse a single siglist. */ + siglist = efi_sigstore_parse_siglist(esl); + if (!siglist) { + debug("Parsing signature list of %ls failed\n", name); + goto err; + } + + /* Append siglist */ + siglist->next = sigstore; + sigstore = siglist; + + /* Next */ + db_size -= esl->signature_list_size; + esl = (void *)esl + esl->signature_list_size; + } + free(db); + + return sigstore; + +err: + efi_sigstore_free(sigstore); + free(db); + + return NULL; +} #endif /* CONFIG_EFI_SECURE_BOOT */ From patchwork Wed Dec 18 00:45:01 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: AKASHI Takahiro X-Patchwork-Id: 1211838 X-Patchwork-Delegate: xypron.glpk@gmx.de Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=85.214.62.61; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=linaro.org Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.b="H7wuv6is"; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [85.214.62.61]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 47cx9v3wF4z9sRl for ; Wed, 18 Dec 2019 11:45:07 +1100 (AEDT) Received: from phobos.denx.de (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 7324081638; Wed, 18 Dec 2019 01:44:25 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=fail (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=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.b="H7wuv6is"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id DA14581656; Wed, 18 Dec 2019 01:44:20 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-0.1 required=5.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,SPF_HELO_NONE,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.2 Received: from mail-pg1-x544.google.com (mail-pg1-x544.google.com [IPv6:2607:f8b0:4864:20::544]) (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 CE0A2815EE for ; Wed, 18 Dec 2019 01:44:15 +0100 (CET) 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-pg1-x544.google.com with SMTP id k197so239519pga.10 for ; Tue, 17 Dec 2019 16:44:15 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=RcA8kSgHlYSeLPtQEmuEGIk3aj3B4fFpB0Kuyn7vvQk=; b=H7wuv6isRT7TrTDuqkTPsArUPwY/6infjF4b9CA0ZWUuI7x3UVCzy8IKNam7vIo29g CsEF6sk1k/FB86zdHMRIxl0EKpzp8wLOGlhM4KF3AGFNz12M753m/mGZ/+9Za7fEMoop 1UVwYIVHVRxTvs9jtOQpSpYDjtKwzVHGND3oArkTzA5T0rT8sduueOz5AzfDJc/s+HqH 7MImz3NIeGbnDfkaL7T6HCNwAbjMkYeGiwhPr07x4ju04Tv4BQYLFUvzLvzlR4lpn3u0 0M2vNp7HcmtWlf78OAG/kRVYiUMP5Z9/VyRwKYHRbUnAHnyHKl74PycdXVuVU72yYhaK PaiA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=RcA8kSgHlYSeLPtQEmuEGIk3aj3B4fFpB0Kuyn7vvQk=; b=A9ChILky3oHLwpTGh9/I1TJgLuRFA2ZqrGeC7LuDdsG8MjlGY4U7WQDP8Qbot0Qqoe MW4sGLJ3ix6neARvQA9WjPVTxJKoVK4SQFTcK3prlCi91Y0Cnj6hkKJIjM8zTgowdYGe 5EMdFLH2vnlEY0d+Bax5uTZAnHfnuYVICAmeMkDY2oyEB0yVuycjZJ1FKtd7nRyW5jrN 8qJfQsONaIT/v7dfl31iUBf3x4FYtbuAd3J9Xd6frIKwZdCH3pqHsIqJeUQGXpGJhMv4 OHEf9jdttC7GWVSb5NnIecCvlSZ1KbFIbMZFD235qEuy7jbLyQuJwb2gwl2fEXv1O/Ss +ziQ== X-Gm-Message-State: APjAAAU+8DmyRiu6rxgdThJ6kCh1ioV+6DI4qvDZoTwB0JXoqeFDPd7D 4n+x1u2kAwuUag0JJFTH/UB1UQ== X-Google-Smtp-Source: APXvYqyeiS1cUNagRJNiH514eVCkL5VOfSSpza10+qG5gIwin7gU85NK4cKvWZJwCuFs+R6FL48xeQ== X-Received: by 2002:a65:68ca:: with SMTP id k10mr849414pgt.222.1576629853726; Tue, 17 Dec 2019 16:44:13 -0800 (PST) Received: from linaro.org ([121.95.100.191]) by smtp.googlemail.com with ESMTPSA id x33sm188092pga.86.2019.12.17.16.44.12 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 17 Dec 2019 16:44:13 -0800 (PST) From: AKASHI Takahiro To: xypron.glpk@gmx.de, agraf@csgraf.de, trini@konsulko.com Subject: [PATCH v4 05/16] efi_loader: variable: support variable authentication Date: Wed, 18 Dec 2019 09:45:01 +0900 Message-Id: <20191218004512.24939-6-takahiro.akashi@linaro.org> X-Mailer: git-send-email 2.24.0 In-Reply-To: <20191218004512.24939-1-takahiro.akashi@linaro.org> References: <20191218004512.24939-1-takahiro.akashi@linaro.org> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.26 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: u-boot@lists.denx.de, mail@patrick-wildt.de Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.101.4 at phobos.denx.de X-Virus-Status: Clean With this commit, EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS is supported for authenticated variables and the system secure state will transfer between setup mode and user mode as UEFI specification section 32.3 describes. Internally, authentication data is stored as part of authenticated variable's value. It is nothing but a pkcs7 message (but we need some wrapper, see efi_variable_parse_signature()) and will be validated by efi_variable_authenticate(), hence efi_signature_verify_with_db(). Associated time value will be encoded in "{...,time=...}" along with other UEFI variable's attributes. Signed-off-by: AKASHI Takahiro --- include/efi_loader.h | 3 + lib/efi_loader/efi_variable.c | 665 ++++++++++++++++++++++++++++------ 2 files changed, 564 insertions(+), 104 deletions(-) diff --git a/include/efi_loader.h b/include/efi_loader.h index 3b3618e0be24..1f88caf86709 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -175,6 +175,7 @@ extern const efi_guid_t efi_guid_image_security_database; extern const efi_guid_t efi_guid_sha256; extern const efi_guid_t efi_guid_cert_x509; extern const efi_guid_t efi_guid_cert_x509_sha256; +extern const efi_guid_t efi_guid_cert_type_pkcs7; extern unsigned int __efi_runtime_start, __efi_runtime_stop; extern unsigned int __efi_runtime_rel_start, __efi_runtime_rel_stop; @@ -723,6 +724,8 @@ efi_status_t efi_image_region_add(struct efi_image_regions *regs, void efi_sigstore_free(struct efi_signature_store *sigstore); struct efi_signature_store *efi_sigstore_parse_sigdb(u16 *name); + +bool efi_secure_boot_enabled(void); #endif /* CONFIG_EFI_SECURE_BOOT */ #else /* CONFIG_IS_ENABLED(EFI_LOADER) */ diff --git a/lib/efi_loader/efi_variable.c b/lib/efi_loader/efi_variable.c index 46f35bc60ba0..171b4abb4c58 100644 --- a/lib/efi_loader/efi_variable.c +++ b/lib/efi_loader/efi_variable.c @@ -10,7 +10,13 @@ #include #include #include +#include #include +#include +#include "../lib/crypto/pkcs7_parser.h" + +const efi_guid_t efi_guid_cert_type_pkcs7 = EFI_CERT_TYPE_PKCS7_GUID; +static bool efi_secure_boot; #define READ_ONLY BIT(31) @@ -107,7 +113,7 @@ static const char *prefix(const char *str, const char *prefix) * @attrp: pointer to UEFI attributes * Return: pointer to remainder of U-Boot variable value */ -static const char *parse_attr(const char *str, u32 *attrp) +static const char *parse_attr(const char *str, u32 *attrp, u64 *timep) { u32 attr = 0; char sep = '{'; @@ -130,6 +136,12 @@ static const char *parse_attr(const char *str, u32 *attrp) attr |= EFI_VARIABLE_BOOTSERVICE_ACCESS; } else if ((s = prefix(str, "run"))) { attr |= EFI_VARIABLE_RUNTIME_ACCESS; + } else if ((s = prefix(str, "time="))) { + attr |= EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS; + hex2bin((u8 *)timep, s, sizeof(*timep)); + s += sizeof(*timep) * 2; + } else if (*str == '}') { + break; } else { printf("invalid attribute: %s\n", str); break; @@ -147,48 +159,291 @@ static const char *parse_attr(const char *str, u32 *attrp) } /** - * efi_get_variable() - retrieve value of a UEFI variable + * efi_secure_boot_enabled - return if secure boot is enabled or not * - * This function implements the GetVariable runtime service. + * Return: true if enabled, false if disabled + */ +bool efi_secure_boot_enabled(void) +{ + return efi_secure_boot; +} + +#ifdef CONFIG_EFI_SECURE_BOOT +static u8 pkcs7_hdr[] = { + /* SEQUENCE */ + 0x30, 0x82, 0x05, 0xc7, + /* OID: pkcs7-signedData */ + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, + /* Context Structured? */ + 0xa0, 0x82, 0x05, 0xb8, +}; + +/** + * efi_variable_parse_signature - parse a signature in variable + * @buf: Pointer to variable's value + * @buflen: Length of @buf * - * See the Unified Extensible Firmware Interface (UEFI) specification for - * details. + * Parse a signature embedded in variable's value and instantiate + * a pkcs7_message structure. Since pkcs7_parse_message() accepts only + * pkcs7's signedData, some header needed be prepended for correctly + * parsing authentication data, particularly for variable's. * - * @variable_name: name of the variable - * @vendor: vendor GUID - * @attributes: attributes of the variable - * @data_size: size of the buffer to which the variable value is copied - * @data: buffer to which the variable value is copied - * Return: status code + * Return: Pointer to pkcs7_message structure on success, NULL on error */ -efi_status_t EFIAPI efi_get_variable(u16 *variable_name, - const efi_guid_t *vendor, u32 *attributes, - efi_uintn_t *data_size, void *data) +static struct pkcs7_message *efi_variable_parse_signature(const void *buf, + size_t buflen) +{ + u8 *ebuf; + size_t ebuflen, len; + struct pkcs7_message *msg; + + /* + * This is the best assumption to check if the binary is + * already in a form of pkcs7's signedData. + */ + if (buflen > sizeof(pkcs7_hdr) && + !memcmp(&((u8 *)buf)[4], &pkcs7_hdr[4], 11)) { + msg = pkcs7_parse_message(buf, buflen); + goto out; + } + + /* + * Otherwise, we should add a dummy prefix sequence for pkcs7 + * message parser to be able to process. + * NOTE: EDK2 also uses similar hack in WrapPkcs7Data() + * in CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyCommon.c + * TODO: + * The header should be composed in a more refined manner. + */ + debug("Makeshift prefix added to authentication data\n"); + ebuflen = sizeof(pkcs7_hdr) + buflen; + if (ebuflen <= 0x7f) { + debug("Data is too short\n"); + return NULL; + } + + ebuf = malloc(ebuflen); + if (!ebuf) { + debug("Out of memory\n"); + return NULL; + } + + memcpy(ebuf, pkcs7_hdr, sizeof(pkcs7_hdr)); + memcpy(ebuf + sizeof(pkcs7_hdr), buf, buflen); + len = ebuflen - 4; + ebuf[2] = (len >> 8) & 0xff; + ebuf[3] = len & 0xff; + len = ebuflen - 0x13; + ebuf[0x11] = (len >> 8) & 0xff; + ebuf[0x12] = len & 0xff; + + msg = pkcs7_parse_message(ebuf, ebuflen); + + free(ebuf); + +out: + if (IS_ERR(msg)) + return NULL; + + return msg; +} + +/** + * efi_variable_authenticate - authenticate a variable + * @variable: Variable name in u16 + * @vendor: Guid of variable + * @data_size: Size of @data + * @data: Pointer to variable's value + * @given_attr: Attributes to be given at SetVariable() + * @env_attr: Attributes that an existing variable holds + * @time: signed time that an existing variable holds + * + * Called by efi_set_variable() to verify that the input is correct. + * Will replace the given data pointer with another that points to + * the actual data to store in the internal memory. + * On success, @data and @data_size will be replaced with variable's + * actual data, excluding authentication data, and its size, and variable's + * attributes and signed time will also be returned in @env_attr and @time, + * respectively. + * + * Return: EFI_SUCCESS on success, status code (negative) on error + */ +static efi_status_t efi_variable_authenticate(u16 *variable, + const efi_guid_t *vendor, + efi_uintn_t *data_size, + const void **data, u32 given_attr, + u32 *env_attr, u64 *time) +{ + const struct efi_variable_authentication_2 *auth; + struct efi_signature_store *truststore, *truststore2; + struct pkcs7_message *var_sig; + struct efi_image_regions *regs; + const struct efi_time *timestamp; + struct rtc_time tm; + u64 new_time; + efi_status_t ret; + + var_sig = NULL; + truststore = NULL; + truststore2 = NULL; + regs = NULL; + ret = EFI_SECURITY_VIOLATION; + + if (*data_size < sizeof(struct efi_variable_authentication_2)) + goto err; + + /* authentication data */ + auth = *data; + if (*data_size < (sizeof(auth->time_stamp) + + auth->auth_info.hdr.dwLength)) + goto err; + + if (guidcmp(&auth->auth_info.cert_type, &efi_guid_cert_type_pkcs7)) + goto err; + + *data += sizeof(auth->time_stamp) + auth->auth_info.hdr.dwLength; + *data_size -= (sizeof(auth->time_stamp) + + auth->auth_info.hdr.dwLength); + + timestamp = &auth->time_stamp; + memset(&tm, 0, sizeof(tm)); + tm.tm_year = timestamp->year; + tm.tm_mon = timestamp->month; + tm.tm_mday = timestamp->day; + tm.tm_hour = timestamp->hour; + tm.tm_min = timestamp->minute; + tm.tm_sec = timestamp->second; + new_time = rtc_mktime(&tm); + + if (!efi_secure_boot_enabled()) { + /* finished checking */ + *time = new_time; + return EFI_SUCCESS; + } + + if (new_time <= *time) + goto err; + + /* data to be digested */ + regs = calloc(sizeof(*regs) + sizeof(struct image_region) * 5, 1); + if (!regs) + goto err; + regs->max = 5; + efi_image_region_add(regs, (uint8_t *)variable, + (uint8_t *)variable + + u16_strlen(variable) * sizeof(u16), 1); + efi_image_region_add(regs, (uint8_t *)vendor, + (uint8_t *)vendor + sizeof(*vendor), 1); + efi_image_region_add(regs, (uint8_t *)&given_attr, + (uint8_t *)&given_attr + sizeof(given_attr), 1); + efi_image_region_add(regs, (uint8_t *)timestamp, + (uint8_t *)timestamp + sizeof(*timestamp), 1); + efi_image_region_add(regs, (uint8_t *)*data, + (uint8_t *)*data + *data_size, 1); + + /* variable's signature list */ + if (auth->auth_info.hdr.dwLength < sizeof(auth->auth_info)) + goto err; + var_sig = efi_variable_parse_signature(auth->auth_info.cert_data, + auth->auth_info.hdr.dwLength + - sizeof(auth->auth_info)); + if (IS_ERR(var_sig)) { + debug("Parsing variable's signature failed\n"); + var_sig = NULL; + goto err; + } + + /* signature database used for authentication */ + if (u16_strcmp(variable, L"PK") == 0 || + u16_strcmp(variable, L"KEK") == 0) { + /* with PK */ + truststore = efi_sigstore_parse_sigdb(L"PK"); + if (!truststore) + goto err; + } else if (u16_strcmp(variable, L"db") == 0 || + u16_strcmp(variable, L"dbx") == 0) { + /* with PK and KEK */ + truststore = efi_sigstore_parse_sigdb(L"KEK"); + truststore2 = efi_sigstore_parse_sigdb(L"PK"); + + if (!truststore) { + if (!truststore2) + goto err; + + truststore = truststore2; + truststore2 = NULL; + } + } else { + /* TODO: support private authenticated variables */ + goto err; + } + + /* verify signature */ + if (efi_signature_verify_with_sigdb(regs, var_sig, truststore, NULL)) { + debug("Verified\n"); + } else { + if (truststore2 && + efi_signature_verify_with_sigdb(regs, var_sig, + truststore2, NULL)) { + debug("Verified\n"); + } else { + debug("Verifying variable's signature failed\n"); + goto err; + } + } + + /* finished checking */ + *time = rtc_mktime(&tm); + ret = EFI_SUCCESS; + +err: + efi_sigstore_free(truststore); + efi_sigstore_free(truststore2); + pkcs7_free_message(var_sig); + free(regs); + + return ret; +} +#else +static efi_status_t efi_variable_authenticate(u16 *variable, + const efi_guid_t *vendor, + efi_uintn_t *data_size, + const void **data, u32 given_attr, + u32 *env_attr, u64 *time) +{ + return EFI_SUCCESS; +} +#endif /* CONFIG_EFI_SECURE_BOOT */ + +static +efi_status_t EFIAPI efi_get_variable_common(u16 *variable_name, + const efi_guid_t *vendor, + u32 *attributes, + efi_uintn_t *data_size, void *data, + bool is_non_volatile) { char *native_name; efi_status_t ret; unsigned long in_size; - const char *val, *s; + const char *val = NULL, *s; + u64 time = 0; u32 attr; - EFI_ENTRY("\"%ls\" %pUl %p %p %p", variable_name, vendor, attributes, - data_size, data); - if (!variable_name || !vendor || !data_size) return EFI_EXIT(EFI_INVALID_PARAMETER); ret = efi_to_native(&native_name, variable_name, vendor); if (ret) - return EFI_EXIT(ret); + return ret; EFI_PRINT("get '%s'\n", native_name); val = env_get(native_name); free(native_name); if (!val) - return EFI_EXIT(EFI_NOT_FOUND); + return EFI_NOT_FOUND; - val = parse_attr(val, &attr); + val = parse_attr(val, &attr, &time); in_size = *data_size; @@ -197,7 +452,7 @@ efi_status_t EFIAPI efi_get_variable(u16 *variable_name, /* number of hexadecimal digits must be even */ if (len & 1) - return EFI_EXIT(EFI_DEVICE_ERROR); + return EFI_DEVICE_ERROR; /* two characters per byte: */ len /= 2; @@ -208,11 +463,13 @@ efi_status_t EFIAPI efi_get_variable(u16 *variable_name, goto out; } - if (!data) - return EFI_EXIT(EFI_INVALID_PARAMETER); + if (!data) { + debug("Variable with no data shouldn't exist.\n"); + return EFI_INVALID_PARAMETER; + } if (hex2bin(data, s, len)) - return EFI_EXIT(EFI_DEVICE_ERROR); + return EFI_DEVICE_ERROR; EFI_PRINT("got value: \"%s\"\n", s); } else if ((s = prefix(val, "(utf8)"))) { @@ -225,8 +482,10 @@ efi_status_t EFIAPI efi_get_variable(u16 *variable_name, goto out; } - if (!data) - return EFI_EXIT(EFI_INVALID_PARAMETER); + if (!data) { + debug("Variable with no data shouldn't exist.\n"); + return EFI_INVALID_PARAMETER; + } memcpy(data, s, len); ((char *)data)[len] = '\0'; @@ -234,13 +493,67 @@ efi_status_t EFIAPI efi_get_variable(u16 *variable_name, EFI_PRINT("got value: \"%s\"\n", (char *)data); } else { EFI_PRINT("invalid value: '%s'\n", val); - return EFI_EXIT(EFI_DEVICE_ERROR); + return EFI_DEVICE_ERROR; } out: if (attributes) *attributes = attr & EFI_VARIABLE_MASK; + return ret; +} + +static +efi_status_t EFIAPI efi_get_volatile_variable(u16 *variable_name, + const efi_guid_t *vendor, + u32 *attributes, + efi_uintn_t *data_size, + void *data) +{ + return efi_get_variable_common(variable_name, vendor, attributes, + data_size, data, false); +} + +efi_status_t EFIAPI efi_get_nonvolatile_variable(u16 *variable_name, + const efi_guid_t *vendor, + u32 *attributes, + efi_uintn_t *data_size, + void *data) +{ + return efi_get_variable_common(variable_name, vendor, attributes, + data_size, data, true); +} + +/** + * efi_efi_get_variable() - retrieve value of a UEFI variable + * + * This function implements the GetVariable runtime service. + * + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. + * + * @variable_name: name of the variable + * @vendor: vendor GUID + * @attributes: attributes of the variable + * @data_size: size of the buffer to which the variable value is copied + * @data: buffer to which the variable value is copied + * Return: status code + */ +efi_status_t EFIAPI efi_get_variable(u16 *variable_name, + const efi_guid_t *vendor, u32 *attributes, + efi_uintn_t *data_size, void *data) +{ + efi_status_t ret; + + EFI_ENTRY("\"%ls\" %pUl %p %p %p", variable_name, vendor, attributes, + data_size, data); + + ret = efi_get_volatile_variable(variable_name, vendor, attributes, + data_size, data); + if (ret == EFI_NOT_FOUND) + ret = efi_get_nonvolatile_variable(variable_name, vendor, + attributes, data_size, data); + return EFI_EXIT(ret); } @@ -273,6 +586,7 @@ static efi_status_t parse_uboot_variable(char *variable, { char *guid, *name, *end, c; unsigned long name_len; + u64 time; u16 *p; guid = strchr(variable, '_'); @@ -307,7 +621,7 @@ static efi_status_t parse_uboot_variable(char *variable, *(name - 1) = c; /* attributes */ - parse_attr(end, attributes); + parse_attr(end, attributes, &time); return EFI_SUCCESS; } @@ -389,7 +703,7 @@ efi_status_t EFIAPI efi_get_next_variable_name(efi_uintn_t *variable_name_size, list_len = hexport_r(&env_htab, '\n', H_MATCH_REGEX | H_MATCH_KEY, &efi_variables_list, 0, 1, regexlist); - /* 1 indicates that no match was found */ + if (list_len <= 1) return EFI_EXIT(EFI_NOT_FOUND); @@ -402,143 +716,286 @@ efi_status_t EFIAPI efi_get_next_variable_name(efi_uintn_t *variable_name_size, return EFI_EXIT(ret); } -/** - * efi_set_variable() - set value of a UEFI variable - * - * This function implements the SetVariable runtime service. - * - * See the Unified Extensible Firmware Interface (UEFI) specification for - * details. - * - * @variable_name: name of the variable - * @vendor: vendor GUID - * @attributes: attributes of the variable - * @data_size: size of the buffer with the variable value - * @data: buffer with the variable value - * Return: status code - */ -efi_status_t EFIAPI efi_set_variable(u16 *variable_name, - const efi_guid_t *vendor, u32 attributes, - efi_uintn_t data_size, const void *data) +static +efi_status_t EFIAPI efi_set_variable_common(u16 *variable_name, + const efi_guid_t *vendor, + u32 attributes, + efi_uintn_t data_size, + const void *data, + bool ro_check, + bool is_non_volatile) { - char *native_name = NULL, *val = NULL, *s; - const char *old_val; - size_t old_size; - efi_status_t ret = EFI_SUCCESS; + char *native_name = NULL, *old_data = NULL, *val = NULL, *s; + efi_uintn_t old_size; + bool append, delete; + u64 time = 0; u32 attr; + efi_status_t ret = EFI_SUCCESS; - EFI_ENTRY("\"%ls\" %pUl %x %zu %p", variable_name, vendor, attributes, - data_size, data); + debug("%s: set '%s'\n", __func__, native_name); if (!variable_name || !*variable_name || !vendor || ((attributes & EFI_VARIABLE_RUNTIME_ACCESS) && !(attributes & EFI_VARIABLE_BOOTSERVICE_ACCESS))) { ret = EFI_INVALID_PARAMETER; - goto out; + goto err; } ret = efi_to_native(&native_name, variable_name, vendor); if (ret) - goto out; + goto err; + + /* check if a variable exists */ + old_size = 0; + attr = 0; + ret = EFI_CALL(efi_get_variable(variable_name, vendor, &attr, + &old_size, NULL)); + if (ret == EFI_BUFFER_TOO_SMALL) { + if ((is_non_volatile && !(attr & EFI_VARIABLE_NON_VOLATILE)) || + (!is_non_volatile && (attr & EFI_VARIABLE_NON_VOLATILE))) { + ret = EFI_INVALID_PARAMETER; + goto err; + } + } - old_val = env_get(native_name); - if (old_val) { - old_val = parse_attr(old_val, &attr); + append = !!(attributes & EFI_VARIABLE_APPEND_WRITE); + attributes &= ~(u32)EFI_VARIABLE_APPEND_WRITE; + delete = !append && (!data_size || !attributes); - /* check read-only first */ - if (attr & READ_ONLY) { + /* check attributes */ + if (old_size) { + if (ro_check && (attr & READ_ONLY)) { ret = EFI_WRITE_PROTECTED; - goto out; - } - - if ((data_size == 0 && - !(attributes & EFI_VARIABLE_APPEND_WRITE)) || - !attributes) { - /* delete the variable: */ - env_set(native_name, NULL); - ret = EFI_SUCCESS; - goto out; + goto err; } /* attributes won't be changed */ - if (attr != (attributes & ~EFI_VARIABLE_APPEND_WRITE)) { + if (!delete && + ((ro_check && attr != attributes) || + (!ro_check && ((attr & ~(u32)READ_ONLY) + != (attributes & ~(u32)READ_ONLY))))) { ret = EFI_INVALID_PARAMETER; - goto out; - } - - if (attributes & EFI_VARIABLE_APPEND_WRITE) { - if (!prefix(old_val, "(blob)")) { - ret = EFI_DEVICE_ERROR; - goto out; - } - old_size = strlen(old_val); - } else { - old_size = 0; + goto err; } } else { - if (data_size == 0 || !attributes || - (attributes & EFI_VARIABLE_APPEND_WRITE)) { + if (delete || append) { /* * Trying to delete or to update a non-existent * variable. */ ret = EFI_NOT_FOUND; - goto out; + goto err; + } + } + + if (((!u16_strcmp(variable_name, L"PK") || + !u16_strcmp(variable_name, L"KEK")) && + !guidcmp(vendor, &efi_global_variable_guid)) || + ((!u16_strcmp(variable_name, L"db") || + !u16_strcmp(variable_name, L"dbx")) && + !guidcmp(vendor, &efi_guid_image_security_database))) { + /* authentication is mandatory */ + if (!(attributes & + EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)) { + debug("%ls: AUTHENTICATED_WRITE_ACCESS required\n", + variable_name); + ret = EFI_INVALID_PARAMETER; + goto err; } + } + + /* authenticate a variable */ + if (IS_ENABLED(CONFIG_EFI_SECURE_BOOT)) { + if (attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) { + ret = EFI_INVALID_PARAMETER; + goto err; + } + if (attributes & + EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) { + ret = efi_variable_authenticate(variable_name, vendor, + &data_size, &data, + attributes, &attr, + &time); + if (ret != EFI_SUCCESS) + goto err; + + /* last chance to check for delete */ + if (!data_size) + delete = true; + } + } else { + if (attributes & + (EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS | + EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)) { + debug("Secure boot is not configured\n"); + ret = EFI_INVALID_PARAMETER; + goto err; + } + } + + /* delete a variable */ + if (delete) { + /* !old_size case has been handled before */ + val = NULL; + ret = EFI_SUCCESS; + goto out; + } + if (append) { + old_data = malloc(old_size); + if (!old_data) { + return EFI_OUT_OF_RESOURCES; + goto err; + } + ret = EFI_CALL(efi_get_variable(variable_name, vendor, + &attr, &old_size, old_data)); + if (ret != EFI_SUCCESS) + goto err; + } else { old_size = 0; } - val = malloc(old_size + 2 * data_size - + strlen("{ro,run,boot,nv}(blob)") + 1); + val = malloc(2 * old_size + 2 * data_size + + strlen("{ro,run,boot,nv,time=0123456701234567}(blob)") + + 1); if (!val) { ret = EFI_OUT_OF_RESOURCES; - goto out; + goto err; } s = val; - /* store attributes */ - attributes &= (EFI_VARIABLE_NON_VOLATILE | + /* + * store attributes + */ + attributes &= (READ_ONLY | + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | - EFI_VARIABLE_RUNTIME_ACCESS); + EFI_VARIABLE_RUNTIME_ACCESS | + EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS); s += sprintf(s, "{"); while (attributes) { - u32 attr = 1 << (ffs(attributes) - 1); + attr = 1 << (ffs(attributes) - 1); - if (attr == EFI_VARIABLE_NON_VOLATILE) + if (attr == READ_ONLY) { + s += sprintf(s, "ro"); + } else if (attr == EFI_VARIABLE_NON_VOLATILE) { s += sprintf(s, "nv"); - else if (attr == EFI_VARIABLE_BOOTSERVICE_ACCESS) + } else if (attr == EFI_VARIABLE_BOOTSERVICE_ACCESS) { s += sprintf(s, "boot"); - else if (attr == EFI_VARIABLE_RUNTIME_ACCESS) + } else if (attr == EFI_VARIABLE_RUNTIME_ACCESS) { s += sprintf(s, "run"); + } else if (attr == + EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) { + s += sprintf(s, "time="); + s = bin2hex(s, (u8 *)&time, sizeof(time)); + } attributes &= ~attr; if (attributes) s += sprintf(s, ","); } s += sprintf(s, "}"); - - if (old_size) - /* APPEND_WRITE */ - s += sprintf(s, old_val); - else - s += sprintf(s, "(blob)"); + s += sprintf(s, "(blob)"); /* store payload: */ + if (append) + s = bin2hex(s, old_data, old_size); s = bin2hex(s, data, data_size); *s = '\0'; EFI_PRINT("setting: %s=%s\n", native_name, val); +out: if (env_set(native_name, val)) ret = EFI_DEVICE_ERROR; + else + ret = EFI_SUCCESS; -out: +err: free(native_name); + free(old_data); free(val); - return EFI_EXIT(ret); + return ret; +} + +static +efi_status_t EFIAPI efi_set_volatile_variable(u16 *variable_name, + const efi_guid_t *vendor, + u32 attributes, + efi_uintn_t data_size, + const void *data, + bool ro_check) +{ + return efi_set_variable_common(variable_name, vendor, attributes, + data_size, data, ro_check, false); +} + +efi_status_t EFIAPI efi_set_nonvolatile_variable(u16 *variable_name, + const efi_guid_t *vendor, + u32 attributes, + efi_uintn_t data_size, + const void *data, + bool ro_check) +{ + efi_status_t ret; + + ret = efi_set_variable_common(variable_name, vendor, attributes, + data_size, data, ro_check, true); + + return ret; +} + +static efi_status_t efi_set_variable_internal(u16 *variable_name, + const efi_guid_t *vendor, + u32 attributes, + efi_uintn_t data_size, + const void *data, + bool ro_check) +{ + efi_status_t ret; + + if (attributes & EFI_VARIABLE_NON_VOLATILE) + ret = efi_set_nonvolatile_variable(variable_name, vendor, + attributes, + data_size, data, ro_check); + else + ret = efi_set_volatile_variable(variable_name, vendor, + attributes, data_size, data, + ro_check); + + return ret; +} + +/** + * efi_set_variable() - set value of a UEFI variable + * + * This function implements the SetVariable runtime service. + * + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. + * + * @variable_name: name of the variable + * @vendor: vendor GUID + * @attributes: attributes of the variable + * @data_size: size of the buffer with the variable value + * @data: buffer with the variable value + * Return: status code + */ +efi_status_t EFIAPI efi_set_variable(u16 *variable_name, + const efi_guid_t *vendor, u32 attributes, + efi_uintn_t data_size, const void *data) +{ + EFI_ENTRY("\"%ls\" %pUl %x %zu %p", variable_name, vendor, attributes, + data_size, data); + + /* READ_ONLY bit is not part of API */ + attributes &= ~(u32)READ_ONLY; + + return EFI_EXIT(efi_set_variable_internal(variable_name, vendor, + attributes, data_size, data, + true)); } /** From patchwork Wed Dec 18 00:45:02 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: AKASHI Takahiro X-Patchwork-Id: 1211839 X-Patchwork-Delegate: xypron.glpk@gmx.de Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=85.214.62.61; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=linaro.org Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.b="vzQMWgWX"; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [85.214.62.61]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 47cxB80kjVz9sRl for ; Wed, 18 Dec 2019 11:45:20 +1100 (AEDT) Received: from phobos.denx.de (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id A60B28166B; Wed, 18 Dec 2019 01:44:27 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=fail (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=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.b="vzQMWgWX"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id EC6BB8166B; Wed, 18 Dec 2019 01:44:21 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-0.1 required=5.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,SPF_HELO_NONE,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.2 Received: from mail-pl1-x641.google.com (mail-pl1-x641.google.com [IPv6:2607:f8b0:4864:20::641]) (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 9B22381634 for ; Wed, 18 Dec 2019 01:44:18 +0100 (CET) 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-x641.google.com with SMTP id c23so167301plz.4 for ; Tue, 17 Dec 2019 16:44:18 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=D/zvVisAZbl69uPqmqiVp9Q8RrjET5OOPuGm3i6Lrag=; b=vzQMWgWX8PpeG6K8rSv1UqRjkzp4H9joSOwG2ILrdyVhCqsUCcXxpEwGw2oa/7VMwJ ejrHP5F1f1q6BQNV8Q4YKghIjZXZlnR/XSXA46hNY0u+Vw8bv19xxLWhg0L6vUyd58m2 weFH0yMmkRSqIRqRrKQqy1GT+sZVXQv2fEjravffSKESebFBit+oq4cSAJUQ4S1qewQ2 bdBOJJUultCl5Katr8cLfN+63RMGx1PBxq7gcEnBQ5ozU5vFKXVJlP+RYY7j2mudN1Rt bbUImQORk2BAoYDQ/3/4b5RWXrQNppcbXqZU7yZ8GQD9b9D36FBgPceJhU5amKWCS9Jp WPtQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=D/zvVisAZbl69uPqmqiVp9Q8RrjET5OOPuGm3i6Lrag=; b=PGUsSlVp1T5pZDTUJzviri97cCXc7Zkgl0kTJzbg9FXQSWvmFY0EgEzQCu82T3S7tq T44EhdoWz19ZhmbUzxnYHWn4i2pOWO3pbpupGf8jAtOEBihS55BlNvqH226qt/hO8Y/3 IbYjjoRf+jmkP1WaeG4dM3SPUeiHnuFTmE1UrUNRrJuDV8gEdTla2yslrgk3SPkHftLC TJCyuFCsRxWlP7/YBEMQQVFd8QweSOSrLbcHtl1svtdaXz8aybnd5Uy1lpOHOOyAkUv6 2qlq/Dt2As0LTN5bn6fs5sesPzHOezSe7M1Zody/q1NAnEqw3gpAk+jF9P+xt9WcbY9k kDhw== X-Gm-Message-State: APjAAAUwMeHrp92pEB7G+ZZU7pRcL7k13v0/ZfBNtGwBKBsfaHen3AZW F52fNp3AyZKDL1U5Kb6w3zeq1g== X-Google-Smtp-Source: APXvYqxFkSQrPJ8Rn0AXX4SNzU2d6vLhoEVS21P3Z/+NncgkaHzyvkXQ6KU5DRmMGFzSTPFl+sJBNQ== X-Received: by 2002:a17:90a:db0f:: with SMTP id g15mr211696pjv.40.1576629856974; Tue, 17 Dec 2019 16:44:16 -0800 (PST) Received: from linaro.org ([121.95.100.191]) by smtp.googlemail.com with ESMTPSA id p23sm187266pgh.83.2019.12.17.16.44.16 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 17 Dec 2019 16:44:16 -0800 (PST) From: AKASHI Takahiro To: xypron.glpk@gmx.de, agraf@csgraf.de, trini@konsulko.com Subject: [PATCH v4 06/16] efi_loader: variable: add secure boot state transition Date: Wed, 18 Dec 2019 09:45:02 +0900 Message-Id: <20191218004512.24939-7-takahiro.akashi@linaro.org> X-Mailer: git-send-email 2.24.0 In-Reply-To: <20191218004512.24939-1-takahiro.akashi@linaro.org> References: <20191218004512.24939-1-takahiro.akashi@linaro.org> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.26 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: u-boot@lists.denx.de, mail@patrick-wildt.de Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.101.4 at phobos.denx.de X-Virus-Status: Clean UEFI specification defines several global variables which are related to the current secure boot state. In this commit, those values will be maintained according to operations. Currently, AuditMode and DeployedMode are defined but not implemented. Signed-off-by: AKASHI Takahiro --- lib/efi_loader/efi_variable.c | 231 +++++++++++++++++++++++++++++++++- 1 file changed, 228 insertions(+), 3 deletions(-) diff --git a/lib/efi_loader/efi_variable.c b/lib/efi_loader/efi_variable.c index 171b4abb4c58..2e7570bc9b4f 100644 --- a/lib/efi_loader/efi_variable.c +++ b/lib/efi_loader/efi_variable.c @@ -15,8 +15,16 @@ #include #include "../lib/crypto/pkcs7_parser.h" +enum efi_secure_mode { + EFI_MODE_SETUP, + EFI_MODE_USER, + EFI_MODE_AUDIT, + EFI_MODE_DEPLOYED, +}; + const efi_guid_t efi_guid_cert_type_pkcs7 = EFI_CERT_TYPE_PKCS7_GUID; static bool efi_secure_boot; +static int efi_secure_mode; #define READ_ONLY BIT(31) @@ -158,6 +166,210 @@ static const char *parse_attr(const char *str, u32 *attrp, u64 *timep) return str; } +static efi_status_t efi_set_variable_internal(u16 *variable_name, + const efi_guid_t *vendor, + u32 attributes, + efi_uintn_t data_size, + const void *data, + bool ro_check); + +/** + * efi_transfer_secure_state - handle a secure boot state transition + * @mode: new state + * + * Depending on @mode, secure boot related variables are updated. + * Those variables are *read-only* for users, efi_set_variable_internal() + * is called here. + * + * Return: EFI_SUCCESS on success, status code (negative) on error + */ +static efi_status_t efi_transfer_secure_state(enum efi_secure_mode mode) +{ + u32 attributes; + u8 val; + efi_status_t ret; + + debug("Secure state from %d to %d\n", efi_secure_mode, mode); + + attributes = EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS; + if (mode == EFI_MODE_DEPLOYED) { + val = 1; + ret = efi_set_variable_internal(L"SecureBoot", + &efi_global_variable_guid, + attributes | READ_ONLY, + sizeof(val), &val, + false); + if (ret != EFI_SUCCESS) + goto err; + val = 0; + ret = efi_set_variable_internal(L"SetupMode", + &efi_global_variable_guid, + attributes | READ_ONLY, + sizeof(val), &val, + false); + if (ret != EFI_SUCCESS) + goto err; + val = 0; + ret = efi_set_variable_internal(L"AuditMode", + &efi_global_variable_guid, + attributes | READ_ONLY, + sizeof(val), &val, + false); + if (ret != EFI_SUCCESS) + goto err; + val = 1; + ret = efi_set_variable_internal(L"DeployedMode", + &efi_global_variable_guid, + attributes | READ_ONLY, + sizeof(val), &val, + false); + if (ret != EFI_SUCCESS) + goto err; + + efi_secure_boot = true; + } else if (mode == EFI_MODE_AUDIT) { + ret = efi_set_variable_internal(L"PK", + &efi_global_variable_guid, + attributes, + 0, NULL, + false); + if (ret != EFI_SUCCESS) + goto err; + val = 0; + ret = efi_set_variable_internal(L"SecureBoot", + &efi_global_variable_guid, + attributes | READ_ONLY, + sizeof(val), &val, + false); + if (ret != EFI_SUCCESS) + goto err; + val = 1; + ret = efi_set_variable_internal(L"SetupMode", + &efi_global_variable_guid, + attributes | READ_ONLY, + sizeof(val), &val, + false); + if (ret != EFI_SUCCESS) + goto err; + val = 1; + ret = efi_set_variable_internal(L"AuditMode", + &efi_global_variable_guid, + attributes | READ_ONLY, + sizeof(val), &val, + false); + if (ret != EFI_SUCCESS) + goto err; + val = 0; + ret = efi_set_variable_internal(L"DeployedMode", + &efi_global_variable_guid, + attributes | READ_ONLY, + sizeof(val), &val, + false); + if (ret != EFI_SUCCESS) + goto err; + + efi_secure_boot = true; + } else if (mode == EFI_MODE_USER) { + val = 1; + ret = efi_set_variable_internal(L"SecureBoot", + &efi_global_variable_guid, + attributes | READ_ONLY, + sizeof(val), &val, + false); + if (ret != EFI_SUCCESS) + goto err; + val = 0; + ret = efi_set_variable_internal(L"SetupMode", + &efi_global_variable_guid, + attributes | READ_ONLY, + sizeof(val), &val, + false); + if (ret != EFI_SUCCESS) + goto err; + val = 0; + ret = efi_set_variable_internal(L"AuditMode", + &efi_global_variable_guid, + attributes, + sizeof(val), &val, + false); + if (ret != EFI_SUCCESS) + goto err; + val = 0; + ret = efi_set_variable_internal(L"DeployedMode", + &efi_global_variable_guid, + attributes, + sizeof(val), &val, + false); + if (ret != EFI_SUCCESS) + goto err; + + efi_secure_boot = true; + } else if (mode == EFI_MODE_SETUP) { + val = 0; + ret = efi_set_variable_internal(L"SecureBoot", + &efi_global_variable_guid, + attributes | READ_ONLY, + sizeof(val), &val, + false); + if (ret != EFI_SUCCESS) + goto err; + val = 1; + ret = efi_set_variable_internal(L"SetupMode", + &efi_global_variable_guid, + attributes | READ_ONLY, + sizeof(val), &val, + false); + if (ret != EFI_SUCCESS) + goto err; + val = 0; + ret = efi_set_variable_internal(L"AuditMode", + &efi_global_variable_guid, + attributes, + sizeof(val), &val, + false); + if (ret != EFI_SUCCESS) + goto err; + val = 0; + ret = efi_set_variable_internal(L"DeployedMode", + &efi_global_variable_guid, + attributes | READ_ONLY, + sizeof(val), &val, + false); + if (ret != EFI_SUCCESS) + goto err; + } else { + return EFI_INVALID_PARAMETER; + } + + return EFI_SUCCESS; + +err: + /* TODO: What action should be taken here? */ + printf("ERROR: Secure state transition failed\n"); + return ret; +} + +/** + * efi_init_secure_state - initialize secure boot state + * + * Return: EFI_SUCCESS on success, status code (negative) on error + */ +static efi_status_t efi_init_secure_state(void) +{ + efi_uintn_t size = 0; + efi_status_t ret; + + ret = EFI_CALL(efi_get_variable(L"PK", &efi_global_variable_guid, + NULL, &size, NULL)); + if (ret == EFI_BUFFER_TOO_SMALL && IS_ENABLED(CONFIG_EFI_SECURE_BOOT)) + ret = efi_transfer_secure_state(EFI_MODE_USER); + else + ret = efi_transfer_secure_state(EFI_MODE_SETUP); + + return ret; +} + /** * efi_secure_boot_enabled - return if secure boot is enabled or not * @@ -907,10 +1119,19 @@ efi_status_t EFIAPI efi_set_variable_common(u16 *variable_name, EFI_PRINT("setting: %s=%s\n", native_name, val); out: - if (env_set(native_name, val)) + if (env_set(native_name, val)) { ret = EFI_DEVICE_ERROR; - else + } else { + if ((u16_strcmp(variable_name, L"PK") == 0 && + guidcmp(vendor, &efi_global_variable_guid) == 0)) { + ret = efi_transfer_secure_state( + (delete ? EFI_MODE_SETUP : + EFI_MODE_USER)); + if (ret != EFI_SUCCESS) + goto err; + } ret = EFI_SUCCESS; + } err: free(native_name); @@ -1095,5 +1316,9 @@ void efi_variables_boot_exit_notify(void) */ efi_status_t efi_init_variables(void) { - return EFI_SUCCESS; + efi_status_t ret; + + ret = efi_init_secure_state(); + + return ret; } From patchwork Wed Dec 18 00:45:03 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: AKASHI Takahiro X-Patchwork-Id: 1211840 X-Patchwork-Delegate: xypron.glpk@gmx.de Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=85.214.62.61; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=linaro.org Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.b="N4m/pPuC"; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [85.214.62.61]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 47cxBM2Tflz9sRl for ; Wed, 18 Dec 2019 11:45:31 +1100 (AEDT) Received: from phobos.denx.de (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 92FBF81680; Wed, 18 Dec 2019 01:44:29 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=fail (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=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.b="N4m/pPuC"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id C9E4B81638; Wed, 18 Dec 2019 01:44:24 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-0.1 required=5.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,SPF_HELO_NONE,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.2 Received: from mail-pg1-x541.google.com (mail-pg1-x541.google.com [IPv6:2607:f8b0:4864:20::541]) (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 D109681672 for ; Wed, 18 Dec 2019 01:44:21 +0100 (CET) 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-pg1-x541.google.com with SMTP id a33so254168pgm.5 for ; Tue, 17 Dec 2019 16:44:21 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=/Tn3uvVE3uq5zrBVmLLaHGw4J8x28phKDfBWJ5TvXEY=; b=N4m/pPuCTv4Qo36fDv4zv1Y4Hgu8vEH5p8Knn41PLNA8c2NUT4AQZfmjjI26m8FW10 DYQ4rzYdmkQVKmoIyN5xOINVwc06ku6zARBh3mgMU5blpznHBQXQAsvO6B8XB1i41vOU JlO81lpBSGagDGB8TqthoKb0+KkkEmyvR7/bVDUNRG4X+bVW+aDBuPEBZxoHO6BPqw09 YyXwyk8O166Nh6VTU+Os0IMPQl3rWYByjejh507bt7CY5l+/CCO9G1tTYLETRe1XFuYC J6sklQe3A5yo4nzdEaeFKMsDIKT+Z2w0zdxvhPzFAFxLpDDR8bL/25Unt9y+nH1EUX15 8RdQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=/Tn3uvVE3uq5zrBVmLLaHGw4J8x28phKDfBWJ5TvXEY=; b=BkPlYT4mNS89hI1x3xp4JNwYEpl9Ge+KZ6ZJ1Y//JW6rktdMPenXp1dncALjXFT9QQ LmdcD/BHMLt/U9eIdMeltmqWGPB+xQJuTXjWj3HnOW7jsUomNJDxHZnozVa5YPfb8zc1 FI6CX8i0ZKF8eh0LyFVs6OcsNPkUSkoGU1oIBejAG5HHFtcpsJuDDemcqU0WANCZCRo3 rvi7+JokPSQ3NdMXSZ1cqRwxWAQaLtKQDI1obu/rvLPUKtAeOS3l7PNn1ajoGLmqMeBi p6qFuBwr0tPWHcQWivoquFJ3ZGSCLKfWam8J7XBWdDJzV9V1YIjnuD9k+xjevN/YPXLA fbcQ== X-Gm-Message-State: APjAAAVlj+PbVVB0KiOFPHw6Xc2uMKcz76ig98R8ozSknZD2XmhROOUB 6YcUkqHvlv6bVh5h7JKpsH282g== X-Google-Smtp-Source: APXvYqxpjssJzhxKsIuUVxGUxBzNcy7Dub46thSYVNAMO13ZguMBa0pZeZc12f7YIt/PesvCeDR3Vw== X-Received: by 2002:a63:5442:: with SMTP id e2mr839115pgm.18.1576629860216; Tue, 17 Dec 2019 16:44:20 -0800 (PST) Received: from linaro.org ([121.95.100.191]) by smtp.googlemail.com with ESMTPSA id g7sm265160pfq.33.2019.12.17.16.44.19 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 17 Dec 2019 16:44:19 -0800 (PST) From: AKASHI Takahiro To: xypron.glpk@gmx.de, agraf@csgraf.de, trini@konsulko.com Subject: [PATCH v4 07/16] efi_loader: variable: add VendorKeys variable Date: Wed, 18 Dec 2019 09:45:03 +0900 Message-Id: <20191218004512.24939-8-takahiro.akashi@linaro.org> X-Mailer: git-send-email 2.24.0 In-Reply-To: <20191218004512.24939-1-takahiro.akashi@linaro.org> References: <20191218004512.24939-1-takahiro.akashi@linaro.org> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.26 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: u-boot@lists.denx.de, mail@patrick-wildt.de Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.101.4 at phobos.denx.de X-Virus-Status: Clean The following variable is exported as UEFI specification defines: VendorKeys: whether the system is configured to use only vendor-provided keys or not The value will have to be modified if a platform has its own way of initializing signature database, in particular, PK. Signed-off-by: AKASHI Takahiro --- lib/efi_loader/efi_variable.c | 69 ++++++++++++++++++++++++++++++++--- 1 file changed, 63 insertions(+), 6 deletions(-) diff --git a/lib/efi_loader/efi_variable.c b/lib/efi_loader/efi_variable.c index 2e7570bc9b4f..f967704fc2b6 100644 --- a/lib/efi_loader/efi_variable.c +++ b/lib/efi_loader/efi_variable.c @@ -25,6 +25,7 @@ enum efi_secure_mode { const efi_guid_t efi_guid_cert_type_pkcs7 = EFI_CERT_TYPE_PKCS7_GUID; static bool efi_secure_boot; static int efi_secure_mode; +static u8 efi_vendor_keys; #define READ_ONLY BIT(31) @@ -342,6 +343,8 @@ static efi_status_t efi_transfer_secure_state(enum efi_secure_mode mode) return EFI_INVALID_PARAMETER; } + efi_secure_mode = mode; + return EFI_SUCCESS; err: @@ -357,16 +360,46 @@ err: */ static efi_status_t efi_init_secure_state(void) { - efi_uintn_t size = 0; + enum efi_secure_mode mode; + efi_uintn_t size; efi_status_t ret; + /* + * TODO: + * Since there is currently no "platform-specific" installation + * method of Platform Key, we can't say if VendorKeys is 0 or 1 + * precisely. + */ + + size = 0; ret = EFI_CALL(efi_get_variable(L"PK", &efi_global_variable_guid, NULL, &size, NULL)); - if (ret == EFI_BUFFER_TOO_SMALL && IS_ENABLED(CONFIG_EFI_SECURE_BOOT)) - ret = efi_transfer_secure_state(EFI_MODE_USER); - else - ret = efi_transfer_secure_state(EFI_MODE_SETUP); + if (ret == EFI_BUFFER_TOO_SMALL) { + if (IS_ENABLED(CONFIG_EFI_SECURE_BOOT)) + mode = EFI_MODE_USER; + else + mode = EFI_MODE_SETUP; + + efi_vendor_keys = 0; + } else if (ret == EFI_NOT_FOUND) { + mode = EFI_MODE_SETUP; + efi_vendor_keys = 1; + } else { + goto err; + } + ret = efi_transfer_secure_state(mode); + if (ret == EFI_SUCCESS) + ret = efi_set_variable_internal(L"VendorKeys", + &efi_global_variable_guid, + EFI_VARIABLE_BOOTSERVICE_ACCESS + | EFI_VARIABLE_RUNTIME_ACCESS + | READ_ONLY, + sizeof(efi_vendor_keys), + &efi_vendor_keys, + false); + +err: return ret; } @@ -1122,6 +1155,8 @@ out: if (env_set(native_name, val)) { ret = EFI_DEVICE_ERROR; } else { + bool vendor_keys_modified = false; + if ((u16_strcmp(variable_name, L"PK") == 0 && guidcmp(vendor, &efi_global_variable_guid) == 0)) { ret = efi_transfer_secure_state( @@ -1129,8 +1164,30 @@ out: EFI_MODE_USER)); if (ret != EFI_SUCCESS) goto err; + + if (efi_secure_mode != EFI_MODE_SETUP) + vendor_keys_modified = true; + } else if ((u16_strcmp(variable_name, L"KEK") == 0 && + guidcmp(vendor, &efi_global_variable_guid) == 0)) { + if (efi_secure_mode != EFI_MODE_SETUP) + vendor_keys_modified = true; + } + + /* update VendorKeys */ + if (vendor_keys_modified & efi_vendor_keys) { + efi_vendor_keys = 0; + ret = efi_set_variable_internal( + L"VendorKeys", + &efi_global_variable_guid, + EFI_VARIABLE_BOOTSERVICE_ACCESS + | EFI_VARIABLE_RUNTIME_ACCESS + | READ_ONLY, + sizeof(efi_vendor_keys), + &efi_vendor_keys, + false); + } else { + ret = EFI_SUCCESS; } - ret = EFI_SUCCESS; } err: From patchwork Wed Dec 18 00:45:04 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: AKASHI Takahiro X-Patchwork-Id: 1211841 X-Patchwork-Delegate: xypron.glpk@gmx.de Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=85.214.62.61; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=linaro.org Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.b="Bike0K43"; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [85.214.62.61]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 47cxBb1X6mz9sRl for ; Wed, 18 Dec 2019 11:45:42 +1100 (AEDT) Received: from phobos.denx.de (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id D7A838169C; Wed, 18 Dec 2019 01:44:37 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=fail (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=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.b="Bike0K43"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 08C8B8168D; Wed, 18 Dec 2019 01:44:30 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-0.1 required=5.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,SPF_HELO_NONE,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.2 Received: from mail-pg1-x52d.google.com (mail-pg1-x52d.google.com [IPv6:2607:f8b0:4864:20::52d]) (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 5F5CF81634 for ; Wed, 18 Dec 2019 01:44:25 +0100 (CET) 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-pg1-x52d.google.com with SMTP id a33so254243pgm.5 for ; Tue, 17 Dec 2019 16:44:25 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=Hfg/QzJsqJ5ir/44hDrLmPFXfT6msA45lwHHvwtUKds=; b=Bike0K43ZVp4a4l6AaTmj1maFDILwuRgIcriU5VZIzpRAqj62R5ou2XBBDDgR/N+/1 aliO90/TlXM9y6bCr0e4HpDlLEDALeXGwdPEjUuXn/M2JMPXa7up07nz7TqAOpsWBpFu 92MIVVE/8+qglvEB6zo2QsqztCGn3FbuIhD3cjUFkz9Sd1WlghNEqRuQoXYfAkyjPK2P o8T5ZpmVHI8Yq4y9nCy20NhrFxNM28hjA2457vs16D96vgKw9cbJn1EcQpVT+KLYdd75 3Nc5ulitvZHhJuJm0EBYEtiS8e3iCehu1l64qApQLGnyvI98WxtYXK/Ke7hDFT2j3DMJ SgLw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=Hfg/QzJsqJ5ir/44hDrLmPFXfT6msA45lwHHvwtUKds=; b=CR34FP52gWCZEEZRiJ79Kc9w14PjGK5VYmgvPfUEA0Q+vTQB1c1fXL/eGnFdyJotZv liQIDxs3ZH7Dhz3R0ypf2WJ0yWj36jkSAMrbD3d2P6rtQNTXUwlkot0gzsZXxfgczOi0 L++4TquyWaNUi0q/t11/34vujaCW4CflpYOynEei9sGjDIgpann3PY9M4zJj2ztRfNQ9 fcIc4hy4gq6lEvphYV0TBG1FKSpoJhXSR4sRclIGzA4MlN9zzjdCtCTjGQY0/9/H8ZC7 mbnZ2NjmHsCKnRzeiDbsn1jz0xDjqtOh/9sLMM6mEFEf3Xt9CEeudag17hGLAoEMkxd+ +K0Q== X-Gm-Message-State: APjAAAWNDObWvhl/2EOExBA9SiQtP5AXLGJvxFI0cjTUwrnRe14LAuh4 3YEFRseL1Y2eA68LWmYwPR7SnVbJzBY= X-Google-Smtp-Source: APXvYqzx4LGS/m+oGtTNEiswsBN7Aii9B+VN21blGKYbAcrjBiJbP6KMe9AqICy+VX2NiTfOLw1x3w== X-Received: by 2002:a63:1853:: with SMTP id 19mr821601pgy.170.1576629863526; Tue, 17 Dec 2019 16:44:23 -0800 (PST) Received: from linaro.org ([121.95.100.191]) by smtp.googlemail.com with ESMTPSA id l8sm137291pjy.24.2019.12.17.16.44.22 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 17 Dec 2019 16:44:22 -0800 (PST) From: AKASHI Takahiro To: xypron.glpk@gmx.de, agraf@csgraf.de, trini@konsulko.com Subject: [PATCH v4 08/16] efi_loader: image_loader: support image authentication Date: Wed, 18 Dec 2019 09:45:04 +0900 Message-Id: <20191218004512.24939-9-takahiro.akashi@linaro.org> X-Mailer: git-send-email 2.24.0 In-Reply-To: <20191218004512.24939-1-takahiro.akashi@linaro.org> References: <20191218004512.24939-1-takahiro.akashi@linaro.org> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.26 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: u-boot@lists.denx.de, mail@patrick-wildt.de Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.101.4 at phobos.denx.de X-Virus-Status: Clean With this commit, image validation can be enforced, as UEFI specification section 32.5 describes, if CONFIG_EFI_SECURE_BOOT is enabled. Currently we support * authentication based on db and dbx, so dbx-validated image will always be rejected. * following signature types: EFI_CERT_SHA256_GUID (SHA256 digest for unsigned images) EFI_CERT_X509_GUID (x509 certificate for signed images) Timestamp-based certificate revocation is not supported here. Internally, authentication data is stored in one of certificates tables of PE image (See efi_image_parse()) and will be verified by efi_image_authenticate() before loading a given image. It seems that UEFI specification defines the verification process in a bit ambiguous way. I tried to implement it as closely to as EDK2 does. Signed-off-by: AKASHI Takahiro --- include/efi_loader.h | 7 +- lib/efi_loader/efi_boottime.c | 2 +- lib/efi_loader/efi_image_loader.c | 454 +++++++++++++++++++++++++++++- 3 files changed, 449 insertions(+), 14 deletions(-) diff --git a/include/efi_loader.h b/include/efi_loader.h index 1f88caf86709..e12b49098fb0 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -11,6 +11,7 @@ #include #include #include +#include static inline int guidcmp(const void *g1, const void *g2) { @@ -398,7 +399,8 @@ efi_status_t efi_set_watchdog(unsigned long timeout); /* Called from places to check whether a timer expired */ void efi_timer_check(void); /* PE loader implementation */ -efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle, void *efi, +efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle, + void *efi, size_t efi_size, struct efi_loaded_image *loaded_image_info); /* Called once to store the pristine gd pointer */ void efi_save_gd(void); @@ -726,6 +728,9 @@ void efi_sigstore_free(struct efi_signature_store *sigstore); struct efi_signature_store *efi_sigstore_parse_sigdb(u16 *name); bool efi_secure_boot_enabled(void); + +bool efi_image_parse(void *efi, size_t len, struct efi_image_regions **regp, + WIN_CERTIFICATE **auth, size_t *auth_len); #endif /* CONFIG_EFI_SECURE_BOOT */ #else /* CONFIG_IS_ENABLED(EFI_LOADER) */ diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 493d906c641d..311681764034 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -1879,7 +1879,7 @@ efi_status_t EFIAPI efi_load_image(bool boot_policy, efi_dp_split_file_path(file_path, &dp, &fp); ret = efi_setup_loaded_image(dp, fp, image_obj, &info); if (ret == EFI_SUCCESS) - ret = efi_load_pe(*image_obj, dest_buffer, info); + ret = efi_load_pe(*image_obj, dest_buffer, source_size, info); if (!source_buffer) /* Release buffer to which file was loaded */ efi_free_pages((uintptr_t)dest_buffer, diff --git a/lib/efi_loader/efi_image_loader.c b/lib/efi_loader/efi_image_loader.c index 13541cfa7a28..939758e61e3c 100644 --- a/lib/efi_loader/efi_image_loader.c +++ b/lib/efi_loader/efi_image_loader.c @@ -9,7 +9,9 @@ #include #include +#include #include +#include "../lib/crypto/pkcs7_parser.h" const efi_guid_t efi_global_variable_guid = EFI_GLOBAL_VARIABLE_GUID; const efi_guid_t efi_guid_device_path = EFI_DEVICE_PATH_PROTOCOL_GUID; @@ -205,6 +207,367 @@ static void efi_set_code_and_data_type( } } +#ifdef CONFIG_EFI_SECURE_BOOT +/** + * efi_image_parse - parse a PE image + * @efi: Pointer to image + * @len: Size of @efi + * @regs: Pointer to a list of regions + * @auth: Pointer to a pointer to authentication data in PE + * @auth_len: Size of @auth + * + * Parse image binary in PE32(+) format, assuming that sanity of PE image + * has been checked by a caller. + * On success, an address of authentication data in @efi and its size will + * be returned in @auth and @auth_len, respectively. + * + * Return: true on success, false on error + */ +bool efi_image_parse(void *efi, size_t len, struct efi_image_regions **regp, + WIN_CERTIFICATE **auth, size_t *auth_len) +{ + struct efi_image_regions *regs; + IMAGE_DOS_HEADER *dos; + IMAGE_NT_HEADERS32 *nt; + IMAGE_SECTION_HEADER *sections, **sorted; + int num_regions, num_sections, i, j; + int ctidx = IMAGE_DIRECTORY_ENTRY_SECURITY; + u32 align, size, authsz, authoff; + size_t bytes_hashed; + + dos = (void *)efi; + nt = (void *)(efi + dos->e_lfanew); + + /* + * Count maximum number of regions to be digested. + * We don't have to have an exact number here. + * See efi_image_region_add()'s in parsing below. + */ + num_regions = 3; /* for header */ + num_regions += nt->FileHeader.NumberOfSections; + num_regions++; /* for extra */ + + regs = calloc(sizeof(*regs) + sizeof(struct image_region) * num_regions, + 1); + if (!regs) + goto err; + regs->max = num_regions; + + /* + * Collect data regions for hash calculation + * 1. File headers + */ + if (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) { + IMAGE_NT_HEADERS64 *nt64 = (void *)nt; + IMAGE_OPTIONAL_HEADER64 *opt = &nt64->OptionalHeader; + + /* Skip CheckSum */ + efi_image_region_add(regs, efi, &opt->CheckSum, 0); + if (nt64->OptionalHeader.NumberOfRvaAndSizes <= ctidx) { + efi_image_region_add(regs, + &opt->CheckSum + 1, + efi + opt->SizeOfHeaders, 0); + } else { + /* Skip Certificates Table */ + efi_image_region_add(regs, + &opt->CheckSum + 1, + &opt->DataDirectory[ctidx], 0); + efi_image_region_add(regs, + &opt->DataDirectory[ctidx] + 1, + efi + opt->SizeOfHeaders, 0); + } + + bytes_hashed = opt->SizeOfHeaders; + align = opt->FileAlignment; + authoff = opt->DataDirectory[ctidx].VirtualAddress; + authsz = opt->DataDirectory[ctidx].Size; + } else if (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + IMAGE_OPTIONAL_HEADER32 *opt = &nt->OptionalHeader; + + efi_image_region_add(regs, efi, &opt->CheckSum, 0); + efi_image_region_add(regs, &opt->CheckSum + 1, + &opt->DataDirectory[ctidx], 0); + efi_image_region_add(regs, &opt->DataDirectory[ctidx] + 1, + efi + opt->SizeOfHeaders, 0); + + bytes_hashed = opt->SizeOfHeaders; + align = opt->FileAlignment; + authoff = opt->DataDirectory[ctidx].VirtualAddress; + authsz = opt->DataDirectory[ctidx].Size; + } else { + debug("%s: Invalid optional header magic %x\n", __func__, + nt->OptionalHeader.Magic); + goto err; + } + + /* 2. Sections */ + num_sections = nt->FileHeader.NumberOfSections; + sections = (void *)((uint8_t *)&nt->OptionalHeader + + nt->FileHeader.SizeOfOptionalHeader); + sorted = calloc(sizeof(IMAGE_SECTION_HEADER *), num_sections); + if (!sorted) { + debug("%s: Out of memory\n", __func__); + goto err; + } + + /* + * Make sure the section list is in ascending order. + * As we can assume that it is already ordered in most cases, + * the following code is optimized for this. + */ + for (sorted[0] = §ions[0], i = 1; i < num_sections; i++) { + if (sorted[i - 1]->VirtualAddress + <= sections[i].VirtualAddress) { + sorted[i] = §ions[i]; + } else { + if (i == 1) { + sorted[1] = sorted[0]; + sorted[0] = §ions[1]; + continue; + } + + sorted[i] = sorted[i - 1]; + for (j = i - 2; j >= 0; j--) { + if (!j || sorted[j]->VirtualAddress + <= sections[i].VirtualAddress) { + sorted[j + 1] = §ions[i]; + continue; + } else { + sorted[j + 1] = sorted[j]; + } + } + } + } + + for (i = 0; i < num_sections; i++) { + if (!sorted[i]->SizeOfRawData) + continue; + + size = (sorted[i]->SizeOfRawData + align - 1) & ~(align - 1); + efi_image_region_add(regs, efi + sorted[i]->PointerToRawData, + efi + sorted[i]->PointerToRawData + size, + 0); + debug("section[%d](%s): raw: 0x%x-0x%x, virt: %x-%x\n", + i, sorted[i]->Name, + sorted[i]->PointerToRawData, + sorted[i]->PointerToRawData + size, + sorted[i]->VirtualAddress, + sorted[i]->VirtualAddress + + sorted[i]->Misc.VirtualSize); + + bytes_hashed += size; + } + free(sorted); + + /* 3. Extra data excluding Certificates Table */ + if (bytes_hashed + authsz < len) { + debug("extra data for hash: %lu\n", + len - (bytes_hashed + authsz)); + efi_image_region_add(regs, efi + bytes_hashed, + efi + len - authsz, 0); + } + + /* Return Certificates Table */ + if (authsz) { + if (len < authoff + authsz) { + debug("%s: Size for auth too large: %u >= %zu\n", + __func__, authsz, len - authoff); + goto err; + } + if (authsz < sizeof(*auth)) { + debug("%s: Size for auth too small: %u < %zu\n", + __func__, authsz, sizeof(*auth)); + goto err; + } + *auth = efi + authoff; + *auth_len = authsz; + debug("WIN_CERTIFICATE: 0x%x, size: 0x%x\n", authoff, authsz); + } else { + *auth = NULL; + *auth_len = 0; + } + + *regp = regs; + + return true; + +err: + free(regs); + + return false; +} + +/** + * efi_image_unsigned_authenticate - authenticate unsigned image with + * SHA256 hash + * @regs: List of regions to be verified + * + * If an image is not signed, it doesn't have a signature. In this case, + * its message digest is calculated and it will be compared with one of + * hash values stored in signature databases. + * + * Return: true if authenticated, false if not + */ +static bool efi_image_unsigned_authenticate(struct efi_image_regions *regs) +{ + struct efi_signature_store *db = NULL, *dbx = NULL; + bool ret = false; + + dbx = efi_sigstore_parse_sigdb(L"dbx"); + if (!dbx) { + debug("Getting signature database(dbx) failed\n"); + goto out; + } + + db = efi_sigstore_parse_sigdb(L"db"); + if (!db) { + debug("Getting signature database(db) failed\n"); + goto out; + } + + /* try black-list first */ + if (efi_signature_verify_with_sigdb(regs, NULL, dbx, NULL)) { + debug("Image is not signed and rejected by \"dbx\"\n"); + goto out; + } + + /* try white-list */ + if (efi_signature_verify_with_sigdb(regs, NULL, db, NULL)) + ret = true; + else + debug("Image is not signed and not found in \"db\" or \"dbx\"\n"); + +out: + efi_sigstore_free(db); + efi_sigstore_free(dbx); + + return ret; +} + +/** + * efi_image_authenticate - verify a signature of signed image + * @efi: Pointer to image + * @len: Size of @efi + * + * A signed image should have its signature stored in a table of its PE header. + * So if an image is signed and only if if its signature is verified using + * signature databases, an image is authenticated. + * If an image is not signed, its validity is checked by using + * efi_image_unsigned_authenticated(). + * TODO: + * When AuditMode==0, if the image's signature is not found in + * the authorized database, or is found in the forbidden database, + * the image will not be started and instead, information about it + * will be placed in this table. + * When AuditMode==1, an EFI_IMAGE_EXECUTION_INFO element is created + * in the EFI_IMAGE_EXECUTION_INFO_TABLE for every certificate found + * in the certificate table of every image that is validated. + * + * Return: true if authenticated, false if not + */ +static bool efi_image_authenticate(void *efi, size_t len) +{ + struct efi_image_regions *regs = NULL; + WIN_CERTIFICATE *wincerts = NULL, *wincert; + size_t wincerts_len; + struct pkcs7_message *msg = NULL; + struct efi_signature_store *db = NULL, *dbx = NULL; + struct x509_certificate *cert = NULL; + bool ret = false; + + if (!efi_secure_boot_enabled()) + return true; + + if (!efi_image_parse(efi, len, ®s, &wincerts, + &wincerts_len)) { + debug("Parsing PE executable image failed\n"); + return false; + } + + if (!wincerts) { + /* The image is not signed */ + ret = efi_image_unsigned_authenticate(regs); + free(regs); + + return ret; + } + + /* + * verify signature using db and dbx + */ + db = efi_sigstore_parse_sigdb(L"db"); + if (!db) { + debug("Getting signature database(db) failed\n"); + goto err; + } + + dbx = efi_sigstore_parse_sigdb(L"dbx"); + if (!dbx) { + debug("Getting signature database(dbx) failed\n"); + goto err; + } + + /* go through WIN_CERTIFICATE list */ + for (wincert = wincerts; + (void *)wincert < (void *)wincerts + wincerts_len; + wincert = (void *)wincert + ALIGN(wincert->dwLength, 8)) { + if (wincert->dwLength < sizeof(*wincert)) { + debug("%s: dwLength too small: %u < %zu\n", + __func__, wincert->dwLength, sizeof(*wincert)); + goto err; + } + msg = pkcs7_parse_message((void *)wincert + sizeof(*wincert), + wincert->dwLength - sizeof(*wincert)); + if (!msg) { + debug("Parsing image's signature failed\n"); + goto err; + } + + /* try black-list first */ + if (efi_signature_verify_with_sigdb(regs, msg, dbx, NULL)) { + debug("Signature was rejected by \"dbx\"\n"); + goto err; + } + + if (!efi_signature_verify_signers(msg, dbx)) { + debug("Signer was rejected by \"dbx\"\n"); + goto err; + } else { + ret = true; + } + + /* try white-list */ + if (!efi_signature_verify_with_sigdb(regs, msg, db, &cert)) { + debug("Verifying signature with \"db\" failed\n"); + goto err; + } else { + ret = true; + } + + if (!efi_signature_verify_cert(cert, dbx)) { + debug("Certificate was rejected by \"dbx\"\n"); + goto err; + } else { + ret = true; + } + } + +err: + x509_free_certificate(cert); + efi_sigstore_free(db); + efi_sigstore_free(dbx); + pkcs7_free_message(msg); + free(regs); + + return ret; +} +#else +static bool efi_image_authenticate(void *efi, size_t len) +{ + return true; +} +#endif /* CONFIG_EFI_SECURE_BOOT */ + /** * efi_load_pe() - relocate EFI binary * @@ -216,7 +579,8 @@ static void efi_set_code_and_data_type( * @loaded_image_info: loaded image protocol * Return: status code */ -efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle, void *efi, +efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle, + void *efi, size_t efi_size, struct efi_loaded_image *loaded_image_info) { IMAGE_NT_HEADERS32 *nt; @@ -231,17 +595,57 @@ efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle, void *efi, uint64_t image_base; unsigned long virt_size = 0; int supported = 0; + void *new_efi = NULL; + size_t new_efi_size; + efi_status_t ret; + + /* + * Size must be 8-byte aligned and the trailing bytes must be + * zero'ed. Otherwise hash value may be incorrect. + */ + if (efi_size & 0x7) { + new_efi_size = (efi_size + 0x7) & ~0x7ULL; + new_efi = calloc(new_efi_size, 1); + if (!new_efi) + return EFI_OUT_OF_RESOURCES; + memcpy(new_efi, efi, efi_size); + efi = new_efi; + efi_size = new_efi_size; + } + + /* Sanity check for a file header */ + if (efi_size < sizeof(*dos)) { + printf("%s: Truncated DOS Header\n", __func__); + ret = EFI_LOAD_ERROR; + goto err; + } dos = efi; if (dos->e_magic != IMAGE_DOS_SIGNATURE) { printf("%s: Invalid DOS Signature\n", __func__); - return EFI_LOAD_ERROR; + ret = EFI_LOAD_ERROR; + goto err; + } + + /* assume sizeof(IMAGE_NT_HEADERS32) <= sizeof(IMAGE_NT_HEADERS64) */ + if (efi_size < dos->e_lfanew + sizeof(IMAGE_NT_HEADERS32)) { + printf("%s: Invalid offset for Extended Header\n", __func__); + ret = EFI_LOAD_ERROR; + goto err; } nt = (void *) ((char *)efi + dos->e_lfanew); + if ((nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) && + (efi_size < dos->e_lfanew + sizeof(IMAGE_NT_HEADERS64))) { + printf("%s: Invalid offset for Extended Header\n", __func__); + ret = EFI_LOAD_ERROR; + goto err; + } + if (nt->Signature != IMAGE_NT_SIGNATURE) { printf("%s: Invalid NT Signature\n", __func__); - return EFI_LOAD_ERROR; + ret = EFI_LOAD_ERROR; + goto err; } for (i = 0; machines[i]; i++) @@ -253,14 +657,29 @@ efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle, void *efi, if (!supported) { printf("%s: Machine type 0x%04x is not supported\n", __func__, nt->FileHeader.Machine); - return EFI_LOAD_ERROR; + ret = EFI_LOAD_ERROR; + goto err; } - /* Calculate upper virtual address boundary */ num_sections = nt->FileHeader.NumberOfSections; sections = (void *)&nt->OptionalHeader + nt->FileHeader.SizeOfOptionalHeader; + if (efi_size < ((void *)sections + sizeof(sections[0]) * num_sections + - efi)) { + printf("%s: Invalid number of sections: %d\n", + __func__, num_sections); + ret = EFI_LOAD_ERROR; + goto err; + } + + /* Authenticate an image */ + if (!efi_image_authenticate(efi, efi_size)) { + ret = EFI_ACCESS_DENIED; + goto err; + } + + /* Calculate upper virtual address boundary */ for (i = num_sections - 1; i >= 0; i--) { IMAGE_SECTION_HEADER *sec = §ions[i]; virt_size = max_t(unsigned long, virt_size, @@ -279,7 +698,8 @@ efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle, void *efi, if (!efi_reloc) { printf("%s: Could not allocate %lu bytes\n", __func__, virt_size); - return EFI_OUT_OF_RESOURCES; + ret = EFI_OUT_OF_RESOURCES; + goto err; } handle->entry = efi_reloc + opt->AddressOfEntryPoint; rel_size = opt->DataDirectory[rel_idx].Size; @@ -295,7 +715,8 @@ efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle, void *efi, if (!efi_reloc) { printf("%s: Could not allocate %lu bytes\n", __func__, virt_size); - return EFI_OUT_OF_RESOURCES; + ret = EFI_OUT_OF_RESOURCES; + goto err; } handle->entry = efi_reloc + opt->AddressOfEntryPoint; rel_size = opt->DataDirectory[rel_idx].Size; @@ -304,13 +725,16 @@ efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle, void *efi, } else { printf("%s: Invalid optional header magic %x\n", __func__, nt->OptionalHeader.Magic); - return EFI_LOAD_ERROR; + ret = EFI_LOAD_ERROR; + goto err; } /* Copy PE headers */ - memcpy(efi_reloc, efi, sizeof(*dos) + sizeof(*nt) - + nt->FileHeader.SizeOfOptionalHeader - + num_sections * sizeof(IMAGE_SECTION_HEADER)); + memcpy(efi_reloc, efi, + sizeof(*dos) + + sizeof(*nt) + + nt->FileHeader.SizeOfOptionalHeader + + num_sections * sizeof(IMAGE_SECTION_HEADER)); /* Load sections into RAM */ for (i = num_sections - 1; i >= 0; i--) { @@ -327,7 +751,8 @@ efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle, void *efi, (unsigned long)image_base) != EFI_SUCCESS) { efi_free_pages((uintptr_t) efi_reloc, (virt_size + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT); - return EFI_LOAD_ERROR; + ret = EFI_LOAD_ERROR; + goto err; } /* Flush cache */ @@ -340,4 +765,9 @@ efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle, void *efi, loaded_image_info->image_size = virt_size; return EFI_SUCCESS; + +err: + free(new_efi); + + return ret; } From patchwork Wed Dec 18 00:45:05 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: AKASHI Takahiro X-Patchwork-Id: 1211842 X-Patchwork-Delegate: xypron.glpk@gmx.de Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=85.214.62.61; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=linaro.org Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.b="iMJcFE+8"; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [85.214.62.61]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 47cxBn3MK4z9sRl for ; Wed, 18 Dec 2019 11:45:53 +1100 (AEDT) Received: from phobos.denx.de (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 538AB816B4; Wed, 18 Dec 2019 01:44:40 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=fail (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=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.b="iMJcFE+8"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id C5D7D8169C; Wed, 18 Dec 2019 01:44:31 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-0.1 required=5.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,SPF_HELO_NONE,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.2 Received: from mail-pj1-x1043.google.com (mail-pj1-x1043.google.com [IPv6:2607:f8b0:4864:20::1043]) (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 1115E81675 for ; Wed, 18 Dec 2019 01:44:28 +0100 (CET) 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-pj1-x1043.google.com with SMTP id s94so536563pjc.1 for ; Tue, 17 Dec 2019 16:44:27 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=TEAEDj9erVipp4yLLE2gQ4KtxKQihSj29/GQcgpNpqU=; b=iMJcFE+8OClA88B823GY8Dh7msXOktGlK92COGqgX/JN2kCM+CN4KMopivob9xwytS k+qeFpJvyN5Ex5J4ELKXctaZM2tx9dFVwYj6vOTqExe9RxDNde0GLHR0F/HdZUfB9HBe BdZXP5DM5twjX18SNFufF7qTPxaIdN6vgK14NYq0nnjf5MIe8xwkFLaNuBz+hLkuyvmz 1KHY98k6aoHb6cK9ATPkoFQfXOEKzCXQf2R9IYXrnbHL/DzbkbxomFPDcymRSw7F8SMn ucEP2Fo9Mlexx7voe5OXMJCf+a4dMCQh+RqvT/lly/sikezpCYbOrccj+ALOzmjWrp0U 8C4w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=TEAEDj9erVipp4yLLE2gQ4KtxKQihSj29/GQcgpNpqU=; b=D0ZGs6AsQTE5FLB4KvIXRF4yNCycSFQmXF9o1f1NyV1GeV6r36Zx30JEotUcxgVP76 b4Xd6b1PP5QVunGJa+kOaU8WATQ+BsjLCKQ5sLBQ0lcTipWcCzoIfmpHqannP0qddTor q81OXDIPGbWw4W5mq4rYJNJB3BI2s70FQSV6obkJ72PojjzApQTs28Z72VIUlRBg8vXl xuDTcT+TaPSgNBoB0Yh7MKbpFaqe4ami0So01DS7zy28theQfMiv0UuG6srjRcDarVoN MGq2ehTpIq2tzYLe1iUHaevsfviXT1ydD0SXJvtGMbMh87K3UUvu7ztd4PjfOMn1T8Hl W7qg== X-Gm-Message-State: APjAAAVO0ZADCYL2VLdYSdCqR0/IoIDQ9gZ/townsUUEr204IctDJz1v 0YzsD3kpvTIvKhXWUc/3dhC9dg== X-Google-Smtp-Source: APXvYqxEydMM2UJ6s/NDuaHqP1sfb/MlPE2RxuVQ7eqW+Z28AbbFKv9wIAWdBy40SK9e8aeHZMJjqg== X-Received: by 2002:a17:90a:e98a:: with SMTP id v10mr153618pjy.67.1576629866660; Tue, 17 Dec 2019 16:44:26 -0800 (PST) Received: from linaro.org ([121.95.100.191]) by smtp.googlemail.com with ESMTPSA id q8sm185269pgg.92.2019.12.17.16.44.25 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 17 Dec 2019 16:44:26 -0800 (PST) From: AKASHI Takahiro To: xypron.glpk@gmx.de, agraf@csgraf.de, trini@konsulko.com Subject: [PATCH v4 09/16] efi_loader: set up secure boot Date: Wed, 18 Dec 2019 09:45:05 +0900 Message-Id: <20191218004512.24939-10-takahiro.akashi@linaro.org> X-Mailer: git-send-email 2.24.0 In-Reply-To: <20191218004512.24939-1-takahiro.akashi@linaro.org> References: <20191218004512.24939-1-takahiro.akashi@linaro.org> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.26 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: u-boot@lists.denx.de, mail@patrick-wildt.de Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.101.4 at phobos.denx.de X-Virus-Status: Clean The following variable is exported as UEFI specification defines: SignatureSupport: array of GUIDs representing the type of signatures supported by the platform firmware Signed-off-by: AKASHI Takahiro --- lib/efi_loader/efi_setup.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/lib/efi_loader/efi_setup.c b/lib/efi_loader/efi_setup.c index de7b616c6daa..50cef1b4dfde 100644 --- a/lib/efi_loader/efi_setup.c +++ b/lib/efi_loader/efi_setup.c @@ -82,6 +82,39 @@ out: return ret; } +#ifdef CONFIG_EFI_SECURE_BOOT +/** + * efi_init_secure_boot - initialize secure boot state + * + * Return: EFI_SUCCESS on success, status code (negative) on error + */ +static efi_status_t efi_init_secure_boot(void) +{ + efi_guid_t signature_types[] = { + EFI_CERT_SHA256_GUID, + EFI_CERT_X509_GUID, + }; + efi_status_t ret; + + /* TODO: read-only */ + ret = EFI_CALL(efi_set_variable(L"SignatureSupport", + &efi_global_variable_guid, + EFI_VARIABLE_BOOTSERVICE_ACCESS + | EFI_VARIABLE_RUNTIME_ACCESS, + sizeof(signature_types), + &signature_types)); + if (ret != EFI_SUCCESS) + printf("EFI: cannot initialize SignatureSupport variable\n"); + + return ret; +} +#else +static efi_status_t efi_init_secure_boot(void) +{ + return EFI_SUCCESS; +} +#endif /* CONFIG_EFI_SECURE_BOOT */ + /** * efi_init_obj_list() - Initialize and populate EFI object list * @@ -122,6 +155,11 @@ efi_status_t efi_init_obj_list(void) if (ret != EFI_SUCCESS) goto out; + /* Secure boot */ + ret = efi_init_secure_boot(); + if (ret != EFI_SUCCESS) + goto out; + /* Indicate supported runtime services */ ret = efi_init_runtime_supported(); if (ret != EFI_SUCCESS) From patchwork Wed Dec 18 00:45:06 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: AKASHI Takahiro X-Patchwork-Id: 1211843 X-Patchwork-Delegate: xypron.glpk@gmx.de Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=85.214.62.61; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=linaro.org Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.b="iulZ0U1t"; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [85.214.62.61]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 47cxC009Y3z9sRl for ; Wed, 18 Dec 2019 11:46:03 +1100 (AEDT) Received: from phobos.denx.de (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 0570C816CC; Wed, 18 Dec 2019 01:44:42 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=fail (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=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.b="iulZ0U1t"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id AEA04816A5; Wed, 18 Dec 2019 01:44:34 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-0.1 required=5.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,SPF_HELO_NONE,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.2 Received: from mail-pj1-x1042.google.com (mail-pj1-x1042.google.com [IPv6:2607:f8b0:4864:20::1042]) (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 41DBA8168D for ; Wed, 18 Dec 2019 01:44:31 +0100 (CET) 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-pj1-x1042.google.com with SMTP id n67so35653pjb.5 for ; Tue, 17 Dec 2019 16:44:31 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=7NnQ4scfGaB0+MbEXK3RzIJ7PfVEr7Wa7A51zEDPSaE=; b=iulZ0U1tuI1BXTJmSAe0NduFD0su/uAscj1B6+hGP2PEh7qJl6PrwCBtE6hp5THC2m dZCeFEjmOFjZl2eNzWS+9Q3neRXTcHRwj/rPKh9hfCIA8Uu9m8gIMb8oDzbGBz3fZXgs +8CsKQSpsVngRaVvTWDrvk9tgHSklfNbr9gYy2wb0KojMmB9vWRZP9slX6o3yoUd7MjR cA9yWsWZ/NONv0bEx9yya7SrBIcvH6dtUSBvTLQEUPuXdS/+DrPL3i2Hr7PtagyrmYl4 MMz24HN8NXz5hYNnge/XhdeY5J2dNbqQTvgpe+4pm3A7KoBTeRnH4SQdwwJSsUDqTBF1 wDFw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=7NnQ4scfGaB0+MbEXK3RzIJ7PfVEr7Wa7A51zEDPSaE=; b=IhH97QySb5m1bedqB5pKRmxyYoEqLuPCAtO5e/2Cw2Ua0mtMqr5bEKcOPZoE7KjXUw 9V8Pko4JQRa2WUlG6khHAMFGjQcXnF1AkZ3PdHwUWbbVChL97/iKZaM/A9EmXQnpuJah qDyD3sLD/fVeYHnVWk1KWMZcM/PgMsqlKAy/jfDCZKBxziK8Revav81Pie+aufOlrF1p Hsu/nUTBPaTvhSSNSCksK8cgfGZ8lD5sNS2rPuAEj4f58NHYLY7/SniKjSWVg6c3TYOK yA7qcC134DSlGNFJaopAQz0vbmlzvFOq1Kae7lFcoZ4Z8RO2HkJg4gSMtQXFPFf/ZlEb lNgA== X-Gm-Message-State: APjAAAVFDiBM6PTeeFA5Ywa3snMpJn6BLFwrbTsKvZ9FnMpNJwrr17/q +fAdHvmcVxSkhDRWl/Zoe4UGag== X-Google-Smtp-Source: APXvYqyqFGrT6Fe3C++S1hWz2QhvGjtc6kea+41+lK2lh9SlcBoOb39/YMw9ifXZvLRfktnwbBvF5w== X-Received: by 2002:a17:902:7c83:: with SMTP id y3mr1095447pll.34.1576629869758; Tue, 17 Dec 2019 16:44:29 -0800 (PST) Received: from linaro.org ([121.95.100.191]) by smtp.googlemail.com with ESMTPSA id 189sm258025pfw.73.2019.12.17.16.44.28 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 17 Dec 2019 16:44:29 -0800 (PST) From: AKASHI Takahiro To: xypron.glpk@gmx.de, agraf@csgraf.de, trini@konsulko.com Subject: [PATCH v4 10/16] cmd: env: use appropriate guid for authenticated UEFI variable Date: Wed, 18 Dec 2019 09:45:06 +0900 Message-Id: <20191218004512.24939-11-takahiro.akashi@linaro.org> X-Mailer: git-send-email 2.24.0 In-Reply-To: <20191218004512.24939-1-takahiro.akashi@linaro.org> References: <20191218004512.24939-1-takahiro.akashi@linaro.org> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.26 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: u-boot@lists.denx.de, mail@patrick-wildt.de Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.101.4 at phobos.denx.de X-Virus-Status: Clean A signature database variable is associated with a specific guid. For convenience, if user doesn't supply any guid info, "env set|print -e" should complement it. Signed-off-by: AKASHI Takahiro --- cmd/nvedit_efi.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/cmd/nvedit_efi.c b/cmd/nvedit_efi.c index 8ea0da01283f..579cf430593c 100644 --- a/cmd/nvedit_efi.c +++ b/cmd/nvedit_efi.c @@ -41,6 +41,11 @@ static const struct { } efi_guid_text[] = { /* signature database */ {EFI_GLOBAL_VARIABLE_GUID, "EFI_GLOBAL_VARIABLE_GUID"}, + {EFI_IMAGE_SECURITY_DATABASE_GUID, "EFI_IMAGE_SECURITY_DATABASE_GUID"}, + /* certificate type */ + {EFI_CERT_SHA256_GUID, "EFI_CERT_SHA256_GUID"}, + {EFI_CERT_X509_GUID, "EFI_CERT_X509_GUID"}, + {EFI_CERT_TYPE_PKCS7_GUID, "EFI_CERT_TYPE_PKCS7_GUID"}, }; /* "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" */ @@ -525,9 +530,9 @@ int do_env_set_efi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) if (*ep != ',') return CMD_RET_USAGE; + /* 0 should be allowed for delete */ size = simple_strtoul(++ep, NULL, 16); - if (!size) - return CMD_RET_FAILURE; + value_on_memory = true; } else if (!strcmp(argv[0], "-v")) { verbose = true; @@ -539,8 +544,13 @@ int do_env_set_efi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) return CMD_RET_USAGE; var_name = argv[0]; - if (default_guid) - guid = efi_global_variable_guid; + if (default_guid) { + if (!strcmp(var_name, "db") || !strcmp(var_name, "dbx") || + !strcmp(var_name, "dbt")) + guid = efi_guid_image_security_database; + else + guid = efi_global_variable_guid; + } if (verbose) { printf("GUID: %s\n", efi_guid_to_str((const efi_guid_t *) From patchwork Wed Dec 18 00:45:07 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: AKASHI Takahiro X-Patchwork-Id: 1211844 X-Patchwork-Delegate: xypron.glpk@gmx.de Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=linaro.org Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.b="BKgIc05L"; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [IPv6:2a01:238:438b:c500:173d:9f52:ddab:ee01]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 47cxCN5jgkz9sRl for ; Wed, 18 Dec 2019 11:46:24 +1100 (AEDT) Received: from phobos.denx.de (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id AD47E816C5; Wed, 18 Dec 2019 01:44:46 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=fail (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=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.b="BKgIc05L"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 618278168D; Wed, 18 Dec 2019 01:44:37 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-0.1 required=5.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,SPF_HELO_NONE,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.2 Received: from mail-pf1-x444.google.com (mail-pf1-x444.google.com [IPv6:2607:f8b0:4864:20::444]) (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 777928169C for ; Wed, 18 Dec 2019 01:44:34 +0100 (CET) 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-pf1-x444.google.com with SMTP id x185so202224pfc.5 for ; Tue, 17 Dec 2019 16:44:34 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=HayICzzsx87HHZXT8BNgrL0JMhk/uqSDY5FT/MLk+mk=; b=BKgIc05LdBQC7Dn6IoersXvmszbUyYV+Poh+EYgYB2+ufybhcBV8GvCdFLhBvn7oUc 7/SlzL2HOZaKmlkVNF4yruSdO6kOoPtZmkCDulG/KYVE2aUYAMQnbjoai1EzNeUI0nao HokOKrHz3NUPiax14HDI4vLm0YUoPL+3/jD4RmiGaScdfGRJlCR7Tfu9zmfVTKyvX2QE vAq9SiSrY8AExy6MLD2aUfLN8tkhjYxI1t31W/I3l7/yxV3f5FEayu7ORSTWb+p9pJEH iUyNRit3wBB/zduepANK/YkzrPP5E2dByOb+CnbruIm7lRecVM1F5oLtfy9/3DkNyE4O 6jpA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=HayICzzsx87HHZXT8BNgrL0JMhk/uqSDY5FT/MLk+mk=; b=m5FB391OWfssH7WFQCBxbU7EYkmKOm6R/gqIyW8jw439/fz0LBS2O/e/k5/k+x8K21 fSXdzN2OBkp52UsfitvP6EQQXZzgSpnwSEq8z7Id1gsH4Undlp1okVdAoFxrCo6T63iB vf/icmtmtGjmXECt633kwcZlUEI8ql0xsEq3cM/IgmwPgKM/IhwrXutW84/OPn2WcMmA 1fEGvRHnurmrlkqGyJYVf9WdIzEnF6pEcnnbdBNauJnkk4OWyVK0a7IZn6Hf7zXbUucv /21VsFJDsbIyL5g0jb4KEgku+zA6o2B5APb4vHzQyMwyzdTfeTOy2DI7R0whDmfG+yoY YQcg== X-Gm-Message-State: APjAAAU+C1faTcqrdl1WEUwhfo9pJvJNxHauV/NN57PyTHQ9Be6EcLmD ADsgL/bGsN50pMlIDFca+L2LJg== X-Google-Smtp-Source: APXvYqzjVAXLrndZxXTBJr4QjLRzAbhRdRMLXR1AhtDRrH+zq8cL5pAu9eYZdnrCaW4R6Df90COORQ== X-Received: by 2002:a63:d705:: with SMTP id d5mr852860pgg.24.1576629872890; Tue, 17 Dec 2019 16:44:32 -0800 (PST) Received: from linaro.org ([121.95.100.191]) by smtp.googlemail.com with ESMTPSA id z130sm219020pgz.6.2019.12.17.16.44.31 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 17 Dec 2019 16:44:32 -0800 (PST) From: AKASHI Takahiro To: xypron.glpk@gmx.de, agraf@csgraf.de, trini@konsulko.com Subject: [PATCH v4 11/16] cmd: env: add "-at" option to "env set -e" command Date: Wed, 18 Dec 2019 09:45:07 +0900 Message-Id: <20191218004512.24939-12-takahiro.akashi@linaro.org> X-Mailer: git-send-email 2.24.0 In-Reply-To: <20191218004512.24939-1-takahiro.akashi@linaro.org> References: <20191218004512.24939-1-takahiro.akashi@linaro.org> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.26 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: u-boot@lists.denx.de, mail@patrick-wildt.de Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.101.4 at phobos.denx.de X-Virus-Status: Clean With "-at" option, EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS will be passed to SetVariable() to authenticate the variable. Signed-off-by: AKASHI Takahiro --- cmd/nvedit.c | 5 +++-- cmd/nvedit_efi.c | 5 ++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/cmd/nvedit.c b/cmd/nvedit.c index 99a3bc57b15f..30cd655b7260 100644 --- a/cmd/nvedit.c +++ b/cmd/nvedit.c @@ -1399,7 +1399,7 @@ static char env_help_text[] = #endif #endif #if defined(CONFIG_CMD_NVEDIT_EFI) - "env set -e [-nv][-bs][-rt][-a][-i addr,size][-v] name [arg ...]\n" + "env set -e [-nv][-bs][-rt][-at][-a][-i addr,size][-v] name [arg ...]\n" " - set UEFI variable; unset if '-i' or 'arg' not specified\n" #endif "env set [-f] name [arg ...]\n"; @@ -1461,13 +1461,14 @@ U_BOOT_CMD_COMPLETE( setenv, CONFIG_SYS_MAXARGS, 0, do_env_set, "set environment variables", #if defined(CONFIG_CMD_NVEDIT_EFI) - "-e [-guid guid][-nv][-bs][-rt][-a][-v]\n" + "-e [-guid guid][-nv][-bs][-rt][-at][-a][-v]\n" " [-i addr,size name], or [name [value ...]]\n" " - set UEFI variable 'name' to 'value' ...'\n" " \"-guid\": set vendor guid\n" " \"-nv\": set non-volatile attribute\n" " \"-bs\": set boot-service attribute\n" " \"-rt\": set runtime attribute\n" + " \"-at\": set time-based authentication attribute\n" " \"-a\": append-write\n" " \"-i addr,size\": use as variable's value\n" " \"-v\": verbose message\n" diff --git a/cmd/nvedit_efi.c b/cmd/nvedit_efi.c index 579cf430593c..837e39e02179 100644 --- a/cmd/nvedit_efi.c +++ b/cmd/nvedit_efi.c @@ -458,7 +458,7 @@ out: * Return: CMD_RET_SUCCESS on success, or CMD_RET_RET_FAILURE * * This function is for "env set -e" or "setenv -e" command: - * => env set -e [-guid guid][-nv][-bs][-rt][-a][-v] + * => env set -e [-guid guid][-nv][-bs][-rt][-at][-a][-v] * [-i address,size] var, or * var [value ...] * Encode values specified and set given UEFI variable. @@ -517,6 +517,9 @@ int do_env_set_efi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) attributes |= EFI_VARIABLE_RUNTIME_ACCESS; } else if (!strcmp(argv[0], "-nv")) { attributes |= EFI_VARIABLE_NON_VOLATILE; + } else if (!strcmp(argv[0], "-at")) { + attributes |= + EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS; } else if (!strcmp(argv[0], "-a")) { attributes |= EFI_VARIABLE_APPEND_WRITE; } else if (!strcmp(argv[0], "-i")) { From patchwork Wed Dec 18 00:45:08 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: AKASHI Takahiro X-Patchwork-Id: 1211845 X-Patchwork-Delegate: xypron.glpk@gmx.de Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=85.214.62.61; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=linaro.org Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.b="cDOJgdq/"; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [85.214.62.61]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 47cxCb6gbpz9sRl for ; Wed, 18 Dec 2019 11:46:35 +1100 (AEDT) Received: from phobos.denx.de (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id B7EC8816BA; Wed, 18 Dec 2019 01:44:48 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=fail (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=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.b="cDOJgdq/"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id B4AD7816D2; Wed, 18 Dec 2019 01:44:41 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-0.1 required=5.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,SPF_HELO_NONE,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.2 Received: from mail-pj1-x102b.google.com (mail-pj1-x102b.google.com [IPv6:2607:f8b0:4864:20::102b]) (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 94A3781685 for ; Wed, 18 Dec 2019 01:44:37 +0100 (CET) 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-pj1-x102b.google.com with SMTP id m13so41569pjb.2 for ; Tue, 17 Dec 2019 16:44:37 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=RT80ml6FzlBhaUFPnyjj4B0pdvYyDxf3gWx5nGb+lb4=; b=cDOJgdq/7GHxGG0pxPx6mOcG66HTgCEgV0MCCnVk0KUn4/BJRfGrAAMfeFJOL1vxnF A4bxatjDV2JhOqKyWlh2y/i/B0NZvit+1mnwH8RQDY//BBWt6A2fBJRUuBCa3y+ZEHQ+ n9HUZtPbT5xiSZTRi7u2Ac0iAILp8rfLdoWN/1cW6mK30tGrPz8O22lNTVr6I/MIUBm1 Ct8a0U2+jkqEISnNj9BEAx4lyH0DDBq4/WZ1zWnKPLWDh84FsX5nQ1jOOz5b8D4l+2pJ SdC/EZOrerOS6GtTVex0k7//GBSTmghSz0c3XAkeFeiwqJdaV8cGADo0QUEHLw0GmImA 3tqQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=RT80ml6FzlBhaUFPnyjj4B0pdvYyDxf3gWx5nGb+lb4=; b=DglwX3qtPw22ETCKw/1FrQtZ/OwDOX//pnxar/LsSpuUChGZCxofzgaV08RU7kiC10 bebi2aT9RLNxe9bh7PIuyqFNJZxdJHLMbhIs2i2B7f6LFOHRniKo1OXxrE8WApMb4bW2 cURR5vrJ+c5BmqenxKWHkEU5Am5tGfevCXAPSCrP35Z6v4tFLXwfxzl4lShCVStBngem xA52m0tv0tP3gY1sZwSwIxAFnwABHL7f9PDQ/fsCEPcwy9cgiCxRoCqKZpMADqbTGAr2 rb7c9XU3p3AcvX7tEMOq4nehFpZ1zPuL8e6hD86VjwAjpQYNRHXCsT7To+j/wxaliFNz GNQw== X-Gm-Message-State: APjAAAU4krZLyn300+y165K4eAMJcDOZiIY1n859UhQHty5VF5alVsKk bow+PIBQ5ACQTQyCrTPq53emNA== X-Google-Smtp-Source: APXvYqzS+RGpw9HYtCtJlFf05MKGNVobwE41C41a/qvP9YpaJlCjsD+FGhZ2CpxL6Zgi0iMVWQlQsw== X-Received: by 2002:a17:90a:25f0:: with SMTP id k103mr135996pje.117.1576629876062; Tue, 17 Dec 2019 16:44:36 -0800 (PST) Received: from linaro.org ([121.95.100.191]) by smtp.googlemail.com with ESMTPSA id y6sm216669pgc.10.2019.12.17.16.44.35 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 17 Dec 2019 16:44:35 -0800 (PST) From: AKASHI Takahiro To: xypron.glpk@gmx.de, agraf@csgraf.de, trini@konsulko.com Subject: [PATCH v4 12/16] efi_loader, pytest: set up secure boot environment Date: Wed, 18 Dec 2019 09:45:08 +0900 Message-Id: <20191218004512.24939-13-takahiro.akashi@linaro.org> X-Mailer: git-send-email 2.24.0 In-Reply-To: <20191218004512.24939-1-takahiro.akashi@linaro.org> References: <20191218004512.24939-1-takahiro.akashi@linaro.org> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.26 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: u-boot@lists.denx.de, mail@patrick-wildt.de Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.101.4 at phobos.denx.de X-Virus-Status: Clean A fixture for UEFI secure boot tests (image authentication and variable authentication) is defined. A small file system with test data in a single partition formatted in fat is created. This test requires efitools v1.5.2 or later. If the system's efitools is older, you have to build it on your own and define EFITOOLS_PATH. Signed-off-by: AKASHI Takahiro --- test/py/README.md | 8 ++ test/py/tests/test_efi_secboot/conftest.py | 151 +++++++++++++++++++++ test/py/tests/test_efi_secboot/defs.py | 21 +++ 3 files changed, 180 insertions(+) create mode 100644 test/py/tests/test_efi_secboot/conftest.py create mode 100644 test/py/tests/test_efi_secboot/defs.py diff --git a/test/py/README.md b/test/py/README.md index 3cbe01b73e28..aa8a5607b064 100644 --- a/test/py/README.md +++ b/test/py/README.md @@ -37,7 +37,15 @@ will be required. The following is an incomplete list: | openssl | | sudo OR guestmount | | e2fsprogs | +| util-linux | +| coreutils | | dosfstools | +| efitools | +| mount | +| mtools | +| sbsigntool | +| udisks2 | + Please use the apporirate commands for your distribution to match these tools up with the package that provides them. diff --git a/test/py/tests/test_efi_secboot/conftest.py b/test/py/tests/test_efi_secboot/conftest.py new file mode 100644 index 000000000000..e542fef6e819 --- /dev/null +++ b/test/py/tests/test_efi_secboot/conftest.py @@ -0,0 +1,151 @@ +# SPDX-License-Identifier: GPL-2.0+ +# Copyright (c) 2019, Linaro Limited +# Author: AKASHI Takahiro + +import os +import os.path +import pytest +import re +from subprocess import call, check_call, check_output, CalledProcessError +from defs import * + +# from test/py/conftest.py +def tool_is_in_path(tool): + for path in os.environ["PATH"].split(os.pathsep): + fn = os.path.join(path, tool) + if os.path.isfile(fn) and os.access(fn, os.X_OK): + return True + return False + +# +# Fixture for UEFI secure boot test +# +@pytest.fixture(scope='session') +def efi_boot_env(request, u_boot_config): + """Set up a file system to be used in UEFI secure boot test. + + Args: + request: Pytest request object. + u_boot_config: U-boot configuration. + + Return: + A path to disk image to be used for testing + """ + global HELLO_PATH + + image_path = u_boot_config.persistent_data_dir + image_path = image_path + '/' + EFI_SECBOOT_IMAGE_NAME + image_size = EFI_SECBOOT_IMAGE_SIZE + part_size = EFI_SECBOOT_PART_SIZE + fs_type = EFI_SECBOOT_FS_TYPE + + if HELLO_PATH == '': + HELLO_PATH = u_boot_config.build_dir + '/lib/efi_loader/helloworld.efi' + + try: + non_root = tool_is_in_path('udisksctl') + + # create a disk/partition + check_call('dd if=/dev/zero of=%s bs=1MiB count=%d' + % (image_path, image_size), shell=True) + check_call('sgdisk %s -n 1:0:+%dMiB' + % (image_path, part_size), shell=True) + # create a file system + check_call('dd if=/dev/zero of=%s.tmp bs=1MiB count=%d' + % (image_path, part_size), shell=True) + check_call('mkfs -t %s %s.tmp' % (fs_type, image_path), shell=True) + check_call('dd if=%s.tmp of=%s bs=1MiB seek=1 count=%d conv=notrunc' + % (image_path, image_path, 1), shell=True) + check_call('rm %s.tmp' % image_path, shell=True) + if non_root: + out_data = check_output('udisksctl loop-setup -f %s -o %d' + % (image_path, 1048576), shell=True).decode() + m = re.search('(?<= as )(.*)\.', out_data) + loop_dev = m.group(1) + # print 'loop device is: %s' % loop_dev + out_data = check_output('udisksctl info -b %s' + % loop_dev, shell=True).decode() + m = re.search('MountPoints:[ \t]+(.*)', out_data) + mnt_point = m.group(1) + else: + loop_dev = check_output('sudo losetup -o 1MiB --sizelimit %dMiB --show -f %s | tr -d "\n"' + % (part_size, image_path), shell=True).decode() + mnt_point = '/mnt' + check_output('sudo mount -t %s -o umask=000 %s %s' + % (fs_type, loop_dev, mnt_point), shell=True) + + # print 'mount point is: %s' % mnt_point + + # suffix + # *.key: RSA private key in PEM + # *.crt: X509 certificate (self-signed) in PEM + # *.esl: signature list + # *.hash: message digest of image as signature list + # *.auth: signed signature list in signature database format + # *.efi: UEFI image + # *.efi.signed: signed UEFI image + + # Create signature database + ## PK + check_call('cd %s; openssl req -x509 -sha256 -newkey rsa:2048 -subj /CN=TEST_PK/ -keyout PK.key -out PK.crt -nodes -days 365' + % mnt_point, shell=True) + check_call('cd %s; %scert-to-efi-sig-list -g %s PK.crt PK.esl; %ssign-efi-sig-list -c PK.crt -k PK.key PK PK.esl PK.auth' + % (mnt_point, EFITOOLS_PATH, GUID, EFITOOLS_PATH), + shell=True) + ## PK_null for deletion + check_call('cd %s; sleep 2; touch PK_null.esl; %ssign-efi-sig-list -c PK.crt -k PK.key PK PK_null.esl PK_null.auth' + % (mnt_point, EFITOOLS_PATH), shell=True) + ## KEK + check_call('cd %s; openssl req -x509 -sha256 -newkey rsa:2048 -subj /CN=TEST_KEK/ -keyout KEK.key -out KEK.crt -nodes -days 365' + % mnt_point, shell=True) + check_call('cd %s; %scert-to-efi-sig-list -g %s KEK.crt KEK.esl; %ssign-efi-sig-list -c PK.crt -k PK.key KEK KEK.esl KEK.auth' + % (mnt_point, EFITOOLS_PATH, GUID, EFITOOLS_PATH), + shell=True) + ## db + check_call('cd %s; openssl req -x509 -sha256 -newkey rsa:2048 -subj /CN=TEST_db/ -keyout db.key -out db.crt -nodes -days 365' + % mnt_point, shell=True) + check_call('cd %s; %scert-to-efi-sig-list -g %s db.crt db.esl; %ssign-efi-sig-list -c KEK.crt -k KEK.key db db.esl db.auth' + % (mnt_point, EFITOOLS_PATH, GUID, EFITOOLS_PATH), + shell=True) + ## db1 + check_call('cd %s; openssl req -x509 -sha256 -newkey rsa:2048 -subj /CN=TEST_db1/ -keyout db1.key -out db1.crt -nodes -days 365' + % mnt_point, shell=True) + check_call('cd %s; %scert-to-efi-sig-list -g %s db1.crt db1.esl; %ssign-efi-sig-list -c KEK.crt -k KEK.key db db1.esl db1.auth' + % (mnt_point, EFITOOLS_PATH, GUID, EFITOOLS_PATH), + shell=True) + ## db1-update + check_call('cd %s; %ssign-efi-sig-list -a -c KEK.crt -k KEK.key db db1.esl db1-update.auth' + % (mnt_point, EFITOOLS_PATH), shell=True) + ## dbx + check_call('cd %s; openssl req -x509 -sha256 -newkey rsa:2048 -subj /CN=TEST_dbx/ -keyout dbx.key -out dbx.crt -nodes -days 365' + % mnt_point, shell=True) + check_call('cd %s; %scert-to-efi-sig-list -g %s dbx.crt dbx.esl; %ssign-efi-sig-list -c KEK.crt -k KEK.key dbx dbx.esl dbx.auth' + % (mnt_point, EFITOOLS_PATH, GUID, EFITOOLS_PATH), + shell=True) + + # Copy image + check_call('cp %s %s' % (HELLO_PATH, mnt_point), shell=True) + + ## Sign image + check_call('cd %s; sbsign --key db.key --cert db.crt helloworld.efi' + % mnt_point, shell=True) + ## Digest image + check_call('cd %s; %shash-to-efi-sig-list helloworld.efi db_hello.hash; %ssign-efi-sig-list -c KEK.crt -k KEK.key db db_hello.hash db_hello.auth' + % (mnt_point, EFITOOLS_PATH, EFITOOLS_PATH), + shell=True) + + if non_root: + check_call('udisksctl unmount -b %s' % loop_dev, shell=True) + # not needed + # check_call('udisksctl loop-delete -b %s' % loop_dev, shell=True) + else: + check_call('sudo umount %s' % loop_dev, shell=True) + check_call('sudo losetup -d %s' % loop_dev, shell=True) + + except CalledProcessError as e: + pytest.skip('Setup failed: %s' % e.cmd) + return + else: + yield image_path + finally: + call('rm -f %s' % image_path, shell=True) diff --git a/test/py/tests/test_efi_secboot/defs.py b/test/py/tests/test_efi_secboot/defs.py new file mode 100644 index 000000000000..d6222809c547 --- /dev/null +++ b/test/py/tests/test_efi_secboot/defs.py @@ -0,0 +1,21 @@ +# SPDX-License-Identifier: GPL-2.0+ + +# Disk image name +EFI_SECBOOT_IMAGE_NAME='test_efi_secboot.img' + +# Size in MiB +EFI_SECBOOT_IMAGE_SIZE=16 +EFI_SECBOOT_PART_SIZE=8 + +# Partition file system type +EFI_SECBOOT_FS_TYPE='vfat' + +# Owner guid +GUID='11111111-2222-3333-4444-123456789abc' + +# v1.5.1 or earlier of efitools has a bug in sha256 calculation, and +# you need build a newer version on your own. +EFITOOLS_PATH='' + +# Hello World application for sandbox +HELLO_PATH='' From patchwork Wed Dec 18 00:45:09 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: AKASHI Takahiro X-Patchwork-Id: 1211846 X-Patchwork-Delegate: xypron.glpk@gmx.de Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=linaro.org Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.b="Hl4YNXJ/"; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [IPv6:2a01:238:438b:c500:173d:9f52:ddab:ee01]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 47cxCn4K43z9sRl for ; Wed, 18 Dec 2019 11:46:45 +1100 (AEDT) Received: from phobos.denx.de (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id A4701816FE; Wed, 18 Dec 2019 01:44:51 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=fail (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=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.b="Hl4YNXJ/"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 46DE0816D3; Wed, 18 Dec 2019 01:44:46 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-0.1 required=5.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,SPF_HELO_NONE,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.2 Received: from mail-pl1-x641.google.com (mail-pl1-x641.google.com [IPv6:2607:f8b0:4864:20::641]) (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 D2347816C5 for ; Wed, 18 Dec 2019 01:44:40 +0100 (CET) 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-x641.google.com with SMTP id z3so164497plk.6 for ; Tue, 17 Dec 2019 16:44:40 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=PgdD2BW809g4GSsh9a0WB+hBklXfaWvM8RtkFGLAcBY=; b=Hl4YNXJ/BCrehv9IWgVRwdD7CcOXYJ7mUZtF6g2mR8sjeoSk6cxq1kv/v2DB/P22tk M4gkM+iTWmJqu5TN+M5Up8rPJbgVetSg1EM4ZryxlyKZya5vJ7zBPTxlHG4hYCHy16ea eXaZX69cEzxoyCjvK2KKOdCfkZkHzsNxZ8Tt9iR+9OxU2cAXjZqLFtABv4XA3b5qTFzA +qetpZr2XiqB3jM6Tx0cGsdXrH+G0eeqXaS+IDfiyGpUbvmIisoPHjqlAVDgdZqsumvd 2mfK5dS5RFDbFMkHIpAG8Mp+HyigNbR3cfF50fgiAD86E8vJKzWzjvq8v9HWTu/Sz1G5 njYw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=PgdD2BW809g4GSsh9a0WB+hBklXfaWvM8RtkFGLAcBY=; b=gIW/leh2NMvE3ByrGTZ29Rq624gu+yBU/uJzsnkW0f1AV8uImbrYs9woiDfu4AS/oe RmYxN1w/Bf17vjsqMpEI8DlLkX7hWZFQ8rbeS2RJTxMdsNkE6af72b/XyNiHPS8Q1Tqv FDlbzC+vPCT+Z9yM8HG0SrG8RAO4NLqwaRMW0gAO3KfQ0+fMIDp5IXhfquQmSMbzqmWd ODm1RC7E734StXF22pb30IFVXiwjUvOg8ewgfdH6Mfwdvirz3kzyD1dG21b8y0lXoYjd p+EmjkZExN701qpjqfF5uy4vyg+4/ADXJlVjgIguxHwNzZmodQ6Tt30yWpE7HILzLSAV RVsg== X-Gm-Message-State: APjAAAUoo/Fhju2Cmhassgm2YT839QAMuDQbsd65L+LiGEZC4dcuZ003 86yuZjU8zcObnSUJ4SYOdYaoJA== X-Google-Smtp-Source: APXvYqxxi3jI6vIpmUsguDu0zu1QpzL7nMADQSWQ6YsnT6TwsSLGgYa3Lh34uFCoOmLZCLqoPcg6WQ== X-Received: by 2002:a17:902:6b:: with SMTP id 98mr1106417pla.128.1576629879257; Tue, 17 Dec 2019 16:44:39 -0800 (PST) Received: from linaro.org ([121.95.100.191]) by smtp.googlemail.com with ESMTPSA id k101sm152742pjb.5.2019.12.17.16.44.38 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 17 Dec 2019 16:44:38 -0800 (PST) From: AKASHI Takahiro To: xypron.glpk@gmx.de, agraf@csgraf.de, trini@konsulko.com Subject: [PATCH v4 13/16] efi_loader, pytest: add UEFI secure boot tests (authenticated variables) Date: Wed, 18 Dec 2019 09:45:09 +0900 Message-Id: <20191218004512.24939-14-takahiro.akashi@linaro.org> X-Mailer: git-send-email 2.24.0 In-Reply-To: <20191218004512.24939-1-takahiro.akashi@linaro.org> References: <20191218004512.24939-1-takahiro.akashi@linaro.org> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.26 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: u-boot@lists.denx.de, mail@patrick-wildt.de Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.101.4 at phobos.denx.de X-Virus-Status: Clean Provide a couple of test cases for variable authentication. Signed-off-by: AKASHI Takahiro --- .../py/tests/test_efi_secboot/test_authvar.py | 282 ++++++++++++++++++ 1 file changed, 282 insertions(+) create mode 100644 test/py/tests/test_efi_secboot/test_authvar.py diff --git a/test/py/tests/test_efi_secboot/test_authvar.py b/test/py/tests/test_efi_secboot/test_authvar.py new file mode 100644 index 000000000000..55dcaa95f1ea --- /dev/null +++ b/test/py/tests/test_efi_secboot/test_authvar.py @@ -0,0 +1,282 @@ +# SPDX-License-Identifier: GPL-2.0+ +# Copyright (c) 2019, Linaro Limited +# Author: AKASHI Takahiro +# +# U-Boot UEFI: Variable Authentication Test + +""" +This test verifies variable authentication +""" + +import pytest +import re +from defs import * + +@pytest.mark.boardspec('sandbox') +@pytest.mark.buildconfigspec('efi_secure_boot') +@pytest.mark.buildconfigspec('cmd_fat') +@pytest.mark.buildconfigspec('cmd_nvedit_efi') +@pytest.mark.slow +class TestEfiAuthVar(object): + def test_efi_var_auth1(self, u_boot_console, efi_boot_env): + """ + Test Case 1 - Install signature database + """ + u_boot_console.restart_uboot() + disk_img = efi_boot_env + with u_boot_console.log.section('Test Case 1a'): + # Test Case 1a, Initial secure state + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % disk_img, + 'printenv -e SecureBoot']) + assert('00000000: 00' in ''.join(output)) + + output = u_boot_console.run_command( + 'printenv -e SetupMode') + assert('00000000: 01' in output) + + with u_boot_console.log.section('Test Case 1b'): + # Test Case 1b, PK without AUTHENTICATED_WRITE_ACCESS + output = u_boot_console.run_command_list([ + 'fatload host 0:1 4000000 PK.auth', + 'setenv -e -nv -bs -rt -i 4000000,$filesize PK']) + assert(re.search('Failed to set EFI variable', ''.join(output))) + + with u_boot_console.log.section('Test Case 1c'): + # Test Case 1c, install PK + output = u_boot_console.run_command_list([ + 'fatload host 0:1 4000000 PK.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize PK', + 'printenv -e -n PK']) + assert(re.search('PK:', ''.join(output))) + + output = u_boot_console.run_command( + 'printenv -e SecureBoot') + assert('00000000: 01' in output) + output = u_boot_console.run_command( + 'printenv -e SetupMode') + assert('00000000: 00' in output) + + with u_boot_console.log.section('Test Case 1d'): + # Test Case 1d, db/dbx without KEK + output = u_boot_console.run_command_list([ + 'fatload host 0:1 4000000 db.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize db']) + assert(re.search('Failed to set EFI variable', ''.join(output))) + + output = u_boot_console.run_command_list([ + 'fatload host 0:1 4000000 db.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize dbx']) + assert(re.search('Failed to set EFI variable', ''.join(output))) + + with u_boot_console.log.section('Test Case 1e'): + # Test Case 1e, install KEK + output = u_boot_console.run_command_list([ + 'fatload host 0:1 4000000 KEK.auth', + 'setenv -e -nv -bs -rt -i 4000000,$filesize KEK']) + assert(re.search('Failed to set EFI variable', ''.join(output))) + + output = u_boot_console.run_command_list([ + 'fatload host 0:1 4000000 KEK.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize KEK', + 'printenv -e -n KEK']) + assert(re.search('KEK:', ''.join(output))) + + output = u_boot_console.run_command( + 'printenv -e SecureBoot') + assert('00000000: 01' in output) + + with u_boot_console.log.section('Test Case 1f'): + # Test Case 1f, install db + output = u_boot_console.run_command_list([ + 'fatload host 0:1 4000000 db.auth', + 'setenv -e -nv -bs -rt -i 4000000,$filesize db']) + assert(re.search('Failed to set EFI variable', ''.join(output))) + + output = u_boot_console.run_command_list([ + 'fatload host 0:1 4000000 db.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize db', + 'printenv -e -n -guid d719b2cb-3d3a-4596-a3bc-dad00e67656f db']) + assert(not re.search('Failed to set EFI variable', ''.join(output))) + assert(re.search('db:', ''.join(output))) + + output = u_boot_console.run_command( + 'printenv -e SecureBoot') + assert('00000000: 01' in output) + + with u_boot_console.log.section('Test Case 1g'): + # Test Case 1g, install dbx + output = u_boot_console.run_command_list([ + 'fatload host 0:1 4000000 db.auth', + 'setenv -e -nv -bs -rt -i 4000000,$filesize db']) + assert(re.search('Failed to set EFI variable', ''.join(output))) + + output = u_boot_console.run_command_list([ + 'fatload host 0:1 4000000 db.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize db', + 'printenv -e -n -guid d719b2cb-3d3a-4596-a3bc-dad00e67656f db']) + assert(not re.search('Failed to set EFI variable', ''.join(output))) + assert(re.search('db:', ''.join(output))) + + output = u_boot_console.run_command( + 'printenv -e SecureBoot') + assert('00000000: 01' in output) + + def test_efi_var_auth2(self, u_boot_console, efi_boot_env): + """ + Test Case 2 - Update database by overwriting + """ + u_boot_console.restart_uboot() + disk_img = efi_boot_env + with u_boot_console.log.section('Test Case 2a'): + # Test Case 2a, update without AUTHENTICATED_WRITE_ACCESS + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % disk_img, + 'fatload host 0:1 4000000 PK.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize PK', + 'fatload host 0:1 4000000 KEK.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize KEK', + 'fatload host 0:1 4000000 db.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize db', + 'printenv -e -n -guid d719b2cb-3d3a-4596-a3bc-dad00e67656f db']) + assert(not re.search('Failed to set EFI variable', ''.join(output))) + assert(re.search('db:', ''.join(output))) + + output = u_boot_console.run_command_list([ + 'fatload host 0:1 4000000 db1.auth', + 'setenv -e -nv -bs -rt -i 4000000,$filesize db']) + assert(re.search('Failed to set EFI variable', ''.join(output))) + + with u_boot_console.log.section('Test Case 2b'): + # Test Case 2b, update without correct signature + output = u_boot_console.run_command_list([ + 'fatload host 0:1 4000000 db.esl', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize db']) + assert(re.search('Failed to set EFI variable', ''.join(output))) + + with u_boot_console.log.section('Test Case 2c'): + # Test Case 2c, update with correct signature + output = u_boot_console.run_command_list([ + 'fatload host 0:1 4000000 db1.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize db', + 'printenv -e -n -guid d719b2cb-3d3a-4596-a3bc-dad00e67656f db']) + assert(not re.search('Failed to set EFI variable', ''.join(output))) + assert(re.search('db:', ''.join(output))) + + def test_efi_var_auth3(self, u_boot_console, efi_boot_env): + """ + Test Case 3 - Append database + """ + u_boot_console.restart_uboot() + disk_img = efi_boot_env + with u_boot_console.log.section('Test Case 3a'): + # Test Case 3a, update without AUTHENTICATED_WRITE_ACCESS + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % disk_img, + 'fatload host 0:1 4000000 PK.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize PK', + 'fatload host 0:1 4000000 KEK.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize KEK', + 'fatload host 0:1 4000000 db.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize db', + 'printenv -e -n -guid d719b2cb-3d3a-4596-a3bc-dad00e67656f db']) + assert(not re.search('Failed to set EFI variable', ''.join(output))) + assert(re.search('db:', ''.join(output))) + + output = u_boot_console.run_command_list([ + 'fatload host 0:1 4000000 db1.auth', + 'setenv -e -nv -bs -rt -a -i 4000000,$filesize db']) + assert(re.search('Failed to set EFI variable', ''.join(output))) + + with u_boot_console.log.section('Test Case 3b'): + # Test Case 3b, update without correct signature + output = u_boot_console.run_command_list([ + 'fatload host 0:1 4000000 db.esl', + 'setenv -e -nv -bs -rt -at -a -i 4000000,$filesize db']) + assert(re.search('Failed to set EFI variable', ''.join(output))) + + with u_boot_console.log.section('Test Case 3c'): + # Test Case 3c, update with correct signature + output = u_boot_console.run_command_list([ + 'fatload host 0:1 4000000 db1.auth', + 'setenv -e -nv -bs -rt -at -a -i 4000000,$filesize db', + 'printenv -e -n -guid d719b2cb-3d3a-4596-a3bc-dad00e67656f db']) + assert(not re.search('Failed to set EFI variable', ''.join(output))) + assert(re.search('db:', ''.join(output))) + + def test_efi_var_auth4(self, u_boot_console, efi_boot_env): + """ + Test Case 4 - Delete database without authentication + """ + u_boot_console.restart_uboot() + disk_img = efi_boot_env + with u_boot_console.log.section('Test Case 4a'): + # Test Case 4a, update without AUTHENTICATED_WRITE_ACCESS + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % disk_img, + 'fatload host 0:1 4000000 PK.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize PK', + 'fatload host 0:1 4000000 KEK.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize KEK', + 'fatload host 0:1 4000000 db.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize db', + 'printenv -e -n -guid d719b2cb-3d3a-4596-a3bc-dad00e67656f db']) + assert(not re.search('Failed to set EFI variable', ''.join(output))) + assert(re.search('db:', ''.join(output))) + + output = u_boot_console.run_command_list([ + 'setenv -e -nv -bs -rt db', + 'printenv -e -n -guid d719b2cb-3d3a-4596-a3bc-dad00e67656f db']) + assert(re.search('Failed to set EFI variable', ''.join(output))) + assert(re.search('db:', ''.join(output))) + + with u_boot_console.log.section('Test Case 4b'): + # Test Case 4b, update without correct signature/data + output = u_boot_console.run_command_list([ + 'setenv -e -nv -bs -rt -at db', + 'printenv -e -n -guid d719b2cb-3d3a-4596-a3bc-dad00e67656f db']) + assert(re.search('Failed to set EFI variable', ''.join(output))) + assert(re.search('db:', ''.join(output))) + + def test_efi_var_auth5(self, u_boot_console, efi_boot_env): + """ + Test Case 5 - Uninstall(delete) PK + """ + u_boot_console.restart_uboot() + disk_img = efi_boot_env + with u_boot_console.log.section('Test Case 5a'): + # Test Case 5a, Uninstall PK without correct signature + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % disk_img, + 'fatload host 0:1 4000000 PK.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize PK', + 'fatload host 0:1 4000000 KEK.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize KEK', + 'fatload host 0:1 4000000 db.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize db', + 'printenv -e -n PK']) + assert(not re.search('Failed to set EFI variable', ''.join(output))) + assert(re.search('PK:', ''.join(output))) + + output = u_boot_console.run_command_list([ + 'fatload host 0:1 4000000 PK_null.esl', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize PK', + 'printenv -e -n PK']) + assert(re.search('Failed to set EFI variable', ''.join(output))) + assert(re.search('PK:', ''.join(output))) + + with u_boot_console.log.section('Test Case 5b'): + # Test Case 5b, Uninstall PK with correct signature + output = u_boot_console.run_command_list([ + 'fatload host 0:1 4000000 PK_null.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize PK', + 'printenv -e -n PK']) + assert(not re.search('Failed to set EFI variable', ''.join(output))) + assert(re.search('\"PK\" not defined', ''.join(output))) + + output = u_boot_console.run_command( + 'printenv -e SecureBoot') + assert('00000000: 00' in output) + output = u_boot_console.run_command( + 'printenv -e SetupMode') + assert('00000000: 01' in output) From patchwork Wed Dec 18 00:45:10 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: AKASHI Takahiro X-Patchwork-Id: 1211847 X-Patchwork-Delegate: xypron.glpk@gmx.de Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=linaro.org Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.b="lDkbvTWt"; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [IPv6:2a01:238:438b:c500:173d:9f52:ddab:ee01]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 47cxCz6XDnz9sRl for ; Wed, 18 Dec 2019 11:46:55 +1100 (AEDT) Received: from phobos.denx.de (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id D471F81675; Wed, 18 Dec 2019 01:44:53 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=fail (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=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.b="lDkbvTWt"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 72EC1816D3; Wed, 18 Dec 2019 01:44:48 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-0.1 required=5.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,SPF_HELO_NONE,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.2 Received: from mail-pg1-x52e.google.com (mail-pg1-x52e.google.com [IPv6:2607:f8b0:4864:20::52e]) (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 EEA87816BA for ; Wed, 18 Dec 2019 01:44:43 +0100 (CET) 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-pg1-x52e.google.com with SMTP id x8so246127pgk.8 for ; Tue, 17 Dec 2019 16:44:43 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=8QpZb6Pr8O5j44dXAP1bnp/IaqSQ2ZN9Pvv+SKmffLU=; b=lDkbvTWtE5i0IA+oY+8uD9qI93toU/AsQzIZaE79U1C45q0QixhvgVT4VjHGPv7p1y 67ekfMTmxSVY/M3uilryqa2NPJ/eVvdtIIeVLjKZeXlmdEsyJTFWT3rou6bBTA4n6l5b E1t9rlF52aavDcKbT9yMEa2b4tmD2tPGQNQAaWwz4AW+5HJsBbAM7ZQzLyDGhIuYghhE nTlWNBA4sO1xokcUiSBl0XAOLIZz9KeQTZrsqsUOQvtAQeyy1X+T1l1hVtZjqmmh1wwv fgVhdZ+gTmxIL0b32CN2aGtuqjVj7LVqMGxlrurVIWbYaXrDLpuVNC+qb3uh8pU/9sDe ZfaQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=8QpZb6Pr8O5j44dXAP1bnp/IaqSQ2ZN9Pvv+SKmffLU=; b=FFvBUGg+47FrFMjh/OgnlEYrn3Kz0rzGsEljt2HThRDBlGPb4pCqy8mDiTwa0iHrc5 ScB0rHHI11Aii4N/y9u3/NhFdwL54Tka9JZL6Eg+a/7W/+qpGQQzoT+j2N7PFBRERd6P QMX9l/5OXqmkrs2vaVJO63px1xKqpAgGAyQakz7LTCRT4Ec/uQJJ/YHzsc69ghTlEE8t KwrmUy+91ZgoYeRJO5c+50wsl7XoC14L7TwOsoxvvCMKCVPFV7K767GH/x4q0sjX34uq S4ycJe+c0Os3cIkrSTS3lDW7RuEN0K57EhxFMS6WRrbzpmUCvP4zXegZ2ofshTUmre5R auuQ== X-Gm-Message-State: APjAAAXMQZuZAMvmtLtc4h8aKPhBg5VDeDZR71L+gVIFjXu8Z3DVvG87 v4H9Cs7abi171MAxHwWxgD22LQ== X-Google-Smtp-Source: APXvYqwUu+cIISScX4BUFhvyHjG6eyaM9Y5XjSEiZ3dRHYMrflFouk+zu5ynvZljn+uo0SkmAthDQQ== X-Received: by 2002:a65:4c8b:: with SMTP id m11mr861971pgt.208.1576629882407; Tue, 17 Dec 2019 16:44:42 -0800 (PST) Received: from linaro.org ([121.95.100.191]) by smtp.googlemail.com with ESMTPSA id k9sm132037pje.26.2019.12.17.16.44.41 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 17 Dec 2019 16:44:41 -0800 (PST) From: AKASHI Takahiro To: xypron.glpk@gmx.de, agraf@csgraf.de, trini@konsulko.com Subject: [PATCH v4 14/16] efi_loader, pytest: add UEFI secure boot tests (image) Date: Wed, 18 Dec 2019 09:45:10 +0900 Message-Id: <20191218004512.24939-15-takahiro.akashi@linaro.org> X-Mailer: git-send-email 2.24.0 In-Reply-To: <20191218004512.24939-1-takahiro.akashi@linaro.org> References: <20191218004512.24939-1-takahiro.akashi@linaro.org> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.26 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: u-boot@lists.denx.de, mail@patrick-wildt.de Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.101.4 at phobos.denx.de X-Virus-Status: Clean Provide test cases for * image authentication for signed images (test_efi_secboot/test_signed.py) * image authentication for unsigned images (test_efi_secboot/test_unsigned.py) Signed-off-by: AKASHI Takahiro --- test/py/tests/test_efi_secboot/test_signed.py | 99 +++++++++++++++++ .../tests/test_efi_secboot/test_unsigned.py | 103 ++++++++++++++++++ 2 files changed, 202 insertions(+) create mode 100644 test/py/tests/test_efi_secboot/test_signed.py create mode 100644 test/py/tests/test_efi_secboot/test_unsigned.py diff --git a/test/py/tests/test_efi_secboot/test_signed.py b/test/py/tests/test_efi_secboot/test_signed.py new file mode 100644 index 000000000000..b185e36af2e3 --- /dev/null +++ b/test/py/tests/test_efi_secboot/test_signed.py @@ -0,0 +1,99 @@ +# SPDX-License-Identifier: GPL-2.0+ +# Copyright (c) 2019, Linaro Limited +# Author: AKASHI Takahiro +# +# U-Boot UEFI: Signed Image Authentication Test + +""" +This test verifies image authentication for signed images. +""" + +import pytest +import re +from defs import * + +@pytest.mark.boardspec('sandbox') +@pytest.mark.buildconfigspec('efi_secure_boot') +@pytest.mark.buildconfigspec('cmd_efidebug') +@pytest.mark.buildconfigspec('cmd_fat') +@pytest.mark.buildconfigspec('cmd_nvedit_efi') +@pytest.mark.slow +class TestEfiSignedImage(object): + def test_efi_signed_image_auth1(self, u_boot_console, efi_boot_env): + """ + Test Case 1 - authenticated by db + """ + u_boot_console.restart_uboot() + disk_img = efi_boot_env + with u_boot_console.log.section('Test Case 1a'): + # Test Case 1a, run signed image if no db/dbx + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % disk_img, + 'efidebug boot add 1 HELLO1 host 0:1 /helloworld.efi.signed ""', + 'efidebug boot next 1', + 'bootefi bootmgr']) + assert(re.search('Hello, world!', ''.join(output))) + + with u_boot_console.log.section('Test Case 1b'): + # Test Case 1b, run unsigned image if no db/dbx + output = u_boot_console.run_command_list([ + 'efidebug boot add 2 HELLO2 host 0:1 /helloworld.efi ""', + 'efidebug boot next 2', + 'bootefi bootmgr']) + assert(re.search('Hello, world!', ''.join(output))) + + with u_boot_console.log.section('Test Case 1c'): + # Test Case 1c, not authenticated by db + output = u_boot_console.run_command_list([ + 'fatload host 0:1 4000000 db.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize db', + 'fatload host 0:1 4000000 KEK.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize KEK', + 'fatload host 0:1 4000000 PK.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize PK']) + assert(not re.search('Failed to set EFI variable', ''.join(output))) + output = u_boot_console.run_command_list([ + 'efidebug boot next 2', + 'bootefi bootmgr']) + assert(re.search('\'HELLO2\' failed', ''.join(output))) + + with u_boot_console.log.section('Test Case 1d'): + # Test Case 1d, authenticated by db + output = u_boot_console.run_command_list([ + 'efidebug boot next 1', + 'bootefi bootmgr']) + assert(re.search('Hello, world!', ''.join(output))) + + def test_efi_signed_image_auth2(self, u_boot_console, efi_boot_env): + """ + Test Case 2 - rejected by dbx + """ + u_boot_console.restart_uboot() + disk_img = efi_boot_env + with u_boot_console.log.section('Test Case 2a'): + # Test Case 2a, rejected by dbx + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % disk_img, + 'fatload host 0:1 4000000 db.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize dbx', + 'fatload host 0:1 4000000 KEK.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize KEK', + 'fatload host 0:1 4000000 PK.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize PK']) + assert(not re.search('Failed to set EFI variable', ''.join(output))) + output = u_boot_console.run_command_list([ + 'efidebug boot add 1 HELLO host 0:1 /helloworld.efi.signed ""', + 'efidebug boot next 1', + 'bootefi bootmgr']) + assert(re.search('\'HELLO\' failed', ''.join(output))) + + with u_boot_console.log.section('Test Case 2b'): + # Test Case 2b, rejected by dbx even if db allows + output = u_boot_console.run_command_list([ + 'fatload host 0:1 4000000 db.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize db']) + assert(not re.search('Failed to set EFI variable', ''.join(output))) + output = u_boot_console.run_command_list([ + 'efidebug boot next 1', + 'bootefi bootmgr']) + assert(re.search('\'HELLO\' failed', ''.join(output))) diff --git a/test/py/tests/test_efi_secboot/test_unsigned.py b/test/py/tests/test_efi_secboot/test_unsigned.py new file mode 100644 index 000000000000..7e3727bbd6fe --- /dev/null +++ b/test/py/tests/test_efi_secboot/test_unsigned.py @@ -0,0 +1,103 @@ +# SPDX-License-Identifier: GPL-2.0+ +# Copyright (c) 2019, Linaro Limited +# Author: AKASHI Takahiro +# +# U-Boot UEFI: Signed Image Authentication Test + +""" +This test verifies image authentication for unsigned images. +""" + +import pytest +import re +from defs import * + +@pytest.mark.boardspec('sandbox') +@pytest.mark.buildconfigspec('efi_secure_boot') +@pytest.mark.buildconfigspec('cmd_efidebug') +@pytest.mark.buildconfigspec('cmd_fat') +@pytest.mark.buildconfigspec('cmd_nvedit_efi') +@pytest.mark.slow +class TestEfiUnsignedImage(object): + def test_efi_unsigned_image_auth1(self, u_boot_console, efi_boot_env): + """ + Test Case 1 - rejected when not digest in db or dbx + """ + u_boot_console.restart_uboot() + disk_img = efi_boot_env + with u_boot_console.log.section('Test Case 1'): + # Test Case 1 + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % disk_img, + 'fatload host 0:1 4000000 KEK.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize KEK', + 'fatload host 0:1 4000000 PK.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize PK']) + assert(not re.search('Failed to set EFI variable', ''.join(output))) + + output = u_boot_console.run_command_list([ + 'efidebug boot add 1 HELLO host 0:1 /helloworld.efi ""', + 'efidebug boot next 1', + 'bootefi bootmgr']) + assert(re.search('\'HELLO\' failed', ''.join(output))) + + def test_efi_unsigned_image_auth2(self, u_boot_console, efi_boot_env): + """ + Test Case 2 - authenticated by digest in db + """ + u_boot_console.restart_uboot() + disk_img = efi_boot_env + with u_boot_console.log.section('Test Case 2'): + # Test Case 2 + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % disk_img, + 'fatload host 0:1 4000000 db_hello.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize db', + 'fatload host 0:1 4000000 KEK.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize KEK', + 'fatload host 0:1 4000000 PK.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize PK']) + assert(not re.search('Failed to set EFI variable', ''.join(output))) + + output = u_boot_console.run_command_list([ + 'efidebug boot add 1 HELLO host 0:1 /helloworld.efi ""', + 'efidebug boot next 1', + 'bootefi bootmgr']) + assert(re.search('Hello, world!', ''.join(output))) + + def test_efi_unsigned_image_auth3(self, u_boot_console, efi_boot_env): + """ + Test Case 3 - rejected by digest in dbx + """ + u_boot_console.restart_uboot() + disk_img = efi_boot_env + with u_boot_console.log.section('Test Case 3a'): + # Test Case 3a, rejected by dbx + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % disk_img, + 'fatload host 0:1 4000000 db_hello.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize dbx', + 'fatload host 0:1 4000000 KEK.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize KEK', + 'fatload host 0:1 4000000 PK.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize PK']) + assert(not re.search('Failed to set EFI variable', ''.join(output))) + + output = u_boot_console.run_command_list([ + 'efidebug boot add 1 HELLO host 0:1 /helloworld.efi ""', + 'efidebug boot next 1', + 'bootefi bootmgr']) + assert(re.search('\'HELLO\' failed', ''.join(output))) + + with u_boot_console.log.section('Test Case 3b'): + # Test Case 3b, rejected by dbx even if db allows + output = u_boot_console.run_command_list([ + 'fatload host 0:1 4000000 db_hello.auth', + 'setenv -e -nv -bs -rt -at -i 4000000,$filesize db']) + assert(not re.search('Failed to set EFI variable', ''.join(output))) + + output = u_boot_console.run_command_list([ + 'efidebug boot add 1 HELLO host 0:1 /helloworld.efi ""', + 'efidebug boot next 1', + 'bootefi bootmgr']) + assert(re.search('\'HELLO\' failed', ''.join(output))) From patchwork Wed Dec 18 00:45:11 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: AKASHI Takahiro X-Patchwork-Id: 1211848 X-Patchwork-Delegate: xypron.glpk@gmx.de Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=linaro.org Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.b="hbU9rMf1"; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [IPv6:2a01:238:438b:c500:173d:9f52:ddab:ee01]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 47cxDC0rmVz9sRl for ; Wed, 18 Dec 2019 11:47:07 +1100 (AEDT) Received: from phobos.denx.de (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 6AA2881704; Wed, 18 Dec 2019 01:44:55 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=fail (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=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.b="hbU9rMf1"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 05B3881701; Wed, 18 Dec 2019 01:44:50 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=0.7 required=5.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU, SPF_HELO_NONE, UPPERCASE_50_75, URIBL_BLOCKED autolearn=no autolearn_force=no version=3.4.2 Received: from mail-pj1-x102d.google.com (mail-pj1-x102d.google.com [IPv6:2607:f8b0:4864:20::102d]) (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 D3D3A816F1 for ; Wed, 18 Dec 2019 01:44:46 +0100 (CET) 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-pj1-x102d.google.com with SMTP id m13so41731pjb.2 for ; Tue, 17 Dec 2019 16:44:46 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=OxjcUD7x1Pu+KVd/XEogHgqGDMYe1eMuNVNCpFEg/d0=; b=hbU9rMf1YfMhcbMMH50pOf/XkeXL4CuOlCOr/9M1cqmIpu0p8n+faQdax+0uIx2MWm M5lLSpOxpfQz3W9zcIbp2PqROm+oYc+b0SYnFUlQnm+So5BqK7Tfkruaq+Mm98Za0aP3 tTLXvT5L5w1rkjr7S20p5FA/0T3xjXoVTFQHumr+zoDQgEO6mM+DAYuj1UDnbD3VmFA6 LnfBSHpsnC5KHNmONfp7cWyD43AvJVdmG2XlfRnzcEropE90B9bUW8z/55Z8zwJoPdst nMPC9VqjrZaO50Oa21wF9HbERSPtnBOHsFrGCb7wal/saOCriz5L0W5G5Tjzfj1zHvm8 tPog== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=OxjcUD7x1Pu+KVd/XEogHgqGDMYe1eMuNVNCpFEg/d0=; b=WZAddK5TcrK0UwRrbS44xPj+USzB6OCWD7dU/cX7gOvMETh6Q9vcKRgppJ/SDtAVOg XlDSRgcDozT6SXmKRNgs03zDh5FV65M65jac6a9u4+s+bGCu8A4Pq9vRBNqNjF1o0b84 9twzsWU+sjKx9BSRFDILZ9sNGBonbNiwHPVS06j2oyL0OtF/bC02jzaznXqmcI28JL+C pYKCLgkt//NF17xZmc/6t83E9JNKMiPO+ROla175aniNhz/NM7vlM7t38lGs9ZuCDu67 kcdzt5xAQbrvqGCcP7WOEaNCwbeaKlvgQvT3tkpwcgJZcKY7WTdkag8eCL4U9YHvig9V RNEw== X-Gm-Message-State: APjAAAWvXiuRXijRkrIxXu0ryYcPQXtpO0kCxA/5PaEYIsD8s8AhsgvV GtUfJXPA5yq8KYia8p6S2WkmXg== X-Google-Smtp-Source: APXvYqwk0klIokcOb3WdBprRMox9KPOdYfz7lyR/FwhEl/XeWIikVqvVIrXbPvjMXDgEFvFODQ22BA== X-Received: by 2002:a17:90a:cb05:: with SMTP id z5mr189203pjt.122.1576629885485; Tue, 17 Dec 2019 16:44:45 -0800 (PST) Received: from linaro.org ([121.95.100.191]) by smtp.googlemail.com with ESMTPSA id r1sm214831pgp.15.2019.12.17.16.44.44 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 17 Dec 2019 16:44:44 -0800 (PST) From: AKASHI Takahiro To: xypron.glpk@gmx.de, agraf@csgraf.de, trini@konsulko.com Subject: [PATCH v4 15/16] sandbox: add extra configurations for UEFI and related tests Date: Wed, 18 Dec 2019 09:45:11 +0900 Message-Id: <20191218004512.24939-16-takahiro.akashi@linaro.org> X-Mailer: git-send-email 2.24.0 In-Reply-To: <20191218004512.24939-1-takahiro.akashi@linaro.org> References: <20191218004512.24939-1-takahiro.akashi@linaro.org> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.26 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: u-boot@lists.denx.de, mail@patrick-wildt.de Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.101.4 at phobos.denx.de X-Virus-Status: Clean Adding those extra configurations allows us to successfully run UEFI secure boot pytest on Travis CI. Signed-off-by: AKASHI Takahiro Reviewed-by: Simon Glass --- configs/sandbox64_defconfig | 3 +++ configs/sandbox_defconfig | 3 +++ 2 files changed, 6 insertions(+) diff --git a/configs/sandbox64_defconfig b/configs/sandbox64_defconfig index b0abf99386b9..c40e1d93465b 100644 --- a/configs/sandbox64_defconfig +++ b/configs/sandbox64_defconfig @@ -26,6 +26,7 @@ CONFIG_CMD_ASKENV=y CONFIG_CMD_GREPENV=y CONFIG_CMD_ENV_CALLBACK=y CONFIG_CMD_ENV_FLAGS=y +CONFIG_CMD_NVEDIT_EFI=y CONFIG_LOOPW=y CONFIG_CMD_MD5SUM=y CONFIG_CMD_MEMINFO=y @@ -52,6 +53,7 @@ CONFIG_CMD_DNS=y CONFIG_CMD_LINK_LOCAL=y CONFIG_CMD_ETHSW=y CONFIG_CMD_BMP=y +CONFIG_CMD_EFIDEBUG=y CONFIG_CMD_TIME=y CONFIG_CMD_TIMER=y CONFIG_CMD_SOUND=y @@ -194,6 +196,7 @@ CONFIG_CMD_DHRYSTONE=y CONFIG_TPM=y CONFIG_LZ4=y CONFIG_ERRNO_STR=y +CONFIG_EFI_SECURE_BOOT=y CONFIG_TEST_FDTDEC=y CONFIG_UNIT_TEST=y CONFIG_UT_TIME=y diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig index ee0ec3f233d0..3246348341a4 100644 --- a/configs/sandbox_defconfig +++ b/configs/sandbox_defconfig @@ -29,6 +29,7 @@ CONFIG_CMD_ASKENV=y CONFIG_CMD_GREPENV=y CONFIG_CMD_ENV_CALLBACK=y CONFIG_CMD_ENV_FLAGS=y +CONFIG_CMD_NVEDIT_EFI=y CONFIG_LOOPW=y CONFIG_CMD_MD5SUM=y CONFIG_CMD_MEMINFO=y @@ -60,6 +61,7 @@ CONFIG_CMD_LINK_LOCAL=y CONFIG_CMD_ETHSW=y CONFIG_CMD_BMP=y CONFIG_CMD_BOOTCOUNT=y +CONFIG_CMD_EFIDEBUG=y CONFIG_CMD_TIME=y CONFIG_CMD_TIMER=y CONFIG_CMD_SOUND=y @@ -221,6 +223,7 @@ CONFIG_CMD_DHRYSTONE=y CONFIG_TPM=y CONFIG_LZ4=y CONFIG_ERRNO_STR=y +CONFIG_EFI_SECURE_BOOT=y CONFIG_TEST_FDTDEC=y CONFIG_UNIT_TEST=y CONFIG_UT_TIME=y From patchwork Wed Dec 18 00:45:12 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: AKASHI Takahiro X-Patchwork-Id: 1211849 X-Patchwork-Delegate: xypron.glpk@gmx.de Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=linaro.org Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.b="rr3UfiCQ"; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [IPv6:2a01:238:438b:c500:173d:9f52:ddab:ee01]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 47cxDM6YTqz9sRl for ; Wed, 18 Dec 2019 11:47:15 +1100 (AEDT) Received: from phobos.denx.de (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 8036B81706; Wed, 18 Dec 2019 01:45:00 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=fail (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=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.b="rr3UfiCQ"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 8ACAA81704; Wed, 18 Dec 2019 01:44:53 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-0.1 required=5.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,SPF_HELO_NONE,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.2 Received: from mail-pg1-x543.google.com (mail-pg1-x543.google.com [IPv6:2607:f8b0:4864:20::543]) (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 F33AF81675 for ; Wed, 18 Dec 2019 01:44:49 +0100 (CET) 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-pg1-x543.google.com with SMTP id k25so248181pgt.7 for ; Tue, 17 Dec 2019 16:44:49 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=q+eCfgGmKlUB3NHQs1tAtNYzFMW1AghtJBNRV4XUMcM=; b=rr3UfiCQ3Trx6lByqtvql2Gv1c+F9lOGj1exdOUgY61L2UHjAFzGiipGoDppqJmPGV qGLm0LlQlmIyKZyj6oFNZQEUJpO6ckRVUkkUNJj1PdxjefqFg4YQL8sOVL1x0YBVGbPx iRumc4lcRW8+0frmXeNcdlvxBw5SPrZMQpvu8WmijpdpypoKBZdgkfufh/lHHZ5x/XZx edSUNU0r+3HRdy3Q6j8x6M0+VYqrMKAU3Hf+edNzWL/HoVUvY6Bf00mh+LaY05/OTF1w IPeEvjpte1HD8WNXkzNKO2FzpvWVXOWVNgZaCkDKLNH6oPCOQWVlJPaCkNmr3kuifXYM rjfw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=q+eCfgGmKlUB3NHQs1tAtNYzFMW1AghtJBNRV4XUMcM=; b=rPTUtxJxsUTgu5n6+f2Z7eCdOFYm1XHlxaOTo5nf1oJ+PFvOBjQctCqYBWyJ8Ezrwi 3Ux+VbjLS0/F6hkWiYsE27cx6s+ssAOe+VrrPy6DIsGK3RUB/rsNCOz6fgnqvQcAM+Q5 6Ua6SmHbmKMFksbSBGv78zxycWImv7UxJVrUOUq+1gSkxK6w4Cyarc+2sNLRGzcEXLO/ HLkDffcnuu7z65tlQaHKDORnYwR7oERYqv4ycw294KCF+L0nkrkq/LCX0Q6gQNIS7pPl GBcbcwzK4slLMhilY+wmVG7ZkH1ZzqLC/2P2fu1JkMdPXSR5ZpZrPjndKyerlNn7rihw 5jtQ== X-Gm-Message-State: APjAAAXzyHRfiYGrz8vUCu35TbABCpL3d3GxS4W7w7LetjzWw2SqVFFO YW5Vfy7DszjZYiE0Dst1VWdLTg== X-Google-Smtp-Source: APXvYqy3we8lIl2+etkdNprX9SGJZq9ZZ6AP/uW4+9IHizgYqYjTnOrWr7Hi1xqIu5Wa+Vz5u+f6Lg== X-Received: by 2002:a65:6842:: with SMTP id q2mr238266pgt.345.1576629888550; Tue, 17 Dec 2019 16:44:48 -0800 (PST) Received: from linaro.org ([121.95.100.191]) by smtp.googlemail.com with ESMTPSA id q15sm201761pgi.55.2019.12.17.16.44.47 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 17 Dec 2019 16:44:47 -0800 (PST) From: AKASHI Takahiro To: xypron.glpk@gmx.de, agraf@csgraf.de, trini@konsulko.com Subject: [PATCH v4 16/16] travis: add packages for UEFI secure boot test Date: Wed, 18 Dec 2019 09:45:12 +0900 Message-Id: <20191218004512.24939-17-takahiro.akashi@linaro.org> X-Mailer: git-send-email 2.24.0 In-Reply-To: <20191218004512.24939-1-takahiro.akashi@linaro.org> References: <20191218004512.24939-1-takahiro.akashi@linaro.org> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.26 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: u-boot@lists.denx.de, mail@patrick-wildt.de Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.101.4 at phobos.denx.de X-Virus-Status: Clean Pytest for UEFI secure boot will use several host commands. In particular, Test setup relies on efitools, whose version must be v1.5.2 or later. So fetch a new version of deb package directly. Please note it has a dependency on mtools, which must also be installed along wih efitools. In addition, the path, '/sbin', is added to PATH for use of sgdisk and mkfs. Signed-off-by: AKASHI Takahiro --- .travis.yml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index f6aec9677083..91b6d23ace98 100644 --- a/.travis.yml +++ b/.travis.yml @@ -38,6 +38,14 @@ addons: - libisl15 - clang-7 - srecord + - coreutils + - util-linux + - dosfstools + - gdisk + - mount + - mtools + - openssl + - sbsigntool install: # Clone uboot-test-hooks @@ -58,10 +66,11 @@ install: - mkdir ~/grub2-arm64 - ( cd ~/grub2-arm64; wget -O - http://download.opensuse.org/ports/aarch64/distribution/leap/42.2/repo/oss/suse/aarch64/grub2-arm64-efi-2.02~beta2-87.1.aarch64.rpm | rpm2cpio | cpio -di ) - wget http://mirrors.kernel.org/ubuntu/pool/main/m/mpfr4/libmpfr4_3.1.4-1_amd64.deb && sudo dpkg -i libmpfr4_3.1.4-1_amd64.deb && rm libmpfr4_3.1.4-1_amd64.deb + - wget http://mirrors.kernel.org/ubuntu/pool/universe/e/efitools/efitools_1.8.1-0ubuntu2_amd64.deb && sudo dpkg -i efitools_1.8.1-0ubuntu2_amd64.deb && rm efitools_1.8.1-0ubuntu2_amd64.deb env: global: - - PATH=/tmp/qemu-install/bin:/tmp/uboot-test-hooks/bin:/usr/bin:/bin:/usr/local/bin + - PATH=/tmp/qemu-install/bin:/tmp/uboot-test-hooks/bin:/sbin:/usr/bin:/bin:/usr/local/bin - PYTHONPATH=/tmp/uboot-test-hooks/py/travis-ci - BUILD_DIR=build - HOSTCC="cc"