From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mga01.intel.com (mga01.intel.com [192.55.52.88]) by ml01.01.org (Postfix) with ESMTP id D42FE1A1E18 for ; Mon, 15 Aug 2016 01:18:01 -0700 (PDT) Received: from orsmga003.jf.intel.com ([10.7.209.27]) by fmsmga101.fm.intel.com with ESMTP; 15 Aug 2016 01:18:01 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.28,524,1464678000"; d="scan'208";a="865544512" Received: from shwdeopenpsi168.ccr.corp.intel.com ([10.239.158.144]) by orsmga003.jf.intel.com with ESMTP; 15 Aug 2016 01:18:00 -0700 From: Yonghong Zhu To: edk2-devel@lists.01.org Cc: Liming Gao Date: Mon, 15 Aug 2016 16:17:39 +0800 Message-Id: <1471249059-95652-4-git-send-email-yonghong.zhu@intel.com> X-Mailer: git-send-email 2.6.1.windows.1 In-Reply-To: <1471249059-95652-1-git-send-email-yonghong.zhu@intel.com> References: <1471249059-95652-1-git-send-email-yonghong.zhu@intel.com> Subject: [Patch 3/3] BaseTools: FMP capsule add the support to generate auth info X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 15 Aug 2016 08:18:02 -0000 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 --- 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 1683433..f8af12a 100644 --- a/BaseTools/Source/Python/GenFds/Capsule.py +++ b/BaseTools/Source/Python/GenFds/Capsule.py @@ -1,9 +1,9 @@ ## @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 # which accompanies this distribution. The full text of the license may be found at # http://opensource.org/licenses/bsd-license.php @@ -23,13 +23,20 @@ import StringIO from Common.Misc import SaveFileOnChange 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 # # class Capsule (CapsuleClassObject) : @@ -96,24 +103,87 @@ class Capsule (CapsuleClassObject) : else: FwMgrHdr.write(pack('=I', 0x00000001)) 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: FileName = driver.GenCapsuleSubItem() FwMgrHdr.write(pack('=Q', PreSize)) PreSize += os.path.getsize(FileName) File = open(FileName, 'rb') 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)) # # The real capsule header structure is 28 bytes # diff --git a/BaseTools/Source/Python/GenFds/CapsuleData.py b/BaseTools/Source/Python/GenFds/CapsuleData.py index efc2812..2a5c454 100644 --- a/BaseTools/Source/Python/GenFds/CapsuleData.py +++ b/BaseTools/Source/Python/GenFds/CapsuleData.py @@ -1,9 +1,9 @@ ## @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 # which accompanies this distribution. The full text of the license may be found at # http://opensource.org/licenses/bsd-license.php @@ -178,10 +178,12 @@ class CapsulePayload(CapsuleData): self.ImageTypeId = None self.ImageIndex = None self.HardwareInstance = None self.ImageFile = None self.VendorCodeFile = None + self.Certificate_Guid = None + self.MonotonicCount = None def GenCapsuleSubItem(self): if not self.Version: self.Version = 0x00000002 ImageFileSize = os.path.getsize(self.ImageFile) diff --git a/BaseTools/Source/Python/GenFds/FdfParser.py b/BaseTools/Source/Python/GenFds/FdfParser.py index 8709cfc..02ae7c9 100644 --- a/BaseTools/Source/Python/GenFds/FdfParser.py +++ b/BaseTools/Source/Python/GenFds/FdfParser.py @@ -50,15 +50,17 @@ from Common.Misc import PathClass from Common.String import NormPath 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' ##define T_CHAR_CR '\r' ##define T_CHAR_TAB '\t' @@ -1122,10 +1124,30 @@ class FdfParser: return True else: 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 # # @param self The object pointer @@ -3185,44 +3207,70 @@ class FdfParser: if not self.__IsToken( "]"): raise Warning("expected ']'", self.FileName, self.CurrentLineNumber) 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) if not self.__IsToken("="): 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 ## __GetCapsule() method # diff --git a/BaseTools/Source/Python/GenFds/GenFds.py b/BaseTools/Source/Python/GenFds/GenFds.py index 68232c5..1a0ec7a 100644 --- a/BaseTools/Source/Python/GenFds/GenFds.py +++ b/BaseTools/Source/Python/GenFds/GenFds.py @@ -410,11 +410,68 @@ def BuildOptionPcdValueFormat(TokenSpaceGuidCName, TokenCName, PcdDatumType, Val Value = '1' elif Value == 'FALSE' or Value == '0': 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. # # @retval Opt A optparse.Values object containing the parsed options diff --git a/BaseTools/Source/Python/GenFds/GuidSection.py b/BaseTools/Source/Python/GenFds/GuidSection.py index ac5ae58..f199dcd 100644 --- a/BaseTools/Source/Python/GenFds/GuidSection.py +++ b/BaseTools/Source/Python/GenFds/GuidSection.py @@ -25,10 +25,11 @@ from Common import ToolDefClassObject import sys 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 # # class GuidSection(GuidSectionClassObject) : @@ -126,11 +127,11 @@ class GuidSection(GuidSectionClassObject) : OutputFile = os.path.normpath(OutputFile) 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 # GENCRC32 section # @@ -247,63 +248,7 @@ class GuidSection(GuidSectionClassObject) : self.Alignment = None self.IncludeFvSection = False 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.6.1.windows.1