From nobody Tue Feb 10 05:10:34 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) client-ip=66.175.222.108; envelope-from=bounce+27952+92361+1787277+3901457@groups.io; helo=mail02.groups.io; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce+27952+92361+1787277+3901457@groups.io; dmarc=fail(p=none dis=none) header.from=intel.com ARC-Seal: i=1; a=rsa-sha256; t=1660200860; cv=none; d=zohomail.com; s=zohoarc; b=d/gGrq+hOZ8GjQY4AZ/BWg98/tgyuY3OkU4TaTM2bX4GrWPHHP4hbqOgVt6SdTKz+ISzKSZWTvxfp6qawAGckkrfMVzKx1UOs2czzhj1RTV9MFNFHj3Z32F3ZHvQEjzMPr9m/95oP/14RJnntNMMBQQ+yHZs2fV5HXf9LHYv+kI= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1660200860; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:References:Sender:Subject:To; bh=lftFt/o2V06piswJSJSN87J1s5JfCdZVTOSFrFl0XgQ=; b=Cqe2pXO22S5G0qPUyjTIDdSllFDArtw4aPAc1cflEb3munJUiAM8nffqX6QLFYNo/L+WjwH1vPZwpbJjk1nwG0wGVNYFCs7VZHQwWJKlrn12Iub8Z+0yTgvBj5bzm63Jc8ogjud3R5sh8gvx4bD7SsNPNYRDevpPdvTjC3Ytc38= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce+27952+92361+1787277+3901457@groups.io; dmarc=fail header.from= (p=none dis=none) Received: from mail02.groups.io (mail02.groups.io [66.175.222.108]) by mx.zohomail.com with SMTPS id 1660200860188944.2160267149823; Wed, 10 Aug 2022 23:54:20 -0700 (PDT) Return-Path: X-Received: by 127.0.0.2 with SMTP id pfTiYY1788612xRSXQXSf8PT; Wed, 10 Aug 2022 23:54:18 -0700 X-Received: from mga05.intel.com (mga05.intel.com [192.55.52.43]) by mx.groups.io with SMTP id smtpd.web08.3540.1660200857329267552 for ; Wed, 10 Aug 2022 23:54:18 -0700 X-IronPort-AV: E=McAfee;i="6400,9594,10435"; a="377565829" X-IronPort-AV: E=Sophos;i="5.93,228,1654585200"; d="scan'208";a="377565829" X-Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by fmsmga105.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 10 Aug 2022 23:54:17 -0700 X-IronPort-AV: E=Sophos;i="5.93,228,1654585200"; d="scan'208";a="673586417" X-Received: from moisespe-mobl.amr.corp.intel.com (HELO jvang-mobl.amr.corp.intel.com) ([10.212.171.64]) by fmsmga004-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 10 Aug 2022 23:54:17 -0700 From: "Judah Vang" To: devel@edk2.groups.io Cc: Jian J Wang , Jiewen Yao , Min Xu , Nishant C Mistry Subject: [edk2-devel] [PATCH v4 17/28] SecurityPkg: Add EncryptionVariable lib with AES Date: Wed, 10 Aug 2022 23:53:26 -0700 Message-Id: <20220811065337.2068-18-judah.vang@intel.com> In-Reply-To: <20220811065337.2068-1-judah.vang@intel.com> References: <20220811065337.2068-1-judah.vang@intel.com> MIME-Version: 1.0 Precedence: Bulk List-Unsubscribe: List-Subscribe: List-Help: Sender: devel@edk2.groups.io List-Id: Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io Reply-To: devel@edk2.groups.io,judah.vang@intel.com X-Gm-Message-State: EuhJhThnGQlaOmGZLdSCR9eOx1787277AA= Content-Transfer-Encoding: quoted-printable DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=groups.io; q=dns/txt; s=20140610; t=1660200858; bh=Ssc1Ksf3wl9R0b0Azymz153h/E4pXDfDzw+b1i+yWHc=; h=Cc:Date:From:Reply-To:Subject:To; b=PFNAaJi0FCORDJBCS/j3awWNcddsdsAwQZGTjfc9QYKdzO3XxUGZzw3ZizRMyHzuBHn Zd7dAJpWp0d2KA2o5izVZDEeqc0BrnNEQNwCzj12QtPu5Gzh+smfORhkLxdb4Ix78HLFj C9kNGpNYqFPUWFgk9agGhv0S6BdihTu9CQY= X-ZohoMail-DKIM: pass (identity @groups.io) X-ZM-MESSAGEID: 1660200861904100073 Content-Type: text/plain; charset="utf-8" REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3D2594 V3: Change AllocateZeroPool() with AllocatePages() and FreePool() with FreePages(). FreePool() is not supported in PEI phase so this was causing a memory leak. Reverse the order of the FreePages() call. V1: Add encryption/decryption of protected variable functionality. Add functions to get/set cipher data of a protected variable. This is use for supporting confidentiality for protected variables. Cc: Jian J Wang Cc: Jiewen Yao Cc: Min Xu Cc: Nishant C Mistry Signed-off-by: Jian J Wang Signed-off-by: Nishant C Mistry Signed-off-by: Judah Vang Reviewed-by: Jian J Wang --- SecurityPkg/Library/EncryptionVariableLib/EncryptionVariableLib.inf | 43 = ++ SecurityPkg/Library/EncryptionVariableLib/EncryptionVariable.h | 49 = ++ SecurityPkg/Library/EncryptionVariableLib/EncryptionVariable.c | 734 = ++++++++++++++++++++ 3 files changed, 826 insertions(+) diff --git a/SecurityPkg/Library/EncryptionVariableLib/EncryptionVariableLi= b.inf b/SecurityPkg/Library/EncryptionVariableLib/EncryptionVariableLib.inf new file mode 100644 index 000000000000..7ece52f2fb58 --- /dev/null +++ b/SecurityPkg/Library/EncryptionVariableLib/EncryptionVariableLib.inf @@ -0,0 +1,43 @@ +## @file +# Provides variable encryption/decryption services. +# +# Copyright (c) 2022, Intel Corporation. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION =3D 0x00010029 + BASE_NAME =3D EncryptionVariableLib + FILE_GUID =3D 459E2CB0-AF4B-4415-B6A1-335E71FD8B85 + MODULE_TYPE =3D BASE + VERSION_STRING =3D 1.0 + LIBRARY_CLASS =3D EncryptionVariableLib + +# +# The following information is for reference only and not required by the = build tools. +# +# VALID_ARCHITECTURES =3D IA32 X64 +# + +[Sources] + EncryptionVariable.c + EncryptionVariable.h + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + SecurityPkg/SecurityPkg.dec + CryptoPkg/CryptoPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + DebugLib + MemoryAllocationLib + BaseCryptLib + +[Guids] + gEfiVariableGuid + gEfiAuthenticatedVariableGuid diff --git a/SecurityPkg/Library/EncryptionVariableLib/EncryptionVariable.h= b/SecurityPkg/Library/EncryptionVariableLib/EncryptionVariable.h new file mode 100644 index 000000000000..f35f9f9e3ad7 --- /dev/null +++ b/SecurityPkg/Library/EncryptionVariableLib/EncryptionVariable.h @@ -0,0 +1,49 @@ +/** @file + Definitions used by this library implementation. + +Copyright (c) 2022, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef ENCRYPTION_VARIABLE_H_ +#define ENCRYPTION_VARIABLE_H_ + +#define ENC_KEY_SEP L":" +#define ENC_KEY_SEP_SIZE 2 +#define ENC_KEY_NAME L"VAR_ENC_KEY" +#define ENC_KEY_NAME_SIZE 22 + +#define ENC_KEY_SIZE (256/8) +#define ENC_BLOCK_SIZE AES_BLOCK_SIZE +#define ENC_IVEC_SIZE ENC_BLOCK_SIZE + +#define ENC_PADDING_BYTE 0x0F + +// +// PKCS#5 padding +// +// #define AES_CIPHER_DATA_SIZE(PlainDataSize) +// (AES_BLOCK_SIZE + (PlainDataSize)) & (~(AES_BLOCK_SIZE - 1)) +// +#define AES_CIPHER_DATA_SIZE(PlainDataSize) ALIGN_VALUE (PlainDataSize, A= ES_BLOCK_SIZE) + +#define FREE_POOL(Address) \ + if ((Address) !=3D NULL) { \ + FreePool (Address); \ + (Address) =3D NULL; \ + } + +#pragma pack(1) + +typedef struct { + UINT32 DataType; // SYM_TYPE_AES + UINT32 HeaderSize; // sizeof(VARIABLE_ENCRYPTION_HEADER) + UINT32 PlainDataSize; // Plain data size + UINT32 CipherDataSize; // Cipher data size + UINT8 KeyIvec[ENC_IVEC_SIZE]; +} VARIABLE_ENCRYPTION_HEADER; + +#pragma pack() + +#endif // _ENCRYPTION_VARIABLE_H_ diff --git a/SecurityPkg/Library/EncryptionVariableLib/EncryptionVariable.c= b/SecurityPkg/Library/EncryptionVariableLib/EncryptionVariable.c new file mode 100644 index 000000000000..d128b32f93e0 --- /dev/null +++ b/SecurityPkg/Library/EncryptionVariableLib/EncryptionVariable.c @@ -0,0 +1,734 @@ +/** @file + Implementation of EncryptionVariableLib with AES algorithm support. + +Copyright (c) 2022, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include + +#include +#include +#include +#include +#include +#include + +#include "EncryptionVariable.h" + +/** + Derive encryption key for given variable from variable root key. + + The derivation algorithm is depicted below + + HKDF_Expand(SHA256, RootKey, Name||':'||Guid||':'||Attr||"VAR_ENC_KEY") + + @param[in] VarEncInfo Pointer to structure containing detailed + information about a variable. + @param[in] EncKeySize Size of key requested. + @param[out] EncKey Buffer of key. + + @retval TRUE The key was derived successfully. + @retval FALSE Failed to generate encryption key. + +**/ +STATIC +BOOLEAN +EncVarLibGenEncKey ( + IN VARIABLE_ENCRYPTION_INFO *VarEncInfo, + IN UINTN EncKeySize, + OUT UINT8 *EncKey + ) +{ + BOOLEAN Status; + + struct { + VOID *Data; + UINTN Size; + } InfoGroup[6]; + UINT8 *Info; + UINTN InfoSize; + UINTN Index; + UINT8 Salt[16]; + + // + // info: Name||':'||Guid||':'||Attr||"VAR_ENC_KEY" + // + InfoGroup[0].Size =3D VarEncInfo->Header.NameSize; + InfoGroup[0].Data =3D VarEncInfo->Header.VariableName; + + InfoGroup[1].Size =3D ENC_KEY_SEP_SIZE; + InfoGroup[1].Data =3D ENC_KEY_SEP; + + InfoGroup[2].Size =3D sizeof (*VarEncInfo->Header.VendorGuid); + InfoGroup[2].Data =3D VarEncInfo->Header.VendorGuid; + + InfoGroup[3].Size =3D ENC_KEY_SEP_SIZE; + InfoGroup[3].Data =3D ENC_KEY_SEP; + + InfoGroup[4].Size =3D sizeof (VarEncInfo->Header.Attributes); + InfoGroup[4].Data =3D &VarEncInfo->Header.Attributes; + + InfoGroup[5].Size =3D ENC_KEY_NAME_SIZE; + InfoGroup[5].Data =3D ENC_KEY_NAME; + + for (InfoSize =3D 0, Index =3D 0; Index < ARRAY_SIZE (InfoGroup); ++Inde= x) { + InfoSize +=3D InfoGroup[Index].Size; + } + + Info =3D AllocatePages (EFI_SIZE_TO_PAGES (InfoSize)); + if (Info =3D=3D NULL) { + ASSERT (Info !=3D NULL); + return FALSE; + } + + for (InfoSize =3D 0, Index =3D 0; Index < ARRAY_SIZE (InfoGroup); ++Inde= x) { + CopyMem (Info + InfoSize, InfoGroup[Index].Data, InfoGroup[Index].Size= ); + InfoSize +=3D InfoGroup[Index].Size; + } + + Status =3D HkdfSha256ExtractAndExpand ( + VarEncInfo->Key, + VarEncInfo->KeySize, + Salt, + 0, + Info, + InfoSize, + EncKey, + EncKeySize + ); + + FreePages (Info, EFI_SIZE_TO_PAGES (InfoSize)); + + return Status; +} + +/** + Generate init-vector for AES encryption. + + @param[out] InitVector IVEC buffer. + @param[in] Size Size of IVEC requested. + + @retval TRUE IVEC was generated successfully. + @retval FALSE Failed to generate IVEC. + +**/ +STATIC +BOOLEAN +EncVarLibGenIvec ( + OUT UINT8 *InitVector, + IN UINTN Size + ) +{ + return RandomBytes (InitVector, Size); +} + +/** + Check if there's valid variable information needed by encrypting or decr= ypting. + + @param[in] VarEncInfo Buffer conveying details about a variable. + @param[in] CheckForEnc Flag indicating check for encrypting (TRUE) = or + decrypting (FALSE). + + @retval TRUE VarEncInfo is valid. + @retval FALSE VarEncInfo is invalid. + +**/ +STATIC +BOOLEAN +IsValidVariableInfo ( + IN VARIABLE_ENCRYPTION_INFO *VarEncInfo, + IN BOOLEAN CheckForEnc + ) +{ + BOOLEAN Valid; + + if (CheckForEnc) { + Valid =3D (VarEncInfo->Header.Data !=3D NULL && VarEncInfo->Header.Dat= aSize > 0) + || (VarEncInfo->PlainData !=3D NULL && VarEncInfo->PlainDataSi= ze > 0); + if (!Valid) { + ASSERT ( + (VarEncInfo->Header.Data !=3D NULL && VarEncInfo->Header.DataSize = > 0) + || (VarEncInfo->PlainData !=3D NULL && VarEncInfo->PlainDataS= ize > 0) + ); + } + } else { + Valid =3D (VarEncInfo->Header.Data !=3D NULL && VarEncInfo->Header.Dat= aSize > 0) + || (VarEncInfo->CipherData !=3D NULL && VarEncInfo->CipherData= Size > 0); + if (!Valid) { + ASSERT ( + (VarEncInfo->Header.Data !=3D NULL && VarEncInfo->Header.DataSize = > 0) + || (VarEncInfo->CipherData !=3D NULL && VarEncInfo->CipherDat= aSize > 0) + ); + } + } + + Valid =3D Valid + && VarEncInfo->Header.VariableName !=3D NULL + && VarEncInfo->Header.NameSize > 0 + && VarEncInfo->Header.VendorGuid !=3D NULL + && VarEncInfo->Key !=3D NULL + && VarEncInfo->KeySize > 0; + if (!Valid) { + ASSERT (VarEncInfo->Header.VariableName !=3D NULL); + ASSERT (VarEncInfo->Header.NameSize !=3D 0); + ASSERT (VarEncInfo->Header.VendorGuid !=3D NULL); + ASSERT (VarEncInfo->Key !=3D NULL); + ASSERT (VarEncInfo->KeySize > 0); + } + + return Valid; +} + +/** + Sanity check of encrption header prefixed to encrypted data. + + @param[in] EncHeader Pointer to VARIABLE_ENCRYPTION_HEADER. + @param[in] DataSize Size of variable data payload. + + @retval TRUE EncHeader is valid. + @retval FALSE EncHeader is invalid. + +**/ +STATIC +BOOLEAN +IsValidEncrptionHeader ( + IN VARIABLE_ENCRYPTION_HEADER *EncHeader, + IN UINT32 DataSize + ) +{ + if ( (DataSize > sizeof (VARIABLE_ENCRYPTION_HEADER)) + && ((EncHeader->DataType =3D=3D ENC_TYPE_AES) || (EncHeader->DataType= =3D=3D ENC_TYPE_NULL)) + && (EncHeader->HeaderSize >=3D sizeof (VARIABLE_ENCRYPTION_HEADER)) + && (EncHeader->CipherDataSize > 0) + && ((EncHeader->CipherDataSize % ENC_BLOCK_SIZE) =3D=3D 0) + && (EncHeader->PlainDataSize > 0) + && (EncHeader->PlainDataSize <=3D EncHeader->CipherDataSize) + && ((EncHeader->CipherDataSize + EncHeader->HeaderSize) <=3D DataSize= )) + { + return TRUE; + } + + return FALSE; +} + +/** + Encrypt variable data. + + If VarEncInfo->PlainData is not NULL, VarEncInfo->PlainData holds the pl= ain + data. Otherwise, VarEncInfo->Headr.Data is supposed to be the plain data. + + If VarEncInfo->CipherData is not NULL, The encrypted data is stored in + VarEncInfo->CipherData. Otherwise, the encrypted data is stored directly + in variable data buffer, i.e. VarEncInfo->Headr.Data. + + @param[in, out] VarEncInfo Pointer to structure containing detailed + information about a variable. + + @retval EFI_SUCCESS Variable was encrypted successfully. + @retval EFI_INVALID_PARAMETER Variable information in VarEncInfo is in= valid. + @retval EFI_BUFFER_TOO_SMALL VarEncInfo->CipherData is not NULL but + VarEncInfo->CipherDataSize is too small. + @retval EFI_ABORTED Uknown error occurred during encrypting. + @retval EFI_OUT_OF_RESOURCES Fail to allocate enough resource. + @retval EFI_UNSUPPORTED Unsupported to encrypt variable. + +**/ +EFI_STATUS +EFIAPI +EncryptVariable ( + IN OUT VARIABLE_ENCRYPTION_INFO *VarEncInfo + ) +{ + EFI_STATUS Status; + VOID *AesContext; + UINT8 EncKey[ENC_KEY_SIZE]; + UINT8 Ivec[ENC_IVEC_SIZE]; + UINT8 *PlainBuffer; + UINT8 *CipherBuffer; + UINT8 *PlainData; + UINT32 PlainDataSize; + VARIABLE_ENCRYPTION_HEADER *CipherData; + UINT32 CipherDataSize; + UINT32 PaddingBytes; + + Status =3D EFI_ABORTED; + AesContext =3D NULL; + PlainBuffer =3D NULL; + CipherBuffer =3D NULL; + + if (!IsValidVariableInfo (VarEncInfo, TRUE)) { + return EFI_INVALID_PARAMETER; + } + + if (VarEncInfo->PlainData !=3D NULL) { + PlainData =3D VarEncInfo->PlainData; + PlainDataSize =3D VarEncInfo->PlainDataSize; + } else { + PlainData =3D VarEncInfo->Header.Data; + PlainDataSize =3D (UINT32)VarEncInfo->Header.DataSize; + } + + CipherDataSize =3D AES_CIPHER_DATA_SIZE (PlainDataSize); + if (VarEncInfo->CipherData !=3D NULL) { + if (VarEncInfo->CipherDataSize + < (CipherDataSize + sizeof (VARIABLE_ENCRYPTION_HEADER))) + { + VarEncInfo->CipherDataSize =3D CipherDataSize + + sizeof (VARIABLE_ENCRYPTION_HEADER); + return EFI_BUFFER_TOO_SMALL; + } + + CipherData =3D VarEncInfo->CipherData; + } else { + CipherData =3D VarEncInfo->Header.Data; + } + + // + // Prepare buffer for encrypted data. + // + if ((UINTN)CipherData =3D=3D (UINTN)PlainData) { + // + // Need buffer to store the encrypted data temporarily. + // + CipherBuffer =3D (UINT8 *)AllocateZeroPool ( + CipherDataSize + + sizeof (VARIABLE_ENCRYPTION_HEADER) + ); + if (CipherBuffer =3D=3D NULL) { + ASSERT (CipherBuffer !=3D NULL); + return EFI_OUT_OF_RESOURCES; + } + } else { + CipherBuffer =3D (UINT8 *)CipherData; + } + + // + // Plain variable data must also be multiple of ENC_BLOCK_SIZE. + // + PaddingBytes =3D ALIGN_VALUE (PlainDataSize, ENC_BLOCK_SIZE) - PlainData= Size; + if (PaddingBytes !=3D 0) { + // + // Since the plain data size will be saved in the VARIABLE_ENCRYPTION_= HEADER, + // there's no need to do PKCS way of padding. To save space, just padd= ing + // the plain data to be of the nearest n*ENC_BLOCK_SIZE. + // + PlainBuffer =3D AllocateZeroPool (PlainDataSize + PaddingBytes); + if (PlainBuffer =3D=3D NULL) { + ASSERT (PlainBuffer !=3D NULL); + goto Done; + } + + CopyMem (PlainBuffer, PlainData, PlainDataSize); + SetMem (PlainBuffer + PlainDataSize, PaddingBytes, ENC_PADDING_BYTE); + } else { + PlainBuffer =3D PlainData; + } + + // + // Skip EFI_VARIABLE_APPEND_WRITE bit in generating encryption key. + // + VarEncInfo->Header.Attributes &=3D (~EFI_VARIABLE_APPEND_WRITE); + if (!EncVarLibGenEncKey (VarEncInfo, ENC_KEY_SIZE, EncKey)) { + ASSERT (FALSE); + return EFI_ABORTED; + } + + if (!EncVarLibGenIvec (Ivec, ENC_IVEC_SIZE)) { + ASSERT (FALSE); + return EFI_ABORTED; + } + + AesContext =3D AllocateZeroPool (AesGetContextSize ()); + if (AesContext =3D=3D NULL) { + ASSERT (AesContext !=3D NULL); + return EFI_OUT_OF_RESOURCES; + } + + if (!AesInit (AesContext, EncKey, ENC_KEY_SIZE * 8)) { + ASSERT (FALSE); + goto Done; + } + + if (AesCbcEncrypt ( + AesContext, + PlainBuffer, + PlainDataSize + PaddingBytes, + Ivec, + CipherBuffer + sizeof (VARIABLE_ENCRYPTION_HEADER) + )) + { + // + // Keep the IV for decryption. + // + CopyMem (CipherData->KeyIvec, Ivec, ENC_BLOCK_SIZE); + + if ((UINTN)CipherBuffer !=3D (UINTN)CipherData) { + CopyMem ( + CipherData + 1, + CipherBuffer + sizeof (VARIABLE_ENCRYPTION_HEADER), + CipherDataSize + ); + } + + CipherData->CipherDataSize =3D CipherDataSize; + CipherData->PlainDataSize =3D PlainDataSize; + CipherData->DataType =3D ENC_TYPE_AES; + CipherData->HeaderSize =3D sizeof (VARIABLE_ENCRYPTION_HEADER); + + VarEncInfo->CipherData =3D CipherData; + VarEncInfo->CipherDataSize =3D CipherDataSize + sizeof (VARIABLE_ENC= RYPTION_HEADER); + VarEncInfo->CipherHeaderSize =3D sizeof (VARIABLE_ENCRYPTION_HEADER); + VarEncInfo->CipherDataType =3D ENC_TYPE_AES; + + Status =3D EFI_SUCCESS; + } else { + VarEncInfo->CipherData =3D NULL; + VarEncInfo->CipherDataSize =3D 0; + VarEncInfo->CipherHeaderSize =3D 0; + VarEncInfo->CipherDataType =3D ENC_TYPE_NULL; + + ASSERT (FALSE); + } + +Done: + FREE_POOL (AesContext); + if (PlainBuffer !=3D PlainData) { + FREE_POOL (PlainBuffer); + } + + if (CipherBuffer !=3D (UINT8 *)CipherData) { + FREE_POOL (CipherBuffer); + } + + return Status; +} + +/** + Decrypt variable data. + + If VarEncInfo->CipherData is not NULL, it must holds the cipher data to = be + decrypted. Otherwise, assume the cipher data from variable data buffer, = i.e. + VarEncInfo->Header.Data. + + If VarEncInfo->Flags.DecryptInPlace is TRUE, the decrypted data will be = put + back in the same buffer as cipher buffer got above, after encryption hea= der, + which helps to identify later if the data in buffer is decrypted or not.= This + can avoid repeat decryption when accessing the same variable more than o= nce. + + If VarEncInfo->Flags.DecryptInPlace is FALSE, VarEncInfo->PlainData must= be + passed in with a valid buffer with VarEncInfo->PlainDataSize set correct= ly + with its size. + + Note the VarEncInfo->PlainData is always pointing to the buffer address = with + decrypted data without encryption header, and VarEncInfo->PlainDataSize = is + always the size of original variable data, if this function returned + successfully. + + @param[in, out] VarEncInfo Pointer to structure containing detailed + information about a variable. + + @retval EFI_SUCCESS Variable was decrypted successfully. + @retval EFI_INVALID_PARAMETER Variable information in VarEncInfo is in= valid. + @retval EFI_BUFFER_TOO_SMALL VarEncInfo->PlainData is not NULL but + VarEncInfo->PlainDataSize is too small. + @retval EFI_ABORTED Uknown error occurred during decrypting. + @retval EFI_OUT_OF_RESOURCES Fail to allocate enough resource. + @retval EFI_COMPROMISED_DATA The cipher header is not valid. + @retval EFI_UNSUPPORTED Unsupported to encrypt variable. + +**/ +EFI_STATUS +EFIAPI +DecryptVariable ( + IN OUT VARIABLE_ENCRYPTION_INFO *VarEncInfo + ) +{ + VOID *AesContext; + UINT8 EncKey[ENC_KEY_SIZE]; + UINT8 *PlainBuffer; + UINT8 *PlainData; + VARIABLE_ENCRYPTION_HEADER *CipherData; + UINT32 CipherDataSize; + EFI_STATUS Status; + + Status =3D EFI_ABORTED; + AesContext =3D NULL; + PlainBuffer =3D NULL; + + if (!IsValidVariableInfo (VarEncInfo, FALSE)) { + return EFI_INVALID_PARAMETER; + } + + if (VarEncInfo->CipherData !=3D NULL) { + CipherData =3D VarEncInfo->CipherData; + CipherDataSize =3D VarEncInfo->CipherDataSize; + } else { + CipherData =3D VarEncInfo->Header.Data; + CipherDataSize =3D (UINT32)VarEncInfo->Header.DataSize; + } + + // + // Sanity check of cipher header. + // + if (!IsValidEncrptionHeader (CipherData, CipherDataSize)) { + return EFI_COMPROMISED_DATA; + } + + if ( (VarEncInfo->PlainData !=3D NULL) + && (VarEncInfo->PlainDataSize < CipherData->PlainDataSize)) + { + VarEncInfo->PlainDataSize =3D CipherData->PlainDataSize; + return EFI_BUFFER_TOO_SMALL; + } + + if (CipherData->DataType =3D=3D ENC_TYPE_AES) { + if (VarEncInfo->Flags.DecryptInPlace) { + // + // Reusing cipher data buffer needs to keep the encryption header. + // + PlainData =3D (UINT8 *)CipherData + CipherData->HeaderSize; + } else { + PlainData =3D VarEncInfo->PlainData; + } + + if (PlainData =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Always need buffer to store the decrypted data temporarily, due to + // padding bytes or buffer reuse. Then the buffer must be larger than + // CipherData->PlainDataSize. + // + PlainBuffer =3D AllocatePages (EFI_SIZE_TO_PAGES (CipherDataSize)); + if (PlainBuffer =3D=3D NULL) { + ASSERT (PlainBuffer !=3D NULL); + return EFI_OUT_OF_RESOURCES; + } + + if (!EncVarLibGenEncKey (VarEncInfo, ENC_KEY_SIZE, EncKey)) { + ASSERT (FALSE); + goto Done; + } + + AesContext =3D AllocatePages (EFI_SIZE_TO_PAGES (AesGetContextSize ())= ); + if (AesContext =3D=3D NULL) { + ASSERT (AesContext !=3D NULL); + Status =3D EFI_OUT_OF_RESOURCES; + goto Done; + } + + if (!AesInit (AesContext, EncKey, ENC_KEY_SIZE * 8)) { + ASSERT (FALSE); + goto Done; + } + + if (AesCbcDecrypt ( + AesContext, + (UINT8 *)CipherData + CipherData->HeaderSize, + CipherDataSize - CipherData->HeaderSize, + CipherData->KeyIvec, + PlainBuffer + )) + { + Status =3D EFI_SUCCESS; + } else { + Status =3D EFI_COMPROMISED_DATA; + } + } else { + // + // The data has been decrypted already. + // + PlainBuffer =3D (UINT8 *)CipherData + CipherData->HeaderSize; + + if (VarEncInfo->PlainData !=3D NULL) { + PlainData =3D VarEncInfo->PlainData; + } else { + PlainData =3D PlainBuffer; + } + + Status =3D EFI_SUCCESS; + } + + if (!EFI_ERROR (Status)) { + if (PlainBuffer !=3D PlainData) { + CopyMem (PlainData, PlainBuffer, CipherData->PlainDataSize); + } + + if (VarEncInfo->PlainData !=3D NULL) { + if (VarEncInfo->PlainData !=3D PlainBuffer) { + CopyMem (VarEncInfo->PlainData, PlainBuffer, CipherData->PlainData= Size); + } + } else { + VarEncInfo->PlainData =3D PlainData; + } + + VarEncInfo->PlainDataSize =3D CipherData->PlainDataSize; + VarEncInfo->CipherHeaderSize =3D CipherData->HeaderSize; + VarEncInfo->CipherDataType =3D CipherData->DataType; + + if (VarEncInfo->Flags.DecryptInPlace) { + CipherData->DataType =3D ENC_TYPE_NULL; + } + } + +Done: + if (AesContext !=3D NULL) { + FreePages (AesContext, EFI_SIZE_TO_PAGES (AesGetContextSize ())); + } + + if (PlainBuffer !=3D NULL) { + FreePages (PlainBuffer, EFI_SIZE_TO_PAGES ((CipherDataSize))); + } + + return Status; +} + +/** + Get cipher information about a variable, including plaindata size, + cipher algorithm type, etc. + + For data passed in with VarEncInfo, + + VarEncInfo->Header.Data + - The variable data in normal variable structure. + VarEncInfo->Header.DataSize + - The size of variable data. + + For data passed out with VarEncInfo (valid only if EFI_SUCCESS is return= ed), + + VarEncInfo->CipherDataType + - ENC_TYPE_NULL, if the variable is not encrypted or has been decryp= ted; + - ENC_TYPE_AES, if the variable is encrypted. + VarEncInfo->CipherHeaderSize + - Size of cipher header put before encrypted or decrypted data. + VarEncInfo->PlainData + - NULL, if the variable is encrypted; Or + - pointer to original variable data, if the variable has been decryp= ted. + VarEncInfo->PlainDataSize + - The size of original variable data + VarEncInfo->CipherData + - NULL, if the variable is decrypted; Or + - pointer to start of encrypted variable data, including encryption = header; + VarEncInfo->CipherDataSize + - The size of encrypted variable data, including encryption header. + + @param[in] VarEncInfo Pointer to structure containing detailed + information about a variable. + + @retval EFI_SUCCESS The information was retrieved successful= ly. + @retval EFI_INVALID_PARAMETER Variable information in VarEncInfo is in= valid. + @retval EFI_NOT_FOUND No cipher information recognized. + @retval EFI_UNSUPPORTED Unsupported interface. + +**/ +EFI_STATUS +EFIAPI +GetCipherDataInfo ( + IN VARIABLE_ENCRYPTION_INFO *VarEncInfo + ) +{ + VARIABLE_ENCRYPTION_HEADER *EncHeader; + + if ((VarEncInfo->Header.Data =3D=3D NULL) || (VarEncInfo->Header.DataSiz= e =3D=3D 0)) { + ASSERT (VarEncInfo->Header.Data !=3D NULL); + ASSERT (VarEncInfo->Header.DataSize !=3D 0); + return EFI_INVALID_PARAMETER; + } + + // + // Validate encryption header. + // + EncHeader =3D (VARIABLE_ENCRYPTION_HEADER *)VarEncInfo->Header.Data; + if (!IsValidEncrptionHeader (EncHeader, (UINT32)VarEncInfo->Header.DataS= ize)) { + // + // Not an encrypted variable. + // + return EFI_NOT_FOUND; + } + + if (EncHeader->DataType =3D=3D ENC_TYPE_NULL) { + // + // The data must have been decrypted. + // + VarEncInfo->PlainData =3D (UINT8 *)VarEncInfo->Header.Data = + EncHeader->HeaderSize; + VarEncInfo->CipherData =3D NULL; + VarEncInfo->Flags.DecryptInPlace =3D TRUE; + } else { + // + // The data is encrypted. + // + VarEncInfo->CipherData =3D VarEncInfo->Header.Data; + VarEncInfo->PlainData =3D NULL; + VarEncInfo->Flags.DecryptInPlace =3D FALSE; + } + + VarEncInfo->PlainDataSize =3D EncHeader->PlainDataSize; + VarEncInfo->CipherDataSize =3D EncHeader->CipherDataSize + EncHeader->= HeaderSize; + VarEncInfo->CipherDataType =3D EncHeader->DataType; + VarEncInfo->CipherHeaderSize =3D EncHeader->HeaderSize; + + return EFI_SUCCESS; +} + +/** + Force set cipher information for a variable, like plaindata size, + cipher algorithm type, cipher data etc. + + The destination buffer must be passed via VarEncInfo->Header.Data. + + This method is only used to update and/or change plain data information. + + @param[in] VarEncInfo Pointer to structure containing detailed + information about a variable. + + @retval EFI_SUCCESS The information was updated successfully. + @retval EFI_INVALID_PARAMETER Variable information in VarEncInfo is in= valid. + @retval EFI_UNSUPPORTED If this method is not supported. + +**/ +EFI_STATUS +EFIAPI +SetCipherDataInfo ( + IN VARIABLE_ENCRYPTION_INFO *VarEncInfo + ) +{ + VARIABLE_ENCRYPTION_HEADER *EncHeader; + UINT8 *Data; + + if ( (VarEncInfo->Header.Data =3D=3D NULL) + || (VarEncInfo->Header.DataSize < sizeof (VARIABLE_ENCRYPTION_HEADER)) + || (VarEncInfo->CipherDataType !=3D ENC_TYPE_NULL)) + { + ASSERT (VarEncInfo->Header.Data !=3D NULL); + ASSERT (VarEncInfo->Header.DataSize >=3D sizeof (VARIABLE_ENCRYPTION_H= EADER)); + ASSERT (VarEncInfo->CipherDataType =3D=3D ENC_TYPE_NULL); + return EFI_INVALID_PARAMETER; + } + + Data =3D VarEncInfo->Header.Data; + EncHeader =3D (VARIABLE_ENCRYPTION_HEADER *)Data; + + if ( !IsValidEncrptionHeader (EncHeader, (UINT32)VarEncInfo->Header.Dat= aSize) + || (VarEncInfo->PlainDataSize > EncHeader->CipherDataSize)) + { + return EFI_INVALID_PARAMETER; + } + + if ((VarEncInfo->PlainData !=3D NULL) && (VarEncInfo->PlainDataSize > 0)= ) { + CopyMem ( + Data + EncHeader->HeaderSize, + VarEncInfo->PlainData, + VarEncInfo->PlainDataSize + ); + } + + EncHeader->DataType =3D VarEncInfo->CipherDataType; + if (VarEncInfo->PlainDataSize !=3D 0) { + EncHeader->PlainDataSize =3D VarEncInfo->PlainDataSize; + } + + return EFI_SUCCESS; +} --=20 2.35.1.windows.2 -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#92361): https://edk2.groups.io/g/devel/message/92361 Mute This Topic: https://groups.io/mt/92953543/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-