From 9c7d0d499296e444e39e9b6b34d8c121a325b295 Mon Sep 17 00:00:00 2001 From: Laszlo Ersek Date: Wed, 28 Mar 2018 03:04:06 +0200 Subject: [PATCH] OvmfPkg/TlsAuthConfigLib: configure trusted CA certs for HTTPS boot Introduce TlsAuthConfigLib to read the list of trusted CA certificates from fw_cfg and to store it to EFI_TLS_CA_CERTIFICATE_VARIABLE. The fw_cfg file is formatted by the "p11-kit" and "update-ca-trust" utilities on the host side, so that the host settings take effect in guest HTTPS boot as well. QEMU forwards the file intact to the firmware. The contents are sanity-checked by NetworkPkg/HttpDxe code that was added in commit 0fd13678a681. Link TlsAuthConfigLib via NULL resolution into TlsAuthConfigDxe. This sets EFI_TLS_CA_CERTIFICATE_VARIABLE in time for both NetworkPkg/TlsAuthConfigDxe (for possible HII interaction with the user) and for NetworkPkg/HttpDxe (for the effective TLS configuration). The file formatted by "p11-kit" can be large. On a RHEL-7 host, the the Mozilla CA root certificate bundle -- installed with the "ca-certificates" package -- is processed into a 182KB file. Thus, create EFI_TLS_CA_CERTIFICATE_VARIABLE as a volatile & boot-time only variable. Also, in TLS_ENABLE builds, set the cumulative limit for volatile variables (PcdVariableStoreSize) to 512KB, and the individual limit for the same (PcdMaxVolatileVariableSize) to 256KB. Cc: Ard Biesheuvel Cc: Gary Ching-Pang Lin Cc: Jordan Justen Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Laszlo Ersek Reviewed-by: Gary Lin Tested-by: Gary Lin Reviewed-by: Ard Biesheuvel --- .../TlsAuthConfigLib/TlsAuthConfigLib.c | 133 ++++++++++++++++++ .../TlsAuthConfigLib/TlsAuthConfigLib.inf | 55 ++++++++ OvmfPkg/OvmfPkgIa32.dsc | 13 +- OvmfPkg/OvmfPkgIa32X64.dsc | 13 +- OvmfPkg/OvmfPkgX64.dsc | 13 +- 5 files changed, 224 insertions(+), 3 deletions(-) create mode 100644 OvmfPkg/Library/TlsAuthConfigLib/TlsAuthConfigLib.c create mode 100644 OvmfPkg/Library/TlsAuthConfigLib/TlsAuthConfigLib.inf diff --git a/OvmfPkg/Library/TlsAuthConfigLib/TlsAuthConfigLib.c b/OvmfPkg/Library/TlsAuthConfigLib/TlsAuthConfigLib.c new file mode 100644 index 0000000000..b5b33bc4fc --- /dev/null +++ b/OvmfPkg/Library/TlsAuthConfigLib/TlsAuthConfigLib.c @@ -0,0 +1,133 @@ +/** @file + + A hook-in library for NetworkPkg/TlsAuthConfigDxe, in order to set volatile + variables related to TLS configuration, before TlsAuthConfigDxe or HttpDxe + (which is a UEFI_DRIVER) consume them. + + Copyright (C) 2013, 2015, 2018, Red Hat, Inc. + Copyright (c) 2008 - 2012, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials are licensed and made available + under the terms and conditions of the BSD License which accompanies this + distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT + WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include + +#include + +#include +#include +#include +#include +#include + +/** + Read the list of trusted CA certificates from the fw_cfg file + "etc/edk2/https/cacerts", and store it to + gEfiTlsCaCertificateGuid:EFI_TLS_CA_CERTIFICATE_VARIABLE. + + The contents are validated (for well-formedness) by NetworkPkg/HttpDxe. +**/ +STATIC +VOID +SetCaCerts ( + VOID + ) +{ + EFI_STATUS Status; + FIRMWARE_CONFIG_ITEM HttpsCaCertsItem; + UINTN HttpsCaCertsSize; + VOID *HttpsCaCerts; + + Status = QemuFwCfgFindFile ("etc/edk2/https/cacerts", &HttpsCaCertsItem, + &HttpsCaCertsSize); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_VERBOSE, "%a:%a: not touching CA cert list\n", + gEfiCallerBaseName, __FUNCTION__)); + return; + } + + // + // Delete the current EFI_TLS_CA_CERTIFICATE_VARIABLE if it exists. This + // serves two purposes: + // + // (a) If the variable exists with EFI_VARIABLE_NON_VOLATILE attribute, we + // cannot make it volatile without deleting it first. + // + // (b) If we fail to recreate the variable later, deleting the current one is + // still justified if the fw_cfg file exists. Emptying the set of trusted + // CA certificates will fail HTTPS boot, which is better than trusting + // any certificate that's possibly missing from the fw_cfg file. + // + Status = gRT->SetVariable ( + EFI_TLS_CA_CERTIFICATE_VARIABLE, // VariableName + &gEfiTlsCaCertificateGuid, // VendorGuid + 0, // Attributes + 0, // DataSize + NULL // Data + ); + if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) { + // + // This is fatal. + // + DEBUG ((DEBUG_ERROR, "%a:%a: failed to delete %g:\"%s\"\n", + gEfiCallerBaseName, __FUNCTION__, &gEfiTlsCaCertificateGuid, + EFI_TLS_CA_CERTIFICATE_VARIABLE)); + ASSERT_EFI_ERROR (Status); + CpuDeadLoop (); + } + + if (HttpsCaCertsSize == 0) { + DEBUG ((DEBUG_VERBOSE, "%a:%a: applied empty CA cert list\n", + gEfiCallerBaseName, __FUNCTION__)); + return; + } + + HttpsCaCerts = AllocatePool (HttpsCaCertsSize); + if (HttpsCaCerts == NULL) { + DEBUG ((DEBUG_ERROR, "%a:%a: failed to allocate HttpsCaCerts\n", + gEfiCallerBaseName, __FUNCTION__)); + return; + } + + QemuFwCfgSelectItem (HttpsCaCertsItem); + QemuFwCfgReadBytes (HttpsCaCertsSize, HttpsCaCerts); + + Status = gRT->SetVariable ( + EFI_TLS_CA_CERTIFICATE_VARIABLE, // VariableName + &gEfiTlsCaCertificateGuid, // VendorGuid + EFI_VARIABLE_BOOTSERVICE_ACCESS, // Attributes + HttpsCaCertsSize, // DataSize + HttpsCaCerts // Data + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a:%a: failed to set %g:\"%s\": %r\n", + gEfiCallerBaseName, __FUNCTION__, &gEfiTlsCaCertificateGuid, + EFI_TLS_CA_CERTIFICATE_VARIABLE, Status)); + goto FreeHttpsCaCerts; + } + + DEBUG ((DEBUG_VERBOSE, "%a:%a: stored CA cert list (%Lu byte(s))\n", + gEfiCallerBaseName, __FUNCTION__, (UINT64)HttpsCaCertsSize)); + +FreeHttpsCaCerts: + FreePool (HttpsCaCerts); +} + +RETURN_STATUS +EFIAPI +TlsAuthConfigInit ( + VOID + ) +{ + SetCaCerts (); + + return RETURN_SUCCESS; +} diff --git a/OvmfPkg/Library/TlsAuthConfigLib/TlsAuthConfigLib.inf b/OvmfPkg/Library/TlsAuthConfigLib/TlsAuthConfigLib.inf new file mode 100644 index 0000000000..5f83582a83 --- /dev/null +++ b/OvmfPkg/Library/TlsAuthConfigLib/TlsAuthConfigLib.inf @@ -0,0 +1,55 @@ +## @file +# +# A hook-in library for NetworkPkg/TlsAuthConfigDxe, in order to set volatile +# variables related to TLS configuration, before TlsAuthConfigDxe or HttpDxe +# (which is a UEFI_DRIVER) consume them. +# +# Copyright (C) 2013, 2015, 2018, Red Hat, Inc. +# Copyright (c) 2008 - 2012, Intel Corporation. All rights reserved.
+# +# This program and the accompanying materials are licensed and made available +# under the terms and conditions of the BSD License which accompanies this +# distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT +# WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 1.26 + BASE_NAME = TlsAuthConfigLib + FILE_GUID = 660AB627-4C5F-4D42-A3B6-BD021E9028BD + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = TlsAuthConfigLib|DXE_DRIVER + CONSTRUCTOR = TlsAuthConfigInit + +# +# The following information is for reference only and not required by the build +# tools. +# +# VALID_ARCHITECTURES = IA32 X64 ARM AARCH64 +# + +[Sources] + TlsAuthConfigLib.c + +[Packages] + MdePkg/MdePkg.dec + NetworkPkg/NetworkPkg.dec + OvmfPkg/OvmfPkg.dec + +[LibraryClasses] + BaseLib + DebugLib + MemoryAllocationLib + QemuFwCfgLib + UefiRuntimeServicesTableLib + +[Guids] + gEfiTlsCaCertificateGuid ## PRODUCES ## Variable:L"TlsCaCertificate" + +[Depex] + gEfiVariableWriteArchProtocolGuid diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc index 7664b50dde..c9eb248506 100644 --- a/OvmfPkg/OvmfPkgIa32.dsc +++ b/OvmfPkg/OvmfPkgIa32.dsc @@ -439,15 +439,23 @@ !if ($(FD_SIZE_IN_KB) == 1024) || ($(FD_SIZE_IN_KB) == 2048) gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize|0x2000 gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize|0x2800 +!if $(TLS_ENABLE) == FALSE # match PcdFlashNvStorageVariableSize purely for convenience gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize|0xe000 !endif +!endif !if $(FD_SIZE_IN_KB) == 4096 gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize|0x8400 gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize|0x8400 +!if $(TLS_ENABLE) == FALSE # match PcdFlashNvStorageVariableSize purely for convenience gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize|0x40000 !endif +!endif +!if $(TLS_ENABLE) == TRUE + gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize|0x80000 + gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVolatileVariableSize|0x40000 +!endif gEfiMdeModulePkgTokenSpaceGuid.PcdVpdBaseAddress|0x0 @@ -796,7 +804,10 @@ !endif !if $(TLS_ENABLE) == TRUE NetworkPkg/TlsDxe/TlsDxe.inf - NetworkPkg/TlsAuthConfigDxe/TlsAuthConfigDxe.inf + NetworkPkg/TlsAuthConfigDxe/TlsAuthConfigDxe.inf { + + NULL|OvmfPkg/Library/TlsAuthConfigLib/TlsAuthConfigLib.inf + } !endif OvmfPkg/VirtioNetDxe/VirtioNet.inf diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc index e5969090d4..17aef2d483 100644 --- a/OvmfPkg/OvmfPkgIa32X64.dsc +++ b/OvmfPkg/OvmfPkgIa32X64.dsc @@ -444,15 +444,23 @@ !if ($(FD_SIZE_IN_KB) == 1024) || ($(FD_SIZE_IN_KB) == 2048) gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize|0x2000 gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize|0x2800 +!if $(TLS_ENABLE) == FALSE # match PcdFlashNvStorageVariableSize purely for convenience gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize|0xe000 !endif +!endif !if $(FD_SIZE_IN_KB) == 4096 gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize|0x8400 gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize|0x8400 +!if $(TLS_ENABLE) == FALSE # match PcdFlashNvStorageVariableSize purely for convenience gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize|0x40000 !endif +!endif +!if $(TLS_ENABLE) == TRUE + gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize|0x80000 + gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVolatileVariableSize|0x40000 +!endif gEfiMdeModulePkgTokenSpaceGuid.PcdVpdBaseAddress|0x0 @@ -805,7 +813,10 @@ !endif !if $(TLS_ENABLE) == TRUE NetworkPkg/TlsDxe/TlsDxe.inf - NetworkPkg/TlsAuthConfigDxe/TlsAuthConfigDxe.inf + NetworkPkg/TlsAuthConfigDxe/TlsAuthConfigDxe.inf { + + NULL|OvmfPkg/Library/TlsAuthConfigLib/TlsAuthConfigLib.inf + } !endif OvmfPkg/VirtioNetDxe/VirtioNet.inf diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc index 7197c1984a..8af763ea9e 100644 --- a/OvmfPkg/OvmfPkgX64.dsc +++ b/OvmfPkg/OvmfPkgX64.dsc @@ -444,15 +444,23 @@ !if ($(FD_SIZE_IN_KB) == 1024) || ($(FD_SIZE_IN_KB) == 2048) gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize|0x2000 gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize|0x2800 +!if $(TLS_ENABLE) == FALSE # match PcdFlashNvStorageVariableSize purely for convenience gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize|0xe000 !endif +!endif !if $(FD_SIZE_IN_KB) == 4096 gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize|0x8400 gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize|0x8400 +!if $(TLS_ENABLE) == FALSE # match PcdFlashNvStorageVariableSize purely for convenience gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize|0x40000 !endif +!endif +!if $(TLS_ENABLE) == TRUE + gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize|0x80000 + gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVolatileVariableSize|0x40000 +!endif gEfiMdeModulePkgTokenSpaceGuid.PcdVpdBaseAddress|0x0 @@ -803,7 +811,10 @@ !endif !if $(TLS_ENABLE) == TRUE NetworkPkg/TlsDxe/TlsDxe.inf - NetworkPkg/TlsAuthConfigDxe/TlsAuthConfigDxe.inf + NetworkPkg/TlsAuthConfigDxe/TlsAuthConfigDxe.inf { + + NULL|OvmfPkg/Library/TlsAuthConfigLib/TlsAuthConfigLib.inf + } !endif OvmfPkg/VirtioNetDxe/VirtioNet.inf