diff options
Diffstat (limited to 'BaseTools/Source/Python/Capsule')
| -rw-r--r-- | BaseTools/Source/Python/Capsule/GenerateCapsule.py | 2152 | ||||
| -rw-r--r-- | BaseTools/Source/Python/Capsule/GenerateWindowsDriver.py | 240 | ||||
| -rw-r--r-- | BaseTools/Source/Python/Capsule/WindowsCapsuleSupportHelper.py | 128 |
3 files changed, 1260 insertions, 1260 deletions
diff --git a/BaseTools/Source/Python/Capsule/GenerateCapsule.py b/BaseTools/Source/Python/Capsule/GenerateCapsule.py index 35435946c6..4feba535b9 100644 --- a/BaseTools/Source/Python/Capsule/GenerateCapsule.py +++ b/BaseTools/Source/Python/Capsule/GenerateCapsule.py @@ -1,1076 +1,1076 @@ -## @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 - 2022, 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.10'
-__copyright__ = 'Copyright (c) 2022, Intel Corporation. All rights reserved.'
-__description__ = 'Generate a capsule.\n'
-
-def SignPayloadSignTool (Payload, ToolPath, PfxFile, SubjectName, 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)
- if PfxFile is not None:
- Command = Command + '/f {PfxFile} '.format (PfxFile = PfxFile)
- if SubjectName is not None:
- Command = Command + '/n {SubjectName} '.format (SubjectName = SubjectName)
- 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, SubjectName, 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)
- SignToolSubjectName = ConvertJsonValue (Config, 'SignToolSubjectName', 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,
- SignToolSubjectName,
- 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)
- SignToolSubjectName = ConvertJsonValue (Config, 'SignToolSubjectName', 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,
- SignToolSubjectName,
- 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),
- "SignToolSubjectName": str(PayloadDescriptor.SignToolSubjectName),
- "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].SignToolSubjectName is None:
- del PayloadField ['SignToolSubjectName']
- 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.SignToolSubjectName:
- print ('GenerateCapsule: error: Argument --SubjectName 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,
- SignToolSubjectName = 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.SignToolSubjectName = SignToolSubjectName
- self.OpenSslSignerPrivateCertFile = OpenSslSignerPrivateCertFile
- self.OpenSslOtherPublicCertFile = OpenSslOtherPublicCertFile
- self.OpenSslTrustedPublicCertFile = OpenSslTrustedPublicCertFile
- self.SigningToolPath = SigningToolPath
- self.DepexExp = DepexExp
-
- self.UseSignTool = (self.SignToolPfxFile is not None or
- self.SignToolSubjectName 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:
- if self.SignToolPfxFile is not None:
- 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.SignToolSubjectName,
- 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,
- SinglePayloadDescriptor.SignToolSubjectName,
- 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.SignSubjectName,
- 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].SignToolSubjectName,
- 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].SignToolSubjectName,
- 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,
- SinglePayloadDescriptor.SignToolSubjectName,
- 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 ("--subject-name", dest='SignToolSubjectName',
- help="signtool certificate subject name.")
-
- 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')
+## @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 - 2022, 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.10' +__copyright__ = 'Copyright (c) 2022, Intel Corporation. All rights reserved.' +__description__ = 'Generate a capsule.\n' + +def SignPayloadSignTool (Payload, ToolPath, PfxFile, SubjectName, 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) + if PfxFile is not None: + Command = Command + '/f {PfxFile} '.format (PfxFile = PfxFile) + if SubjectName is not None: + Command = Command + '/n {SubjectName} '.format (SubjectName = SubjectName) + 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, SubjectName, 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) + SignToolSubjectName = ConvertJsonValue (Config, 'SignToolSubjectName', 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, + SignToolSubjectName, + 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) + SignToolSubjectName = ConvertJsonValue (Config, 'SignToolSubjectName', 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, + SignToolSubjectName, + 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), + "SignToolSubjectName": str(PayloadDescriptor.SignToolSubjectName), + "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].SignToolSubjectName is None: + del PayloadField ['SignToolSubjectName'] + 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.SignToolSubjectName: + print ('GenerateCapsule: error: Argument --SubjectName 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, + SignToolSubjectName = 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.SignToolSubjectName = SignToolSubjectName + self.OpenSslSignerPrivateCertFile = OpenSslSignerPrivateCertFile + self.OpenSslOtherPublicCertFile = OpenSslOtherPublicCertFile + self.OpenSslTrustedPublicCertFile = OpenSslTrustedPublicCertFile + self.SigningToolPath = SigningToolPath + self.DepexExp = DepexExp + + self.UseSignTool = (self.SignToolPfxFile is not None or + self.SignToolSubjectName 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: + if self.SignToolPfxFile is not None: + 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.SignToolSubjectName, + 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, + SinglePayloadDescriptor.SignToolSubjectName, + 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.SignSubjectName, + 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].SignToolSubjectName, + 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].SignToolSubjectName, + 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, + SinglePayloadDescriptor.SignToolSubjectName, + 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 ("--subject-name", dest='SignToolSubjectName', + help="signtool certificate subject name.") + + 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') diff --git a/BaseTools/Source/Python/Capsule/GenerateWindowsDriver.py b/BaseTools/Source/Python/Capsule/GenerateWindowsDriver.py index bea7a0df38..9486b0e4c8 100644 --- a/BaseTools/Source/Python/Capsule/GenerateWindowsDriver.py +++ b/BaseTools/Source/Python/Capsule/GenerateWindowsDriver.py @@ -1,120 +1,120 @@ -## @file
-# Generate a capsule windows driver.
-#
-# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-#
-
-'''
-GenerateWindowsDriver
-'''
-
-import sys
-import argparse
-import uuid
-import struct
-import subprocess
-import os
-import tempfile
-import shutil
-import platform
-import re
-import logging
-from WindowsCapsuleSupportHelper import WindowsCapsuleSupportHelper
-from Common.Uefi.Capsule.FmpCapsuleHeader import FmpCapsuleHeaderClass
-from Common.Uefi.Capsule.UefiCapsuleHeader import UefiCapsuleHeaderClass
-
-#
-# Globals for help information
-#
-__prog__ = 'GenerateWindowsDriver'
-__version__ = '0.0'
-__copyright__ = 'Copyright (c) 2019, Intel Corporation. All rights reserved.'
-__description__ = 'Generate Capsule Windows Driver.\n'
-
-def GetCapGuid (InputFile):
- with open(InputFile, 'rb') as File:
- Buffer = File.read()
- try:
- Result = UefiCapsuleHeader.Decode (Buffer)
- if len (Result) > 0:
- FmpCapsuleHeader.Decode (Result)
- for index in range (0, FmpCapsuleHeader.PayloadItemCount):
- Guid = FmpCapsuleHeader.GetFmpCapsuleImageHeader (index).UpdateImageTypeId
- return Guid
- except:
- print ('GenerateCapsule: error: can not decode capsule')
- sys.exit (1)
-
-def ArgCheck(args):
- Version = args.CapsuleVersion_DotString.split('.')
-
- if len(Version) != 4:
- logging.critical("Name invalid: '%s'", args.CapsuleVersion_DotString)
- raise ValueError("Name invalid.")
- for sub in Version:
- if int(sub, 16) > 65536:
- logging.critical("Name invalid: '%s'", args.CapsuleVersion_DotString)
- raise ValueError("Name exceed limit 65536.")
-
- if not (re.compile(r'[\a-fA-F0-9]*$')).match(args.CapsuleVersion_DotString):
- logging.critical("Name invalid: '%s'", args.CapsuleVersion_DotString)
- raise ValueError("Name has invalid chars.")
-
-def CapsuleGuidCheck(InputFile, Guid):
- CapGuid = GetCapGuid(InputFile)
- if (str(Guid).lower() != str(CapGuid)):
- print('GenerateWindowsDriver error: Different Guid from Capsule')
- sys.exit(1)
-
-if __name__ == '__main__':
- def convert_arg_line_to_args(arg_line):
- for arg in arg_line.split():
- if not arg.strip():
- continue
- yield arg
-
- 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
- parser.add_argument("--output-folder", dest = 'OutputFolder', help = "firmware resource update driver package output folder.")
- parser.add_argument("--product-fmp-guid", dest = 'ProductFmpGuid', help = "firmware GUID of resource update driver package")
- parser.add_argument("--capsuleversion-dotstring", dest = 'CapsuleVersion_DotString', help = "firmware version with date on which update driver package is authored")
- parser.add_argument("--capsuleversion-hexstring", dest = 'CapsuleVersion_HexString', help = "firmware version in Hex of update driver package")
- parser.add_argument("--product-fw-provider", dest = 'ProductFwProvider', help = "vendor/provider of entire firmware resource update driver package")
- parser.add_argument("--product-fw-mfg-name", dest = 'ProductFwMfgName', help = "manufacturer/vendor of firmware resource update driver package")
- parser.add_argument("--product-fw-desc", dest = "ProductFwDesc", help = "description about resource update driver")
- parser.add_argument("--capsule-file-name", dest = 'CapsuleFileName', help ="firmware resource image file")
- parser.add_argument("--pfx-file", dest = 'PfxFile', help = "pfx file path used to sign resource update driver")
- parser.add_argument("--arch", dest = 'Arch', help = "supported architecture:arm/x64/amd64/arm64/aarch64", default = 'amd64')
- parser.add_argument("--operating-system-string", dest = 'OperatingSystemString', help = "supported operating system:win10/10/10_au/10_rs2/10_rs3/10_rs4/server10/server2016/serverrs2/serverrs3/serverrs4", default = "win10")
-
- args = parser.parse_args()
- InputFile = os.path.join(args.OutputFolder, '') + args.CapsuleFileName
- UefiCapsuleHeader = UefiCapsuleHeaderClass ()
- FmpCapsuleHeader = FmpCapsuleHeaderClass ()
- CapsuleGuidCheck(InputFile, args.ProductFmpGuid)
- ArgCheck(args)
- ProductName = os.path.splitext(args.CapsuleFileName)[0]
- WindowsDriver = WindowsCapsuleSupportHelper ()
-
- WindowsDriver.PackageWindowsCapsuleFiles (
- args.OutputFolder,
- ProductName,
- args.ProductFmpGuid,
- args.CapsuleVersion_DotString,
- args.CapsuleVersion_HexString,
- args.ProductFwProvider,
- args.ProductFwMfgName,
- args.ProductFwDesc,
- args.CapsuleFileName,
- args.PfxFile,
- None,
- None,
- args.Arch,
- args.OperatingSystemString
- )
+## @file +# Generate a capsule windows driver. +# +# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +# + +''' +GenerateWindowsDriver +''' + +import sys +import argparse +import uuid +import struct +import subprocess +import os +import tempfile +import shutil +import platform +import re +import logging +from WindowsCapsuleSupportHelper import WindowsCapsuleSupportHelper +from Common.Uefi.Capsule.FmpCapsuleHeader import FmpCapsuleHeaderClass +from Common.Uefi.Capsule.UefiCapsuleHeader import UefiCapsuleHeaderClass + +# +# Globals for help information +# +__prog__ = 'GenerateWindowsDriver' +__version__ = '0.0' +__copyright__ = 'Copyright (c) 2019, Intel Corporation. All rights reserved.' +__description__ = 'Generate Capsule Windows Driver.\n' + +def GetCapGuid (InputFile): + with open(InputFile, 'rb') as File: + Buffer = File.read() + try: + Result = UefiCapsuleHeader.Decode (Buffer) + if len (Result) > 0: + FmpCapsuleHeader.Decode (Result) + for index in range (0, FmpCapsuleHeader.PayloadItemCount): + Guid = FmpCapsuleHeader.GetFmpCapsuleImageHeader (index).UpdateImageTypeId + return Guid + except: + print ('GenerateCapsule: error: can not decode capsule') + sys.exit (1) + +def ArgCheck(args): + Version = args.CapsuleVersion_DotString.split('.') + + if len(Version) != 4: + logging.critical("Name invalid: '%s'", args.CapsuleVersion_DotString) + raise ValueError("Name invalid.") + for sub in Version: + if int(sub, 16) > 65536: + logging.critical("Name invalid: '%s'", args.CapsuleVersion_DotString) + raise ValueError("Name exceed limit 65536.") + + if not (re.compile(r'[\a-fA-F0-9]*$')).match(args.CapsuleVersion_DotString): + logging.critical("Name invalid: '%s'", args.CapsuleVersion_DotString) + raise ValueError("Name has invalid chars.") + +def CapsuleGuidCheck(InputFile, Guid): + CapGuid = GetCapGuid(InputFile) + if (str(Guid).lower() != str(CapGuid)): + print('GenerateWindowsDriver error: Different Guid from Capsule') + sys.exit(1) + +if __name__ == '__main__': + def convert_arg_line_to_args(arg_line): + for arg in arg_line.split(): + if not arg.strip(): + continue + yield arg + + 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 + parser.add_argument("--output-folder", dest = 'OutputFolder', help = "firmware resource update driver package output folder.") + parser.add_argument("--product-fmp-guid", dest = 'ProductFmpGuid', help = "firmware GUID of resource update driver package") + parser.add_argument("--capsuleversion-dotstring", dest = 'CapsuleVersion_DotString', help = "firmware version with date on which update driver package is authored") + parser.add_argument("--capsuleversion-hexstring", dest = 'CapsuleVersion_HexString', help = "firmware version in Hex of update driver package") + parser.add_argument("--product-fw-provider", dest = 'ProductFwProvider', help = "vendor/provider of entire firmware resource update driver package") + parser.add_argument("--product-fw-mfg-name", dest = 'ProductFwMfgName', help = "manufacturer/vendor of firmware resource update driver package") + parser.add_argument("--product-fw-desc", dest = "ProductFwDesc", help = "description about resource update driver") + parser.add_argument("--capsule-file-name", dest = 'CapsuleFileName', help ="firmware resource image file") + parser.add_argument("--pfx-file", dest = 'PfxFile', help = "pfx file path used to sign resource update driver") + parser.add_argument("--arch", dest = 'Arch', help = "supported architecture:arm/x64/amd64/arm64/aarch64", default = 'amd64') + parser.add_argument("--operating-system-string", dest = 'OperatingSystemString', help = "supported operating system:win10/10/10_au/10_rs2/10_rs3/10_rs4/server10/server2016/serverrs2/serverrs3/serverrs4", default = "win10") + + args = parser.parse_args() + InputFile = os.path.join(args.OutputFolder, '') + args.CapsuleFileName + UefiCapsuleHeader = UefiCapsuleHeaderClass () + FmpCapsuleHeader = FmpCapsuleHeaderClass () + CapsuleGuidCheck(InputFile, args.ProductFmpGuid) + ArgCheck(args) + ProductName = os.path.splitext(args.CapsuleFileName)[0] + WindowsDriver = WindowsCapsuleSupportHelper () + + WindowsDriver.PackageWindowsCapsuleFiles ( + args.OutputFolder, + ProductName, + args.ProductFmpGuid, + args.CapsuleVersion_DotString, + args.CapsuleVersion_HexString, + args.ProductFwProvider, + args.ProductFwMfgName, + args.ProductFwDesc, + args.CapsuleFileName, + args.PfxFile, + None, + None, + args.Arch, + args.OperatingSystemString + ) diff --git a/BaseTools/Source/Python/Capsule/WindowsCapsuleSupportHelper.py b/BaseTools/Source/Python/Capsule/WindowsCapsuleSupportHelper.py index a29ac21ae8..9b049bddba 100644 --- a/BaseTools/Source/Python/Capsule/WindowsCapsuleSupportHelper.py +++ b/BaseTools/Source/Python/Capsule/WindowsCapsuleSupportHelper.py @@ -1,64 +1,64 @@ -##
-# UefiBuild Plugin that supports Window Capsule files based on the
-# Windows Firmware Update Platform spec.
-# Creates INF, Cat, and then signs it
-#
-# To install run pip install --upgrade edk2-pytool-library
-# edk2-pytool-library-0.9.1 is required.
-#
-# Copyright (c) Microsoft Corporation. All rights reserved.
-# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-##
-
-import sys
-import re
-import datetime
-import os
-import logging
-from edk2toollib.windows.capsule.cat_generator import CatGenerator
-from edk2toollib.windows.capsule.inf_generator import InfGenerator
-from edk2toollib.utility_functions import CatalogSignWithSignTool
-from edk2toollib.windows.locate_tools import FindToolInWinSdk
-
-class WindowsCapsuleSupportHelper(object):
-
- def RegisterHelpers(self, obj):
- fp = os.path.abspath(__file__)
- obj.Register("PackageWindowsCapsuleFiles", WindowsCapsuleSupportHelper.PackageWindowsCapsuleFiles, fp)
-
-
- @staticmethod
- def PackageWindowsCapsuleFiles(OutputFolder, ProductName, ProductFmpGuid, CapsuleVersion_DotString,
- CapsuleVersion_HexString, ProductFwProvider, ProductFwMfgName, ProductFwDesc, CapsuleFileName, PfxFile=None, PfxPass=None,
- Rollback=False, Arch='amd64', OperatingSystem_String='Win10'):
-
- logging.debug("CapsulePackage: Create Windows Capsule Files")
-
- #Make INF
- InfFilePath = os.path.join(OutputFolder, ProductName + ".inf")
- InfTool = InfGenerator(ProductName, ProductFwProvider, ProductFmpGuid, Arch, ProductFwDesc, CapsuleVersion_DotString, CapsuleVersion_HexString)
- InfTool.Manufacturer = ProductFwMfgName #optional
- ret = InfTool.MakeInf(InfFilePath, CapsuleFileName, Rollback)
- if(ret != 0):
- raise Exception("CreateWindowsInf Failed with errorcode %d" % ret)
-
- #Make CAT
- CatFilePath = os.path.realpath(os.path.join(OutputFolder, ProductName + ".cat"))
- CatTool = CatGenerator(Arch, OperatingSystem_String)
- ret = CatTool.MakeCat(CatFilePath)
-
- if(ret != 0):
- raise Exception("Creating Cat file Failed with errorcode %d" % ret)
-
- if(PfxFile is not None):
- #Find Signtool
- SignToolPath = FindToolInWinSdk("signtool.exe")
- if not os.path.exists(SignToolPath):
- raise Exception("Can't find signtool on this machine.")
- #dev sign the cat file
- ret = CatalogSignWithSignTool(SignToolPath, CatFilePath, PfxFile, PfxPass)
- if(ret != 0):
- raise Exception("Signing Cat file Failed with errorcode %d" % ret)
-
- return ret
+## +# UefiBuild Plugin that supports Window Capsule files based on the +# Windows Firmware Update Platform spec. +# Creates INF, Cat, and then signs it +# +# To install run pip install --upgrade edk2-pytool-library +# edk2-pytool-library-0.9.1 is required. +# +# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +import sys +import re +import datetime +import os +import logging +from edk2toollib.windows.capsule.cat_generator import CatGenerator +from edk2toollib.windows.capsule.inf_generator import InfGenerator +from edk2toollib.utility_functions import CatalogSignWithSignTool +from edk2toollib.windows.locate_tools import FindToolInWinSdk + +class WindowsCapsuleSupportHelper(object): + + def RegisterHelpers(self, obj): + fp = os.path.abspath(__file__) + obj.Register("PackageWindowsCapsuleFiles", WindowsCapsuleSupportHelper.PackageWindowsCapsuleFiles, fp) + + + @staticmethod + def PackageWindowsCapsuleFiles(OutputFolder, ProductName, ProductFmpGuid, CapsuleVersion_DotString, + CapsuleVersion_HexString, ProductFwProvider, ProductFwMfgName, ProductFwDesc, CapsuleFileName, PfxFile=None, PfxPass=None, + Rollback=False, Arch='amd64', OperatingSystem_String='Win10'): + + logging.debug("CapsulePackage: Create Windows Capsule Files") + + #Make INF + InfFilePath = os.path.join(OutputFolder, ProductName + ".inf") + InfTool = InfGenerator(ProductName, ProductFwProvider, ProductFmpGuid, Arch, ProductFwDesc, CapsuleVersion_DotString, CapsuleVersion_HexString) + InfTool.Manufacturer = ProductFwMfgName #optional + ret = InfTool.MakeInf(InfFilePath, CapsuleFileName, Rollback) + if(ret != 0): + raise Exception("CreateWindowsInf Failed with errorcode %d" % ret) + + #Make CAT + CatFilePath = os.path.realpath(os.path.join(OutputFolder, ProductName + ".cat")) + CatTool = CatGenerator(Arch, OperatingSystem_String) + ret = CatTool.MakeCat(CatFilePath) + + if(ret != 0): + raise Exception("Creating Cat file Failed with errorcode %d" % ret) + + if(PfxFile is not None): + #Find Signtool + SignToolPath = FindToolInWinSdk("signtool.exe") + if not os.path.exists(SignToolPath): + raise Exception("Can't find signtool on this machine.") + #dev sign the cat file + ret = CatalogSignWithSignTool(SignToolPath, CatFilePath, PfxFile, PfxPass) + if(ret != 0): + raise Exception("Signing Cat file Failed with errorcode %d" % ret) + + return ret |
