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