From 91ae2988c62f03987fe02159d26b001a5201d812 Mon Sep 17 00:00:00 2001 From: Yonghong Zhu Date: Mon, 15 Aug 2016 13:52:12 +0800 Subject: [PATCH] BaseTools: FMP capsule add the support to generate auth info Current BaseTools cannot generate EFI_FIRMWARE_IMAGE_AUTHENTICATION for FMP capsule. this patch fix it by FDF spec's update to add the definition for CERTIFICATE_GUID and MONOTONIC_COUNT. BaseTools call the tool by CERTIFICATE_GUID to generate the certdata and fill the header info. Cc: Liming Gao Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Yonghong Zhu Reviewed-by: Liming Gao --- BaseTools/Source/Python/GenFds/Capsule.py | 80 +++++++++++++++++-- BaseTools/Source/Python/GenFds/CapsuleData.py | 4 +- BaseTools/Source/Python/GenFds/FdfParser.py | 64 +++++++++++++-- BaseTools/Source/Python/GenFds/GenFds.py | 59 +++++++++++++- BaseTools/Source/Python/GenFds/GuidSection.py | 59 +------------- 5 files changed, 194 insertions(+), 72 deletions(-) diff --git a/BaseTools/Source/Python/GenFds/Capsule.py b/BaseTools/Source/Python/GenFds/Capsule.py index 1683433e43..f8af12a7c2 100644 --- a/BaseTools/Source/Python/GenFds/Capsule.py +++ b/BaseTools/Source/Python/GenFds/Capsule.py @@ -1,7 +1,7 @@ ## @file # generate capsule # -# Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.
+# Copyright (c) 2007 - 2016, 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 @@ -25,9 +25,16 @@ from GenFds import GenFds from Common.Misc import PackRegistryFormatGuid import uuid from struct import pack +from GenFds import FindExtendTool +from Common import EdkLogger +from Common.BuildToolError import * T_CHAR_LF = '\n' +WIN_CERT_REVISION = 0x0200 +WIN_CERT_TYPE_EFI_GUID = 0x0EF1 +EFI_CERT_TYPE_PKCS7_GUID = uuid.UUID('{4aafd29d-68df-49ee-8aa9-347d375665a7}') +EFI_CERT_TYPE_RSA2048_SHA256_GUID = uuid.UUID('{a7717414-c616-4977-9420-844712a735bf}') ## create inf file describes what goes into capsule and call GenFv to generate capsule # @@ -98,6 +105,32 @@ class Capsule (CapsuleClassObject) : FwMgrHdr.write(pack('=HH', len(self.CapsuleDataList), len(self.FmpPayloadList))) FwMgrHdrSize = 4+2+2+8*(len(self.CapsuleDataList)+len(self.FmpPayloadList)) + # + # typedef struct _WIN_CERTIFICATE { + # UINT32 dwLength; + # UINT16 wRevision; + # UINT16 wCertificateType; + # //UINT8 bCertificate[ANYSIZE_ARRAY]; + # } WIN_CERTIFICATE; + # + # typedef struct _WIN_CERTIFICATE_UEFI_GUID { + # WIN_CERTIFICATE Hdr; + # EFI_GUID CertType; + # //UINT8 CertData[ANYSIZE_ARRAY]; + # } WIN_CERTIFICATE_UEFI_GUID; + # + # typedef struct { + # UINT64 MonotonicCount; + # WIN_CERTIFICATE_UEFI_GUID AuthInfo; + # } EFI_FIRMWARE_IMAGE_AUTHENTICATION; + # + # typedef struct _EFI_CERT_BLOCK_RSA_2048_SHA256 { + # EFI_GUID HashType; + # UINT8 PublicKey[256]; + # UINT8 Signature[256]; + # } EFI_CERT_BLOCK_RSA_2048_SHA256; + # + PreSize = FwMgrHdrSize Content = StringIO.StringIO() for driver in self.CapsuleDataList: @@ -108,10 +141,47 @@ class Capsule (CapsuleClassObject) : Content.write(File.read()) File.close() for fmp in self.FmpPayloadList: - payload = fmp.GenCapsuleSubItem() - FwMgrHdr.write(pack('=Q', PreSize)) - PreSize += len(payload) - Content.write(payload) + if fmp.Certificate_Guid: + ExternalTool, ExternalOption = FindExtendTool([], GenFdsGlobalVariable.ArchList, fmp.Certificate_Guid) + CmdOption = '' + CapInputFile = fmp.ImageFile + if not os.path.isabs(fmp.ImageFile): + CapInputFile = os.path.join(GenFdsGlobalVariable.WorkSpaceDir, fmp.ImageFile) + CapOutputTmp = os.path.join(GenFdsGlobalVariable.FvDir, self.UiCapsuleName) + '.tmp' + if ExternalTool == None: + EdkLogger.error("GenFds", GENFDS_ERROR, "No tool found with GUID %s" % fmp.Certificate_Guid) + else: + CmdOption += ExternalTool + if ExternalOption: + CmdOption = CmdOption + ' ' + ExternalOption + CmdOption += ' -e ' + ' --monotonic-count ' + str(fmp.MonotonicCount) + ' -o ' + CapOutputTmp + ' ' + CapInputFile + CmdList = CmdOption.split() + GenFdsGlobalVariable.CallExternalTool(CmdList, "Failed to generate FMP auth capsule") + if uuid.UUID(fmp.Certificate_Guid) == EFI_CERT_TYPE_PKCS7_GUID: + dwLength = 4 + 2 + 2 + 16 + os.path.getsize(CapOutputTmp) - os.path.getsize(CapInputFile) + else: + dwLength = 4 + 2 + 2 + 16 + 16 + 256 + 256 + Buffer = pack('Q', fmp.MonotonicCount) + Buffer += pack('I', dwLength) + Buffer += pack('H', WIN_CERT_REVISION) + Buffer += pack('H', WIN_CERT_TYPE_EFI_GUID) + Buffer += uuid.UUID(fmp.Certificate_Guid).get_bytes_le() + if os.path.exists(CapOutputTmp): + TmpFile = open(CapOutputTmp, 'rb') + Buffer += TmpFile.read() + TmpFile.close() + if fmp.VendorCodeFile: + VendorFile = open(fmp.VendorCodeFile, 'rb') + Buffer += VendorFile.read() + VendorFile.close() + FwMgrHdr.write(pack('=Q', PreSize)) + PreSize += len(Buffer) + Content.write(Buffer) + else: + payload = fmp.GenCapsuleSubItem() + FwMgrHdr.write(pack('=Q', PreSize)) + PreSize += len(payload) + Content.write(payload) BodySize = len(FwMgrHdr.getvalue()) + len(Content.getvalue()) Header.write(pack('=I', HdrSize + BodySize)) # diff --git a/BaseTools/Source/Python/GenFds/CapsuleData.py b/BaseTools/Source/Python/GenFds/CapsuleData.py index efc281222b..2a5c4545de 100644 --- a/BaseTools/Source/Python/GenFds/CapsuleData.py +++ b/BaseTools/Source/Python/GenFds/CapsuleData.py @@ -1,7 +1,7 @@ ## @file # generate capsule # -# Copyright (c) 2007-2013, Intel Corporation. All rights reserved.
+# Copyright (c) 2007-2016, 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 @@ -180,6 +180,8 @@ class CapsulePayload(CapsuleData): self.HardwareInstance = None self.ImageFile = None self.VendorCodeFile = None + self.Certificate_Guid = None + self.MonotonicCount = None def GenCapsuleSubItem(self): if not self.Version: diff --git a/BaseTools/Source/Python/GenFds/FdfParser.py b/BaseTools/Source/Python/GenFds/FdfParser.py index 8709cfc091..02ae7c9f9c 100644 --- a/BaseTools/Source/Python/GenFds/FdfParser.py +++ b/BaseTools/Source/Python/GenFds/FdfParser.py @@ -52,11 +52,13 @@ import Common.GlobalData as GlobalData from Common.Expression import * from Common import GlobalData from Common.String import ReplaceMacro - +import uuid from Common.Misc import tdict import Common.LongFilePathOs as os from Common.LongFilePathSupport import OpenLongFilePath as open +from Capsule import EFI_CERT_TYPE_PKCS7_GUID +from Capsule import EFI_CERT_TYPE_RSA2048_SHA256_GUID ##define T_CHAR_SPACE ' ' ##define T_CHAR_NULL '\0' @@ -1124,6 +1126,26 @@ class FdfParser: self.__UndoToken() return False + def __Verify(self, Name, Value, Scope): + if Scope in ['UINT64', 'UINT8']: + ValueNumber = 0 + try: + if Value.upper().startswith('0X'): + ValueNumber = int (Value, 16) + else: + ValueNumber = int (Value) + except: + EdkLogger.error("FdfParser", FORMAT_INVALID, "The value is not valid dec or hex number for %s." % Name) + if ValueNumber < 0: + EdkLogger.error("FdfParser", FORMAT_INVALID, "The value can't be set to negative value for %s." % Name) + if Scope == 'UINT64': + if ValueNumber >= 0x10000000000000000: + EdkLogger.error("FdfParser", FORMAT_INVALID, "Too large value for %s." % Name) + if Scope == 'UINT8': + if ValueNumber >= 0x100: + EdkLogger.error("FdfParser", FORMAT_INVALID, "Too large value for %s." % Name) + return True + ## __UndoToken() method # # Go back one token unit in file buffer @@ -3187,7 +3209,7 @@ class FdfParser: if not self.__GetNextToken(): raise Warning("The FMP payload section is empty!", self.FileName, self.CurrentLineNumber) - FmpKeyList = ['IMAGE_HEADER_INIT_VERSION', 'IMAGE_TYPE_ID', 'IMAGE_INDEX', 'HARDWARE_INSTANCE'] + FmpKeyList = ['IMAGE_HEADER_INIT_VERSION', 'IMAGE_TYPE_ID', 'IMAGE_INDEX', 'HARDWARE_INSTANCE', 'CERTIFICATE_GUID', 'MONOTONIC_COUNT'] while self.__Token in FmpKeyList: Name = self.__Token FmpKeyList.remove(Name) @@ -3195,32 +3217,58 @@ class FdfParser: raise Warning("expected '='", self.FileName, self.CurrentLineNumber) if Name == 'IMAGE_TYPE_ID': if not self.__GetNextGuid(): - raise Warning("expected GUID value for IMAGE_TYPE_ID", self.FileName, self.CurrentLineNumber) + raise Warning("expected GUID value for IMAGE_TYPE_ID.", self.FileName, self.CurrentLineNumber) FmpData.ImageTypeId = self.__Token + elif Name == 'CERTIFICATE_GUID': + if not self.__GetNextGuid(): + raise Warning("expected GUID value for CERTIFICATE_GUID.", self.FileName, self.CurrentLineNumber) + FmpData.Certificate_Guid = self.__Token + if uuid.UUID(FmpData.Certificate_Guid) != EFI_CERT_TYPE_RSA2048_SHA256_GUID and uuid.UUID(FmpData.Certificate_Guid) != EFI_CERT_TYPE_PKCS7_GUID: + raise Warning("Only support EFI_CERT_TYPE_RSA2048_SHA256_GUID or EFI_CERT_TYPE_PKCS7_GUID for CERTIFICATE_GUID.", self.FileName, self.CurrentLineNumber) else: if not self.__GetNextToken(): raise Warning("expected value of %s" % Name, self.FileName, self.CurrentLineNumber) Value = self.__Token if Name == 'IMAGE_HEADER_INIT_VERSION': - FmpData.Version = Value + if self.__Verify(Name, Value, 'UINT8'): + FmpData.Version = Value elif Name == 'IMAGE_INDEX': - FmpData.ImageIndex = Value + if self.__Verify(Name, Value, 'UINT8'): + FmpData.ImageIndex = Value elif Name == 'HARDWARE_INSTANCE': - FmpData.HardwareInstance = Value + if self.__Verify(Name, Value, 'UINT8'): + FmpData.HardwareInstance = Value + elif Name == 'MONOTONIC_COUNT': + if self.__Verify(Name, Value, 'UINT64'): + FmpData.MonotonicCount = Value + if FmpData.MonotonicCount.upper().startswith('0X'): + FmpData.MonotonicCount = (long)(FmpData.MonotonicCount, 16) + else: + FmpData.MonotonicCount = (long)(FmpData.MonotonicCount) if not self.__GetNextToken(): break else: self.__UndoToken() + if (FmpData.MonotonicCount and not FmpData.Certificate_Guid) or (not FmpData.MonotonicCount and FmpData.Certificate_Guid): + EdkLogger.error("FdfParser", FORMAT_INVALID, "CERTIFICATE_GUID and MONOTONIC_COUNT must be work as a pair.") + # remove CERTIFICATE_GUID and MONOTONIC_COUNT from FmpKeyList, since these keys are optional + if 'CERTIFICATE_GUID' in FmpKeyList: + FmpKeyList.remove('CERTIFICATE_GUID') + if 'MONOTONIC_COUNT' in FmpKeyList: + FmpKeyList.remove('MONOTONIC_COUNT') if FmpKeyList: - raise Warning("Missing keywords %s in FMP payload section" % ', '.join(FmpKeyList), self.FileName, self.CurrentLineNumber) + raise Warning("Missing keywords %s in FMP payload section." % ', '.join(FmpKeyList), self.FileName, self.CurrentLineNumber) ImageFile = self.__ParseRawFileStatement() if not ImageFile: - raise Warning("Missing image file in FMP payload section", self.FileName, self.CurrentLineNumber) + raise Warning("Missing image file in FMP payload section.", self.FileName, self.CurrentLineNumber) FmpData.ImageFile = ImageFile VendorCodeFile = self.__ParseRawFileStatement() if VendorCodeFile: FmpData.VendorCodeFile = VendorCodeFile + AdditionalFile = self.__ParseRawFileStatement() + if AdditionalFile: + raise Warning("At most one Image file and one Vendor code file are allowed in FMP payload section.", self.FileName, self.CurrentLineNumber) self.Profile.FmpPayloadDict[FmpUiName] = FmpData return True diff --git a/BaseTools/Source/Python/GenFds/GenFds.py b/BaseTools/Source/Python/GenFds/GenFds.py index f2de47ea83..c2e9418b84 100644 --- a/BaseTools/Source/Python/GenFds/GenFds.py +++ b/BaseTools/Source/Python/GenFds/GenFds.py @@ -415,7 +415,64 @@ def BuildOptionPcdValueFormat(TokenSpaceGuidCName, TokenCName, PcdDatumType, Val Value = '0' return Value - +## FindExtendTool() +# +# Find location of tools to process data +# +# @param KeyStringList Filter for inputs of section generation +# @param CurrentArchList Arch list +# @param NameGuid The Guid name +# +def FindExtendTool(KeyStringList, CurrentArchList, NameGuid): + # if user not specify filter, try to deduce it from global data. + if KeyStringList == None or KeyStringList == []: + Target = GenFdsGlobalVariable.TargetName + ToolChain = GenFdsGlobalVariable.ToolChainTag + ToolDb = ToolDefClassObject.ToolDefDict(GenFdsGlobalVariable.ConfDir).ToolsDefTxtDatabase + if ToolChain not in ToolDb['TOOL_CHAIN_TAG']: + EdkLogger.error("GenFds", GENFDS_ERROR, "Can not find external tool because tool tag %s is not defined in tools_def.txt!" % ToolChain) + KeyStringList = [Target + '_' + ToolChain + '_' + CurrentArchList[0]] + for Arch in CurrentArchList: + if Target + '_' + ToolChain + '_' + Arch not in KeyStringList: + KeyStringList.append(Target + '_' + ToolChain + '_' + Arch) + + if GenFdsGlobalVariable.GuidToolDefinition: + if NameGuid in GenFdsGlobalVariable.GuidToolDefinition.keys(): + return GenFdsGlobalVariable.GuidToolDefinition[NameGuid] + + ToolDefinition = ToolDefClassObject.ToolDefDict(GenFdsGlobalVariable.ConfDir).ToolsDefTxtDictionary + ToolPathTmp = None + ToolOption = None + for ToolDef in ToolDefinition.items(): + if NameGuid == ToolDef[1]: + KeyList = ToolDef[0].split('_') + Key = KeyList[0] + \ + '_' + \ + KeyList[1] + \ + '_' + \ + KeyList[2] + if Key in KeyStringList and KeyList[4] == 'GUID': + + ToolPath = ToolDefinition.get(Key + \ + '_' + \ + KeyList[3] + \ + '_' + \ + 'PATH') + + ToolOption = ToolDefinition.get(Key + \ + '_' + \ + KeyList[3] + \ + '_' + \ + 'FLAGS') + if ToolPathTmp == None: + ToolPathTmp = ToolPath + else: + if ToolPathTmp != ToolPath: + EdkLogger.error("GenFds", GENFDS_ERROR, "Don't know which tool to use, %s or %s ?" % (ToolPathTmp, ToolPath)) + + GenFdsGlobalVariable.GuidToolDefinition[NameGuid] = (ToolPathTmp, ToolOption) + return ToolPathTmp, ToolOption + ## Parse command line options # # Using standard Python module optparse to parse command line option of this tool. diff --git a/BaseTools/Source/Python/GenFds/GuidSection.py b/BaseTools/Source/Python/GenFds/GuidSection.py index ac5ae585f9..f199dcd2cc 100644 --- a/BaseTools/Source/Python/GenFds/GuidSection.py +++ b/BaseTools/Source/Python/GenFds/GuidSection.py @@ -27,6 +27,7 @@ from Common import EdkLogger from Common.BuildToolError import * from FvImageSection import FvImageSection from Common.LongFilePathSupport import OpenLongFilePath as open +from GenFds import FindExtendTool ## generate GUIDed section # @@ -128,7 +129,7 @@ class GuidSection(GuidSectionClassObject) : ExternalTool = None ExternalOption = None if self.NameGuid != None: - ExternalTool, ExternalOption = self.__FindExtendTool__() + ExternalTool, ExternalOption = FindExtendTool(self.KeyStringList, self.CurrentArchList, self.NameGuid) # # If not have GUID , call default @@ -249,61 +250,5 @@ class GuidSection(GuidSectionClassObject) : self.ProcessRequired = "TRUE" return OutputFileList, self.Alignment - ## __FindExtendTool() - # - # Find location of tools to process section data - # - # @param self The object pointer - # - def __FindExtendTool__(self): - # if user not specify filter, try to deduce it from global data. - if self.KeyStringList == None or self.KeyStringList == []: - Target = GenFdsGlobalVariable.TargetName - ToolChain = GenFdsGlobalVariable.ToolChainTag - ToolDb = ToolDefClassObject.ToolDefDict(GenFdsGlobalVariable.ConfDir).ToolsDefTxtDatabase - if ToolChain not in ToolDb['TOOL_CHAIN_TAG']: - EdkLogger.error("GenFds", GENFDS_ERROR, "Can not find external tool because tool tag %s is not defined in tools_def.txt!" % ToolChain) - self.KeyStringList = [Target + '_' + ToolChain + '_' + self.CurrentArchList[0]] - for Arch in self.CurrentArchList: - if Target + '_' + ToolChain + '_' + Arch not in self.KeyStringList: - self.KeyStringList.append(Target + '_' + ToolChain + '_' + Arch) - - if GenFdsGlobalVariable.GuidToolDefinition: - if self.NameGuid in GenFdsGlobalVariable.GuidToolDefinition.keys(): - return GenFdsGlobalVariable.GuidToolDefinition[self.NameGuid] - - ToolDefinition = ToolDefClassObject.ToolDefDict(GenFdsGlobalVariable.ConfDir).ToolsDefTxtDictionary - ToolPathTmp = None - ToolOption = None - for ToolDef in ToolDefinition.items(): - if self.NameGuid == ToolDef[1]: - KeyList = ToolDef[0].split('_') - Key = KeyList[0] + \ - '_' + \ - KeyList[1] + \ - '_' + \ - KeyList[2] - if Key in self.KeyStringList and KeyList[4] == 'GUID': - - ToolPath = ToolDefinition.get(Key + \ - '_' + \ - KeyList[3] + \ - '_' + \ - 'PATH') - - ToolOption = ToolDefinition.get(Key + \ - '_' + \ - KeyList[3] + \ - '_' + \ - 'FLAGS') - if ToolPathTmp == None: - ToolPathTmp = ToolPath - else: - if ToolPathTmp != ToolPath: - EdkLogger.error("GenFds", GENFDS_ERROR, "Don't know which tool to use, %s or %s ?" % (ToolPathTmp, ToolPath)) - - GenFdsGlobalVariable.GuidToolDefinition[self.NameGuid] = (ToolPathTmp, ToolOption) - return ToolPathTmp, ToolOption - -- 2.39.2