From nobody Fri Apr 19 11:55:17 2024 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+89434+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+89434+1787277+3901457@groups.io; dmarc=fail(p=none dis=none) header.from=intel.com ARC-Seal: i=1; a=rsa-sha256; t=1651255524; cv=none; d=zohomail.com; s=zohoarc; b=G5tfO8zS1cKzp+VezbULkgioxAYa/MjuK3tVYdq5FUGSKmWHNbvUdKiDUBz3u6nJaJZ3D68lbwhMW5wM9H4GiuHcCnXJRf7ooINdPIMvM2I3Z0//R5SoZh1xMsPeEyZnS+j2pRtTjF3lp0sFWs4P3Vn4gOrKiJ4L0SfNTqNICKk= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1651255524; 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=NjcoZ2JQZjqbMI3N6mZDh76NQ//IKFxLLUZTrwDH1fU=; b=dLezvh3Bg79jlAi0he9kfANZXuwrXn9+Q4c9jS6VE21LMXs32aMG3pywJrcXzcQNQlSXk94qDxNGQQ0JmyfbTkNNIbQrVu4xQzjhrqpxACCSOecyELqC2UxDDQgmTzrOLg/fBNjglMA3bRE7jrFwbDKxl7hSC9C5/2ZHPYq/IYY= 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+89434+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 1651255524674718.1013952280558; Fri, 29 Apr 2022 11:05:24 -0700 (PDT) Return-Path: X-Received: by 127.0.0.2 with SMTP id 0DoKYY1788612xCUv5r5gAcX; Fri, 29 Apr 2022 11:05:24 -0700 X-Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) by mx.groups.io with SMTP id smtpd.web11.13472.1651255521036807512 for ; Fri, 29 Apr 2022 11:05:22 -0700 X-IronPort-AV: E=McAfee;i="6400,9594,10332"; a="266550652" X-IronPort-AV: E=Sophos;i="5.91,186,1647327600"; d="scan'208";a="266550652" X-Received: from orsmga003.jf.intel.com ([10.7.209.27]) by orsmga103.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 29 Apr 2022 11:05:20 -0700 X-IronPort-AV: E=Sophos;i="5.91,186,1647327600"; d="scan'208";a="514955740" X-Received: from jvang-mobl.amr.corp.intel.com ([10.212.198.238]) by orsmga003-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 29 Apr 2022 11:05:20 -0700 From: "Judah Vang" To: devel@edk2.groups.io Cc: Jian J Wang , Jiewen Yao , Nishant C Mistry Subject: [edk2-devel] [Patch v2 16/28] SecurityPkg: Add EncryptionVariable lib with AES Date: Fri, 29 Apr 2022 11:04:18 -0700 Message-Id: <20220429180430.3292-17-judah.vang@intel.com> In-Reply-To: <20220429180430.3292-1-judah.vang@intel.com> References: <20220429180430.3292-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: JQj3xlqTclN0WKoeKODG13oJx1787277AA= Content-Transfer-Encoding: quoted-printable DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=groups.io; q=dns/txt; s=20140610; t=1651255524; bh=4dMKsIAyCoEw1T/zz8xx4Nu0/48En+0WS/lrCzlZUsw=; h=Cc:Date:From:Reply-To:Subject:To; b=b8kSbrbLR6PIuR073sUNvuPBTVSx8P9/UvRnikhPVFH1lAq6/ugVaqOnD0pAWkUtj1W Qxb4l68qhkKcaFh/MU7MZqkatR+ZTKwaQ0s5Eua0zfLlE3Tmn79efbfw//5/6GjBl8RiM xHo0hDnF0ULHpSo+J4VTQ+u+kSxNOcED8Bs= X-ZohoMail-DKIM: pass (identity @groups.io) X-ZM-MESSAGEID: 1651255528327100061 Content-Type: text/plain; charset="utf-8" REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3D2594 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: Nishant C Mistry Signed-off-by: Jian J Wang Signed-off-by: Nishant C Mistry Signed-off-by: Judah Vang --- SecurityPkg/Library/EncryptionVariableLib/EncryptionVariableLib.inf | 43 = ++ SecurityPkg/Library/EncryptionVariableLib/EncryptionVariable.h | 49 = ++ SecurityPkg/Library/EncryptionVariableLib/EncryptionVariable.c | 728 = ++++++++++++++++++++ 3 files changed, 820 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..58ffb09e0373 --- /dev/null +++ b/SecurityPkg/Library/EncryptionVariableLib/EncryptionVariable.c @@ -0,0 +1,728 @@ +/** @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 AllocateZeroPool (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 + ); + + FreePool (Info); + + 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: + FreePages (PlainBuffer, EFI_SIZE_TO_PAGES ((CipherDataSize))); + FreePages (AesContext, EFI_SIZE_TO_PAGES (AesGetContextSize ())); + 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 (#89434): https://edk2.groups.io/g/devel/message/89434 Mute This Topic: https://groups.io/mt/90781904/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-