BaseTools/Capsule: Add Capsule Generation Tools

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]
                       [--fw-version FWVERSION] [--lsv LOWESTSUPPORTEDVERSION]
                       [--pfx-file SIGNTOOLPFXFILE]
                       [--signer-private-cert OPENSSLSIGNERPRIVATECERTFILE]
                       [--other-public-cert OPENSSLOTHERPUBLICCERTFILE]
                       [--trusted-public-cert OPENSSLTRUSTEDPUBLICCERTFILE]
                       [--signing-tool-path SIGNINGTOOLPATH] [--version] [-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.
  --fw-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 OpenSSL tool. Optional if path to
                        tools are already in PATH.
  --version             show program's version number and exit
  -v, --verbose         Turn on verbose output with informational messages
                        printed, including capsule headers and warning
                        messages.
  -q, --quiet           Disable all messages except fatal errors.
  --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>
Reviewed-by: Yonghong Zhu <yonghong.zhu@intel.com>
This commit is contained in:
Kinney, Michael D 2018-05-01 20:54:46 -07:00
parent 3a0c1bf64b
commit 8b63877aca
11 changed files with 1310 additions and 0 deletions

View File

@ -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" "$@"

View File

@ -0,0 +1 @@
@%PYTHON_HOME%\python.exe %BASE_TOOLS_PATH%\Source\Python\Capsule\GenerateCapsule.py %*

View File

@ -0,0 +1,522 @@
## @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
import platform
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'
__version__ = '0.9'
__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 ("--fw-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 OpenSSL tool. Optional if path to tools are already in PATH.")
#
# Add optional arguments common to all operations
#
parser.add_argument ('--version', action='version', version='%(prog)s ' + __version__)
parser.add_argument ("-v", "--verbose", dest = 'Verbose', action = "store_true",
help = "Turn on verbose output with informational messages printed, including capsule headers and warning messages.")
parser.add_argument ("-q", "--quiet", dest = 'Quiet', action = "store_true",
help = "Disable all messages except fatal errors.")
parser.add_argument ("--debug", dest = 'Debug', type = int, metavar = '[0-9]', choices = range (0, 10), default = 0,
help = "Set debug level")
#
# Parse command line arguments
#
args = parser.parse_args()
#
# Perform additional argument verification
#
if args.Encode:
if args.Guid is None:
parser.error ('the following option is required: --guid')
if 'PersistAcrossReset' not in args.CapsuleFlag:
if 'PopulateSystemTable' in args.CapsuleFlag:
parser.error ('--capflag PopulateSystemTable also requires --capflag PersistAcrossReset')
if 'InitiateReset' in args.CapsuleFlag:
parser.error ('--capflag InitiateReset also requires --capflag PersistAcrossReset')
UseSignTool = args.SignToolPfxFile is not None
UseOpenSsl = (args.OpenSslSignerPrivateCertFile is not None and
args.OpenSslOtherPublicCertFile is not None and
args.OpenSslTrustedPublicCertFile is not None)
AnyOpenSsl = (args.OpenSslSignerPrivateCertFile is not None or
args.OpenSslOtherPublicCertFile is not None or
args.OpenSslTrustedPublicCertFile is not None)
if args.Encode or args.Decode:
if args.OutputFile is None:
parser.error ('the following option is required for all encode and decode operations: --output')
if UseSignTool and AnyOpenSsl:
parser.error ('Providing both signtool and OpenSSL options is not supported')
if not UseSignTool and not UseOpenSsl and AnyOpenSsl:
parser.error ('all the following options are required for OpenSSL: --signer-private-cert, --other-public-cert, --trusted-public-cert')
if UseSignTool and platform.system() != 'Windows':
parser.error ('Use of signtool is not supported on this operating system.')
if args.Encode and (UseSignTool or UseOpenSsl):
if args.FwVersion is None or args.LowestSupportedVersion is None:
parser.error ('the following options are required: --fw-version, --lsv')
if UseSignTool:
args.SignToolPfxFile.close()
args.SignToolPfxFile = args.SignToolPfxFile.name
if UseOpenSsl:
args.OpenSslSignerPrivateCertFile.close()
args.OpenSslOtherPublicCertFile.close()
args.OpenSslTrustedPublicCertFile.close()
args.OpenSslSignerPrivateCertFile = args.OpenSslSignerPrivateCertFile.name
args.OpenSslOtherPublicCertFile = args.OpenSslOtherPublicCertFile.name
args.OpenSslTrustedPublicCertFile = args.OpenSslTrustedPublicCertFile.name
#
# 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:
Result = Buffer
if UseSignTool or UseOpenSsl:
try:
FmpPayloadHeader.FwVersion = args.FwVersion
FmpPayloadHeader.LowestSupportedVersion = args.LowestSupportedVersion
FmpPayloadHeader.Payload = Result
Result = FmpPayloadHeader.Encode ()
if args.Verbose:
FmpPayloadHeader.DumpInfo ()
except:
print ('GenerateCapsule: error: can not encode FMP Payload Header')
sys.exit (1)
#
# Sign image with 64-bit MonotonicCount appended to end of image
#
try:
if UseSignTool:
CertData = SignPayloadSignTool (
Result + struct.pack ('<Q', args.MonotonicCount),
args.SigningToolPath,
args.SignToolPfxFile
)
else:
CertData = SignPayloadOpenSsl (
Result + struct.pack ('<Q', args.MonotonicCount),
args.SigningToolPath,
args.OpenSslSignerPrivateCertFile,
args.OpenSslOtherPublicCertFile,
args.OpenSslTrustedPublicCertFile
)
except:
print ('GenerateCapsule: error: can not sign payload')
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
if args.Verbose:
print ('========')
UefiCapsuleHeader.DumpInfo ()
print ('--------')
FmpCapsuleHeader.DumpInfo ()
if UseSignTool or UseOpenSsl:
Result = FmpAuthHeader.Decode (Result)
#
# Verify Image with 64-bit MonotonicCount appended to end of image
#
try:
if UseSignTool:
CertData = VerifyPayloadSignTool (
FmpAuthHeader.Payload + struct.pack ('<Q', FmpAuthHeader.MonotonicCount),
FmpAuthHeader.CertData,
args.SigningToolPath,
args.SignToolPfxFile
)
else:
CertData = VerifyPayloadOpenSsl (
FmpAuthHeader.Payload + struct.pack ('<Q', FmpAuthHeader.MonotonicCount),
FmpAuthHeader.CertData,
args.SigningToolPath,
args.OpenSslSignerPrivateCertFile,
args.OpenSslOtherPublicCertFile,
args.OpenSslTrustedPublicCertFile
)
except ValueError:
print ('GenerateCapsule: warning: can not verify payload.')
Result = FmpPayloadHeader.Decode (Result)
if args.Verbose:
print ('--------')
FmpAuthHeader.DumpInfo ()
print ('--------')
FmpPayloadHeader.DumpInfo ()
else:
if args.Verbose:
print ('--------')
print ('No EFI_FIRMWARE_IMAGE_AUTHENTICATION')
print ('--------')
print ('No FMP_PAYLOAD_HEADER')
if args.Verbose:
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
print ('========')
UefiCapsuleHeader.DumpInfo ()
print ('--------')
FmpCapsuleHeader.DumpInfo ()
try:
Result = FmpAuthHeader.Decode (Result)
Result = FmpPayloadHeader.Decode (Result)
print ('--------')
FmpAuthHeader.DumpInfo ()
print ('--------')
FmpPayloadHeader.DumpInfo ()
except:
print ('--------')
print ('No EFI_FIRMWARE_IMAGE_AUTHENTICATION')
print ('--------')
print ('No FMP_PAYLOAD_HEADER')
print ('========')
except:
print ('GenerateCapsule: error: can not decode capsule')
sys.exit (1)
else:
print('GenerateCapsule: error: invalid options')
sys.exit (1)
#
# 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')

View File

@ -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)))

View File

@ -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.
#

View File

@ -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.
#

View File

@ -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)))

View File

@ -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 ()

View File

@ -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)))

View File

@ -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.
#

View File

@ -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.
#