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 <liming.gao@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Yonghong Zhu <yonghong.zhu@intel.com>
Reviewed-by: Liming Gao <liming.gao@intel.com>
This commit is contained in:
Yonghong Zhu 2016-08-15 13:52:12 +08:00
parent 9b98c41640
commit 91ae2988c6
5 changed files with 194 additions and 72 deletions

View File

@ -1,7 +1,7 @@
## @file ## @file
# generate capsule # generate capsule
# #
# Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR> # Copyright (c) 2007 - 2016, Intel Corporation. All rights reserved.<BR>
# #
# This program and the accompanying materials # This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License # 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 from Common.Misc import PackRegistryFormatGuid
import uuid import uuid
from struct import pack from struct import pack
from GenFds import FindExtendTool
from Common import EdkLogger
from Common.BuildToolError import *
T_CHAR_LF = '\n' 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 ## 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))) FwMgrHdr.write(pack('=HH', len(self.CapsuleDataList), len(self.FmpPayloadList)))
FwMgrHdrSize = 4+2+2+8*(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 PreSize = FwMgrHdrSize
Content = StringIO.StringIO() Content = StringIO.StringIO()
for driver in self.CapsuleDataList: for driver in self.CapsuleDataList:
@ -108,6 +141,43 @@ class Capsule (CapsuleClassObject) :
Content.write(File.read()) Content.write(File.read())
File.close() File.close()
for fmp in self.FmpPayloadList: for fmp in self.FmpPayloadList:
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() payload = fmp.GenCapsuleSubItem()
FwMgrHdr.write(pack('=Q', PreSize)) FwMgrHdr.write(pack('=Q', PreSize))
PreSize += len(payload) PreSize += len(payload)

View File

@ -1,7 +1,7 @@
## @file ## @file
# generate capsule # generate capsule
# #
# Copyright (c) 2007-2013, Intel Corporation. All rights reserved.<BR> # Copyright (c) 2007-2016, Intel Corporation. All rights reserved.<BR>
# #
# This program and the accompanying materials # This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License # 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.HardwareInstance = None
self.ImageFile = None self.ImageFile = None
self.VendorCodeFile = None self.VendorCodeFile = None
self.Certificate_Guid = None
self.MonotonicCount = None
def GenCapsuleSubItem(self): def GenCapsuleSubItem(self):
if not self.Version: if not self.Version:

View File

@ -52,11 +52,13 @@ import Common.GlobalData as GlobalData
from Common.Expression import * from Common.Expression import *
from Common import GlobalData from Common import GlobalData
from Common.String import ReplaceMacro from Common.String import ReplaceMacro
import uuid
from Common.Misc import tdict from Common.Misc import tdict
import Common.LongFilePathOs as os import Common.LongFilePathOs as os
from Common.LongFilePathSupport import OpenLongFilePath as open 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_SPACE ' '
##define T_CHAR_NULL '\0' ##define T_CHAR_NULL '\0'
@ -1124,6 +1126,26 @@ class FdfParser:
self.__UndoToken() self.__UndoToken()
return False 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 ## __UndoToken() method
# #
# Go back one token unit in file buffer # Go back one token unit in file buffer
@ -3187,7 +3209,7 @@ class FdfParser:
if not self.__GetNextToken(): if not self.__GetNextToken():
raise Warning("The FMP payload section is empty!", self.FileName, self.CurrentLineNumber) 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: while self.__Token in FmpKeyList:
Name = self.__Token Name = self.__Token
FmpKeyList.remove(Name) FmpKeyList.remove(Name)
@ -3195,32 +3217,58 @@ class FdfParser:
raise Warning("expected '='", self.FileName, self.CurrentLineNumber) raise Warning("expected '='", self.FileName, self.CurrentLineNumber)
if Name == 'IMAGE_TYPE_ID': if Name == 'IMAGE_TYPE_ID':
if not self.__GetNextGuid(): 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 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: else:
if not self.__GetNextToken(): if not self.__GetNextToken():
raise Warning("expected value of %s" % Name, self.FileName, self.CurrentLineNumber) raise Warning("expected value of %s" % Name, self.FileName, self.CurrentLineNumber)
Value = self.__Token Value = self.__Token
if Name == 'IMAGE_HEADER_INIT_VERSION': if Name == 'IMAGE_HEADER_INIT_VERSION':
if self.__Verify(Name, Value, 'UINT8'):
FmpData.Version = Value FmpData.Version = Value
elif Name == 'IMAGE_INDEX': elif Name == 'IMAGE_INDEX':
if self.__Verify(Name, Value, 'UINT8'):
FmpData.ImageIndex = Value FmpData.ImageIndex = Value
elif Name == 'HARDWARE_INSTANCE': elif Name == 'HARDWARE_INSTANCE':
if self.__Verify(Name, Value, 'UINT8'):
FmpData.HardwareInstance = Value 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(): if not self.__GetNextToken():
break break
else: else:
self.__UndoToken() 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: 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() ImageFile = self.__ParseRawFileStatement()
if not ImageFile: 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 FmpData.ImageFile = ImageFile
VendorCodeFile = self.__ParseRawFileStatement() VendorCodeFile = self.__ParseRawFileStatement()
if VendorCodeFile: if VendorCodeFile:
FmpData.VendorCodeFile = 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 self.Profile.FmpPayloadDict[FmpUiName] = FmpData
return True return True

View File

@ -415,6 +415,63 @@ def BuildOptionPcdValueFormat(TokenSpaceGuidCName, TokenCName, PcdDatumType, Val
Value = '0' Value = '0'
return Value 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 ## Parse command line options
# #

View File

@ -27,6 +27,7 @@ from Common import EdkLogger
from Common.BuildToolError import * from Common.BuildToolError import *
from FvImageSection import FvImageSection from FvImageSection import FvImageSection
from Common.LongFilePathSupport import OpenLongFilePath as open from Common.LongFilePathSupport import OpenLongFilePath as open
from GenFds import FindExtendTool
## generate GUIDed section ## generate GUIDed section
# #
@ -128,7 +129,7 @@ class GuidSection(GuidSectionClassObject) :
ExternalTool = None ExternalTool = None
ExternalOption = None ExternalOption = None
if self.NameGuid != None: if self.NameGuid != None:
ExternalTool, ExternalOption = self.__FindExtendTool__() ExternalTool, ExternalOption = FindExtendTool(self.KeyStringList, self.CurrentArchList, self.NameGuid)
# #
# If not have GUID , call default # If not have GUID , call default
@ -249,61 +250,5 @@ class GuidSection(GuidSectionClassObject) :
self.ProcessRequired = "TRUE" self.ProcessRequired = "TRUE"
return OutputFileList, self.Alignment 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