* [Patch] BaseTools/Capsule: Supports UEFI Capsule with multiple payloads and embedded drivers @ 2019-05-27 7:28 Eric Jin 2019-05-27 13:58 ` [edk2-devel] " Liming Gao 2019-06-11 3:06 ` Bob Feng 0 siblings, 2 replies; 4+ messages in thread From: Eric Jin @ 2019-05-27 7:28 UTC (permalink / raw) To: devel; +Cc: Bob Feng, Liming Gao, Kinney, Michael D https://bugzilla.tianocore.org/show_bug.cgi?id=1834 * Add arguments "--embedded-driver" to support embedded driver in command line. * Add arguments "--update-image-index" to identify ImageIndex within the device in command line. * Add arguments "-j JSONFILE" to support multiple payloads and embedded drivers with JSON file. The update is in a backwards compatible manner, so all command line options to support single payload are still supported. But all the options associated with multiple payloads should be provided in a JSON file. Cc: Bob Feng <bob.c.feng@intel.com> Cc: Liming Gao <liming.gao@intel.com> Cc: Kinney, Michael D <michael.d.kinney@intel.com> Signed-off-by: Eric Jin <eric.jin@intel.com> --- BaseTools/Source/Python/Capsule/GenerateCapsule.py | 961 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- BaseTools/Source/Python/Common/Uefi/Capsule/FmpAuthHeader.py | 14 +++++++++++++- BaseTools/Source/Python/Common/Uefi/Capsule/FmpCapsuleHeader.py | 12 +++++++----- 3 files changed, 730 insertions(+), 257 deletions(-) diff --git a/BaseTools/Source/Python/Capsule/GenerateCapsule.py b/BaseTools/Source/Python/Capsule/GenerateCapsule.py index 4de3635298..ee95c4cc2e 100644 --- a/BaseTools/Source/Python/Capsule/GenerateCapsule.py +++ b/BaseTools/Source/Python/Capsule/GenerateCapsule.py @@ -1,18 +1,16 @@ ## @file # Generate a capsule. # -# This tool generates a UEFI Capsule around an FMP Capsule. The capsule payload +# This tool generates a UEFI Capsule around an FMP Capsule. The capsule payload # be signed using signtool or OpenSSL and if it is signed the signed content # includes an FMP Payload Header. # # This tool is intended to be used to generate UEFI Capsules to update the -# system firmware or device firmware for integrated devices. In order to +# system firmware or device firmware for integrated devices. In order to # keep the tool as simple as possible, it has the following limitations: -# * Do not support multiple payloads in a capsule. -# * Do not support optional drivers in a capsule. # * Do not support vendor code bytes in a capsule. # -# Copyright (c) 2018, Intel Corporation. All rights reserved.<BR> +# Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<BR> # SPDX-License-Identifier: BSD-2-Clause-Patent # @@ -29,6 +27,7 @@ import os import tempfile import shutil import platform +import json from Common.Uefi.Capsule.UefiCapsuleHeader import UefiCapsuleHeaderClass from Common.Uefi.Capsule.FmpCapsuleHeader import FmpCapsuleHeaderClass from Common.Uefi.Capsule.FmpAuthHeader import FmpAuthHeaderClass @@ -42,7 +41,7 @@ __version__ = '0.9' __copyright__ = 'Copyright (c) 2018, Intel Corporation. All rights reserved.' __description__ = 'Generate a capsule.\n' -def SignPayloadSignTool (Payload, ToolPath, PfxFile): +def SignPayloadSignTool (Payload, ToolPath, PfxFile, Verbose = False): # # Create a temporary directory # @@ -75,6 +74,8 @@ def SignPayloadSignTool (Payload, ToolPath, PfxFile): Command = Command + '/p7 {TempDir} '.format (TempDir = TempDirectoryName) Command = Command + '/f {PfxFile} '.format (PfxFile = PfxFile) Command = Command + TempFileName + if Verbose: + print (Command) # # Sign the input file using the specified private key @@ -88,7 +89,7 @@ def SignPayloadSignTool (Payload, ToolPath, PfxFile): if Process.returncode != 0: shutil.rmtree (TempDirectoryName) - print (Result[1].decode(encoding='utf-8', errors='ignore')) + print (Result[1].decode()) raise ValueError ('GenerateCapsule: error: signtool failed.') # @@ -105,11 +106,11 @@ def SignPayloadSignTool (Payload, ToolPath, PfxFile): shutil.rmtree (TempDirectoryName) return Signature -def VerifyPayloadSignTool (Payload, CertData, ToolPath, PfxFile): +def VerifyPayloadSignTool (Payload, CertData, ToolPath, PfxFile, Verbose = False): print ('signtool verify is not supported.') raise ValueError ('GenerateCapsule: error: signtool verify is not supported.') -def SignPayloadOpenSsl (Payload, ToolPath, SignerPrivateCertFile, OtherPublicCertFile, TrustedPublicCertFile): +def SignPayloadOpenSsl (Payload, ToolPath, SignerPrivateCertFile, OtherPublicCertFile, TrustedPublicCertFile, Verbose = False): # # Build openssl command # @@ -119,6 +120,8 @@ def SignPayloadOpenSsl (Payload, ToolPath, SignerPrivateCertFile, OtherPublicCer Command = Command + '"{Path}" '.format (Path = os.path.join (ToolPath, 'openssl')) Command = Command + 'smime -sign -binary -outform DER -md sha256 ' Command = Command + '-signer "{Private}" -certfile "{Public}"'.format (Private = SignerPrivateCertFile, Public = OtherPublicCertFile) + if Verbose: + print (Command) # # Sign the input file using the specified private key and capture signature from STDOUT @@ -131,12 +134,12 @@ def SignPayloadOpenSsl (Payload, ToolPath, SignerPrivateCertFile, OtherPublicCer raise ValueError ('GenerateCapsule: error: can not run openssl.') if Process.returncode != 0: - print (Result[1].decode(encoding='utf-8', errors='ignore')) + print (Result[1].decode()) raise ValueError ('GenerateCapsule: error: openssl failed.') return Signature -def VerifyPayloadOpenSsl (Payload, CertData, ToolPath, SignerPrivateCertFile, OtherPublicCertFile, TrustedPublicCertFile): +def VerifyPayloadOpenSsl (Payload, CertData, ToolPath, SignerPrivateCertFile, OtherPublicCertFile, TrustedPublicCertFile, Verbose = False): # # Create a temporary directory # @@ -167,6 +170,8 @@ def VerifyPayloadOpenSsl (Payload, CertData, ToolPath, SignerPrivateCertFile, Ot Command = Command + '"{Path}" '.format (Path = os.path.join (ToolPath, 'openssl')) Command = Command + 'smime -verify -inform DER ' Command = Command + '-content {Content} -CAfile "{Public}"'.format (Content = TempFileName, Public = TrustedPublicCertFile) + if Verbose: + print (Command) # # Verify signature @@ -180,7 +185,7 @@ def VerifyPayloadOpenSsl (Payload, CertData, ToolPath, SignerPrivateCertFile, Ot if Process.returncode != 0: shutil.rmtree (TempDirectoryName) - print (Result[1].decode(encoding='utf-8', errors='ignore')) + print (Result[1].decode()) raise ValueError ('GenerateCapsule: error: openssl failed.') shutil.rmtree (TempDirectoryName) @@ -212,6 +217,660 @@ if __name__ == '__main__': raise argparse.ArgumentTypeError (Message) return Value + def ConvertJsonValue (Config, FieldName, Convert, Required = True, Default = None, Open = False): + if FieldName not in Config: + if Required: + print ('GenerateCapsule: error: Payload descriptor invalid syntax. Could not find {Key} in payload descriptor.'.format(Key = FieldName)) + sys.exit (1) + return Default + try: + Value = Convert (Config[FieldName]) + except Exception as Message: + print ('GenerateCapsule: error: {Key} in payload descriptor has invalid syntax. '.format (Key = FieldName) + str(Message)) + sys.exit (1) + if Open: + try: + Value = open (Value, "rb") + except: + print ('GenerateCapsule: error: can not open file {File}'.format (File = FieldName)) + sys.exit (1) + return Value + + def DecodeJsonFileParse (Json): + if 'Payloads' not in Json: + print ('GenerateCapsule: error "Payloads" section not found in JSON file {File}'.format (File = args.JsonFile.name)) + sys.exit (1) + for Config in Json['Payloads']: + # + # Parse fields from JSON + # + PayloadFile = ConvertJsonValue (Config, 'Payload', os.path.expandvars, Required = False) + Guid = ConvertJsonValue (Config, 'Guid', ValidateRegistryFormatGuid, Required = False) + FwVersion = ConvertJsonValue (Config, 'FwVersion', ValidateUnsignedInteger, Required = False) + LowestSupportedVersion = ConvertJsonValue (Config, 'LowestSupportedVersion', ValidateUnsignedInteger, Required = False) + HardwareInstance = ConvertJsonValue (Config, 'HardwareInstance', ValidateUnsignedInteger, Required = False, Default = 0) + MonotonicCount = ConvertJsonValue (Config, 'MonotonicCount', ValidateUnsignedInteger, Required = False, Default = 0) + SignToolPfxFile = ConvertJsonValue (Config, 'SignToolPfxFile', os.path.expandvars, Required = False, Default = None, Open = True) + OpenSslSignerPrivateCertFile = ConvertJsonValue (Config, 'OpenSslSignerPrivateCertFile', os.path.expandvars, Required = False, Default = None, Open = True) + OpenSslOtherPublicCertFile = ConvertJsonValue (Config, 'OpenSslOtherPublicCertFile', os.path.expandvars, Required = False, Default = None, Open = True) + OpenSslTrustedPublicCertFile = ConvertJsonValue (Config, 'OpenSslTrustedPublicCertFile', os.path.expandvars, Required = False, Default = None, Open = True) + SigningToolPath = ConvertJsonValue (Config, 'SigningToolPath', os.path.expandvars, Required = False, Default = None) + UpdateImageIndex = ConvertJsonValue (Config, 'UpdateImageIndex', ValidateUnsignedInteger, Required = False, Default = 1) + + PayloadDescriptorList.append (PayloadDescriptor ( + PayloadFile, + Guid, + FwVersion, + LowestSupportedVersion, + MonotonicCount, + HardwareInstance, + UpdateImageIndex, + SignToolPfxFile, + OpenSslSignerPrivateCertFile, + OpenSslOtherPublicCertFile, + OpenSslTrustedPublicCertFile, + SigningToolPath + )) + + def EncodeJsonFileParse (Json): + if 'EmbeddedDrivers' not in Json: + print ('GenerateCapsule: warning "EmbeddedDrivers" section not found in JSON file {File}'.format (File = args.JsonFile.name)) + else: + for Config in Json['EmbeddedDrivers']: + EmbeddedDriverFile = ConvertJsonValue(Config, 'Driver', os.path.expandvars, Open = True) + # + #Read EmbeddedDriver file + # + try: + if args.Verbose: + print ('Read EmbeddedDriver file {File}'.format (File = EmbeddedDriverFile.name)) + Driver = EmbeddedDriverFile.read() + except: + print ('GenerateCapsule: error: can not read EmbeddedDriver file {File}'.format (File = EmbeddedDriverFile.name)) + sys.exit(1) + EmbeddedDriverDescriptorList.append (Driver) + + if 'Payloads' not in Json: + print ('GenerateCapsule: error: "Payloads" section not found in JSON file {File}'.format (File = args.JsonFile.name)) + sys.exit (1) + for Config in Json['Payloads']: + # + # Parse fields from JSON + # + PayloadFile = ConvertJsonValue (Config, 'Payload', os.path.expandvars, Open = True) + Guid = ConvertJsonValue (Config, 'Guid', ValidateRegistryFormatGuid) + FwVersion = ConvertJsonValue (Config, 'FwVersion', ValidateUnsignedInteger) + LowestSupportedVersion = ConvertJsonValue (Config, 'LowestSupportedVersion', ValidateUnsignedInteger) + HardwareInstance = ConvertJsonValue (Config, 'HardwareInstance', ValidateUnsignedInteger, Required = False, Default = 0) + UpdateImageIndex = ConvertJsonValue (Config, 'UpdateImageIndex', ValidateUnsignedInteger, Required = False, Default = 1) + MonotonicCount = ConvertJsonValue (Config, 'MonotonicCount', ValidateUnsignedInteger, Required = False, Default = 0) + SignToolPfxFile = ConvertJsonValue (Config, 'SignToolPfxFile', os.path.expandvars, Required = False, Default = None, Open = True) + OpenSslSignerPrivateCertFile = ConvertJsonValue (Config, 'OpenSslSignerPrivateCertFile', os.path.expandvars, Required = False, Default = None, Open = True) + OpenSslOtherPublicCertFile = ConvertJsonValue (Config, 'OpenSslOtherPublicCertFile', os.path.expandvars, Required = False, Default = None, Open = True) + OpenSslTrustedPublicCertFile = ConvertJsonValue (Config, 'OpenSslTrustedPublicCertFile', os.path.expandvars, Required = False, Default = None, Open = True) + SigningToolPath = ConvertJsonValue (Config, 'SigningToolPath', os.path.expandvars, Required = False, Default = None) + + # + # Read binary input file + # + try: + if args.Verbose: + print ('Read binary input file {File}'.format (File = PayloadFile.name)) + Payload = PayloadFile.read() + except: + print ('GenerateCapsule: error: can not read binary input file {File}'.format (File = PayloadFile.name)) + sys.exit (1) + PayloadDescriptorList.append (PayloadDescriptor ( + Payload, + Guid, + FwVersion, + LowestSupportedVersion, + MonotonicCount, + HardwareInstance, + UpdateImageIndex, + SignToolPfxFile, + OpenSslSignerPrivateCertFile, + OpenSslOtherPublicCertFile, + OpenSslTrustedPublicCertFile, + SigningToolPath + )) + + def GenerateOutputJson (PayloadJsonDescriptorList): + PayloadJson = { + "Payloads" : [ + { + "Guid": str(PayloadDescriptor.Guid).upper(), + "FwVersion": str(PayloadDescriptor.FwVersion), + "LowestSupportedVersion": str(PayloadDescriptor.LowestSupportedVersion), + "MonotonicCount": str(PayloadDescriptor.MonotonicCount), + "Payload": PayloadDescriptor.Payload, + "HardwareInstance": str(PayloadDescriptor.HardwareInstance), + "UpdateImageIndex": str(PayloadDescriptor.UpdateImageIndex), + "SignToolPfxFile": str(PayloadDescriptor.SignToolPfxFile), + "OpenSslSignerPrivateCertFile": str(PayloadDescriptor.OpenSslSignerPrivateCertFile), + "OpenSslOtherPublicCertFile": str(PayloadDescriptor.OpenSslOtherPublicCertFile), + "OpenSslTrustedPublicCertFile": str(PayloadDescriptor.OpenSslTrustedPublicCertFile), + "SigningToolPath": str(PayloadDescriptor.SigningToolPath) + }for PayloadDescriptor in PayloadJsonDescriptorList + ] + } + OutputJsonFile = args.OutputFile.name + '.json' + if 'Payloads' in PayloadJson: + PayloadSection = PayloadJson ['Payloads'] + Index = 0 + for PayloadField in PayloadSection: + if PayloadJsonDescriptorList[Index].SignToolPfxFile is None: + del PayloadField ['SignToolPfxFile'] + if PayloadJsonDescriptorList[Index].OpenSslSignerPrivateCertFile is None: + del PayloadField ['OpenSslSignerPrivateCertFile'] + if PayloadJsonDescriptorList[Index].OpenSslOtherPublicCertFile is None: + del PayloadField ['OpenSslOtherPublicCertFile'] + if PayloadJsonDescriptorList[Index].OpenSslTrustedPublicCertFile is None: + del PayloadField ['OpenSslTrustedPublicCertFile'] + if PayloadJsonDescriptorList[Index].SigningToolPath is None: + del PayloadField ['SigningToolPath'] + Index = Index + 1 + Result = json.dumps (PayloadJson, indent=4, sort_keys=True, separators=(',', ': ')) + OutputFile = open (OutputJsonFile, 'w') + OutputFile.write (Result) + OutputFile.close () + + def CheckArgumentConflict (args): + if args.Encode: + if args.InputFile: + print ('GenerateCapsule: error: Argument InputFile conflicts with Argument -j') + sys.exit (1) + if args.EmbeddedDriver: + print ('GenerateCapsule: error: Argument --embedded-driver conflicts with Argument -j') + sys.exit (1) + if args.Guid: + print ('GenerateCapsule: error: Argument --guid conflicts with Argument -j') + sys.exit (1) + if args.FwVersion: + print ('GenerateCapsule: error: Argument --fw-version conflicts with Argument -j') + sys.exit (1) + if args.LowestSupportedVersion: + print ('GenerateCapsule: error: Argument --lsv conflicts with Argument -j') + sys.exit (1) + if args.MonotonicCount: + print ('GenerateCapsule: error: Argument --monotonic-count conflicts with Argument -j') + sys.exit (1) + if args.HardwareInstance: + print ('GenerateCapsule: error: Argument --hardware-instance conflicts with Argument -j') + sys.exit (1) + if args.SignToolPfxFile: + print ('GenerateCapsule: error: Argument --pfx-file conflicts with Argument -j') + sys.exit (1) + if args.OpenSslSignerPrivateCertFile: + print ('GenerateCapsule: error: Argument --signer-private-cert conflicts with Argument -j') + sys.exit (1) + if args.OpenSslOtherPublicCertFile: + print ('GenerateCapsule: error: Argument --other-public-cert conflicts with Argument -j') + sys.exit (1) + if args.OpenSslTrustedPublicCertFile: + print ('GenerateCapsule: error: Argument --trusted-public-cert conflicts with Argument -j') + sys.exit (1) + if args.SigningToolPath: + print ('GenerateCapsule: error: Argument --signing-tool-path conflicts with Argument -j') + sys.exit (1) + + class PayloadDescriptor (object): + def __init__(self, + Payload, + Guid, + FwVersion, + LowestSupportedVersion, + MonotonicCount = 0, + HardwareInstance = 0, + UpdateImageIndex = 1, + SignToolPfxFile = None, + OpenSslSignerPrivateCertFile = None, + OpenSslOtherPublicCertFile = None, + OpenSslTrustedPublicCertFile = None, + SigningToolPath = None + ): + self.Payload = Payload + self.Guid = Guid + self.FwVersion = FwVersion + self.LowestSupportedVersion = LowestSupportedVersion + self.MonotonicCount = MonotonicCount + self.HardwareInstance = HardwareInstance + self.UpdateImageIndex = UpdateImageIndex + self.SignToolPfxFile = SignToolPfxFile + self.OpenSslSignerPrivateCertFile = OpenSslSignerPrivateCertFile + self.OpenSslOtherPublicCertFile = OpenSslOtherPublicCertFile + self.OpenSslTrustedPublicCertFile = OpenSslTrustedPublicCertFile + self.SigningToolPath = SigningToolPath + + self.UseSignTool = self.SignToolPfxFile is not None + self.UseOpenSsl = (self.OpenSslSignerPrivateCertFile is not None and + self.OpenSslOtherPublicCertFile is not None and + self.OpenSslTrustedPublicCertFile is not None) + self.AnyOpenSsl = (self.OpenSslSignerPrivateCertFile is not None or + self.OpenSslOtherPublicCertFile is not None or + self.OpenSslTrustedPublicCertFile is not None) + + def Validate(self, args): + if self.UseSignTool and self.AnyOpenSsl: + raise argparse.ArgumentTypeError ('Providing both signtool and OpenSSL options is not supported') + if not self.UseSignTool and not self.UseOpenSsl and self.AnyOpenSsl: + if args.JsonFile: + raise argparse.ArgumentTypeError ('the following JSON fields are required for OpenSSL: OpenSslSignerPrivateCertFile, OpenSslOtherPublicCertFile, OpenSslTrustedPublicCertFile') + else: + raise argparse.ArgumentTypeError ('the following options are required for OpenSSL: --signer-private-cert, --other-public-cert, --trusted-public-cert') + if self.UseSignTool and platform.system() != 'Windows': + raise argparse.ArgumentTypeError ('Use of signtool is not supported on this operating system.') + if args.Encode: + if self.FwVersion is None or self.LowestSupportedVersion is None: + if args.JsonFile: + raise argparse.ArgumentTypeError ('the following JSON fields are required: FwVersion, LowestSupportedVersion') + else: + raise argparse.ArgumentTypeError ('the following options are required: --fw-version, --lsv') + if self.FwVersion > 0xFFFFFFFF: + if args.JsonFile: + raise argparse.ArgumentTypeError ('JSON field FwVersion must be an integer in range 0x0..0xffffffff') + else: + raise argparse.ArgumentTypeError ('--fw-version must be an integer in range 0x0..0xffffffff') + if self.LowestSupportedVersion > 0xFFFFFFFF: + if args.JsonFile: + raise argparse.ArgumentTypeError ('JSON field LowestSupportedVersion must be an integer in range 0x0..0xffffffff') + else: + raise argparse.ArgumentTypeError ('--lsv must be an integer in range 0x0..0xffffffff') + + if args.Encode: + if self.Guid is None: + if args.JsonFile: + raise argparse.ArgumentTypeError ('the following JSON field is required: Guid') + else: + raise argparse.ArgumentTypeError ('the following option is required: --guid') + if self.HardwareInstance > 0xFFFFFFFFFFFFFFFF: + if args.JsonFile: + raise argparse.ArgumentTypeError ('JSON field HardwareInstance must be an integer in range 0x0..0xffffffffffffffff') + else: + raise argparse.ArgumentTypeError ('--hardware-instance must be an integer in range 0x0..0xffffffffffffffff') + if self.MonotonicCount > 0xFFFFFFFFFFFFFFFF: + if args.JsonFile: + raise argparse.ArgumentTypeError ('JSON field MonotonicCount must be an integer in range 0x0..0xffffffffffffffff') + else: + raise argparse.ArgumentTypeError ('--monotonic-count must be an integer in range 0x0..0xffffffffffffffff') + if self.UpdateImageIndex >0xFF: + if args.JsonFile: + raise argparse.ArgumentTypeError ('JSON field UpdateImageIndex must be an integer in range 0x0..0xff') + else: + raise argparse.ArgumentTypeError ('--update-image-index must be an integer in range 0x0..0xff') + + if self.UseSignTool: + self.SignToolPfxFile.close() + self.SignToolPfxFile = self.SignToolPfxFile.name + if self.UseOpenSsl: + self.OpenSslSignerPrivateCertFile.close() + self.OpenSslOtherPublicCertFile.close() + self.OpenSslTrustedPublicCertFile.close() + self.OpenSslSignerPrivateCertFile = self.OpenSslSignerPrivateCertFile.name + self.OpenSslOtherPublicCertFile = self.OpenSslOtherPublicCertFile.name + self.OpenSslTrustedPublicCertFile = self.OpenSslTrustedPublicCertFile.name + + # + # Perform additional argument verification + # + if args.Encode: + if 'PersistAcrossReset' not in args.CapsuleFlag: + if 'InitiateReset' in args.CapsuleFlag: + raise argparse.ArgumentTypeError ('--capflag InitiateReset also requires --capflag PersistAcrossReset') + if args.CapsuleOemFlag > 0xFFFF: + raise argparse.ArgumentTypeError ('--capoemflag must be an integer between 0x0000 and 0xffff') + + return True + + + def Encode (PayloadDescriptorList, EmbeddedDriverDescriptorList, Buffer): + if args.JsonFile: + CheckArgumentConflict(args) + try: + Json = json.loads (args.JsonFile.read ()) + except Exception as Message: + print ('GenerateCapsule: error: ' + str(Message)) + sys.exit (1) + EncodeJsonFileParse(Json) + else: + for Driver in args.EmbeddedDriver: + EmbeddedDriverDescriptorList.append (Driver.read()) + PayloadDescriptorList.append (PayloadDescriptor ( + Buffer, + args.Guid, + args.FwVersion, + args.LowestSupportedVersion, + args.MonotonicCount, + args.HardwareInstance, + args.UpdateImageIndex, + args.SignToolPfxFile, + args.OpenSslSignerPrivateCertFile, + args.OpenSslOtherPublicCertFile, + args.OpenSslTrustedPublicCertFile, + args.SigningToolPath + )) + for SinglePayloadDescriptor in PayloadDescriptorList: + try: + SinglePayloadDescriptor.Validate (args) + except Exception as Message: + print ('GenerateCapsule: error: ' + str(Message)) + sys.exit (1) + for SinglePayloadDescriptor in PayloadDescriptorList: + Result = SinglePayloadDescriptor.Payload + try: + FmpPayloadHeader.FwVersion = SinglePayloadDescriptor.FwVersion + FmpPayloadHeader.LowestSupportedVersion = SinglePayloadDescriptor.LowestSupportedVersion + FmpPayloadHeader.Payload = SinglePayloadDescriptor.Payload + Result = FmpPayloadHeader.Encode () + if args.Verbose: + FmpPayloadHeader.DumpInfo () + except: + raise + print ('GenerateCapsule: error: can not encode FMP Payload Header') + sys.exit (1) + if SinglePayloadDescriptor.UseOpenSsl or SinglePayloadDescriptor.UseSignTool: + # + # Sign image with 64-bit MonotonicCount appended to end of image + # + try: + if SinglePayloadDescriptor.UseSignTool: + CertData = SignPayloadSignTool ( + Result + struct.pack ('<Q', SinglePayloadDescriptor.MonotonicCount), + SinglePayloadDescriptor.SigningToolPath, + SinglePayloadDescriptor.SignToolPfxFile, + Verbose = args.Verbose + ) + else: + CertData = SignPayloadOpenSsl ( + Result + struct.pack ('<Q', SinglePayloadDescriptor.MonotonicCount), + SinglePayloadDescriptor.SigningToolPath, + SinglePayloadDescriptor.OpenSslSignerPrivateCertFile, + SinglePayloadDescriptor.OpenSslOtherPublicCertFile, + SinglePayloadDescriptor.OpenSslTrustedPublicCertFile, + Verbose = args.Verbose + ) + except: + print ('GenerateCapsule: error: can not sign payload') + sys.exit (1) + + try: + FmpAuthHeader.MonotonicCount = SinglePayloadDescriptor.MonotonicCount + FmpAuthHeader.CertData = CertData + FmpAuthHeader.Payload = Result + Result = FmpAuthHeader.Encode () + if args.Verbose: + FmpAuthHeader.DumpInfo () + except: + print ('GenerateCapsule: error: can not encode FMP Auth Header') + sys.exit (1) + FmpCapsuleHeader.AddPayload (SinglePayloadDescriptor.Guid, Result, HardwareInstance = SinglePayloadDescriptor.HardwareInstance, UpdateImageIndex = SinglePayloadDescriptor.UpdateImageIndex) + try: + for EmbeddedDriver in EmbeddedDriverDescriptorList: + FmpCapsuleHeader.AddEmbeddedDriver(EmbeddedDriver) + + Result = FmpCapsuleHeader.Encode () + if args.Verbose: + FmpCapsuleHeader.DumpInfo () + except: + print ('GenerateCapsule: error: can not encode FMP Capsule Header') + sys.exit (1) + + try: + UefiCapsuleHeader.OemFlags = args.CapsuleOemFlag + UefiCapsuleHeader.PersistAcrossReset = 'PersistAcrossReset' in args.CapsuleFlag + UefiCapsuleHeader.PopulateSystemTable = False + UefiCapsuleHeader.InitiateReset = 'InitiateReset' in args.CapsuleFlag + UefiCapsuleHeader.Payload = Result + Result = UefiCapsuleHeader.Encode () + if args.Verbose: + UefiCapsuleHeader.DumpInfo () + except: + print ('GenerateCapsule: error: can not encode UEFI Capsule Header') + sys.exit (1) + try: + if args.Verbose: + print ('Write binary output file {File}'.format (File = args.OutputFile.name)) + args.OutputFile.write (Result) + args.OutputFile.close () + except: + print ('GenerateCapsule: error: can not write binary output file {File}'.format (File = args.OutputFile.name)) + sys.exit (1) + + def Decode (PayloadDescriptorList, PayloadJsonDescriptorList, Buffer): + if args.JsonFile: + CheckArgumentConflict(args) + # + # Parse payload descriptors from JSON + # + try: + Json = json.loads (args.JsonFile.read()) + except Exception as Message: + print ('GenerateCapsule: error: ' + str(Message)) + sys.exit (1) + DecodeJsonFileParse (Json) + else: + PayloadDescriptorList.append (PayloadDescriptor ( + Buffer, + args.Guid, + args.FwVersion, + args.LowestSupportedVersion, + args.MonotonicCount, + args.HardwareInstance, + args.UpdateImageIndex, + args.SignToolPfxFile, + args.OpenSslSignerPrivateCertFile, + args.OpenSslOtherPublicCertFile, + args.OpenSslTrustedPublicCertFile, + args.SigningToolPath + )) + # + # Perform additional verification on payload descriptors + # + for SinglePayloadDescriptor in PayloadDescriptorList: + try: + SinglePayloadDescriptor.Validate (args) + except Exception as Message: + print ('GenerateCapsule: error: ' + str(Message)) + sys.exit (1) + try: + Result = UefiCapsuleHeader.Decode (Buffer) + if len (Result) > 0: + Result = FmpCapsuleHeader.Decode (Result) + if args.JsonFile: + if FmpCapsuleHeader.PayloadItemCount != len (PayloadDescriptorList): + CapsulePayloadNum = FmpCapsuleHeader.PayloadItemCount + JsonPayloadNum = len (PayloadDescriptorList) + print ('GenerateCapsule: Decode error: {JsonPayloadNumber} payloads in JSON file {File} and {CapsulePayloadNumber} payloads in Capsule {CapsuleName}'.format (JsonPayloadNumber = JsonPayloadNum, File = args.JsonFile.name, CapsulePayloadNumber = CapsulePayloadNum, CapsuleName = args.InputFile.name)) + sys.exit (1) + for Index in range (0, FmpCapsuleHeader.PayloadItemCount): + if Index < len (PayloadDescriptorList): + GUID = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).UpdateImageTypeId + HardwareInstance = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).UpdateHardwareInstance + UpdateImageIndex = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).UpdateImageIndex + if PayloadDescriptorList[Index].Guid != GUID or PayloadDescriptorList[Index].HardwareInstance != HardwareInstance: + print ('GenerateCapsule: Decode error: Guid or HardwareInstance pair in input JSON file {File} does not match the payload {PayloadIndex} in Capsule {InputCapsule}'.format (File = args.JsonFile.name, PayloadIndex = Index + 1, InputCapsule = args.InputFile.name)) + sys.exit (1) + PayloadDescriptorList[Index].Payload = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).Payload + DecodeJsonOutput = args.OutputFile.name + '.Payload.{Index:d}.bin'.format (Index = Index + 1) + PayloadJsonDescriptorList.append (PayloadDescriptor ( + DecodeJsonOutput, + GUID, + None, + None, + None, + HardwareInstance, + UpdateImageIndex, + PayloadDescriptorList[Index].SignToolPfxFile, + PayloadDescriptorList[Index].OpenSslSignerPrivateCertFile, + PayloadDescriptorList[Index].OpenSslOtherPublicCertFile, + PayloadDescriptorList[Index].OpenSslTrustedPublicCertFile, + PayloadDescriptorList[Index].SigningToolPath + )) + else: + PayloadDescriptorList[0].Payload = FmpCapsuleHeader.GetFmpCapsuleImageHeader (0).Payload + for Index in range (0, FmpCapsuleHeader.PayloadItemCount): + if Index > 0: + PayloadDecodeFile = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).Payload + PayloadDescriptorList.append (PayloadDescriptor (PayloadDecodeFile, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None + )) + GUID = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).UpdateImageTypeId + HardwareInstance = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).UpdateHardwareInstance + UpdateImageIndex = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).UpdateImageIndex + DecodeJsonOutput = args.OutputFile.name + '.Payload.{Index:d}.bin'.format (Index = Index + 1) + PayloadJsonDescriptorList.append (PayloadDescriptor ( + DecodeJsonOutput, + GUID, + None, + None, + None, + HardwareInstance, + UpdateImageIndex, + PayloadDescriptorList[Index].SignToolPfxFile, + PayloadDescriptorList[Index].OpenSslSignerPrivateCertFile, + PayloadDescriptorList[Index].OpenSslOtherPublicCertFile, + PayloadDescriptorList[Index].OpenSslTrustedPublicCertFile, + PayloadDescriptorList[Index].SigningToolPath + )) + JsonIndex = 0 + for SinglePayloadDescriptor in PayloadDescriptorList: + if args.Verbose: + print ('========') + UefiCapsuleHeader.DumpInfo () + print ('--------') + FmpCapsuleHeader.DumpInfo () + if FmpAuthHeader.IsSigned(SinglePayloadDescriptor.Payload): + if not SinglePayloadDescriptor.UseOpenSsl and not SinglePayloadDescriptor.UseSignTool: + print ('GenerateCapsule: decode warning: can not verify singed payload without cert or pfx file. Index = {Index}'.format (Index = JsonIndex + 1)) + SinglePayloadDescriptor.Payload = FmpAuthHeader.Decode (SinglePayloadDescriptor.Payload) + PayloadJsonDescriptorList[JsonIndex].MonotonicCount = FmpAuthHeader.MonotonicCount + if args.Verbose: + print ('--------') + FmpAuthHeader.DumpInfo () + + # + # Verify Image with 64-bit MonotonicCount appended to end of image + # + try: + if SinglePayloadDescriptor.UseSignTool: + CertData = VerifyPayloadSignTool ( + FmpAuthHeader.Payload + struct.pack ('<Q', FmpAuthHeader.MonotonicCount), + FmpAuthHeader.CertData, + SinglePayloadDescriptor.SigningToolPath, + SinglePayloadDescriptor.SignToolPfxFile, + Verbose = args.Verbose + ) + else: + CertData = VerifyPayloadOpenSsl ( + FmpAuthHeader.Payload + struct.pack ('<Q', FmpAuthHeader.MonotonicCount), + FmpAuthHeader.CertData, + SinglePayloadDescriptor.SigningToolPath, + SinglePayloadDescriptor.OpenSslSignerPrivateCertFile, + SinglePayloadDescriptor.OpenSslOtherPublicCertFile, + SinglePayloadDescriptor.OpenSslTrustedPublicCertFile, + Verbose = args.Verbose + ) + except ValueError: + print ('GenerateCapsule: warning: payload verification failed Index = {Index}'.format (Index = JsonIndex + 1)) + else: + if args.Verbose: + print ('--------') + print ('No EFI_FIRMWARE_IMAGE_AUTHENTICATION') + try: + SinglePayloadDescriptor.Payload = FmpPayloadHeader.Decode (SinglePayloadDescriptor.Payload) + PayloadJsonDescriptorList[JsonIndex].FwVersion = FmpPayloadHeader.FwVersion + PayloadJsonDescriptorList[JsonIndex].LowestSupportedVersion = FmpPayloadHeader.LowestSupportedVersion + JsonIndex = JsonIndex + 1 + if args.Verbose: + print ('--------') + FmpPayloadHeader.DumpInfo () + print ('========') + except: + if args.Verbose: + print ('--------') + print ('No FMP_PAYLOAD_HEADER') + print ('========') + raise + # + # Write embedded driver file(s) + # + for Index in range (0, FmpCapsuleHeader.EmbeddedDriverCount): + EmbeddedDriverBuffer = FmpCapsuleHeader.GetEmbeddedDriver (Index) + EmbeddedDriverPath = args.OutputFile.name + '.EmbeddedDriver.{Index:d}.efi'.format (Index = Index + 1) + try: + if args.Verbose: + print ('Write embedded driver file {File}'.format (File = EmbeddedDriverPath)) + EmbeddedDriverFile = open (EmbeddedDriverPath, 'wb') + EmbeddedDriverFile.write (EmbeddedDriverBuffer) + EmbeddedDriverFile.close () + except: + print ('GenerateCapsule: error: can not write embedded driver file {File}'.format (File = EmbeddedDriverPath)) + sys.exit (1) + + except: + raise + print ('GenerateCapsule: error: can not decode capsule') + sys.exit (1) + GenerateOutputJson(PayloadJsonDescriptorList) + PayloadIndex = 0 + for SinglePayloadDescriptor in PayloadDescriptorList: + if args.OutputFile is None: + print ('GenerateCapsule: Decode error: OutputFile is needed for decode output') + sys.exit (1) + try: + if args.Verbose: + print ('Write binary output file {File}'.format (File = args.OutputFile.name)) + PayloadDecodePath = args.OutputFile.name + '.Payload.{Index:d}.bin'.format (Index = PayloadIndex + 1) + PayloadDecodeFile = open (PayloadDecodePath, 'wb') + PayloadDecodeFile.write (SinglePayloadDescriptor.Payload) + PayloadDecodeFile.close () + PayloadIndex = PayloadIndex + 1 + except: + print ('GenerateCapsule: error: can not write binary output file {File}'.format (File = SinglePayloadDescriptor.OutputFile.name)) + sys.exit (1) + + def DumpInfo (Buffer, args): + if args.OutputFile is not None: + raise argparse.ArgumentTypeError ('the following option is not supported for dumpinfo operations: --output') + try: + Result = UefiCapsuleHeader.Decode (Buffer) + print ('========') + UefiCapsuleHeader.DumpInfo () + if len (Result) > 0: + FmpCapsuleHeader.Decode (Result) + print ('--------') + FmpCapsuleHeader.DumpInfo () + for Index in range (0, FmpCapsuleHeader.PayloadItemCount): + Result = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).Payload + try: + Result = FmpAuthHeader.Decode (Result) + print ('--------') + FmpAuthHeader.DumpInfo () + except: + print ('--------') + print ('No EFI_FIRMWARE_IMAGE_AUTHENTICATION') + try: + Result = FmpPayloadHeader.Decode (Result) + print ('--------') + FmpPayloadHeader.DumpInfo () + except: + print ('--------') + print ('No FMP_PAYLOAD_HEADER') + print ('========') + except: + print ('GenerateCapsule: error: can not decode capsule') + sys.exit (1) + # # Create command line argument parser object # @@ -226,7 +885,7 @@ if __name__ == '__main__': # # Add input and output file arguments # - parser.add_argument("InputFile", type = argparse.FileType('rb'), + parser.add_argument("InputFile", type = argparse.FileType('rb'), nargs='?', help = "Input binary payload filename.") parser.add_argument("-o", "--output", dest = 'OutputFile', type = argparse.FileType('wb'), help = "Output filename.") @@ -243,6 +902,8 @@ if __name__ == '__main__': # # Add optional arguments for this command # + parser.add_argument ("-j", "--json-file", dest = 'JsonFile', type=argparse.FileType('r'), + help = "JSON configuration file for multiple payloads and embedded drivers.") parser.add_argument ("--capflag", dest = 'CapsuleFlag', action='append', default = [], choices=['PersistAcrossReset', 'InitiateReset'], help = "Capsule flag can be PersistAcrossReset or InitiateReset or not set") @@ -250,7 +911,7 @@ if __name__ == '__main__': help = "Capsule OEM Flag is an integer between 0x0000 and 0xffff.") parser.add_argument ("--guid", dest = 'Guid', type = ValidateRegistryFormatGuid, - help = "The FMP/ESRT GUID in registry format. Required for encode operations.") + help = "The FMP/ESRT GUID in registry format. Required for single payload encode operations.") parser.add_argument ("--hardware-instance", dest = 'HardwareInstance', type = ValidateUnsignedInteger, default = 0x0000000000000000, help = "The 64-bit hardware instance. The default is 0x0000000000000000") @@ -259,9 +920,9 @@ if __name__ == '__main__': help = "64-bit monotonic count value in header. Default is 0x0000000000000000.") parser.add_argument ("--fw-version", dest = 'FwVersion', type = ValidateUnsignedInteger, - help = "The 32-bit version of the binary payload (e.g. 0x11223344 or 5678). Required for encode operations that sign a payload.") + help = "The 32-bit version of the binary payload (e.g. 0x11223344 or 5678). Required for encode operations.") parser.add_argument ("--lsv", dest = 'LowestSupportedVersion', type = ValidateUnsignedInteger, - help = "The 32-bit lowest supported version of the binary payload (e.g. 0x11223344 or 5678). Required for encode operations that sign a payload.") + help = "The 32-bit lowest supported version of the binary payload (e.g. 0x11223344 or 5678). Required for encode operations.") parser.add_argument ("--pfx-file", dest='SignToolPfxFile', type=argparse.FileType('rb'), help="signtool PFX certificate filename.") @@ -276,6 +937,9 @@ if __name__ == '__main__': parser.add_argument ("--signing-tool-path", dest = 'SigningToolPath', help = "Path to signtool or OpenSSL tool. Optional if path to tools are already in PATH.") + parser.add_argument ("--embedded-driver", dest = 'EmbeddedDriver', type = argparse.FileType('rb'), action='append', default = [], + help = "Path to embedded UEFI driver to add to capsule.") + # # Add optional arguments common to all operations # @@ -286,79 +950,29 @@ if __name__ == '__main__': help = "Disable all messages except fatal errors.") parser.add_argument ("--debug", dest = 'Debug', type = int, metavar = '[0-9]', choices = range (0, 10), default = 0, help = "Set debug level") + parser.add_argument ("--update-image-index", dest = 'UpdateImageIndex', type = ValidateUnsignedInteger, default = 0x01, help = "unique number identifying the firmware image within the device ") # # Parse command line arguments # args = parser.parse_args() - # - # Perform additional argument verification - # - if args.Encode: - if args.Guid is None: - parser.error ('the following option is required: --guid') - if 'PersistAcrossReset' not in args.CapsuleFlag: - if 'InitiateReset' in args.CapsuleFlag: - parser.error ('--capflag InitiateReset also requires --capflag PersistAcrossReset') - if args.CapsuleOemFlag > 0xFFFF: - parser.error ('--capoemflag must be an integer between 0x0000 and 0xffff') - if args.HardwareInstance > 0xFFFFFFFFFFFFFFFF: - parser.error ('--hardware-instance must be an integer in range 0x0..0xffffffffffffffff') - if args.MonotonicCount > 0xFFFFFFFFFFFFFFFF: - parser.error ('--monotonic-count must be an integer in range 0x0..0xffffffffffffffff') - - UseSignTool = args.SignToolPfxFile is not None - UseOpenSsl = (args.OpenSslSignerPrivateCertFile is not None and - args.OpenSslOtherPublicCertFile is not None and - args.OpenSslTrustedPublicCertFile is not None) - AnyOpenSsl = (args.OpenSslSignerPrivateCertFile is not None or - args.OpenSslOtherPublicCertFile is not None or - args.OpenSslTrustedPublicCertFile is not None) - if args.Encode or args.Decode: - if args.OutputFile is None: - parser.error ('the following option is required for all encode and decode operations: --output') - - if UseSignTool and AnyOpenSsl: - parser.error ('Providing both signtool and OpenSSL options is not supported') - if not UseSignTool and not UseOpenSsl and AnyOpenSsl: - parser.error ('all the following options are required for OpenSSL: --signer-private-cert, --other-public-cert, --trusted-public-cert') - if UseSignTool and platform.system() != 'Windows': - parser.error ('Use of signtool is not supported on this operating system.') - if args.Encode and (UseSignTool or UseOpenSsl): - if args.FwVersion is None or args.LowestSupportedVersion is None: - parser.error ('the following options are required: --fw-version, --lsv') - if args.FwVersion > 0xFFFFFFFF: - parser.error ('--fw-version must be an integer in range 0x0..0xffffffff') - if args.LowestSupportedVersion > 0xFFFFFFFF: - parser.error ('--lsv must be an integer in range 0x0..0xffffffff') - - if UseSignTool: - args.SignToolPfxFile.close() - args.SignToolPfxFile = args.SignToolPfxFile.name - if UseOpenSsl: - args.OpenSslSignerPrivateCertFile.close() - args.OpenSslOtherPublicCertFile.close() - args.OpenSslTrustedPublicCertFile.close() - args.OpenSslSignerPrivateCertFile = args.OpenSslSignerPrivateCertFile.name - args.OpenSslOtherPublicCertFile = args.OpenSslOtherPublicCertFile.name - args.OpenSslTrustedPublicCertFile = args.OpenSslTrustedPublicCertFile.name - - if args.DumpInfo: - if args.OutputFile is not None: - parser.error ('the following option is not supported for dumpinfo operations: --output') - # # Read binary input file # - try: - if args.Verbose: - print ('Read binary input file {File}'.format (File = args.InputFile.name)) - Buffer = args.InputFile.read () - args.InputFile.close () - except: - print ('GenerateCapsule: error: can not read binary input file {File}'.format (File = args.InputFile.name)) - sys.exit (1) + Buffer = '' + if args.InputFile: + if os.path.getsize (args.InputFile.name) == 0: + print ('GenerateCapsule: error: InputFile {File} is empty'.format (File = args.InputFile.name)) + sys.exit (1) + try: + if args.Verbose: + print ('Read binary input file {File}'.format (File = args.InputFile.name)) + Buffer = args.InputFile.read () + args.InputFile.close () + except: + print ('GenerateCapsule: error: can not read binary input file {File}'.format (File = args.InputFile.name)) + sys.exit (1) # # Create objects @@ -368,182 +982,27 @@ if __name__ == '__main__': FmpAuthHeader = FmpAuthHeaderClass () FmpPayloadHeader = FmpPayloadHeaderClass () - if args.Encode: - Result = Buffer - if UseSignTool or UseOpenSsl: - try: - FmpPayloadHeader.FwVersion = args.FwVersion - FmpPayloadHeader.LowestSupportedVersion = args.LowestSupportedVersion - FmpPayloadHeader.Payload = Result - Result = FmpPayloadHeader.Encode () - if args.Verbose: - FmpPayloadHeader.DumpInfo () - except: - print ('GenerateCapsule: error: can not encode FMP Payload Header') - sys.exit (1) - - # - # Sign image with 64-bit MonotonicCount appended to end of image - # - try: - if UseSignTool: - CertData = SignPayloadSignTool ( - Result + struct.pack ('<Q', args.MonotonicCount), - args.SigningToolPath, - args.SignToolPfxFile - ) - else: - CertData = SignPayloadOpenSsl ( - Result + struct.pack ('<Q', args.MonotonicCount), - args.SigningToolPath, - args.OpenSslSignerPrivateCertFile, - args.OpenSslOtherPublicCertFile, - args.OpenSslTrustedPublicCertFile - ) - except: - print ('GenerateCapsule: error: can not sign payload') - sys.exit (1) - - try: - FmpAuthHeader.MonotonicCount = args.MonotonicCount - FmpAuthHeader.CertData = CertData - FmpAuthHeader.Payload = Result - Result = FmpAuthHeader.Encode () - if args.Verbose: - FmpAuthHeader.DumpInfo () - except: - print ('GenerateCapsule: error: can not encode FMP Auth Header') - sys.exit (1) - - try: - FmpCapsuleHeader.AddPayload (args.Guid, Result, HardwareInstance = args.HardwareInstance) - Result = FmpCapsuleHeader.Encode () - if args.Verbose: - FmpCapsuleHeader.DumpInfo () - except: - print ('GenerateCapsule: error: can not encode FMP Capsule Header') - sys.exit (1) - - try: - UefiCapsuleHeader.OemFlags = args.CapsuleOemFlag - UefiCapsuleHeader.PersistAcrossReset = 'PersistAcrossReset' in args.CapsuleFlag - UefiCapsuleHeader.PopulateSystemTable = False - UefiCapsuleHeader.InitiateReset = 'InitiateReset' in args.CapsuleFlag - UefiCapsuleHeader.Payload = Result - Result = UefiCapsuleHeader.Encode () - if args.Verbose: - UefiCapsuleHeader.DumpInfo () - except: - print ('GenerateCapsule: error: can not encode UEFI Capsule Header') - sys.exit (1) - - elif args.Decode: - try: - Result = UefiCapsuleHeader.Decode (Buffer) - FmpCapsuleHeader.Decode (Result) - Result = FmpCapsuleHeader.GetFmpCapsuleImageHeader (0).Payload - if args.Verbose: - print ('========') - UefiCapsuleHeader.DumpInfo () - print ('--------') - FmpCapsuleHeader.DumpInfo () - if UseSignTool or UseOpenSsl: - Result = FmpAuthHeader.Decode (Result) - if args.Verbose: - print ('--------') - FmpAuthHeader.DumpInfo () + EmbeddedDriverDescriptorList = [] + PayloadDescriptorList = [] + PayloadJsonDescriptorList = [] - # - # Verify Image with 64-bit MonotonicCount appended to end of image - # - try: - if UseSignTool: - CertData = VerifyPayloadSignTool ( - FmpAuthHeader.Payload + struct.pack ('<Q', FmpAuthHeader.MonotonicCount), - FmpAuthHeader.CertData, - args.SigningToolPath, - args.SignToolPfxFile - ) - else: - CertData = VerifyPayloadOpenSsl ( - FmpAuthHeader.Payload + struct.pack ('<Q', FmpAuthHeader.MonotonicCount), - FmpAuthHeader.CertData, - args.SigningToolPath, - args.OpenSslSignerPrivateCertFile, - args.OpenSslOtherPublicCertFile, - args.OpenSslTrustedPublicCertFile - ) - except ValueError: - print ('GenerateCapsule: warning: can not verify payload.') - - try: - Result = FmpPayloadHeader.Decode (Result) - if args.Verbose: - print ('--------') - FmpPayloadHeader.DumpInfo () - print ('========') - except: - if args.Verbose: - print ('--------') - print ('No FMP_PAYLOAD_HEADER') - print ('========') - raise - else: - if args.Verbose: - print ('--------') - print ('No EFI_FIRMWARE_IMAGE_AUTHENTICATION') - print ('--------') - print ('No FMP_PAYLOAD_HEADER') - print ('========') - except: - print ('GenerateCapsule: error: can not decode capsule') - sys.exit (1) + # + #Encode Operation + # + if args.Encode: + Encode (PayloadDescriptorList, EmbeddedDriverDescriptorList, Buffer) - elif args.DumpInfo: - try: - Result = UefiCapsuleHeader.Decode (Buffer) - FmpCapsuleHeader.Decode (Result) - Result = FmpCapsuleHeader.GetFmpCapsuleImageHeader (0).Payload - print ('========') - UefiCapsuleHeader.DumpInfo () - print ('--------') - FmpCapsuleHeader.DumpInfo () - try: - Result = FmpAuthHeader.Decode (Result) - print ('--------') - FmpAuthHeader.DumpInfo () - try: - Result = FmpPayloadHeader.Decode (Result) - print ('--------') - FmpPayloadHeader.DumpInfo () - except: - print ('--------') - print ('No FMP_PAYLOAD_HEADER') - except: - print ('--------') - print ('No EFI_FIRMWARE_IMAGE_AUTHENTICATION') - print ('--------') - print ('No FMP_PAYLOAD_HEADER') - print ('========') - except: - print ('GenerateCapsule: error: can not decode capsule') - sys.exit (1) - else: - print('GenerateCapsule: error: invalid options') - sys.exit (1) + # + #Decode Operation + # + if args.Decode: + Decode (PayloadDescriptorList, PayloadJsonDescriptorList, Buffer) # - # Write binary output file + #Dump Info Operation # - if args.OutputFile is not None: - try: - if args.Verbose: - print ('Write binary output file {File}'.format (File = args.OutputFile.name)) - args.OutputFile.write (Result) - args.OutputFile.close () - except: - print ('GenerateCapsule: error: can not write binary output file {File}'.format (File = args.OutputFile.name)) - sys.exit (1) + if args.DumpInfo: + DumpInfo (Buffer, args) if args.Verbose: print('Success') diff --git a/BaseTools/Source/Python/Common/Uefi/Capsule/FmpAuthHeader.py b/BaseTools/Source/Python/Common/Uefi/Capsule/FmpAuthHeader.py index 4b8c6da26a..48c605faa8 100644 --- a/BaseTools/Source/Python/Common/Uefi/Capsule/FmpAuthHeader.py +++ b/BaseTools/Source/Python/Common/Uefi/Capsule/FmpAuthHeader.py @@ -2,7 +2,7 @@ # Module that encodes and decodes a EFI_FIRMWARE_IMAGE_AUTHENTICATION with # certificate data and payload data. # -# Copyright (c) 2018, Intel Corporation. All rights reserved.<BR> +# Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<BR> # SPDX-License-Identifier: BSD-2-Clause-Patent # @@ -166,6 +166,18 @@ class FmpAuthHeaderClass (object): self._Valid = True return self.Payload + def IsSigned (self, Buffer): + if len (Buffer) < self._StructSize: + return False + (MonotonicCount, dwLength, wRevision, wCertificateType, CertType) = \ + struct.unpack ( + self._StructFormat, + Buffer[0:self._StructSize] + ) + if CertType != self._EFI_CERT_TYPE_PKCS7_GUID.bytes_le: + return False + return True + def DumpInfo (self): if not self._Valid: raise ValueError diff --git a/BaseTools/Source/Python/Common/Uefi/Capsule/FmpCapsuleHeader.py b/BaseTools/Source/Python/Common/Uefi/Capsule/FmpCapsuleHeader.py index c24258d047..91d24919c4 100644 --- a/BaseTools/Source/Python/Common/Uefi/Capsule/FmpCapsuleHeader.py +++ b/BaseTools/Source/Python/Common/Uefi/Capsule/FmpCapsuleHeader.py @@ -2,7 +2,7 @@ # Module that encodes and decodes a EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER with # a payload. # -# Copyright (c) 2018, Intel Corporation. All rights reserved.<BR> +# Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<BR> # SPDX-License-Identifier: BSD-2-Clause-Patent # @@ -172,8 +172,8 @@ class FmpCapsuleHeaderClass (object): raise ValueError return self._EmbeddedDriverList[Index] - def AddPayload (self, UpdateImageTypeId, Payload = b'', VendorCodeBytes = b'', HardwareInstance = 0): - self._PayloadList.append ((UpdateImageTypeId, Payload, VendorCodeBytes, HardwareInstance)) + def AddPayload (self, UpdateImageTypeId, Payload = b'', VendorCodeBytes = b'', HardwareInstance = 0, UpdateImageIndex = 1): + self._PayloadList.append ((UpdateImageTypeId, Payload, VendorCodeBytes, HardwareInstance, UpdateImageIndex)) def GetFmpCapsuleImageHeader (self, Index): if Index >= len (self._FmpCapsuleImageHeaderList): @@ -198,10 +198,10 @@ class FmpCapsuleHeaderClass (object): self._ItemOffsetList.append (Offset) Offset = Offset + len (EmbeddedDriver) Index = 1 - for (UpdateImageTypeId, Payload, VendorCodeBytes, HardwareInstance) in self._PayloadList: + for (UpdateImageTypeId, Payload, VendorCodeBytes, HardwareInstance, UpdateImageIndex) in self._PayloadList: FmpCapsuleImageHeader = FmpCapsuleImageHeaderClass () FmpCapsuleImageHeader.UpdateImageTypeId = UpdateImageTypeId - FmpCapsuleImageHeader.UpdateImageIndex = Index + FmpCapsuleImageHeader.UpdateImageIndex = UpdateImageIndex FmpCapsuleImageHeader.Payload = Payload FmpCapsuleImageHeader.VendorCodeBytes = VendorCodeBytes FmpCapsuleImageHeader.UpdateHardwareInstance = HardwareInstance @@ -288,6 +288,8 @@ class FmpCapsuleHeaderClass (object): raise ValueError print ('EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER.Version = {Version:08X}'.format (Version = self.Version)) print ('EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER.EmbeddedDriverCount = {EmbeddedDriverCount:08X}'.format (EmbeddedDriverCount = self.EmbeddedDriverCount)) + for EmbeddedDriver in self._EmbeddedDriverList: + print (' sizeof (EmbeddedDriver) = {Size:08X}'.format (Size = len (EmbeddedDriver))) print ('EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER.PayloadItemCount = {PayloadItemCount:08X}'.format (PayloadItemCount = self.PayloadItemCount)) print ('EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER.ItemOffsetList = ') for Offset in self._ItemOffsetList: -- 2.20.0.windows.1 ^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [edk2-devel] [Patch] BaseTools/Capsule: Supports UEFI Capsule with multiple payloads and embedded drivers 2019-05-27 7:28 [Patch] BaseTools/Capsule: Supports UEFI Capsule with multiple payloads and embedded drivers Eric Jin @ 2019-05-27 13:58 ` Liming Gao 2019-05-28 2:10 ` Eric Jin 2019-06-11 3:06 ` Bob Feng 1 sibling, 1 reply; 4+ messages in thread From: Liming Gao @ 2019-05-27 13:58 UTC (permalink / raw) To: devel@edk2.groups.io, Jin, Eric Cc: Feng, Bob C, Kinney, Michael D, Kinney, Michael D Seemly, this is new feature implementation. It will not be for Q2 stable tag. Right? > -----Original Message----- > From: devel@edk2.groups.io [mailto:devel@edk2.groups.io] On Behalf Of Eric Jin > Sent: Monday, May 27, 2019 3:28 PM > To: devel@edk2.groups.io > Cc: Feng, Bob C <bob.c.feng@intel.com>; Gao, Liming <liming.gao@intel.com>; Kinney; Kinney, Michael D <michael.d.kinney@intel.com> > Subject: [edk2-devel] [Patch] BaseTools/Capsule: Supports UEFI Capsule with multiple payloads and embedded drivers > > https://bugzilla.tianocore.org/show_bug.cgi?id=1834 > > * Add arguments "--embedded-driver" to support embedded driver in command line. > * Add arguments "--update-image-index" to identify ImageIndex within the device > in command line. > * Add arguments "-j JSONFILE" to support multiple payloads and embedded drivers > with JSON file. > > The update is in a backwards compatible manner, so all command line options to > support single payload are still supported. But all the options associated with > multiple payloads should be provided in a JSON file. > > Cc: Bob Feng <bob.c.feng@intel.com> > Cc: Liming Gao <liming.gao@intel.com> > Cc: Kinney, Michael D <michael.d.kinney@intel.com> > Signed-off-by: Eric Jin <eric.jin@intel.com> > --- > BaseTools/Source/Python/Capsule/GenerateCapsule.py | 961 > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------------- > ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- > -------- > BaseTools/Source/Python/Common/Uefi/Capsule/FmpAuthHeader.py | 14 +++++++++++++- > BaseTools/Source/Python/Common/Uefi/Capsule/FmpCapsuleHeader.py | 12 +++++++----- > 3 files changed, 730 insertions(+), 257 deletions(-) > > diff --git a/BaseTools/Source/Python/Capsule/GenerateCapsule.py b/BaseTools/Source/Python/Capsule/GenerateCapsule.py > index 4de3635298..ee95c4cc2e 100644 > --- a/BaseTools/Source/Python/Capsule/GenerateCapsule.py > +++ b/BaseTools/Source/Python/Capsule/GenerateCapsule.py > @@ -1,18 +1,16 @@ > ## @file > > # Generate a capsule. > > # > > -# This tool generates a UEFI Capsule around an FMP Capsule. The capsule payload > > +# This tool generates a UEFI Capsule around an FMP Capsule. The capsule payload > > # be signed using signtool or OpenSSL and if it is signed the signed content > > # includes an FMP Payload Header. > > # > > # This tool is intended to be used to generate UEFI Capsules to update the > > -# system firmware or device firmware for integrated devices. In order to > > +# system firmware or device firmware for integrated devices. In order to > > # keep the tool as simple as possible, it has the following limitations: > > -# * Do not support multiple payloads in a capsule. > > -# * Do not support optional drivers in a capsule. > > # * Do not support vendor code bytes in a capsule. > > # > > -# Copyright (c) 2018, Intel Corporation. All rights reserved.<BR> > > +# Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<BR> > > # SPDX-License-Identifier: BSD-2-Clause-Patent > > # > > > > @@ -29,6 +27,7 @@ import os > import tempfile > > import shutil > > import platform > > +import json > > from Common.Uefi.Capsule.UefiCapsuleHeader import UefiCapsuleHeaderClass > > from Common.Uefi.Capsule.FmpCapsuleHeader import FmpCapsuleHeaderClass > > from Common.Uefi.Capsule.FmpAuthHeader import FmpAuthHeaderClass > > @@ -42,7 +41,7 @@ __version__ = '0.9' > __copyright__ = 'Copyright (c) 2018, Intel Corporation. All rights reserved.' > > __description__ = 'Generate a capsule.\n' > > > > -def SignPayloadSignTool (Payload, ToolPath, PfxFile): > > +def SignPayloadSignTool (Payload, ToolPath, PfxFile, Verbose = False): > > # > > # Create a temporary directory > > # > > @@ -75,6 +74,8 @@ def SignPayloadSignTool (Payload, ToolPath, PfxFile): > Command = Command + '/p7 {TempDir} '.format (TempDir = TempDirectoryName) > > Command = Command + '/f {PfxFile} '.format (PfxFile = PfxFile) > > Command = Command + TempFileName > > + if Verbose: > > + print (Command) > > > > # > > # Sign the input file using the specified private key > > @@ -88,7 +89,7 @@ def SignPayloadSignTool (Payload, ToolPath, PfxFile): > > > if Process.returncode != 0: > > shutil.rmtree (TempDirectoryName) > > - print (Result[1].decode(encoding='utf-8', errors='ignore')) > > + print (Result[1].decode()) > > raise ValueError ('GenerateCapsule: error: signtool failed.') > > > > # > > @@ -105,11 +106,11 @@ def SignPayloadSignTool (Payload, ToolPath, PfxFile): > shutil.rmtree (TempDirectoryName) > > return Signature > > > > -def VerifyPayloadSignTool (Payload, CertData, ToolPath, PfxFile): > > +def VerifyPayloadSignTool (Payload, CertData, ToolPath, PfxFile, Verbose = False): > > print ('signtool verify is not supported.') > > raise ValueError ('GenerateCapsule: error: signtool verify is not supported.') > > > > -def SignPayloadOpenSsl (Payload, ToolPath, SignerPrivateCertFile, OtherPublicCertFile, TrustedPublicCertFile): > > +def SignPayloadOpenSsl (Payload, ToolPath, SignerPrivateCertFile, OtherPublicCertFile, TrustedPublicCertFile, Verbose = False): > > # > > # Build openssl command > > # > > @@ -119,6 +120,8 @@ def SignPayloadOpenSsl (Payload, ToolPath, SignerPrivateCertFile, OtherPublicCer > Command = Command + '"{Path}" '.format (Path = os.path.join (ToolPath, 'openssl')) > > Command = Command + 'smime -sign -binary -outform DER -md sha256 ' > > Command = Command + '-signer "{Private}" -certfile "{Public}"'.format (Private = SignerPrivateCertFile, Public = OtherPublicCertFile) > > + if Verbose: > > + print (Command) > > > > # > > # Sign the input file using the specified private key and capture signature from STDOUT > > @@ -131,12 +134,12 @@ def SignPayloadOpenSsl (Payload, ToolPath, SignerPrivateCertFile, OtherPublicCer > raise ValueError ('GenerateCapsule: error: can not run openssl.') > > > > if Process.returncode != 0: > > - print (Result[1].decode(encoding='utf-8', errors='ignore')) > > + print (Result[1].decode()) > > raise ValueError ('GenerateCapsule: error: openssl failed.') > > > > return Signature > > > > -def VerifyPayloadOpenSsl (Payload, CertData, ToolPath, SignerPrivateCertFile, OtherPublicCertFile, TrustedPublicCertFile): > > +def VerifyPayloadOpenSsl (Payload, CertData, ToolPath, SignerPrivateCertFile, OtherPublicCertFile, TrustedPublicCertFile, Verbose = False): > > # > > # Create a temporary directory > > # > > @@ -167,6 +170,8 @@ def VerifyPayloadOpenSsl (Payload, CertData, ToolPath, SignerPrivateCertFile, Ot > Command = Command + '"{Path}" '.format (Path = os.path.join (ToolPath, 'openssl')) > > Command = Command + 'smime -verify -inform DER ' > > Command = Command + '-content {Content} -CAfile "{Public}"'.format (Content = TempFileName, Public = TrustedPublicCertFile) > > + if Verbose: > > + print (Command) > > > > # > > # Verify signature > > @@ -180,7 +185,7 @@ def VerifyPayloadOpenSsl (Payload, CertData, ToolPath, SignerPrivateCertFile, Ot > > > if Process.returncode != 0: > > shutil.rmtree (TempDirectoryName) > > - print (Result[1].decode(encoding='utf-8', errors='ignore')) > > + print (Result[1].decode()) > > raise ValueError ('GenerateCapsule: error: openssl failed.') > > > > shutil.rmtree (TempDirectoryName) > > @@ -212,6 +217,660 @@ if __name__ == '__main__': > raise argparse.ArgumentTypeError (Message) > > return Value > > > > + def ConvertJsonValue (Config, FieldName, Convert, Required = True, Default = None, Open = False): > > + if FieldName not in Config: > > + if Required: > > + print ('GenerateCapsule: error: Payload descriptor invalid syntax. Could not find {Key} in payload > descriptor.'.format(Key = FieldName)) > > + sys.exit (1) > > + return Default > > + try: > > + Value = Convert (Config[FieldName]) > > + except Exception as Message: > > + print ('GenerateCapsule: error: {Key} in payload descriptor has invalid syntax. '.format (Key = FieldName) + str(Message)) > > + sys.exit (1) > > + if Open: > > + try: > > + Value = open (Value, "rb") > > + except: > > + print ('GenerateCapsule: error: can not open file {File}'.format (File = FieldName)) > > + sys.exit (1) > > + return Value > > + > > + def DecodeJsonFileParse (Json): > > + if 'Payloads' not in Json: > > + print ('GenerateCapsule: error "Payloads" section not found in JSON file {File}'.format (File = args.JsonFile.name)) > > + sys.exit (1) > > + for Config in Json['Payloads']: > > + # > > + # Parse fields from JSON > > + # > > + PayloadFile = ConvertJsonValue (Config, 'Payload', os.path.expandvars, Required = False) > > + Guid = ConvertJsonValue (Config, 'Guid', ValidateRegistryFormatGuid, Required = False) > > + FwVersion = ConvertJsonValue (Config, 'FwVersion', ValidateUnsignedInteger, Required = False) > > + LowestSupportedVersion = ConvertJsonValue (Config, 'LowestSupportedVersion', ValidateUnsignedInteger, Required > = False) > > + HardwareInstance = ConvertJsonValue (Config, 'HardwareInstance', ValidateUnsignedInteger, Required = > False, Default = 0) > > + MonotonicCount = ConvertJsonValue (Config, 'MonotonicCount', ValidateUnsignedInteger, Required = > False, Default = 0) > > + SignToolPfxFile = ConvertJsonValue (Config, 'SignToolPfxFile', os.path.expandvars, Required = False, Default > = None, Open = True) > > + OpenSslSignerPrivateCertFile = ConvertJsonValue (Config, 'OpenSslSignerPrivateCertFile', os.path.expandvars, Required = > False, Default = None, Open = True) > > + OpenSslOtherPublicCertFile = ConvertJsonValue (Config, 'OpenSslOtherPublicCertFile', os.path.expandvars, Required = > False, Default = None, Open = True) > > + OpenSslTrustedPublicCertFile = ConvertJsonValue (Config, 'OpenSslTrustedPublicCertFile', os.path.expandvars, Required = > False, Default = None, Open = True) > > + SigningToolPath = ConvertJsonValue (Config, 'SigningToolPath', os.path.expandvars, Required = False, > Default = None) > > + UpdateImageIndex = ConvertJsonValue (Config, 'UpdateImageIndex', ValidateUnsignedInteger, Required = > False, Default = 1) > > + > > + PayloadDescriptorList.append (PayloadDescriptor ( > > + PayloadFile, > > + Guid, > > + FwVersion, > > + LowestSupportedVersion, > > + MonotonicCount, > > + HardwareInstance, > > + UpdateImageIndex, > > + SignToolPfxFile, > > + OpenSslSignerPrivateCertFile, > > + OpenSslOtherPublicCertFile, > > + OpenSslTrustedPublicCertFile, > > + SigningToolPath > > + )) > > + > > + def EncodeJsonFileParse (Json): > > + if 'EmbeddedDrivers' not in Json: > > + print ('GenerateCapsule: warning "EmbeddedDrivers" section not found in JSON file {File}'.format (File = > args.JsonFile.name)) > > + else: > > + for Config in Json['EmbeddedDrivers']: > > + EmbeddedDriverFile = ConvertJsonValue(Config, 'Driver', os.path.expandvars, Open = True) > > + # > > + #Read EmbeddedDriver file > > + # > > + try: > > + if args.Verbose: > > + print ('Read EmbeddedDriver file {File}'.format (File = EmbeddedDriverFile.name)) > > + Driver = EmbeddedDriverFile.read() > > + except: > > + print ('GenerateCapsule: error: can not read EmbeddedDriver file {File}'.format (File = EmbeddedDriverFile.name)) > > + sys.exit(1) > > + EmbeddedDriverDescriptorList.append (Driver) > > + > > + if 'Payloads' not in Json: > > + print ('GenerateCapsule: error: "Payloads" section not found in JSON file {File}'.format (File = args.JsonFile.name)) > > + sys.exit (1) > > + for Config in Json['Payloads']: > > + # > > + # Parse fields from JSON > > + # > > + PayloadFile = ConvertJsonValue (Config, 'Payload', os.path.expandvars, Open = True) > > + Guid = ConvertJsonValue (Config, 'Guid', ValidateRegistryFormatGuid) > > + FwVersion = ConvertJsonValue (Config, 'FwVersion', ValidateUnsignedInteger) > > + LowestSupportedVersion = ConvertJsonValue (Config, 'LowestSupportedVersion', ValidateUnsignedInteger) > > + HardwareInstance = ConvertJsonValue (Config, 'HardwareInstance', ValidateUnsignedInteger, Required = > False, Default = 0) > > + UpdateImageIndex = ConvertJsonValue (Config, 'UpdateImageIndex', ValidateUnsignedInteger, Required = > False, Default = 1) > > + MonotonicCount = ConvertJsonValue (Config, 'MonotonicCount', ValidateUnsignedInteger, Required = > False, Default = 0) > > + SignToolPfxFile = ConvertJsonValue (Config, 'SignToolPfxFile', os.path.expandvars, Required = False, Default > = None, Open = True) > > + OpenSslSignerPrivateCertFile = ConvertJsonValue (Config, 'OpenSslSignerPrivateCertFile', os.path.expandvars, Required = > False, Default = None, Open = True) > > + OpenSslOtherPublicCertFile = ConvertJsonValue (Config, 'OpenSslOtherPublicCertFile', os.path.expandvars, Required = > False, Default = None, Open = True) > > + OpenSslTrustedPublicCertFile = ConvertJsonValue (Config, 'OpenSslTrustedPublicCertFile', os.path.expandvars, Required = > False, Default = None, Open = True) > > + SigningToolPath = ConvertJsonValue (Config, 'SigningToolPath', os.path.expandvars, Required = False, > Default = None) > > + > > + # > > + # Read binary input file > > + # > > + try: > > + if args.Verbose: > > + print ('Read binary input file {File}'.format (File = PayloadFile.name)) > > + Payload = PayloadFile.read() > > + except: > > + print ('GenerateCapsule: error: can not read binary input file {File}'.format (File = PayloadFile.name)) > > + sys.exit (1) > > + PayloadDescriptorList.append (PayloadDescriptor ( > > + Payload, > > + Guid, > > + FwVersion, > > + LowestSupportedVersion, > > + MonotonicCount, > > + HardwareInstance, > > + UpdateImageIndex, > > + SignToolPfxFile, > > + OpenSslSignerPrivateCertFile, > > + OpenSslOtherPublicCertFile, > > + OpenSslTrustedPublicCertFile, > > + SigningToolPath > > + )) > > + > > + def GenerateOutputJson (PayloadJsonDescriptorList): > > + PayloadJson = { > > + "Payloads" : [ > > + { > > + "Guid": str(PayloadDescriptor.Guid).upper(), > > + "FwVersion": str(PayloadDescriptor.FwVersion), > > + "LowestSupportedVersion": str(PayloadDescriptor.LowestSupportedVersion), > > + "MonotonicCount": str(PayloadDescriptor.MonotonicCount), > > + "Payload": PayloadDescriptor.Payload, > > + "HardwareInstance": str(PayloadDescriptor.HardwareInstance), > > + "UpdateImageIndex": str(PayloadDescriptor.UpdateImageIndex), > > + "SignToolPfxFile": str(PayloadDescriptor.SignToolPfxFile), > > + "OpenSslSignerPrivateCertFile": str(PayloadDescriptor.OpenSslSignerPrivateCertFile), > > + "OpenSslOtherPublicCertFile": str(PayloadDescriptor.OpenSslOtherPublicCertFile), > > + "OpenSslTrustedPublicCertFile": str(PayloadDescriptor.OpenSslTrustedPublicCertFile), > > + "SigningToolPath": str(PayloadDescriptor.SigningToolPath) > > + }for PayloadDescriptor in PayloadJsonDescriptorList > > + ] > > + } > > + OutputJsonFile = args.OutputFile.name + '.json' > > + if 'Payloads' in PayloadJson: > > + PayloadSection = PayloadJson ['Payloads'] > > + Index = 0 > > + for PayloadField in PayloadSection: > > + if PayloadJsonDescriptorList[Index].SignToolPfxFile is None: > > + del PayloadField ['SignToolPfxFile'] > > + if PayloadJsonDescriptorList[Index].OpenSslSignerPrivateCertFile is None: > > + del PayloadField ['OpenSslSignerPrivateCertFile'] > > + if PayloadJsonDescriptorList[Index].OpenSslOtherPublicCertFile is None: > > + del PayloadField ['OpenSslOtherPublicCertFile'] > > + if PayloadJsonDescriptorList[Index].OpenSslTrustedPublicCertFile is None: > > + del PayloadField ['OpenSslTrustedPublicCertFile'] > > + if PayloadJsonDescriptorList[Index].SigningToolPath is None: > > + del PayloadField ['SigningToolPath'] > > + Index = Index + 1 > > + Result = json.dumps (PayloadJson, indent=4, sort_keys=True, separators=(',', ': ')) > > + OutputFile = open (OutputJsonFile, 'w') > > + OutputFile.write (Result) > > + OutputFile.close () > > + > > + def CheckArgumentConflict (args): > > + if args.Encode: > > + if args.InputFile: > > + print ('GenerateCapsule: error: Argument InputFile conflicts with Argument -j') > > + sys.exit (1) > > + if args.EmbeddedDriver: > > + print ('GenerateCapsule: error: Argument --embedded-driver conflicts with Argument -j') > > + sys.exit (1) > > + if args.Guid: > > + print ('GenerateCapsule: error: Argument --guid conflicts with Argument -j') > > + sys.exit (1) > > + if args.FwVersion: > > + print ('GenerateCapsule: error: Argument --fw-version conflicts with Argument -j') > > + sys.exit (1) > > + if args.LowestSupportedVersion: > > + print ('GenerateCapsule: error: Argument --lsv conflicts with Argument -j') > > + sys.exit (1) > > + if args.MonotonicCount: > > + print ('GenerateCapsule: error: Argument --monotonic-count conflicts with Argument -j') > > + sys.exit (1) > > + if args.HardwareInstance: > > + print ('GenerateCapsule: error: Argument --hardware-instance conflicts with Argument -j') > > + sys.exit (1) > > + if args.SignToolPfxFile: > > + print ('GenerateCapsule: error: Argument --pfx-file conflicts with Argument -j') > > + sys.exit (1) > > + if args.OpenSslSignerPrivateCertFile: > > + print ('GenerateCapsule: error: Argument --signer-private-cert conflicts with Argument -j') > > + sys.exit (1) > > + if args.OpenSslOtherPublicCertFile: > > + print ('GenerateCapsule: error: Argument --other-public-cert conflicts with Argument -j') > > + sys.exit (1) > > + if args.OpenSslTrustedPublicCertFile: > > + print ('GenerateCapsule: error: Argument --trusted-public-cert conflicts with Argument -j') > > + sys.exit (1) > > + if args.SigningToolPath: > > + print ('GenerateCapsule: error: Argument --signing-tool-path conflicts with Argument -j') > > + sys.exit (1) > > + > > + class PayloadDescriptor (object): > > + def __init__(self, > > + Payload, > > + Guid, > > + FwVersion, > > + LowestSupportedVersion, > > + MonotonicCount = 0, > > + HardwareInstance = 0, > > + UpdateImageIndex = 1, > > + SignToolPfxFile = None, > > + OpenSslSignerPrivateCertFile = None, > > + OpenSslOtherPublicCertFile = None, > > + OpenSslTrustedPublicCertFile = None, > > + SigningToolPath = None > > + ): > > + self.Payload = Payload > > + self.Guid = Guid > > + self.FwVersion = FwVersion > > + self.LowestSupportedVersion = LowestSupportedVersion > > + self.MonotonicCount = MonotonicCount > > + self.HardwareInstance = HardwareInstance > > + self.UpdateImageIndex = UpdateImageIndex > > + self.SignToolPfxFile = SignToolPfxFile > > + self.OpenSslSignerPrivateCertFile = OpenSslSignerPrivateCertFile > > + self.OpenSslOtherPublicCertFile = OpenSslOtherPublicCertFile > > + self.OpenSslTrustedPublicCertFile = OpenSslTrustedPublicCertFile > > + self.SigningToolPath = SigningToolPath > > + > > + self.UseSignTool = self.SignToolPfxFile is not None > > + self.UseOpenSsl = (self.OpenSslSignerPrivateCertFile is not None and > > + self.OpenSslOtherPublicCertFile is not None and > > + self.OpenSslTrustedPublicCertFile is not None) > > + self.AnyOpenSsl = (self.OpenSslSignerPrivateCertFile is not None or > > + self.OpenSslOtherPublicCertFile is not None or > > + self.OpenSslTrustedPublicCertFile is not None) > > + > > + def Validate(self, args): > > + if self.UseSignTool and self.AnyOpenSsl: > > + raise argparse.ArgumentTypeError ('Providing both signtool and OpenSSL options is not supported') > > + if not self.UseSignTool and not self.UseOpenSsl and self.AnyOpenSsl: > > + if args.JsonFile: > > + raise argparse.ArgumentTypeError ('the following JSON fields are required for OpenSSL: > OpenSslSignerPrivateCertFile, OpenSslOtherPublicCertFile, OpenSslTrustedPublicCertFile') > > + else: > > + raise argparse.ArgumentTypeError ('the following options are required for OpenSSL: --signer-private-cert, > --other-public-cert, --trusted-public-cert') > > + if self.UseSignTool and platform.system() != 'Windows': > > + raise argparse.ArgumentTypeError ('Use of signtool is not supported on this operating system.') > > + if args.Encode: > > + if self.FwVersion is None or self.LowestSupportedVersion is None: > > + if args.JsonFile: > > + raise argparse.ArgumentTypeError ('the following JSON fields are required: FwVersion, > LowestSupportedVersion') > > + else: > > + raise argparse.ArgumentTypeError ('the following options are required: --fw-version, --lsv') > > + if self.FwVersion > 0xFFFFFFFF: > > + if args.JsonFile: > > + raise argparse.ArgumentTypeError ('JSON field FwVersion must be an integer in range 0x0..0xffffffff') > > + else: > > + raise argparse.ArgumentTypeError ('--fw-version must be an integer in range 0x0..0xffffffff') > > + if self.LowestSupportedVersion > 0xFFFFFFFF: > > + if args.JsonFile: > > + raise argparse.ArgumentTypeError ('JSON field LowestSupportedVersion must be an integer in range > 0x0..0xffffffff') > > + else: > > + raise argparse.ArgumentTypeError ('--lsv must be an integer in range 0x0..0xffffffff') > > + > > + if args.Encode: > > + if self.Guid is None: > > + if args.JsonFile: > > + raise argparse.ArgumentTypeError ('the following JSON field is required: Guid') > > + else: > > + raise argparse.ArgumentTypeError ('the following option is required: --guid') > > + if self.HardwareInstance > 0xFFFFFFFFFFFFFFFF: > > + if args.JsonFile: > > + raise argparse.ArgumentTypeError ('JSON field HardwareInstance must be an integer in range > 0x0..0xffffffffffffffff') > > + else: > > + raise argparse.ArgumentTypeError ('--hardware-instance must be an integer in range 0x0..0xffffffffffffffff') > > + if self.MonotonicCount > 0xFFFFFFFFFFFFFFFF: > > + if args.JsonFile: > > + raise argparse.ArgumentTypeError ('JSON field MonotonicCount must be an integer in range > 0x0..0xffffffffffffffff') > > + else: > > + raise argparse.ArgumentTypeError ('--monotonic-count must be an integer in range 0x0..0xffffffffffffffff') > > + if self.UpdateImageIndex >0xFF: > > + if args.JsonFile: > > + raise argparse.ArgumentTypeError ('JSON field UpdateImageIndex must be an integer in range 0x0..0xff') > > + else: > > + raise argparse.ArgumentTypeError ('--update-image-index must be an integer in range 0x0..0xff') > > + > > + if self.UseSignTool: > > + self.SignToolPfxFile.close() > > + self.SignToolPfxFile = self.SignToolPfxFile.name > > + if self.UseOpenSsl: > > + self.OpenSslSignerPrivateCertFile.close() > > + self.OpenSslOtherPublicCertFile.close() > > + self.OpenSslTrustedPublicCertFile.close() > > + self.OpenSslSignerPrivateCertFile = self.OpenSslSignerPrivateCertFile.name > > + self.OpenSslOtherPublicCertFile = self.OpenSslOtherPublicCertFile.name > > + self.OpenSslTrustedPublicCertFile = self.OpenSslTrustedPublicCertFile.name > > + > > + # > > + # Perform additional argument verification > > + # > > + if args.Encode: > > + if 'PersistAcrossReset' not in args.CapsuleFlag: > > + if 'InitiateReset' in args.CapsuleFlag: > > + raise argparse.ArgumentTypeError ('--capflag InitiateReset also requires --capflag PersistAcrossReset') > > + if args.CapsuleOemFlag > 0xFFFF: > > + raise argparse.ArgumentTypeError ('--capoemflag must be an integer between 0x0000 and 0xffff') > > + > > + return True > > + > > + > > + def Encode (PayloadDescriptorList, EmbeddedDriverDescriptorList, Buffer): > > + if args.JsonFile: > > + CheckArgumentConflict(args) > > + try: > > + Json = json.loads (args.JsonFile.read ()) > > + except Exception as Message: > > + print ('GenerateCapsule: error: ' + str(Message)) > > + sys.exit (1) > > + EncodeJsonFileParse(Json) > > + else: > > + for Driver in args.EmbeddedDriver: > > + EmbeddedDriverDescriptorList.append (Driver.read()) > > + PayloadDescriptorList.append (PayloadDescriptor ( > > + Buffer, > > + args.Guid, > > + args.FwVersion, > > + args.LowestSupportedVersion, > > + args.MonotonicCount, > > + args.HardwareInstance, > > + args.UpdateImageIndex, > > + args.SignToolPfxFile, > > + args.OpenSslSignerPrivateCertFile, > > + args.OpenSslOtherPublicCertFile, > > + args.OpenSslTrustedPublicCertFile, > > + args.SigningToolPath > > + )) > > + for SinglePayloadDescriptor in PayloadDescriptorList: > > + try: > > + SinglePayloadDescriptor.Validate (args) > > + except Exception as Message: > > + print ('GenerateCapsule: error: ' + str(Message)) > > + sys.exit (1) > > + for SinglePayloadDescriptor in PayloadDescriptorList: > > + Result = SinglePayloadDescriptor.Payload > > + try: > > + FmpPayloadHeader.FwVersion = SinglePayloadDescriptor.FwVersion > > + FmpPayloadHeader.LowestSupportedVersion = SinglePayloadDescriptor.LowestSupportedVersion > > + FmpPayloadHeader.Payload = SinglePayloadDescriptor.Payload > > + Result = FmpPayloadHeader.Encode () > > + if args.Verbose: > > + FmpPayloadHeader.DumpInfo () > > + except: > > + raise > > + print ('GenerateCapsule: error: can not encode FMP Payload Header') > > + sys.exit (1) > > + if SinglePayloadDescriptor.UseOpenSsl or SinglePayloadDescriptor.UseSignTool: > > + # > > + # Sign image with 64-bit MonotonicCount appended to end of image > > + # > > + try: > > + if SinglePayloadDescriptor.UseSignTool: > > + CertData = SignPayloadSignTool ( > > + Result + struct.pack ('<Q', SinglePayloadDescriptor.MonotonicCount), > > + SinglePayloadDescriptor.SigningToolPath, > > + SinglePayloadDescriptor.SignToolPfxFile, > > + Verbose = args.Verbose > > + ) > > + else: > > + CertData = SignPayloadOpenSsl ( > > + Result + struct.pack ('<Q', SinglePayloadDescriptor.MonotonicCount), > > + SinglePayloadDescriptor.SigningToolPath, > > + SinglePayloadDescriptor.OpenSslSignerPrivateCertFile, > > + SinglePayloadDescriptor.OpenSslOtherPublicCertFile, > > + SinglePayloadDescriptor.OpenSslTrustedPublicCertFile, > > + Verbose = args.Verbose > > + ) > > + except: > > + print ('GenerateCapsule: error: can not sign payload') > > + sys.exit (1) > > + > > + try: > > + FmpAuthHeader.MonotonicCount = SinglePayloadDescriptor.MonotonicCount > > + FmpAuthHeader.CertData = CertData > > + FmpAuthHeader.Payload = Result > > + Result = FmpAuthHeader.Encode () > > + if args.Verbose: > > + FmpAuthHeader.DumpInfo () > > + except: > > + print ('GenerateCapsule: error: can not encode FMP Auth Header') > > + sys.exit (1) > > + FmpCapsuleHeader.AddPayload (SinglePayloadDescriptor.Guid, Result, HardwareInstance = > SinglePayloadDescriptor.HardwareInstance, UpdateImageIndex = SinglePayloadDescriptor.UpdateImageIndex) > > + try: > > + for EmbeddedDriver in EmbeddedDriverDescriptorList: > > + FmpCapsuleHeader.AddEmbeddedDriver(EmbeddedDriver) > > + > > + Result = FmpCapsuleHeader.Encode () > > + if args.Verbose: > > + FmpCapsuleHeader.DumpInfo () > > + except: > > + print ('GenerateCapsule: error: can not encode FMP Capsule Header') > > + sys.exit (1) > > + > > + try: > > + UefiCapsuleHeader.OemFlags = args.CapsuleOemFlag > > + UefiCapsuleHeader.PersistAcrossReset = 'PersistAcrossReset' in args.CapsuleFlag > > + UefiCapsuleHeader.PopulateSystemTable = False > > + UefiCapsuleHeader.InitiateReset = 'InitiateReset' in args.CapsuleFlag > > + UefiCapsuleHeader.Payload = Result > > + Result = UefiCapsuleHeader.Encode () > > + if args.Verbose: > > + UefiCapsuleHeader.DumpInfo () > > + except: > > + print ('GenerateCapsule: error: can not encode UEFI Capsule Header') > > + sys.exit (1) > > + try: > > + if args.Verbose: > > + print ('Write binary output file {File}'.format (File = args.OutputFile.name)) > > + args.OutputFile.write (Result) > > + args.OutputFile.close () > > + except: > > + print ('GenerateCapsule: error: can not write binary output file {File}'.format (File = args.OutputFile.name)) > > + sys.exit (1) > > + > > + def Decode (PayloadDescriptorList, PayloadJsonDescriptorList, Buffer): > > + if args.JsonFile: > > + CheckArgumentConflict(args) > > + # > > + # Parse payload descriptors from JSON > > + # > > + try: > > + Json = json.loads (args.JsonFile.read()) > > + except Exception as Message: > > + print ('GenerateCapsule: error: ' + str(Message)) > > + sys.exit (1) > > + DecodeJsonFileParse (Json) > > + else: > > + PayloadDescriptorList.append (PayloadDescriptor ( > > + Buffer, > > + args.Guid, > > + args.FwVersion, > > + args.LowestSupportedVersion, > > + args.MonotonicCount, > > + args.HardwareInstance, > > + args.UpdateImageIndex, > > + args.SignToolPfxFile, > > + args.OpenSslSignerPrivateCertFile, > > + args.OpenSslOtherPublicCertFile, > > + args.OpenSslTrustedPublicCertFile, > > + args.SigningToolPath > > + )) > > + # > > + # Perform additional verification on payload descriptors > > + # > > + for SinglePayloadDescriptor in PayloadDescriptorList: > > + try: > > + SinglePayloadDescriptor.Validate (args) > > + except Exception as Message: > > + print ('GenerateCapsule: error: ' + str(Message)) > > + sys.exit (1) > > + try: > > + Result = UefiCapsuleHeader.Decode (Buffer) > > + if len (Result) > 0: > > + Result = FmpCapsuleHeader.Decode (Result) > > + if args.JsonFile: > > + if FmpCapsuleHeader.PayloadItemCount != len (PayloadDescriptorList): > > + CapsulePayloadNum = FmpCapsuleHeader.PayloadItemCount > > + JsonPayloadNum = len (PayloadDescriptorList) > > + print ('GenerateCapsule: Decode error: {JsonPayloadNumber} payloads in JSON file {File} and > {CapsulePayloadNumber} payloads in Capsule {CapsuleName}'.format (JsonPayloadNumber = JsonPayloadNum, File = args.JsonFile.name, > CapsulePayloadNumber = CapsulePayloadNum, CapsuleName = args.InputFile.name)) > > + sys.exit (1) > > + for Index in range (0, FmpCapsuleHeader.PayloadItemCount): > > + if Index < len (PayloadDescriptorList): > > + GUID = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).UpdateImageTypeId > > + HardwareInstance = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).UpdateHardwareInstance > > + UpdateImageIndex = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).UpdateImageIndex > > + if PayloadDescriptorList[Index].Guid != GUID or PayloadDescriptorList[Index].HardwareInstance != > HardwareInstance: > > + print ('GenerateCapsule: Decode error: Guid or HardwareInstance pair in input JSON file {File} does > not match the payload {PayloadIndex} in Capsule {InputCapsule}'.format (File = args.JsonFile.name, PayloadIndex = Index + 1, InputCapsule > = args.InputFile.name)) > > + sys.exit (1) > > + PayloadDescriptorList[Index].Payload = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).Payload > > + DecodeJsonOutput = args.OutputFile.name + '.Payload.{Index:d}.bin'.format (Index = Index + 1) > > + PayloadJsonDescriptorList.append (PayloadDescriptor ( > > + DecodeJsonOutput, > > + GUID, > > + None, > > + None, > > + None, > > + HardwareInstance, > > + UpdateImageIndex, > > + PayloadDescriptorList[Index].SignToolPfxFile, > > + PayloadDescriptorList[Index].OpenSslSignerPrivateCertFile, > > + PayloadDescriptorList[Index].OpenSslOtherPublicCertFile, > > + PayloadDescriptorList[Index].OpenSslTrustedPublicCertFile, > > + PayloadDescriptorList[Index].SigningToolPath > > + )) > > + else: > > + PayloadDescriptorList[0].Payload = FmpCapsuleHeader.GetFmpCapsuleImageHeader (0).Payload > > + for Index in range (0, FmpCapsuleHeader.PayloadItemCount): > > + if Index > 0: > > + PayloadDecodeFile = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).Payload > > + PayloadDescriptorList.append (PayloadDescriptor (PayloadDecodeFile, > > + None, > > + None, > > + None, > > + None, > > + None, > > + None, > > + None, > > + None, > > + None, > > + None, > > + None > > + )) > > + GUID = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).UpdateImageTypeId > > + HardwareInstance = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).UpdateHardwareInstance > > + UpdateImageIndex = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).UpdateImageIndex > > + DecodeJsonOutput = args.OutputFile.name + '.Payload.{Index:d}.bin'.format (Index = Index + 1) > > + PayloadJsonDescriptorList.append (PayloadDescriptor ( > > + DecodeJsonOutput, > > + GUID, > > + None, > > + None, > > + None, > > + HardwareInstance, > > + UpdateImageIndex, > > + PayloadDescriptorList[Index].SignToolPfxFile, > > + PayloadDescriptorList[Index].OpenSslSignerPrivateCertFile, > > + PayloadDescriptorList[Index].OpenSslOtherPublicCertFile, > > + PayloadDescriptorList[Index].OpenSslTrustedPublicCertFile, > > + PayloadDescriptorList[Index].SigningToolPath > > + )) > > + JsonIndex = 0 > > + for SinglePayloadDescriptor in PayloadDescriptorList: > > + if args.Verbose: > > + print ('========') > > + UefiCapsuleHeader.DumpInfo () > > + print ('--------') > > + FmpCapsuleHeader.DumpInfo () > > + if FmpAuthHeader.IsSigned(SinglePayloadDescriptor.Payload): > > + if not SinglePayloadDescriptor.UseOpenSsl and not SinglePayloadDescriptor.UseSignTool: > > + print ('GenerateCapsule: decode warning: can not verify singed payload without cert or pfx file. Index = > {Index}'.format (Index = JsonIndex + 1)) > > + SinglePayloadDescriptor.Payload = FmpAuthHeader.Decode (SinglePayloadDescriptor.Payload) > > + PayloadJsonDescriptorList[JsonIndex].MonotonicCount = FmpAuthHeader.MonotonicCount > > + if args.Verbose: > > + print ('--------') > > + FmpAuthHeader.DumpInfo () > > + > > + # > > + # Verify Image with 64-bit MonotonicCount appended to end of image > > + # > > + try: > > + if SinglePayloadDescriptor.UseSignTool: > > + CertData = VerifyPayloadSignTool ( > > + FmpAuthHeader.Payload + struct.pack ('<Q', FmpAuthHeader.MonotonicCount), > > + FmpAuthHeader.CertData, > > + SinglePayloadDescriptor.SigningToolPath, > > + SinglePayloadDescriptor.SignToolPfxFile, > > + Verbose = args.Verbose > > + ) > > + else: > > + CertData = VerifyPayloadOpenSsl ( > > + FmpAuthHeader.Payload + struct.pack ('<Q', FmpAuthHeader.MonotonicCount), > > + FmpAuthHeader.CertData, > > + SinglePayloadDescriptor.SigningToolPath, > > + SinglePayloadDescriptor.OpenSslSignerPrivateCertFile, > > + SinglePayloadDescriptor.OpenSslOtherPublicCertFile, > > + SinglePayloadDescriptor.OpenSslTrustedPublicCertFile, > > + Verbose = args.Verbose > > + ) > > + except ValueError: > > + print ('GenerateCapsule: warning: payload verification failed Index = {Index}'.format (Index = JsonIndex + > 1)) > > + else: > > + if args.Verbose: > > + print ('--------') > > + print ('No EFI_FIRMWARE_IMAGE_AUTHENTICATION') > > + try: > > + SinglePayloadDescriptor.Payload = FmpPayloadHeader.Decode (SinglePayloadDescriptor.Payload) > > + PayloadJsonDescriptorList[JsonIndex].FwVersion = FmpPayloadHeader.FwVersion > > + PayloadJsonDescriptorList[JsonIndex].LowestSupportedVersion = > FmpPayloadHeader.LowestSupportedVersion > > + JsonIndex = JsonIndex + 1 > > + if args.Verbose: > > + print ('--------') > > + FmpPayloadHeader.DumpInfo () > > + print ('========') > > + except: > > + if args.Verbose: > > + print ('--------') > > + print ('No FMP_PAYLOAD_HEADER') > > + print ('========') > > + raise > > + # > > + # Write embedded driver file(s) > > + # > > + for Index in range (0, FmpCapsuleHeader.EmbeddedDriverCount): > > + EmbeddedDriverBuffer = FmpCapsuleHeader.GetEmbeddedDriver (Index) > > + EmbeddedDriverPath = args.OutputFile.name + '.EmbeddedDriver.{Index:d}.efi'.format (Index = Index + 1) > > + try: > > + if args.Verbose: > > + print ('Write embedded driver file {File}'.format (File = EmbeddedDriverPath)) > > + EmbeddedDriverFile = open (EmbeddedDriverPath, 'wb') > > + EmbeddedDriverFile.write (EmbeddedDriverBuffer) > > + EmbeddedDriverFile.close () > > + except: > > + print ('GenerateCapsule: error: can not write embedded driver file {File}'.format (File = EmbeddedDriverPath)) > > + sys.exit (1) > > + > > + except: > > + raise > > + print ('GenerateCapsule: error: can not decode capsule') > > + sys.exit (1) > > + GenerateOutputJson(PayloadJsonDescriptorList) > > + PayloadIndex = 0 > > + for SinglePayloadDescriptor in PayloadDescriptorList: > > + if args.OutputFile is None: > > + print ('GenerateCapsule: Decode error: OutputFile is needed for decode output') > > + sys.exit (1) > > + try: > > + if args.Verbose: > > + print ('Write binary output file {File}'.format (File = args.OutputFile.name)) > > + PayloadDecodePath = args.OutputFile.name + '.Payload.{Index:d}.bin'.format (Index = PayloadIndex + 1) > > + PayloadDecodeFile = open (PayloadDecodePath, 'wb') > > + PayloadDecodeFile.write (SinglePayloadDescriptor.Payload) > > + PayloadDecodeFile.close () > > + PayloadIndex = PayloadIndex + 1 > > + except: > > + print ('GenerateCapsule: error: can not write binary output file {File}'.format (File = > SinglePayloadDescriptor.OutputFile.name)) > > + sys.exit (1) > > + > > + def DumpInfo (Buffer, args): > > + if args.OutputFile is not None: > > + raise argparse.ArgumentTypeError ('the following option is not supported for dumpinfo operations: --output') > > + try: > > + Result = UefiCapsuleHeader.Decode (Buffer) > > + print ('========') > > + UefiCapsuleHeader.DumpInfo () > > + if len (Result) > 0: > > + FmpCapsuleHeader.Decode (Result) > > + print ('--------') > > + FmpCapsuleHeader.DumpInfo () > > + for Index in range (0, FmpCapsuleHeader.PayloadItemCount): > > + Result = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).Payload > > + try: > > + Result = FmpAuthHeader.Decode (Result) > > + print ('--------') > > + FmpAuthHeader.DumpInfo () > > + except: > > + print ('--------') > > + print ('No EFI_FIRMWARE_IMAGE_AUTHENTICATION') > > + try: > > + Result = FmpPayloadHeader.Decode (Result) > > + print ('--------') > > + FmpPayloadHeader.DumpInfo () > > + except: > > + print ('--------') > > + print ('No FMP_PAYLOAD_HEADER') > > + print ('========') > > + except: > > + print ('GenerateCapsule: error: can not decode capsule') > > + sys.exit (1) > > + > > # > > # Create command line argument parser object > > # > > @@ -226,7 +885,7 @@ if __name__ == '__main__': > # > > # Add input and output file arguments > > # > > - parser.add_argument("InputFile", type = argparse.FileType('rb'), > > + parser.add_argument("InputFile", type = argparse.FileType('rb'), nargs='?', > > help = "Input binary payload filename.") > > parser.add_argument("-o", "--output", dest = 'OutputFile', type = argparse.FileType('wb'), > > help = "Output filename.") > > @@ -243,6 +902,8 @@ if __name__ == '__main__': > # > > # Add optional arguments for this command > > # > > + parser.add_argument ("-j", "--json-file", dest = 'JsonFile', type=argparse.FileType('r'), > > + help = "JSON configuration file for multiple payloads and embedded drivers.") > > parser.add_argument ("--capflag", dest = 'CapsuleFlag', action='append', default = [], > > choices=['PersistAcrossReset', 'InitiateReset'], > > help = "Capsule flag can be PersistAcrossReset or InitiateReset or not set") > > @@ -250,7 +911,7 @@ if __name__ == '__main__': > help = "Capsule OEM Flag is an integer between 0x0000 and 0xffff.") > > > > parser.add_argument ("--guid", dest = 'Guid', type = ValidateRegistryFormatGuid, > > - help = "The FMP/ESRT GUID in registry format. Required for encode operations.") > > + help = "The FMP/ESRT GUID in registry format. Required for single payload encode operations.") > > parser.add_argument ("--hardware-instance", dest = 'HardwareInstance', type = ValidateUnsignedInteger, default = > 0x0000000000000000, > > help = "The 64-bit hardware instance. The default is 0x0000000000000000") > > > > @@ -259,9 +920,9 @@ if __name__ == '__main__': > help = "64-bit monotonic count value in header. Default is 0x0000000000000000.") > > > > parser.add_argument ("--fw-version", dest = 'FwVersion', type = ValidateUnsignedInteger, > > - help = "The 32-bit version of the binary payload (e.g. 0x11223344 or 5678). Required for encode > operations that sign a payload.") > > + help = "The 32-bit version of the binary payload (e.g. 0x11223344 or 5678). Required for encode > operations.") > > parser.add_argument ("--lsv", dest = 'LowestSupportedVersion', type = ValidateUnsignedInteger, > > - help = "The 32-bit lowest supported version of the binary payload (e.g. 0x11223344 or 5678). Required for > encode operations that sign a payload.") > > + help = "The 32-bit lowest supported version of the binary payload (e.g. 0x11223344 or 5678). Required for > encode operations.") > > > > parser.add_argument ("--pfx-file", dest='SignToolPfxFile', type=argparse.FileType('rb'), > > help="signtool PFX certificate filename.") > > @@ -276,6 +937,9 @@ if __name__ == '__main__': > parser.add_argument ("--signing-tool-path", dest = 'SigningToolPath', > > help = "Path to signtool or OpenSSL tool. Optional if path to tools are already in PATH.") > > > > + parser.add_argument ("--embedded-driver", dest = 'EmbeddedDriver', type = argparse.FileType('rb'), action='append', default = [], > > + help = "Path to embedded UEFI driver to add to capsule.") > > + > > # > > # Add optional arguments common to all operations > > # > > @@ -286,79 +950,29 @@ if __name__ == '__main__': > help = "Disable all messages except fatal errors.") > > parser.add_argument ("--debug", dest = 'Debug', type = int, metavar = '[0-9]', choices = range (0, 10), default = 0, > > help = "Set debug level") > > + parser.add_argument ("--update-image-index", dest = 'UpdateImageIndex', type = ValidateUnsignedInteger, default = 0x01, help = > "unique number identifying the firmware image within the device ") > > > > # > > # Parse command line arguments > > # > > args = parser.parse_args() > > > > - # > > - # Perform additional argument verification > > - # > > - if args.Encode: > > - if args.Guid is None: > > - parser.error ('the following option is required: --guid') > > - if 'PersistAcrossReset' not in args.CapsuleFlag: > > - if 'InitiateReset' in args.CapsuleFlag: > > - parser.error ('--capflag InitiateReset also requires --capflag PersistAcrossReset') > > - if args.CapsuleOemFlag > 0xFFFF: > > - parser.error ('--capoemflag must be an integer between 0x0000 and 0xffff') > > - if args.HardwareInstance > 0xFFFFFFFFFFFFFFFF: > > - parser.error ('--hardware-instance must be an integer in range 0x0..0xffffffffffffffff') > > - if args.MonotonicCount > 0xFFFFFFFFFFFFFFFF: > > - parser.error ('--monotonic-count must be an integer in range 0x0..0xffffffffffffffff') > > - > > - UseSignTool = args.SignToolPfxFile is not None > > - UseOpenSsl = (args.OpenSslSignerPrivateCertFile is not None and > > - args.OpenSslOtherPublicCertFile is not None and > > - args.OpenSslTrustedPublicCertFile is not None) > > - AnyOpenSsl = (args.OpenSslSignerPrivateCertFile is not None or > > - args.OpenSslOtherPublicCertFile is not None or > > - args.OpenSslTrustedPublicCertFile is not None) > > - if args.Encode or args.Decode: > > - if args.OutputFile is None: > > - parser.error ('the following option is required for all encode and decode operations: --output') > > - > > - if UseSignTool and AnyOpenSsl: > > - parser.error ('Providing both signtool and OpenSSL options is not supported') > > - if not UseSignTool and not UseOpenSsl and AnyOpenSsl: > > - parser.error ('all the following options are required for OpenSSL: --signer-private-cert, --other-public-cert, > --trusted-public-cert') > > - if UseSignTool and platform.system() != 'Windows': > > - parser.error ('Use of signtool is not supported on this operating system.') > > - if args.Encode and (UseSignTool or UseOpenSsl): > > - if args.FwVersion is None or args.LowestSupportedVersion is None: > > - parser.error ('the following options are required: --fw-version, --lsv') > > - if args.FwVersion > 0xFFFFFFFF: > > - parser.error ('--fw-version must be an integer in range 0x0..0xffffffff') > > - if args.LowestSupportedVersion > 0xFFFFFFFF: > > - parser.error ('--lsv must be an integer in range 0x0..0xffffffff') > > - > > - if UseSignTool: > > - args.SignToolPfxFile.close() > > - args.SignToolPfxFile = args.SignToolPfxFile.name > > - if UseOpenSsl: > > - args.OpenSslSignerPrivateCertFile.close() > > - args.OpenSslOtherPublicCertFile.close() > > - args.OpenSslTrustedPublicCertFile.close() > > - args.OpenSslSignerPrivateCertFile = args.OpenSslSignerPrivateCertFile.name > > - args.OpenSslOtherPublicCertFile = args.OpenSslOtherPublicCertFile.name > > - args.OpenSslTrustedPublicCertFile = args.OpenSslTrustedPublicCertFile.name > > - > > - if args.DumpInfo: > > - if args.OutputFile is not None: > > - parser.error ('the following option is not supported for dumpinfo operations: --output') > > - > > # > > # Read binary input file > > # > > - try: > > - if args.Verbose: > > - print ('Read binary input file {File}'.format (File = args.InputFile.name)) > > - Buffer = args.InputFile.read () > > - args.InputFile.close () > > - except: > > - print ('GenerateCapsule: error: can not read binary input file {File}'.format (File = args.InputFile.name)) > > - sys.exit (1) > > + Buffer = '' > > + if args.InputFile: > > + if os.path.getsize (args.InputFile.name) == 0: > > + print ('GenerateCapsule: error: InputFile {File} is empty'.format (File = args.InputFile.name)) > > + sys.exit (1) > > + try: > > + if args.Verbose: > > + print ('Read binary input file {File}'.format (File = args.InputFile.name)) > > + Buffer = args.InputFile.read () > > + args.InputFile.close () > > + except: > > + print ('GenerateCapsule: error: can not read binary input file {File}'.format (File = args.InputFile.name)) > > + sys.exit (1) > > > > # > > # Create objects > > @@ -368,182 +982,27 @@ if __name__ == '__main__': > FmpAuthHeader = FmpAuthHeaderClass () > > FmpPayloadHeader = FmpPayloadHeaderClass () > > > > - if args.Encode: > > - Result = Buffer > > - if UseSignTool or UseOpenSsl: > > - try: > > - FmpPayloadHeader.FwVersion = args.FwVersion > > - FmpPayloadHeader.LowestSupportedVersion = args.LowestSupportedVersion > > - FmpPayloadHeader.Payload = Result > > - Result = FmpPayloadHeader.Encode () > > - if args.Verbose: > > - FmpPayloadHeader.DumpInfo () > > - except: > > - print ('GenerateCapsule: error: can not encode FMP Payload Header') > > - sys.exit (1) > > - > > - # > > - # Sign image with 64-bit MonotonicCount appended to end of image > > - # > > - try: > > - if UseSignTool: > > - CertData = SignPayloadSignTool ( > > - Result + struct.pack ('<Q', args.MonotonicCount), > > - args.SigningToolPath, > > - args.SignToolPfxFile > > - ) > > - else: > > - CertData = SignPayloadOpenSsl ( > > - Result + struct.pack ('<Q', args.MonotonicCount), > > - args.SigningToolPath, > > - args.OpenSslSignerPrivateCertFile, > > - args.OpenSslOtherPublicCertFile, > > - args.OpenSslTrustedPublicCertFile > > - ) > > - except: > > - print ('GenerateCapsule: error: can not sign payload') > > - sys.exit (1) > > - > > - try: > > - FmpAuthHeader.MonotonicCount = args.MonotonicCount > > - FmpAuthHeader.CertData = CertData > > - FmpAuthHeader.Payload = Result > > - Result = FmpAuthHeader.Encode () > > - if args.Verbose: > > - FmpAuthHeader.DumpInfo () > > - except: > > - print ('GenerateCapsule: error: can not encode FMP Auth Header') > > - sys.exit (1) > > - > > - try: > > - FmpCapsuleHeader.AddPayload (args.Guid, Result, HardwareInstance = args.HardwareInstance) > > - Result = FmpCapsuleHeader.Encode () > > - if args.Verbose: > > - FmpCapsuleHeader.DumpInfo () > > - except: > > - print ('GenerateCapsule: error: can not encode FMP Capsule Header') > > - sys.exit (1) > > - > > - try: > > - UefiCapsuleHeader.OemFlags = args.CapsuleOemFlag > > - UefiCapsuleHeader.PersistAcrossReset = 'PersistAcrossReset' in args.CapsuleFlag > > - UefiCapsuleHeader.PopulateSystemTable = False > > - UefiCapsuleHeader.InitiateReset = 'InitiateReset' in args.CapsuleFlag > > - UefiCapsuleHeader.Payload = Result > > - Result = UefiCapsuleHeader.Encode () > > - if args.Verbose: > > - UefiCapsuleHeader.DumpInfo () > > - except: > > - print ('GenerateCapsule: error: can not encode UEFI Capsule Header') > > - sys.exit (1) > > - > > - elif args.Decode: > > - try: > > - Result = UefiCapsuleHeader.Decode (Buffer) > > - FmpCapsuleHeader.Decode (Result) > > - Result = FmpCapsuleHeader.GetFmpCapsuleImageHeader (0).Payload > > - if args.Verbose: > > - print ('========') > > - UefiCapsuleHeader.DumpInfo () > > - print ('--------') > > - FmpCapsuleHeader.DumpInfo () > > - if UseSignTool or UseOpenSsl: > > - Result = FmpAuthHeader.Decode (Result) > > - if args.Verbose: > > - print ('--------') > > - FmpAuthHeader.DumpInfo () > > + EmbeddedDriverDescriptorList = [] > > + PayloadDescriptorList = [] > > + PayloadJsonDescriptorList = [] > > > > - # > > - # Verify Image with 64-bit MonotonicCount appended to end of image > > - # > > - try: > > - if UseSignTool: > > - CertData = VerifyPayloadSignTool ( > > - FmpAuthHeader.Payload + struct.pack ('<Q', FmpAuthHeader.MonotonicCount), > > - FmpAuthHeader.CertData, > > - args.SigningToolPath, > > - args.SignToolPfxFile > > - ) > > - else: > > - CertData = VerifyPayloadOpenSsl ( > > - FmpAuthHeader.Payload + struct.pack ('<Q', FmpAuthHeader.MonotonicCount), > > - FmpAuthHeader.CertData, > > - args.SigningToolPath, > > - args.OpenSslSignerPrivateCertFile, > > - args.OpenSslOtherPublicCertFile, > > - args.OpenSslTrustedPublicCertFile > > - ) > > - except ValueError: > > - print ('GenerateCapsule: warning: can not verify payload.') > > - > > - try: > > - Result = FmpPayloadHeader.Decode (Result) > > - if args.Verbose: > > - print ('--------') > > - FmpPayloadHeader.DumpInfo () > > - print ('========') > > - except: > > - if args.Verbose: > > - print ('--------') > > - print ('No FMP_PAYLOAD_HEADER') > > - print ('========') > > - raise > > - else: > > - if args.Verbose: > > - print ('--------') > > - print ('No EFI_FIRMWARE_IMAGE_AUTHENTICATION') > > - print ('--------') > > - print ('No FMP_PAYLOAD_HEADER') > > - print ('========') > > - except: > > - print ('GenerateCapsule: error: can not decode capsule') > > - sys.exit (1) > > + # > > + #Encode Operation > > + # > > + if args.Encode: > > + Encode (PayloadDescriptorList, EmbeddedDriverDescriptorList, Buffer) > > > > - elif args.DumpInfo: > > - try: > > - Result = UefiCapsuleHeader.Decode (Buffer) > > - FmpCapsuleHeader.Decode (Result) > > - Result = FmpCapsuleHeader.GetFmpCapsuleImageHeader (0).Payload > > - print ('========') > > - UefiCapsuleHeader.DumpInfo () > > - print ('--------') > > - FmpCapsuleHeader.DumpInfo () > > - try: > > - Result = FmpAuthHeader.Decode (Result) > > - print ('--------') > > - FmpAuthHeader.DumpInfo () > > - try: > > - Result = FmpPayloadHeader.Decode (Result) > > - print ('--------') > > - FmpPayloadHeader.DumpInfo () > > - except: > > - print ('--------') > > - print ('No FMP_PAYLOAD_HEADER') > > - except: > > - print ('--------') > > - print ('No EFI_FIRMWARE_IMAGE_AUTHENTICATION') > > - print ('--------') > > - print ('No FMP_PAYLOAD_HEADER') > > - print ('========') > > - except: > > - print ('GenerateCapsule: error: can not decode capsule') > > - sys.exit (1) > > - else: > > - print('GenerateCapsule: error: invalid options') > > - sys.exit (1) > > + # > > + #Decode Operation > > + # > > + if args.Decode: > > + Decode (PayloadDescriptorList, PayloadJsonDescriptorList, Buffer) > > > > # > > - # Write binary output file > > + #Dump Info Operation > > # > > - if args.OutputFile is not None: > > - try: > > - if args.Verbose: > > - print ('Write binary output file {File}'.format (File = args.OutputFile.name)) > > - args.OutputFile.write (Result) > > - args.OutputFile.close () > > - except: > > - print ('GenerateCapsule: error: can not write binary output file {File}'.format (File = args.OutputFile.name)) > > - sys.exit (1) > > + if args.DumpInfo: > > + DumpInfo (Buffer, args) > > > > if args.Verbose: > > print('Success') > > diff --git a/BaseTools/Source/Python/Common/Uefi/Capsule/FmpAuthHeader.py > b/BaseTools/Source/Python/Common/Uefi/Capsule/FmpAuthHeader.py > index 4b8c6da26a..48c605faa8 100644 > --- a/BaseTools/Source/Python/Common/Uefi/Capsule/FmpAuthHeader.py > +++ b/BaseTools/Source/Python/Common/Uefi/Capsule/FmpAuthHeader.py > @@ -2,7 +2,7 @@ > # Module that encodes and decodes a EFI_FIRMWARE_IMAGE_AUTHENTICATION with > > # certificate data and payload data. > > # > > -# Copyright (c) 2018, Intel Corporation. All rights reserved.<BR> > > +# Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<BR> > > # SPDX-License-Identifier: BSD-2-Clause-Patent > > # > > > > @@ -166,6 +166,18 @@ class FmpAuthHeaderClass (object): > self._Valid = True > > return self.Payload > > > > + def IsSigned (self, Buffer): > > + if len (Buffer) < self._StructSize: > > + return False > > + (MonotonicCount, dwLength, wRevision, wCertificateType, CertType) = \ > > + struct.unpack ( > > + self._StructFormat, > > + Buffer[0:self._StructSize] > > + ) > > + if CertType != self._EFI_CERT_TYPE_PKCS7_GUID.bytes_le: > > + return False > > + return True > > + > > def DumpInfo (self): > > if not self._Valid: > > raise ValueError > > diff --git a/BaseTools/Source/Python/Common/Uefi/Capsule/FmpCapsuleHeader.py > b/BaseTools/Source/Python/Common/Uefi/Capsule/FmpCapsuleHeader.py > index c24258d047..91d24919c4 100644 > --- a/BaseTools/Source/Python/Common/Uefi/Capsule/FmpCapsuleHeader.py > +++ b/BaseTools/Source/Python/Common/Uefi/Capsule/FmpCapsuleHeader.py > @@ -2,7 +2,7 @@ > # Module that encodes and decodes a EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER with > > # a payload. > > # > > -# Copyright (c) 2018, Intel Corporation. All rights reserved.<BR> > > +# Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<BR> > > # SPDX-License-Identifier: BSD-2-Clause-Patent > > # > > > > @@ -172,8 +172,8 @@ class FmpCapsuleHeaderClass (object): > raise ValueError > > return self._EmbeddedDriverList[Index] > > > > - def AddPayload (self, UpdateImageTypeId, Payload = b'', VendorCodeBytes = b'', HardwareInstance = 0): > > - self._PayloadList.append ((UpdateImageTypeId, Payload, VendorCodeBytes, HardwareInstance)) > > + def AddPayload (self, UpdateImageTypeId, Payload = b'', VendorCodeBytes = b'', HardwareInstance = 0, UpdateImageIndex = 1): > > + self._PayloadList.append ((UpdateImageTypeId, Payload, VendorCodeBytes, HardwareInstance, UpdateImageIndex)) > > > > def GetFmpCapsuleImageHeader (self, Index): > > if Index >= len (self._FmpCapsuleImageHeaderList): > > @@ -198,10 +198,10 @@ class FmpCapsuleHeaderClass (object): > self._ItemOffsetList.append (Offset) > > Offset = Offset + len (EmbeddedDriver) > > Index = 1 > > - for (UpdateImageTypeId, Payload, VendorCodeBytes, HardwareInstance) in self._PayloadList: > > + for (UpdateImageTypeId, Payload, VendorCodeBytes, HardwareInstance, UpdateImageIndex) in self._PayloadList: > > FmpCapsuleImageHeader = FmpCapsuleImageHeaderClass () > > FmpCapsuleImageHeader.UpdateImageTypeId = UpdateImageTypeId > > - FmpCapsuleImageHeader.UpdateImageIndex = Index > > + FmpCapsuleImageHeader.UpdateImageIndex = UpdateImageIndex > > FmpCapsuleImageHeader.Payload = Payload > > FmpCapsuleImageHeader.VendorCodeBytes = VendorCodeBytes > > FmpCapsuleImageHeader.UpdateHardwareInstance = HardwareInstance > > @@ -288,6 +288,8 @@ class FmpCapsuleHeaderClass (object): > raise ValueError > > print ('EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER.Version = {Version:08X}'.format (Version = self.Version)) > > print ('EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER.EmbeddedDriverCount = {EmbeddedDriverCount:08X}'.format > (EmbeddedDriverCount = self.EmbeddedDriverCount)) > > + for EmbeddedDriver in self._EmbeddedDriverList: > > + print (' sizeof (EmbeddedDriver) = {Size:08X}'.format (Size = len (EmbeddedDriver))) > > print ('EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER.PayloadItemCount = {PayloadItemCount:08X}'.format > (PayloadItemCount = self.PayloadItemCount)) > > print ('EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER.ItemOffsetList = ') > > for Offset in self._ItemOffsetList: > > -- > 2.20.0.windows.1 > > > -=-=-=-=-=-= > Groups.io Links: You receive all messages sent to this group. > > View/Reply Online (#41406): https://edk2.groups.io/g/devel/message/41406 > Mute This Topic: https://groups.io/mt/31807319/1759384 > Group Owner: devel+owner@edk2.groups.io > Unsubscribe: https://edk2.groups.io/g/devel/unsub [liming.gao@intel.com] > -=-=-=-=-=-= ^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [edk2-devel] [Patch] BaseTools/Capsule: Supports UEFI Capsule with multiple payloads and embedded drivers 2019-05-27 13:58 ` [edk2-devel] " Liming Gao @ 2019-05-28 2:10 ` Eric Jin 0 siblings, 0 replies; 4+ messages in thread From: Eric Jin @ 2019-05-28 2:10 UTC (permalink / raw) To: Gao, Liming, devel@edk2.groups.io Cc: Feng, Bob C, Kinney, Michael D, Kinney, Michael D Liming, Yes. It is not for Q2 stable tag. Best Regards Eric -----Original Message----- From: Gao, Liming Sent: Monday, May 27, 2019 9:58 PM To: devel@edk2.groups.io; Jin, Eric <eric.jin@intel.com> Cc: Feng, Bob C <bob.c.feng@intel.com>; Kinney, Michael D <michael.d.kinney@intel.com>; Kinney, Michael D <michael.d.kinney@intel.com> Subject: RE: [edk2-devel] [Patch] BaseTools/Capsule: Supports UEFI Capsule with multiple payloads and embedded drivers Seemly, this is new feature implementation. It will not be for Q2 stable tag. Right? > -----Original Message----- > From: devel@edk2.groups.io [mailto:devel@edk2.groups.io] On Behalf Of Eric Jin > Sent: Monday, May 27, 2019 3:28 PM > To: devel@edk2.groups.io > Cc: Feng, Bob C <bob.c.feng@intel.com>; Gao, Liming <liming.gao@intel.com>; Kinney; Kinney, Michael D <michael.d.kinney@intel.com> > Subject: [edk2-devel] [Patch] BaseTools/Capsule: Supports UEFI Capsule with multiple payloads and embedded drivers > > https://bugzilla.tianocore.org/show_bug.cgi?id=1834 > > * Add arguments "--embedded-driver" to support embedded driver in command line. > * Add arguments "--update-image-index" to identify ImageIndex within the device > in command line. > * Add arguments "-j JSONFILE" to support multiple payloads and embedded drivers > with JSON file. > > The update is in a backwards compatible manner, so all command line options to > support single payload are still supported. But all the options associated with > multiple payloads should be provided in a JSON file. > > Cc: Bob Feng <bob.c.feng@intel.com> > Cc: Liming Gao <liming.gao@intel.com> > Cc: Kinney, Michael D <michael.d.kinney@intel.com> > Signed-off-by: Eric Jin <eric.jin@intel.com> > --- > BaseTools/Source/Python/Capsule/GenerateCapsule.py | 961 > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------------- > ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- > -------- > BaseTools/Source/Python/Common/Uefi/Capsule/FmpAuthHeader.py | 14 +++++++++++++- > BaseTools/Source/Python/Common/Uefi/Capsule/FmpCapsuleHeader.py | 12 +++++++----- > 3 files changed, 730 insertions(+), 257 deletions(-) > > diff --git a/BaseTools/Source/Python/Capsule/GenerateCapsule.py b/BaseTools/Source/Python/Capsule/GenerateCapsule.py > index 4de3635298..ee95c4cc2e 100644 > --- a/BaseTools/Source/Python/Capsule/GenerateCapsule.py > +++ b/BaseTools/Source/Python/Capsule/GenerateCapsule.py > @@ -1,18 +1,16 @@ > ## @file > > # Generate a capsule. > > # > > -# This tool generates a UEFI Capsule around an FMP Capsule. The capsule payload > > +# This tool generates a UEFI Capsule around an FMP Capsule. The capsule payload > > # be signed using signtool or OpenSSL and if it is signed the signed content > > # includes an FMP Payload Header. > > # > > # This tool is intended to be used to generate UEFI Capsules to update the > > -# system firmware or device firmware for integrated devices. In order to > > +# system firmware or device firmware for integrated devices. In order to > > # keep the tool as simple as possible, it has the following limitations: > > -# * Do not support multiple payloads in a capsule. > > -# * Do not support optional drivers in a capsule. > > # * Do not support vendor code bytes in a capsule. > > # > > -# Copyright (c) 2018, Intel Corporation. All rights reserved.<BR> > > +# Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<BR> > > # SPDX-License-Identifier: BSD-2-Clause-Patent > > # > > > > @@ -29,6 +27,7 @@ import os > import tempfile > > import shutil > > import platform > > +import json > > from Common.Uefi.Capsule.UefiCapsuleHeader import UefiCapsuleHeaderClass > > from Common.Uefi.Capsule.FmpCapsuleHeader import FmpCapsuleHeaderClass > > from Common.Uefi.Capsule.FmpAuthHeader import FmpAuthHeaderClass > > @@ -42,7 +41,7 @@ __version__ = '0.9' > __copyright__ = 'Copyright (c) 2018, Intel Corporation. All rights reserved.' > > __description__ = 'Generate a capsule.\n' > > > > -def SignPayloadSignTool (Payload, ToolPath, PfxFile): > > +def SignPayloadSignTool (Payload, ToolPath, PfxFile, Verbose = False): > > # > > # Create a temporary directory > > # > > @@ -75,6 +74,8 @@ def SignPayloadSignTool (Payload, ToolPath, PfxFile): > Command = Command + '/p7 {TempDir} '.format (TempDir = TempDirectoryName) > > Command = Command + '/f {PfxFile} '.format (PfxFile = PfxFile) > > Command = Command + TempFileName > > + if Verbose: > > + print (Command) > > > > # > > # Sign the input file using the specified private key > > @@ -88,7 +89,7 @@ def SignPayloadSignTool (Payload, ToolPath, PfxFile): > > > if Process.returncode != 0: > > shutil.rmtree (TempDirectoryName) > > - print (Result[1].decode(encoding='utf-8', errors='ignore')) > > + print (Result[1].decode()) > > raise ValueError ('GenerateCapsule: error: signtool failed.') > > > > # > > @@ -105,11 +106,11 @@ def SignPayloadSignTool (Payload, ToolPath, PfxFile): > shutil.rmtree (TempDirectoryName) > > return Signature > > > > -def VerifyPayloadSignTool (Payload, CertData, ToolPath, PfxFile): > > +def VerifyPayloadSignTool (Payload, CertData, ToolPath, PfxFile, Verbose = False): > > print ('signtool verify is not supported.') > > raise ValueError ('GenerateCapsule: error: signtool verify is not supported.') > > > > -def SignPayloadOpenSsl (Payload, ToolPath, SignerPrivateCertFile, OtherPublicCertFile, TrustedPublicCertFile): > > +def SignPayloadOpenSsl (Payload, ToolPath, SignerPrivateCertFile, OtherPublicCertFile, TrustedPublicCertFile, Verbose = False): > > # > > # Build openssl command > > # > > @@ -119,6 +120,8 @@ def SignPayloadOpenSsl (Payload, ToolPath, SignerPrivateCertFile, OtherPublicCer > Command = Command + '"{Path}" '.format (Path = os.path.join (ToolPath, 'openssl')) > > Command = Command + 'smime -sign -binary -outform DER -md sha256 ' > > Command = Command + '-signer "{Private}" -certfile "{Public}"'.format (Private = SignerPrivateCertFile, Public = OtherPublicCertFile) > > + if Verbose: > > + print (Command) > > > > # > > # Sign the input file using the specified private key and capture signature from STDOUT > > @@ -131,12 +134,12 @@ def SignPayloadOpenSsl (Payload, ToolPath, SignerPrivateCertFile, OtherPublicCer > raise ValueError ('GenerateCapsule: error: can not run openssl.') > > > > if Process.returncode != 0: > > - print (Result[1].decode(encoding='utf-8', errors='ignore')) > > + print (Result[1].decode()) > > raise ValueError ('GenerateCapsule: error: openssl failed.') > > > > return Signature > > > > -def VerifyPayloadOpenSsl (Payload, CertData, ToolPath, SignerPrivateCertFile, OtherPublicCertFile, TrustedPublicCertFile): > > +def VerifyPayloadOpenSsl (Payload, CertData, ToolPath, SignerPrivateCertFile, OtherPublicCertFile, TrustedPublicCertFile, Verbose = False): > > # > > # Create a temporary directory > > # > > @@ -167,6 +170,8 @@ def VerifyPayloadOpenSsl (Payload, CertData, ToolPath, SignerPrivateCertFile, Ot > Command = Command + '"{Path}" '.format (Path = os.path.join (ToolPath, 'openssl')) > > Command = Command + 'smime -verify -inform DER ' > > Command = Command + '-content {Content} -CAfile "{Public}"'.format (Content = TempFileName, Public = TrustedPublicCertFile) > > + if Verbose: > > + print (Command) > > > > # > > # Verify signature > > @@ -180,7 +185,7 @@ def VerifyPayloadOpenSsl (Payload, CertData, ToolPath, SignerPrivateCertFile, Ot > > > if Process.returncode != 0: > > shutil.rmtree (TempDirectoryName) > > - print (Result[1].decode(encoding='utf-8', errors='ignore')) > > + print (Result[1].decode()) > > raise ValueError ('GenerateCapsule: error: openssl failed.') > > > > shutil.rmtree (TempDirectoryName) > > @@ -212,6 +217,660 @@ if __name__ == '__main__': > raise argparse.ArgumentTypeError (Message) > > return Value > > > > + def ConvertJsonValue (Config, FieldName, Convert, Required = True, Default = None, Open = False): > > + if FieldName not in Config: > > + if Required: > > + print ('GenerateCapsule: error: Payload descriptor invalid syntax. Could not find {Key} in payload > descriptor.'.format(Key = FieldName)) > > + sys.exit (1) > > + return Default > > + try: > > + Value = Convert (Config[FieldName]) > > + except Exception as Message: > > + print ('GenerateCapsule: error: {Key} in payload descriptor has invalid syntax. '.format (Key = FieldName) + str(Message)) > > + sys.exit (1) > > + if Open: > > + try: > > + Value = open (Value, "rb") > > + except: > > + print ('GenerateCapsule: error: can not open file {File}'.format (File = FieldName)) > > + sys.exit (1) > > + return Value > > + > > + def DecodeJsonFileParse (Json): > > + if 'Payloads' not in Json: > > + print ('GenerateCapsule: error "Payloads" section not found in JSON file {File}'.format (File = args.JsonFile.name)) > > + sys.exit (1) > > + for Config in Json['Payloads']: > > + # > > + # Parse fields from JSON > > + # > > + PayloadFile = ConvertJsonValue (Config, 'Payload', os.path.expandvars, Required = False) > > + Guid = ConvertJsonValue (Config, 'Guid', ValidateRegistryFormatGuid, Required = False) > > + FwVersion = ConvertJsonValue (Config, 'FwVersion', ValidateUnsignedInteger, Required = False) > > + LowestSupportedVersion = ConvertJsonValue (Config, 'LowestSupportedVersion', ValidateUnsignedInteger, Required > = False) > > + HardwareInstance = ConvertJsonValue (Config, 'HardwareInstance', ValidateUnsignedInteger, Required = > False, Default = 0) > > + MonotonicCount = ConvertJsonValue (Config, 'MonotonicCount', ValidateUnsignedInteger, Required = > False, Default = 0) > > + SignToolPfxFile = ConvertJsonValue (Config, 'SignToolPfxFile', os.path.expandvars, Required = False, Default > = None, Open = True) > > + OpenSslSignerPrivateCertFile = ConvertJsonValue (Config, 'OpenSslSignerPrivateCertFile', os.path.expandvars, Required = > False, Default = None, Open = True) > > + OpenSslOtherPublicCertFile = ConvertJsonValue (Config, 'OpenSslOtherPublicCertFile', os.path.expandvars, Required = > False, Default = None, Open = True) > > + OpenSslTrustedPublicCertFile = ConvertJsonValue (Config, 'OpenSslTrustedPublicCertFile', os.path.expandvars, Required = > False, Default = None, Open = True) > > + SigningToolPath = ConvertJsonValue (Config, 'SigningToolPath', os.path.expandvars, Required = False, > Default = None) > > + UpdateImageIndex = ConvertJsonValue (Config, 'UpdateImageIndex', ValidateUnsignedInteger, Required = > False, Default = 1) > > + > > + PayloadDescriptorList.append (PayloadDescriptor ( > > + PayloadFile, > > + Guid, > > + FwVersion, > > + LowestSupportedVersion, > > + MonotonicCount, > > + HardwareInstance, > > + UpdateImageIndex, > > + SignToolPfxFile, > > + OpenSslSignerPrivateCertFile, > > + OpenSslOtherPublicCertFile, > > + OpenSslTrustedPublicCertFile, > > + SigningToolPath > > + )) > > + > > + def EncodeJsonFileParse (Json): > > + if 'EmbeddedDrivers' not in Json: > > + print ('GenerateCapsule: warning "EmbeddedDrivers" section not found in JSON file {File}'.format (File = > args.JsonFile.name)) > > + else: > > + for Config in Json['EmbeddedDrivers']: > > + EmbeddedDriverFile = ConvertJsonValue(Config, 'Driver', os.path.expandvars, Open = True) > > + # > > + #Read EmbeddedDriver file > > + # > > + try: > > + if args.Verbose: > > + print ('Read EmbeddedDriver file {File}'.format (File = EmbeddedDriverFile.name)) > > + Driver = EmbeddedDriverFile.read() > > + except: > > + print ('GenerateCapsule: error: can not read EmbeddedDriver file {File}'.format (File = EmbeddedDriverFile.name)) > > + sys.exit(1) > > + EmbeddedDriverDescriptorList.append (Driver) > > + > > + if 'Payloads' not in Json: > > + print ('GenerateCapsule: error: "Payloads" section not found in JSON file {File}'.format (File = args.JsonFile.name)) > > + sys.exit (1) > > + for Config in Json['Payloads']: > > + # > > + # Parse fields from JSON > > + # > > + PayloadFile = ConvertJsonValue (Config, 'Payload', os.path.expandvars, Open = True) > > + Guid = ConvertJsonValue (Config, 'Guid', ValidateRegistryFormatGuid) > > + FwVersion = ConvertJsonValue (Config, 'FwVersion', ValidateUnsignedInteger) > > + LowestSupportedVersion = ConvertJsonValue (Config, 'LowestSupportedVersion', ValidateUnsignedInteger) > > + HardwareInstance = ConvertJsonValue (Config, 'HardwareInstance', ValidateUnsignedInteger, Required = > False, Default = 0) > > + UpdateImageIndex = ConvertJsonValue (Config, 'UpdateImageIndex', ValidateUnsignedInteger, Required = > False, Default = 1) > > + MonotonicCount = ConvertJsonValue (Config, 'MonotonicCount', ValidateUnsignedInteger, Required = > False, Default = 0) > > + SignToolPfxFile = ConvertJsonValue (Config, 'SignToolPfxFile', os.path.expandvars, Required = False, Default > = None, Open = True) > > + OpenSslSignerPrivateCertFile = ConvertJsonValue (Config, 'OpenSslSignerPrivateCertFile', os.path.expandvars, Required = > False, Default = None, Open = True) > > + OpenSslOtherPublicCertFile = ConvertJsonValue (Config, 'OpenSslOtherPublicCertFile', os.path.expandvars, Required = > False, Default = None, Open = True) > > + OpenSslTrustedPublicCertFile = ConvertJsonValue (Config, 'OpenSslTrustedPublicCertFile', os.path.expandvars, Required = > False, Default = None, Open = True) > > + SigningToolPath = ConvertJsonValue (Config, 'SigningToolPath', os.path.expandvars, Required = False, > Default = None) > > + > > + # > > + # Read binary input file > > + # > > + try: > > + if args.Verbose: > > + print ('Read binary input file {File}'.format (File = PayloadFile.name)) > > + Payload = PayloadFile.read() > > + except: > > + print ('GenerateCapsule: error: can not read binary input file {File}'.format (File = PayloadFile.name)) > > + sys.exit (1) > > + PayloadDescriptorList.append (PayloadDescriptor ( > > + Payload, > > + Guid, > > + FwVersion, > > + LowestSupportedVersion, > > + MonotonicCount, > > + HardwareInstance, > > + UpdateImageIndex, > > + SignToolPfxFile, > > + OpenSslSignerPrivateCertFile, > > + OpenSslOtherPublicCertFile, > > + OpenSslTrustedPublicCertFile, > > + SigningToolPath > > + )) > > + > > + def GenerateOutputJson (PayloadJsonDescriptorList): > > + PayloadJson = { > > + "Payloads" : [ > > + { > > + "Guid": str(PayloadDescriptor.Guid).upper(), > > + "FwVersion": str(PayloadDescriptor.FwVersion), > > + "LowestSupportedVersion": str(PayloadDescriptor.LowestSupportedVersion), > > + "MonotonicCount": str(PayloadDescriptor.MonotonicCount), > > + "Payload": PayloadDescriptor.Payload, > > + "HardwareInstance": str(PayloadDescriptor.HardwareInstance), > > + "UpdateImageIndex": str(PayloadDescriptor.UpdateImageIndex), > > + "SignToolPfxFile": str(PayloadDescriptor.SignToolPfxFile), > > + "OpenSslSignerPrivateCertFile": str(PayloadDescriptor.OpenSslSignerPrivateCertFile), > > + "OpenSslOtherPublicCertFile": str(PayloadDescriptor.OpenSslOtherPublicCertFile), > > + "OpenSslTrustedPublicCertFile": str(PayloadDescriptor.OpenSslTrustedPublicCertFile), > > + "SigningToolPath": str(PayloadDescriptor.SigningToolPath) > > + }for PayloadDescriptor in PayloadJsonDescriptorList > > + ] > > + } > > + OutputJsonFile = args.OutputFile.name + '.json' > > + if 'Payloads' in PayloadJson: > > + PayloadSection = PayloadJson ['Payloads'] > > + Index = 0 > > + for PayloadField in PayloadSection: > > + if PayloadJsonDescriptorList[Index].SignToolPfxFile is None: > > + del PayloadField ['SignToolPfxFile'] > > + if PayloadJsonDescriptorList[Index].OpenSslSignerPrivateCertFile is None: > > + del PayloadField ['OpenSslSignerPrivateCertFile'] > > + if PayloadJsonDescriptorList[Index].OpenSslOtherPublicCertFile is None: > > + del PayloadField ['OpenSslOtherPublicCertFile'] > > + if PayloadJsonDescriptorList[Index].OpenSslTrustedPublicCertFile is None: > > + del PayloadField ['OpenSslTrustedPublicCertFile'] > > + if PayloadJsonDescriptorList[Index].SigningToolPath is None: > > + del PayloadField ['SigningToolPath'] > > + Index = Index + 1 > > + Result = json.dumps (PayloadJson, indent=4, sort_keys=True, separators=(',', ': ')) > > + OutputFile = open (OutputJsonFile, 'w') > > + OutputFile.write (Result) > > + OutputFile.close () > > + > > + def CheckArgumentConflict (args): > > + if args.Encode: > > + if args.InputFile: > > + print ('GenerateCapsule: error: Argument InputFile conflicts with Argument -j') > > + sys.exit (1) > > + if args.EmbeddedDriver: > > + print ('GenerateCapsule: error: Argument --embedded-driver conflicts with Argument -j') > > + sys.exit (1) > > + if args.Guid: > > + print ('GenerateCapsule: error: Argument --guid conflicts with Argument -j') > > + sys.exit (1) > > + if args.FwVersion: > > + print ('GenerateCapsule: error: Argument --fw-version conflicts with Argument -j') > > + sys.exit (1) > > + if args.LowestSupportedVersion: > > + print ('GenerateCapsule: error: Argument --lsv conflicts with Argument -j') > > + sys.exit (1) > > + if args.MonotonicCount: > > + print ('GenerateCapsule: error: Argument --monotonic-count conflicts with Argument -j') > > + sys.exit (1) > > + if args.HardwareInstance: > > + print ('GenerateCapsule: error: Argument --hardware-instance conflicts with Argument -j') > > + sys.exit (1) > > + if args.SignToolPfxFile: > > + print ('GenerateCapsule: error: Argument --pfx-file conflicts with Argument -j') > > + sys.exit (1) > > + if args.OpenSslSignerPrivateCertFile: > > + print ('GenerateCapsule: error: Argument --signer-private-cert conflicts with Argument -j') > > + sys.exit (1) > > + if args.OpenSslOtherPublicCertFile: > > + print ('GenerateCapsule: error: Argument --other-public-cert conflicts with Argument -j') > > + sys.exit (1) > > + if args.OpenSslTrustedPublicCertFile: > > + print ('GenerateCapsule: error: Argument --trusted-public-cert conflicts with Argument -j') > > + sys.exit (1) > > + if args.SigningToolPath: > > + print ('GenerateCapsule: error: Argument --signing-tool-path conflicts with Argument -j') > > + sys.exit (1) > > + > > + class PayloadDescriptor (object): > > + def __init__(self, > > + Payload, > > + Guid, > > + FwVersion, > > + LowestSupportedVersion, > > + MonotonicCount = 0, > > + HardwareInstance = 0, > > + UpdateImageIndex = 1, > > + SignToolPfxFile = None, > > + OpenSslSignerPrivateCertFile = None, > > + OpenSslOtherPublicCertFile = None, > > + OpenSslTrustedPublicCertFile = None, > > + SigningToolPath = None > > + ): > > + self.Payload = Payload > > + self.Guid = Guid > > + self.FwVersion = FwVersion > > + self.LowestSupportedVersion = LowestSupportedVersion > > + self.MonotonicCount = MonotonicCount > > + self.HardwareInstance = HardwareInstance > > + self.UpdateImageIndex = UpdateImageIndex > > + self.SignToolPfxFile = SignToolPfxFile > > + self.OpenSslSignerPrivateCertFile = OpenSslSignerPrivateCertFile > > + self.OpenSslOtherPublicCertFile = OpenSslOtherPublicCertFile > > + self.OpenSslTrustedPublicCertFile = OpenSslTrustedPublicCertFile > > + self.SigningToolPath = SigningToolPath > > + > > + self.UseSignTool = self.SignToolPfxFile is not None > > + self.UseOpenSsl = (self.OpenSslSignerPrivateCertFile is not None and > > + self.OpenSslOtherPublicCertFile is not None and > > + self.OpenSslTrustedPublicCertFile is not None) > > + self.AnyOpenSsl = (self.OpenSslSignerPrivateCertFile is not None or > > + self.OpenSslOtherPublicCertFile is not None or > > + self.OpenSslTrustedPublicCertFile is not None) > > + > > + def Validate(self, args): > > + if self.UseSignTool and self.AnyOpenSsl: > > + raise argparse.ArgumentTypeError ('Providing both signtool and OpenSSL options is not supported') > > + if not self.UseSignTool and not self.UseOpenSsl and self.AnyOpenSsl: > > + if args.JsonFile: > > + raise argparse.ArgumentTypeError ('the following JSON fields are required for OpenSSL: > OpenSslSignerPrivateCertFile, OpenSslOtherPublicCertFile, OpenSslTrustedPublicCertFile') > > + else: > > + raise argparse.ArgumentTypeError ('the following options are required for OpenSSL: --signer-private-cert, > --other-public-cert, --trusted-public-cert') > > + if self.UseSignTool and platform.system() != 'Windows': > > + raise argparse.ArgumentTypeError ('Use of signtool is not supported on this operating system.') > > + if args.Encode: > > + if self.FwVersion is None or self.LowestSupportedVersion is None: > > + if args.JsonFile: > > + raise argparse.ArgumentTypeError ('the following JSON fields are required: FwVersion, > LowestSupportedVersion') > > + else: > > + raise argparse.ArgumentTypeError ('the following options are required: --fw-version, --lsv') > > + if self.FwVersion > 0xFFFFFFFF: > > + if args.JsonFile: > > + raise argparse.ArgumentTypeError ('JSON field FwVersion must be an integer in range 0x0..0xffffffff') > > + else: > > + raise argparse.ArgumentTypeError ('--fw-version must be an integer in range 0x0..0xffffffff') > > + if self.LowestSupportedVersion > 0xFFFFFFFF: > > + if args.JsonFile: > > + raise argparse.ArgumentTypeError ('JSON field LowestSupportedVersion must be an integer in range > 0x0..0xffffffff') > > + else: > > + raise argparse.ArgumentTypeError ('--lsv must be an integer in range 0x0..0xffffffff') > > + > > + if args.Encode: > > + if self.Guid is None: > > + if args.JsonFile: > > + raise argparse.ArgumentTypeError ('the following JSON field is required: Guid') > > + else: > > + raise argparse.ArgumentTypeError ('the following option is required: --guid') > > + if self.HardwareInstance > 0xFFFFFFFFFFFFFFFF: > > + if args.JsonFile: > > + raise argparse.ArgumentTypeError ('JSON field HardwareInstance must be an integer in range > 0x0..0xffffffffffffffff') > > + else: > > + raise argparse.ArgumentTypeError ('--hardware-instance must be an integer in range 0x0..0xffffffffffffffff') > > + if self.MonotonicCount > 0xFFFFFFFFFFFFFFFF: > > + if args.JsonFile: > > + raise argparse.ArgumentTypeError ('JSON field MonotonicCount must be an integer in range > 0x0..0xffffffffffffffff') > > + else: > > + raise argparse.ArgumentTypeError ('--monotonic-count must be an integer in range 0x0..0xffffffffffffffff') > > + if self.UpdateImageIndex >0xFF: > > + if args.JsonFile: > > + raise argparse.ArgumentTypeError ('JSON field UpdateImageIndex must be an integer in range 0x0..0xff') > > + else: > > + raise argparse.ArgumentTypeError ('--update-image-index must be an integer in range 0x0..0xff') > > + > > + if self.UseSignTool: > > + self.SignToolPfxFile.close() > > + self.SignToolPfxFile = self.SignToolPfxFile.name > > + if self.UseOpenSsl: > > + self.OpenSslSignerPrivateCertFile.close() > > + self.OpenSslOtherPublicCertFile.close() > > + self.OpenSslTrustedPublicCertFile.close() > > + self.OpenSslSignerPrivateCertFile = self.OpenSslSignerPrivateCertFile.name > > + self.OpenSslOtherPublicCertFile = self.OpenSslOtherPublicCertFile.name > > + self.OpenSslTrustedPublicCertFile = self.OpenSslTrustedPublicCertFile.name > > + > > + # > > + # Perform additional argument verification > > + # > > + if args.Encode: > > + if 'PersistAcrossReset' not in args.CapsuleFlag: > > + if 'InitiateReset' in args.CapsuleFlag: > > + raise argparse.ArgumentTypeError ('--capflag InitiateReset also requires --capflag PersistAcrossReset') > > + if args.CapsuleOemFlag > 0xFFFF: > > + raise argparse.ArgumentTypeError ('--capoemflag must be an integer between 0x0000 and 0xffff') > > + > > + return True > > + > > + > > + def Encode (PayloadDescriptorList, EmbeddedDriverDescriptorList, Buffer): > > + if args.JsonFile: > > + CheckArgumentConflict(args) > > + try: > > + Json = json.loads (args.JsonFile.read ()) > > + except Exception as Message: > > + print ('GenerateCapsule: error: ' + str(Message)) > > + sys.exit (1) > > + EncodeJsonFileParse(Json) > > + else: > > + for Driver in args.EmbeddedDriver: > > + EmbeddedDriverDescriptorList.append (Driver.read()) > > + PayloadDescriptorList.append (PayloadDescriptor ( > > + Buffer, > > + args.Guid, > > + args.FwVersion, > > + args.LowestSupportedVersion, > > + args.MonotonicCount, > > + args.HardwareInstance, > > + args.UpdateImageIndex, > > + args.SignToolPfxFile, > > + args.OpenSslSignerPrivateCertFile, > > + args.OpenSslOtherPublicCertFile, > > + args.OpenSslTrustedPublicCertFile, > > + args.SigningToolPath > > + )) > > + for SinglePayloadDescriptor in PayloadDescriptorList: > > + try: > > + SinglePayloadDescriptor.Validate (args) > > + except Exception as Message: > > + print ('GenerateCapsule: error: ' + str(Message)) > > + sys.exit (1) > > + for SinglePayloadDescriptor in PayloadDescriptorList: > > + Result = SinglePayloadDescriptor.Payload > > + try: > > + FmpPayloadHeader.FwVersion = SinglePayloadDescriptor.FwVersion > > + FmpPayloadHeader.LowestSupportedVersion = SinglePayloadDescriptor.LowestSupportedVersion > > + FmpPayloadHeader.Payload = SinglePayloadDescriptor.Payload > > + Result = FmpPayloadHeader.Encode () > > + if args.Verbose: > > + FmpPayloadHeader.DumpInfo () > > + except: > > + raise > > + print ('GenerateCapsule: error: can not encode FMP Payload Header') > > + sys.exit (1) > > + if SinglePayloadDescriptor.UseOpenSsl or SinglePayloadDescriptor.UseSignTool: > > + # > > + # Sign image with 64-bit MonotonicCount appended to end of image > > + # > > + try: > > + if SinglePayloadDescriptor.UseSignTool: > > + CertData = SignPayloadSignTool ( > > + Result + struct.pack ('<Q', SinglePayloadDescriptor.MonotonicCount), > > + SinglePayloadDescriptor.SigningToolPath, > > + SinglePayloadDescriptor.SignToolPfxFile, > > + Verbose = args.Verbose > > + ) > > + else: > > + CertData = SignPayloadOpenSsl ( > > + Result + struct.pack ('<Q', SinglePayloadDescriptor.MonotonicCount), > > + SinglePayloadDescriptor.SigningToolPath, > > + SinglePayloadDescriptor.OpenSslSignerPrivateCertFile, > > + SinglePayloadDescriptor.OpenSslOtherPublicCertFile, > > + SinglePayloadDescriptor.OpenSslTrustedPublicCertFile, > > + Verbose = args.Verbose > > + ) > > + except: > > + print ('GenerateCapsule: error: can not sign payload') > > + sys.exit (1) > > + > > + try: > > + FmpAuthHeader.MonotonicCount = SinglePayloadDescriptor.MonotonicCount > > + FmpAuthHeader.CertData = CertData > > + FmpAuthHeader.Payload = Result > > + Result = FmpAuthHeader.Encode () > > + if args.Verbose: > > + FmpAuthHeader.DumpInfo () > > + except: > > + print ('GenerateCapsule: error: can not encode FMP Auth Header') > > + sys.exit (1) > > + FmpCapsuleHeader.AddPayload (SinglePayloadDescriptor.Guid, Result, HardwareInstance = > SinglePayloadDescriptor.HardwareInstance, UpdateImageIndex = SinglePayloadDescriptor.UpdateImageIndex) > > + try: > > + for EmbeddedDriver in EmbeddedDriverDescriptorList: > > + FmpCapsuleHeader.AddEmbeddedDriver(EmbeddedDriver) > > + > > + Result = FmpCapsuleHeader.Encode () > > + if args.Verbose: > > + FmpCapsuleHeader.DumpInfo () > > + except: > > + print ('GenerateCapsule: error: can not encode FMP Capsule Header') > > + sys.exit (1) > > + > > + try: > > + UefiCapsuleHeader.OemFlags = args.CapsuleOemFlag > > + UefiCapsuleHeader.PersistAcrossReset = 'PersistAcrossReset' in args.CapsuleFlag > > + UefiCapsuleHeader.PopulateSystemTable = False > > + UefiCapsuleHeader.InitiateReset = 'InitiateReset' in args.CapsuleFlag > > + UefiCapsuleHeader.Payload = Result > > + Result = UefiCapsuleHeader.Encode () > > + if args.Verbose: > > + UefiCapsuleHeader.DumpInfo () > > + except: > > + print ('GenerateCapsule: error: can not encode UEFI Capsule Header') > > + sys.exit (1) > > + try: > > + if args.Verbose: > > + print ('Write binary output file {File}'.format (File = args.OutputFile.name)) > > + args.OutputFile.write (Result) > > + args.OutputFile.close () > > + except: > > + print ('GenerateCapsule: error: can not write binary output file {File}'.format (File = args.OutputFile.name)) > > + sys.exit (1) > > + > > + def Decode (PayloadDescriptorList, PayloadJsonDescriptorList, Buffer): > > + if args.JsonFile: > > + CheckArgumentConflict(args) > > + # > > + # Parse payload descriptors from JSON > > + # > > + try: > > + Json = json.loads (args.JsonFile.read()) > > + except Exception as Message: > > + print ('GenerateCapsule: error: ' + str(Message)) > > + sys.exit (1) > > + DecodeJsonFileParse (Json) > > + else: > > + PayloadDescriptorList.append (PayloadDescriptor ( > > + Buffer, > > + args.Guid, > > + args.FwVersion, > > + args.LowestSupportedVersion, > > + args.MonotonicCount, > > + args.HardwareInstance, > > + args.UpdateImageIndex, > > + args.SignToolPfxFile, > > + args.OpenSslSignerPrivateCertFile, > > + args.OpenSslOtherPublicCertFile, > > + args.OpenSslTrustedPublicCertFile, > > + args.SigningToolPath > > + )) > > + # > > + # Perform additional verification on payload descriptors > > + # > > + for SinglePayloadDescriptor in PayloadDescriptorList: > > + try: > > + SinglePayloadDescriptor.Validate (args) > > + except Exception as Message: > > + print ('GenerateCapsule: error: ' + str(Message)) > > + sys.exit (1) > > + try: > > + Result = UefiCapsuleHeader.Decode (Buffer) > > + if len (Result) > 0: > > + Result = FmpCapsuleHeader.Decode (Result) > > + if args.JsonFile: > > + if FmpCapsuleHeader.PayloadItemCount != len (PayloadDescriptorList): > > + CapsulePayloadNum = FmpCapsuleHeader.PayloadItemCount > > + JsonPayloadNum = len (PayloadDescriptorList) > > + print ('GenerateCapsule: Decode error: {JsonPayloadNumber} payloads in JSON file {File} and > {CapsulePayloadNumber} payloads in Capsule {CapsuleName}'.format (JsonPayloadNumber = JsonPayloadNum, File = args.JsonFile.name, > CapsulePayloadNumber = CapsulePayloadNum, CapsuleName = args.InputFile.name)) > > + sys.exit (1) > > + for Index in range (0, FmpCapsuleHeader.PayloadItemCount): > > + if Index < len (PayloadDescriptorList): > > + GUID = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).UpdateImageTypeId > > + HardwareInstance = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).UpdateHardwareInstance > > + UpdateImageIndex = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).UpdateImageIndex > > + if PayloadDescriptorList[Index].Guid != GUID or PayloadDescriptorList[Index].HardwareInstance != > HardwareInstance: > > + print ('GenerateCapsule: Decode error: Guid or HardwareInstance pair in input JSON file {File} does > not match the payload {PayloadIndex} in Capsule {InputCapsule}'.format (File = args.JsonFile.name, PayloadIndex = Index + 1, InputCapsule > = args.InputFile.name)) > > + sys.exit (1) > > + PayloadDescriptorList[Index].Payload = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).Payload > > + DecodeJsonOutput = args.OutputFile.name + '.Payload.{Index:d}.bin'.format (Index = Index + 1) > > + PayloadJsonDescriptorList.append (PayloadDescriptor ( > > + DecodeJsonOutput, > > + GUID, > > + None, > > + None, > > + None, > > + HardwareInstance, > > + UpdateImageIndex, > > + PayloadDescriptorList[Index].SignToolPfxFile, > > + PayloadDescriptorList[Index].OpenSslSignerPrivateCertFile, > > + PayloadDescriptorList[Index].OpenSslOtherPublicCertFile, > > + PayloadDescriptorList[Index].OpenSslTrustedPublicCertFile, > > + PayloadDescriptorList[Index].SigningToolPath > > + )) > > + else: > > + PayloadDescriptorList[0].Payload = FmpCapsuleHeader.GetFmpCapsuleImageHeader (0).Payload > > + for Index in range (0, FmpCapsuleHeader.PayloadItemCount): > > + if Index > 0: > > + PayloadDecodeFile = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).Payload > > + PayloadDescriptorList.append (PayloadDescriptor (PayloadDecodeFile, > > + None, > > + None, > > + None, > > + None, > > + None, > > + None, > > + None, > > + None, > > + None, > > + None, > > + None > > + )) > > + GUID = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).UpdateImageTypeId > > + HardwareInstance = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).UpdateHardwareInstance > > + UpdateImageIndex = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).UpdateImageIndex > > + DecodeJsonOutput = args.OutputFile.name + '.Payload.{Index:d}.bin'.format (Index = Index + 1) > > + PayloadJsonDescriptorList.append (PayloadDescriptor ( > > + DecodeJsonOutput, > > + GUID, > > + None, > > + None, > > + None, > > + HardwareInstance, > > + UpdateImageIndex, > > + PayloadDescriptorList[Index].SignToolPfxFile, > > + PayloadDescriptorList[Index].OpenSslSignerPrivateCertFile, > > + PayloadDescriptorList[Index].OpenSslOtherPublicCertFile, > > + PayloadDescriptorList[Index].OpenSslTrustedPublicCertFile, > > + PayloadDescriptorList[Index].SigningToolPath > > + )) > > + JsonIndex = 0 > > + for SinglePayloadDescriptor in PayloadDescriptorList: > > + if args.Verbose: > > + print ('========') > > + UefiCapsuleHeader.DumpInfo () > > + print ('--------') > > + FmpCapsuleHeader.DumpInfo () > > + if FmpAuthHeader.IsSigned(SinglePayloadDescriptor.Payload): > > + if not SinglePayloadDescriptor.UseOpenSsl and not SinglePayloadDescriptor.UseSignTool: > > + print ('GenerateCapsule: decode warning: can not verify singed payload without cert or pfx file. Index = > {Index}'.format (Index = JsonIndex + 1)) > > + SinglePayloadDescriptor.Payload = FmpAuthHeader.Decode (SinglePayloadDescriptor.Payload) > > + PayloadJsonDescriptorList[JsonIndex].MonotonicCount = FmpAuthHeader.MonotonicCount > > + if args.Verbose: > > + print ('--------') > > + FmpAuthHeader.DumpInfo () > > + > > + # > > + # Verify Image with 64-bit MonotonicCount appended to end of image > > + # > > + try: > > + if SinglePayloadDescriptor.UseSignTool: > > + CertData = VerifyPayloadSignTool ( > > + FmpAuthHeader.Payload + struct.pack ('<Q', FmpAuthHeader.MonotonicCount), > > + FmpAuthHeader.CertData, > > + SinglePayloadDescriptor.SigningToolPath, > > + SinglePayloadDescriptor.SignToolPfxFile, > > + Verbose = args.Verbose > > + ) > > + else: > > + CertData = VerifyPayloadOpenSsl ( > > + FmpAuthHeader.Payload + struct.pack ('<Q', FmpAuthHeader.MonotonicCount), > > + FmpAuthHeader.CertData, > > + SinglePayloadDescriptor.SigningToolPath, > > + SinglePayloadDescriptor.OpenSslSignerPrivateCertFile, > > + SinglePayloadDescriptor.OpenSslOtherPublicCertFile, > > + SinglePayloadDescriptor.OpenSslTrustedPublicCertFile, > > + Verbose = args.Verbose > > + ) > > + except ValueError: > > + print ('GenerateCapsule: warning: payload verification failed Index = {Index}'.format (Index = JsonIndex + > 1)) > > + else: > > + if args.Verbose: > > + print ('--------') > > + print ('No EFI_FIRMWARE_IMAGE_AUTHENTICATION') > > + try: > > + SinglePayloadDescriptor.Payload = FmpPayloadHeader.Decode (SinglePayloadDescriptor.Payload) > > + PayloadJsonDescriptorList[JsonIndex].FwVersion = FmpPayloadHeader.FwVersion > > + PayloadJsonDescriptorList[JsonIndex].LowestSupportedVersion = > FmpPayloadHeader.LowestSupportedVersion > > + JsonIndex = JsonIndex + 1 > > + if args.Verbose: > > + print ('--------') > > + FmpPayloadHeader.DumpInfo () > > + print ('========') > > + except: > > + if args.Verbose: > > + print ('--------') > > + print ('No FMP_PAYLOAD_HEADER') > > + print ('========') > > + raise > > + # > > + # Write embedded driver file(s) > > + # > > + for Index in range (0, FmpCapsuleHeader.EmbeddedDriverCount): > > + EmbeddedDriverBuffer = FmpCapsuleHeader.GetEmbeddedDriver (Index) > > + EmbeddedDriverPath = args.OutputFile.name + '.EmbeddedDriver.{Index:d}.efi'.format (Index = Index + 1) > > + try: > > + if args.Verbose: > > + print ('Write embedded driver file {File}'.format (File = EmbeddedDriverPath)) > > + EmbeddedDriverFile = open (EmbeddedDriverPath, 'wb') > > + EmbeddedDriverFile.write (EmbeddedDriverBuffer) > > + EmbeddedDriverFile.close () > > + except: > > + print ('GenerateCapsule: error: can not write embedded driver file {File}'.format (File = EmbeddedDriverPath)) > > + sys.exit (1) > > + > > + except: > > + raise > > + print ('GenerateCapsule: error: can not decode capsule') > > + sys.exit (1) > > + GenerateOutputJson(PayloadJsonDescriptorList) > > + PayloadIndex = 0 > > + for SinglePayloadDescriptor in PayloadDescriptorList: > > + if args.OutputFile is None: > > + print ('GenerateCapsule: Decode error: OutputFile is needed for decode output') > > + sys.exit (1) > > + try: > > + if args.Verbose: > > + print ('Write binary output file {File}'.format (File = args.OutputFile.name)) > > + PayloadDecodePath = args.OutputFile.name + '.Payload.{Index:d}.bin'.format (Index = PayloadIndex + 1) > > + PayloadDecodeFile = open (PayloadDecodePath, 'wb') > > + PayloadDecodeFile.write (SinglePayloadDescriptor.Payload) > > + PayloadDecodeFile.close () > > + PayloadIndex = PayloadIndex + 1 > > + except: > > + print ('GenerateCapsule: error: can not write binary output file {File}'.format (File = > SinglePayloadDescriptor.OutputFile.name)) > > + sys.exit (1) > > + > > + def DumpInfo (Buffer, args): > > + if args.OutputFile is not None: > > + raise argparse.ArgumentTypeError ('the following option is not supported for dumpinfo operations: --output') > > + try: > > + Result = UefiCapsuleHeader.Decode (Buffer) > > + print ('========') > > + UefiCapsuleHeader.DumpInfo () > > + if len (Result) > 0: > > + FmpCapsuleHeader.Decode (Result) > > + print ('--------') > > + FmpCapsuleHeader.DumpInfo () > > + for Index in range (0, FmpCapsuleHeader.PayloadItemCount): > > + Result = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).Payload > > + try: > > + Result = FmpAuthHeader.Decode (Result) > > + print ('--------') > > + FmpAuthHeader.DumpInfo () > > + except: > > + print ('--------') > > + print ('No EFI_FIRMWARE_IMAGE_AUTHENTICATION') > > + try: > > + Result = FmpPayloadHeader.Decode (Result) > > + print ('--------') > > + FmpPayloadHeader.DumpInfo () > > + except: > > + print ('--------') > > + print ('No FMP_PAYLOAD_HEADER') > > + print ('========') > > + except: > > + print ('GenerateCapsule: error: can not decode capsule') > > + sys.exit (1) > > + > > # > > # Create command line argument parser object > > # > > @@ -226,7 +885,7 @@ if __name__ == '__main__': > # > > # Add input and output file arguments > > # > > - parser.add_argument("InputFile", type = argparse.FileType('rb'), > > + parser.add_argument("InputFile", type = argparse.FileType('rb'), nargs='?', > > help = "Input binary payload filename.") > > parser.add_argument("-o", "--output", dest = 'OutputFile', type = argparse.FileType('wb'), > > help = "Output filename.") > > @@ -243,6 +902,8 @@ if __name__ == '__main__': > # > > # Add optional arguments for this command > > # > > + parser.add_argument ("-j", "--json-file", dest = 'JsonFile', type=argparse.FileType('r'), > > + help = "JSON configuration file for multiple payloads and embedded drivers.") > > parser.add_argument ("--capflag", dest = 'CapsuleFlag', action='append', default = [], > > choices=['PersistAcrossReset', 'InitiateReset'], > > help = "Capsule flag can be PersistAcrossReset or InitiateReset or not set") > > @@ -250,7 +911,7 @@ if __name__ == '__main__': > help = "Capsule OEM Flag is an integer between 0x0000 and 0xffff.") > > > > parser.add_argument ("--guid", dest = 'Guid', type = ValidateRegistryFormatGuid, > > - help = "The FMP/ESRT GUID in registry format. Required for encode operations.") > > + help = "The FMP/ESRT GUID in registry format. Required for single payload encode operations.") > > parser.add_argument ("--hardware-instance", dest = 'HardwareInstance', type = ValidateUnsignedInteger, default = > 0x0000000000000000, > > help = "The 64-bit hardware instance. The default is 0x0000000000000000") > > > > @@ -259,9 +920,9 @@ if __name__ == '__main__': > help = "64-bit monotonic count value in header. Default is 0x0000000000000000.") > > > > parser.add_argument ("--fw-version", dest = 'FwVersion', type = ValidateUnsignedInteger, > > - help = "The 32-bit version of the binary payload (e.g. 0x11223344 or 5678). Required for encode > operations that sign a payload.") > > + help = "The 32-bit version of the binary payload (e.g. 0x11223344 or 5678). Required for encode > operations.") > > parser.add_argument ("--lsv", dest = 'LowestSupportedVersion', type = ValidateUnsignedInteger, > > - help = "The 32-bit lowest supported version of the binary payload (e.g. 0x11223344 or 5678). Required for > encode operations that sign a payload.") > > + help = "The 32-bit lowest supported version of the binary payload (e.g. 0x11223344 or 5678). Required for > encode operations.") > > > > parser.add_argument ("--pfx-file", dest='SignToolPfxFile', type=argparse.FileType('rb'), > > help="signtool PFX certificate filename.") > > @@ -276,6 +937,9 @@ if __name__ == '__main__': > parser.add_argument ("--signing-tool-path", dest = 'SigningToolPath', > > help = "Path to signtool or OpenSSL tool. Optional if path to tools are already in PATH.") > > > > + parser.add_argument ("--embedded-driver", dest = 'EmbeddedDriver', type = argparse.FileType('rb'), action='append', default = [], > > + help = "Path to embedded UEFI driver to add to capsule.") > > + > > # > > # Add optional arguments common to all operations > > # > > @@ -286,79 +950,29 @@ if __name__ == '__main__': > help = "Disable all messages except fatal errors.") > > parser.add_argument ("--debug", dest = 'Debug', type = int, metavar = '[0-9]', choices = range (0, 10), default = 0, > > help = "Set debug level") > > + parser.add_argument ("--update-image-index", dest = 'UpdateImageIndex', type = ValidateUnsignedInteger, default = 0x01, help = > "unique number identifying the firmware image within the device ") > > > > # > > # Parse command line arguments > > # > > args = parser.parse_args() > > > > - # > > - # Perform additional argument verification > > - # > > - if args.Encode: > > - if args.Guid is None: > > - parser.error ('the following option is required: --guid') > > - if 'PersistAcrossReset' not in args.CapsuleFlag: > > - if 'InitiateReset' in args.CapsuleFlag: > > - parser.error ('--capflag InitiateReset also requires --capflag PersistAcrossReset') > > - if args.CapsuleOemFlag > 0xFFFF: > > - parser.error ('--capoemflag must be an integer between 0x0000 and 0xffff') > > - if args.HardwareInstance > 0xFFFFFFFFFFFFFFFF: > > - parser.error ('--hardware-instance must be an integer in range 0x0..0xffffffffffffffff') > > - if args.MonotonicCount > 0xFFFFFFFFFFFFFFFF: > > - parser.error ('--monotonic-count must be an integer in range 0x0..0xffffffffffffffff') > > - > > - UseSignTool = args.SignToolPfxFile is not None > > - UseOpenSsl = (args.OpenSslSignerPrivateCertFile is not None and > > - args.OpenSslOtherPublicCertFile is not None and > > - args.OpenSslTrustedPublicCertFile is not None) > > - AnyOpenSsl = (args.OpenSslSignerPrivateCertFile is not None or > > - args.OpenSslOtherPublicCertFile is not None or > > - args.OpenSslTrustedPublicCertFile is not None) > > - if args.Encode or args.Decode: > > - if args.OutputFile is None: > > - parser.error ('the following option is required for all encode and decode operations: --output') > > - > > - if UseSignTool and AnyOpenSsl: > > - parser.error ('Providing both signtool and OpenSSL options is not supported') > > - if not UseSignTool and not UseOpenSsl and AnyOpenSsl: > > - parser.error ('all the following options are required for OpenSSL: --signer-private-cert, --other-public-cert, > --trusted-public-cert') > > - if UseSignTool and platform.system() != 'Windows': > > - parser.error ('Use of signtool is not supported on this operating system.') > > - if args.Encode and (UseSignTool or UseOpenSsl): > > - if args.FwVersion is None or args.LowestSupportedVersion is None: > > - parser.error ('the following options are required: --fw-version, --lsv') > > - if args.FwVersion > 0xFFFFFFFF: > > - parser.error ('--fw-version must be an integer in range 0x0..0xffffffff') > > - if args.LowestSupportedVersion > 0xFFFFFFFF: > > - parser.error ('--lsv must be an integer in range 0x0..0xffffffff') > > - > > - if UseSignTool: > > - args.SignToolPfxFile.close() > > - args.SignToolPfxFile = args.SignToolPfxFile.name > > - if UseOpenSsl: > > - args.OpenSslSignerPrivateCertFile.close() > > - args.OpenSslOtherPublicCertFile.close() > > - args.OpenSslTrustedPublicCertFile.close() > > - args.OpenSslSignerPrivateCertFile = args.OpenSslSignerPrivateCertFile.name > > - args.OpenSslOtherPublicCertFile = args.OpenSslOtherPublicCertFile.name > > - args.OpenSslTrustedPublicCertFile = args.OpenSslTrustedPublicCertFile.name > > - > > - if args.DumpInfo: > > - if args.OutputFile is not None: > > - parser.error ('the following option is not supported for dumpinfo operations: --output') > > - > > # > > # Read binary input file > > # > > - try: > > - if args.Verbose: > > - print ('Read binary input file {File}'.format (File = args.InputFile.name)) > > - Buffer = args.InputFile.read () > > - args.InputFile.close () > > - except: > > - print ('GenerateCapsule: error: can not read binary input file {File}'.format (File = args.InputFile.name)) > > - sys.exit (1) > > + Buffer = '' > > + if args.InputFile: > > + if os.path.getsize (args.InputFile.name) == 0: > > + print ('GenerateCapsule: error: InputFile {File} is empty'.format (File = args.InputFile.name)) > > + sys.exit (1) > > + try: > > + if args.Verbose: > > + print ('Read binary input file {File}'.format (File = args.InputFile.name)) > > + Buffer = args.InputFile.read () > > + args.InputFile.close () > > + except: > > + print ('GenerateCapsule: error: can not read binary input file {File}'.format (File = args.InputFile.name)) > > + sys.exit (1) > > > > # > > # Create objects > > @@ -368,182 +982,27 @@ if __name__ == '__main__': > FmpAuthHeader = FmpAuthHeaderClass () > > FmpPayloadHeader = FmpPayloadHeaderClass () > > > > - if args.Encode: > > - Result = Buffer > > - if UseSignTool or UseOpenSsl: > > - try: > > - FmpPayloadHeader.FwVersion = args.FwVersion > > - FmpPayloadHeader.LowestSupportedVersion = args.LowestSupportedVersion > > - FmpPayloadHeader.Payload = Result > > - Result = FmpPayloadHeader.Encode () > > - if args.Verbose: > > - FmpPayloadHeader.DumpInfo () > > - except: > > - print ('GenerateCapsule: error: can not encode FMP Payload Header') > > - sys.exit (1) > > - > > - # > > - # Sign image with 64-bit MonotonicCount appended to end of image > > - # > > - try: > > - if UseSignTool: > > - CertData = SignPayloadSignTool ( > > - Result + struct.pack ('<Q', args.MonotonicCount), > > - args.SigningToolPath, > > - args.SignToolPfxFile > > - ) > > - else: > > - CertData = SignPayloadOpenSsl ( > > - Result + struct.pack ('<Q', args.MonotonicCount), > > - args.SigningToolPath, > > - args.OpenSslSignerPrivateCertFile, > > - args.OpenSslOtherPublicCertFile, > > - args.OpenSslTrustedPublicCertFile > > - ) > > - except: > > - print ('GenerateCapsule: error: can not sign payload') > > - sys.exit (1) > > - > > - try: > > - FmpAuthHeader.MonotonicCount = args.MonotonicCount > > - FmpAuthHeader.CertData = CertData > > - FmpAuthHeader.Payload = Result > > - Result = FmpAuthHeader.Encode () > > - if args.Verbose: > > - FmpAuthHeader.DumpInfo () > > - except: > > - print ('GenerateCapsule: error: can not encode FMP Auth Header') > > - sys.exit (1) > > - > > - try: > > - FmpCapsuleHeader.AddPayload (args.Guid, Result, HardwareInstance = args.HardwareInstance) > > - Result = FmpCapsuleHeader.Encode () > > - if args.Verbose: > > - FmpCapsuleHeader.DumpInfo () > > - except: > > - print ('GenerateCapsule: error: can not encode FMP Capsule Header') > > - sys.exit (1) > > - > > - try: > > - UefiCapsuleHeader.OemFlags = args.CapsuleOemFlag > > - UefiCapsuleHeader.PersistAcrossReset = 'PersistAcrossReset' in args.CapsuleFlag > > - UefiCapsuleHeader.PopulateSystemTable = False > > - UefiCapsuleHeader.InitiateReset = 'InitiateReset' in args.CapsuleFlag > > - UefiCapsuleHeader.Payload = Result > > - Result = UefiCapsuleHeader.Encode () > > - if args.Verbose: > > - UefiCapsuleHeader.DumpInfo () > > - except: > > - print ('GenerateCapsule: error: can not encode UEFI Capsule Header') > > - sys.exit (1) > > - > > - elif args.Decode: > > - try: > > - Result = UefiCapsuleHeader.Decode (Buffer) > > - FmpCapsuleHeader.Decode (Result) > > - Result = FmpCapsuleHeader.GetFmpCapsuleImageHeader (0).Payload > > - if args.Verbose: > > - print ('========') > > - UefiCapsuleHeader.DumpInfo () > > - print ('--------') > > - FmpCapsuleHeader.DumpInfo () > > - if UseSignTool or UseOpenSsl: > > - Result = FmpAuthHeader.Decode (Result) > > - if args.Verbose: > > - print ('--------') > > - FmpAuthHeader.DumpInfo () > > + EmbeddedDriverDescriptorList = [] > > + PayloadDescriptorList = [] > > + PayloadJsonDescriptorList = [] > > > > - # > > - # Verify Image with 64-bit MonotonicCount appended to end of image > > - # > > - try: > > - if UseSignTool: > > - CertData = VerifyPayloadSignTool ( > > - FmpAuthHeader.Payload + struct.pack ('<Q', FmpAuthHeader.MonotonicCount), > > - FmpAuthHeader.CertData, > > - args.SigningToolPath, > > - args.SignToolPfxFile > > - ) > > - else: > > - CertData = VerifyPayloadOpenSsl ( > > - FmpAuthHeader.Payload + struct.pack ('<Q', FmpAuthHeader.MonotonicCount), > > - FmpAuthHeader.CertData, > > - args.SigningToolPath, > > - args.OpenSslSignerPrivateCertFile, > > - args.OpenSslOtherPublicCertFile, > > - args.OpenSslTrustedPublicCertFile > > - ) > > - except ValueError: > > - print ('GenerateCapsule: warning: can not verify payload.') > > - > > - try: > > - Result = FmpPayloadHeader.Decode (Result) > > - if args.Verbose: > > - print ('--------') > > - FmpPayloadHeader.DumpInfo () > > - print ('========') > > - except: > > - if args.Verbose: > > - print ('--------') > > - print ('No FMP_PAYLOAD_HEADER') > > - print ('========') > > - raise > > - else: > > - if args.Verbose: > > - print ('--------') > > - print ('No EFI_FIRMWARE_IMAGE_AUTHENTICATION') > > - print ('--------') > > - print ('No FMP_PAYLOAD_HEADER') > > - print ('========') > > - except: > > - print ('GenerateCapsule: error: can not decode capsule') > > - sys.exit (1) > > + # > > + #Encode Operation > > + # > > + if args.Encode: > > + Encode (PayloadDescriptorList, EmbeddedDriverDescriptorList, Buffer) > > > > - elif args.DumpInfo: > > - try: > > - Result = UefiCapsuleHeader.Decode (Buffer) > > - FmpCapsuleHeader.Decode (Result) > > - Result = FmpCapsuleHeader.GetFmpCapsuleImageHeader (0).Payload > > - print ('========') > > - UefiCapsuleHeader.DumpInfo () > > - print ('--------') > > - FmpCapsuleHeader.DumpInfo () > > - try: > > - Result = FmpAuthHeader.Decode (Result) > > - print ('--------') > > - FmpAuthHeader.DumpInfo () > > - try: > > - Result = FmpPayloadHeader.Decode (Result) > > - print ('--------') > > - FmpPayloadHeader.DumpInfo () > > - except: > > - print ('--------') > > - print ('No FMP_PAYLOAD_HEADER') > > - except: > > - print ('--------') > > - print ('No EFI_FIRMWARE_IMAGE_AUTHENTICATION') > > - print ('--------') > > - print ('No FMP_PAYLOAD_HEADER') > > - print ('========') > > - except: > > - print ('GenerateCapsule: error: can not decode capsule') > > - sys.exit (1) > > - else: > > - print('GenerateCapsule: error: invalid options') > > - sys.exit (1) > > + # > > + #Decode Operation > > + # > > + if args.Decode: > > + Decode (PayloadDescriptorList, PayloadJsonDescriptorList, Buffer) > > > > # > > - # Write binary output file > > + #Dump Info Operation > > # > > - if args.OutputFile is not None: > > - try: > > - if args.Verbose: > > - print ('Write binary output file {File}'.format (File = args.OutputFile.name)) > > - args.OutputFile.write (Result) > > - args.OutputFile.close () > > - except: > > - print ('GenerateCapsule: error: can not write binary output file {File}'.format (File = args.OutputFile.name)) > > - sys.exit (1) > > + if args.DumpInfo: > > + DumpInfo (Buffer, args) > > > > if args.Verbose: > > print('Success') > > diff --git a/BaseTools/Source/Python/Common/Uefi/Capsule/FmpAuthHeader.py > b/BaseTools/Source/Python/Common/Uefi/Capsule/FmpAuthHeader.py > index 4b8c6da26a..48c605faa8 100644 > --- a/BaseTools/Source/Python/Common/Uefi/Capsule/FmpAuthHeader.py > +++ b/BaseTools/Source/Python/Common/Uefi/Capsule/FmpAuthHeader.py > @@ -2,7 +2,7 @@ > # Module that encodes and decodes a EFI_FIRMWARE_IMAGE_AUTHENTICATION with > > # certificate data and payload data. > > # > > -# Copyright (c) 2018, Intel Corporation. All rights reserved.<BR> > > +# Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<BR> > > # SPDX-License-Identifier: BSD-2-Clause-Patent > > # > > > > @@ -166,6 +166,18 @@ class FmpAuthHeaderClass (object): > self._Valid = True > > return self.Payload > > > > + def IsSigned (self, Buffer): > > + if len (Buffer) < self._StructSize: > > + return False > > + (MonotonicCount, dwLength, wRevision, wCertificateType, CertType) = \ > > + struct.unpack ( > > + self._StructFormat, > > + Buffer[0:self._StructSize] > > + ) > > + if CertType != self._EFI_CERT_TYPE_PKCS7_GUID.bytes_le: > > + return False > > + return True > > + > > def DumpInfo (self): > > if not self._Valid: > > raise ValueError > > diff --git a/BaseTools/Source/Python/Common/Uefi/Capsule/FmpCapsuleHeader.py > b/BaseTools/Source/Python/Common/Uefi/Capsule/FmpCapsuleHeader.py > index c24258d047..91d24919c4 100644 > --- a/BaseTools/Source/Python/Common/Uefi/Capsule/FmpCapsuleHeader.py > +++ b/BaseTools/Source/Python/Common/Uefi/Capsule/FmpCapsuleHeader.py > @@ -2,7 +2,7 @@ > # Module that encodes and decodes a EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER with > > # a payload. > > # > > -# Copyright (c) 2018, Intel Corporation. All rights reserved.<BR> > > +# Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<BR> > > # SPDX-License-Identifier: BSD-2-Clause-Patent > > # > > > > @@ -172,8 +172,8 @@ class FmpCapsuleHeaderClass (object): > raise ValueError > > return self._EmbeddedDriverList[Index] > > > > - def AddPayload (self, UpdateImageTypeId, Payload = b'', VendorCodeBytes = b'', HardwareInstance = 0): > > - self._PayloadList.append ((UpdateImageTypeId, Payload, VendorCodeBytes, HardwareInstance)) > > + def AddPayload (self, UpdateImageTypeId, Payload = b'', VendorCodeBytes = b'', HardwareInstance = 0, UpdateImageIndex = 1): > > + self._PayloadList.append ((UpdateImageTypeId, Payload, VendorCodeBytes, HardwareInstance, UpdateImageIndex)) > > > > def GetFmpCapsuleImageHeader (self, Index): > > if Index >= len (self._FmpCapsuleImageHeaderList): > > @@ -198,10 +198,10 @@ class FmpCapsuleHeaderClass (object): > self._ItemOffsetList.append (Offset) > > Offset = Offset + len (EmbeddedDriver) > > Index = 1 > > - for (UpdateImageTypeId, Payload, VendorCodeBytes, HardwareInstance) in self._PayloadList: > > + for (UpdateImageTypeId, Payload, VendorCodeBytes, HardwareInstance, UpdateImageIndex) in self._PayloadList: > > FmpCapsuleImageHeader = FmpCapsuleImageHeaderClass () > > FmpCapsuleImageHeader.UpdateImageTypeId = UpdateImageTypeId > > - FmpCapsuleImageHeader.UpdateImageIndex = Index > > + FmpCapsuleImageHeader.UpdateImageIndex = UpdateImageIndex > > FmpCapsuleImageHeader.Payload = Payload > > FmpCapsuleImageHeader.VendorCodeBytes = VendorCodeBytes > > FmpCapsuleImageHeader.UpdateHardwareInstance = HardwareInstance > > @@ -288,6 +288,8 @@ class FmpCapsuleHeaderClass (object): > raise ValueError > > print ('EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER.Version = {Version:08X}'.format (Version = self.Version)) > > print ('EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER.EmbeddedDriverCount = {EmbeddedDriverCount:08X}'.format > (EmbeddedDriverCount = self.EmbeddedDriverCount)) > > + for EmbeddedDriver in self._EmbeddedDriverList: > > + print (' sizeof (EmbeddedDriver) = {Size:08X}'.format (Size = len (EmbeddedDriver))) > > print ('EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER.PayloadItemCount = {PayloadItemCount:08X}'.format > (PayloadItemCount = self.PayloadItemCount)) > > print ('EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER.ItemOffsetList = ') > > for Offset in self._ItemOffsetList: > > -- > 2.20.0.windows.1 > > > -=-=-=-=-=-= > Groups.io Links: You receive all messages sent to this group. > > View/Reply Online (#41406): https://edk2.groups.io/g/devel/message/41406 > Mute This Topic: https://groups.io/mt/31807319/1759384 > Group Owner: devel+owner@edk2.groups.io > Unsubscribe: https://edk2.groups.io/g/devel/unsub [liming.gao@intel.com] > -=-=-=-=-=-= ^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [Patch] BaseTools/Capsule: Supports UEFI Capsule with multiple payloads and embedded drivers 2019-05-27 7:28 [Patch] BaseTools/Capsule: Supports UEFI Capsule with multiple payloads and embedded drivers Eric Jin 2019-05-27 13:58 ` [edk2-devel] " Liming Gao @ 2019-06-11 3:06 ` Bob Feng 1 sibling, 0 replies; 4+ messages in thread From: Bob Feng @ 2019-06-11 3:06 UTC (permalink / raw) To: Jin, Eric, devel@edk2.groups.io; +Cc: Gao, Liming, Kinney, Michael D Hi Eric, Here are some comments on this patch. + try: + Value = open (Value, "rb") + except: + print ('GenerateCapsule: error: can not open file {File}'.format (File = FieldName)) + sys.exit (1) + return Value There is no close() for the opened file. Suggest to use with statement. + Result = json.dumps (PayloadJson, indent=4, sort_keys=True, separators=(',', ': ')) + OutputFile = open (OutputJsonFile, 'w') + OutputFile.write (Result) + OutputFile.close () Here, please use try and with statement for open() function. + for SinglePayloadDescriptor in PayloadDescriptorList: + Result = SinglePayloadDescriptor.Payload + try: + FmpPayloadHeader.FwVersion = SinglePayloadDescriptor.FwVersion + FmpPayloadHeader.LowestSupportedVersion = SinglePayloadDescriptor.LowestSupportedVersion + FmpPayloadHeader.Payload = SinglePayloadDescriptor.Payload + Result = FmpPayloadHeader.Encode () + if args.Verbose: + FmpPayloadHeader.DumpInfo () + except: + raise + print ('GenerateCapsule: error: can not encode FMP Payload Header') + sys.exit (1) The raise statement in except block looks wrong. + try: + SinglePayloadDescriptor.Payload = FmpPayloadHeader.Decode (SinglePayloadDescriptor.Payload) + PayloadJsonDescriptorList[JsonIndex].FwVersion = FmpPayloadHeader.FwVersion + PayloadJsonDescriptorList[JsonIndex].LowestSupportedVersion = FmpPayloadHeader.LowestSupportedVersion + JsonIndex = JsonIndex + 1 + if args.Verbose: + print ('--------') + FmpPayloadHeader.DumpInfo () + print ('========') + except: + if args.Verbose: + print ('--------') + print ('No FMP_PAYLOAD_HEADER') + print ('========') + raise It looks that the raise statement here should be replaced with print(...) and exit(1) according to your code style in this patch. Thanks, Bob -----Original Message----- From: Jin, Eric Sent: Monday, May 27, 2019 3:28 PM To: devel@edk2.groups.io Cc: Feng, Bob C <bob.c.feng@intel.com>; Gao, Liming <liming.gao@intel.com>; Kinney; Kinney, Michael D <michael.d.kinney@intel.com> Subject: [Patch] BaseTools/Capsule: Supports UEFI Capsule with multiple payloads and embedded drivers https://bugzilla.tianocore.org/show_bug.cgi?id=1834 * Add arguments "--embedded-driver" to support embedded driver in command line. * Add arguments "--update-image-index" to identify ImageIndex within the device in command line. * Add arguments "-j JSONFILE" to support multiple payloads and embedded drivers with JSON file. The update is in a backwards compatible manner, so all command line options to support single payload are still supported. But all the options associated with multiple payloads should be provided in a JSON file. Cc: Bob Feng <bob.c.feng@intel.com> Cc: Liming Gao <liming.gao@intel.com> Cc: Kinney, Michael D <michael.d.kinney@intel.com> Signed-off-by: Eric Jin <eric.jin@intel.com> --- BaseTools/Source/Python/Capsule/GenerateCapsule.py | 961 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- BaseTools/Source/Python/Common/Uefi/Capsule/FmpAuthHeader.py | 14 +++++++++++++- BaseTools/Source/Python/Common/Uefi/Capsule/FmpCapsuleHeader.py | 12 +++++++----- 3 files changed, 730 insertions(+), 257 deletions(-) diff --git a/BaseTools/Source/Python/Capsule/GenerateCapsule.py b/BaseTools/Source/Python/Capsule/GenerateCapsule.py index 4de3635298..ee95c4cc2e 100644 --- a/BaseTools/Source/Python/Capsule/GenerateCapsule.py +++ b/BaseTools/Source/Python/Capsule/GenerateCapsule.py @@ -1,18 +1,16 @@ ## @file # Generate a capsule. # -# This tool generates a UEFI Capsule around an FMP Capsule. The capsule payload +# This tool generates a UEFI Capsule around an FMP Capsule. The capsule payload # be signed using signtool or OpenSSL and if it is signed the signed content # includes an FMP Payload Header. # # This tool is intended to be used to generate UEFI Capsules to update the -# system firmware or device firmware for integrated devices. In order to +# system firmware or device firmware for integrated devices. In order to # keep the tool as simple as possible, it has the following limitations: -# * Do not support multiple payloads in a capsule. -# * Do not support optional drivers in a capsule. # * Do not support vendor code bytes in a capsule. # -# Copyright (c) 2018, Intel Corporation. All rights reserved.<BR> +# Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<BR> # SPDX-License-Identifier: BSD-2-Clause-Patent # @@ -29,6 +27,7 @@ import os import tempfile import shutil import platform +import json from Common.Uefi.Capsule.UefiCapsuleHeader import UefiCapsuleHeaderClass from Common.Uefi.Capsule.FmpCapsuleHeader import FmpCapsuleHeaderClass from Common.Uefi.Capsule.FmpAuthHeader import FmpAuthHeaderClass @@ -42,7 +41,7 @@ __version__ = '0.9' __copyright__ = 'Copyright (c) 2018, Intel Corporation. All rights reserved.' __description__ = 'Generate a capsule.\n' -def SignPayloadSignTool (Payload, ToolPath, PfxFile): +def SignPayloadSignTool (Payload, ToolPath, PfxFile, Verbose = False): # # Create a temporary directory # @@ -75,6 +74,8 @@ def SignPayloadSignTool (Payload, ToolPath, PfxFile): Command = Command + '/p7 {TempDir} '.format (TempDir = TempDirectoryName) Command = Command + '/f {PfxFile} '.format (PfxFile = PfxFile) Command = Command + TempFileName + if Verbose: + print (Command) # # Sign the input file using the specified private key @@ -88,7 +89,7 @@ def SignPayloadSignTool (Payload, ToolPath, PfxFile): if Process.returncode != 0: shutil.rmtree (TempDirectoryName) - print (Result[1].decode(encoding='utf-8', errors='ignore')) + print (Result[1].decode()) raise ValueError ('GenerateCapsule: error: signtool failed.') # @@ -105,11 +106,11 @@ def SignPayloadSignTool (Payload, ToolPath, PfxFile): shutil.rmtree (TempDirectoryName) return Signature -def VerifyPayloadSignTool (Payload, CertData, ToolPath, PfxFile): +def VerifyPayloadSignTool (Payload, CertData, ToolPath, PfxFile, Verbose = False): print ('signtool verify is not supported.') raise ValueError ('GenerateCapsule: error: signtool verify is not supported.') -def SignPayloadOpenSsl (Payload, ToolPath, SignerPrivateCertFile, OtherPublicCertFile, TrustedPublicCertFile): +def SignPayloadOpenSsl (Payload, ToolPath, SignerPrivateCertFile, OtherPublicCertFile, TrustedPublicCertFile, Verbose = False): # # Build openssl command # @@ -119,6 +120,8 @@ def SignPayloadOpenSsl (Payload, ToolPath, SignerPrivateCertFile, OtherPublicCer Command = Command + '"{Path}" '.format (Path = os.path.join (ToolPath, 'openssl')) Command = Command + 'smime -sign -binary -outform DER -md sha256 ' Command = Command + '-signer "{Private}" -certfile "{Public}"'.format (Private = SignerPrivateCertFile, Public = OtherPublicCertFile) + if Verbose: + print (Command) # # Sign the input file using the specified private key and capture signature from STDOUT @@ -131,12 +134,12 @@ def SignPayloadOpenSsl (Payload, ToolPath, SignerPrivateCertFile, OtherPublicCer raise ValueError ('GenerateCapsule: error: can not run openssl.') if Process.returncode != 0: - print (Result[1].decode(encoding='utf-8', errors='ignore')) + print (Result[1].decode()) raise ValueError ('GenerateCapsule: error: openssl failed.') return Signature -def VerifyPayloadOpenSsl (Payload, CertData, ToolPath, SignerPrivateCertFile, OtherPublicCertFile, TrustedPublicCertFile): +def VerifyPayloadOpenSsl (Payload, CertData, ToolPath, SignerPrivateCertFile, OtherPublicCertFile, TrustedPublicCertFile, Verbose = False): # # Create a temporary directory # @@ -167,6 +170,8 @@ def VerifyPayloadOpenSsl (Payload, CertData, ToolPath, SignerPrivateCertFile, Ot Command = Command + '"{Path}" '.format (Path = os.path.join (ToolPath, 'openssl')) Command = Command + 'smime -verify -inform DER ' Command = Command + '-content {Content} -CAfile "{Public}"'.format (Content = TempFileName, Public = TrustedPublicCertFile) + if Verbose: + print (Command) # # Verify signature @@ -180,7 +185,7 @@ def VerifyPayloadOpenSsl (Payload, CertData, ToolPath, SignerPrivateCertFile, Ot if Process.returncode != 0: shutil.rmtree (TempDirectoryName) - print (Result[1].decode(encoding='utf-8', errors='ignore')) + print (Result[1].decode()) raise ValueError ('GenerateCapsule: error: openssl failed.') shutil.rmtree (TempDirectoryName) @@ -212,6 +217,660 @@ if __name__ == '__main__': raise argparse.ArgumentTypeError (Message) return Value + def ConvertJsonValue (Config, FieldName, Convert, Required = True, Default = None, Open = False): + if FieldName not in Config: + if Required: + print ('GenerateCapsule: error: Payload descriptor invalid syntax. Could not find {Key} in payload descriptor.'.format(Key = FieldName)) + sys.exit (1) + return Default + try: + Value = Convert (Config[FieldName]) + except Exception as Message: + print ('GenerateCapsule: error: {Key} in payload descriptor has invalid syntax. '.format (Key = FieldName) + str(Message)) + sys.exit (1) + if Open: + try: + Value = open (Value, "rb") + except: + print ('GenerateCapsule: error: can not open file {File}'.format (File = FieldName)) + sys.exit (1) + return Value + + def DecodeJsonFileParse (Json): + if 'Payloads' not in Json: + print ('GenerateCapsule: error "Payloads" section not found in JSON file {File}'.format (File = args.JsonFile.name)) + sys.exit (1) + for Config in Json['Payloads']: + # + # Parse fields from JSON + # + PayloadFile = ConvertJsonValue (Config, 'Payload', os.path.expandvars, Required = False) + Guid = ConvertJsonValue (Config, 'Guid', ValidateRegistryFormatGuid, Required = False) + FwVersion = ConvertJsonValue (Config, 'FwVersion', ValidateUnsignedInteger, Required = False) + LowestSupportedVersion = ConvertJsonValue (Config, 'LowestSupportedVersion', ValidateUnsignedInteger, Required = False) + HardwareInstance = ConvertJsonValue (Config, 'HardwareInstance', ValidateUnsignedInteger, Required = False, Default = 0) + MonotonicCount = ConvertJsonValue (Config, 'MonotonicCount', ValidateUnsignedInteger, Required = False, Default = 0) + SignToolPfxFile = ConvertJsonValue (Config, 'SignToolPfxFile', os.path.expandvars, Required = False, Default = None, Open = True) + OpenSslSignerPrivateCertFile = ConvertJsonValue (Config, 'OpenSslSignerPrivateCertFile', os.path.expandvars, Required = False, Default = None, Open = True) + OpenSslOtherPublicCertFile = ConvertJsonValue (Config, 'OpenSslOtherPublicCertFile', os.path.expandvars, Required = False, Default = None, Open = True) + OpenSslTrustedPublicCertFile = ConvertJsonValue (Config, 'OpenSslTrustedPublicCertFile', os.path.expandvars, Required = False, Default = None, Open = True) + SigningToolPath = ConvertJsonValue (Config, 'SigningToolPath', os.path.expandvars, Required = False, Default = None) + UpdateImageIndex = ConvertJsonValue (Config, 'UpdateImageIndex', ValidateUnsignedInteger, Required = False, Default = 1) + + PayloadDescriptorList.append (PayloadDescriptor ( + PayloadFile, + Guid, + FwVersion, + LowestSupportedVersion, + MonotonicCount, + HardwareInstance, + UpdateImageIndex, + SignToolPfxFile, + OpenSslSignerPrivateCertFile, + OpenSslOtherPublicCertFile, + OpenSslTrustedPublicCertFile, + SigningToolPath + )) + + def EncodeJsonFileParse (Json): + if 'EmbeddedDrivers' not in Json: + print ('GenerateCapsule: warning "EmbeddedDrivers" section not found in JSON file {File}'.format (File = args.JsonFile.name)) + else: + for Config in Json['EmbeddedDrivers']: + EmbeddedDriverFile = ConvertJsonValue(Config, 'Driver', os.path.expandvars, Open = True) + # + #Read EmbeddedDriver file + # + try: + if args.Verbose: + print ('Read EmbeddedDriver file {File}'.format (File = EmbeddedDriverFile.name)) + Driver = EmbeddedDriverFile.read() + except: + print ('GenerateCapsule: error: can not read EmbeddedDriver file {File}'.format (File = EmbeddedDriverFile.name)) + sys.exit(1) + EmbeddedDriverDescriptorList.append (Driver) + + if 'Payloads' not in Json: + print ('GenerateCapsule: error: "Payloads" section not found in JSON file {File}'.format (File = args.JsonFile.name)) + sys.exit (1) + for Config in Json['Payloads']: + # + # Parse fields from JSON + # + PayloadFile = ConvertJsonValue (Config, 'Payload', os.path.expandvars, Open = True) + Guid = ConvertJsonValue (Config, 'Guid', ValidateRegistryFormatGuid) + FwVersion = ConvertJsonValue (Config, 'FwVersion', ValidateUnsignedInteger) + LowestSupportedVersion = ConvertJsonValue (Config, 'LowestSupportedVersion', ValidateUnsignedInteger) + HardwareInstance = ConvertJsonValue (Config, 'HardwareInstance', ValidateUnsignedInteger, Required = False, Default = 0) + UpdateImageIndex = ConvertJsonValue (Config, 'UpdateImageIndex', ValidateUnsignedInteger, Required = False, Default = 1) + MonotonicCount = ConvertJsonValue (Config, 'MonotonicCount', ValidateUnsignedInteger, Required = False, Default = 0) + SignToolPfxFile = ConvertJsonValue (Config, 'SignToolPfxFile', os.path.expandvars, Required = False, Default = None, Open = True) + OpenSslSignerPrivateCertFile = ConvertJsonValue (Config, 'OpenSslSignerPrivateCertFile', os.path.expandvars, Required = False, Default = None, Open = True) + OpenSslOtherPublicCertFile = ConvertJsonValue (Config, 'OpenSslOtherPublicCertFile', os.path.expandvars, Required = False, Default = None, Open = True) + OpenSslTrustedPublicCertFile = ConvertJsonValue (Config, 'OpenSslTrustedPublicCertFile', os.path.expandvars, Required = False, Default = None, Open = True) + SigningToolPath = ConvertJsonValue (Config, 'SigningToolPath', os.path.expandvars, Required = False, Default = None) + + # + # Read binary input file + # + try: + if args.Verbose: + print ('Read binary input file {File}'.format (File = PayloadFile.name)) + Payload = PayloadFile.read() + except: + print ('GenerateCapsule: error: can not read binary input file {File}'.format (File = PayloadFile.name)) + sys.exit (1) + PayloadDescriptorList.append (PayloadDescriptor ( + Payload, + Guid, + FwVersion, + LowestSupportedVersion, + MonotonicCount, + HardwareInstance, + UpdateImageIndex, + SignToolPfxFile, + OpenSslSignerPrivateCertFile, + OpenSslOtherPublicCertFile, + OpenSslTrustedPublicCertFile, + SigningToolPath + )) + + def GenerateOutputJson (PayloadJsonDescriptorList): + PayloadJson = { + "Payloads" : [ + { + "Guid": str(PayloadDescriptor.Guid).upper(), + "FwVersion": str(PayloadDescriptor.FwVersion), + "LowestSupportedVersion": str(PayloadDescriptor.LowestSupportedVersion), + "MonotonicCount": str(PayloadDescriptor.MonotonicCount), + "Payload": PayloadDescriptor.Payload, + "HardwareInstance": str(PayloadDescriptor.HardwareInstance), + "UpdateImageIndex": str(PayloadDescriptor.UpdateImageIndex), + "SignToolPfxFile": str(PayloadDescriptor.SignToolPfxFile), + "OpenSslSignerPrivateCertFile": str(PayloadDescriptor.OpenSslSignerPrivateCertFile), + "OpenSslOtherPublicCertFile": str(PayloadDescriptor.OpenSslOtherPublicCertFile), + "OpenSslTrustedPublicCertFile": str(PayloadDescriptor.OpenSslTrustedPublicCertFile), + "SigningToolPath": str(PayloadDescriptor.SigningToolPath) + }for PayloadDescriptor in PayloadJsonDescriptorList + ] + } + OutputJsonFile = args.OutputFile.name + '.json' + if 'Payloads' in PayloadJson: + PayloadSection = PayloadJson ['Payloads'] + Index = 0 + for PayloadField in PayloadSection: + if PayloadJsonDescriptorList[Index].SignToolPfxFile is None: + del PayloadField ['SignToolPfxFile'] + if PayloadJsonDescriptorList[Index].OpenSslSignerPrivateCertFile is None: + del PayloadField ['OpenSslSignerPrivateCertFile'] + if PayloadJsonDescriptorList[Index].OpenSslOtherPublicCertFile is None: + del PayloadField ['OpenSslOtherPublicCertFile'] + if PayloadJsonDescriptorList[Index].OpenSslTrustedPublicCertFile is None: + del PayloadField ['OpenSslTrustedPublicCertFile'] + if PayloadJsonDescriptorList[Index].SigningToolPath is None: + del PayloadField ['SigningToolPath'] + Index = Index + 1 + Result = json.dumps (PayloadJson, indent=4, sort_keys=True, separators=(',', ': ')) + OutputFile = open (OutputJsonFile, 'w') + OutputFile.write (Result) + OutputFile.close () + + def CheckArgumentConflict (args): + if args.Encode: + if args.InputFile: + print ('GenerateCapsule: error: Argument InputFile conflicts with Argument -j') + sys.exit (1) + if args.EmbeddedDriver: + print ('GenerateCapsule: error: Argument --embedded-driver conflicts with Argument -j') + sys.exit (1) + if args.Guid: + print ('GenerateCapsule: error: Argument --guid conflicts with Argument -j') + sys.exit (1) + if args.FwVersion: + print ('GenerateCapsule: error: Argument --fw-version conflicts with Argument -j') + sys.exit (1) + if args.LowestSupportedVersion: + print ('GenerateCapsule: error: Argument --lsv conflicts with Argument -j') + sys.exit (1) + if args.MonotonicCount: + print ('GenerateCapsule: error: Argument --monotonic-count conflicts with Argument -j') + sys.exit (1) + if args.HardwareInstance: + print ('GenerateCapsule: error: Argument --hardware-instance conflicts with Argument -j') + sys.exit (1) + if args.SignToolPfxFile: + print ('GenerateCapsule: error: Argument --pfx-file conflicts with Argument -j') + sys.exit (1) + if args.OpenSslSignerPrivateCertFile: + print ('GenerateCapsule: error: Argument --signer-private-cert conflicts with Argument -j') + sys.exit (1) + if args.OpenSslOtherPublicCertFile: + print ('GenerateCapsule: error: Argument --other-public-cert conflicts with Argument -j') + sys.exit (1) + if args.OpenSslTrustedPublicCertFile: + print ('GenerateCapsule: error: Argument --trusted-public-cert conflicts with Argument -j') + sys.exit (1) + if args.SigningToolPath: + print ('GenerateCapsule: error: Argument --signing-tool-path conflicts with Argument -j') + sys.exit (1) + + class PayloadDescriptor (object): + def __init__(self, + Payload, + Guid, + FwVersion, + LowestSupportedVersion, + MonotonicCount = 0, + HardwareInstance = 0, + UpdateImageIndex = 1, + SignToolPfxFile = None, + OpenSslSignerPrivateCertFile = None, + OpenSslOtherPublicCertFile = None, + OpenSslTrustedPublicCertFile = None, + SigningToolPath = None + ): + self.Payload = Payload + self.Guid = Guid + self.FwVersion = FwVersion + self.LowestSupportedVersion = LowestSupportedVersion + self.MonotonicCount = MonotonicCount + self.HardwareInstance = HardwareInstance + self.UpdateImageIndex = UpdateImageIndex + self.SignToolPfxFile = SignToolPfxFile + self.OpenSslSignerPrivateCertFile = OpenSslSignerPrivateCertFile + self.OpenSslOtherPublicCertFile = OpenSslOtherPublicCertFile + self.OpenSslTrustedPublicCertFile = OpenSslTrustedPublicCertFile + self.SigningToolPath = SigningToolPath + + self.UseSignTool = self.SignToolPfxFile is not None + self.UseOpenSsl = (self.OpenSslSignerPrivateCertFile is not None and + self.OpenSslOtherPublicCertFile is not None and + self.OpenSslTrustedPublicCertFile is not None) + self.AnyOpenSsl = (self.OpenSslSignerPrivateCertFile is not None or + self.OpenSslOtherPublicCertFile is not None or + self.OpenSslTrustedPublicCertFile is not None) + + def Validate(self, args): + if self.UseSignTool and self.AnyOpenSsl: + raise argparse.ArgumentTypeError ('Providing both signtool and OpenSSL options is not supported') + if not self.UseSignTool and not self.UseOpenSsl and self.AnyOpenSsl: + if args.JsonFile: + raise argparse.ArgumentTypeError ('the following JSON fields are required for OpenSSL: OpenSslSignerPrivateCertFile, OpenSslOtherPublicCertFile, OpenSslTrustedPublicCertFile') + else: + raise argparse.ArgumentTypeError ('the following options are required for OpenSSL: --signer-private-cert, --other-public-cert, --trusted-public-cert') + if self.UseSignTool and platform.system() != 'Windows': + raise argparse.ArgumentTypeError ('Use of signtool is not supported on this operating system.') + if args.Encode: + if self.FwVersion is None or self.LowestSupportedVersion is None: + if args.JsonFile: + raise argparse.ArgumentTypeError ('the following JSON fields are required: FwVersion, LowestSupportedVersion') + else: + raise argparse.ArgumentTypeError ('the following options are required: --fw-version, --lsv') + if self.FwVersion > 0xFFFFFFFF: + if args.JsonFile: + raise argparse.ArgumentTypeError ('JSON field FwVersion must be an integer in range 0x0..0xffffffff') + else: + raise argparse.ArgumentTypeError ('--fw-version must be an integer in range 0x0..0xffffffff') + if self.LowestSupportedVersion > 0xFFFFFFFF: + if args.JsonFile: + raise argparse.ArgumentTypeError ('JSON field LowestSupportedVersion must be an integer in range 0x0..0xffffffff') + else: + raise argparse.ArgumentTypeError ('--lsv must be an integer in range 0x0..0xffffffff') + + if args.Encode: + if self.Guid is None: + if args.JsonFile: + raise argparse.ArgumentTypeError ('the following JSON field is required: Guid') + else: + raise argparse.ArgumentTypeError ('the following option is required: --guid') + if self.HardwareInstance > 0xFFFFFFFFFFFFFFFF: + if args.JsonFile: + raise argparse.ArgumentTypeError ('JSON field HardwareInstance must be an integer in range 0x0..0xffffffffffffffff') + else: + raise argparse.ArgumentTypeError ('--hardware-instance must be an integer in range 0x0..0xffffffffffffffff') + if self.MonotonicCount > 0xFFFFFFFFFFFFFFFF: + if args.JsonFile: + raise argparse.ArgumentTypeError ('JSON field MonotonicCount must be an integer in range 0x0..0xffffffffffffffff') + else: + raise argparse.ArgumentTypeError ('--monotonic-count must be an integer in range 0x0..0xffffffffffffffff') + if self.UpdateImageIndex >0xFF: + if args.JsonFile: + raise argparse.ArgumentTypeError ('JSON field UpdateImageIndex must be an integer in range 0x0..0xff') + else: + raise argparse.ArgumentTypeError ('--update-image-index must be an integer in range 0x0..0xff') + + if self.UseSignTool: + self.SignToolPfxFile.close() + self.SignToolPfxFile = self.SignToolPfxFile.name + if self.UseOpenSsl: + self.OpenSslSignerPrivateCertFile.close() + self.OpenSslOtherPublicCertFile.close() + self.OpenSslTrustedPublicCertFile.close() + self.OpenSslSignerPrivateCertFile = self.OpenSslSignerPrivateCertFile.name + self.OpenSslOtherPublicCertFile = self.OpenSslOtherPublicCertFile.name + self.OpenSslTrustedPublicCertFile = self.OpenSslTrustedPublicCertFile.name + + # + # Perform additional argument verification + # + if args.Encode: + if 'PersistAcrossReset' not in args.CapsuleFlag: + if 'InitiateReset' in args.CapsuleFlag: + raise argparse.ArgumentTypeError ('--capflag InitiateReset also requires --capflag PersistAcrossReset') + if args.CapsuleOemFlag > 0xFFFF: + raise argparse.ArgumentTypeError ('--capoemflag must be an integer between 0x0000 and 0xffff') + + return True + + + def Encode (PayloadDescriptorList, EmbeddedDriverDescriptorList, Buffer): + if args.JsonFile: + CheckArgumentConflict(args) + try: + Json = json.loads (args.JsonFile.read ()) + except Exception as Message: + print ('GenerateCapsule: error: ' + str(Message)) + sys.exit (1) + EncodeJsonFileParse(Json) + else: + for Driver in args.EmbeddedDriver: + EmbeddedDriverDescriptorList.append (Driver.read()) + PayloadDescriptorList.append (PayloadDescriptor ( + Buffer, + args.Guid, + args.FwVersion, + args.LowestSupportedVersion, + args.MonotonicCount, + args.HardwareInstance, + args.UpdateImageIndex, + args.SignToolPfxFile, + args.OpenSslSignerPrivateCertFile, + args.OpenSslOtherPublicCertFile, + args.OpenSslTrustedPublicCertFile, + args.SigningToolPath + )) + for SinglePayloadDescriptor in PayloadDescriptorList: + try: + SinglePayloadDescriptor.Validate (args) + except Exception as Message: + print ('GenerateCapsule: error: ' + str(Message)) + sys.exit (1) + for SinglePayloadDescriptor in PayloadDescriptorList: + Result = SinglePayloadDescriptor.Payload + try: + FmpPayloadHeader.FwVersion = SinglePayloadDescriptor.FwVersion + FmpPayloadHeader.LowestSupportedVersion = SinglePayloadDescriptor.LowestSupportedVersion + FmpPayloadHeader.Payload = SinglePayloadDescriptor.Payload + Result = FmpPayloadHeader.Encode () + if args.Verbose: + FmpPayloadHeader.DumpInfo () + except: + raise + print ('GenerateCapsule: error: can not encode FMP Payload Header') + sys.exit (1) + if SinglePayloadDescriptor.UseOpenSsl or SinglePayloadDescriptor.UseSignTool: + # + # Sign image with 64-bit MonotonicCount appended to end of image + # + try: + if SinglePayloadDescriptor.UseSignTool: + CertData = SignPayloadSignTool ( + Result + struct.pack ('<Q', SinglePayloadDescriptor.MonotonicCount), + SinglePayloadDescriptor.SigningToolPath, + SinglePayloadDescriptor.SignToolPfxFile, + Verbose = args.Verbose + ) + else: + CertData = SignPayloadOpenSsl ( + Result + struct.pack ('<Q', SinglePayloadDescriptor.MonotonicCount), + SinglePayloadDescriptor.SigningToolPath, + SinglePayloadDescriptor.OpenSslSignerPrivateCertFile, + SinglePayloadDescriptor.OpenSslOtherPublicCertFile, + SinglePayloadDescriptor.OpenSslTrustedPublicCertFile, + Verbose = args.Verbose + ) + except: + print ('GenerateCapsule: error: can not sign payload') + sys.exit (1) + + try: + FmpAuthHeader.MonotonicCount = SinglePayloadDescriptor.MonotonicCount + FmpAuthHeader.CertData = CertData + FmpAuthHeader.Payload = Result + Result = FmpAuthHeader.Encode () + if args.Verbose: + FmpAuthHeader.DumpInfo () + except: + print ('GenerateCapsule: error: can not encode FMP Auth Header') + sys.exit (1) + FmpCapsuleHeader.AddPayload (SinglePayloadDescriptor.Guid, Result, HardwareInstance = SinglePayloadDescriptor.HardwareInstance, UpdateImageIndex = SinglePayloadDescriptor.UpdateImageIndex) + try: + for EmbeddedDriver in EmbeddedDriverDescriptorList: + FmpCapsuleHeader.AddEmbeddedDriver(EmbeddedDriver) + + Result = FmpCapsuleHeader.Encode () + if args.Verbose: + FmpCapsuleHeader.DumpInfo () + except: + print ('GenerateCapsule: error: can not encode FMP Capsule Header') + sys.exit (1) + + try: + UefiCapsuleHeader.OemFlags = args.CapsuleOemFlag + UefiCapsuleHeader.PersistAcrossReset = 'PersistAcrossReset' in args.CapsuleFlag + UefiCapsuleHeader.PopulateSystemTable = False + UefiCapsuleHeader.InitiateReset = 'InitiateReset' in args.CapsuleFlag + UefiCapsuleHeader.Payload = Result + Result = UefiCapsuleHeader.Encode () + if args.Verbose: + UefiCapsuleHeader.DumpInfo () + except: + print ('GenerateCapsule: error: can not encode UEFI Capsule Header') + sys.exit (1) + try: + if args.Verbose: + print ('Write binary output file {File}'.format (File = args.OutputFile.name)) + args.OutputFile.write (Result) + args.OutputFile.close () + except: + print ('GenerateCapsule: error: can not write binary output file {File}'.format (File = args.OutputFile.name)) + sys.exit (1) + + def Decode (PayloadDescriptorList, PayloadJsonDescriptorList, Buffer): + if args.JsonFile: + CheckArgumentConflict(args) + # + # Parse payload descriptors from JSON + # + try: + Json = json.loads (args.JsonFile.read()) + except Exception as Message: + print ('GenerateCapsule: error: ' + str(Message)) + sys.exit (1) + DecodeJsonFileParse (Json) + else: + PayloadDescriptorList.append (PayloadDescriptor ( + Buffer, + args.Guid, + args.FwVersion, + args.LowestSupportedVersion, + args.MonotonicCount, + args.HardwareInstance, + args.UpdateImageIndex, + args.SignToolPfxFile, + args.OpenSslSignerPrivateCertFile, + args.OpenSslOtherPublicCertFile, + args.OpenSslTrustedPublicCertFile, + args.SigningToolPath + )) + # + # Perform additional verification on payload descriptors + # + for SinglePayloadDescriptor in PayloadDescriptorList: + try: + SinglePayloadDescriptor.Validate (args) + except Exception as Message: + print ('GenerateCapsule: error: ' + str(Message)) + sys.exit (1) + try: + Result = UefiCapsuleHeader.Decode (Buffer) + if len (Result) > 0: + Result = FmpCapsuleHeader.Decode (Result) + if args.JsonFile: + if FmpCapsuleHeader.PayloadItemCount != len (PayloadDescriptorList): + CapsulePayloadNum = FmpCapsuleHeader.PayloadItemCount + JsonPayloadNum = len (PayloadDescriptorList) + print ('GenerateCapsule: Decode error: {JsonPayloadNumber} payloads in JSON file {File} and {CapsulePayloadNumber} payloads in Capsule {CapsuleName}'.format (JsonPayloadNumber = JsonPayloadNum, File = args.JsonFile.name, CapsulePayloadNumber = CapsulePayloadNum, CapsuleName = args.InputFile.name)) + sys.exit (1) + for Index in range (0, FmpCapsuleHeader.PayloadItemCount): + if Index < len (PayloadDescriptorList): + GUID = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).UpdateImageTypeId + HardwareInstance = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).UpdateHardwareInstance + UpdateImageIndex = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).UpdateImageIndex + if PayloadDescriptorList[Index].Guid != GUID or PayloadDescriptorList[Index].HardwareInstance != HardwareInstance: + print ('GenerateCapsule: Decode error: Guid or HardwareInstance pair in input JSON file {File} does not match the payload {PayloadIndex} in Capsule {InputCapsule}'.format (File = args.JsonFile.name, PayloadIndex = Index + 1, InputCapsule = args.InputFile.name)) + sys.exit (1) + PayloadDescriptorList[Index].Payload = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).Payload + DecodeJsonOutput = args.OutputFile.name + '.Payload.{Index:d}.bin'.format (Index = Index + 1) + PayloadJsonDescriptorList.append (PayloadDescriptor ( + DecodeJsonOutput, + GUID, + None, + None, + None, + HardwareInstance, + UpdateImageIndex, + PayloadDescriptorList[Index].SignToolPfxFile, + PayloadDescriptorList[Index].OpenSslSignerPrivateCertFile, + PayloadDescriptorList[Index].OpenSslOtherPublicCertFile, + PayloadDescriptorList[Index].OpenSslTrustedPublicCertFile, + PayloadDescriptorList[Index].SigningToolPath + )) + else: + PayloadDescriptorList[0].Payload = FmpCapsuleHeader.GetFmpCapsuleImageHeader (0).Payload + for Index in range (0, FmpCapsuleHeader.PayloadItemCount): + if Index > 0: + PayloadDecodeFile = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).Payload + PayloadDescriptorList.append (PayloadDescriptor (PayloadDecodeFile, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None + )) + GUID = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).UpdateImageTypeId + HardwareInstance = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).UpdateHardwareInstance + UpdateImageIndex = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).UpdateImageIndex + DecodeJsonOutput = args.OutputFile.name + '.Payload.{Index:d}.bin'.format (Index = Index + 1) + PayloadJsonDescriptorList.append (PayloadDescriptor ( + DecodeJsonOutput, + GUID, + None, + None, + None, + HardwareInstance, + UpdateImageIndex, + PayloadDescriptorList[Index].SignToolPfxFile, + PayloadDescriptorList[Index].OpenSslSignerPrivateCertFile, + PayloadDescriptorList[Index].OpenSslOtherPublicCertFile, + PayloadDescriptorList[Index].OpenSslTrustedPublicCertFile, + PayloadDescriptorList[Index].SigningToolPath + )) + JsonIndex = 0 + for SinglePayloadDescriptor in PayloadDescriptorList: + if args.Verbose: + print ('========') + UefiCapsuleHeader.DumpInfo () + print ('--------') + FmpCapsuleHeader.DumpInfo () + if FmpAuthHeader.IsSigned(SinglePayloadDescriptor.Payload): + if not SinglePayloadDescriptor.UseOpenSsl and not SinglePayloadDescriptor.UseSignTool: + print ('GenerateCapsule: decode warning: can not verify singed payload without cert or pfx file. Index = {Index}'.format (Index = JsonIndex + 1)) + SinglePayloadDescriptor.Payload = FmpAuthHeader.Decode (SinglePayloadDescriptor.Payload) + PayloadJsonDescriptorList[JsonIndex].MonotonicCount = FmpAuthHeader.MonotonicCount + if args.Verbose: + print ('--------') + FmpAuthHeader.DumpInfo () + + # + # Verify Image with 64-bit MonotonicCount appended to end of image + # + try: + if SinglePayloadDescriptor.UseSignTool: + CertData = VerifyPayloadSignTool ( + FmpAuthHeader.Payload + struct.pack ('<Q', FmpAuthHeader.MonotonicCount), + FmpAuthHeader.CertData, + SinglePayloadDescriptor.SigningToolPath, + SinglePayloadDescriptor.SignToolPfxFile, + Verbose = args.Verbose + ) + else: + CertData = VerifyPayloadOpenSsl ( + FmpAuthHeader.Payload + struct.pack ('<Q', FmpAuthHeader.MonotonicCount), + FmpAuthHeader.CertData, + SinglePayloadDescriptor.SigningToolPath, + SinglePayloadDescriptor.OpenSslSignerPrivateCertFile, + SinglePayloadDescriptor.OpenSslOtherPublicCertFile, + SinglePayloadDescriptor.OpenSslTrustedPublicCertFile, + Verbose = args.Verbose + ) + except ValueError: + print ('GenerateCapsule: warning: payload verification failed Index = {Index}'.format (Index = JsonIndex + 1)) + else: + if args.Verbose: + print ('--------') + print ('No EFI_FIRMWARE_IMAGE_AUTHENTICATION') + try: + SinglePayloadDescriptor.Payload = FmpPayloadHeader.Decode (SinglePayloadDescriptor.Payload) + PayloadJsonDescriptorList[JsonIndex].FwVersion = FmpPayloadHeader.FwVersion + PayloadJsonDescriptorList[JsonIndex].LowestSupportedVersion = FmpPayloadHeader.LowestSupportedVersion + JsonIndex = JsonIndex + 1 + if args.Verbose: + print ('--------') + FmpPayloadHeader.DumpInfo () + print ('========') + except: + if args.Verbose: + print ('--------') + print ('No FMP_PAYLOAD_HEADER') + print ('========') + raise + # + # Write embedded driver file(s) + # + for Index in range (0, FmpCapsuleHeader.EmbeddedDriverCount): + EmbeddedDriverBuffer = FmpCapsuleHeader.GetEmbeddedDriver (Index) + EmbeddedDriverPath = args.OutputFile.name + '.EmbeddedDriver.{Index:d}.efi'.format (Index = Index + 1) + try: + if args.Verbose: + print ('Write embedded driver file {File}'.format (File = EmbeddedDriverPath)) + EmbeddedDriverFile = open (EmbeddedDriverPath, 'wb') + EmbeddedDriverFile.write (EmbeddedDriverBuffer) + EmbeddedDriverFile.close () + except: + print ('GenerateCapsule: error: can not write embedded driver file {File}'.format (File = EmbeddedDriverPath)) + sys.exit (1) + + except: + raise + print ('GenerateCapsule: error: can not decode capsule') + sys.exit (1) + GenerateOutputJson(PayloadJsonDescriptorList) + PayloadIndex = 0 + for SinglePayloadDescriptor in PayloadDescriptorList: + if args.OutputFile is None: + print ('GenerateCapsule: Decode error: OutputFile is needed for decode output') + sys.exit (1) + try: + if args.Verbose: + print ('Write binary output file {File}'.format (File = args.OutputFile.name)) + PayloadDecodePath = args.OutputFile.name + '.Payload.{Index:d}.bin'.format (Index = PayloadIndex + 1) + PayloadDecodeFile = open (PayloadDecodePath, 'wb') + PayloadDecodeFile.write (SinglePayloadDescriptor.Payload) + PayloadDecodeFile.close () + PayloadIndex = PayloadIndex + 1 + except: + print ('GenerateCapsule: error: can not write binary output file {File}'.format (File = SinglePayloadDescriptor.OutputFile.name)) + sys.exit (1) + + def DumpInfo (Buffer, args): + if args.OutputFile is not None: + raise argparse.ArgumentTypeError ('the following option is not supported for dumpinfo operations: --output') + try: + Result = UefiCapsuleHeader.Decode (Buffer) + print ('========') + UefiCapsuleHeader.DumpInfo () + if len (Result) > 0: + FmpCapsuleHeader.Decode (Result) + print ('--------') + FmpCapsuleHeader.DumpInfo () + for Index in range (0, FmpCapsuleHeader.PayloadItemCount): + Result = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).Payload + try: + Result = FmpAuthHeader.Decode (Result) + print ('--------') + FmpAuthHeader.DumpInfo () + except: + print ('--------') + print ('No EFI_FIRMWARE_IMAGE_AUTHENTICATION') + try: + Result = FmpPayloadHeader.Decode (Result) + print ('--------') + FmpPayloadHeader.DumpInfo () + except: + print ('--------') + print ('No FMP_PAYLOAD_HEADER') + print ('========') + except: + print ('GenerateCapsule: error: can not decode capsule') + sys.exit (1) + # # Create command line argument parser object # @@ -226,7 +885,7 @@ if __name__ == '__main__': # # Add input and output file arguments # - parser.add_argument("InputFile", type = argparse.FileType('rb'), + parser.add_argument("InputFile", type = argparse.FileType('rb'), nargs='?', help = "Input binary payload filename.") parser.add_argument("-o", "--output", dest = 'OutputFile', type = argparse.FileType('wb'), help = "Output filename.") @@ -243,6 +902,8 @@ if __name__ == '__main__': # # Add optional arguments for this command # + parser.add_argument ("-j", "--json-file", dest = 'JsonFile', type=argparse.FileType('r'), + help = "JSON configuration file for multiple payloads and embedded drivers.") parser.add_argument ("--capflag", dest = 'CapsuleFlag', action='append', default = [], choices=['PersistAcrossReset', 'InitiateReset'], help = "Capsule flag can be PersistAcrossReset or InitiateReset or not set") @@ -250,7 +911,7 @@ if __name__ == '__main__': help = "Capsule OEM Flag is an integer between 0x0000 and 0xffff.") parser.add_argument ("--guid", dest = 'Guid', type = ValidateRegistryFormatGuid, - help = "The FMP/ESRT GUID in registry format. Required for encode operations.") + help = "The FMP/ESRT GUID in registry format. Required for single payload encode operations.") parser.add_argument ("--hardware-instance", dest = 'HardwareInstance', type = ValidateUnsignedInteger, default = 0x0000000000000000, help = "The 64-bit hardware instance. The default is 0x0000000000000000") @@ -259,9 +920,9 @@ if __name__ == '__main__': help = "64-bit monotonic count value in header. Default is 0x0000000000000000.") parser.add_argument ("--fw-version", dest = 'FwVersion', type = ValidateUnsignedInteger, - help = "The 32-bit version of the binary payload (e.g. 0x11223344 or 5678). Required for encode operations that sign a payload.") + help = "The 32-bit version of the binary payload (e.g. 0x11223344 or 5678). Required for encode operations.") parser.add_argument ("--lsv", dest = 'LowestSupportedVersion', type = ValidateUnsignedInteger, - help = "The 32-bit lowest supported version of the binary payload (e.g. 0x11223344 or 5678). Required for encode operations that sign a payload.") + help = "The 32-bit lowest supported version of the binary payload (e.g. 0x11223344 or 5678). Required for encode operations.") parser.add_argument ("--pfx-file", dest='SignToolPfxFile', type=argparse.FileType('rb'), help="signtool PFX certificate filename.") @@ -276,6 +937,9 @@ if __name__ == '__main__': parser.add_argument ("--signing-tool-path", dest = 'SigningToolPath', help = "Path to signtool or OpenSSL tool. Optional if path to tools are already in PATH.") + parser.add_argument ("--embedded-driver", dest = 'EmbeddedDriver', type = argparse.FileType('rb'), action='append', default = [], + help = "Path to embedded UEFI driver to add to capsule.") + # # Add optional arguments common to all operations # @@ -286,79 +950,29 @@ if __name__ == '__main__': help = "Disable all messages except fatal errors.") parser.add_argument ("--debug", dest = 'Debug', type = int, metavar = '[0-9]', choices = range (0, 10), default = 0, help = "Set debug level") + parser.add_argument ("--update-image-index", dest = 'UpdateImageIndex', type = ValidateUnsignedInteger, default = 0x01, help = "unique number identifying the firmware image within the device ") # # Parse command line arguments # args = parser.parse_args() - # - # Perform additional argument verification - # - if args.Encode: - if args.Guid is None: - parser.error ('the following option is required: --guid') - if 'PersistAcrossReset' not in args.CapsuleFlag: - if 'InitiateReset' in args.CapsuleFlag: - parser.error ('--capflag InitiateReset also requires --capflag PersistAcrossReset') - if args.CapsuleOemFlag > 0xFFFF: - parser.error ('--capoemflag must be an integer between 0x0000 and 0xffff') - if args.HardwareInstance > 0xFFFFFFFFFFFFFFFF: - parser.error ('--hardware-instance must be an integer in range 0x0..0xffffffffffffffff') - if args.MonotonicCount > 0xFFFFFFFFFFFFFFFF: - parser.error ('--monotonic-count must be an integer in range 0x0..0xffffffffffffffff') - - UseSignTool = args.SignToolPfxFile is not None - UseOpenSsl = (args.OpenSslSignerPrivateCertFile is not None and - args.OpenSslOtherPublicCertFile is not None and - args.OpenSslTrustedPublicCertFile is not None) - AnyOpenSsl = (args.OpenSslSignerPrivateCertFile is not None or - args.OpenSslOtherPublicCertFile is not None or - args.OpenSslTrustedPublicCertFile is not None) - if args.Encode or args.Decode: - if args.OutputFile is None: - parser.error ('the following option is required for all encode and decode operations: --output') - - if UseSignTool and AnyOpenSsl: - parser.error ('Providing both signtool and OpenSSL options is not supported') - if not UseSignTool and not UseOpenSsl and AnyOpenSsl: - parser.error ('all the following options are required for OpenSSL: --signer-private-cert, --other-public-cert, --trusted-public-cert') - if UseSignTool and platform.system() != 'Windows': - parser.error ('Use of signtool is not supported on this operating system.') - if args.Encode and (UseSignTool or UseOpenSsl): - if args.FwVersion is None or args.LowestSupportedVersion is None: - parser.error ('the following options are required: --fw-version, --lsv') - if args.FwVersion > 0xFFFFFFFF: - parser.error ('--fw-version must be an integer in range 0x0..0xffffffff') - if args.LowestSupportedVersion > 0xFFFFFFFF: - parser.error ('--lsv must be an integer in range 0x0..0xffffffff') - - if UseSignTool: - args.SignToolPfxFile.close() - args.SignToolPfxFile = args.SignToolPfxFile.name - if UseOpenSsl: - args.OpenSslSignerPrivateCertFile.close() - args.OpenSslOtherPublicCertFile.close() - args.OpenSslTrustedPublicCertFile.close() - args.OpenSslSignerPrivateCertFile = args.OpenSslSignerPrivateCertFile.name - args.OpenSslOtherPublicCertFile = args.OpenSslOtherPublicCertFile.name - args.OpenSslTrustedPublicCertFile = args.OpenSslTrustedPublicCertFile.name - - if args.DumpInfo: - if args.OutputFile is not None: - parser.error ('the following option is not supported for dumpinfo operations: --output') - # # Read binary input file # - try: - if args.Verbose: - print ('Read binary input file {File}'.format (File = args.InputFile.name)) - Buffer = args.InputFile.read () - args.InputFile.close () - except: - print ('GenerateCapsule: error: can not read binary input file {File}'.format (File = args.InputFile.name)) - sys.exit (1) + Buffer = '' + if args.InputFile: + if os.path.getsize (args.InputFile.name) == 0: + print ('GenerateCapsule: error: InputFile {File} is empty'.format (File = args.InputFile.name)) + sys.exit (1) + try: + if args.Verbose: + print ('Read binary input file {File}'.format (File = args.InputFile.name)) + Buffer = args.InputFile.read () + args.InputFile.close () + except: + print ('GenerateCapsule: error: can not read binary input file {File}'.format (File = args.InputFile.name)) + sys.exit (1) # # Create objects @@ -368,182 +982,27 @@ if __name__ == '__main__': FmpAuthHeader = FmpAuthHeaderClass () FmpPayloadHeader = FmpPayloadHeaderClass () - if args.Encode: - Result = Buffer - if UseSignTool or UseOpenSsl: - try: - FmpPayloadHeader.FwVersion = args.FwVersion - FmpPayloadHeader.LowestSupportedVersion = args.LowestSupportedVersion - FmpPayloadHeader.Payload = Result - Result = FmpPayloadHeader.Encode () - if args.Verbose: - FmpPayloadHeader.DumpInfo () - except: - print ('GenerateCapsule: error: can not encode FMP Payload Header') - sys.exit (1) - - # - # Sign image with 64-bit MonotonicCount appended to end of image - # - try: - if UseSignTool: - CertData = SignPayloadSignTool ( - Result + struct.pack ('<Q', args.MonotonicCount), - args.SigningToolPath, - args.SignToolPfxFile - ) - else: - CertData = SignPayloadOpenSsl ( - Result + struct.pack ('<Q', args.MonotonicCount), - args.SigningToolPath, - args.OpenSslSignerPrivateCertFile, - args.OpenSslOtherPublicCertFile, - args.OpenSslTrustedPublicCertFile - ) - except: - print ('GenerateCapsule: error: can not sign payload') - sys.exit (1) - - try: - FmpAuthHeader.MonotonicCount = args.MonotonicCount - FmpAuthHeader.CertData = CertData - FmpAuthHeader.Payload = Result - Result = FmpAuthHeader.Encode () - if args.Verbose: - FmpAuthHeader.DumpInfo () - except: - print ('GenerateCapsule: error: can not encode FMP Auth Header') - sys.exit (1) - - try: - FmpCapsuleHeader.AddPayload (args.Guid, Result, HardwareInstance = args.HardwareInstance) - Result = FmpCapsuleHeader.Encode () - if args.Verbose: - FmpCapsuleHeader.DumpInfo () - except: - print ('GenerateCapsule: error: can not encode FMP Capsule Header') - sys.exit (1) - - try: - UefiCapsuleHeader.OemFlags = args.CapsuleOemFlag - UefiCapsuleHeader.PersistAcrossReset = 'PersistAcrossReset' in args.CapsuleFlag - UefiCapsuleHeader.PopulateSystemTable = False - UefiCapsuleHeader.InitiateReset = 'InitiateReset' in args.CapsuleFlag - UefiCapsuleHeader.Payload = Result - Result = UefiCapsuleHeader.Encode () - if args.Verbose: - UefiCapsuleHeader.DumpInfo () - except: - print ('GenerateCapsule: error: can not encode UEFI Capsule Header') - sys.exit (1) - - elif args.Decode: - try: - Result = UefiCapsuleHeader.Decode (Buffer) - FmpCapsuleHeader.Decode (Result) - Result = FmpCapsuleHeader.GetFmpCapsuleImageHeader (0).Payload - if args.Verbose: - print ('========') - UefiCapsuleHeader.DumpInfo () - print ('--------') - FmpCapsuleHeader.DumpInfo () - if UseSignTool or UseOpenSsl: - Result = FmpAuthHeader.Decode (Result) - if args.Verbose: - print ('--------') - FmpAuthHeader.DumpInfo () + EmbeddedDriverDescriptorList = [] + PayloadDescriptorList = [] + PayloadJsonDescriptorList = [] - # - # Verify Image with 64-bit MonotonicCount appended to end of image - # - try: - if UseSignTool: - CertData = VerifyPayloadSignTool ( - FmpAuthHeader.Payload + struct.pack ('<Q', FmpAuthHeader.MonotonicCount), - FmpAuthHeader.CertData, - args.SigningToolPath, - args.SignToolPfxFile - ) - else: - CertData = VerifyPayloadOpenSsl ( - FmpAuthHeader.Payload + struct.pack ('<Q', FmpAuthHeader.MonotonicCount), - FmpAuthHeader.CertData, - args.SigningToolPath, - args.OpenSslSignerPrivateCertFile, - args.OpenSslOtherPublicCertFile, - args.OpenSslTrustedPublicCertFile - ) - except ValueError: - print ('GenerateCapsule: warning: can not verify payload.') - - try: - Result = FmpPayloadHeader.Decode (Result) - if args.Verbose: - print ('--------') - FmpPayloadHeader.DumpInfo () - print ('========') - except: - if args.Verbose: - print ('--------') - print ('No FMP_PAYLOAD_HEADER') - print ('========') - raise - else: - if args.Verbose: - print ('--------') - print ('No EFI_FIRMWARE_IMAGE_AUTHENTICATION') - print ('--------') - print ('No FMP_PAYLOAD_HEADER') - print ('========') - except: - print ('GenerateCapsule: error: can not decode capsule') - sys.exit (1) + # + #Encode Operation + # + if args.Encode: + Encode (PayloadDescriptorList, EmbeddedDriverDescriptorList, Buffer) - elif args.DumpInfo: - try: - Result = UefiCapsuleHeader.Decode (Buffer) - FmpCapsuleHeader.Decode (Result) - Result = FmpCapsuleHeader.GetFmpCapsuleImageHeader (0).Payload - print ('========') - UefiCapsuleHeader.DumpInfo () - print ('--------') - FmpCapsuleHeader.DumpInfo () - try: - Result = FmpAuthHeader.Decode (Result) - print ('--------') - FmpAuthHeader.DumpInfo () - try: - Result = FmpPayloadHeader.Decode (Result) - print ('--------') - FmpPayloadHeader.DumpInfo () - except: - print ('--------') - print ('No FMP_PAYLOAD_HEADER') - except: - print ('--------') - print ('No EFI_FIRMWARE_IMAGE_AUTHENTICATION') - print ('--------') - print ('No FMP_PAYLOAD_HEADER') - print ('========') - except: - print ('GenerateCapsule: error: can not decode capsule') - sys.exit (1) - else: - print('GenerateCapsule: error: invalid options') - sys.exit (1) + # + #Decode Operation + # + if args.Decode: + Decode (PayloadDescriptorList, PayloadJsonDescriptorList, Buffer) # - # Write binary output file + #Dump Info Operation # - if args.OutputFile is not None: - try: - if args.Verbose: - print ('Write binary output file {File}'.format (File = args.OutputFile.name)) - args.OutputFile.write (Result) - args.OutputFile.close () - except: - print ('GenerateCapsule: error: can not write binary output file {File}'.format (File = args.OutputFile.name)) - sys.exit (1) + if args.DumpInfo: + DumpInfo (Buffer, args) if args.Verbose: print('Success') diff --git a/BaseTools/Source/Python/Common/Uefi/Capsule/FmpAuthHeader.py b/BaseTools/Source/Python/Common/Uefi/Capsule/FmpAuthHeader.py index 4b8c6da26a..48c605faa8 100644 --- a/BaseTools/Source/Python/Common/Uefi/Capsule/FmpAuthHeader.py +++ b/BaseTools/Source/Python/Common/Uefi/Capsule/FmpAuthHeader.py @@ -2,7 +2,7 @@ # Module that encodes and decodes a EFI_FIRMWARE_IMAGE_AUTHENTICATION with # certificate data and payload data. # -# Copyright (c) 2018, Intel Corporation. All rights reserved.<BR> +# Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<BR> # SPDX-License-Identifier: BSD-2-Clause-Patent # @@ -166,6 +166,18 @@ class FmpAuthHeaderClass (object): self._Valid = True return self.Payload + def IsSigned (self, Buffer): + if len (Buffer) < self._StructSize: + return False + (MonotonicCount, dwLength, wRevision, wCertificateType, CertType) = \ + struct.unpack ( + self._StructFormat, + Buffer[0:self._StructSize] + ) + if CertType != self._EFI_CERT_TYPE_PKCS7_GUID.bytes_le: + return False + return True + def DumpInfo (self): if not self._Valid: raise ValueError diff --git a/BaseTools/Source/Python/Common/Uefi/Capsule/FmpCapsuleHeader.py b/BaseTools/Source/Python/Common/Uefi/Capsule/FmpCapsuleHeader.py index c24258d047..91d24919c4 100644 --- a/BaseTools/Source/Python/Common/Uefi/Capsule/FmpCapsuleHeader.py +++ b/BaseTools/Source/Python/Common/Uefi/Capsule/FmpCapsuleHeader.py @@ -2,7 +2,7 @@ # Module that encodes and decodes a EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER with # a payload. # -# Copyright (c) 2018, Intel Corporation. All rights reserved.<BR> +# Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<BR> # SPDX-License-Identifier: BSD-2-Clause-Patent # @@ -172,8 +172,8 @@ class FmpCapsuleHeaderClass (object): raise ValueError return self._EmbeddedDriverList[Index] - def AddPayload (self, UpdateImageTypeId, Payload = b'', VendorCodeBytes = b'', HardwareInstance = 0): - self._PayloadList.append ((UpdateImageTypeId, Payload, VendorCodeBytes, HardwareInstance)) + def AddPayload (self, UpdateImageTypeId, Payload = b'', VendorCodeBytes = b'', HardwareInstance = 0, UpdateImageIndex = 1): + self._PayloadList.append ((UpdateImageTypeId, Payload, VendorCodeBytes, HardwareInstance, UpdateImageIndex)) def GetFmpCapsuleImageHeader (self, Index): if Index >= len (self._FmpCapsuleImageHeaderList): @@ -198,10 +198,10 @@ class FmpCapsuleHeaderClass (object): self._ItemOffsetList.append (Offset) Offset = Offset + len (EmbeddedDriver) Index = 1 - for (UpdateImageTypeId, Payload, VendorCodeBytes, HardwareInstance) in self._PayloadList: + for (UpdateImageTypeId, Payload, VendorCodeBytes, HardwareInstance, UpdateImageIndex) in self._PayloadList: FmpCapsuleImageHeader = FmpCapsuleImageHeaderClass () FmpCapsuleImageHeader.UpdateImageTypeId = UpdateImageTypeId - FmpCapsuleImageHeader.UpdateImageIndex = Index + FmpCapsuleImageHeader.UpdateImageIndex = UpdateImageIndex FmpCapsuleImageHeader.Payload = Payload FmpCapsuleImageHeader.VendorCodeBytes = VendorCodeBytes FmpCapsuleImageHeader.UpdateHardwareInstance = HardwareInstance @@ -288,6 +288,8 @@ class FmpCapsuleHeaderClass (object): raise ValueError print ('EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER.Version = {Version:08X}'.format (Version = self.Version)) print ('EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER.EmbeddedDriverCount = {EmbeddedDriverCount:08X}'.format (EmbeddedDriverCount = self.EmbeddedDriverCount)) + for EmbeddedDriver in self._EmbeddedDriverList: + print (' sizeof (EmbeddedDriver) = {Size:08X}'.format (Size = len (EmbeddedDriver))) print ('EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER.PayloadItemCount = {PayloadItemCount:08X}'.format (PayloadItemCount = self.PayloadItemCount)) print ('EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER.ItemOffsetList = ') for Offset in self._ItemOffsetList: -- 2.20.0.windows.1 ^ permalink raw reply related [flat|nested] 4+ messages in thread
end of thread, other threads:[~2019-06-11 3:06 UTC | newest] Thread overview: 4+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2019-05-27 7:28 [Patch] BaseTools/Capsule: Supports UEFI Capsule with multiple payloads and embedded drivers Eric Jin 2019-05-27 13:58 ` [edk2-devel] " Liming Gao 2019-05-28 2:10 ` Eric Jin 2019-06-11 3:06 ` Bob Feng
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox