summaryrefslogtreecommitdiffstats
path: root/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Capsule/GenerateCapsule.py
diff options
context:
space:
mode:
Diffstat (limited to '')
-rwxr-xr-xsrc/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Capsule/GenerateCapsule.py1051
1 files changed, 1051 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Capsule/GenerateCapsule.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Capsule/GenerateCapsule.py
new file mode 100755
index 00000000..f8d85bca
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/BaseTools/Source/Python/Capsule/GenerateCapsule.py
@@ -0,0 +1,1051 @@
+## @file
+# Generate a capsule.
+#
+# 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
+# keep the tool as simple as possible, it has the following limitations:
+# * Do not support vendor code bytes in a capsule.
+#
+# Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+
+'''
+GenerateCapsule
+'''
+
+import sys
+import argparse
+import uuid
+import struct
+import subprocess
+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
+from Common.Uefi.Capsule.CapsuleDependency import CapsuleDependencyClass
+from Common.Edk2.Capsule.FmpPayloadHeader import FmpPayloadHeaderClass
+
+#
+# Globals for help information
+#
+__prog__ = 'GenerateCapsule'
+__version__ = '0.9'
+__copyright__ = 'Copyright (c) 2018, Intel Corporation. All rights reserved.'
+__description__ = 'Generate a capsule.\n'
+
+def SignPayloadSignTool (Payload, ToolPath, PfxFile, Verbose = False):
+ #
+ # Create a temporary directory
+ #
+ TempDirectoryName = tempfile.mkdtemp()
+
+ #
+ # Generate temp file name for the payload contents
+ #
+ TempFileName = os.path.join (TempDirectoryName, 'Payload.bin')
+
+ #
+ # Create temporary payload file for signing
+ #
+ try:
+ with open (TempFileName, 'wb') as File:
+ File.write (Payload)
+ except:
+ shutil.rmtree (TempDirectoryName)
+ raise ValueError ('GenerateCapsule: error: can not write temporary payload file.')
+
+ #
+ # Build signtool command
+ #
+ if ToolPath is None:
+ ToolPath = ''
+ Command = ''
+ Command = Command + '"{Path}" '.format (Path = os.path.join (ToolPath, 'signtool.exe'))
+ Command = Command + 'sign /fd sha256 /p7ce DetachedSignedData /p7co 1.2.840.113549.1.7.2 '
+ Command = Command + '/p7 {TempDir} '.format (TempDir = TempDirectoryName)
+ Command = Command + '/f {PfxFile} '.format (PfxFile = PfxFile)
+ Command = Command + TempFileName
+ if Verbose:
+ print (Command)
+
+ #
+ # Sign the input file using the specified private key
+ #
+ try:
+ Process = subprocess.Popen (Command, stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE, shell = True)
+ Result = Process.communicate('')
+ except:
+ shutil.rmtree (TempDirectoryName)
+ raise ValueError ('GenerateCapsule: error: can not run signtool.')
+
+ if Process.returncode != 0:
+ shutil.rmtree (TempDirectoryName)
+ print (Result[1].decode())
+ raise ValueError ('GenerateCapsule: error: signtool failed.')
+
+ #
+ # Read the signature from the generated output file
+ #
+ try:
+ with open (TempFileName + '.p7', 'rb') as File:
+ Signature = File.read ()
+ except:
+ shutil.rmtree (TempDirectoryName)
+ raise ValueError ('GenerateCapsule: error: can not read signature file.')
+
+ shutil.rmtree (TempDirectoryName)
+ return Signature
+
+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, Verbose = False):
+ #
+ # Build openssl command
+ #
+ if ToolPath is None:
+ ToolPath = ''
+ Command = ''
+ Command = Command + '"{Path}" '.format (Path = os.path.join (ToolPath, 'openssl'))
+ Command = Command + 'smime -sign -binary -outform DER -md sha256 '
+ Command = Command + '-signer "{Private}" -certfile "{Public}"'.format (Private = SignerPrivateCertFile, Public = OtherPublicCertFile)
+ if Verbose:
+ print (Command)
+
+ #
+ # Sign the input file using the specified private key and capture signature from STDOUT
+ #
+ try:
+ Process = subprocess.Popen (Command, stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE, shell = True)
+ Result = Process.communicate(input = Payload)
+ Signature = Result[0]
+ except:
+ raise ValueError ('GenerateCapsule: error: can not run openssl.')
+
+ if Process.returncode != 0:
+ print (Result[1].decode())
+ raise ValueError ('GenerateCapsule: error: openssl failed.')
+
+ return Signature
+
+def VerifyPayloadOpenSsl (Payload, CertData, ToolPath, SignerPrivateCertFile, OtherPublicCertFile, TrustedPublicCertFile, Verbose = False):
+ #
+ # Create a temporary directory
+ #
+ TempDirectoryName = tempfile.mkdtemp()
+
+ #
+ # Generate temp file name for the payload contents
+ #
+ TempFileName = os.path.join (TempDirectoryName, 'Payload.bin')
+
+ #
+ # Create temporary payload file for verification
+ #
+ try:
+ with open (TempFileName, 'wb') as File:
+ File.write (Payload)
+ except:
+ shutil.rmtree (TempDirectoryName)
+ raise ValueError ('GenerateCapsule: error: can not write temporary payload file.')
+
+ #
+ # Build openssl command
+ #
+ if ToolPath is None:
+ ToolPath = ''
+ Command = ''
+ Command = Command + '"{Path}" '.format (Path = os.path.join (ToolPath, 'openssl'))
+ Command = Command + 'smime -verify -inform DER '
+ Command = Command + '-content {Content} -CAfile "{Public}"'.format (Content = TempFileName, Public = TrustedPublicCertFile)
+ if Verbose:
+ print (Command)
+
+ #
+ # Verify signature
+ #
+ try:
+ Process = subprocess.Popen (Command, stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE, shell = True)
+ Result = Process.communicate(input = CertData)
+ except:
+ shutil.rmtree (TempDirectoryName)
+ raise ValueError ('GenerateCapsule: error: can not run openssl.')
+
+ if Process.returncode != 0:
+ shutil.rmtree (TempDirectoryName)
+ print (Result[1].decode())
+ raise ValueError ('GenerateCapsule: error: openssl failed.')
+
+ shutil.rmtree (TempDirectoryName)
+ return Payload
+
+if __name__ == '__main__':
+ def convert_arg_line_to_args(arg_line):
+ for arg in arg_line.split():
+ if not arg.strip():
+ continue
+ yield arg
+
+ def ValidateUnsignedInteger (Argument):
+ try:
+ Value = int (Argument, 0)
+ except:
+ Message = '{Argument} is not a valid integer value.'.format (Argument = Argument)
+ raise argparse.ArgumentTypeError (Message)
+ if Value < 0:
+ Message = '{Argument} is a negative value.'.format (Argument = Argument)
+ raise argparse.ArgumentTypeError (Message)
+ return Value
+
+ def ValidateRegistryFormatGuid (Argument):
+ try:
+ Value = uuid.UUID (Argument)
+ except:
+ Message = '{Argument} is not a valid registry format GUID value.'.format (Argument = Argument)
+ raise argparse.ArgumentTypeError (Message)
+ return Value
+
+ 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:
+ print ('GenerateCapsule: error: {Key} in payload descriptor has invalid syntax.'.format (Key = FieldName))
+ 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)
+ DepexExp = ConvertJsonValue (Config, 'Dependencies', str, 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()
+ PayloadFile.close ()
+ 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,
+ DepexExp
+ ))
+
+ 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),
+ "Dependencies" : str(PayloadDescriptor.DepexExp)
+ }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=(',', ': '))
+ with open (OutputJsonFile, 'w') as OutputFile:
+ OutputFile.write (Result)
+
+ 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,
+ DepexExp = 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.DepexExp = DepexExp
+
+ 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)
+ self.UseDependency = self.DepexExp 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:
+ print ('GenerateCapsule: error: {JSONFile} loads failure. '.format (JSONFile = args.JsonFile))
+ 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,
+ None
+ ))
+ for SinglePayloadDescriptor in PayloadDescriptorList:
+ try:
+ SinglePayloadDescriptor.Validate (args)
+ except Exception as Msg:
+ print ('GenerateCapsule: error:' + str(Msg))
+ sys.exit (1)
+ for SinglePayloadDescriptor in PayloadDescriptorList:
+ ImageCapsuleSupport = 0x0000000000000000
+ 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:
+ print ('GenerateCapsule: error: can not encode FMP Payload Header')
+ sys.exit (1)
+ if SinglePayloadDescriptor.UseDependency:
+ CapsuleDependency.Payload = Result
+ CapsuleDependency.DepexExp = SinglePayloadDescriptor.DepexExp
+ ImageCapsuleSupport |= FmpCapsuleHeader.CAPSULE_SUPPORT_DEPENDENCY
+ Result = CapsuleDependency.Encode ()
+ if args.Verbose:
+ CapsuleDependency.DumpInfo ()
+ 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 Exception as Msg:
+ print ('GenerateCapsule: error: can not sign payload \n' + str(Msg))
+ sys.exit (1)
+
+ try:
+ FmpAuthHeader.MonotonicCount = SinglePayloadDescriptor.MonotonicCount
+ FmpAuthHeader.CertData = CertData
+ FmpAuthHeader.Payload = Result
+ ImageCapsuleSupport |= FmpCapsuleHeader.CAPSULE_SUPPORT_AUTHENTICATION
+ 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, CapsuleSupport = ImageCapsuleSupport)
+ 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:
+ print ('GenerateCapsule: error: {JSONFile} loads failure. '.format (JSONFile = args.JsonFile))
+ 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,
+ None
+ ))
+ #
+ # Perform additional verification on payload descriptors
+ #
+ for SinglePayloadDescriptor in PayloadDescriptorList:
+ try:
+ SinglePayloadDescriptor.Validate (args)
+ except Exception as Msg:
+ print ('GenerateCapsule: error:' + str(Msg))
+ 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,
+ None
+ ))
+ 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,
+ 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,
+ None
+ ))
+ 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 Exception as Msg:
+ print ('GenerateCapsule: warning: payload verification failed Index = {Index} \n'.format (Index = JsonIndex + 1) + str(Msg))
+ else:
+ if args.Verbose:
+ print ('--------')
+ print ('No EFI_FIRMWARE_IMAGE_AUTHENTICATION')
+
+ PayloadSignature = struct.unpack ('<I', SinglePayloadDescriptor.Payload[0:4])
+ if PayloadSignature != FmpPayloadHeader.Signature:
+ SinglePayloadDescriptor.UseDependency = True
+ try:
+ SinglePayloadDescriptor.Payload = CapsuleDependency.Decode (SinglePayloadDescriptor.Payload)
+ PayloadJsonDescriptorList[JsonIndex].DepexExp = CapsuleDependency.DepexExp
+ if args.Verbose:
+ print ('--------')
+ CapsuleDependency.DumpInfo ()
+ except Exception as Msg:
+ print ('GenerateCapsule: error: invalid dependency expression')
+ else:
+ if args.Verbose:
+ print ('--------')
+ print ('No EFI_FIRMWARE_IMAGE_DEP')
+
+ 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 ('========')
+ sys.exit (1)
+ #
+ # 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))
+ with open (EmbeddedDriverPath, 'wb') as EmbeddedDriverFile:
+ EmbeddedDriverFile.write (EmbeddedDriverBuffer)
+ except:
+ print ('GenerateCapsule: error: can not write embedded driver file {File}'.format (File = EmbeddedDriverPath))
+ sys.exit (1)
+
+ except:
+ 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)
+ with open (PayloadDecodePath, 'wb') as PayloadDecodeFile:
+ PayloadDecodeFile.write (SinglePayloadDescriptor.Payload)
+ 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')
+
+ PayloadSignature = struct.unpack ('<I', Result[0:4])
+ if PayloadSignature != FmpPayloadHeader.Signature:
+ try:
+ Result = CapsuleDependency.Decode (Result)
+ print ('--------')
+ CapsuleDependency.DumpInfo ()
+ except:
+ print ('GenerateCapsule: error: invalid dependency expression')
+ else:
+ print ('--------')
+ print ('No EFI_FIRMWARE_IMAGE_DEP')
+ 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
+ #
+ parser = argparse.ArgumentParser (
+ prog = __prog__,
+ description = __description__ + __copyright__,
+ conflict_handler = 'resolve',
+ fromfile_prefix_chars = '@'
+ )
+ parser.convert_arg_line_to_args = convert_arg_line_to_args
+
+ #
+ # Add input and output file arguments
+ #
+ parser.add_argument("InputFile", type = argparse.FileType('rb'), nargs='?',
+ help = "Input binary payload filename.")
+ parser.add_argument("-o", "--output", dest = 'OutputFile', type = argparse.FileType('wb'),
+ help = "Output filename.")
+ #
+ # Add group for -e and -d flags that are mutually exclusive and required
+ #
+ group = parser.add_mutually_exclusive_group (required = True)
+ group.add_argument ("-e", "--encode", dest = 'Encode', action = "store_true",
+ help = "Encode file")
+ group.add_argument ("-d", "--decode", dest = 'Decode', action = "store_true",
+ help = "Decode file")
+ group.add_argument ("--dump-info", dest = 'DumpInfo', action = "store_true",
+ help = "Display FMP Payload Header information")
+ #
+ # Add optional arguments for this command
+ #
+ parser.add_argument ("-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")
+ parser.add_argument ("--capoemflag", dest = 'CapsuleOemFlag', type = ValidateUnsignedInteger, default = 0x0000,
+ help = "Capsule OEM Flag is an integer between 0x0000 and 0xffff.")
+
+ parser.add_argument ("--guid", dest = 'Guid', type = ValidateRegistryFormatGuid,
+ help = "The FMP/ESRT GUID in registry format. Required for 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")
+
+
+ parser.add_argument ("--monotonic-count", dest = 'MonotonicCount', type = ValidateUnsignedInteger, default = 0x0000000000000000,
+ help = "64-bit monotonic count value in header. Default is 0x0000000000000000.")
+
+ parser.add_argument ("--fw-version", dest = 'FwVersion', type = ValidateUnsignedInteger,
+ help = "The 32-bit version of the binary payload (e.g. 0x11223344 or 5678). 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.")
+
+ parser.add_argument ("--pfx-file", dest='SignToolPfxFile', type=argparse.FileType('rb'),
+ help="signtool PFX certificate filename.")
+
+ parser.add_argument ("--signer-private-cert", dest='OpenSslSignerPrivateCertFile', type=argparse.FileType('rb'),
+ help="OpenSSL signer private certificate filename.")
+ parser.add_argument ("--other-public-cert", dest='OpenSslOtherPublicCertFile', type=argparse.FileType('rb'),
+ help="OpenSSL other public certificate filename.")
+ parser.add_argument ("--trusted-public-cert", dest='OpenSslTrustedPublicCertFile', type=argparse.FileType('rb'),
+ help="OpenSSL trusted public certificate filename.")
+
+ parser.add_argument ("--signing-tool-path", dest = 'SigningToolPath',
+ help = "Path to signtool or OpenSSL tool. Optional if path to tools are already in PATH.")
+
+ 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
+ #
+ parser.add_argument ('--version', action='version', version='%(prog)s ' + __version__)
+ parser.add_argument ("-v", "--verbose", dest = 'Verbose', action = "store_true",
+ help = "Turn on verbose output with informational messages printed, including capsule headers and warning messages.")
+ parser.add_argument ("-q", "--quiet", dest = 'Quiet', action = "store_true",
+ help = "Disable all messages except fatal errors.")
+ parser.add_argument ("--debug", dest = 'Debug', type = int, metavar = '[0-9]', choices = range (0, 10), default = 0,
+ help = "Set debug level")
+ 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()
+
+ #
+ # Read binary input file
+ #
+ 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
+ #
+ UefiCapsuleHeader = UefiCapsuleHeaderClass ()
+ FmpCapsuleHeader = FmpCapsuleHeaderClass ()
+ FmpAuthHeader = FmpAuthHeaderClass ()
+ FmpPayloadHeader = FmpPayloadHeaderClass ()
+ CapsuleDependency = CapsuleDependencyClass ()
+
+ EmbeddedDriverDescriptorList = []
+ PayloadDescriptorList = []
+ PayloadJsonDescriptorList = []
+
+ #
+ #Encode Operation
+ #
+ if args.Encode:
+ Encode (PayloadDescriptorList, EmbeddedDriverDescriptorList, Buffer)
+
+ #
+ #Decode Operation
+ #
+ if args.Decode:
+ Decode (PayloadDescriptorList, PayloadJsonDescriptorList, Buffer)
+
+ #
+ #Dump Info Operation
+ #
+ if args.DumpInfo:
+ DumpInfo (Buffer, args)
+
+ if args.Verbose:
+ print('Success')