* [RFC 0/1] Add Capsule Generation Tools @ 2018-05-29 22:56 Michael D Kinney 2018-05-29 22:56 ` [RFC 1/1] BaseTools/Capsule: " Michael D Kinney 0 siblings, 1 reply; 4+ messages in thread From: Michael D Kinney @ 2018-05-29 22:56 UTC (permalink / raw) To: edk2-devel; +Cc: Sean Brogan, Jiewen Yao, Yonghong Zhu, Liming Gao https://bugzilla.tianocore.org/show_bug.cgi?id=945 Based on content from the following branch https://github.com/Microsoft/MS_UEFI/tree/share/beta/CapsuleTools Command line unit tests for python modules available from following branch: https://github.com/mdkinney/edk2/tree/Bug_945_StandAloneCapsuleTools_V2 https://github.com/mdkinney/edk2/tree/Bug_945_StandAloneCapsuleTools_V2/BaseToolsUnitTest * Convert C tools to Python * Add common python modules to: BaseTools/Source/Python/Common/Uefi/Capsule BaseTools/Source/Python/Common/Edk2/Capsule * Add GenerateCapsule.py to BaseTools/Source/Python/Capsule * Add Windows and Posix wrappers for GenerateCapsule.py usage: GenerateCapsule [-h] [-o OUTPUTFILE] (-e | -d | --dump-info) [--capflag {PersistAcrossReset,PopulateSystemTable,InitiateReset}] [--capoemflag CAPSULEOEMFLAG] [--guid GUID] [--hardware-instance HARDWAREINSTANCE] [--monotonic-count MONOTONICCOUNT] [--version FWVERSION] [--lsv LOWESTSUPPORTEDVERSION] [--pfx-file SIGNTOOLPFXFILE] [--signer-private-cert OPENSSLSIGNERPRIVATECERTFILE] [--other-public-cert OPENSSLOTHERPUBLICCERTFILE] [--trusted-public-cert OPENSSLTRUSTEDPUBLICCERTFILE] [--signing-tool-path SIGNINGTOOLPATH] [-v] [-q] [--debug [0-9]] InputFile Generate a capsule. Copyright (c) 2018, Intel Corporation. All rights reserved. positional arguments: InputFile Input binary payload filename. optional arguments: -h, --help show this help message and exit -o OUTPUTFILE, --output OUTPUTFILE Output filename. -e, --encode Encode file -d, --decode Decode file --dump-info Display FMP Payload Header information --capflag {PersistAcrossReset,PopulateSystemTable,InitiateReset} Capsule flag can be PersistAcrossReset, or PopulateSystemTable or InitiateReset or not set --capoemflag CAPSULEOEMFLAG Capsule OEM Flag is an integer between 0x0000 and 0xffff. --guid GUID The FMP/ESRT GUID in registry format. Required for encode operations. --hardware-instance HARDWAREINSTANCE The 64-bit hardware instance. The default is 0x0000000000000000 --monotonic-count MONOTONICCOUNT 64-bit monotonic count value in header. Default is 0x0000000000000000. --version FWVERSION The 32-bit version of the binary payload (e.g. 0x11223344 or 5678). --lsv LOWESTSUPPORTEDVERSION The 32-bit lowest supported version of the binary payload (e.g. 0x11223344 or 5678). --pfx-file SIGNTOOLPFXFILE signtool PFX certificate filename. --signer-private-cert OPENSSLSIGNERPRIVATECERTFILE OpenSSL signer private certificate filename. --other-public-cert OPENSSLOTHERPUBLICCERTFILE OpenSSL other public certificate filename. --trusted-public-cert OPENSSLTRUSTEDPUBLICCERTFILE OpenSSL trusted public certificate filename. --signing-tool-path SIGNINGTOOLPATH Path to signtool or Open SLL tool. Optional if path to tools are already in PATH. -v, --verbose Increase output messages -q, --quiet Reduce output messages --debug [0-9] Set debug level Cc: Sean Brogan <sean.brogan@microsoft.com> Cc: Jiewen Yao <jiewen.yao@intel.com> Cc: Yonghong Zhu <yonghong.zhu@intel.com> Cc: Liming Gao <liming.gao@intel.com> Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Michael D Kinney <michael.d.kinney@intel.com> Kinney, Michael D (1): BaseTools/Capsule: Add Capsule Generation Tools BaseTools/BinWrappers/PosixLike/GenerateCapsule | 14 + .../BinWrappers/WindowsLike/GenerateCapsule.bat | 1 + BaseTools/Source/Python/Capsule/GenerateCapsule.py | 500 +++++++++++++++++++++ .../Python/Common/Edk2/Capsule/FmpPayloadHeader.py | 91 ++++ .../Source/Python/Common/Edk2/Capsule/__init__.py | 15 + BaseTools/Source/Python/Common/Edk2/__init__.py | 15 + .../Python/Common/Uefi/Capsule/FmpAuthHeader.py | 184 ++++++++ .../Python/Common/Uefi/Capsule/FmpCapsuleHeader.py | 302 +++++++++++++ .../Common/Uefi/Capsule/UefiCapsuleHeader.py | 136 ++++++ .../Source/Python/Common/Uefi/Capsule/__init__.py | 15 + BaseTools/Source/Python/Common/Uefi/__init__.py | 15 + 11 files changed, 1288 insertions(+) create mode 100644 BaseTools/BinWrappers/PosixLike/GenerateCapsule create mode 100644 BaseTools/BinWrappers/WindowsLike/GenerateCapsule.bat create mode 100644 BaseTools/Source/Python/Capsule/GenerateCapsule.py create mode 100644 BaseTools/Source/Python/Common/Edk2/Capsule/FmpPayloadHeader.py create mode 100644 BaseTools/Source/Python/Common/Edk2/Capsule/__init__.py create mode 100644 BaseTools/Source/Python/Common/Edk2/__init__.py create mode 100644 BaseTools/Source/Python/Common/Uefi/Capsule/FmpAuthHeader.py create mode 100644 BaseTools/Source/Python/Common/Uefi/Capsule/FmpCapsuleHeader.py create mode 100644 BaseTools/Source/Python/Common/Uefi/Capsule/UefiCapsuleHeader.py create mode 100644 BaseTools/Source/Python/Common/Uefi/Capsule/__init__.py create mode 100644 BaseTools/Source/Python/Common/Uefi/__init__.py -- 2.14.2.windows.3 ^ permalink raw reply [flat|nested] 4+ messages in thread
* [RFC 1/1] BaseTools/Capsule: Add Capsule Generation Tools 2018-05-29 22:56 [RFC 0/1] Add Capsule Generation Tools Michael D Kinney @ 2018-05-29 22:56 ` Michael D Kinney 2018-05-31 14:25 ` Gao, Liming 0 siblings, 1 reply; 4+ messages in thread From: Michael D Kinney @ 2018-05-29 22:56 UTC (permalink / raw) To: edk2-devel Cc: Kinney, Michael D, Sean Brogan, Jiewen Yao, Yonghong Zhu, Liming Gao From: "Kinney, Michael D" <michael.d.kinney@intel.com> https://bugzilla.tianocore.org/show_bug.cgi?id=945 Based on content from the following branch https://github.com/Microsoft/MS_UEFI/tree/share/beta/CapsuleTools * Convert C tools to Python * Add common python modules to: BaseTools/Source/Python/Common/Uefi/Capsule BaseTools/Source/Python/Common/Edk2/Capsule * Add GenerateCapsule.py to BaseTools/Source/Python/Capsule * Add Windows and Posix wrappers for GenerateCapsule.py usage: GenerateCapsule [-h] [-o OUTPUTFILE] (-e | -d | --dump-info) [--capflag {PersistAcrossReset,PopulateSystemTable,InitiateReset}] [--capoemflag CAPSULEOEMFLAG] [--guid GUID] [--hardware-instance HARDWAREINSTANCE] [--monotonic-count MONOTONICCOUNT] [--version FWVERSION] [--lsv LOWESTSUPPORTEDVERSION] [--pfx-file SIGNTOOLPFXFILE] [--signer-private-cert OPENSSLSIGNERPRIVATECERTFILE] [--other-public-cert OPENSSLOTHERPUBLICCERTFILE] [--trusted-public-cert OPENSSLTRUSTEDPUBLICCERTFILE] [--signing-tool-path SIGNINGTOOLPATH] [-v] [-q] [--debug [0-9]] InputFile Generate a capsule. Copyright (c) 2018, Intel Corporation. All rights reserved. positional arguments: InputFile Input binary payload filename. optional arguments: -h, --help show this help message and exit -o OUTPUTFILE, --output OUTPUTFILE Output filename. -e, --encode Encode file -d, --decode Decode file --dump-info Display FMP Payload Header information --capflag {PersistAcrossReset,PopulateSystemTable,InitiateReset} Capsule flag can be PersistAcrossReset, or PopulateSystemTable or InitiateReset or not set --capoemflag CAPSULEOEMFLAG Capsule OEM Flag is an integer between 0x0000 and 0xffff. --guid GUID The FMP/ESRT GUID in registry format. Required for encode operations. --hardware-instance HARDWAREINSTANCE The 64-bit hardware instance. The default is 0x0000000000000000 --monotonic-count MONOTONICCOUNT 64-bit monotonic count value in header. Default is 0x0000000000000000. --version FWVERSION The 32-bit version of the binary payload (e.g. 0x11223344 or 5678). --lsv LOWESTSUPPORTEDVERSION The 32-bit lowest supported version of the binary payload (e.g. 0x11223344 or 5678). --pfx-file SIGNTOOLPFXFILE signtool PFX certificate filename. --signer-private-cert OPENSSLSIGNERPRIVATECERTFILE OpenSSL signer private certificate filename. --other-public-cert OPENSSLOTHERPUBLICCERTFILE OpenSSL other public certificate filename. --trusted-public-cert OPENSSLTRUSTEDPUBLICCERTFILE OpenSSL trusted public certificate filename. --signing-tool-path SIGNINGTOOLPATH Path to signtool or Open SLL tool. Optional if path to tools are already in PATH. -v, --verbose Increase output messages -q, --quiet Reduce output messages --debug [0-9] Set debug level Cc: Sean Brogan <sean.brogan@microsoft.com> Cc: Jiewen Yao <jiewen.yao@intel.com> Cc: Yonghong Zhu <yonghong.zhu@intel.com> Cc: Liming Gao <liming.gao@intel.com> Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Michael D Kinney <michael.d.kinney@intel.com> --- BaseTools/BinWrappers/PosixLike/GenerateCapsule | 14 + .../BinWrappers/WindowsLike/GenerateCapsule.bat | 1 + BaseTools/Source/Python/Capsule/GenerateCapsule.py | 500 +++++++++++++++++++++ .../Python/Common/Edk2/Capsule/FmpPayloadHeader.py | 91 ++++ .../Source/Python/Common/Edk2/Capsule/__init__.py | 15 + BaseTools/Source/Python/Common/Edk2/__init__.py | 15 + .../Python/Common/Uefi/Capsule/FmpAuthHeader.py | 184 ++++++++ .../Python/Common/Uefi/Capsule/FmpCapsuleHeader.py | 302 +++++++++++++ .../Common/Uefi/Capsule/UefiCapsuleHeader.py | 136 ++++++ .../Source/Python/Common/Uefi/Capsule/__init__.py | 15 + BaseTools/Source/Python/Common/Uefi/__init__.py | 15 + 11 files changed, 1288 insertions(+) create mode 100644 BaseTools/BinWrappers/PosixLike/GenerateCapsule create mode 100644 BaseTools/BinWrappers/WindowsLike/GenerateCapsule.bat create mode 100644 BaseTools/Source/Python/Capsule/GenerateCapsule.py create mode 100644 BaseTools/Source/Python/Common/Edk2/Capsule/FmpPayloadHeader.py create mode 100644 BaseTools/Source/Python/Common/Edk2/Capsule/__init__.py create mode 100644 BaseTools/Source/Python/Common/Edk2/__init__.py create mode 100644 BaseTools/Source/Python/Common/Uefi/Capsule/FmpAuthHeader.py create mode 100644 BaseTools/Source/Python/Common/Uefi/Capsule/FmpCapsuleHeader.py create mode 100644 BaseTools/Source/Python/Common/Uefi/Capsule/UefiCapsuleHeader.py create mode 100644 BaseTools/Source/Python/Common/Uefi/Capsule/__init__.py create mode 100644 BaseTools/Source/Python/Common/Uefi/__init__.py diff --git a/BaseTools/BinWrappers/PosixLike/GenerateCapsule b/BaseTools/BinWrappers/PosixLike/GenerateCapsule new file mode 100644 index 0000000000..59a6c8ba43 --- /dev/null +++ b/BaseTools/BinWrappers/PosixLike/GenerateCapsule @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +#python `dirname $0`/RunToolFromSource.py `basename $0` $* + +# If a python2 command is available, use it in preference to python +if command -v python2 >/dev/null 2>&1; then + python_exe=python2 +fi + +full_cmd=${BASH_SOURCE:-$0} # see http://mywiki.wooledge.org/BashFAQ/028 for a discussion of why $0 is not a good choice here +dir=$(dirname "$full_cmd") +cmd=${full_cmd##*/} + +export PYTHONPATH="$dir/../../Source/Python${PYTHONPATH:+:"$PYTHONPATH"}" +exec "${python_exe:-python}" "$dir/../../Source/Python/Capsule/$cmd.py" "$@" diff --git a/BaseTools/BinWrappers/WindowsLike/GenerateCapsule.bat b/BaseTools/BinWrappers/WindowsLike/GenerateCapsule.bat new file mode 100644 index 0000000000..ca442d181b --- /dev/null +++ b/BaseTools/BinWrappers/WindowsLike/GenerateCapsule.bat @@ -0,0 +1 @@ +@%PYTHON_HOME%\python.exe %BASE_TOOLS_PATH%\Source\Python\Capsule\GenerateCapsule.py %* diff --git a/BaseTools/Source/Python/Capsule/GenerateCapsule.py b/BaseTools/Source/Python/Capsule/GenerateCapsule.py new file mode 100644 index 0000000000..32ab95c3e0 --- /dev/null +++ b/BaseTools/Source/Python/Capsule/GenerateCapsule.py @@ -0,0 +1,500 @@ +## @file +# Generate a capsule. +# +# Copyright (c) 2018, Intel Corporation. All rights reserved.<BR> +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# + +''' +GenerateCapsule +''' + +import sys +import argparse +import uuid +import struct +import subprocess +import os +import tempfile +import shutil +from Common.Uefi.Capsule.UefiCapsuleHeader import UefiCapsuleHeaderClass +from Common.Uefi.Capsule.FmpCapsuleHeader import FmpCapsuleHeaderClass +from Common.Uefi.Capsule.FmpAuthHeader import FmpAuthHeaderClass +from Common.Edk2.Capsule.FmpPayloadHeader import FmpPayloadHeaderClass + +# +# Globals for help information +# +__prog__ = 'GenerateCapsule' +__copyright__ = 'Copyright (c) 2018, Intel Corporation. All rights reserved.' +__description__ = 'Generate a capsule.\n' + +def SignPayloadSignTool (Payload, ToolPath, PfxFile): + # + # Create a temporary directory + # + TempDirectoryName = tempfile.mkdtemp() + + # + # Generate temp file name for the payload contents + # + TempFileName = os.path.join (TempDirectoryName, 'Payload.bin') + + # + # Create temporary payload file for signing + # + try: + File = open (TempFileName, mode='wb') + File.write (Payload) + File.close () + except: + shutil.rmtree (TempDirectoryName) + raise ValueError ('GenerateCapsule: error: can not write temporary payload file.') + + # + # Build signtool command + # + if ToolPath is None: + ToolPath = '' + Command = '' + Command = Command + '"{Path}" '.format (Path = os.path.join (ToolPath, 'signtool.exe')) + Command = Command + 'sign /fd sha256 /p7ce DetachedSignedData /p7co 1.2.840.113549.1.7.2 ' + Command = Command + '/p7 {TempDir} '.format (TempDir = TempDirectoryName) + Command = Command + '/f {PfxFile} '.format (PfxFile = PfxFile) + Command = Command + TempFileName + + # + # Sign the input file using the specified private key + # + try: + Process = subprocess.Popen (Command, stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE, shell = True) + Result = Process.communicate('') + except: + shutil.rmtree (TempDirectoryName) + raise ValueError ('GenerateCapsule: error: can not run signtool.') + + if Process.returncode != 0: + shutil.rmtree (TempDirectoryName) + print (Result[1].decode()) + raise ValueError ('GenerateCapsule: error: signtool failed.') + + # + # Read the signature from the generated output file + # + try: + File = open (TempFileName + '.p7', mode='rb') + Signature = File.read () + File.close () + except: + shutil.rmtree (TempDirectoryName) + raise ValueError ('GenerateCapsule: error: can not read signature file.') + + shutil.rmtree (TempDirectoryName) + return Signature + +def VerifyPayloadSignTool (Payload, CertData, ToolPath, PfxFile): + print ('signtool verify is not supported.') + raise ValueError ('GenerateCapsule: error: signtool verify is not supported.') + +def SignPayloadOpenSsl (Payload, ToolPath, SignerPrivateCertFile, OtherPublicCertFile, TrustedPublicCertFile): + # + # Build openssl command + # + if ToolPath is None: + ToolPath = '' + Command = '' + 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) + + # + # Sign the input file using the specified private key and capture signature from STDOUT + # + try: + Process = subprocess.Popen (Command, stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE, shell = True) + Result = Process.communicate(input = Payload) + Signature = Result[0] + except: + raise ValueError ('GenerateCapsule: error: can not run openssl.') + + if Process.returncode != 0: + print (Result[1].decode()) + raise ValueError ('GenerateCapsule: error: openssl failed.') + + return Signature + +def VerifyPayloadOpenSsl (Payload, CertData, ToolPath, SignerPrivateCertFile, OtherPublicCertFile, TrustedPublicCertFile): + # + # Create a temporary directory + # + TempDirectoryName = tempfile.mkdtemp() + + # + # Generate temp file name for the payload contents + # + TempFileName = os.path.join (TempDirectoryName, 'Payload.bin') + + # + # Create temporary payload file for verification + # + try: + File = open (TempFileName, mode='wb') + File.write (Payload) + File.close () + except: + shutil.rmtree (TempDirectoryName) + raise ValueError ('GenerateCapsule: error: can not write temporary payload file.') + + # + # Build openssl command + # + if ToolPath is None: + ToolPath = '' + Command = '' + 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) + + # + # Verify signature + # + try: + Process = subprocess.Popen (Command, stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE, shell = True) + Result = Process.communicate(input = CertData) + except: + shutil.rmtree (TempDirectoryName) + raise ValueError ('GenerateCapsule: error: can not run openssl.') + + if Process.returncode != 0: + shutil.rmtree (TempDirectoryName) + print (Result[1].decode()) + raise ValueError ('GenerateCapsule: error: openssl failed.') + + shutil.rmtree (TempDirectoryName) + return Payload + +if __name__ == '__main__': + def convert_arg_line_to_args(arg_line): + for arg in arg_line.split(): + if not arg.strip(): + continue + yield arg + + def ValidateUnsignedInteger (Argument): + try: + Value = int (Argument, 0) + except: + Message = '{Argument} is not a valid integer value.'.format (Argument = Argument) + raise argparse.ArgumentTypeError (Message) + if Value < 0: + Message = '{Argument} is a negative value.'.format (Argument = Argument) + raise argparse.ArgumentTypeError (Message) + return Value + + def ValidateRegistryFormatGuid (Argument): + try: + Value = uuid.UUID (Argument) + except: + Message = '{Argument} is not a valid registry format GUID value.'.format (Argument = Argument) + raise argparse.ArgumentTypeError (Message) + return Value + + # + # Create command line argument parser object + # + parser = argparse.ArgumentParser ( + prog = __prog__, + description = __description__ + __copyright__, + conflict_handler = 'resolve', + fromfile_prefix_chars = '@' + ) + parser.convert_arg_line_to_args = convert_arg_line_to_args + + # + # Add input and output file arguments + # + parser.add_argument("InputFile", type = argparse.FileType('rb'), + help = "Input binary payload filename.") + parser.add_argument("-o", "--output", dest = 'OutputFile', type = argparse.FileType('wb'), + help = "Output filename.") + # + # Add group for -e and -d flags that are mutually exclusive and required + # + group = parser.add_mutually_exclusive_group (required = True) + group.add_argument ("-e", "--encode", dest = 'Encode', action = "store_true", + help = "Encode file") + group.add_argument ("-d", "--decode", dest = 'Decode', action = "store_true", + help = "Decode file") + group.add_argument ("--dump-info", dest = 'DumpInfo', action = "store_true", + help = "Display FMP Payload Header information") + # + # Add optional arguments for this command + # + parser.add_argument ("--capflag", dest = 'CapsuleFlag', action='append', default = [], + choices=['PersistAcrossReset', 'PopulateSystemTable', 'InitiateReset'], + help = "Capsule flag can be PersistAcrossReset, or PopulateSystemTable or InitiateReset or not set") + parser.add_argument ("--capoemflag", dest = 'CapsuleOemFlag', type = ValidateUnsignedInteger, default = 0x0000, + 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.") + parser.add_argument ("--hardware-instance", dest = 'HardwareInstance', type = ValidateUnsignedInteger, default = 0x0000000000000000, + help = "The 64-bit hardware instance. The default is 0x0000000000000000") + + + parser.add_argument ("--monotonic-count", dest = 'MonotonicCount', type = ValidateUnsignedInteger, default = 0x0000000000000000, + help = "64-bit monotonic count value in header. Default is 0x0000000000000000.") + + parser.add_argument ("--version", dest = 'FwVersion', type = ValidateUnsignedInteger, + help = "The 32-bit version of the binary payload (e.g. 0x11223344 or 5678).") + parser.add_argument ("--lsv", dest = 'LowestSupportedVersion', type = ValidateUnsignedInteger, + help = "The 32-bit lowest supported version of the binary payload (e.g. 0x11223344 or 5678).") + + parser.add_argument ("--pfx-file", dest='SignToolPfxFile', type=argparse.FileType('rb'), + help="signtool PFX certificate filename.") + + parser.add_argument ("--signer-private-cert", dest='OpenSslSignerPrivateCertFile', type=argparse.FileType('rb'), + help="OpenSSL signer private certificate filename.") + parser.add_argument ("--other-public-cert", dest='OpenSslOtherPublicCertFile', type=argparse.FileType('rb'), + help="OpenSSL other public certificate filename.") + parser.add_argument ("--trusted-public-cert", dest='OpenSslTrustedPublicCertFile', type=argparse.FileType('rb'), + help="OpenSSL trusted public certificate filename.") + + parser.add_argument ("--signing-tool-path", dest = 'SigningToolPath', + help = "Path to signtool or Open SLL tool. Optional if path to tools are already in PATH.") + + # + # Add optional arguments common to all commands + # + parser.add_argument("-v", "--verbose", dest = 'Verbose', action = "store_true", + help = "Increase output messages") + parser.add_argument("-q", "--quiet", dest = 'Quiet', action = "store_true", + help = "Reduce output messages") + parser.add_argument("--debug", dest = 'Debug', type = int, metavar = '[0-9]', choices = range(0,10), default = 0, + help = "Set debug level") + + # + # Parse command line arguments + # + args = parser.parse_args() + + # + # Perform additional argument verification + # + if not args.DumpInfo and args.OutputFile is None: + parser.error ('the following arguments are required for all commands except --dump-info: --output') + + if args.Encode and (args.Guid is None or args.FwVersion is None or args.LowestSupportedVersion is None): + parser.error ('the following arguments are required: --version, --lsv, --guid') + + if not args.DumpInfo and not args.OutputFile: + parser.error ('the following arguments are required: --output') + + if not args.DumpInfo: + if args.SignToolPfxFile is None and args.OpenSslSignerPrivateCertFile is None and args.OpenSslOtherPublicCertFile is None and args.OpenSslTrustedPublicCertFile is None: + parser.error ('certificate file arguments are required: --pfx-file | [--signer-private-cert --other-public-cert --trusted-public-cert]') + + if args.SignToolPfxFile is not None: + if args.OpenSslSignerPrivateCertFile is not None: + parser.error ('Providing both signtool and OpenSSL options is not supported') + if args.OpenSslOtherPublicCertFile is not None: + parser.error ('Providing both signtool and OpenSSL options is not supported') + if args.OpenSslTrustedPublicCertFile is not None: + parser.error ('Providing both signtool and OpenSSL options is not supported') + args.SignToolPfxFile.close() + args.SignToolPfxFile = args.SignToolPfxFile.name + + if not args.DumpInfo: + if args.SignToolPfxFile is None: + if args.OpenSslSignerPrivateCertFile is None: + parser.error ('the following arguments are required: --signer-private-cert') + if args.OpenSslOtherPublicCertFile is None: + parser.error ('the following arguments are required: --other-public-cert') + if args.OpenSslTrustedPublicCertFile is None: + parser.error ('the following arguments are required: --trusted-public-cert') + args.OpenSslSignerPrivateCertFile.close() + args.OpenSslOtherPublicCertFile.close() + args.OpenSslTrustedPublicCertFile.close() + args.OpenSslSignerPrivateCertFile = args.OpenSslSignerPrivateCertFile.name + args.OpenSslOtherPublicCertFile = args.OpenSslOtherPublicCertFile.name + args.OpenSslTrustedPublicCertFile = args.OpenSslTrustedPublicCertFile.name + + # + # 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) + + # + # Create objects + # + UefiCapsuleHeader = UefiCapsuleHeaderClass () + FmpCapsuleHeader = FmpCapsuleHeaderClass () + FmpAuthHeader = FmpAuthHeaderClass () + FmpPayloadHeader = FmpPayloadHeaderClass () + + if args.Encode: + try: + FmpPayloadHeader.FwVersion = args.FwVersion + FmpPayloadHeader.LowestSupportedVersion = args.LowestSupportedVersion + FmpPayloadHeader.Payload = Buffer + 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 args.SignToolPfxFile is not None: + 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') + raise + 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 = 'PopulateSystemTable' in args.CapsuleFlag + 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 + Result = FmpAuthHeader.Decode (Result) + + # + # Verify Image with 64-bit MonotonicCount appended to end of image + # + try: + if args.SignToolPfxFile is not None: + 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.') + + Result = FmpPayloadHeader.Decode (Result) + if args.Verbose: + print ('========') + UefiCapsuleHeader.DumpInfo () + print ('--------') + FmpCapsuleHeader.DumpInfo () + print ('--------') + FmpAuthHeader.DumpInfo () + print ('--------') + FmpPayloadHeader.DumpInfo () + print ('========') + except: + print ('GenerateCapsule: error: can not decode capsule') + raise + sys.exit (1) + + elif args.DumpInfo: + try: + Result = UefiCapsuleHeader.Decode (Buffer) + FmpCapsuleHeader.Decode (Result) + Result = FmpCapsuleHeader.GetFmpCapsuleImageHeader (0).Payload + Result = FmpAuthHeader.Decode (Result) + Result = FmpPayloadHeader.Decode (Result) + + print ('========') + UefiCapsuleHeader.DumpInfo () + print ('--------') + FmpCapsuleHeader.DumpInfo () + print ('--------') + FmpAuthHeader.DumpInfo () + print ('--------') + FmpPayloadHeader.DumpInfo () + print ('========') + except: + print ('GenerateCapsule: error: can not decode capsule') + sys.exit (1) + else: + print('GenerateCapsule: error: invalid options') + sys.exit (1) + + # + # Write binary output file + # + 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.Verbose: + print('Success') diff --git a/BaseTools/Source/Python/Common/Edk2/Capsule/FmpPayloadHeader.py b/BaseTools/Source/Python/Common/Edk2/Capsule/FmpPayloadHeader.py new file mode 100644 index 0000000000..0ed51752d3 --- /dev/null +++ b/BaseTools/Source/Python/Common/Edk2/Capsule/FmpPayloadHeader.py @@ -0,0 +1,91 @@ +## @file +# Module that encodes and decodes a FMP_PAYLOAD_HEADER with a payload. +# The FMP_PAYLOAD_HEADER is processed by the FmpPayloadHeaderLib in the +# FmpDevicePkg. +# +# Copyright (c) 2018, Intel Corporation. All rights reserved.<BR> +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# + +''' +FmpPayloadHeader +''' + +import struct + +def _SIGNATURE_32 (A, B, C, D): + return struct.unpack ('=I',bytearray (A + B + C + D, 'ascii'))[0] + +def _SIGNATURE_32_TO_STRING (Signature): + return struct.pack ("<I", Signature).decode () + +class FmpPayloadHeaderClass (object): + # + # typedef struct { + # UINT32 Signature; + # UINT32 HeaderSize; + # UINT32 FwVersion; + # UINT32 LowestSupportedVersion; + # } FMP_PAYLOAD_HEADER; + # + # #define FMP_PAYLOAD_HEADER_SIGNATURE SIGNATURE_32 ('M', 'S', 'S', '1') + # + _StructFormat = '<IIII' + _StructSize = struct.calcsize (_StructFormat) + + _FMP_PAYLOAD_HEADER_SIGNATURE = _SIGNATURE_32 ('M', 'S', 'S', '1') + + def __init__ (self): + self._Valid = False + self.Signature = self._FMP_PAYLOAD_HEADER_SIGNATURE + self.HeaderSize = self._StructSize + self.FwVersion = 0x00000000 + self.LowestSupportedVersion = 0x00000000 + self.Payload = b'' + + def Encode (self): + FmpPayloadHeader = struct.pack ( + self._StructFormat, + self.Signature, + self.HeaderSize, + self.FwVersion, + self.LowestSupportedVersion + ) + self._Valid = True + return FmpPayloadHeader + self.Payload + + def Decode (self, Buffer): + if len (Buffer) < self._StructSize: + raise ValueError + (Signature, HeaderSize, FwVersion, LowestSupportedVersion) = \ + struct.unpack ( + self._StructFormat, + Buffer[0:self._StructSize] + ) + if Signature != self._FMP_PAYLOAD_HEADER_SIGNATURE: + raise ValueError + if HeaderSize < self._StructSize: + raise ValueError + self.Signature = Signature + self.HeaderSize = HeaderSize + self.FwVersion = FwVersion + self.LowestSupportedVersion = LowestSupportedVersion + self.Payload = Buffer[self.HeaderSize:] + + self._Valid = True + return self.Payload + + def DumpInfo (self): + if not self._Valid: + raise ValueError + print ('FMP_PAYLOAD_HEADER.Signature = {Signature:08X} ({SignatureString})'.format (Signature = self.Signature, SignatureString = _SIGNATURE_32_TO_STRING (self.Signature))) + print ('FMP_PAYLOAD_HEADER.HeaderSize = {HeaderSize:08X}'.format (HeaderSize = self.HeaderSize)) + print ('FMP_PAYLOAD_HEADER.FwVersion = {FwVersion:08X}'.format (FwVersion = self.FwVersion)) + print ('FMP_PAYLOAD_HEADER.LowestSupportedVersion = {LowestSupportedVersion:08X}'.format (LowestSupportedVersion = self.LowestSupportedVersion)) + print ('sizeof (Payload) = {Size:08X}'.format (Size = len (self.Payload))) diff --git a/BaseTools/Source/Python/Common/Edk2/Capsule/__init__.py b/BaseTools/Source/Python/Common/Edk2/Capsule/__init__.py new file mode 100644 index 0000000000..71c6f06838 --- /dev/null +++ b/BaseTools/Source/Python/Common/Edk2/Capsule/__init__.py @@ -0,0 +1,15 @@ +## @file +# Python 'Common.Edk2.Capsule' package initialization file. +# +# This file is required to make Python interpreter treat the directory +# as containing package. +# +# Copyright (c) 2018, Intel Corporation. All rights reserved.<BR> +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# diff --git a/BaseTools/Source/Python/Common/Edk2/__init__.py b/BaseTools/Source/Python/Common/Edk2/__init__.py new file mode 100644 index 0000000000..97d925cbf8 --- /dev/null +++ b/BaseTools/Source/Python/Common/Edk2/__init__.py @@ -0,0 +1,15 @@ +## @file +# Python 'Common.Edk2' package initialization file. +# +# This file is required to make Python interpreter treat the directory +# as containing package. +# +# Copyright (c) 2018, Intel Corporation. All rights reserved.<BR> +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# diff --git a/BaseTools/Source/Python/Common/Uefi/Capsule/FmpAuthHeader.py b/BaseTools/Source/Python/Common/Uefi/Capsule/FmpAuthHeader.py new file mode 100644 index 0000000000..aec52bf772 --- /dev/null +++ b/BaseTools/Source/Python/Common/Uefi/Capsule/FmpAuthHeader.py @@ -0,0 +1,184 @@ +## @file +# 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> +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# + +''' +FmpAuthHeader +''' + +import struct +import uuid + +class FmpAuthHeaderClass (object): + # /// + # /// Image Attribute -Authentication Required + # /// + # typedef struct { + # /// + # /// It is included in the signature of AuthInfo. It is used to ensure freshness/no replay. + # /// It is incremented during each firmware image operation. + # /// + # UINT64 MonotonicCount; + # /// + # /// Provides the authorization for the firmware image operations. It is a signature across + # /// the image data and the Monotonic Count value. Caller uses the private key that is + # /// associated with a public key that has been provisioned via the key exchange. + # /// Because this is defined as a signature, WIN_CERTIFICATE_UEFI_GUID.CertType must + # /// be EFI_CERT_TYPE_PKCS7_GUID. + # /// + # WIN_CERTIFICATE_UEFI_GUID AuthInfo; + # } EFI_FIRMWARE_IMAGE_AUTHENTICATION; + # + # /// + # /// Certificate which encapsulates a GUID-specific digital signature + # /// + # typedef struct { + # /// + # /// This is the standard WIN_CERTIFICATE header, where + # /// wCertificateType is set to WIN_CERT_TYPE_EFI_GUID. + # /// + # WIN_CERTIFICATE Hdr; + # /// + # /// This is the unique id which determines the + # /// format of the CertData. . + # /// + # EFI_GUID CertType; + # /// + # /// The following is the certificate data. The format of + # /// the data is determined by the CertType. + # /// If CertType is EFI_CERT_TYPE_RSA2048_SHA256_GUID, + # /// the CertData will be EFI_CERT_BLOCK_RSA_2048_SHA256 structure. + # /// + # UINT8 CertData[1]; + # } WIN_CERTIFICATE_UEFI_GUID; + # + # /// + # /// The WIN_CERTIFICATE structure is part of the PE/COFF specification. + # /// + # typedef struct { + # /// + # /// The length of the entire certificate, + # /// including the length of the header, in bytes. + # /// + # UINT32 dwLength; + # /// + # /// The revision level of the WIN_CERTIFICATE + # /// structure. The current revision level is 0x0200. + # /// + # UINT16 wRevision; + # /// + # /// The certificate type. See WIN_CERT_TYPE_xxx for the UEFI + # /// certificate types. The UEFI specification reserves the range of + # /// certificate type values from 0x0EF0 to 0x0EFF. + # /// + # UINT16 wCertificateType; + # /// + # /// The following is the actual certificate. The format of + # /// the certificate depends on wCertificateType. + # /// + # /// UINT8 bCertificate[ANYSIZE_ARRAY]; + # /// + # } WIN_CERTIFICATE; + # + # #define WIN_CERT_TYPE_EFI_GUID 0x0EF1 + # + # /// + # /// This identifies a signature containing a DER-encoded PKCS #7 version 1.5 [RFC2315] + # /// SignedData value. + # /// + # #define EFI_CERT_TYPE_PKCS7_GUID \ + # { \ + # 0x4aafd29d, 0x68df, 0x49ee, {0x8a, 0xa9, 0x34, 0x7d, 0x37, 0x56, 0x65, 0xa7} \ + # } + + _StructFormat = '<QIHH16s' + _StructSize = struct.calcsize (_StructFormat) + + _MonotonicCountFormat = '<Q' + _MonotonicCountSize = struct.calcsize (_MonotonicCountFormat) + + _StructAuthInfoFormat = '<IHH16s' + _StructAuthInfoSize = struct.calcsize (_StructAuthInfoFormat) + + _WIN_CERT_REVISION = 0x0200 + _WIN_CERT_TYPE_EFI_GUID = 0x0EF1 + _EFI_CERT_TYPE_PKCS7_GUID = uuid.UUID ('4aafd29d-68df-49ee-8aa9-347d375665a7') + + def __init__ (self): + self._Valid = False + self.MonotonicCount = 0 + self.dwLength = self._StructAuthInfoSize + self.wRevision = self._WIN_CERT_REVISION + self.wCertificateType = self._WIN_CERT_TYPE_EFI_GUID + self.CertType = self._EFI_CERT_TYPE_PKCS7_GUID + self.CertData = b'' + self.Payload = b'' + + + def Encode (self): + if self.wRevision != self._WIN_CERT_REVISION: + raise ValueError + if self.wCertificateType != self._WIN_CERT_TYPE_EFI_GUID: + raise ValueError + if self.CertType != self._EFI_CERT_TYPE_PKCS7_GUID: + raise ValueError + self.dwLength = self._StructAuthInfoSize + len (self.CertData) + + FmpAuthHeader = struct.pack ( + self._StructFormat, + self.MonotonicCount, + self.dwLength, + self.wRevision, + self.wCertificateType, + self.CertType.bytes_le + ) + self._Valid = True + + return FmpAuthHeader + self.CertData + self.Payload + + def Decode (self, Buffer): + if len (Buffer) < self._StructSize: + raise ValueError + (MonotonicCount, dwLength, wRevision, wCertificateType, CertType) = \ + struct.unpack ( + self._StructFormat, + Buffer[0:self._StructSize] + ) + if dwLength < self._StructAuthInfoSize: + raise ValueError + if wRevision != self._WIN_CERT_REVISION: + raise ValueError + if wCertificateType != self._WIN_CERT_TYPE_EFI_GUID: + raise ValueError + if CertType != self._EFI_CERT_TYPE_PKCS7_GUID.bytes_le: + raise ValueError + self.MonotonicCount = MonotonicCount + self.dwLength = dwLength + self.wRevision = wRevision + self.wCertificateType = wCertificateType + self.CertType = uuid.UUID (bytes = CertType) + self.CertData = Buffer[self._StructSize:self._MonotonicCountSize + self.dwLength] + self.Payload = Buffer[self._MonotonicCountSize + self.dwLength:] + self._Valid = True + return self.Payload + + def DumpInfo (self): + if not self._Valid: + raise ValueError + print ('EFI_FIRMWARE_IMAGE_AUTHENTICATION.MonotonicCount = {MonotonicCount:016X}'.format (MonotonicCount = self.MonotonicCount)) + print ('EFI_FIRMWARE_IMAGE_AUTHENTICATION.AuthInfo.Hdr.dwLength = {dwLength:08X}'.format (dwLength = self.dwLength)) + print ('EFI_FIRMWARE_IMAGE_AUTHENTICATION.AuthInfo.Hdr.wRevision = {wRevision:04X}'.format (wRevision = self.wRevision)) + print ('EFI_FIRMWARE_IMAGE_AUTHENTICATION.AuthInfo.Hdr.wCertificateType = {wCertificateType:04X}'.format (wCertificateType = self.wCertificateType)) + print ('EFI_FIRMWARE_IMAGE_AUTHENTICATION.AuthInfo.CertType = {Guid}'.format (Guid = str(self.CertType).upper())) + print ('sizeof (EFI_FIRMWARE_IMAGE_AUTHENTICATION.AuthInfo.CertData) = {Size:08X}'.format (Size = len (self.CertData))) + print ('sizeof (Payload) = {Size:08X}'.format (Size = len (self.Payload))) diff --git a/BaseTools/Source/Python/Common/Uefi/Capsule/FmpCapsuleHeader.py b/BaseTools/Source/Python/Common/Uefi/Capsule/FmpCapsuleHeader.py new file mode 100644 index 0000000000..2461fb5068 --- /dev/null +++ b/BaseTools/Source/Python/Common/Uefi/Capsule/FmpCapsuleHeader.py @@ -0,0 +1,302 @@ +## @file +# Module that encodes and decodes a EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER with +# a payload. +# +# Copyright (c) 2018, Intel Corporation. All rights reserved.<BR> +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# + +''' +FmpCapsuleHeader +''' + +import struct +import uuid + +class FmpCapsuleImageHeaderClass (object): + # typedef struct { + # UINT32 Version; + # + # /// + # /// Used to identify device firmware targeted by this update. This guid is matched by + # /// system firmware against ImageTypeId field within a EFI_FIRMWARE_IMAGE_DESCRIPTOR + # /// + # EFI_GUID UpdateImageTypeId; + # + # /// + # /// Passed as ImageIndex in call to EFI_FIRMWARE_MANAGEMENT_PROTOCOL.SetImage () + # /// + # UINT8 UpdateImageIndex; + # UINT8 reserved_bytes[3]; + # + # /// + # /// Size of the binary update image which immediately follows this structure + # /// + # UINT32 UpdateImageSize; + # + # /// + # /// Size of the VendorCode bytes which optionally immediately follow binary update image in the capsule + # /// + # UINT32 UpdateVendorCodeSize; + # + # /// + # /// The HardwareInstance to target with this update. If value is zero it means match all + # /// HardwareInstances. This field allows update software to target only a single device in + # /// cases where there are more than one device with the same ImageTypeId GUID. + # /// This header is outside the signed data of the Authentication Info structure and + # /// therefore can be modified without changing the Auth data. + # /// + # UINT64 UpdateHardwareInstance; + # } EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER; + # + # #define EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION 0x00000002 + + _StructFormat = '<I16sB3BIIQ' + _StructSize = struct.calcsize (_StructFormat) + + EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION = 0x00000002 + + def __init__ (self): + self._Valid = False + self.Version = self.EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION + self.UpdateImageTypeId = uuid.UUID ('00000000-0000-0000-0000-000000000000') + self.UpdateImageIndex = 0 + self.UpdateImageSize = 0 + self.UpdateVendorCodeSize = 0 + self.UpdateHardwareInstance = 0x0000000000000000 + self.Payload = b'' + self.VendorCodeBytes = b'' + + def Encode (self): + self.UpdateImageSize = len (self.Payload) + self.UpdateVendorCodeSize = len (self.VendorCodeBytes) + FmpCapsuleImageHeader = struct.pack ( + self._StructFormat, + self.Version, + self.UpdateImageTypeId.bytes_le, + self.UpdateImageIndex, + 0,0,0, + self.UpdateImageSize, + self.UpdateVendorCodeSize, + self.UpdateHardwareInstance + ) + self._Valid = True + return FmpCapsuleImageHeader + self.Payload + self.VendorCodeBytes + + def Decode (self, Buffer): + if len (Buffer) < self._StructSize: + raise ValueError + (Version, UpdateImageTypeId, UpdateImageIndex, r0, r1, r2, UpdateImageSize, UpdateVendorCodeSize, UpdateHardwareInstance) = \ + struct.unpack ( + self._StructFormat, + Buffer[0:self._StructSize] + ) + + if Version < self.EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION: + raise ValueError + if UpdateImageIndex < 1: + raise ValueError + if UpdateImageSize + UpdateVendorCodeSize != len (Buffer[self._StructSize:]): + raise ValueError + + self.Version = Version + self.UpdateImageTypeId = uuid.UUID (bytes_le = UpdateImageTypeId) + self.UpdateImageIndex = UpdateImageIndex + self.UpdateImageSize = UpdateImageSize + self.UpdateVendorCodeSize = UpdateVendorCodeSize + self.UpdateHardwareInstance = UpdateHardwareInstance + self.Payload = Buffer[self._StructSize:self._StructSize + UpdateImageSize] + self.VendorCodeBytes = Buffer[self._StructSize + UpdateImageSize:] + self._Valid = True + return Buffer[self._StructSize:] + + def DumpInfo (self): + if not self._Valid: + raise ValueError + print ('EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER.Version = {Version:08X}'.format (Version = self.Version)) + print ('EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER.UpdateImageTypeId = {UpdateImageTypeId}'.format (UpdateImageTypeId = str(self.UpdateImageTypeId).upper())) + print ('EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER.UpdateImageIndex = {UpdateImageIndex:08X}'.format (UpdateImageIndex = self.UpdateImageIndex)) + print ('EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER.UpdateImageSize = {UpdateImageSize:08X}'.format (UpdateImageSize = self.UpdateImageSize)) + print ('EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER.UpdateVendorCodeSize = {UpdateVendorCodeSize:08X}'.format (UpdateVendorCodeSize = self.UpdateVendorCodeSize)) + print ('EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER.UpdateHardwareInstance = {UpdateHardwareInstance:016X}'.format (UpdateHardwareInstance = self.UpdateHardwareInstance)) + print ('sizeof (Payload) = {Size:08X}'.format (Size = len (self.Payload))) + print ('sizeof (VendorCodeBytes) = {Size:08X}'.format (Size = len (self.VendorCodeBytes))) + +class FmpCapsuleHeaderClass (object): + # typedef struct { + # UINT32 Version; + # + # /// + # /// The number of drivers included in the capsule and the number of corresponding + # /// offsets stored in ItemOffsetList array. + # /// + # UINT16 EmbeddedDriverCount; + # + # /// + # /// The number of payload items included in the capsule and the number of + # /// corresponding offsets stored in the ItemOffsetList array. + # /// + # UINT16 PayloadItemCount; + # + # /// + # /// Variable length array of dimension [EmbeddedDriverCount + PayloadItemCount] + # /// containing offsets of each of the drivers and payload items contained within the capsule + # /// + # // UINT64 ItemOffsetList[]; + # } EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER; + # + # #define EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION 0x00000001 + _StructFormat = '<IHH' + _StructSize = struct.calcsize (_StructFormat) + + _ItemOffsetFormat = '<Q' + _ItemOffsetSize = struct.calcsize (_ItemOffsetFormat) + + EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION = 0x00000001 + + def __init__ (self): + self._Valid = False + self.Version = self.EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION + self.EmbeddedDriverCount = 0 + self.PayloadItemCount = 0 + self._ItemOffsetList = [] + self._EmbeddedDriverList = [] + self._PayloadList = [] + self._FmpCapsuleImageHeaderList = [] + + def AddEmbeddedDriver (self, EmbeddedDriver): + self._EmbeddedDriverList.append (EmbeddedDriver) + + def GetEmbeddedDriver (self, Index): + if Index > len (self._EmbeddedDriverList): + raise ValueError + return self._EmbeddedDriverList[Index] + + def AddPayload (self, UpdateImageTypeId, Payload = b'', VendorCodeBytes = b'', HardwareInstance = 0): + self._PayloadList.append ((UpdateImageTypeId, Payload, VendorCodeBytes, HardwareInstance)) + + def GetFmpCapsuleImageHeader (self, Index): + if Index >= len (self._FmpCapsuleImageHeaderList): + raise ValueError + return self._FmpCapsuleImageHeaderList[Index] + + def Encode (self): + self.EmbeddedDriverCount = len (self._EmbeddedDriverList) + self.PayloadItemCount = len (self._PayloadList) + + FmpCapsuleHeader = struct.pack ( + self._StructFormat, + self.Version, + self.EmbeddedDriverCount, + self.PayloadItemCount + ) + + FmpCapsuleData = b'' + Offset = self._StructSize + (self.EmbeddedDriverCount + self.PayloadItemCount) * self._ItemOffsetSize + for EmbeddedDriver in self._EmbeddedDriverList: + FmpCapsuleData = FmpCapsuleData + EmbeddedDriver + self._ItemOffsetList.append (Offset) + Offset = Offset + len (EmbeddedDriver) + Index = 1 + for (UpdateImageTypeId, Payload, VendorCodeBytes, HardwareInstance) in self._PayloadList: + FmpCapsuleImageHeader = FmpCapsuleImageHeaderClass () + FmpCapsuleImageHeader.UpdateImageTypeId = UpdateImageTypeId + FmpCapsuleImageHeader.UpdateImageIndex = Index + FmpCapsuleImageHeader.Payload = Payload + FmpCapsuleImageHeader.VendorCodeBytes = VendorCodeBytes + FmpCapsuleImageHeader.UpdateHardwareInstance = HardwareInstance + FmpCapsuleImage = FmpCapsuleImageHeader.Encode () + FmpCapsuleData = FmpCapsuleData + FmpCapsuleImage + + self._ItemOffsetList.append (Offset) + self._FmpCapsuleImageHeaderList.append (FmpCapsuleImageHeader) + + Offset = Offset + len (FmpCapsuleImage) + Index = Index + 1 + + for Offset in self._ItemOffsetList: + FmpCapsuleHeader = FmpCapsuleHeader + struct.pack (self._ItemOffsetFormat, Offset) + + self._Valid = True + return FmpCapsuleHeader + FmpCapsuleData + + def Decode (self, Buffer): + if len (Buffer) < self._StructSize: + raise ValueError + (Version, EmbeddedDriverCount, PayloadItemCount) = \ + struct.unpack ( + self._StructFormat, + Buffer[0:self._StructSize] + ) + if Version < self.EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION: + raise ValueError + + self.Version = Version + self.EmbeddedDriverCount = EmbeddedDriverCount + self.PayloadItemCount = PayloadItemCount + self._ItemOffsetList = [] + self._EmbeddedDriverList = [] + self._PayloadList = [] + self._FmpCapsuleImageHeaderList = [] + + # + # Parse the ItemOffsetList values + # + Offset = self._StructSize + for Index in range (0, EmbeddedDriverCount + PayloadItemCount): + ItemOffset = struct.unpack (self._ItemOffsetFormat, Buffer[Offset:Offset + self._ItemOffsetSize])[0] + if ItemOffset >= len (Buffer): + raise ValueError + self._ItemOffsetList.append (ItemOffset) + Offset = Offset + self._ItemOffsetSize + Result = Buffer[Offset:] + + # + # Parse the EmbeddedDrivers + # + for Index in range (0, EmbeddedDriverCount): + Offset = self._ItemOffsetList[Index] + if Index < (len (self._ItemOffsetList) - 1): + Length = self._ItemOffsetList[Index + 1] - Offset + else: + Length = len (Buffer) - Offset + self.AddEmbeddedDriver (Buffer[Offset:Offset + Length]) + + # + # Parse the Payloads that are FMP Capsule Images + # + for Index in range (EmbeddedDriverCount, EmbeddedDriverCount + PayloadItemCount): + Offset = self._ItemOffsetList[Index] + if Index < (len (self._ItemOffsetList) - 1): + Length = self._ItemOffsetList[Index + 1] - Offset + else: + Length = len (Buffer) - Offset + FmpCapsuleImageHeader = FmpCapsuleImageHeaderClass () + FmpCapsuleImageHeader.Decode (Buffer[Offset:Offset + Length]) + self.AddPayload ( + FmpCapsuleImageHeader.UpdateImageTypeId, + FmpCapsuleImageHeader.Payload, + FmpCapsuleImageHeader.VendorCodeBytes + ) + self._FmpCapsuleImageHeaderList.append (FmpCapsuleImageHeader) + + self._Valid = True + return Result + + def DumpInfo (self): + if not self._Valid: + 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)) + 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: + print (' {Offset:016X}'.format (Offset = Offset)) + for FmpCapsuleImageHeader in self._FmpCapsuleImageHeaderList: + FmpCapsuleImageHeader.DumpInfo () diff --git a/BaseTools/Source/Python/Common/Uefi/Capsule/UefiCapsuleHeader.py b/BaseTools/Source/Python/Common/Uefi/Capsule/UefiCapsuleHeader.py new file mode 100644 index 0000000000..cfe1cb6c46 --- /dev/null +++ b/BaseTools/Source/Python/Common/Uefi/Capsule/UefiCapsuleHeader.py @@ -0,0 +1,136 @@ +## @file +# Module that encodes and decodes a EFI_CAPSULE_HEADER with a payload +# +# Copyright (c) 2018, Intel Corporation. All rights reserved.<BR> +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# + +''' +UefiCapsuleHeader +''' + +import struct +import uuid + +class UefiCapsuleHeaderClass (object): + # typedef struct { + # /// + # /// A GUID that defines the contents of a capsule. + # /// + # EFI_GUID CapsuleGuid; + # /// + # /// The size of the capsule header. This may be larger than the size of + # /// the EFI_CAPSULE_HEADER since CapsuleGuid may imply + # /// extended header entries + # /// + # UINT32 HeaderSize; + # /// + # /// Bit-mapped list describing the capsule attributes. The Flag values + # /// of 0x0000 - 0xFFFF are defined by CapsuleGuid. Flag values + # /// of 0x10000 - 0xFFFFFFFF are defined by this specification + # /// + # UINT32 Flags; + # /// + # /// Size in bytes of the capsule. + # /// + # UINT32 CapsuleImageSize; + # } EFI_CAPSULE_HEADER; + # + # #define CAPSULE_FLAGS_PERSIST_ACROSS_RESET 0x00010000 + # #define CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE 0x00020000 + # #define CAPSULE_FLAGS_INITIATE_RESET 0x00040000 + # + _StructFormat = '<16sIIII' + _StructSize = struct.calcsize (_StructFormat) + + EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID = uuid.UUID ('6DCBD5ED-E82D-4C44-BDA1-7194199AD92A') + + _CAPSULE_FLAGS_PERSIST_ACROSS_RESET = 0x00010000 + _CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE = 0x00020000 + _CAPSULE_FLAGS_INITIATE_RESET = 0x00040000 + + def __init__ (self): + self._Valid = False + self.CapsuleGuid = self.EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID + self.HeaderSize = self._StructSize + self.OemFlags = 0x0000 + self.PersistAcrossReset = False + self.PopulateSystemTable = False + self.InitiateReset = False + self.CapsuleImageSize = self.HeaderSize + self.Payload = b'' + + def Encode (self): + Flags = self.OemFlags + if self.PersistAcrossReset: + Flags = Flags | self._CAPSULE_FLAGS_PERSIST_ACROSS_RESET + if self.PopulateSystemTable: + Flags = Flags | self._CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE + if self.InitiateReset: + Flags = Flags | self._CAPSULE_FLAGS_INITIATE_RESET + + self.CapsuleImageSize = self.HeaderSize + len (self.Payload) + + UefiCapsuleHeader = struct.pack ( + self._StructFormat, + self.CapsuleGuid.bytes_le, + self.HeaderSize, + Flags, + self.CapsuleImageSize, + 0 + ) + self._Valid = True + return UefiCapsuleHeader + self.Payload + + def Decode (self, Buffer): + if len (Buffer) < self._StructSize: + raise ValueError + (CapsuleGuid, HeaderSize, Flags, CapsuleImageSize, Reserved) = \ + struct.unpack ( + self._StructFormat, + Buffer[0:self._StructSize] + ) + if HeaderSize < self._StructSize: + raise ValueError + if CapsuleImageSize != len (Buffer): + raise ValueError + self.CapsuleGuid = uuid.UUID (bytes_le = CapsuleGuid) + self.HeaderSize = HeaderSize + self.OemFlags = Flags & 0xffff + self.PersistAcrossReset = (Flags & self._CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0 + self.PopulateSystemTable = (Flags & self._CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) != 0 + self.InitiateReset = (Flags & self._CAPSULE_FLAGS_INITIATE_RESET) != 0 + self.CapsuleImageSize = CapsuleImageSize + self.Payload = Buffer[self.HeaderSize:] + + self._Valid = True + return self.Payload + + def DumpInfo (self): + if not self._Valid: + raise ValueError + Flags = self.OemFlags + if self.PersistAcrossReset: + Flags = Flags | self._CAPSULE_FLAGS_PERSIST_ACROSS_RESET + if self.PopulateSystemTable: + Flags = Flags | self._CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE + if self.InitiateReset: + Flags = Flags | self._CAPSULE_FLAGS_INITIATE_RESET + print ('EFI_CAPSULE_HEADER.CapsuleGuid = {Guid}'.format (Guid = str(self.CapsuleGuid).upper())) + print ('EFI_CAPSULE_HEADER.HeaderSize = {Size:08X}'.format (Size = self.HeaderSize)) + print ('EFI_CAPSULE_HEADER.Flags = {Flags:08X}'.format (Flags = Flags)) + print (' OEM Flags = {Flags:04X}'.format (Flags = self.OemFlags)) + if self.PersistAcrossReset: + print (' CAPSULE_FLAGS_PERSIST_ACROSS_RESET') + if self.PopulateSystemTable: + print (' CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE') + if self.InitiateReset: + print (' CAPSULE_FLAGS_INITIATE_RESET') + print ('EFI_CAPSULE_HEADER.CapsuleImageSize = {Size:08X}'.format (Size = self.CapsuleImageSize)) + print ('sizeof (Payload) = {Size:08X}'.format (Size = len (self.Payload))) diff --git a/BaseTools/Source/Python/Common/Uefi/Capsule/__init__.py b/BaseTools/Source/Python/Common/Uefi/Capsule/__init__.py new file mode 100644 index 0000000000..d9db4aa919 --- /dev/null +++ b/BaseTools/Source/Python/Common/Uefi/Capsule/__init__.py @@ -0,0 +1,15 @@ +## @file +# Python 'Common.Uefi.Capsule' package initialization file. +# +# This file is required to make Python interpreter treat the directory +# as containing package. +# +# Copyright (c) 2018, Intel Corporation. All rights reserved.<BR> +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# diff --git a/BaseTools/Source/Python/Common/Uefi/__init__.py b/BaseTools/Source/Python/Common/Uefi/__init__.py new file mode 100644 index 0000000000..d80219dcb3 --- /dev/null +++ b/BaseTools/Source/Python/Common/Uefi/__init__.py @@ -0,0 +1,15 @@ +## @file +# Python 'Common.Uefi' package initialization file. +# +# This file is required to make Python interpreter treat the directory +# as containing package. +# +# Copyright (c) 2018, Intel Corporation. All rights reserved.<BR> +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# -- 2.14.2.windows.3 ^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [RFC 1/1] BaseTools/Capsule: Add Capsule Generation Tools 2018-05-29 22:56 ` [RFC 1/1] BaseTools/Capsule: " Michael D Kinney @ 2018-05-31 14:25 ` Gao, Liming 2018-05-31 16:36 ` Kinney, Michael D 0 siblings, 1 reply; 4+ messages in thread From: Gao, Liming @ 2018-05-31 14:25 UTC (permalink / raw) To: Kinney, Michael D, edk2-devel@lists.01.org Cc: Sean Brogan, Yao, Jiewen, Zhu, Yonghong Mike: Which C tool is converted? Does it support all capsule generation functionality in GenFv tool? And, GenFds has the logic to generate FMP capsule. Can they share same logic? Thanks Liming > -----Original Message----- > From: Kinney, Michael D > Sent: Wednesday, May 30, 2018 6:57 AM > To: edk2-devel@lists.01.org > Cc: Kinney, Michael D <michael.d.kinney@intel.com>; Sean Brogan <sean.brogan@microsoft.com>; Yao, Jiewen > <jiewen.yao@intel.com>; Zhu, Yonghong <yonghong.zhu@intel.com>; Gao, Liming <liming.gao@intel.com> > Subject: [RFC 1/1] BaseTools/Capsule: Add Capsule Generation Tools > > From: "Kinney, Michael D" <michael.d.kinney@intel.com> > > https://bugzilla.tianocore.org/show_bug.cgi?id=945 > > Based on content from the following branch > > https://github.com/Microsoft/MS_UEFI/tree/share/beta/CapsuleTools > > * Convert C tools to Python > * Add common python modules to: > BaseTools/Source/Python/Common/Uefi/Capsule > BaseTools/Source/Python/Common/Edk2/Capsule > * Add GenerateCapsule.py to BaseTools/Source/Python/Capsule > * Add Windows and Posix wrappers for GenerateCapsule.py > > usage: GenerateCapsule [-h] [-o OUTPUTFILE] (-e | -d | --dump-info) > [--capflag {PersistAcrossReset,PopulateSystemTable,InitiateReset}] > [--capoemflag CAPSULEOEMFLAG] [--guid GUID] > [--hardware-instance HARDWAREINSTANCE] > [--monotonic-count MONOTONICCOUNT] > [--version FWVERSION] [--lsv LOWESTSUPPORTEDVERSION] > [--pfx-file SIGNTOOLPFXFILE] > [--signer-private-cert OPENSSLSIGNERPRIVATECERTFILE] > [--other-public-cert OPENSSLOTHERPUBLICCERTFILE] > [--trusted-public-cert OPENSSLTRUSTEDPUBLICCERTFILE] > [--signing-tool-path SIGNINGTOOLPATH] [-v] [-q] > [--debug [0-9]] > InputFile > > Generate a capsule. Copyright (c) 2018, Intel Corporation. All rights > reserved. > > positional arguments: > InputFile Input binary payload filename. > > optional arguments: > -h, --help show this help message and exit > -o OUTPUTFILE, --output OUTPUTFILE > Output filename. > -e, --encode Encode file > -d, --decode Decode file > --dump-info Display FMP Payload Header information > --capflag {PersistAcrossReset,PopulateSystemTable,InitiateReset} > Capsule flag can be PersistAcrossReset, or > PopulateSystemTable or InitiateReset or not set > --capoemflag CAPSULEOEMFLAG > Capsule OEM Flag is an integer between 0x0000 and > 0xffff. > --guid GUID The FMP/ESRT GUID in registry format. Required for > encode operations. > --hardware-instance HARDWAREINSTANCE > The 64-bit hardware instance. The default is > 0x0000000000000000 > --monotonic-count MONOTONICCOUNT > 64-bit monotonic count value in header. Default is > 0x0000000000000000. > --version FWVERSION The 32-bit version of the binary payload (e.g. > 0x11223344 or 5678). > --lsv LOWESTSUPPORTEDVERSION > The 32-bit lowest supported version of the binary > payload (e.g. 0x11223344 or 5678). > --pfx-file SIGNTOOLPFXFILE > signtool PFX certificate filename. > --signer-private-cert OPENSSLSIGNERPRIVATECERTFILE > OpenSSL signer private certificate filename. > --other-public-cert OPENSSLOTHERPUBLICCERTFILE > OpenSSL other public certificate filename. > --trusted-public-cert OPENSSLTRUSTEDPUBLICCERTFILE > OpenSSL trusted public certificate filename. > --signing-tool-path SIGNINGTOOLPATH > Path to signtool or Open SLL tool. Optional if path to > tools are already in PATH. > -v, --verbose Increase output messages > -q, --quiet Reduce output messages > --debug [0-9] Set debug level > > Cc: Sean Brogan <sean.brogan@microsoft.com> > Cc: Jiewen Yao <jiewen.yao@intel.com> > Cc: Yonghong Zhu <yonghong.zhu@intel.com> > Cc: Liming Gao <liming.gao@intel.com> > Contributed-under: TianoCore Contribution Agreement 1.1 > Signed-off-by: Michael D Kinney <michael.d.kinney@intel.com> > --- > BaseTools/BinWrappers/PosixLike/GenerateCapsule | 14 + > .../BinWrappers/WindowsLike/GenerateCapsule.bat | 1 + > BaseTools/Source/Python/Capsule/GenerateCapsule.py | 500 +++++++++++++++++++++ > .../Python/Common/Edk2/Capsule/FmpPayloadHeader.py | 91 ++++ > .../Source/Python/Common/Edk2/Capsule/__init__.py | 15 + > BaseTools/Source/Python/Common/Edk2/__init__.py | 15 + > .../Python/Common/Uefi/Capsule/FmpAuthHeader.py | 184 ++++++++ > .../Python/Common/Uefi/Capsule/FmpCapsuleHeader.py | 302 +++++++++++++ > .../Common/Uefi/Capsule/UefiCapsuleHeader.py | 136 ++++++ > .../Source/Python/Common/Uefi/Capsule/__init__.py | 15 + > BaseTools/Source/Python/Common/Uefi/__init__.py | 15 + > 11 files changed, 1288 insertions(+) > create mode 100644 BaseTools/BinWrappers/PosixLike/GenerateCapsule > create mode 100644 BaseTools/BinWrappers/WindowsLike/GenerateCapsule.bat > create mode 100644 BaseTools/Source/Python/Capsule/GenerateCapsule.py > create mode 100644 BaseTools/Source/Python/Common/Edk2/Capsule/FmpPayloadHeader.py > create mode 100644 BaseTools/Source/Python/Common/Edk2/Capsule/__init__.py > create mode 100644 BaseTools/Source/Python/Common/Edk2/__init__.py > create mode 100644 BaseTools/Source/Python/Common/Uefi/Capsule/FmpAuthHeader.py > create mode 100644 BaseTools/Source/Python/Common/Uefi/Capsule/FmpCapsuleHeader.py > create mode 100644 BaseTools/Source/Python/Common/Uefi/Capsule/UefiCapsuleHeader.py > create mode 100644 BaseTools/Source/Python/Common/Uefi/Capsule/__init__.py > create mode 100644 BaseTools/Source/Python/Common/Uefi/__init__.py > > diff --git a/BaseTools/BinWrappers/PosixLike/GenerateCapsule b/BaseTools/BinWrappers/PosixLike/GenerateCapsule > new file mode 100644 > index 0000000000..59a6c8ba43 > --- /dev/null > +++ b/BaseTools/BinWrappers/PosixLike/GenerateCapsule > @@ -0,0 +1,14 @@ > +#!/usr/bin/env bash > +#python `dirname $0`/RunToolFromSource.py `basename $0` $* > + > +# If a python2 command is available, use it in preference to python > +if command -v python2 >/dev/null 2>&1; then > + python_exe=python2 > +fi > + > +full_cmd=${BASH_SOURCE:-$0} # see http://mywiki.wooledge.org/BashFAQ/028 for a discussion of why $0 is not a good choice here > +dir=$(dirname "$full_cmd") > +cmd=${full_cmd##*/} > + > +export PYTHONPATH="$dir/../../Source/Python${PYTHONPATH:+:"$PYTHONPATH"}" > +exec "${python_exe:-python}" "$dir/../../Source/Python/Capsule/$cmd.py" "$@" > diff --git a/BaseTools/BinWrappers/WindowsLike/GenerateCapsule.bat b/BaseTools/BinWrappers/WindowsLike/GenerateCapsule.bat > new file mode 100644 > index 0000000000..ca442d181b > --- /dev/null > +++ b/BaseTools/BinWrappers/WindowsLike/GenerateCapsule.bat > @@ -0,0 +1 @@ > +@%PYTHON_HOME%\python.exe %BASE_TOOLS_PATH%\Source\Python\Capsule\GenerateCapsule.py %* > diff --git a/BaseTools/Source/Python/Capsule/GenerateCapsule.py b/BaseTools/Source/Python/Capsule/GenerateCapsule.py > new file mode 100644 > index 0000000000..32ab95c3e0 > --- /dev/null > +++ b/BaseTools/Source/Python/Capsule/GenerateCapsule.py > @@ -0,0 +1,500 @@ > +## @file > +# Generate a capsule. > +# > +# Copyright (c) 2018, Intel Corporation. All rights reserved.<BR> > +# This program and the accompanying materials > +# are licensed and made available under the terms and conditions of the BSD License > +# which accompanies this distribution. The full text of the license may be found at > +# http://opensource.org/licenses/bsd-license.php > +# > +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, > +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. > +# > + > +''' > +GenerateCapsule > +''' > + > +import sys > +import argparse > +import uuid > +import struct > +import subprocess > +import os > +import tempfile > +import shutil > +from Common.Uefi.Capsule.UefiCapsuleHeader import UefiCapsuleHeaderClass > +from Common.Uefi.Capsule.FmpCapsuleHeader import FmpCapsuleHeaderClass > +from Common.Uefi.Capsule.FmpAuthHeader import FmpAuthHeaderClass > +from Common.Edk2.Capsule.FmpPayloadHeader import FmpPayloadHeaderClass > + > +# > +# Globals for help information > +# > +__prog__ = 'GenerateCapsule' > +__copyright__ = 'Copyright (c) 2018, Intel Corporation. All rights reserved.' > +__description__ = 'Generate a capsule.\n' > + > +def SignPayloadSignTool (Payload, ToolPath, PfxFile): > + # > + # Create a temporary directory > + # > + TempDirectoryName = tempfile.mkdtemp() > + > + # > + # Generate temp file name for the payload contents > + # > + TempFileName = os.path.join (TempDirectoryName, 'Payload.bin') > + > + # > + # Create temporary payload file for signing > + # > + try: > + File = open (TempFileName, mode='wb') > + File.write (Payload) > + File.close () > + except: > + shutil.rmtree (TempDirectoryName) > + raise ValueError ('GenerateCapsule: error: can not write temporary payload file.') > + > + # > + # Build signtool command > + # > + if ToolPath is None: > + ToolPath = '' > + Command = '' > + Command = Command + '"{Path}" '.format (Path = os.path.join (ToolPath, 'signtool.exe')) > + Command = Command + 'sign /fd sha256 /p7ce DetachedSignedData /p7co 1.2.840.113549.1.7.2 ' > + Command = Command + '/p7 {TempDir} '.format (TempDir = TempDirectoryName) > + Command = Command + '/f {PfxFile} '.format (PfxFile = PfxFile) > + Command = Command + TempFileName > + > + # > + # Sign the input file using the specified private key > + # > + try: > + Process = subprocess.Popen (Command, stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE, shell = > True) > + Result = Process.communicate('') > + except: > + shutil.rmtree (TempDirectoryName) > + raise ValueError ('GenerateCapsule: error: can not run signtool.') > + > + if Process.returncode != 0: > + shutil.rmtree (TempDirectoryName) > + print (Result[1].decode()) > + raise ValueError ('GenerateCapsule: error: signtool failed.') > + > + # > + # Read the signature from the generated output file > + # > + try: > + File = open (TempFileName + '.p7', mode='rb') > + Signature = File.read () > + File.close () > + except: > + shutil.rmtree (TempDirectoryName) > + raise ValueError ('GenerateCapsule: error: can not read signature file.') > + > + shutil.rmtree (TempDirectoryName) > + return Signature > + > +def VerifyPayloadSignTool (Payload, CertData, ToolPath, PfxFile): > + print ('signtool verify is not supported.') > + raise ValueError ('GenerateCapsule: error: signtool verify is not supported.') > + > +def SignPayloadOpenSsl (Payload, ToolPath, SignerPrivateCertFile, OtherPublicCertFile, TrustedPublicCertFile): > + # > + # Build openssl command > + # > + if ToolPath is None: > + ToolPath = '' > + Command = '' > + 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) > + > + # > + # Sign the input file using the specified private key and capture signature from STDOUT > + # > + try: > + Process = subprocess.Popen (Command, stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE, shell = > True) > + Result = Process.communicate(input = Payload) > + Signature = Result[0] > + except: > + raise ValueError ('GenerateCapsule: error: can not run openssl.') > + > + if Process.returncode != 0: > + print (Result[1].decode()) > + raise ValueError ('GenerateCapsule: error: openssl failed.') > + > + return Signature > + > +def VerifyPayloadOpenSsl (Payload, CertData, ToolPath, SignerPrivateCertFile, OtherPublicCertFile, TrustedPublicCertFile): > + # > + # Create a temporary directory > + # > + TempDirectoryName = tempfile.mkdtemp() > + > + # > + # Generate temp file name for the payload contents > + # > + TempFileName = os.path.join (TempDirectoryName, 'Payload.bin') > + > + # > + # Create temporary payload file for verification > + # > + try: > + File = open (TempFileName, mode='wb') > + File.write (Payload) > + File.close () > + except: > + shutil.rmtree (TempDirectoryName) > + raise ValueError ('GenerateCapsule: error: can not write temporary payload file.') > + > + # > + # Build openssl command > + # > + if ToolPath is None: > + ToolPath = '' > + Command = '' > + 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) > + > + # > + # Verify signature > + # > + try: > + Process = subprocess.Popen (Command, stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE, shell = > True) > + Result = Process.communicate(input = CertData) > + except: > + shutil.rmtree (TempDirectoryName) > + raise ValueError ('GenerateCapsule: error: can not run openssl.') > + > + if Process.returncode != 0: > + shutil.rmtree (TempDirectoryName) > + print (Result[1].decode()) > + raise ValueError ('GenerateCapsule: error: openssl failed.') > + > + shutil.rmtree (TempDirectoryName) > + return Payload > + > +if __name__ == '__main__': > + def convert_arg_line_to_args(arg_line): > + for arg in arg_line.split(): > + if not arg.strip(): > + continue > + yield arg > + > + def ValidateUnsignedInteger (Argument): > + try: > + Value = int (Argument, 0) > + except: > + Message = '{Argument} is not a valid integer value.'.format (Argument = Argument) > + raise argparse.ArgumentTypeError (Message) > + if Value < 0: > + Message = '{Argument} is a negative value.'.format (Argument = Argument) > + raise argparse.ArgumentTypeError (Message) > + return Value > + > + def ValidateRegistryFormatGuid (Argument): > + try: > + Value = uuid.UUID (Argument) > + except: > + Message = '{Argument} is not a valid registry format GUID value.'.format (Argument = Argument) > + raise argparse.ArgumentTypeError (Message) > + return Value > + > + # > + # Create command line argument parser object > + # > + parser = argparse.ArgumentParser ( > + prog = __prog__, > + description = __description__ + __copyright__, > + conflict_handler = 'resolve', > + fromfile_prefix_chars = '@' > + ) > + parser.convert_arg_line_to_args = convert_arg_line_to_args > + > + # > + # Add input and output file arguments > + # > + parser.add_argument("InputFile", type = argparse.FileType('rb'), > + help = "Input binary payload filename.") > + parser.add_argument("-o", "--output", dest = 'OutputFile', type = argparse.FileType('wb'), > + help = "Output filename.") > + # > + # Add group for -e and -d flags that are mutually exclusive and required > + # > + group = parser.add_mutually_exclusive_group (required = True) > + group.add_argument ("-e", "--encode", dest = 'Encode', action = "store_true", > + help = "Encode file") > + group.add_argument ("-d", "--decode", dest = 'Decode', action = "store_true", > + help = "Decode file") > + group.add_argument ("--dump-info", dest = 'DumpInfo', action = "store_true", > + help = "Display FMP Payload Header information") > + # > + # Add optional arguments for this command > + # > + parser.add_argument ("--capflag", dest = 'CapsuleFlag', action='append', default = [], > + choices=['PersistAcrossReset', 'PopulateSystemTable', 'InitiateReset'], > + help = "Capsule flag can be PersistAcrossReset, or PopulateSystemTable or InitiateReset or not set") > + parser.add_argument ("--capoemflag", dest = 'CapsuleOemFlag', type = ValidateUnsignedInteger, default = 0x0000, > + 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.") > + parser.add_argument ("--hardware-instance", dest = 'HardwareInstance', type = ValidateUnsignedInteger, default = > 0x0000000000000000, > + help = "The 64-bit hardware instance. The default is 0x0000000000000000") > + > + > + parser.add_argument ("--monotonic-count", dest = 'MonotonicCount', type = ValidateUnsignedInteger, default = > 0x0000000000000000, > + help = "64-bit monotonic count value in header. Default is 0x0000000000000000.") > + > + parser.add_argument ("--version", dest = 'FwVersion', type = ValidateUnsignedInteger, > + help = "The 32-bit version of the binary payload (e.g. 0x11223344 or 5678).") > + parser.add_argument ("--lsv", dest = 'LowestSupportedVersion', type = ValidateUnsignedInteger, > + help = "The 32-bit lowest supported version of the binary payload (e.g. 0x11223344 or 5678).") > + > + parser.add_argument ("--pfx-file", dest='SignToolPfxFile', type=argparse.FileType('rb'), > + help="signtool PFX certificate filename.") > + > + parser.add_argument ("--signer-private-cert", dest='OpenSslSignerPrivateCertFile', type=argparse.FileType('rb'), > + help="OpenSSL signer private certificate filename.") > + parser.add_argument ("--other-public-cert", dest='OpenSslOtherPublicCertFile', type=argparse.FileType('rb'), > + help="OpenSSL other public certificate filename.") > + parser.add_argument ("--trusted-public-cert", dest='OpenSslTrustedPublicCertFile', type=argparse.FileType('rb'), > + help="OpenSSL trusted public certificate filename.") > + > + parser.add_argument ("--signing-tool-path", dest = 'SigningToolPath', > + help = "Path to signtool or Open SLL tool. Optional if path to tools are already in PATH.") > + > + # > + # Add optional arguments common to all commands > + # > + parser.add_argument("-v", "--verbose", dest = 'Verbose', action = "store_true", > + help = "Increase output messages") > + parser.add_argument("-q", "--quiet", dest = 'Quiet', action = "store_true", > + help = "Reduce output messages") > + parser.add_argument("--debug", dest = 'Debug', type = int, metavar = '[0-9]', choices = range(0,10), default = 0, > + help = "Set debug level") > + > + # > + # Parse command line arguments > + # > + args = parser.parse_args() > + > + # > + # Perform additional argument verification > + # > + if not args.DumpInfo and args.OutputFile is None: > + parser.error ('the following arguments are required for all commands except --dump-info: --output') > + > + if args.Encode and (args.Guid is None or args.FwVersion is None or args.LowestSupportedVersion is None): > + parser.error ('the following arguments are required: --version, --lsv, --guid') > + > + if not args.DumpInfo and not args.OutputFile: > + parser.error ('the following arguments are required: --output') > + > + if not args.DumpInfo: > + if args.SignToolPfxFile is None and args.OpenSslSignerPrivateCertFile is None and args.OpenSslOtherPublicCertFile is None > and args.OpenSslTrustedPublicCertFile is None: > + parser.error ('certificate file arguments are required: --pfx-file | [--signer-private-cert --other-public-cert > --trusted-public-cert]') > + > + if args.SignToolPfxFile is not None: > + if args.OpenSslSignerPrivateCertFile is not None: > + parser.error ('Providing both signtool and OpenSSL options is not supported') > + if args.OpenSslOtherPublicCertFile is not None: > + parser.error ('Providing both signtool and OpenSSL options is not supported') > + if args.OpenSslTrustedPublicCertFile is not None: > + parser.error ('Providing both signtool and OpenSSL options is not supported') > + args.SignToolPfxFile.close() > + args.SignToolPfxFile = args.SignToolPfxFile.name > + > + if not args.DumpInfo: > + if args.SignToolPfxFile is None: > + if args.OpenSslSignerPrivateCertFile is None: > + parser.error ('the following arguments are required: --signer-private-cert') > + if args.OpenSslOtherPublicCertFile is None: > + parser.error ('the following arguments are required: --other-public-cert') > + if args.OpenSslTrustedPublicCertFile is None: > + parser.error ('the following arguments are required: --trusted-public-cert') > + args.OpenSslSignerPrivateCertFile.close() > + args.OpenSslOtherPublicCertFile.close() > + args.OpenSslTrustedPublicCertFile.close() > + args.OpenSslSignerPrivateCertFile = args.OpenSslSignerPrivateCertFile.name > + args.OpenSslOtherPublicCertFile = args.OpenSslOtherPublicCertFile.name > + args.OpenSslTrustedPublicCertFile = args.OpenSslTrustedPublicCertFile.name > + > + # > + # 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) > + > + # > + # Create objects > + # > + UefiCapsuleHeader = UefiCapsuleHeaderClass () > + FmpCapsuleHeader = FmpCapsuleHeaderClass () > + FmpAuthHeader = FmpAuthHeaderClass () > + FmpPayloadHeader = FmpPayloadHeaderClass () > + > + if args.Encode: > + try: > + FmpPayloadHeader.FwVersion = args.FwVersion > + FmpPayloadHeader.LowestSupportedVersion = args.LowestSupportedVersion > + FmpPayloadHeader.Payload = Buffer > + 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 args.SignToolPfxFile is not None: > + 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') > + raise > + 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 = 'PopulateSystemTable' in args.CapsuleFlag > + 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 > + Result = FmpAuthHeader.Decode (Result) > + > + # > + # Verify Image with 64-bit MonotonicCount appended to end of image > + # > + try: > + if args.SignToolPfxFile is not None: > + 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.') > + > + Result = FmpPayloadHeader.Decode (Result) > + if args.Verbose: > + print ('========') > + UefiCapsuleHeader.DumpInfo () > + print ('--------') > + FmpCapsuleHeader.DumpInfo () > + print ('--------') > + FmpAuthHeader.DumpInfo () > + print ('--------') > + FmpPayloadHeader.DumpInfo () > + print ('========') > + except: > + print ('GenerateCapsule: error: can not decode capsule') > + raise > + sys.exit (1) > + > + elif args.DumpInfo: > + try: > + Result = UefiCapsuleHeader.Decode (Buffer) > + FmpCapsuleHeader.Decode (Result) > + Result = FmpCapsuleHeader.GetFmpCapsuleImageHeader (0).Payload > + Result = FmpAuthHeader.Decode (Result) > + Result = FmpPayloadHeader.Decode (Result) > + > + print ('========') > + UefiCapsuleHeader.DumpInfo () > + print ('--------') > + FmpCapsuleHeader.DumpInfo () > + print ('--------') > + FmpAuthHeader.DumpInfo () > + print ('--------') > + FmpPayloadHeader.DumpInfo () > + print ('========') > + except: > + print ('GenerateCapsule: error: can not decode capsule') > + sys.exit (1) > + else: > + print('GenerateCapsule: error: invalid options') > + sys.exit (1) > + > + # > + # Write binary output file > + # > + 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.Verbose: > + print('Success') > diff --git a/BaseTools/Source/Python/Common/Edk2/Capsule/FmpPayloadHeader.py > b/BaseTools/Source/Python/Common/Edk2/Capsule/FmpPayloadHeader.py > new file mode 100644 > index 0000000000..0ed51752d3 > --- /dev/null > +++ b/BaseTools/Source/Python/Common/Edk2/Capsule/FmpPayloadHeader.py > @@ -0,0 +1,91 @@ > +## @file > +# Module that encodes and decodes a FMP_PAYLOAD_HEADER with a payload. > +# The FMP_PAYLOAD_HEADER is processed by the FmpPayloadHeaderLib in the > +# FmpDevicePkg. > +# > +# Copyright (c) 2018, Intel Corporation. All rights reserved.<BR> > +# This program and the accompanying materials > +# are licensed and made available under the terms and conditions of the BSD License > +# which accompanies this distribution. The full text of the license may be found at > +# http://opensource.org/licenses/bsd-license.php > +# > +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, > +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. > +# > + > +''' > +FmpPayloadHeader > +''' > + > +import struct > + > +def _SIGNATURE_32 (A, B, C, D): > + return struct.unpack ('=I',bytearray (A + B + C + D, 'ascii'))[0] > + > +def _SIGNATURE_32_TO_STRING (Signature): > + return struct.pack ("<I", Signature).decode () > + > +class FmpPayloadHeaderClass (object): > + # > + # typedef struct { > + # UINT32 Signature; > + # UINT32 HeaderSize; > + # UINT32 FwVersion; > + # UINT32 LowestSupportedVersion; > + # } FMP_PAYLOAD_HEADER; > + # > + # #define FMP_PAYLOAD_HEADER_SIGNATURE SIGNATURE_32 ('M', 'S', 'S', '1') > + # > + _StructFormat = '<IIII' > + _StructSize = struct.calcsize (_StructFormat) > + > + _FMP_PAYLOAD_HEADER_SIGNATURE = _SIGNATURE_32 ('M', 'S', 'S', '1') > + > + def __init__ (self): > + self._Valid = False > + self.Signature = self._FMP_PAYLOAD_HEADER_SIGNATURE > + self.HeaderSize = self._StructSize > + self.FwVersion = 0x00000000 > + self.LowestSupportedVersion = 0x00000000 > + self.Payload = b'' > + > + def Encode (self): > + FmpPayloadHeader = struct.pack ( > + self._StructFormat, > + self.Signature, > + self.HeaderSize, > + self.FwVersion, > + self.LowestSupportedVersion > + ) > + self._Valid = True > + return FmpPayloadHeader + self.Payload > + > + def Decode (self, Buffer): > + if len (Buffer) < self._StructSize: > + raise ValueError > + (Signature, HeaderSize, FwVersion, LowestSupportedVersion) = \ > + struct.unpack ( > + self._StructFormat, > + Buffer[0:self._StructSize] > + ) > + if Signature != self._FMP_PAYLOAD_HEADER_SIGNATURE: > + raise ValueError > + if HeaderSize < self._StructSize: > + raise ValueError > + self.Signature = Signature > + self.HeaderSize = HeaderSize > + self.FwVersion = FwVersion > + self.LowestSupportedVersion = LowestSupportedVersion > + self.Payload = Buffer[self.HeaderSize:] > + > + self._Valid = True > + return self.Payload > + > + def DumpInfo (self): > + if not self._Valid: > + raise ValueError > + print ('FMP_PAYLOAD_HEADER.Signature = {Signature:08X} ({SignatureString})'.format (Signature = > self.Signature, SignatureString = _SIGNATURE_32_TO_STRING (self.Signature))) > + print ('FMP_PAYLOAD_HEADER.HeaderSize = {HeaderSize:08X}'.format (HeaderSize = self.HeaderSize)) > + print ('FMP_PAYLOAD_HEADER.FwVersion = {FwVersion:08X}'.format (FwVersion = self.FwVersion)) > + print ('FMP_PAYLOAD_HEADER.LowestSupportedVersion = {LowestSupportedVersion:08X}'.format > (LowestSupportedVersion = self.LowestSupportedVersion)) > + print ('sizeof (Payload) = {Size:08X}'.format (Size = len (self.Payload))) > diff --git a/BaseTools/Source/Python/Common/Edk2/Capsule/__init__.py > b/BaseTools/Source/Python/Common/Edk2/Capsule/__init__.py > new file mode 100644 > index 0000000000..71c6f06838 > --- /dev/null > +++ b/BaseTools/Source/Python/Common/Edk2/Capsule/__init__.py > @@ -0,0 +1,15 @@ > +## @file > +# Python 'Common.Edk2.Capsule' package initialization file. > +# > +# This file is required to make Python interpreter treat the directory > +# as containing package. > +# > +# Copyright (c) 2018, Intel Corporation. All rights reserved.<BR> > +# This program and the accompanying materials > +# are licensed and made available under the terms and conditions of the BSD License > +# which accompanies this distribution. The full text of the license may be found at > +# http://opensource.org/licenses/bsd-license.php > +# > +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, > +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. > +# > diff --git a/BaseTools/Source/Python/Common/Edk2/__init__.py b/BaseTools/Source/Python/Common/Edk2/__init__.py > new file mode 100644 > index 0000000000..97d925cbf8 > --- /dev/null > +++ b/BaseTools/Source/Python/Common/Edk2/__init__.py > @@ -0,0 +1,15 @@ > +## @file > +# Python 'Common.Edk2' package initialization file. > +# > +# This file is required to make Python interpreter treat the directory > +# as containing package. > +# > +# Copyright (c) 2018, Intel Corporation. All rights reserved.<BR> > +# This program and the accompanying materials > +# are licensed and made available under the terms and conditions of the BSD License > +# which accompanies this distribution. The full text of the license may be found at > +# http://opensource.org/licenses/bsd-license.php > +# > +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, > +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. > +# > diff --git a/BaseTools/Source/Python/Common/Uefi/Capsule/FmpAuthHeader.py > b/BaseTools/Source/Python/Common/Uefi/Capsule/FmpAuthHeader.py > new file mode 100644 > index 0000000000..aec52bf772 > --- /dev/null > +++ b/BaseTools/Source/Python/Common/Uefi/Capsule/FmpAuthHeader.py > @@ -0,0 +1,184 @@ > +## @file > +# 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> > +# This program and the accompanying materials > +# are licensed and made available under the terms and conditions of the BSD License > +# which accompanies this distribution. The full text of the license may be found at > +# http://opensource.org/licenses/bsd-license.php > +# > +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, > +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. > +# > + > +''' > +FmpAuthHeader > +''' > + > +import struct > +import uuid > + > +class FmpAuthHeaderClass (object): > + # /// > + # /// Image Attribute -Authentication Required > + # /// > + # typedef struct { > + # /// > + # /// It is included in the signature of AuthInfo. It is used to ensure freshness/no replay. > + # /// It is incremented during each firmware image operation. > + # /// > + # UINT64 MonotonicCount; > + # /// > + # /// Provides the authorization for the firmware image operations. It is a signature across > + # /// the image data and the Monotonic Count value. Caller uses the private key that is > + # /// associated with a public key that has been provisioned via the key exchange. > + # /// Because this is defined as a signature, WIN_CERTIFICATE_UEFI_GUID.CertType must > + # /// be EFI_CERT_TYPE_PKCS7_GUID. > + # /// > + # WIN_CERTIFICATE_UEFI_GUID AuthInfo; > + # } EFI_FIRMWARE_IMAGE_AUTHENTICATION; > + # > + # /// > + # /// Certificate which encapsulates a GUID-specific digital signature > + # /// > + # typedef struct { > + # /// > + # /// This is the standard WIN_CERTIFICATE header, where > + # /// wCertificateType is set to WIN_CERT_TYPE_EFI_GUID. > + # /// > + # WIN_CERTIFICATE Hdr; > + # /// > + # /// This is the unique id which determines the > + # /// format of the CertData. . > + # /// > + # EFI_GUID CertType; > + # /// > + # /// The following is the certificate data. The format of > + # /// the data is determined by the CertType. > + # /// If CertType is EFI_CERT_TYPE_RSA2048_SHA256_GUID, > + # /// the CertData will be EFI_CERT_BLOCK_RSA_2048_SHA256 structure. > + # /// > + # UINT8 CertData[1]; > + # } WIN_CERTIFICATE_UEFI_GUID; > + # > + # /// > + # /// The WIN_CERTIFICATE structure is part of the PE/COFF specification. > + # /// > + # typedef struct { > + # /// > + # /// The length of the entire certificate, > + # /// including the length of the header, in bytes. > + # /// > + # UINT32 dwLength; > + # /// > + # /// The revision level of the WIN_CERTIFICATE > + # /// structure. The current revision level is 0x0200. > + # /// > + # UINT16 wRevision; > + # /// > + # /// The certificate type. See WIN_CERT_TYPE_xxx for the UEFI > + # /// certificate types. The UEFI specification reserves the range of > + # /// certificate type values from 0x0EF0 to 0x0EFF. > + # /// > + # UINT16 wCertificateType; > + # /// > + # /// The following is the actual certificate. The format of > + # /// the certificate depends on wCertificateType. > + # /// > + # /// UINT8 bCertificate[ANYSIZE_ARRAY]; > + # /// > + # } WIN_CERTIFICATE; > + # > + # #define WIN_CERT_TYPE_EFI_GUID 0x0EF1 > + # > + # /// > + # /// This identifies a signature containing a DER-encoded PKCS #7 version 1.5 [RFC2315] > + # /// SignedData value. > + # /// > + # #define EFI_CERT_TYPE_PKCS7_GUID \ > + # { \ > + # 0x4aafd29d, 0x68df, 0x49ee, {0x8a, 0xa9, 0x34, 0x7d, 0x37, 0x56, 0x65, 0xa7} \ > + # } > + > + _StructFormat = '<QIHH16s' > + _StructSize = struct.calcsize (_StructFormat) > + > + _MonotonicCountFormat = '<Q' > + _MonotonicCountSize = struct.calcsize (_MonotonicCountFormat) > + > + _StructAuthInfoFormat = '<IHH16s' > + _StructAuthInfoSize = struct.calcsize (_StructAuthInfoFormat) > + > + _WIN_CERT_REVISION = 0x0200 > + _WIN_CERT_TYPE_EFI_GUID = 0x0EF1 > + _EFI_CERT_TYPE_PKCS7_GUID = uuid.UUID ('4aafd29d-68df-49ee-8aa9-347d375665a7') > + > + def __init__ (self): > + self._Valid = False > + self.MonotonicCount = 0 > + self.dwLength = self._StructAuthInfoSize > + self.wRevision = self._WIN_CERT_REVISION > + self.wCertificateType = self._WIN_CERT_TYPE_EFI_GUID > + self.CertType = self._EFI_CERT_TYPE_PKCS7_GUID > + self.CertData = b'' > + self.Payload = b'' > + > + > + def Encode (self): > + if self.wRevision != self._WIN_CERT_REVISION: > + raise ValueError > + if self.wCertificateType != self._WIN_CERT_TYPE_EFI_GUID: > + raise ValueError > + if self.CertType != self._EFI_CERT_TYPE_PKCS7_GUID: > + raise ValueError > + self.dwLength = self._StructAuthInfoSize + len (self.CertData) > + > + FmpAuthHeader = struct.pack ( > + self._StructFormat, > + self.MonotonicCount, > + self.dwLength, > + self.wRevision, > + self.wCertificateType, > + self.CertType.bytes_le > + ) > + self._Valid = True > + > + return FmpAuthHeader + self.CertData + self.Payload > + > + def Decode (self, Buffer): > + if len (Buffer) < self._StructSize: > + raise ValueError > + (MonotonicCount, dwLength, wRevision, wCertificateType, CertType) = \ > + struct.unpack ( > + self._StructFormat, > + Buffer[0:self._StructSize] > + ) > + if dwLength < self._StructAuthInfoSize: > + raise ValueError > + if wRevision != self._WIN_CERT_REVISION: > + raise ValueError > + if wCertificateType != self._WIN_CERT_TYPE_EFI_GUID: > + raise ValueError > + if CertType != self._EFI_CERT_TYPE_PKCS7_GUID.bytes_le: > + raise ValueError > + self.MonotonicCount = MonotonicCount > + self.dwLength = dwLength > + self.wRevision = wRevision > + self.wCertificateType = wCertificateType > + self.CertType = uuid.UUID (bytes = CertType) > + self.CertData = Buffer[self._StructSize:self._MonotonicCountSize + self.dwLength] > + self.Payload = Buffer[self._MonotonicCountSize + self.dwLength:] > + self._Valid = True > + return self.Payload > + > + def DumpInfo (self): > + if not self._Valid: > + raise ValueError > + print ('EFI_FIRMWARE_IMAGE_AUTHENTICATION.MonotonicCount = {MonotonicCount:016X}'.format > (MonotonicCount = self.MonotonicCount)) > + print ('EFI_FIRMWARE_IMAGE_AUTHENTICATION.AuthInfo.Hdr.dwLength = {dwLength:08X}'.format (dwLength = > self.dwLength)) > + print ('EFI_FIRMWARE_IMAGE_AUTHENTICATION.AuthInfo.Hdr.wRevision = {wRevision:04X}'.format (wRevision = > self.wRevision)) > + print ('EFI_FIRMWARE_IMAGE_AUTHENTICATION.AuthInfo.Hdr.wCertificateType = {wCertificateType:04X}'.format > (wCertificateType = self.wCertificateType)) > + print ('EFI_FIRMWARE_IMAGE_AUTHENTICATION.AuthInfo.CertType = {Guid}'.format (Guid = > str(self.CertType).upper())) > + print ('sizeof (EFI_FIRMWARE_IMAGE_AUTHENTICATION.AuthInfo.CertData) = {Size:08X}'.format (Size = len > (self.CertData))) > + print ('sizeof (Payload) = {Size:08X}'.format (Size = len > (self.Payload))) > diff --git a/BaseTools/Source/Python/Common/Uefi/Capsule/FmpCapsuleHeader.py > b/BaseTools/Source/Python/Common/Uefi/Capsule/FmpCapsuleHeader.py > new file mode 100644 > index 0000000000..2461fb5068 > --- /dev/null > +++ b/BaseTools/Source/Python/Common/Uefi/Capsule/FmpCapsuleHeader.py > @@ -0,0 +1,302 @@ > +## @file > +# Module that encodes and decodes a EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER with > +# a payload. > +# > +# Copyright (c) 2018, Intel Corporation. All rights reserved.<BR> > +# This program and the accompanying materials > +# are licensed and made available under the terms and conditions of the BSD License > +# which accompanies this distribution. The full text of the license may be found at > +# http://opensource.org/licenses/bsd-license.php > +# > +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, > +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. > +# > + > +''' > +FmpCapsuleHeader > +''' > + > +import struct > +import uuid > + > +class FmpCapsuleImageHeaderClass (object): > + # typedef struct { > + # UINT32 Version; > + # > + # /// > + # /// Used to identify device firmware targeted by this update. This guid is matched by > + # /// system firmware against ImageTypeId field within a EFI_FIRMWARE_IMAGE_DESCRIPTOR > + # /// > + # EFI_GUID UpdateImageTypeId; > + # > + # /// > + # /// Passed as ImageIndex in call to EFI_FIRMWARE_MANAGEMENT_PROTOCOL.SetImage () > + # /// > + # UINT8 UpdateImageIndex; > + # UINT8 reserved_bytes[3]; > + # > + # /// > + # /// Size of the binary update image which immediately follows this structure > + # /// > + # UINT32 UpdateImageSize; > + # > + # /// > + # /// Size of the VendorCode bytes which optionally immediately follow binary update image in the capsule > + # /// > + # UINT32 UpdateVendorCodeSize; > + # > + # /// > + # /// The HardwareInstance to target with this update. If value is zero it means match all > + # /// HardwareInstances. This field allows update software to target only a single device in > + # /// cases where there are more than one device with the same ImageTypeId GUID. > + # /// This header is outside the signed data of the Authentication Info structure and > + # /// therefore can be modified without changing the Auth data. > + # /// > + # UINT64 UpdateHardwareInstance; > + # } EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER; > + # > + # #define EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION 0x00000002 > + > + _StructFormat = '<I16sB3BIIQ' > + _StructSize = struct.calcsize (_StructFormat) > + > + EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION = 0x00000002 > + > + def __init__ (self): > + self._Valid = False > + self.Version = self.EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION > + self.UpdateImageTypeId = uuid.UUID ('00000000-0000-0000-0000-000000000000') > + self.UpdateImageIndex = 0 > + self.UpdateImageSize = 0 > + self.UpdateVendorCodeSize = 0 > + self.UpdateHardwareInstance = 0x0000000000000000 > + self.Payload = b'' > + self.VendorCodeBytes = b'' > + > + def Encode (self): > + self.UpdateImageSize = len (self.Payload) > + self.UpdateVendorCodeSize = len (self.VendorCodeBytes) > + FmpCapsuleImageHeader = struct.pack ( > + self._StructFormat, > + self.Version, > + self.UpdateImageTypeId.bytes_le, > + self.UpdateImageIndex, > + 0,0,0, > + self.UpdateImageSize, > + self.UpdateVendorCodeSize, > + self.UpdateHardwareInstance > + ) > + self._Valid = True > + return FmpCapsuleImageHeader + self.Payload + self.VendorCodeBytes > + > + def Decode (self, Buffer): > + if len (Buffer) < self._StructSize: > + raise ValueError > + (Version, UpdateImageTypeId, UpdateImageIndex, r0, r1, r2, UpdateImageSize, UpdateVendorCodeSize, > UpdateHardwareInstance) = \ > + struct.unpack ( > + self._StructFormat, > + Buffer[0:self._StructSize] > + ) > + > + if Version < self.EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION: > + raise ValueError > + if UpdateImageIndex < 1: > + raise ValueError > + if UpdateImageSize + UpdateVendorCodeSize != len (Buffer[self._StructSize:]): > + raise ValueError > + > + self.Version = Version > + self.UpdateImageTypeId = uuid.UUID (bytes_le = UpdateImageTypeId) > + self.UpdateImageIndex = UpdateImageIndex > + self.UpdateImageSize = UpdateImageSize > + self.UpdateVendorCodeSize = UpdateVendorCodeSize > + self.UpdateHardwareInstance = UpdateHardwareInstance > + self.Payload = Buffer[self._StructSize:self._StructSize + UpdateImageSize] > + self.VendorCodeBytes = Buffer[self._StructSize + UpdateImageSize:] > + self._Valid = True > + return Buffer[self._StructSize:] > + > + def DumpInfo (self): > + if not self._Valid: > + raise ValueError > + print ('EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER.Version = {Version:08X}'.format > (Version = self.Version)) > + print ('EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER.UpdateImageTypeId = > {UpdateImageTypeId}'.format (UpdateImageTypeId = str(self.UpdateImageTypeId).upper())) > + print ('EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER.UpdateImageIndex = > {UpdateImageIndex:08X}'.format (UpdateImageIndex = self.UpdateImageIndex)) > + print ('EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER.UpdateImageSize = > {UpdateImageSize:08X}'.format (UpdateImageSize = self.UpdateImageSize)) > + print ('EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER.UpdateVendorCodeSize = > {UpdateVendorCodeSize:08X}'.format (UpdateVendorCodeSize = self.UpdateVendorCodeSize)) > + print ('EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER.UpdateHardwareInstance = > {UpdateHardwareInstance:016X}'.format (UpdateHardwareInstance = self.UpdateHardwareInstance)) > + print ('sizeof (Payload) = {Size:08X}'.format (Size = len > (self.Payload))) > + print ('sizeof (VendorCodeBytes) = {Size:08X}'.format (Size = len > (self.VendorCodeBytes))) > + > +class FmpCapsuleHeaderClass (object): > + # typedef struct { > + # UINT32 Version; > + # > + # /// > + # /// The number of drivers included in the capsule and the number of corresponding > + # /// offsets stored in ItemOffsetList array. > + # /// > + # UINT16 EmbeddedDriverCount; > + # > + # /// > + # /// The number of payload items included in the capsule and the number of > + # /// corresponding offsets stored in the ItemOffsetList array. > + # /// > + # UINT16 PayloadItemCount; > + # > + # /// > + # /// Variable length array of dimension [EmbeddedDriverCount + PayloadItemCount] > + # /// containing offsets of each of the drivers and payload items contained within the capsule > + # /// > + # // UINT64 ItemOffsetList[]; > + # } EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER; > + # > + # #define EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION 0x00000001 > + _StructFormat = '<IHH' > + _StructSize = struct.calcsize (_StructFormat) > + > + _ItemOffsetFormat = '<Q' > + _ItemOffsetSize = struct.calcsize (_ItemOffsetFormat) > + > + EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION = 0x00000001 > + > + def __init__ (self): > + self._Valid = False > + self.Version = self.EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION > + self.EmbeddedDriverCount = 0 > + self.PayloadItemCount = 0 > + self._ItemOffsetList = [] > + self._EmbeddedDriverList = [] > + self._PayloadList = [] > + self._FmpCapsuleImageHeaderList = [] > + > + def AddEmbeddedDriver (self, EmbeddedDriver): > + self._EmbeddedDriverList.append (EmbeddedDriver) > + > + def GetEmbeddedDriver (self, Index): > + if Index > len (self._EmbeddedDriverList): > + raise ValueError > + return self._EmbeddedDriverList[Index] > + > + def AddPayload (self, UpdateImageTypeId, Payload = b'', VendorCodeBytes = b'', HardwareInstance = 0): > + self._PayloadList.append ((UpdateImageTypeId, Payload, VendorCodeBytes, HardwareInstance)) > + > + def GetFmpCapsuleImageHeader (self, Index): > + if Index >= len (self._FmpCapsuleImageHeaderList): > + raise ValueError > + return self._FmpCapsuleImageHeaderList[Index] > + > + def Encode (self): > + self.EmbeddedDriverCount = len (self._EmbeddedDriverList) > + self.PayloadItemCount = len (self._PayloadList) > + > + FmpCapsuleHeader = struct.pack ( > + self._StructFormat, > + self.Version, > + self.EmbeddedDriverCount, > + self.PayloadItemCount > + ) > + > + FmpCapsuleData = b'' > + Offset = self._StructSize + (self.EmbeddedDriverCount + self.PayloadItemCount) * self._ItemOffsetSize > + for EmbeddedDriver in self._EmbeddedDriverList: > + FmpCapsuleData = FmpCapsuleData + EmbeddedDriver > + self._ItemOffsetList.append (Offset) > + Offset = Offset + len (EmbeddedDriver) > + Index = 1 > + for (UpdateImageTypeId, Payload, VendorCodeBytes, HardwareInstance) in self._PayloadList: > + FmpCapsuleImageHeader = FmpCapsuleImageHeaderClass () > + FmpCapsuleImageHeader.UpdateImageTypeId = UpdateImageTypeId > + FmpCapsuleImageHeader.UpdateImageIndex = Index > + FmpCapsuleImageHeader.Payload = Payload > + FmpCapsuleImageHeader.VendorCodeBytes = VendorCodeBytes > + FmpCapsuleImageHeader.UpdateHardwareInstance = HardwareInstance > + FmpCapsuleImage = FmpCapsuleImageHeader.Encode () > + FmpCapsuleData = FmpCapsuleData + FmpCapsuleImage > + > + self._ItemOffsetList.append (Offset) > + self._FmpCapsuleImageHeaderList.append (FmpCapsuleImageHeader) > + > + Offset = Offset + len (FmpCapsuleImage) > + Index = Index + 1 > + > + for Offset in self._ItemOffsetList: > + FmpCapsuleHeader = FmpCapsuleHeader + struct.pack (self._ItemOffsetFormat, Offset) > + > + self._Valid = True > + return FmpCapsuleHeader + FmpCapsuleData > + > + def Decode (self, Buffer): > + if len (Buffer) < self._StructSize: > + raise ValueError > + (Version, EmbeddedDriverCount, PayloadItemCount) = \ > + struct.unpack ( > + self._StructFormat, > + Buffer[0:self._StructSize] > + ) > + if Version < self.EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION: > + raise ValueError > + > + self.Version = Version > + self.EmbeddedDriverCount = EmbeddedDriverCount > + self.PayloadItemCount = PayloadItemCount > + self._ItemOffsetList = [] > + self._EmbeddedDriverList = [] > + self._PayloadList = [] > + self._FmpCapsuleImageHeaderList = [] > + > + # > + # Parse the ItemOffsetList values > + # > + Offset = self._StructSize > + for Index in range (0, EmbeddedDriverCount + PayloadItemCount): > + ItemOffset = struct.unpack (self._ItemOffsetFormat, Buffer[Offset:Offset + self._ItemOffsetSize])[0] > + if ItemOffset >= len (Buffer): > + raise ValueError > + self._ItemOffsetList.append (ItemOffset) > + Offset = Offset + self._ItemOffsetSize > + Result = Buffer[Offset:] > + > + # > + # Parse the EmbeddedDrivers > + # > + for Index in range (0, EmbeddedDriverCount): > + Offset = self._ItemOffsetList[Index] > + if Index < (len (self._ItemOffsetList) - 1): > + Length = self._ItemOffsetList[Index + 1] - Offset > + else: > + Length = len (Buffer) - Offset > + self.AddEmbeddedDriver (Buffer[Offset:Offset + Length]) > + > + # > + # Parse the Payloads that are FMP Capsule Images > + # > + for Index in range (EmbeddedDriverCount, EmbeddedDriverCount + PayloadItemCount): > + Offset = self._ItemOffsetList[Index] > + if Index < (len (self._ItemOffsetList) - 1): > + Length = self._ItemOffsetList[Index + 1] - Offset > + else: > + Length = len (Buffer) - Offset > + FmpCapsuleImageHeader = FmpCapsuleImageHeaderClass () > + FmpCapsuleImageHeader.Decode (Buffer[Offset:Offset + Length]) > + self.AddPayload ( > + FmpCapsuleImageHeader.UpdateImageTypeId, > + FmpCapsuleImageHeader.Payload, > + FmpCapsuleImageHeader.VendorCodeBytes > + ) > + self._FmpCapsuleImageHeaderList.append (FmpCapsuleImageHeader) > + > + self._Valid = True > + return Result > + > + def DumpInfo (self): > + if not self._Valid: > + 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)) > + 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: > + print (' {Offset:016X}'.format (Offset = Offset)) > + for FmpCapsuleImageHeader in self._FmpCapsuleImageHeaderList: > + FmpCapsuleImageHeader.DumpInfo () > diff --git a/BaseTools/Source/Python/Common/Uefi/Capsule/UefiCapsuleHeader.py > b/BaseTools/Source/Python/Common/Uefi/Capsule/UefiCapsuleHeader.py > new file mode 100644 > index 0000000000..cfe1cb6c46 > --- /dev/null > +++ b/BaseTools/Source/Python/Common/Uefi/Capsule/UefiCapsuleHeader.py > @@ -0,0 +1,136 @@ > +## @file > +# Module that encodes and decodes a EFI_CAPSULE_HEADER with a payload > +# > +# Copyright (c) 2018, Intel Corporation. All rights reserved.<BR> > +# This program and the accompanying materials > +# are licensed and made available under the terms and conditions of the BSD License > +# which accompanies this distribution. The full text of the license may be found at > +# http://opensource.org/licenses/bsd-license.php > +# > +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, > +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. > +# > + > +''' > +UefiCapsuleHeader > +''' > + > +import struct > +import uuid > + > +class UefiCapsuleHeaderClass (object): > + # typedef struct { > + # /// > + # /// A GUID that defines the contents of a capsule. > + # /// > + # EFI_GUID CapsuleGuid; > + # /// > + # /// The size of the capsule header. This may be larger than the size of > + # /// the EFI_CAPSULE_HEADER since CapsuleGuid may imply > + # /// extended header entries > + # /// > + # UINT32 HeaderSize; > + # /// > + # /// Bit-mapped list describing the capsule attributes. The Flag values > + # /// of 0x0000 - 0xFFFF are defined by CapsuleGuid. Flag values > + # /// of 0x10000 - 0xFFFFFFFF are defined by this specification > + # /// > + # UINT32 Flags; > + # /// > + # /// Size in bytes of the capsule. > + # /// > + # UINT32 CapsuleImageSize; > + # } EFI_CAPSULE_HEADER; > + # > + # #define CAPSULE_FLAGS_PERSIST_ACROSS_RESET 0x00010000 > + # #define CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE 0x00020000 > + # #define CAPSULE_FLAGS_INITIATE_RESET 0x00040000 > + # > + _StructFormat = '<16sIIII' > + _StructSize = struct.calcsize (_StructFormat) > + > + EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID = uuid.UUID ('6DCBD5ED-E82D-4C44-BDA1-7194199AD92A') > + > + _CAPSULE_FLAGS_PERSIST_ACROSS_RESET = 0x00010000 > + _CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE = 0x00020000 > + _CAPSULE_FLAGS_INITIATE_RESET = 0x00040000 > + > + def __init__ (self): > + self._Valid = False > + self.CapsuleGuid = self.EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID > + self.HeaderSize = self._StructSize > + self.OemFlags = 0x0000 > + self.PersistAcrossReset = False > + self.PopulateSystemTable = False > + self.InitiateReset = False > + self.CapsuleImageSize = self.HeaderSize > + self.Payload = b'' > + > + def Encode (self): > + Flags = self.OemFlags > + if self.PersistAcrossReset: > + Flags = Flags | self._CAPSULE_FLAGS_PERSIST_ACROSS_RESET > + if self.PopulateSystemTable: > + Flags = Flags | self._CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE > + if self.InitiateReset: > + Flags = Flags | self._CAPSULE_FLAGS_INITIATE_RESET > + > + self.CapsuleImageSize = self.HeaderSize + len (self.Payload) > + > + UefiCapsuleHeader = struct.pack ( > + self._StructFormat, > + self.CapsuleGuid.bytes_le, > + self.HeaderSize, > + Flags, > + self.CapsuleImageSize, > + 0 > + ) > + self._Valid = True > + return UefiCapsuleHeader + self.Payload > + > + def Decode (self, Buffer): > + if len (Buffer) < self._StructSize: > + raise ValueError > + (CapsuleGuid, HeaderSize, Flags, CapsuleImageSize, Reserved) = \ > + struct.unpack ( > + self._StructFormat, > + Buffer[0:self._StructSize] > + ) > + if HeaderSize < self._StructSize: > + raise ValueError > + if CapsuleImageSize != len (Buffer): > + raise ValueError > + self.CapsuleGuid = uuid.UUID (bytes_le = CapsuleGuid) > + self.HeaderSize = HeaderSize > + self.OemFlags = Flags & 0xffff > + self.PersistAcrossReset = (Flags & self._CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0 > + self.PopulateSystemTable = (Flags & self._CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) != 0 > + self.InitiateReset = (Flags & self._CAPSULE_FLAGS_INITIATE_RESET) != 0 > + self.CapsuleImageSize = CapsuleImageSize > + self.Payload = Buffer[self.HeaderSize:] > + > + self._Valid = True > + return self.Payload > + > + def DumpInfo (self): > + if not self._Valid: > + raise ValueError > + Flags = self.OemFlags > + if self.PersistAcrossReset: > + Flags = Flags | self._CAPSULE_FLAGS_PERSIST_ACROSS_RESET > + if self.PopulateSystemTable: > + Flags = Flags | self._CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE > + if self.InitiateReset: > + Flags = Flags | self._CAPSULE_FLAGS_INITIATE_RESET > + print ('EFI_CAPSULE_HEADER.CapsuleGuid = {Guid}'.format (Guid = str(self.CapsuleGuid).upper())) > + print ('EFI_CAPSULE_HEADER.HeaderSize = {Size:08X}'.format (Size = self.HeaderSize)) > + print ('EFI_CAPSULE_HEADER.Flags = {Flags:08X}'.format (Flags = Flags)) > + print (' OEM Flags = {Flags:04X}'.format (Flags = self.OemFlags)) > + if self.PersistAcrossReset: > + print (' CAPSULE_FLAGS_PERSIST_ACROSS_RESET') > + if self.PopulateSystemTable: > + print (' CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE') > + if self.InitiateReset: > + print (' CAPSULE_FLAGS_INITIATE_RESET') > + print ('EFI_CAPSULE_HEADER.CapsuleImageSize = {Size:08X}'.format (Size = self.CapsuleImageSize)) > + print ('sizeof (Payload) = {Size:08X}'.format (Size = len (self.Payload))) > diff --git a/BaseTools/Source/Python/Common/Uefi/Capsule/__init__.py > b/BaseTools/Source/Python/Common/Uefi/Capsule/__init__.py > new file mode 100644 > index 0000000000..d9db4aa919 > --- /dev/null > +++ b/BaseTools/Source/Python/Common/Uefi/Capsule/__init__.py > @@ -0,0 +1,15 @@ > +## @file > +# Python 'Common.Uefi.Capsule' package initialization file. > +# > +# This file is required to make Python interpreter treat the directory > +# as containing package. > +# > +# Copyright (c) 2018, Intel Corporation. All rights reserved.<BR> > +# This program and the accompanying materials > +# are licensed and made available under the terms and conditions of the BSD License > +# which accompanies this distribution. The full text of the license may be found at > +# http://opensource.org/licenses/bsd-license.php > +# > +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, > +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. > +# > diff --git a/BaseTools/Source/Python/Common/Uefi/__init__.py b/BaseTools/Source/Python/Common/Uefi/__init__.py > new file mode 100644 > index 0000000000..d80219dcb3 > --- /dev/null > +++ b/BaseTools/Source/Python/Common/Uefi/__init__.py > @@ -0,0 +1,15 @@ > +## @file > +# Python 'Common.Uefi' package initialization file. > +# > +# This file is required to make Python interpreter treat the directory > +# as containing package. > +# > +# Copyright (c) 2018, Intel Corporation. All rights reserved.<BR> > +# This program and the accompanying materials > +# are licensed and made available under the terms and conditions of the BSD License > +# which accompanies this distribution. The full text of the license may be found at > +# http://opensource.org/licenses/bsd-license.php > +# > +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, > +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. > +# > -- > 2.14.2.windows.3 ^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [RFC 1/1] BaseTools/Capsule: Add Capsule Generation Tools 2018-05-31 14:25 ` Gao, Liming @ 2018-05-31 16:36 ` Kinney, Michael D 0 siblings, 0 replies; 4+ messages in thread From: Kinney, Michael D @ 2018-05-31 16:36 UTC (permalink / raw) To: Gao, Liming, edk2-devel@lists.01.org, Kinney, Michael D Cc: Sean Brogan, Yao, Jiewen, Zhu, Yonghong Liming, The C code was in the original content from MS_UEFI. It may be possible to update GenFds to use the new python modules. I have not investigated this yet. Mike > -----Original Message----- > From: Gao, Liming > Sent: Thursday, May 31, 2018 7:26 AM > To: Kinney, Michael D <michael.d.kinney@intel.com>; > edk2-devel@lists.01.org > Cc: Sean Brogan <sean.brogan@microsoft.com>; Yao, Jiewen > <jiewen.yao@intel.com>; Zhu, Yonghong > <yonghong.zhu@intel.com> > Subject: RE: [RFC 1/1] BaseTools/Capsule: Add Capsule > Generation Tools > > Mike: > Which C tool is converted? Does it support all capsule > generation functionality in GenFv tool? > > And, GenFds has the logic to generate FMP capsule. Can > they share same logic? > > Thanks > Liming > > -----Original Message----- > > From: Kinney, Michael D > > Sent: Wednesday, May 30, 2018 6:57 AM > > To: edk2-devel@lists.01.org > > Cc: Kinney, Michael D <michael.d.kinney@intel.com>; > Sean Brogan <sean.brogan@microsoft.com>; Yao, Jiewen > > <jiewen.yao@intel.com>; Zhu, Yonghong > <yonghong.zhu@intel.com>; Gao, Liming > <liming.gao@intel.com> > > Subject: [RFC 1/1] BaseTools/Capsule: Add Capsule > Generation Tools > > > > From: "Kinney, Michael D" <michael.d.kinney@intel.com> > > > > https://bugzilla.tianocore.org/show_bug.cgi?id=945 > > > > Based on content from the following branch > > > > > https://github.com/Microsoft/MS_UEFI/tree/share/beta/Cap > suleTools > > > > * Convert C tools to Python > > * Add common python modules to: > > BaseTools/Source/Python/Common/Uefi/Capsule > > BaseTools/Source/Python/Common/Edk2/Capsule > > * Add GenerateCapsule.py to > BaseTools/Source/Python/Capsule > > * Add Windows and Posix wrappers for > GenerateCapsule.py > > > > usage: GenerateCapsule [-h] [-o OUTPUTFILE] (-e | -d | > --dump-info) > > [--capflag > {PersistAcrossReset,PopulateSystemTable,InitiateReset}] > > [--capoemflag CAPSULEOEMFLAG] > [--guid GUID] > > [--hardware-instance > HARDWAREINSTANCE] > > [--monotonic-count > MONOTONICCOUNT] > > [--version FWVERSION] [--lsv > LOWESTSUPPORTEDVERSION] > > [--pfx-file SIGNTOOLPFXFILE] > > [--signer-private-cert > OPENSSLSIGNERPRIVATECERTFILE] > > [--other-public-cert > OPENSSLOTHERPUBLICCERTFILE] > > [--trusted-public-cert > OPENSSLTRUSTEDPUBLICCERTFILE] > > [--signing-tool-path > SIGNINGTOOLPATH] [-v] [-q] > > [--debug [0-9]] > > InputFile > > > > Generate a capsule. Copyright (c) 2018, Intel > Corporation. All rights > > reserved. > > > > positional arguments: > > InputFile Input binary payload filename. > > > > optional arguments: > > -h, --help show this help message and > exit > > -o OUTPUTFILE, --output OUTPUTFILE > > Output filename. > > -e, --encode Encode file > > -d, --decode Decode file > > --dump-info Display FMP Payload Header > information > > --capflag > {PersistAcrossReset,PopulateSystemTable,InitiateReset} > > Capsule flag can be > PersistAcrossReset, or > > PopulateSystemTable or > InitiateReset or not set > > --capoemflag CAPSULEOEMFLAG > > Capsule OEM Flag is an integer > between 0x0000 and > > 0xffff. > > --guid GUID The FMP/ESRT GUID in registry > format. Required for > > encode operations. > > --hardware-instance HARDWAREINSTANCE > > The 64-bit hardware instance. > The default is > > 0x0000000000000000 > > --monotonic-count MONOTONICCOUNT > > 64-bit monotonic count value > in header. Default is > > 0x0000000000000000. > > --version FWVERSION The 32-bit version of the > binary payload (e.g. > > 0x11223344 or 5678). > > --lsv LOWESTSUPPORTEDVERSION > > The 32-bit lowest supported > version of the binary > > payload (e.g. 0x11223344 or > 5678). > > --pfx-file SIGNTOOLPFXFILE > > signtool PFX certificate > filename. > > --signer-private-cert OPENSSLSIGNERPRIVATECERTFILE > > OpenSSL signer private > certificate filename. > > --other-public-cert OPENSSLOTHERPUBLICCERTFILE > > OpenSSL other public > certificate filename. > > --trusted-public-cert OPENSSLTRUSTEDPUBLICCERTFILE > > OpenSSL trusted public > certificate filename. > > --signing-tool-path SIGNINGTOOLPATH > > Path to signtool or Open SLL > tool. Optional if path to > > tools are already in PATH. > > -v, --verbose Increase output messages > > -q, --quiet Reduce output messages > > --debug [0-9] Set debug level > > > > Cc: Sean Brogan <sean.brogan@microsoft.com> > > Cc: Jiewen Yao <jiewen.yao@intel.com> > > Cc: Yonghong Zhu <yonghong.zhu@intel.com> > > Cc: Liming Gao <liming.gao@intel.com> > > Contributed-under: TianoCore Contribution Agreement > 1.1 > > Signed-off-by: Michael D Kinney > <michael.d.kinney@intel.com> > > --- > > BaseTools/BinWrappers/PosixLike/GenerateCapsule | > 14 + > > .../BinWrappers/WindowsLike/GenerateCapsule.bat | > 1 + > > BaseTools/Source/Python/Capsule/GenerateCapsule.py | > 500 +++++++++++++++++++++ > > .../Python/Common/Edk2/Capsule/FmpPayloadHeader.py | > 91 ++++ > > .../Source/Python/Common/Edk2/Capsule/__init__.py | > 15 + > > BaseTools/Source/Python/Common/Edk2/__init__.py | > 15 + > > .../Python/Common/Uefi/Capsule/FmpAuthHeader.py | > 184 ++++++++ > > .../Python/Common/Uefi/Capsule/FmpCapsuleHeader.py | > 302 +++++++++++++ > > .../Common/Uefi/Capsule/UefiCapsuleHeader.py | > 136 ++++++ > > .../Source/Python/Common/Uefi/Capsule/__init__.py | > 15 + > > BaseTools/Source/Python/Common/Uefi/__init__.py | > 15 + > > 11 files changed, 1288 insertions(+) > > create mode 100644 > BaseTools/BinWrappers/PosixLike/GenerateCapsule > > create mode 100644 > BaseTools/BinWrappers/WindowsLike/GenerateCapsule.bat > > create mode 100644 > BaseTools/Source/Python/Capsule/GenerateCapsule.py > > create mode 100644 > BaseTools/Source/Python/Common/Edk2/Capsule/FmpPayloadHe > ader.py > > create mode 100644 > BaseTools/Source/Python/Common/Edk2/Capsule/__init__.py > > create mode 100644 > BaseTools/Source/Python/Common/Edk2/__init__.py > > create mode 100644 > BaseTools/Source/Python/Common/Uefi/Capsule/FmpAuthHeade > r.py > > create mode 100644 > BaseTools/Source/Python/Common/Uefi/Capsule/FmpCapsuleHe > ader.py > > create mode 100644 > BaseTools/Source/Python/Common/Uefi/Capsule/UefiCapsuleH > eader.py > > create mode 100644 > BaseTools/Source/Python/Common/Uefi/Capsule/__init__.py > > create mode 100644 > BaseTools/Source/Python/Common/Uefi/__init__.py > > > > diff --git > a/BaseTools/BinWrappers/PosixLike/GenerateCapsule > b/BaseTools/BinWrappers/PosixLike/GenerateCapsule > > new file mode 100644 > > index 0000000000..59a6c8ba43 > > --- /dev/null > > +++ b/BaseTools/BinWrappers/PosixLike/GenerateCapsule > > @@ -0,0 +1,14 @@ > > +#!/usr/bin/env bash > > +#python `dirname $0`/RunToolFromSource.py `basename > $0` $* > > + > > +# If a python2 command is available, use it in > preference to python > > +if command -v python2 >/dev/null 2>&1; then > > + python_exe=python2 > > +fi > > + > > +full_cmd=${BASH_SOURCE:-$0} # see > http://mywiki.wooledge.org/BashFAQ/028 for a discussion > of why $0 is not a good choice here > > +dir=$(dirname "$full_cmd") > > +cmd=${full_cmd##*/} > > + > > +export > PYTHONPATH="$dir/../../Source/Python${PYTHONPATH:+:"$PYT > HONPATH"}" > > +exec "${python_exe:-python}" > "$dir/../../Source/Python/Capsule/$cmd.py" "$@" > > diff --git > a/BaseTools/BinWrappers/WindowsLike/GenerateCapsule.bat > b/BaseTools/BinWrappers/WindowsLike/GenerateCapsule.bat > > new file mode 100644 > > index 0000000000..ca442d181b > > --- /dev/null > > +++ > b/BaseTools/BinWrappers/WindowsLike/GenerateCapsule.bat > > @@ -0,0 +1 @@ > > +@%PYTHON_HOME%\python.exe > %BASE_TOOLS_PATH%\Source\Python\Capsule\GenerateCapsule. > py %* > > diff --git > a/BaseTools/Source/Python/Capsule/GenerateCapsule.py > b/BaseTools/Source/Python/Capsule/GenerateCapsule.py > > new file mode 100644 > > index 0000000000..32ab95c3e0 > > --- /dev/null > > +++ > b/BaseTools/Source/Python/Capsule/GenerateCapsule.py > > @@ -0,0 +1,500 @@ > > +## @file > > +# Generate a capsule. > > +# > > +# Copyright (c) 2018, Intel Corporation. All rights > reserved.<BR> > > +# This program and the accompanying materials > > +# are licensed and made available under the terms and > conditions of the BSD License > > +# which accompanies this distribution. The full text > of the license may be found at > > +# http://opensource.org/licenses/bsd-license.php > > +# > > +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON > AN "AS IS" BASIS, > > +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, > EITHER EXPRESS OR IMPLIED. > > +# > > + > > +''' > > +GenerateCapsule > > +''' > > + > > +import sys > > +import argparse > > +import uuid > > +import struct > > +import subprocess > > +import os > > +import tempfile > > +import shutil > > +from Common.Uefi.Capsule.UefiCapsuleHeader import > UefiCapsuleHeaderClass > > +from Common.Uefi.Capsule.FmpCapsuleHeader import > FmpCapsuleHeaderClass > > +from Common.Uefi.Capsule.FmpAuthHeader import > FmpAuthHeaderClass > > +from Common.Edk2.Capsule.FmpPayloadHeader import > FmpPayloadHeaderClass > > + > > +# > > +# Globals for help information > > +# > > +__prog__ = 'GenerateCapsule' > > +__copyright__ = 'Copyright (c) 2018, Intel > Corporation. All rights reserved.' > > +__description__ = 'Generate a capsule.\n' > > + > > +def SignPayloadSignTool (Payload, ToolPath, PfxFile): > > + # > > + # Create a temporary directory > > + # > > + TempDirectoryName = tempfile.mkdtemp() > > + > > + # > > + # Generate temp file name for the payload > contents > > + # > > + TempFileName = os.path.join (TempDirectoryName, > 'Payload.bin') > > + > > + # > > + # Create temporary payload file for signing > > + # > > + try: > > + File = open (TempFileName, mode='wb') > > + File.write (Payload) > > + File.close () > > + except: > > + shutil.rmtree (TempDirectoryName) > > + raise ValueError ('GenerateCapsule: error: > can not write temporary payload file.') > > + > > + # > > + # Build signtool command > > + # > > + if ToolPath is None: > > + ToolPath = '' > > + Command = '' > > + Command = Command + '"{Path}" '.format (Path = > os.path.join (ToolPath, 'signtool.exe')) > > + Command = Command + 'sign /fd sha256 /p7ce > DetachedSignedData /p7co 1.2.840.113549.1.7.2 ' > > + Command = Command + '/p7 {TempDir} '.format > (TempDir = TempDirectoryName) > > + Command = Command + '/f {PfxFile} '.format > (PfxFile = PfxFile) > > + Command = Command + TempFileName > > + > > + # > > + # Sign the input file using the specified private > key > > + # > > + try: > > + Process = subprocess.Popen (Command, stdin = > subprocess.PIPE, stdout = subprocess.PIPE, stderr = > subprocess.PIPE, shell = > > True) > > + Result = Process.communicate('') > > + except: > > + shutil.rmtree (TempDirectoryName) > > + raise ValueError ('GenerateCapsule: error: > can not run signtool.') > > + > > + if Process.returncode != 0: > > + shutil.rmtree (TempDirectoryName) > > + print (Result[1].decode()) > > + raise ValueError ('GenerateCapsule: error: > signtool failed.') > > + > > + # > > + # Read the signature from the generated output > file > > + # > > + try: > > + File = open (TempFileName + '.p7', mode='rb') > > + Signature = File.read () > > + File.close () > > + except: > > + shutil.rmtree (TempDirectoryName) > > + raise ValueError ('GenerateCapsule: error: > can not read signature file.') > > + > > + shutil.rmtree (TempDirectoryName) > > + return Signature > > + > > +def VerifyPayloadSignTool (Payload, CertData, > ToolPath, PfxFile): > > + print ('signtool verify is not supported.') > > + raise ValueError ('GenerateCapsule: error: > signtool verify is not supported.') > > + > > +def SignPayloadOpenSsl (Payload, ToolPath, > SignerPrivateCertFile, OtherPublicCertFile, > TrustedPublicCertFile): > > + # > > + # Build openssl command > > + # > > + if ToolPath is None: > > + ToolPath = '' > > + Command = '' > > + 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) > > + > > + # > > + # Sign the input file using the specified private > key and capture signature from STDOUT > > + # > > + try: > > + Process = subprocess.Popen (Command, stdin = > subprocess.PIPE, stdout = subprocess.PIPE, stderr = > subprocess.PIPE, shell = > > True) > > + Result = Process.communicate(input = Payload) > > + Signature = Result[0] > > + except: > > + raise ValueError ('GenerateCapsule: error: > can not run openssl.') > > + > > + if Process.returncode != 0: > > + print (Result[1].decode()) > > + raise ValueError ('GenerateCapsule: error: > openssl failed.') > > + > > + return Signature > > + > > +def VerifyPayloadOpenSsl (Payload, CertData, > ToolPath, SignerPrivateCertFile, OtherPublicCertFile, > TrustedPublicCertFile): > > + # > > + # Create a temporary directory > > + # > > + TempDirectoryName = tempfile.mkdtemp() > > + > > + # > > + # Generate temp file name for the payload > contents > > + # > > + TempFileName = os.path.join (TempDirectoryName, > 'Payload.bin') > > + > > + # > > + # Create temporary payload file for verification > > + # > > + try: > > + File = open (TempFileName, mode='wb') > > + File.write (Payload) > > + File.close () > > + except: > > + shutil.rmtree (TempDirectoryName) > > + raise ValueError ('GenerateCapsule: error: > can not write temporary payload file.') > > + > > + # > > + # Build openssl command > > + # > > + if ToolPath is None: > > + ToolPath = '' > > + Command = '' > > + 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) > > + > > + # > > + # Verify signature > > + # > > + try: > > + Process = subprocess.Popen (Command, stdin = > subprocess.PIPE, stdout = subprocess.PIPE, stderr = > subprocess.PIPE, shell = > > True) > > + Result = Process.communicate(input = > CertData) > > + except: > > + shutil.rmtree (TempDirectoryName) > > + raise ValueError ('GenerateCapsule: error: > can not run openssl.') > > + > > + if Process.returncode != 0: > > + shutil.rmtree (TempDirectoryName) > > + print (Result[1].decode()) > > + raise ValueError ('GenerateCapsule: error: > openssl failed.') > > + > > + shutil.rmtree (TempDirectoryName) > > + return Payload > > + > > +if __name__ == '__main__': > > + def convert_arg_line_to_args(arg_line): > > + for arg in arg_line.split(): > > + if not arg.strip(): > > + continue > > + yield arg > > + > > + def ValidateUnsignedInteger (Argument): > > + try: > > + Value = int (Argument, 0) > > + except: > > + Message = '{Argument} is not a valid > integer value.'.format (Argument = Argument) > > + raise argparse.ArgumentTypeError > (Message) > > + if Value < 0: > > + Message = '{Argument} is a negative > value.'.format (Argument = Argument) > > + raise argparse.ArgumentTypeError > (Message) > > + return Value > > + > > + def ValidateRegistryFormatGuid (Argument): > > + try: > > + Value = uuid.UUID (Argument) > > + except: > > + Message = '{Argument} is not a valid > registry format GUID value.'.format (Argument = > Argument) > > + raise argparse.ArgumentTypeError > (Message) > > + return Value > > + > > + # > > + # Create command line argument parser object > > + # > > + parser = argparse.ArgumentParser ( > > + prog = __prog__, > > + description = __description__ > + __copyright__, > > + conflict_handler = 'resolve', > > + fromfile_prefix_chars = '@' > > + ) > > + parser.convert_arg_line_to_args = > convert_arg_line_to_args > > + > > + # > > + # Add input and output file arguments > > + # > > + parser.add_argument("InputFile", type = > argparse.FileType('rb'), > > + help = "Input binary payload > filename.") > > + parser.add_argument("-o", "--output", dest = > 'OutputFile', type = argparse.FileType('wb'), > > + help = "Output filename.") > > + # > > + # Add group for -e and -d flags that are mutually > exclusive and required > > + # > > + group = parser.add_mutually_exclusive_group > (required = True) > > + group.add_argument ("-e", "--encode", dest = > 'Encode', action = "store_true", > > + help = "Encode file") > > + group.add_argument ("-d", "--decode", dest = > 'Decode', action = "store_true", > > + help = "Decode file") > > + group.add_argument ("--dump-info", dest = > 'DumpInfo', action = "store_true", > > + help = "Display FMP Payload > Header information") > > + # > > + # Add optional arguments for this command > > + # > > + parser.add_argument ("--capflag", dest = > 'CapsuleFlag', action='append', default = [], > > + > choices=['PersistAcrossReset', 'PopulateSystemTable', > 'InitiateReset'], > > + help = "Capsule flag can be > PersistAcrossReset, or PopulateSystemTable or > InitiateReset or not set") > > + parser.add_argument ("--capoemflag", dest = > 'CapsuleOemFlag', type = ValidateUnsignedInteger, > default = 0x0000, > > + 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.") > > + parser.add_argument ("--hardware-instance", dest > = 'HardwareInstance', type = ValidateUnsignedInteger, > default = > > 0x0000000000000000, > > + help = "The 64-bit hardware > instance. The default is 0x0000000000000000") > > + > > + > > + parser.add_argument ("--monotonic-count", dest = > 'MonotonicCount', type = ValidateUnsignedInteger, > default = > > 0x0000000000000000, > > + help = "64-bit monotonic > count value in header. Default is 0x0000000000000000.") > > + > > + parser.add_argument ("--version", dest = > 'FwVersion', type = ValidateUnsignedInteger, > > + help = "The 32-bit version > of the binary payload (e.g. 0x11223344 or 5678).") > > + parser.add_argument ("--lsv", dest = > 'LowestSupportedVersion', type = > ValidateUnsignedInteger, > > + help = "The 32-bit lowest > supported version of the binary payload (e.g. 0x11223344 > or 5678).") > > + > > + parser.add_argument ("--pfx-file", > dest='SignToolPfxFile', type=argparse.FileType('rb'), > > + help="signtool PFX > certificate filename.") > > + > > + parser.add_argument ("--signer-private-cert", > dest='OpenSslSignerPrivateCertFile', > type=argparse.FileType('rb'), > > + help="OpenSSL signer private > certificate filename.") > > + parser.add_argument ("--other-public-cert", > dest='OpenSslOtherPublicCertFile', > type=argparse.FileType('rb'), > > + help="OpenSSL other public > certificate filename.") > > + parser.add_argument ("--trusted-public-cert", > dest='OpenSslTrustedPublicCertFile', > type=argparse.FileType('rb'), > > + help="OpenSSL trusted public > certificate filename.") > > + > > + parser.add_argument ("--signing-tool-path", dest > = 'SigningToolPath', > > + help = "Path to signtool or > Open SLL tool. Optional if path to tools are already in > PATH.") > > + > > + # > > + # Add optional arguments common to all commands > > + # > > + parser.add_argument("-v", "--verbose", dest = > 'Verbose', action = "store_true", > > + help = "Increase output > messages") > > + parser.add_argument("-q", "--quiet", dest = > 'Quiet', action = "store_true", > > + help = "Reduce output > messages") > > + parser.add_argument("--debug", dest = 'Debug', > type = int, metavar = '[0-9]', choices = range(0,10), > default = 0, > > + help = "Set debug level") > > + > > + # > > + # Parse command line arguments > > + # > > + args = parser.parse_args() > > + > > + # > > + # Perform additional argument verification > > + # > > + if not args.DumpInfo and args.OutputFile is None: > > + parser.error ('the following arguments are > required for all commands except --dump-info: --output') > > + > > + if args.Encode and (args.Guid is None or > args.FwVersion is None or args.LowestSupportedVersion is > None): > > + parser.error ('the following arguments are > required: --version, --lsv, --guid') > > + > > + if not args.DumpInfo and not args.OutputFile: > > + parser.error ('the following arguments are > required: --output') > > + > > + if not args.DumpInfo: > > + if args.SignToolPfxFile is None and > args.OpenSslSignerPrivateCertFile is None and > args.OpenSslOtherPublicCertFile is None > > and args.OpenSslTrustedPublicCertFile is None: > > + parser.error ('certificate file arguments > are required: --pfx-file | [--signer-private-cert -- > other-public-cert > > --trusted-public-cert]') > > + > > + if args.SignToolPfxFile is not None: > > + if args.OpenSslSignerPrivateCertFile is not > None: > > + parser.error ('Providing both signtool > and OpenSSL options is not supported') > > + if args.OpenSslOtherPublicCertFile is not > None: > > + parser.error ('Providing both signtool > and OpenSSL options is not supported') > > + if args.OpenSslTrustedPublicCertFile is not > None: > > + parser.error ('Providing both signtool > and OpenSSL options is not supported') > > + args.SignToolPfxFile.close() > > + args.SignToolPfxFile = > args.SignToolPfxFile.name > > + > > + if not args.DumpInfo: > > + if args.SignToolPfxFile is None: > > + if args.OpenSslSignerPrivateCertFile is > None: > > + parser.error ('the following > arguments are required: --signer-private-cert') > > + if args.OpenSslOtherPublicCertFile is > None: > > + parser.error ('the following > arguments are required: --other-public-cert') > > + if args.OpenSslTrustedPublicCertFile is > None: > > + parser.error ('the following > arguments are required: --trusted-public-cert') > > + args.OpenSslSignerPrivateCertFile.close() > > + args.OpenSslOtherPublicCertFile.close() > > + args.OpenSslTrustedPublicCertFile.close() > > + args.OpenSslSignerPrivateCertFile = > args.OpenSslSignerPrivateCertFile.name > > + args.OpenSslOtherPublicCertFile = > args.OpenSslOtherPublicCertFile.name > > + args.OpenSslTrustedPublicCertFile = > args.OpenSslTrustedPublicCertFile.name > > + > > + # > > + # 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) > > + > > + # > > + # Create objects > > + # > > + UefiCapsuleHeader = UefiCapsuleHeaderClass () > > + FmpCapsuleHeader = FmpCapsuleHeaderClass () > > + FmpAuthHeader = FmpAuthHeaderClass () > > + FmpPayloadHeader = FmpPayloadHeaderClass () > > + > > + if args.Encode: > > + try: > > + FmpPayloadHeader.FwVersion = > args.FwVersion > > + FmpPayloadHeader.LowestSupportedVersion = > args.LowestSupportedVersion > > + FmpPayloadHeader.Payload = > Buffer > > + 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 args.SignToolPfxFile is not None: > > + 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') > > + raise > > + 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 = > 'PopulateSystemTable' in args.CapsuleFlag > > + 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 > > + Result = FmpAuthHeader.Decode (Result) > > + > > + # > > + # Verify Image with 64-bit MonotonicCount > appended to end of image > > + # > > + try: > > + if args.SignToolPfxFile is not None: > > + 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.') > > + > > + Result = FmpPayloadHeader.Decode (Result) > > + if args.Verbose: > > + print ('========') > > + UefiCapsuleHeader.DumpInfo () > > + print ('--------') > > + FmpCapsuleHeader.DumpInfo () > > + print ('--------') > > + FmpAuthHeader.DumpInfo () > > + print ('--------') > > + FmpPayloadHeader.DumpInfo () > > + print ('========') > > + except: > > + print ('GenerateCapsule: error: can not > decode capsule') > > + raise > > + sys.exit (1) > > + > > + elif args.DumpInfo: > > + try: > > + Result = UefiCapsuleHeader.Decode > (Buffer) > > + FmpCapsuleHeader.Decode (Result) > > + Result = > FmpCapsuleHeader.GetFmpCapsuleImageHeader (0).Payload > > + Result = FmpAuthHeader.Decode (Result) > > + Result = FmpPayloadHeader.Decode (Result) > > + > > + print ('========') > > + UefiCapsuleHeader.DumpInfo () > > + print ('--------') > > + FmpCapsuleHeader.DumpInfo () > > + print ('--------') > > + FmpAuthHeader.DumpInfo () > > + print ('--------') > > + FmpPayloadHeader.DumpInfo () > > + print ('========') > > + except: > > + print ('GenerateCapsule: error: can not > decode capsule') > > + sys.exit (1) > > + else: > > + print('GenerateCapsule: error: invalid > options') > > + sys.exit (1) > > + > > + # > > + # Write binary output file > > + # > > + 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.Verbose: > > + print('Success') > > diff --git > a/BaseTools/Source/Python/Common/Edk2/Capsule/FmpPayload > Header.py > > > b/BaseTools/Source/Python/Common/Edk2/Capsule/FmpPayload > Header.py > > new file mode 100644 > > index 0000000000..0ed51752d3 > > --- /dev/null > > +++ > b/BaseTools/Source/Python/Common/Edk2/Capsule/FmpPayload > Header.py > > @@ -0,0 +1,91 @@ > > +## @file > > +# Module that encodes and decodes a > FMP_PAYLOAD_HEADER with a payload. > > +# The FMP_PAYLOAD_HEADER is processed by the > FmpPayloadHeaderLib in the > > +# FmpDevicePkg. > > +# > > +# Copyright (c) 2018, Intel Corporation. All rights > reserved.<BR> > > +# This program and the accompanying materials > > +# are licensed and made available under the terms and > conditions of the BSD License > > +# which accompanies this distribution. The full text > of the license may be found at > > +# http://opensource.org/licenses/bsd-license.php > > +# > > +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON > AN "AS IS" BASIS, > > +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, > EITHER EXPRESS OR IMPLIED. > > +# > > + > > +''' > > +FmpPayloadHeader > > +''' > > + > > +import struct > > + > > +def _SIGNATURE_32 (A, B, C, D): > > + return struct.unpack ('=I',bytearray (A + B + C + > D, 'ascii'))[0] > > + > > +def _SIGNATURE_32_TO_STRING (Signature): > > + return struct.pack ("<I", Signature).decode () > > + > > +class FmpPayloadHeaderClass (object): > > + # > > + # typedef struct { > > + # UINT32 Signature; > > + # UINT32 HeaderSize; > > + # UINT32 FwVersion; > > + # UINT32 LowestSupportedVersion; > > + # } FMP_PAYLOAD_HEADER; > > + # > > + # #define FMP_PAYLOAD_HEADER_SIGNATURE > SIGNATURE_32 ('M', 'S', 'S', '1') > > + # > > + _StructFormat = '<IIII' > > + _StructSize = struct.calcsize (_StructFormat) > > + > > + _FMP_PAYLOAD_HEADER_SIGNATURE = _SIGNATURE_32 > ('M', 'S', 'S', '1') > > + > > + def __init__ (self): > > + self._Valid = False > > + self.Signature = > self._FMP_PAYLOAD_HEADER_SIGNATURE > > + self.HeaderSize = > self._StructSize > > + self.FwVersion = 0x00000000 > > + self.LowestSupportedVersion = 0x00000000 > > + self.Payload = b'' > > + > > + def Encode (self): > > + FmpPayloadHeader = struct.pack ( > > + > self._StructFormat, > > + self.Signature, > > + self.HeaderSize, > > + self.FwVersion, > > + > self.LowestSupportedVersion > > + ) > > + self._Valid = True > > + return FmpPayloadHeader + self.Payload > > + > > + def Decode (self, Buffer): > > + if len (Buffer) < self._StructSize: > > + raise ValueError > > + (Signature, HeaderSize, FwVersion, > LowestSupportedVersion) = \ > > + struct.unpack ( > > + self._StructFormat, > > + Buffer[0:self._StructSize] > > + ) > > + if Signature != > self._FMP_PAYLOAD_HEADER_SIGNATURE: > > + raise ValueError > > + if HeaderSize < self._StructSize: > > + raise ValueError > > + self.Signature = Signature > > + self.HeaderSize = HeaderSize > > + self.FwVersion = FwVersion > > + self.LowestSupportedVersion = > LowestSupportedVersion > > + self.Payload = > Buffer[self.HeaderSize:] > > + > > + self._Valid = True > > + return self.Payload > > + > > + def DumpInfo (self): > > + if not self._Valid: > > + raise ValueError > > + print ('FMP_PAYLOAD_HEADER.Signature > = {Signature:08X} ({SignatureString})'.format (Signature > = > > self.Signature, SignatureString = > _SIGNATURE_32_TO_STRING (self.Signature))) > > + print ('FMP_PAYLOAD_HEADER.HeaderSize > = {HeaderSize:08X}'.format (HeaderSize = > self.HeaderSize)) > > + print ('FMP_PAYLOAD_HEADER.FwVersion > = {FwVersion:08X}'.format (FwVersion = self.FwVersion)) > > + print > ('FMP_PAYLOAD_HEADER.LowestSupportedVersion = > {LowestSupportedVersion:08X}'.format > > (LowestSupportedVersion = > self.LowestSupportedVersion)) > > + print ('sizeof (Payload) > = {Size:08X}'.format (Size = len (self.Payload))) > > diff --git > a/BaseTools/Source/Python/Common/Edk2/Capsule/__init__.p > y > > > b/BaseTools/Source/Python/Common/Edk2/Capsule/__init__.p > y > > new file mode 100644 > > index 0000000000..71c6f06838 > > --- /dev/null > > +++ > b/BaseTools/Source/Python/Common/Edk2/Capsule/__init__.p > y > > @@ -0,0 +1,15 @@ > > +## @file > > +# Python 'Common.Edk2.Capsule' package initialization > file. > > +# > > +# This file is required to make Python interpreter > treat the directory > > +# as containing package. > > +# > > +# Copyright (c) 2018, Intel Corporation. All rights > reserved.<BR> > > +# This program and the accompanying materials > > +# are licensed and made available under the terms and > conditions of the BSD License > > +# which accompanies this distribution. The full text > of the license may be found at > > +# http://opensource.org/licenses/bsd-license.php > > +# > > +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON > AN "AS IS" BASIS, > > +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, > EITHER EXPRESS OR IMPLIED. > > +# > > diff --git > a/BaseTools/Source/Python/Common/Edk2/__init__.py > b/BaseTools/Source/Python/Common/Edk2/__init__.py > > new file mode 100644 > > index 0000000000..97d925cbf8 > > --- /dev/null > > +++ b/BaseTools/Source/Python/Common/Edk2/__init__.py > > @@ -0,0 +1,15 @@ > > +## @file > > +# Python 'Common.Edk2' package initialization file. > > +# > > +# This file is required to make Python interpreter > treat the directory > > +# as containing package. > > +# > > +# Copyright (c) 2018, Intel Corporation. All rights > reserved.<BR> > > +# This program and the accompanying materials > > +# are licensed and made available under the terms and > conditions of the BSD License > > +# which accompanies this distribution. The full text > of the license may be found at > > +# http://opensource.org/licenses/bsd-license.php > > +# > > +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON > AN "AS IS" BASIS, > > +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, > EITHER EXPRESS OR IMPLIED. > > +# > > diff --git > a/BaseTools/Source/Python/Common/Uefi/Capsule/FmpAuthHea > der.py > > > b/BaseTools/Source/Python/Common/Uefi/Capsule/FmpAuthHea > der.py > > new file mode 100644 > > index 0000000000..aec52bf772 > > --- /dev/null > > +++ > b/BaseTools/Source/Python/Common/Uefi/Capsule/FmpAuthHea > der.py > > @@ -0,0 +1,184 @@ > > +## @file > > +# 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> > > +# This program and the accompanying materials > > +# are licensed and made available under the terms and > conditions of the BSD License > > +# which accompanies this distribution. The full text > of the license may be found at > > +# http://opensource.org/licenses/bsd-license.php > > +# > > +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON > AN "AS IS" BASIS, > > +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, > EITHER EXPRESS OR IMPLIED. > > +# > > + > > +''' > > +FmpAuthHeader > > +''' > > + > > +import struct > > +import uuid > > + > > +class FmpAuthHeaderClass (object): > > + # /// > > + # /// Image Attribute -Authentication Required > > + # /// > > + # typedef struct { > > + # /// > > + # /// It is included in the signature of > AuthInfo. It is used to ensure freshness/no replay. > > + # /// It is incremented during each firmware > image operation. > > + # /// > > + # UINT64 > MonotonicCount; > > + # /// > > + # /// Provides the authorization for the > firmware image operations. It is a signature across > > + # /// the image data and the Monotonic Count > value. Caller uses the private key that is > > + # /// associated with a public key that has > been provisioned via the key exchange. > > + # /// Because this is defined as a signature, > WIN_CERTIFICATE_UEFI_GUID.CertType must > > + # /// be EFI_CERT_TYPE_PKCS7_GUID. > > + # /// > > + # WIN_CERTIFICATE_UEFI_GUID > AuthInfo; > > + # } EFI_FIRMWARE_IMAGE_AUTHENTICATION; > > + # > > + # /// > > + # /// Certificate which encapsulates a GUID- > specific digital signature > > + # /// > > + # typedef struct { > > + # /// > > + # /// This is the standard WIN_CERTIFICATE > header, where > > + # /// wCertificateType is set to > WIN_CERT_TYPE_EFI_GUID. > > + # /// > > + # WIN_CERTIFICATE Hdr; > > + # /// > > + # /// This is the unique id which determines > the > > + # /// format of the CertData. . > > + # /// > > + # EFI_GUID CertType; > > + # /// > > + # /// The following is the certificate data. > The format of > > + # /// the data is determined by the CertType. > > + # /// If CertType is > EFI_CERT_TYPE_RSA2048_SHA256_GUID, > > + # /// the CertData will be > EFI_CERT_BLOCK_RSA_2048_SHA256 structure. > > + # /// > > + # UINT8 CertData[1]; > > + # } WIN_CERTIFICATE_UEFI_GUID; > > + # > > + # /// > > + # /// The WIN_CERTIFICATE structure is part of > the PE/COFF specification. > > + # /// > > + # typedef struct { > > + # /// > > + # /// The length of the entire certificate, > > + # /// including the length of the header, in > bytes. > > + # /// > > + # UINT32 dwLength; > > + # /// > > + # /// The revision level of the WIN_CERTIFICATE > > + # /// structure. The current revision level is > 0x0200. > > + # /// > > + # UINT16 wRevision; > > + # /// > > + # /// The certificate type. See > WIN_CERT_TYPE_xxx for the UEFI > > + # /// certificate types. The UEFI specification > reserves the range of > > + # /// certificate type values from 0x0EF0 to > 0x0EFF. > > + # /// > > + # UINT16 wCertificateType; > > + # /// > > + # /// The following is the actual certificate. > The format of > > + # /// the certificate depends on > wCertificateType. > > + # /// > > + # /// UINT8 bCertificate[ANYSIZE_ARRAY]; > > + # /// > > + # } WIN_CERTIFICATE; > > + # > > + # #define WIN_CERT_TYPE_EFI_GUID 0x0EF1 > > + # > > + # /// > > + # /// This identifies a signature containing a > DER-encoded PKCS #7 version 1.5 [RFC2315] > > + # /// SignedData value. > > + # /// > > + # #define EFI_CERT_TYPE_PKCS7_GUID \ > > + # { \ > > + # 0x4aafd29d, 0x68df, 0x49ee, {0x8a, 0xa9, > 0x34, 0x7d, 0x37, 0x56, 0x65, 0xa7} \ > > + # } > > + > > + _StructFormat = '<QIHH16s' > > + _StructSize = struct.calcsize (_StructFormat) > > + > > + _MonotonicCountFormat = '<Q' > > + _MonotonicCountSize = struct.calcsize > (_MonotonicCountFormat) > > + > > + _StructAuthInfoFormat = '<IHH16s' > > + _StructAuthInfoSize = struct.calcsize > (_StructAuthInfoFormat) > > + > > + _WIN_CERT_REVISION = 0x0200 > > + _WIN_CERT_TYPE_EFI_GUID = 0x0EF1 > > + _EFI_CERT_TYPE_PKCS7_GUID = uuid.UUID ('4aafd29d- > 68df-49ee-8aa9-347d375665a7') > > + > > + def __init__ (self): > > + self._Valid = False > > + self.MonotonicCount = 0 > > + self.dwLength = > self._StructAuthInfoSize > > + self.wRevision = > self._WIN_CERT_REVISION > > + self.wCertificateType = > self._WIN_CERT_TYPE_EFI_GUID > > + self.CertType = > self._EFI_CERT_TYPE_PKCS7_GUID > > + self.CertData = b'' > > + self.Payload = b'' > > + > > + > > + def Encode (self): > > + if self.wRevision != self._WIN_CERT_REVISION: > > + raise ValueError > > + if self.wCertificateType != > self._WIN_CERT_TYPE_EFI_GUID: > > + raise ValueError > > + if self.CertType != > self._EFI_CERT_TYPE_PKCS7_GUID: > > + raise ValueError > > + self.dwLength = self._StructAuthInfoSize + > len (self.CertData) > > + > > + FmpAuthHeader = struct.pack ( > > + self._StructFormat, > > + self.MonotonicCount, > > + self.dwLength, > > + self.wRevision, > > + > self.wCertificateType, > > + > self.CertType.bytes_le > > + ) > > + self._Valid = True > > + > > + return FmpAuthHeader + self.CertData + > self.Payload > > + > > + def Decode (self, Buffer): > > + if len (Buffer) < self._StructSize: > > + raise ValueError > > + (MonotonicCount, dwLength, wRevision, > wCertificateType, CertType) = \ > > + struct.unpack ( > > + self._StructFormat, > > + Buffer[0:self._StructSize] > > + ) > > + if dwLength < self._StructAuthInfoSize: > > + raise ValueError > > + if wRevision != self._WIN_CERT_REVISION: > > + raise ValueError > > + if wCertificateType != > self._WIN_CERT_TYPE_EFI_GUID: > > + raise ValueError > > + if CertType != > self._EFI_CERT_TYPE_PKCS7_GUID.bytes_le: > > + raise ValueError > > + self.MonotonicCount = MonotonicCount > > + self.dwLength = dwLength > > + self.wRevision = wRevision > > + self.wCertificateType = wCertificateType > > + self.CertType = uuid.UUID (bytes = > CertType) > > + self.CertData = > Buffer[self._StructSize:self._MonotonicCountSize + > self.dwLength] > > + self.Payload = > Buffer[self._MonotonicCountSize + self.dwLength:] > > + self._Valid = True > > + return self.Payload > > + > > + def DumpInfo (self): > > + if not self._Valid: > > + raise ValueError > > + print > ('EFI_FIRMWARE_IMAGE_AUTHENTICATION.MonotonicCount > = {MonotonicCount:016X}'.format > > (MonotonicCount = self.MonotonicCount)) > > + print > ('EFI_FIRMWARE_IMAGE_AUTHENTICATION.AuthInfo.Hdr.dwLengt > h = {dwLength:08X}'.format (dwLength = > > self.dwLength)) > > + print > ('EFI_FIRMWARE_IMAGE_AUTHENTICATION.AuthInfo.Hdr.wRevisi > on = {wRevision:04X}'.format (wRevision = > > self.wRevision)) > > + print > ('EFI_FIRMWARE_IMAGE_AUTHENTICATION.AuthInfo.Hdr.wCertif > icateType = {wCertificateType:04X}'.format > > (wCertificateType = self.wCertificateType)) > > + print > ('EFI_FIRMWARE_IMAGE_AUTHENTICATION.AuthInfo.CertType > = {Guid}'.format (Guid = > > str(self.CertType).upper())) > > + print ('sizeof > (EFI_FIRMWARE_IMAGE_AUTHENTICATION.AuthInfo.CertData) > = {Size:08X}'.format (Size = len > > (self.CertData))) > > + print ('sizeof (Payload) > = {Size:08X}'.format (Size = len > > (self.Payload))) > > diff --git > a/BaseTools/Source/Python/Common/Uefi/Capsule/FmpCapsule > Header.py > > > b/BaseTools/Source/Python/Common/Uefi/Capsule/FmpCapsule > Header.py > > new file mode 100644 > > index 0000000000..2461fb5068 > > --- /dev/null > > +++ > b/BaseTools/Source/Python/Common/Uefi/Capsule/FmpCapsule > Header.py > > @@ -0,0 +1,302 @@ > > +## @file > > +# Module that encodes and decodes a > EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER with > > +# a payload. > > +# > > +# Copyright (c) 2018, Intel Corporation. All rights > reserved.<BR> > > +# This program and the accompanying materials > > +# are licensed and made available under the terms and > conditions of the BSD License > > +# which accompanies this distribution. The full text > of the license may be found at > > +# http://opensource.org/licenses/bsd-license.php > > +# > > +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON > AN "AS IS" BASIS, > > +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, > EITHER EXPRESS OR IMPLIED. > > +# > > + > > +''' > > +FmpCapsuleHeader > > +''' > > + > > +import struct > > +import uuid > > + > > +class FmpCapsuleImageHeaderClass (object): > > + # typedef struct { > > + # UINT32 Version; > > + # > > + # /// > > + # /// Used to identify device firmware targeted > by this update. This guid is matched by > > + # /// system firmware against ImageTypeId field > within a EFI_FIRMWARE_IMAGE_DESCRIPTOR > > + # /// > > + # EFI_GUID UpdateImageTypeId; > > + # > > + # /// > > + # /// Passed as ImageIndex in call to > EFI_FIRMWARE_MANAGEMENT_PROTOCOL.SetImage () > > + # /// > > + # UINT8 UpdateImageIndex; > > + # UINT8 reserved_bytes[3]; > > + # > > + # /// > > + # /// Size of the binary update image which > immediately follows this structure > > + # /// > > + # UINT32 UpdateImageSize; > > + # > > + # /// > > + # /// Size of the VendorCode bytes which > optionally immediately follow binary update image in the > capsule > > + # /// > > + # UINT32 UpdateVendorCodeSize; > > + # > > + # /// > > + # /// The HardwareInstance to target with this > update. If value is zero it means match all > > + # /// HardwareInstances. This field allows > update software to target only a single device in > > + # /// cases where there are more than one > device with the same ImageTypeId GUID. > > + # /// This header is outside the signed data of > the Authentication Info structure and > > + # /// therefore can be modified without > changing the Auth data. > > + # /// > > + # UINT64 UpdateHardwareInstance; > > + # } EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER; > > + # > > + # #define > EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSIO > N 0x00000002 > > + > > + _StructFormat = '<I16sB3BIIQ' > > + _StructSize = struct.calcsize (_StructFormat) > > + > > + > EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSIO > N = 0x00000002 > > + > > + def __init__ (self): > > + self._Valid = False > > + self.Version = > self.EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_V > ERSION > > + self.UpdateImageTypeId = uuid.UUID > ('00000000-0000-0000-0000-000000000000') > > + self.UpdateImageIndex = 0 > > + self.UpdateImageSize = 0 > > + self.UpdateVendorCodeSize = 0 > > + self.UpdateHardwareInstance = > 0x0000000000000000 > > + self.Payload = b'' > > + self.VendorCodeBytes = b'' > > + > > + def Encode (self): > > + self.UpdateImageSize = len > (self.Payload) > > + self.UpdateVendorCodeSize = len > (self.VendorCodeBytes) > > + FmpCapsuleImageHeader = struct.pack ( > > + > self._StructFormat, > > + > self.Version, > > + > self.UpdateImageTypeId.bytes_le, > > + > self.UpdateImageIndex, > > + 0,0,0, > > + > self.UpdateImageSize, > > + > self.UpdateVendorCodeSize, > > + > self.UpdateHardwareInstance > > + ) > > + self._Valid = True > > + return FmpCapsuleImageHeader + self.Payload + > self.VendorCodeBytes > > + > > + def Decode (self, Buffer): > > + if len (Buffer) < self._StructSize: > > + raise ValueError > > + (Version, UpdateImageTypeId, > UpdateImageIndex, r0, r1, r2, UpdateImageSize, > UpdateVendorCodeSize, > > UpdateHardwareInstance) = \ > > + struct.unpack ( > > + self._StructFormat, > > + Buffer[0:self._StructSize] > > + ) > > + > > + if Version < > self.EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_V > ERSION: > > + raise ValueError > > + if UpdateImageIndex < 1: > > + raise ValueError > > + if UpdateImageSize + UpdateVendorCodeSize != > len (Buffer[self._StructSize:]): > > + raise ValueError > > + > > + self.Version = Version > > + self.UpdateImageTypeId = uuid.UUID > (bytes_le = UpdateImageTypeId) > > + self.UpdateImageIndex = > UpdateImageIndex > > + self.UpdateImageSize = UpdateImageSize > > + self.UpdateVendorCodeSize = > UpdateVendorCodeSize > > + self.UpdateHardwareInstance = > UpdateHardwareInstance > > + self.Payload = > Buffer[self._StructSize:self._StructSize + > UpdateImageSize] > > + self.VendorCodeBytes = > Buffer[self._StructSize + UpdateImageSize:] > > + self._Valid = True > > + return Buffer[self._StructSize:] > > + > > + def DumpInfo (self): > > + if not self._Valid: > > + raise ValueError > > + print > ('EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER.Version > = {Version:08X}'.format > > (Version = self.Version)) > > + print > ('EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER.UpdateIma > geTypeId = > > {UpdateImageTypeId}'.format (UpdateImageTypeId = > str(self.UpdateImageTypeId).upper())) > > + print > ('EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER.UpdateIma > geIndex = > > {UpdateImageIndex:08X}'.format (UpdateImageIndex = > self.UpdateImageIndex)) > > + print > ('EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER.UpdateIma > geSize = > > {UpdateImageSize:08X}'.format (UpdateImageSize = > self.UpdateImageSize)) > > + print > ('EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER.UpdateVen > dorCodeSize = > > {UpdateVendorCodeSize:08X}'.format > (UpdateVendorCodeSize = self.UpdateVendorCodeSize)) > > + print > ('EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER.UpdateHar > dwareInstance = > > {UpdateHardwareInstance:016X}'.format > (UpdateHardwareInstance = self.UpdateHardwareInstance)) > > + print ('sizeof (Payload) > = {Size:08X}'.format (Size = len > > (self.Payload))) > > + print ('sizeof (VendorCodeBytes) > = {Size:08X}'.format (Size = len > > (self.VendorCodeBytes))) > > + > > +class FmpCapsuleHeaderClass (object): > > + # typedef struct { > > + # UINT32 Version; > > + # > > + # /// > > + # /// The number of drivers included in the > capsule and the number of corresponding > > + # /// offsets stored in ItemOffsetList array. > > + # /// > > + # UINT16 EmbeddedDriverCount; > > + # > > + # /// > > + # /// The number of payload items included in > the capsule and the number of > > + # /// corresponding offsets stored in the > ItemOffsetList array. > > + # /// > > + # UINT16 PayloadItemCount; > > + # > > + # /// > > + # /// Variable length array of dimension > [EmbeddedDriverCount + PayloadItemCount] > > + # /// containing offsets of each of the drivers > and payload items contained within the capsule > > + # /// > > + # // UINT64 ItemOffsetList[]; > > + # } EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER; > > + # > > + # #define > EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION > 0x00000001 > > + _StructFormat = '<IHH' > > + _StructSize = struct.calcsize (_StructFormat) > > + > > + _ItemOffsetFormat = '<Q' > > + _ItemOffsetSize = struct.calcsize > (_ItemOffsetFormat) > > + > > + > EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION = > 0x00000001 > > + > > + def __init__ (self): > > + self._Valid = False > > + self.Version = > self.EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION > > + self.EmbeddedDriverCount = 0 > > + self.PayloadItemCount = 0 > > + self._ItemOffsetList = [] > > + self._EmbeddedDriverList = [] > > + self._PayloadList = [] > > + self._FmpCapsuleImageHeaderList = [] > > + > > + def AddEmbeddedDriver (self, EmbeddedDriver): > > + self._EmbeddedDriverList.append > (EmbeddedDriver) > > + > > + def GetEmbeddedDriver (self, Index): > > + if Index > len (self._EmbeddedDriverList): > > + raise ValueError > > + return self._EmbeddedDriverList[Index] > > + > > + def AddPayload (self, UpdateImageTypeId, Payload > = b'', VendorCodeBytes = b'', HardwareInstance = 0): > > + self._PayloadList.append ((UpdateImageTypeId, > Payload, VendorCodeBytes, HardwareInstance)) > > + > > + def GetFmpCapsuleImageHeader (self, Index): > > + if Index >= len > (self._FmpCapsuleImageHeaderList): > > + raise ValueError > > + return self._FmpCapsuleImageHeaderList[Index] > > + > > + def Encode (self): > > + self.EmbeddedDriverCount = len > (self._EmbeddedDriverList) > > + self.PayloadItemCount = len > (self._PayloadList) > > + > > + FmpCapsuleHeader = struct.pack ( > > + > self._StructFormat, > > + self.Version, > > + > self.EmbeddedDriverCount, > > + > self.PayloadItemCount > > + ) > > + > > + FmpCapsuleData = b'' > > + Offset = self._StructSize + > (self.EmbeddedDriverCount + self.PayloadItemCount) * > self._ItemOffsetSize > > + for EmbeddedDriver in > self._EmbeddedDriverList: > > + FmpCapsuleData = FmpCapsuleData + > EmbeddedDriver > > + self._ItemOffsetList.append (Offset) > > + Offset = Offset + len (EmbeddedDriver) > > + Index = 1 > > + for (UpdateImageTypeId, Payload, > VendorCodeBytes, HardwareInstance) in self._PayloadList: > > + FmpCapsuleImageHeader = > FmpCapsuleImageHeaderClass () > > + FmpCapsuleImageHeader.UpdateImageTypeId > = UpdateImageTypeId > > + FmpCapsuleImageHeader.UpdateImageIndex > = Index > > + FmpCapsuleImageHeader.Payload > = Payload > > + FmpCapsuleImageHeader.VendorCodeBytes > = VendorCodeBytes > > + > FmpCapsuleImageHeader.UpdateHardwareInstance = > HardwareInstance > > + FmpCapsuleImage = > FmpCapsuleImageHeader.Encode () > > + FmpCapsuleData = FmpCapsuleData + > FmpCapsuleImage > > + > > + self._ItemOffsetList.append (Offset) > > + self._FmpCapsuleImageHeaderList.append > (FmpCapsuleImageHeader) > > + > > + Offset = Offset + len (FmpCapsuleImage) > > + Index = Index + 1 > > + > > + for Offset in self._ItemOffsetList: > > + FmpCapsuleHeader = FmpCapsuleHeader + > struct.pack (self._ItemOffsetFormat, Offset) > > + > > + self._Valid = True > > + return FmpCapsuleHeader + FmpCapsuleData > > + > > + def Decode (self, Buffer): > > + if len (Buffer) < self._StructSize: > > + raise ValueError > > + (Version, EmbeddedDriverCount, > PayloadItemCount) = \ > > + struct.unpack ( > > + self._StructFormat, > > + Buffer[0:self._StructSize] > > + ) > > + if Version < > self.EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION > : > > + raise ValueError > > + > > + self.Version = Version > > + self.EmbeddedDriverCount = > EmbeddedDriverCount > > + self.PayloadItemCount = > PayloadItemCount > > + self._ItemOffsetList = [] > > + self._EmbeddedDriverList = [] > > + self._PayloadList = [] > > + self._FmpCapsuleImageHeaderList = [] > > + > > + # > > + # Parse the ItemOffsetList values > > + # > > + Offset = self._StructSize > > + for Index in range (0, EmbeddedDriverCount + > PayloadItemCount): > > + ItemOffset = struct.unpack > (self._ItemOffsetFormat, Buffer[Offset:Offset + > self._ItemOffsetSize])[0] > > + if ItemOffset >= len (Buffer): > > + raise ValueError > > + self._ItemOffsetList.append (ItemOffset) > > + Offset = Offset + self._ItemOffsetSize > > + Result = Buffer[Offset:] > > + > > + # > > + # Parse the EmbeddedDrivers > > + # > > + for Index in range (0, EmbeddedDriverCount): > > + Offset = self._ItemOffsetList[Index] > > + if Index < (len (self._ItemOffsetList) - > 1): > > + Length = self._ItemOffsetList[Index + > 1] - Offset > > + else: > > + Length = len (Buffer) - Offset > > + self.AddEmbeddedDriver > (Buffer[Offset:Offset + Length]) > > + > > + # > > + # Parse the Payloads that are FMP Capsule > Images > > + # > > + for Index in range (EmbeddedDriverCount, > EmbeddedDriverCount + PayloadItemCount): > > + Offset = self._ItemOffsetList[Index] > > + if Index < (len (self._ItemOffsetList) - > 1): > > + Length = self._ItemOffsetList[Index + > 1] - Offset > > + else: > > + Length = len (Buffer) - Offset > > + FmpCapsuleImageHeader = > FmpCapsuleImageHeaderClass () > > + FmpCapsuleImageHeader.Decode > (Buffer[Offset:Offset + Length]) > > + self.AddPayload ( > > + > FmpCapsuleImageHeader.UpdateImageTypeId, > > + FmpCapsuleImageHeader.Payload, > > + > FmpCapsuleImageHeader.VendorCodeBytes > > + ) > > + self._FmpCapsuleImageHeaderList.append > (FmpCapsuleImageHeader) > > + > > + self._Valid = True > > + return Result > > + > > + def DumpInfo (self): > > + if not self._Valid: > > + raise ValueError > > + print > ('EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER.Version > = {Version:08X}'.format (Version = > > self.Version)) > > + print > ('EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER.EmbeddedDriverC > ount = {EmbeddedDriverCount:08X}'.format > > (EmbeddedDriverCount = self.EmbeddedDriverCount)) > > + print > ('EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER.PayloadItemCoun > t = {PayloadItemCount:08X}'.format > > (PayloadItemCount = self.PayloadItemCount)) > > + print > ('EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER.ItemOffsetList > = ') > > + for Offset in self._ItemOffsetList: > > + print (' {Offset:016X}'.format (Offset = > Offset)) > > + for FmpCapsuleImageHeader in > self._FmpCapsuleImageHeaderList: > > + FmpCapsuleImageHeader.DumpInfo () > > diff --git > a/BaseTools/Source/Python/Common/Uefi/Capsule/UefiCapsul > eHeader.py > > > b/BaseTools/Source/Python/Common/Uefi/Capsule/UefiCapsul > eHeader.py > > new file mode 100644 > > index 0000000000..cfe1cb6c46 > > --- /dev/null > > +++ > b/BaseTools/Source/Python/Common/Uefi/Capsule/UefiCapsul > eHeader.py > > @@ -0,0 +1,136 @@ > > +## @file > > +# Module that encodes and decodes a > EFI_CAPSULE_HEADER with a payload > > +# > > +# Copyright (c) 2018, Intel Corporation. All rights > reserved.<BR> > > +# This program and the accompanying materials > > +# are licensed and made available under the terms and > conditions of the BSD License > > +# which accompanies this distribution. The full text > of the license may be found at > > +# http://opensource.org/licenses/bsd-license.php > > +# > > +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON > AN "AS IS" BASIS, > > +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, > EITHER EXPRESS OR IMPLIED. > > +# > > + > > +''' > > +UefiCapsuleHeader > > +''' > > + > > +import struct > > +import uuid > > + > > +class UefiCapsuleHeaderClass (object): > > + # typedef struct { > > + # /// > > + # /// A GUID that defines the contents of a > capsule. > > + # /// > > + # EFI_GUID CapsuleGuid; > > + # /// > > + # /// The size of the capsule header. This may > be larger than the size of > > + # /// the EFI_CAPSULE_HEADER since CapsuleGuid > may imply > > + # /// extended header entries > > + # /// > > + # UINT32 HeaderSize; > > + # /// > > + # /// Bit-mapped list describing the capsule > attributes. The Flag values > > + # /// of 0x0000 - 0xFFFF are defined by > CapsuleGuid. Flag values > > + # /// of 0x10000 - 0xFFFFFFFF are defined by > this specification > > + # /// > > + # UINT32 Flags; > > + # /// > > + # /// Size in bytes of the capsule. > > + # /// > > + # UINT32 CapsuleImageSize; > > + # } EFI_CAPSULE_HEADER; > > + # > > + # #define CAPSULE_FLAGS_PERSIST_ACROSS_RESET > 0x00010000 > > + # #define CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE > 0x00020000 > > + # #define CAPSULE_FLAGS_INITIATE_RESET > 0x00040000 > > + # > > + _StructFormat = '<16sIIII' > > + _StructSize = struct.calcsize (_StructFormat) > > + > > + EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID = > uuid.UUID ('6DCBD5ED-E82D-4C44-BDA1-7194199AD92A') > > + > > + _CAPSULE_FLAGS_PERSIST_ACROSS_RESET = 0x00010000 > > + _CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE = 0x00020000 > > + _CAPSULE_FLAGS_INITIATE_RESET = 0x00040000 > > + > > + def __init__ (self): > > + self._Valid = False > > + self.CapsuleGuid = > self.EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID > > + self.HeaderSize = self._StructSize > > + self.OemFlags = 0x0000 > > + self.PersistAcrossReset = False > > + self.PopulateSystemTable = False > > + self.InitiateReset = False > > + self.CapsuleImageSize = self.HeaderSize > > + self.Payload = b'' > > + > > + def Encode (self): > > + Flags = self.OemFlags > > + if self.PersistAcrossReset: > > + Flags = Flags | > self._CAPSULE_FLAGS_PERSIST_ACROSS_RESET > > + if self.PopulateSystemTable: > > + Flags = Flags | > self._CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE > > + if self.InitiateReset: > > + Flags = Flags | > self._CAPSULE_FLAGS_INITIATE_RESET > > + > > + self.CapsuleImageSize = self.HeaderSize + len > (self.Payload) > > + > > + UefiCapsuleHeader = struct.pack ( > > + > self._StructFormat, > > + > self.CapsuleGuid.bytes_le, > > + self.HeaderSize, > > + Flags, > > + > self.CapsuleImageSize, > > + 0 > > + ) > > + self._Valid = True > > + return UefiCapsuleHeader + self.Payload > > + > > + def Decode (self, Buffer): > > + if len (Buffer) < self._StructSize: > > + raise ValueError > > + (CapsuleGuid, HeaderSize, Flags, > CapsuleImageSize, Reserved) = \ > > + struct.unpack ( > > + self._StructFormat, > > + Buffer[0:self._StructSize] > > + ) > > + if HeaderSize < self._StructSize: > > + raise ValueError > > + if CapsuleImageSize != len (Buffer): > > + raise ValueError > > + self.CapsuleGuid = uuid.UUID > (bytes_le = CapsuleGuid) > > + self.HeaderSize = HeaderSize > > + self.OemFlags = Flags & 0xffff > > + self.PersistAcrossReset = (Flags & > self._CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0 > > + self.PopulateSystemTable = (Flags & > self._CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) != 0 > > + self.InitiateReset = (Flags & > self._CAPSULE_FLAGS_INITIATE_RESET) != 0 > > + self.CapsuleImageSize = CapsuleImageSize > > + self.Payload = > Buffer[self.HeaderSize:] > > + > > + self._Valid = True > > + return self.Payload > > + > > + def DumpInfo (self): > > + if not self._Valid: > > + raise ValueError > > + Flags = self.OemFlags > > + if self.PersistAcrossReset: > > + Flags = Flags | > self._CAPSULE_FLAGS_PERSIST_ACROSS_RESET > > + if self.PopulateSystemTable: > > + Flags = Flags | > self._CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE > > + if self.InitiateReset: > > + Flags = Flags | > self._CAPSULE_FLAGS_INITIATE_RESET > > + print ('EFI_CAPSULE_HEADER.CapsuleGuid = > {Guid}'.format (Guid = str(self.CapsuleGuid).upper())) > > + print ('EFI_CAPSULE_HEADER.HeaderSize = > {Size:08X}'.format (Size = self.HeaderSize)) > > + print ('EFI_CAPSULE_HEADER.Flags = > {Flags:08X}'.format (Flags = Flags)) > > + print (' OEM Flags = > {Flags:04X}'.format (Flags = self.OemFlags)) > > + if self.PersistAcrossReset: > > + print (' > CAPSULE_FLAGS_PERSIST_ACROSS_RESET') > > + if self.PopulateSystemTable: > > + print (' > CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE') > > + if self.InitiateReset: > > + print (' CAPSULE_FLAGS_INITIATE_RESET') > > + print ('EFI_CAPSULE_HEADER.CapsuleImageSize = > {Size:08X}'.format (Size = self.CapsuleImageSize)) > > + print ('sizeof (Payload) = > {Size:08X}'.format (Size = len (self.Payload))) > > diff --git > a/BaseTools/Source/Python/Common/Uefi/Capsule/__init__.p > y > > > b/BaseTools/Source/Python/Common/Uefi/Capsule/__init__.p > y > > new file mode 100644 > > index 0000000000..d9db4aa919 > > --- /dev/null > > +++ > b/BaseTools/Source/Python/Common/Uefi/Capsule/__init__.p > y > > @@ -0,0 +1,15 @@ > > +## @file > > +# Python 'Common.Uefi.Capsule' package initialization > file. > > +# > > +# This file is required to make Python interpreter > treat the directory > > +# as containing package. > > +# > > +# Copyright (c) 2018, Intel Corporation. All rights > reserved.<BR> > > +# This program and the accompanying materials > > +# are licensed and made available under the terms and > conditions of the BSD License > > +# which accompanies this distribution. The full text > of the license may be found at > > +# http://opensource.org/licenses/bsd-license.php > > +# > > +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON > AN "AS IS" BASIS, > > +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, > EITHER EXPRESS OR IMPLIED. > > +# > > diff --git > a/BaseTools/Source/Python/Common/Uefi/__init__.py > b/BaseTools/Source/Python/Common/Uefi/__init__.py > > new file mode 100644 > > index 0000000000..d80219dcb3 > > --- /dev/null > > +++ b/BaseTools/Source/Python/Common/Uefi/__init__.py > > @@ -0,0 +1,15 @@ > > +## @file > > +# Python 'Common.Uefi' package initialization file. > > +# > > +# This file is required to make Python interpreter > treat the directory > > +# as containing package. > > +# > > +# Copyright (c) 2018, Intel Corporation. All rights > reserved.<BR> > > +# This program and the accompanying materials > > +# are licensed and made available under the terms and > conditions of the BSD License > > +# which accompanies this distribution. The full text > of the license may be found at > > +# http://opensource.org/licenses/bsd-license.php > > +# > > +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON > AN "AS IS" BASIS, > > +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, > EITHER EXPRESS OR IMPLIED. > > +# > > -- > > 2.14.2.windows.3 ^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2018-05-31 16:36 UTC | newest] Thread overview: 4+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2018-05-29 22:56 [RFC 0/1] Add Capsule Generation Tools Michael D Kinney 2018-05-29 22:56 ` [RFC 1/1] BaseTools/Capsule: " Michael D Kinney 2018-05-31 14:25 ` Gao, Liming 2018-05-31 16:36 ` Kinney, Michael D
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox