public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [Patch] BaseTools/Capsule: Supports UEFI Capsule with multiple payloads and embedded drivers
@ 2019-05-27  7:28 Eric Jin
  2019-05-27 13:58 ` [edk2-devel] " Liming Gao
  2019-06-11  3:06 ` Bob Feng
  0 siblings, 2 replies; 4+ messages in thread
From: Eric Jin @ 2019-05-27  7:28 UTC (permalink / raw)
  To: devel; +Cc: Bob Feng, Liming Gao, Kinney, Michael D

https://bugzilla.tianocore.org/show_bug.cgi?id=1834

* Add arguments "--embedded-driver" to support embedded driver in command line.
* Add arguments "--update-image-index" to identify ImageIndex within the device
  in command line.
* Add arguments "-j JSONFILE" to support multiple payloads and embedded drivers
  with JSON file.

The update is in a backwards compatible manner, so all command line options to
support single payload are still supported. But all the options associated with
multiple payloads should be provided in a JSON file.

Cc: Bob Feng <bob.c.feng@intel.com>
Cc: Liming Gao <liming.gao@intel.com>
Cc: Kinney, Michael D <michael.d.kinney@intel.com>
Signed-off-by: Eric Jin <eric.jin@intel.com>
---
 BaseTools/Source/Python/Capsule/GenerateCapsule.py              | 961 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 BaseTools/Source/Python/Common/Uefi/Capsule/FmpAuthHeader.py    |  14 +++++++++++++-
 BaseTools/Source/Python/Common/Uefi/Capsule/FmpCapsuleHeader.py |  12 +++++++-----
 3 files changed, 730 insertions(+), 257 deletions(-)

diff --git a/BaseTools/Source/Python/Capsule/GenerateCapsule.py b/BaseTools/Source/Python/Capsule/GenerateCapsule.py
index 4de3635298..ee95c4cc2e 100644
--- a/BaseTools/Source/Python/Capsule/GenerateCapsule.py
+++ b/BaseTools/Source/Python/Capsule/GenerateCapsule.py
@@ -1,18 +1,16 @@
 ## @file
 # Generate a capsule.
 #
-# This tool generates a UEFI Capsule around an FMP Capsule.  The capsule payload
+# This tool generates a UEFI Capsule around an FMP Capsule. The capsule payload
 # be signed using signtool or OpenSSL and if it is signed the signed content
 # includes an FMP Payload Header.
 #
 # This tool is intended to be used to generate UEFI Capsules to update the
-# system firmware or device firmware for integrated devices.  In order to
+# system firmware or device firmware for integrated devices. In order to
 # keep the tool as simple as possible, it has the following limitations:
-#   * Do not support multiple payloads in a capsule.
-#   * Do not support optional drivers in a capsule.
 #   * Do not support vendor code bytes in a capsule.
 #
-# Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<BR>
 # SPDX-License-Identifier: BSD-2-Clause-Patent
 #
 
@@ -29,6 +27,7 @@ import os
 import tempfile
 import shutil
 import platform
+import json
 from Common.Uefi.Capsule.UefiCapsuleHeader import UefiCapsuleHeaderClass
 from Common.Uefi.Capsule.FmpCapsuleHeader  import FmpCapsuleHeaderClass
 from Common.Uefi.Capsule.FmpAuthHeader     import FmpAuthHeaderClass
@@ -42,7 +41,7 @@ __version__     = '0.9'
 __copyright__   = 'Copyright (c) 2018, Intel Corporation. All rights reserved.'
 __description__ = 'Generate a capsule.\n'
 
-def SignPayloadSignTool (Payload, ToolPath, PfxFile):
+def SignPayloadSignTool (Payload, ToolPath, PfxFile, Verbose = False):
     #
     # Create a temporary directory
     #
@@ -75,6 +74,8 @@ def SignPayloadSignTool (Payload, ToolPath, PfxFile):
     Command = Command + '/p7 {TempDir} '.format (TempDir = TempDirectoryName)
     Command = Command + '/f {PfxFile} '.format (PfxFile = PfxFile)
     Command = Command + TempFileName
+    if Verbose:
+        print (Command)
 
     #
     # Sign the input file using the specified private key
@@ -88,7 +89,7 @@ def SignPayloadSignTool (Payload, ToolPath, PfxFile):
 
     if Process.returncode != 0:
         shutil.rmtree (TempDirectoryName)
-        print (Result[1].decode(encoding='utf-8', errors='ignore'))
+        print (Result[1].decode())
         raise ValueError ('GenerateCapsule: error: signtool failed.')
 
     #
@@ -105,11 +106,11 @@ def SignPayloadSignTool (Payload, ToolPath, PfxFile):
     shutil.rmtree (TempDirectoryName)
     return Signature
 
-def VerifyPayloadSignTool (Payload, CertData, ToolPath, PfxFile):
+def VerifyPayloadSignTool (Payload, CertData, ToolPath, PfxFile, Verbose = False):
     print ('signtool verify is not supported.')
     raise ValueError ('GenerateCapsule: error: signtool verify is not supported.')
 
-def SignPayloadOpenSsl (Payload, ToolPath, SignerPrivateCertFile, OtherPublicCertFile, TrustedPublicCertFile):
+def SignPayloadOpenSsl (Payload, ToolPath, SignerPrivateCertFile, OtherPublicCertFile, TrustedPublicCertFile, Verbose = False):
     #
     # Build openssl command
     #
@@ -119,6 +120,8 @@ def SignPayloadOpenSsl (Payload, ToolPath, SignerPrivateCertFile, OtherPublicCer
     Command = Command + '"{Path}" '.format (Path = os.path.join (ToolPath, 'openssl'))
     Command = Command + 'smime -sign -binary -outform DER -md sha256 '
     Command = Command + '-signer "{Private}" -certfile "{Public}"'.format (Private = SignerPrivateCertFile, Public = OtherPublicCertFile)
+    if Verbose:
+        print (Command)
 
     #
     # Sign the input file using the specified private key and capture signature from STDOUT
@@ -131,12 +134,12 @@ def SignPayloadOpenSsl (Payload, ToolPath, SignerPrivateCertFile, OtherPublicCer
         raise ValueError ('GenerateCapsule: error: can not run openssl.')
 
     if Process.returncode != 0:
-        print (Result[1].decode(encoding='utf-8', errors='ignore'))
+        print (Result[1].decode())
         raise ValueError ('GenerateCapsule: error: openssl failed.')
 
     return Signature
 
-def VerifyPayloadOpenSsl (Payload, CertData, ToolPath, SignerPrivateCertFile, OtherPublicCertFile, TrustedPublicCertFile):
+def VerifyPayloadOpenSsl (Payload, CertData, ToolPath, SignerPrivateCertFile, OtherPublicCertFile, TrustedPublicCertFile, Verbose = False):
     #
     # Create a temporary directory
     #
@@ -167,6 +170,8 @@ def VerifyPayloadOpenSsl (Payload, CertData, ToolPath, SignerPrivateCertFile, Ot
     Command = Command + '"{Path}" '.format (Path = os.path.join (ToolPath, 'openssl'))
     Command = Command + 'smime -verify -inform DER '
     Command = Command + '-content {Content} -CAfile "{Public}"'.format (Content = TempFileName, Public = TrustedPublicCertFile)
+    if Verbose:
+        print (Command)
 
     #
     # Verify signature
@@ -180,7 +185,7 @@ def VerifyPayloadOpenSsl (Payload, CertData, ToolPath, SignerPrivateCertFile, Ot
 
     if Process.returncode != 0:
         shutil.rmtree (TempDirectoryName)
-        print (Result[1].decode(encoding='utf-8', errors='ignore'))
+        print (Result[1].decode())
         raise ValueError ('GenerateCapsule: error: openssl failed.')
 
     shutil.rmtree (TempDirectoryName)
@@ -212,6 +217,660 @@ if __name__ == '__main__':
             raise argparse.ArgumentTypeError (Message)
         return Value
 
+    def ConvertJsonValue (Config, FieldName, Convert, Required = True, Default = None, Open = False):
+        if FieldName not in Config:
+            if Required:
+                print ('GenerateCapsule: error: Payload descriptor invalid syntax. Could not find {Key} in payload descriptor.'.format(Key = FieldName))
+                sys.exit (1)
+            return Default
+        try:
+            Value = Convert (Config[FieldName])
+        except Exception as Message:
+            print ('GenerateCapsule: error: {Key} in payload descriptor has invalid syntax.  '.format (Key = FieldName) + str(Message))
+            sys.exit (1)
+        if Open:
+            try:
+                Value = open (Value, "rb")
+            except:
+                print ('GenerateCapsule: error: can not open file {File}'.format (File = FieldName))
+                sys.exit (1)
+        return Value
+
+    def DecodeJsonFileParse (Json):
+        if 'Payloads' not in Json:
+            print ('GenerateCapsule: error "Payloads" section not found in JSON file {File}'.format (File = args.JsonFile.name))
+            sys.exit (1)
+        for Config in Json['Payloads']:
+            #
+            # Parse fields from JSON
+            #
+            PayloadFile                  = ConvertJsonValue (Config, 'Payload', os.path.expandvars, Required = False)
+            Guid                         = ConvertJsonValue (Config, 'Guid', ValidateRegistryFormatGuid, Required = False)
+            FwVersion                    = ConvertJsonValue (Config, 'FwVersion', ValidateUnsignedInteger, Required = False)
+            LowestSupportedVersion       = ConvertJsonValue (Config, 'LowestSupportedVersion', ValidateUnsignedInteger, Required = False)
+            HardwareInstance             = ConvertJsonValue (Config, 'HardwareInstance', ValidateUnsignedInteger, Required = False, Default = 0)
+            MonotonicCount               = ConvertJsonValue (Config, 'MonotonicCount', ValidateUnsignedInteger, Required = False, Default = 0)
+            SignToolPfxFile              = ConvertJsonValue (Config, 'SignToolPfxFile', os.path.expandvars, Required = False, Default = None, Open = True)
+            OpenSslSignerPrivateCertFile = ConvertJsonValue (Config, 'OpenSslSignerPrivateCertFile', os.path.expandvars, Required = False, Default = None, Open = True)
+            OpenSslOtherPublicCertFile   = ConvertJsonValue (Config, 'OpenSslOtherPublicCertFile', os.path.expandvars, Required = False, Default = None, Open = True)
+            OpenSslTrustedPublicCertFile = ConvertJsonValue (Config, 'OpenSslTrustedPublicCertFile', os.path.expandvars, Required = False, Default = None, Open = True)
+            SigningToolPath              = ConvertJsonValue (Config, 'SigningToolPath', os.path.expandvars, Required = False, Default = None)
+            UpdateImageIndex             = ConvertJsonValue (Config, 'UpdateImageIndex', ValidateUnsignedInteger, Required = False, Default = 1)
+
+            PayloadDescriptorList.append (PayloadDescriptor (
+                                            PayloadFile,
+                                            Guid,
+                                            FwVersion,
+                                            LowestSupportedVersion,
+                                            MonotonicCount,
+                                            HardwareInstance,
+                                            UpdateImageIndex,
+                                            SignToolPfxFile,
+                                            OpenSslSignerPrivateCertFile,
+                                            OpenSslOtherPublicCertFile,
+                                            OpenSslTrustedPublicCertFile,
+                                            SigningToolPath
+                                            ))
+
+    def EncodeJsonFileParse (Json):
+        if 'EmbeddedDrivers' not in Json:
+            print ('GenerateCapsule: warning "EmbeddedDrivers" section not found in JSON file {File}'.format (File = args.JsonFile.name))
+        else:
+            for Config in Json['EmbeddedDrivers']:
+                EmbeddedDriverFile      = ConvertJsonValue(Config, 'Driver', os.path.expandvars, Open = True)
+                #
+                #Read EmbeddedDriver file
+                #
+                try:
+                    if args.Verbose:
+                        print ('Read EmbeddedDriver file {File}'.format (File = EmbeddedDriverFile.name))
+                    Driver = EmbeddedDriverFile.read()
+                except:
+                    print ('GenerateCapsule: error: can not read EmbeddedDriver file {File}'.format (File = EmbeddedDriverFile.name))
+                    sys.exit(1)
+                EmbeddedDriverDescriptorList.append (Driver)
+
+        if 'Payloads' not in Json:
+            print ('GenerateCapsule: error: "Payloads" section not found in JSON file {File}'.format (File = args.JsonFile.name))
+            sys.exit (1)
+        for Config in Json['Payloads']:
+            #
+            # Parse fields from JSON
+            #
+            PayloadFile                  = ConvertJsonValue (Config, 'Payload', os.path.expandvars, Open = True)
+            Guid                         = ConvertJsonValue (Config, 'Guid', ValidateRegistryFormatGuid)
+            FwVersion                    = ConvertJsonValue (Config, 'FwVersion', ValidateUnsignedInteger)
+            LowestSupportedVersion       = ConvertJsonValue (Config, 'LowestSupportedVersion', ValidateUnsignedInteger)
+            HardwareInstance             = ConvertJsonValue (Config, 'HardwareInstance', ValidateUnsignedInteger, Required = False, Default = 0)
+            UpdateImageIndex             = ConvertJsonValue (Config, 'UpdateImageIndex', ValidateUnsignedInteger, Required = False, Default = 1)
+            MonotonicCount               = ConvertJsonValue (Config, 'MonotonicCount', ValidateUnsignedInteger, Required = False, Default = 0)
+            SignToolPfxFile              = ConvertJsonValue (Config, 'SignToolPfxFile', os.path.expandvars, Required = False, Default = None, Open = True)
+            OpenSslSignerPrivateCertFile = ConvertJsonValue (Config, 'OpenSslSignerPrivateCertFile', os.path.expandvars, Required = False, Default = None, Open = True)
+            OpenSslOtherPublicCertFile   = ConvertJsonValue (Config, 'OpenSslOtherPublicCertFile', os.path.expandvars, Required = False, Default = None, Open = True)
+            OpenSslTrustedPublicCertFile = ConvertJsonValue (Config, 'OpenSslTrustedPublicCertFile', os.path.expandvars, Required = False, Default = None, Open = True)
+            SigningToolPath              = ConvertJsonValue (Config, 'SigningToolPath', os.path.expandvars, Required = False, Default = None)
+
+            #
+            # Read binary input file
+            #
+            try:
+                if args.Verbose:
+                    print ('Read binary input file {File}'.format (File = PayloadFile.name))
+                Payload = PayloadFile.read()
+            except:
+                print ('GenerateCapsule: error: can not read binary input file {File}'.format (File = PayloadFile.name))
+                sys.exit (1)
+            PayloadDescriptorList.append (PayloadDescriptor (
+                                            Payload,
+                                            Guid,
+                                            FwVersion,
+                                            LowestSupportedVersion,
+                                            MonotonicCount,
+                                            HardwareInstance,
+                                            UpdateImageIndex,
+                                            SignToolPfxFile,
+                                            OpenSslSignerPrivateCertFile,
+                                            OpenSslOtherPublicCertFile,
+                                            OpenSslTrustedPublicCertFile,
+                                            SigningToolPath
+                                            ))
+
+    def GenerateOutputJson (PayloadJsonDescriptorList):
+        PayloadJson = {
+                          "Payloads" : [
+                              {
+                                  "Guid": str(PayloadDescriptor.Guid).upper(),
+                                  "FwVersion": str(PayloadDescriptor.FwVersion),
+                                  "LowestSupportedVersion": str(PayloadDescriptor.LowestSupportedVersion),
+                                  "MonotonicCount": str(PayloadDescriptor.MonotonicCount),
+                                  "Payload": PayloadDescriptor.Payload,
+                                  "HardwareInstance": str(PayloadDescriptor.HardwareInstance),
+                                  "UpdateImageIndex": str(PayloadDescriptor.UpdateImageIndex),
+                                  "SignToolPfxFile": str(PayloadDescriptor.SignToolPfxFile),
+                                  "OpenSslSignerPrivateCertFile": str(PayloadDescriptor.OpenSslSignerPrivateCertFile),
+                                  "OpenSslOtherPublicCertFile": str(PayloadDescriptor.OpenSslOtherPublicCertFile),
+                                  "OpenSslTrustedPublicCertFile": str(PayloadDescriptor.OpenSslTrustedPublicCertFile),
+                                  "SigningToolPath": str(PayloadDescriptor.SigningToolPath)
+                              }for PayloadDescriptor in PayloadJsonDescriptorList
+                          ]
+                      }
+        OutputJsonFile = args.OutputFile.name + '.json'
+        if 'Payloads' in PayloadJson:
+            PayloadSection = PayloadJson ['Payloads']
+        Index = 0
+        for PayloadField in PayloadSection:
+            if PayloadJsonDescriptorList[Index].SignToolPfxFile is None:
+                del PayloadField ['SignToolPfxFile']
+            if PayloadJsonDescriptorList[Index].OpenSslSignerPrivateCertFile is None:
+                del PayloadField ['OpenSslSignerPrivateCertFile']
+            if PayloadJsonDescriptorList[Index].OpenSslOtherPublicCertFile is None:
+                del PayloadField ['OpenSslOtherPublicCertFile']
+            if PayloadJsonDescriptorList[Index].OpenSslTrustedPublicCertFile is None:
+                del PayloadField ['OpenSslTrustedPublicCertFile']
+            if PayloadJsonDescriptorList[Index].SigningToolPath is None:
+                del PayloadField ['SigningToolPath']
+            Index = Index + 1
+        Result = json.dumps (PayloadJson, indent=4, sort_keys=True, separators=(',', ': '))
+        OutputFile = open (OutputJsonFile, 'w')
+        OutputFile.write (Result)
+        OutputFile.close ()
+
+    def CheckArgumentConflict (args):
+        if args.Encode:
+            if args.InputFile:
+                print ('GenerateCapsule: error: Argument InputFile conflicts with Argument -j')
+                sys.exit (1)
+            if args.EmbeddedDriver:
+                print ('GenerateCapsule: error: Argument --embedded-driver conflicts with Argument -j')
+                sys.exit (1)
+        if args.Guid:
+            print ('GenerateCapsule: error: Argument --guid conflicts with Argument -j')
+            sys.exit (1)
+        if args.FwVersion:
+            print ('GenerateCapsule: error: Argument --fw-version conflicts with Argument -j')
+            sys.exit (1)
+        if args.LowestSupportedVersion:
+            print ('GenerateCapsule: error: Argument --lsv conflicts with Argument -j')
+            sys.exit (1)
+        if args.MonotonicCount:
+            print ('GenerateCapsule: error: Argument --monotonic-count conflicts with Argument -j')
+            sys.exit (1)
+        if args.HardwareInstance:
+            print ('GenerateCapsule: error: Argument --hardware-instance conflicts with Argument -j')
+            sys.exit (1)
+        if args.SignToolPfxFile:
+            print ('GenerateCapsule: error: Argument --pfx-file conflicts with Argument -j')
+            sys.exit (1)
+        if args.OpenSslSignerPrivateCertFile:
+            print ('GenerateCapsule: error: Argument --signer-private-cert conflicts with Argument -j')
+            sys.exit (1)
+        if args.OpenSslOtherPublicCertFile:
+            print ('GenerateCapsule: error: Argument --other-public-cert conflicts with Argument -j')
+            sys.exit (1)   
+        if args.OpenSslTrustedPublicCertFile:
+            print ('GenerateCapsule: error: Argument --trusted-public-cert conflicts with Argument -j')
+            sys.exit (1)   
+        if args.SigningToolPath:
+            print ('GenerateCapsule: error: Argument --signing-tool-path conflicts with Argument -j')
+            sys.exit (1)
+
+    class PayloadDescriptor (object):
+        def __init__(self,
+                     Payload,
+                     Guid,
+                     FwVersion,
+                     LowestSupportedVersion,
+                     MonotonicCount               = 0,
+                     HardwareInstance             = 0,
+                     UpdateImageIndex             = 1,
+                     SignToolPfxFile              = None,
+                     OpenSslSignerPrivateCertFile = None,
+                     OpenSslOtherPublicCertFile   = None,
+                     OpenSslTrustedPublicCertFile = None,
+                     SigningToolPath              = None
+                     ):
+            self.Payload                      = Payload
+            self.Guid                         = Guid
+            self.FwVersion                    = FwVersion
+            self.LowestSupportedVersion       = LowestSupportedVersion
+            self.MonotonicCount               = MonotonicCount
+            self.HardwareInstance             = HardwareInstance
+            self.UpdateImageIndex             = UpdateImageIndex
+            self.SignToolPfxFile              = SignToolPfxFile
+            self.OpenSslSignerPrivateCertFile = OpenSslSignerPrivateCertFile
+            self.OpenSslOtherPublicCertFile   = OpenSslOtherPublicCertFile
+            self.OpenSslTrustedPublicCertFile = OpenSslTrustedPublicCertFile
+            self.SigningToolPath              = SigningToolPath
+
+            self.UseSignTool = self.SignToolPfxFile is not None
+            self.UseOpenSsl  = (self.OpenSslSignerPrivateCertFile is not None and
+                                self.OpenSslOtherPublicCertFile is not None and
+                                self.OpenSslTrustedPublicCertFile is not None)
+            self.AnyOpenSsl  = (self.OpenSslSignerPrivateCertFile is not None or
+                                self.OpenSslOtherPublicCertFile is not None or
+                                self.OpenSslTrustedPublicCertFile is not None)
+
+        def Validate(self, args):
+            if self.UseSignTool and self.AnyOpenSsl:
+                raise argparse.ArgumentTypeError ('Providing both signtool and OpenSSL options is not supported')
+            if not self.UseSignTool and not self.UseOpenSsl and self.AnyOpenSsl:
+                if args.JsonFile:
+                    raise argparse.ArgumentTypeError ('the following JSON fields are required for OpenSSL: OpenSslSignerPrivateCertFile, OpenSslOtherPublicCertFile, OpenSslTrustedPublicCertFile')
+                else:
+                    raise argparse.ArgumentTypeError ('the following options are required for OpenSSL: --signer-private-cert, --other-public-cert, --trusted-public-cert')
+            if self.UseSignTool and platform.system() != 'Windows':
+                raise argparse.ArgumentTypeError ('Use of signtool is not supported on this operating system.')
+            if args.Encode:
+                if self.FwVersion is None or self.LowestSupportedVersion is None:
+                    if args.JsonFile:
+                        raise argparse.ArgumentTypeError ('the following JSON fields are required: FwVersion, LowestSupportedVersion')
+                    else:
+                        raise argparse.ArgumentTypeError ('the following options are required: --fw-version, --lsv')
+                if self.FwVersion > 0xFFFFFFFF:
+                    if args.JsonFile:
+                        raise argparse.ArgumentTypeError ('JSON field FwVersion must be an integer in range 0x0..0xffffffff')
+                    else:
+                        raise argparse.ArgumentTypeError ('--fw-version must be an integer in range 0x0..0xffffffff')
+                if self.LowestSupportedVersion > 0xFFFFFFFF:
+                    if args.JsonFile:
+                        raise argparse.ArgumentTypeError ('JSON field LowestSupportedVersion must be an integer in range 0x0..0xffffffff')
+                    else:
+                        raise argparse.ArgumentTypeError ('--lsv must be an integer in range 0x0..0xffffffff')
+
+            if args.Encode:
+                if self.Guid is None:
+                    if args.JsonFile:
+                        raise argparse.ArgumentTypeError ('the following JSON field is required: Guid')
+                    else:
+                        raise argparse.ArgumentTypeError ('the following option is required: --guid')
+                if self.HardwareInstance > 0xFFFFFFFFFFFFFFFF:
+                    if args.JsonFile:
+                        raise argparse.ArgumentTypeError ('JSON field HardwareInstance must be an integer in range 0x0..0xffffffffffffffff')
+                    else:
+                        raise argparse.ArgumentTypeError ('--hardware-instance must be an integer in range 0x0..0xffffffffffffffff')
+                if self.MonotonicCount > 0xFFFFFFFFFFFFFFFF:
+                    if args.JsonFile:
+                        raise argparse.ArgumentTypeError ('JSON field MonotonicCount must be an integer in range 0x0..0xffffffffffffffff')
+                    else:
+                        raise argparse.ArgumentTypeError ('--monotonic-count must be an integer in range 0x0..0xffffffffffffffff')
+                if self.UpdateImageIndex >0xFF:
+                    if args.JsonFile:
+                        raise argparse.ArgumentTypeError ('JSON field UpdateImageIndex must be an integer in range 0x0..0xff')
+                    else:
+                        raise argparse.ArgumentTypeError ('--update-image-index must be an integer in range 0x0..0xff')
+
+            if self.UseSignTool:
+                self.SignToolPfxFile.close()
+                self.SignToolPfxFile = self.SignToolPfxFile.name
+            if self.UseOpenSsl:
+                self.OpenSslSignerPrivateCertFile.close()
+                self.OpenSslOtherPublicCertFile.close()
+                self.OpenSslTrustedPublicCertFile.close()
+                self.OpenSslSignerPrivateCertFile = self.OpenSslSignerPrivateCertFile.name
+                self.OpenSslOtherPublicCertFile   = self.OpenSslOtherPublicCertFile.name
+                self.OpenSslTrustedPublicCertFile = self.OpenSslTrustedPublicCertFile.name
+
+            #
+            # Perform additional argument verification
+            #
+            if args.Encode:
+                if 'PersistAcrossReset' not in args.CapsuleFlag:
+                    if 'InitiateReset' in args.CapsuleFlag:
+                        raise argparse.ArgumentTypeError ('--capflag InitiateReset also requires --capflag PersistAcrossReset')
+                if args.CapsuleOemFlag > 0xFFFF:
+                    raise argparse.ArgumentTypeError ('--capoemflag must be an integer between 0x0000 and 0xffff')
+
+            return True
+
+
+    def Encode (PayloadDescriptorList, EmbeddedDriverDescriptorList, Buffer):
+        if args.JsonFile:
+            CheckArgumentConflict(args)
+            try:
+                Json = json.loads (args.JsonFile.read ())
+            except Exception as Message:
+                print ('GenerateCapsule: error: ' + str(Message))
+                sys.exit (1)
+            EncodeJsonFileParse(Json)
+        else:
+            for Driver in args.EmbeddedDriver:
+                EmbeddedDriverDescriptorList.append (Driver.read())
+            PayloadDescriptorList.append (PayloadDescriptor (
+                                            Buffer,
+                                            args.Guid,
+                                            args.FwVersion,
+                                            args.LowestSupportedVersion,
+                                            args.MonotonicCount,
+                                            args.HardwareInstance,
+                                            args.UpdateImageIndex,
+                                            args.SignToolPfxFile,
+                                            args.OpenSslSignerPrivateCertFile,
+                                            args.OpenSslOtherPublicCertFile,
+                                            args.OpenSslTrustedPublicCertFile,
+                                            args.SigningToolPath
+                                            ))
+        for SinglePayloadDescriptor in PayloadDescriptorList:
+            try:
+                SinglePayloadDescriptor.Validate (args)
+            except Exception as Message:
+                print ('GenerateCapsule: error: ' + str(Message))
+                sys.exit (1)
+        for SinglePayloadDescriptor in PayloadDescriptorList:
+            Result = SinglePayloadDescriptor.Payload
+            try:
+                FmpPayloadHeader.FwVersion              = SinglePayloadDescriptor.FwVersion
+                FmpPayloadHeader.LowestSupportedVersion = SinglePayloadDescriptor.LowestSupportedVersion
+                FmpPayloadHeader.Payload                = SinglePayloadDescriptor.Payload
+                Result = FmpPayloadHeader.Encode ()
+                if args.Verbose:
+                    FmpPayloadHeader.DumpInfo ()
+            except:
+                raise
+                print ('GenerateCapsule: error: can not encode FMP Payload Header')
+                sys.exit (1)
+            if SinglePayloadDescriptor.UseOpenSsl or SinglePayloadDescriptor.UseSignTool:
+                #
+                # Sign image with 64-bit MonotonicCount appended to end of image
+                #
+                try:
+                    if SinglePayloadDescriptor.UseSignTool:
+                        CertData = SignPayloadSignTool (
+                            Result + struct.pack ('<Q', SinglePayloadDescriptor.MonotonicCount),
+                            SinglePayloadDescriptor.SigningToolPath,
+                            SinglePayloadDescriptor.SignToolPfxFile,
+                            Verbose = args.Verbose
+                        )
+                    else:
+                        CertData = SignPayloadOpenSsl (
+                            Result + struct.pack ('<Q', SinglePayloadDescriptor.MonotonicCount),
+                            SinglePayloadDescriptor.SigningToolPath,
+                            SinglePayloadDescriptor.OpenSslSignerPrivateCertFile,
+                            SinglePayloadDescriptor.OpenSslOtherPublicCertFile,
+                            SinglePayloadDescriptor.OpenSslTrustedPublicCertFile,
+                            Verbose = args.Verbose
+                        )
+                except:
+                    print ('GenerateCapsule: error: can not sign payload')
+                    sys.exit (1)
+
+                try:
+                    FmpAuthHeader.MonotonicCount = SinglePayloadDescriptor.MonotonicCount
+                    FmpAuthHeader.CertData       = CertData
+                    FmpAuthHeader.Payload        = Result
+                    Result = FmpAuthHeader.Encode ()
+                    if args.Verbose:
+                        FmpAuthHeader.DumpInfo ()
+                except:
+                    print ('GenerateCapsule: error: can not encode FMP Auth Header')
+                    sys.exit (1)
+            FmpCapsuleHeader.AddPayload (SinglePayloadDescriptor.Guid, Result, HardwareInstance = SinglePayloadDescriptor.HardwareInstance, UpdateImageIndex = SinglePayloadDescriptor.UpdateImageIndex)
+        try:
+            for EmbeddedDriver in EmbeddedDriverDescriptorList:
+                FmpCapsuleHeader.AddEmbeddedDriver(EmbeddedDriver)
+
+            Result = FmpCapsuleHeader.Encode ()
+            if args.Verbose:
+                FmpCapsuleHeader.DumpInfo ()
+        except:
+            print ('GenerateCapsule: error: can not encode FMP Capsule Header')
+            sys.exit (1)
+
+        try:
+            UefiCapsuleHeader.OemFlags            = args.CapsuleOemFlag
+            UefiCapsuleHeader.PersistAcrossReset  = 'PersistAcrossReset'  in args.CapsuleFlag
+            UefiCapsuleHeader.PopulateSystemTable = False
+            UefiCapsuleHeader.InitiateReset       = 'InitiateReset'       in args.CapsuleFlag
+            UefiCapsuleHeader.Payload             = Result
+            Result = UefiCapsuleHeader.Encode ()
+            if args.Verbose:
+                UefiCapsuleHeader.DumpInfo ()
+        except:
+            print ('GenerateCapsule: error: can not encode UEFI Capsule Header')
+            sys.exit (1)
+        try:
+            if args.Verbose:
+                print ('Write binary output file {File}'.format (File = args.OutputFile.name))
+            args.OutputFile.write (Result)
+            args.OutputFile.close ()
+        except:
+            print ('GenerateCapsule: error: can not write binary output file {File}'.format (File = args.OutputFile.name))
+            sys.exit (1)
+
+    def Decode (PayloadDescriptorList, PayloadJsonDescriptorList, Buffer):
+        if args.JsonFile:
+            CheckArgumentConflict(args)
+        #
+        # Parse payload descriptors from JSON
+        #
+            try:
+                Json = json.loads (args.JsonFile.read())
+            except Exception as Message:
+                print ('GenerateCapsule: error: ' + str(Message))
+                sys.exit (1)
+            DecodeJsonFileParse (Json)    
+        else:
+            PayloadDescriptorList.append (PayloadDescriptor (
+                                            Buffer,
+                                            args.Guid,
+                                            args.FwVersion,
+                                            args.LowestSupportedVersion,
+                                            args.MonotonicCount,
+                                            args.HardwareInstance,
+                                            args.UpdateImageIndex,
+                                            args.SignToolPfxFile,
+                                            args.OpenSslSignerPrivateCertFile,
+                                            args.OpenSslOtherPublicCertFile,
+                                            args.OpenSslTrustedPublicCertFile,
+                                            args.SigningToolPath
+                                            ))
+        #
+        # Perform additional verification on payload descriptors
+        #
+        for SinglePayloadDescriptor in PayloadDescriptorList:
+            try:
+                SinglePayloadDescriptor.Validate (args)
+            except Exception as Message:
+                print ('GenerateCapsule: error: ' + str(Message))
+                sys.exit (1)
+        try:
+            Result = UefiCapsuleHeader.Decode (Buffer)
+            if len (Result) > 0:
+                Result = FmpCapsuleHeader.Decode (Result)
+                if args.JsonFile:
+                    if FmpCapsuleHeader.PayloadItemCount != len (PayloadDescriptorList):
+                        CapsulePayloadNum = FmpCapsuleHeader.PayloadItemCount
+                        JsonPayloadNum = len (PayloadDescriptorList)
+                        print ('GenerateCapsule: Decode error: {JsonPayloadNumber} payloads in JSON file {File} and {CapsulePayloadNumber} payloads in Capsule {CapsuleName}'.format (JsonPayloadNumber = JsonPayloadNum, File = args.JsonFile.name, CapsulePayloadNumber = CapsulePayloadNum, CapsuleName = args.InputFile.name))
+                        sys.exit (1)
+                    for Index in range (0, FmpCapsuleHeader.PayloadItemCount):
+                        if Index < len (PayloadDescriptorList):
+                            GUID = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).UpdateImageTypeId
+                            HardwareInstance = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).UpdateHardwareInstance
+                            UpdateImageIndex = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).UpdateImageIndex
+                            if PayloadDescriptorList[Index].Guid != GUID or PayloadDescriptorList[Index].HardwareInstance != HardwareInstance:
+                                print ('GenerateCapsule: Decode error: Guid or HardwareInstance pair in input JSON file {File} does not match the payload {PayloadIndex} in Capsule {InputCapsule}'.format (File = args.JsonFile.name, PayloadIndex = Index + 1, InputCapsule = args.InputFile.name))
+                                sys.exit (1)
+                            PayloadDescriptorList[Index].Payload = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).Payload
+                            DecodeJsonOutput = args.OutputFile.name + '.Payload.{Index:d}.bin'.format (Index = Index + 1)
+                            PayloadJsonDescriptorList.append (PayloadDescriptor (
+                                                                DecodeJsonOutput,
+                                                                GUID,
+                                                                None,
+                                                                None,
+                                                                None,
+                                                                HardwareInstance,
+                                                                UpdateImageIndex,
+                                                                PayloadDescriptorList[Index].SignToolPfxFile,
+                                                                PayloadDescriptorList[Index].OpenSslSignerPrivateCertFile,
+                                                                PayloadDescriptorList[Index].OpenSslOtherPublicCertFile,
+                                                                PayloadDescriptorList[Index].OpenSslTrustedPublicCertFile,
+                                                                PayloadDescriptorList[Index].SigningToolPath
+                                                                ))
+                else:
+                    PayloadDescriptorList[0].Payload = FmpCapsuleHeader.GetFmpCapsuleImageHeader (0).Payload
+                    for Index in range (0, FmpCapsuleHeader.PayloadItemCount):
+                        if Index > 0:
+                            PayloadDecodeFile = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).Payload
+                            PayloadDescriptorList.append (PayloadDescriptor (PayloadDecodeFile,
+                                                            None,
+                                                            None,
+                                                            None,
+                                                            None,
+                                                            None,
+                                                            None,
+                                                            None,
+                                                            None,
+                                                            None,
+                                                            None,
+                                                            None
+                                                            ))
+                        GUID = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).UpdateImageTypeId
+                        HardwareInstance = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).UpdateHardwareInstance
+                        UpdateImageIndex = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).UpdateImageIndex
+                        DecodeJsonOutput = args.OutputFile.name + '.Payload.{Index:d}.bin'.format (Index = Index + 1)
+                        PayloadJsonDescriptorList.append (PayloadDescriptor (
+                                                            DecodeJsonOutput,
+                                                            GUID,
+                                                            None,
+                                                            None,
+                                                            None,
+                                                            HardwareInstance,
+                                                            UpdateImageIndex,
+                                                            PayloadDescriptorList[Index].SignToolPfxFile,
+                                                            PayloadDescriptorList[Index].OpenSslSignerPrivateCertFile,
+                                                            PayloadDescriptorList[Index].OpenSslOtherPublicCertFile,
+                                                            PayloadDescriptorList[Index].OpenSslTrustedPublicCertFile,
+                                                            PayloadDescriptorList[Index].SigningToolPath
+                                                            ))
+                JsonIndex = 0
+                for SinglePayloadDescriptor in PayloadDescriptorList:
+                    if args.Verbose:
+                        print ('========')
+                        UefiCapsuleHeader.DumpInfo ()
+                        print ('--------')
+                        FmpCapsuleHeader.DumpInfo ()
+                    if FmpAuthHeader.IsSigned(SinglePayloadDescriptor.Payload):
+                        if not SinglePayloadDescriptor.UseOpenSsl and not SinglePayloadDescriptor.UseSignTool:
+                            print ('GenerateCapsule: decode warning: can not verify singed payload without cert or pfx file. Index = {Index}'.format (Index = JsonIndex + 1))
+                        SinglePayloadDescriptor.Payload = FmpAuthHeader.Decode (SinglePayloadDescriptor.Payload)
+                        PayloadJsonDescriptorList[JsonIndex].MonotonicCount = FmpAuthHeader.MonotonicCount
+                        if args.Verbose:
+                            print ('--------')
+                            FmpAuthHeader.DumpInfo ()
+
+                        #
+                        # Verify Image with 64-bit MonotonicCount appended to end of image
+                        #
+                        try:
+                          if SinglePayloadDescriptor.UseSignTool:
+                              CertData = VerifyPayloadSignTool (
+                                           FmpAuthHeader.Payload + struct.pack ('<Q', FmpAuthHeader.MonotonicCount),
+                                           FmpAuthHeader.CertData,
+                                           SinglePayloadDescriptor.SigningToolPath,
+                                           SinglePayloadDescriptor.SignToolPfxFile,
+                                           Verbose = args.Verbose
+                                           )
+                          else:
+                              CertData = VerifyPayloadOpenSsl (
+                                           FmpAuthHeader.Payload + struct.pack ('<Q', FmpAuthHeader.MonotonicCount),
+                                           FmpAuthHeader.CertData,
+                                           SinglePayloadDescriptor.SigningToolPath,
+                                           SinglePayloadDescriptor.OpenSslSignerPrivateCertFile,
+                                           SinglePayloadDescriptor.OpenSslOtherPublicCertFile,
+                                           SinglePayloadDescriptor.OpenSslTrustedPublicCertFile,
+                                           Verbose = args.Verbose
+                                           )
+                        except ValueError:
+                            print ('GenerateCapsule: warning: payload verification failed Index = {Index}'.format (Index = JsonIndex + 1))
+                    else:
+                        if args.Verbose:
+                            print ('--------')
+                            print ('No EFI_FIRMWARE_IMAGE_AUTHENTICATION')
+                    try:
+                        SinglePayloadDescriptor.Payload = FmpPayloadHeader.Decode (SinglePayloadDescriptor.Payload)
+                        PayloadJsonDescriptorList[JsonIndex].FwVersion = FmpPayloadHeader.FwVersion
+                        PayloadJsonDescriptorList[JsonIndex].LowestSupportedVersion = FmpPayloadHeader.LowestSupportedVersion
+                        JsonIndex = JsonIndex + 1
+                        if args.Verbose:
+                            print ('--------')
+                            FmpPayloadHeader.DumpInfo ()
+                            print ('========')
+                    except:
+                        if args.Verbose:
+                            print ('--------')
+                            print ('No FMP_PAYLOAD_HEADER')
+                            print ('========')
+                        raise
+                #
+                # Write embedded driver file(s)
+                #
+                for Index in range (0, FmpCapsuleHeader.EmbeddedDriverCount):
+                    EmbeddedDriverBuffer = FmpCapsuleHeader.GetEmbeddedDriver (Index)
+                    EmbeddedDriverPath = args.OutputFile.name + '.EmbeddedDriver.{Index:d}.efi'.format (Index = Index + 1)
+                    try:
+                        if args.Verbose:
+                            print ('Write embedded driver file {File}'.format (File = EmbeddedDriverPath))
+                        EmbeddedDriverFile = open (EmbeddedDriverPath, 'wb')
+                        EmbeddedDriverFile.write (EmbeddedDriverBuffer)
+                        EmbeddedDriverFile.close ()
+                    except:
+                        print ('GenerateCapsule: error: can not write embedded driver file {File}'.format (File = EmbeddedDriverPath))
+                        sys.exit (1)
+
+        except:
+            raise
+            print ('GenerateCapsule: error: can not decode capsule')
+            sys.exit (1)
+        GenerateOutputJson(PayloadJsonDescriptorList)
+        PayloadIndex = 0
+        for SinglePayloadDescriptor in PayloadDescriptorList:
+            if args.OutputFile is None:
+                print ('GenerateCapsule: Decode error: OutputFile is needed for decode output')
+                sys.exit (1)
+            try:
+                if args.Verbose:
+                    print ('Write binary output file {File}'.format (File = args.OutputFile.name))
+                PayloadDecodePath = args.OutputFile.name + '.Payload.{Index:d}.bin'.format (Index = PayloadIndex + 1)
+                PayloadDecodeFile = open (PayloadDecodePath, 'wb')
+                PayloadDecodeFile.write (SinglePayloadDescriptor.Payload)
+                PayloadDecodeFile.close ()
+                PayloadIndex = PayloadIndex + 1
+            except:
+                print ('GenerateCapsule: error: can not write binary output file {File}'.format (File = SinglePayloadDescriptor.OutputFile.name))
+                sys.exit (1)
+
+    def DumpInfo (Buffer, args):
+        if args.OutputFile is not None:
+            raise argparse.ArgumentTypeError ('the following option is not supported for dumpinfo operations: --output')
+        try:
+            Result = UefiCapsuleHeader.Decode (Buffer)
+            print ('========')
+            UefiCapsuleHeader.DumpInfo ()
+            if len (Result) > 0:
+                FmpCapsuleHeader.Decode (Result)
+                print ('--------')
+                FmpCapsuleHeader.DumpInfo ()
+                for Index in range (0, FmpCapsuleHeader.PayloadItemCount):
+                    Result = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).Payload
+                    try:
+                        Result = FmpAuthHeader.Decode (Result)
+                        print ('--------')
+                        FmpAuthHeader.DumpInfo ()
+                    except:
+                        print ('--------')
+                        print ('No EFI_FIRMWARE_IMAGE_AUTHENTICATION')
+                    try:
+                        Result = FmpPayloadHeader.Decode (Result)
+                        print ('--------')
+                        FmpPayloadHeader.DumpInfo ()
+                    except:
+                        print ('--------')
+                        print ('No FMP_PAYLOAD_HEADER')
+                    print ('========')
+        except:
+            print ('GenerateCapsule: error: can not decode capsule')
+            sys.exit (1)
+
     #
     # Create command line argument parser object
     #
@@ -226,7 +885,7 @@ if __name__ == '__main__':
     #
     # Add input and output file arguments
     #
-    parser.add_argument("InputFile",  type = argparse.FileType('rb'),
+    parser.add_argument("InputFile",  type = argparse.FileType('rb'), nargs='?',
                         help = "Input binary payload filename.")
     parser.add_argument("-o", "--output", dest = 'OutputFile', type = argparse.FileType('wb'),
                         help = "Output filename.")
@@ -243,6 +902,8 @@ if __name__ == '__main__':
     #
     # Add optional arguments for this command
     #
+    parser.add_argument ("-j", "--json-file", dest = 'JsonFile', type=argparse.FileType('r'),
+                         help = "JSON configuration file for multiple payloads and embedded drivers.")
     parser.add_argument ("--capflag", dest = 'CapsuleFlag', action='append', default = [],
                          choices=['PersistAcrossReset', 'InitiateReset'],
                          help = "Capsule flag can be PersistAcrossReset or InitiateReset or not set")
@@ -250,7 +911,7 @@ if __name__ == '__main__':
                          help = "Capsule OEM Flag is an integer between 0x0000 and 0xffff.")
 
     parser.add_argument ("--guid", dest = 'Guid', type = ValidateRegistryFormatGuid,
-                         help = "The FMP/ESRT GUID in registry format.  Required for encode operations.")
+                         help = "The FMP/ESRT GUID in registry format.  Required for single payload encode operations.")
     parser.add_argument ("--hardware-instance", dest = 'HardwareInstance', type = ValidateUnsignedInteger, default = 0x0000000000000000,
                          help = "The 64-bit hardware instance.  The default is 0x0000000000000000")
 
@@ -259,9 +920,9 @@ if __name__ == '__main__':
                          help = "64-bit monotonic count value in header.  Default is 0x0000000000000000.")
 
     parser.add_argument ("--fw-version", dest = 'FwVersion', type = ValidateUnsignedInteger,
-                         help = "The 32-bit version of the binary payload (e.g. 0x11223344 or 5678).  Required for encode operations that sign a payload.")
+                         help = "The 32-bit version of the binary payload (e.g. 0x11223344 or 5678).  Required for encode operations.")
     parser.add_argument ("--lsv", dest = 'LowestSupportedVersion', type = ValidateUnsignedInteger,
-                         help = "The 32-bit lowest supported version of the binary payload (e.g. 0x11223344 or 5678).  Required for encode operations that sign a payload.")
+                         help = "The 32-bit lowest supported version of the binary payload (e.g. 0x11223344 or 5678).  Required for encode operations.")
 
     parser.add_argument ("--pfx-file", dest='SignToolPfxFile', type=argparse.FileType('rb'),
                          help="signtool PFX certificate filename.")
@@ -276,6 +937,9 @@ if __name__ == '__main__':
     parser.add_argument ("--signing-tool-path", dest = 'SigningToolPath',
                          help = "Path to signtool or OpenSSL tool.  Optional if path to tools are already in PATH.")
 
+    parser.add_argument ("--embedded-driver", dest = 'EmbeddedDriver', type = argparse.FileType('rb'), action='append', default = [],
+                         help = "Path to embedded UEFI driver to add to capsule.")
+
     #
     # Add optional arguments common to all operations
     #
@@ -286,79 +950,29 @@ if __name__ == '__main__':
                          help = "Disable all messages except fatal errors.")
     parser.add_argument ("--debug", dest = 'Debug', type = int, metavar = '[0-9]', choices = range (0, 10), default = 0,
                          help = "Set debug level")
+    parser.add_argument ("--update-image-index", dest = 'UpdateImageIndex', type = ValidateUnsignedInteger, default = 0x01, help = "unique number identifying the firmware image within the device ")
 
     #
     # Parse command line arguments
     #
     args = parser.parse_args()
 
-    #
-    # Perform additional argument verification
-    #
-    if args.Encode:
-        if args.Guid is None:
-            parser.error ('the following option is required: --guid')
-        if 'PersistAcrossReset' not in args.CapsuleFlag:
-            if 'InitiateReset' in args.CapsuleFlag:
-                parser.error ('--capflag InitiateReset also requires --capflag PersistAcrossReset')
-        if args.CapsuleOemFlag > 0xFFFF:
-            parser.error ('--capoemflag must be an integer between 0x0000 and 0xffff')
-        if args.HardwareInstance > 0xFFFFFFFFFFFFFFFF:
-            parser.error ('--hardware-instance must be an integer in range 0x0..0xffffffffffffffff')
-        if args.MonotonicCount > 0xFFFFFFFFFFFFFFFF:
-            parser.error ('--monotonic-count must be an integer in range 0x0..0xffffffffffffffff')
-
-    UseSignTool = args.SignToolPfxFile is not None
-    UseOpenSsl  = (args.OpenSslSignerPrivateCertFile is not None and
-                   args.OpenSslOtherPublicCertFile is not None and
-                   args.OpenSslTrustedPublicCertFile is not None)
-    AnyOpenSsl  = (args.OpenSslSignerPrivateCertFile is not None or
-                   args.OpenSslOtherPublicCertFile is not None or
-                   args.OpenSslTrustedPublicCertFile is not None)
-    if args.Encode or args.Decode:
-        if args.OutputFile is None:
-            parser.error ('the following option is required for all encode and decode operations: --output')
-
-        if UseSignTool and AnyOpenSsl:
-            parser.error ('Providing both signtool and OpenSSL options is not supported')
-        if not UseSignTool and not UseOpenSsl and AnyOpenSsl:
-            parser.error ('all the following options are required for OpenSSL: --signer-private-cert, --other-public-cert, --trusted-public-cert')
-        if UseSignTool and platform.system() != 'Windows':
-            parser.error ('Use of signtool is not supported on this operating system.')
-        if args.Encode and (UseSignTool or UseOpenSsl):
-            if args.FwVersion is None or args.LowestSupportedVersion is None:
-                parser.error ('the following options are required: --fw-version, --lsv')
-            if args.FwVersion > 0xFFFFFFFF:
-                parser.error ('--fw-version must be an integer in range 0x0..0xffffffff')
-            if args.LowestSupportedVersion > 0xFFFFFFFF:
-                parser.error ('--lsv must be an integer in range 0x0..0xffffffff')
-
-        if UseSignTool:
-            args.SignToolPfxFile.close()
-            args.SignToolPfxFile = args.SignToolPfxFile.name
-        if UseOpenSsl:
-            args.OpenSslSignerPrivateCertFile.close()
-            args.OpenSslOtherPublicCertFile.close()
-            args.OpenSslTrustedPublicCertFile.close()
-            args.OpenSslSignerPrivateCertFile = args.OpenSslSignerPrivateCertFile.name
-            args.OpenSslOtherPublicCertFile   = args.OpenSslOtherPublicCertFile.name
-            args.OpenSslTrustedPublicCertFile = args.OpenSslTrustedPublicCertFile.name
-
-    if args.DumpInfo:
-        if args.OutputFile is not None:
-            parser.error ('the following option is not supported for dumpinfo operations: --output')
-
     #
     # Read binary input file
     #
-    try:
-        if args.Verbose:
-            print ('Read binary input file {File}'.format (File = args.InputFile.name))
-        Buffer = args.InputFile.read ()
-        args.InputFile.close ()
-    except:
-        print ('GenerateCapsule: error: can not read binary input file {File}'.format (File = args.InputFile.name))
-        sys.exit (1)
+    Buffer = ''
+    if args.InputFile:
+        if os.path.getsize (args.InputFile.name) == 0:
+            print ('GenerateCapsule: error: InputFile {File} is empty'.format (File = args.InputFile.name))
+            sys.exit (1)
+        try:
+            if args.Verbose:
+                print ('Read binary input file {File}'.format (File = args.InputFile.name))
+            Buffer = args.InputFile.read ()
+            args.InputFile.close ()
+        except:
+            print ('GenerateCapsule: error: can not read binary input file {File}'.format (File = args.InputFile.name))
+            sys.exit (1)
 
     #
     # Create objects
@@ -368,182 +982,27 @@ if __name__ == '__main__':
     FmpAuthHeader     = FmpAuthHeaderClass ()
     FmpPayloadHeader  = FmpPayloadHeaderClass ()
 
-    if args.Encode:
-        Result = Buffer
-        if UseSignTool or UseOpenSsl:
-            try:
-                FmpPayloadHeader.FwVersion              = args.FwVersion
-                FmpPayloadHeader.LowestSupportedVersion = args.LowestSupportedVersion
-                FmpPayloadHeader.Payload                = Result
-                Result = FmpPayloadHeader.Encode ()
-                if args.Verbose:
-                    FmpPayloadHeader.DumpInfo ()
-            except:
-                print ('GenerateCapsule: error: can not encode FMP Payload Header')
-                sys.exit (1)
-
-            #
-            # Sign image with 64-bit MonotonicCount appended to end of image
-            #
-            try:
-                if UseSignTool:
-                    CertData = SignPayloadSignTool (
-                                 Result + struct.pack ('<Q', args.MonotonicCount),
-                                 args.SigningToolPath,
-                                 args.SignToolPfxFile
-                                 )
-                else:
-                    CertData = SignPayloadOpenSsl (
-                                 Result + struct.pack ('<Q', args.MonotonicCount),
-                                 args.SigningToolPath,
-                                 args.OpenSslSignerPrivateCertFile,
-                                 args.OpenSslOtherPublicCertFile,
-                                 args.OpenSslTrustedPublicCertFile
-                                 )
-            except:
-                print ('GenerateCapsule: error: can not sign payload')
-                sys.exit (1)
-
-            try:
-                FmpAuthHeader.MonotonicCount = args.MonotonicCount
-                FmpAuthHeader.CertData       = CertData
-                FmpAuthHeader.Payload        = Result
-                Result = FmpAuthHeader.Encode ()
-                if args.Verbose:
-                    FmpAuthHeader.DumpInfo ()
-            except:
-                print ('GenerateCapsule: error: can not encode FMP Auth Header')
-                sys.exit (1)
-
-        try:
-            FmpCapsuleHeader.AddPayload (args.Guid, Result, HardwareInstance = args.HardwareInstance)
-            Result = FmpCapsuleHeader.Encode ()
-            if args.Verbose:
-                FmpCapsuleHeader.DumpInfo ()
-        except:
-            print ('GenerateCapsule: error: can not encode FMP Capsule Header')
-            sys.exit (1)
-
-        try:
-            UefiCapsuleHeader.OemFlags            = args.CapsuleOemFlag
-            UefiCapsuleHeader.PersistAcrossReset  = 'PersistAcrossReset'  in args.CapsuleFlag
-            UefiCapsuleHeader.PopulateSystemTable = False
-            UefiCapsuleHeader.InitiateReset       = 'InitiateReset'       in args.CapsuleFlag
-            UefiCapsuleHeader.Payload             = Result
-            Result = UefiCapsuleHeader.Encode ()
-            if args.Verbose:
-                UefiCapsuleHeader.DumpInfo ()
-        except:
-            print ('GenerateCapsule: error: can not encode UEFI Capsule Header')
-            sys.exit (1)
-
-    elif args.Decode:
-        try:
-            Result = UefiCapsuleHeader.Decode (Buffer)
-            FmpCapsuleHeader.Decode (Result)
-            Result = FmpCapsuleHeader.GetFmpCapsuleImageHeader (0).Payload
-            if args.Verbose:
-                print ('========')
-                UefiCapsuleHeader.DumpInfo ()
-                print ('--------')
-                FmpCapsuleHeader.DumpInfo ()
-            if UseSignTool or UseOpenSsl:
-                Result = FmpAuthHeader.Decode (Result)
-                if args.Verbose:
-                    print ('--------')
-                    FmpAuthHeader.DumpInfo ()
+    EmbeddedDriverDescriptorList = []
+    PayloadDescriptorList = []
+    PayloadJsonDescriptorList = []
 
-                #
-                # Verify Image with 64-bit MonotonicCount appended to end of image
-                #
-                try:
-                  if UseSignTool:
-                      CertData = VerifyPayloadSignTool (
-                                   FmpAuthHeader.Payload + struct.pack ('<Q', FmpAuthHeader.MonotonicCount),
-                                   FmpAuthHeader.CertData,
-                                   args.SigningToolPath,
-                                   args.SignToolPfxFile
-                                   )
-                  else:
-                      CertData = VerifyPayloadOpenSsl (
-                                   FmpAuthHeader.Payload + struct.pack ('<Q', FmpAuthHeader.MonotonicCount),
-                                   FmpAuthHeader.CertData,
-                                   args.SigningToolPath,
-                                   args.OpenSslSignerPrivateCertFile,
-                                   args.OpenSslOtherPublicCertFile,
-                                   args.OpenSslTrustedPublicCertFile
-                                   )
-                except ValueError:
-                    print ('GenerateCapsule: warning: can not verify payload.')
-
-                try:
-                    Result = FmpPayloadHeader.Decode (Result)
-                    if args.Verbose:
-                        print ('--------')
-                        FmpPayloadHeader.DumpInfo ()
-                        print ('========')
-                except:
-                    if args.Verbose:
-                        print ('--------')
-                        print ('No FMP_PAYLOAD_HEADER')
-                        print ('========')
-                    raise
-            else:
-                if args.Verbose:
-                    print ('--------')
-                    print ('No EFI_FIRMWARE_IMAGE_AUTHENTICATION')
-                    print ('--------')
-                    print ('No FMP_PAYLOAD_HEADER')
-                    print ('========')
-        except:
-            print ('GenerateCapsule: error: can not decode capsule')
-            sys.exit (1)
+    #
+    #Encode Operation
+    #
+    if args.Encode:
+        Encode (PayloadDescriptorList, EmbeddedDriverDescriptorList, Buffer)
 
-    elif args.DumpInfo:
-        try:
-            Result = UefiCapsuleHeader.Decode (Buffer)
-            FmpCapsuleHeader.Decode (Result)
-            Result = FmpCapsuleHeader.GetFmpCapsuleImageHeader (0).Payload
-            print ('========')
-            UefiCapsuleHeader.DumpInfo ()
-            print ('--------')
-            FmpCapsuleHeader.DumpInfo ()
-            try:
-                Result = FmpAuthHeader.Decode (Result)
-                print ('--------')
-                FmpAuthHeader.DumpInfo ()
-                try:
-                    Result = FmpPayloadHeader.Decode (Result)
-                    print ('--------')
-                    FmpPayloadHeader.DumpInfo ()
-                except:
-                    print ('--------')
-                    print ('No FMP_PAYLOAD_HEADER')
-            except:
-                print ('--------')
-                print ('No EFI_FIRMWARE_IMAGE_AUTHENTICATION')
-                print ('--------')
-                print ('No FMP_PAYLOAD_HEADER')
-            print ('========')
-        except:
-            print ('GenerateCapsule: error: can not decode capsule')
-            sys.exit (1)
-    else:
-        print('GenerateCapsule: error: invalid options')
-        sys.exit (1)
+    #
+    #Decode Operation
+    #
+    if args.Decode:
+        Decode (PayloadDescriptorList, PayloadJsonDescriptorList, Buffer)
 
     #
-    # Write binary output file
+    #Dump Info Operation
     #
-    if args.OutputFile is not None:
-        try:
-            if args.Verbose:
-                print ('Write binary output file {File}'.format (File = args.OutputFile.name))
-            args.OutputFile.write (Result)
-            args.OutputFile.close ()
-        except:
-            print ('GenerateCapsule: error: can not write binary output file {File}'.format (File = args.OutputFile.name))
-            sys.exit (1)
+    if args.DumpInfo:
+        DumpInfo (Buffer, args)
 
     if args.Verbose:
         print('Success')
diff --git a/BaseTools/Source/Python/Common/Uefi/Capsule/FmpAuthHeader.py b/BaseTools/Source/Python/Common/Uefi/Capsule/FmpAuthHeader.py
index 4b8c6da26a..48c605faa8 100644
--- a/BaseTools/Source/Python/Common/Uefi/Capsule/FmpAuthHeader.py
+++ b/BaseTools/Source/Python/Common/Uefi/Capsule/FmpAuthHeader.py
@@ -2,7 +2,7 @@
 # Module that encodes and decodes a EFI_FIRMWARE_IMAGE_AUTHENTICATION with
 # certificate data and payload data.
 #
-# Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<BR>
 # SPDX-License-Identifier: BSD-2-Clause-Patent
 #
 
@@ -166,6 +166,18 @@ class FmpAuthHeaderClass (object):
         self._Valid           = True
         return self.Payload
 
+    def IsSigned (self, Buffer):
+        if len (Buffer) < self._StructSize:
+            return False
+        (MonotonicCount, dwLength, wRevision, wCertificateType, CertType) = \
+            struct.unpack (
+                     self._StructFormat,
+                     Buffer[0:self._StructSize]
+                     )
+        if CertType != self._EFI_CERT_TYPE_PKCS7_GUID.bytes_le:
+            return False
+        return True
+
     def DumpInfo (self):
         if not self._Valid:
             raise ValueError
diff --git a/BaseTools/Source/Python/Common/Uefi/Capsule/FmpCapsuleHeader.py b/BaseTools/Source/Python/Common/Uefi/Capsule/FmpCapsuleHeader.py
index c24258d047..91d24919c4 100644
--- a/BaseTools/Source/Python/Common/Uefi/Capsule/FmpCapsuleHeader.py
+++ b/BaseTools/Source/Python/Common/Uefi/Capsule/FmpCapsuleHeader.py
@@ -2,7 +2,7 @@
 # Module that encodes and decodes a EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER with
 # a payload.
 #
-# Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<BR>
 # SPDX-License-Identifier: BSD-2-Clause-Patent
 #
 
@@ -172,8 +172,8 @@ class FmpCapsuleHeaderClass (object):
             raise ValueError
         return self._EmbeddedDriverList[Index]
 
-    def AddPayload (self, UpdateImageTypeId, Payload = b'', VendorCodeBytes = b'', HardwareInstance = 0):
-        self._PayloadList.append ((UpdateImageTypeId, Payload, VendorCodeBytes, HardwareInstance))
+    def AddPayload (self, UpdateImageTypeId, Payload = b'', VendorCodeBytes = b'', HardwareInstance = 0, UpdateImageIndex = 1):
+        self._PayloadList.append ((UpdateImageTypeId, Payload, VendorCodeBytes, HardwareInstance, UpdateImageIndex))
 
     def GetFmpCapsuleImageHeader (self, Index):
         if Index >= len (self._FmpCapsuleImageHeaderList):
@@ -198,10 +198,10 @@ class FmpCapsuleHeaderClass (object):
             self._ItemOffsetList.append (Offset)
             Offset = Offset + len (EmbeddedDriver)
         Index = 1
-        for (UpdateImageTypeId, Payload, VendorCodeBytes, HardwareInstance) in self._PayloadList:
+        for (UpdateImageTypeId, Payload, VendorCodeBytes, HardwareInstance, UpdateImageIndex) in self._PayloadList:
             FmpCapsuleImageHeader = FmpCapsuleImageHeaderClass ()
             FmpCapsuleImageHeader.UpdateImageTypeId      = UpdateImageTypeId
-            FmpCapsuleImageHeader.UpdateImageIndex       = Index
+            FmpCapsuleImageHeader.UpdateImageIndex       = UpdateImageIndex
             FmpCapsuleImageHeader.Payload                = Payload
             FmpCapsuleImageHeader.VendorCodeBytes        = VendorCodeBytes
             FmpCapsuleImageHeader.UpdateHardwareInstance = HardwareInstance
@@ -288,6 +288,8 @@ class FmpCapsuleHeaderClass (object):
             raise ValueError
         print ('EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER.Version             = {Version:08X}'.format (Version = self.Version))
         print ('EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER.EmbeddedDriverCount = {EmbeddedDriverCount:08X}'.format (EmbeddedDriverCount = self.EmbeddedDriverCount))
+        for EmbeddedDriver in self._EmbeddedDriverList:
+            print ('  sizeof (EmbeddedDriver)                                  = {Size:08X}'.format (Size = len (EmbeddedDriver)))
         print ('EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER.PayloadItemCount    = {PayloadItemCount:08X}'.format (PayloadItemCount = self.PayloadItemCount))
         print ('EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER.ItemOffsetList      = ')
         for Offset in self._ItemOffsetList:
-- 
2.20.0.windows.1


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [edk2-devel] [Patch] BaseTools/Capsule: Supports UEFI Capsule with multiple payloads and embedded drivers
  2019-05-27  7:28 [Patch] BaseTools/Capsule: Supports UEFI Capsule with multiple payloads and embedded drivers Eric Jin
@ 2019-05-27 13:58 ` Liming Gao
  2019-05-28  2:10   ` Eric Jin
  2019-06-11  3:06 ` Bob Feng
  1 sibling, 1 reply; 4+ messages in thread
From: Liming Gao @ 2019-05-27 13:58 UTC (permalink / raw)
  To: devel@edk2.groups.io, Jin, Eric
  Cc: Feng, Bob C, Kinney, Michael D, Kinney, Michael D

Seemly, this is new feature implementation. It will not be for Q2 stable tag. Right?

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


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [edk2-devel] [Patch] BaseTools/Capsule: Supports UEFI Capsule with multiple payloads and embedded drivers
  2019-05-27 13:58 ` [edk2-devel] " Liming Gao
@ 2019-05-28  2:10   ` Eric Jin
  0 siblings, 0 replies; 4+ messages in thread
From: Eric Jin @ 2019-05-28  2:10 UTC (permalink / raw)
  To: Gao, Liming, devel@edk2.groups.io
  Cc: Feng, Bob C, Kinney, Michael D, Kinney, Michael D

Liming,

Yes. It is not for Q2 stable tag.

Best Regards
Eric

-----Original Message-----
From: Gao, Liming 
Sent: Monday, May 27, 2019 9:58 PM
To: devel@edk2.groups.io; Jin, Eric <eric.jin@intel.com>
Cc: Feng, Bob C <bob.c.feng@intel.com>; Kinney, Michael D <michael.d.kinney@intel.com>; Kinney, Michael D <michael.d.kinney@intel.com>
Subject: RE: [edk2-devel] [Patch] BaseTools/Capsule: Supports UEFI Capsule with multiple payloads and embedded drivers

Seemly, this is new feature implementation. It will not be for Q2 stable tag. Right?

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


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [Patch] BaseTools/Capsule: Supports UEFI Capsule with multiple payloads and embedded drivers
  2019-05-27  7:28 [Patch] BaseTools/Capsule: Supports UEFI Capsule with multiple payloads and embedded drivers Eric Jin
  2019-05-27 13:58 ` [edk2-devel] " Liming Gao
@ 2019-06-11  3:06 ` Bob Feng
  1 sibling, 0 replies; 4+ messages in thread
From: Bob Feng @ 2019-06-11  3:06 UTC (permalink / raw)
  To: Jin, Eric, devel@edk2.groups.io; +Cc: Gao, Liming, Kinney, Michael D

Hi Eric,

Here are some comments on this patch.

+            try: 
+                Value = open (Value, "rb") 
+            except: 
+                print ('GenerateCapsule: error: can not open file {File}'.format (File = FieldName)) 
+                sys.exit (1) 
+        return Value

There is no close() for the opened file. Suggest to use with statement.

+        Result = json.dumps (PayloadJson, indent=4, sort_keys=True, separators=(',', ': '))
+        OutputFile = open (OutputJsonFile, 'w')
+        OutputFile.write (Result)
+        OutputFile.close ()

Here, please use try and with statement for open() function.

+        for SinglePayloadDescriptor in PayloadDescriptorList:
+            Result = SinglePayloadDescriptor.Payload
+            try:
+                FmpPayloadHeader.FwVersion              = SinglePayloadDescriptor.FwVersion
+                FmpPayloadHeader.LowestSupportedVersion = SinglePayloadDescriptor.LowestSupportedVersion
+                FmpPayloadHeader.Payload                = SinglePayloadDescriptor.Payload
+                Result = FmpPayloadHeader.Encode ()
+                if args.Verbose:
+                    FmpPayloadHeader.DumpInfo ()
+            except:
+                raise
+                print ('GenerateCapsule: error: can not encode FMP Payload Header')
+                sys.exit (1)

The raise statement in except block looks wrong.

+                    try:
+                        SinglePayloadDescriptor.Payload = FmpPayloadHeader.Decode (SinglePayloadDescriptor.Payload)
+                        PayloadJsonDescriptorList[JsonIndex].FwVersion = FmpPayloadHeader.FwVersion
+                        PayloadJsonDescriptorList[JsonIndex].LowestSupportedVersion = FmpPayloadHeader.LowestSupportedVersion
+                        JsonIndex = JsonIndex + 1
+                        if args.Verbose:
+                            print ('--------')
+                            FmpPayloadHeader.DumpInfo ()
+                            print ('========')
+                    except:
+                        if args.Verbose:
+                            print ('--------')
+                            print ('No FMP_PAYLOAD_HEADER')
+                            print ('========')
+                        raise

It looks that the raise statement here should be replaced with print(...) and exit(1) according to your code style in this patch.


Thanks,
Bob


-----Original Message-----
From: Jin, Eric 
Sent: Monday, May 27, 2019 3:28 PM
To: devel@edk2.groups.io
Cc: Feng, Bob C <bob.c.feng@intel.com>; Gao, Liming <liming.gao@intel.com>; Kinney; Kinney, Michael D <michael.d.kinney@intel.com>
Subject: [Patch] BaseTools/Capsule: Supports UEFI Capsule with multiple payloads and embedded drivers

https://bugzilla.tianocore.org/show_bug.cgi?id=1834

* Add arguments "--embedded-driver" to support embedded driver in command line.
* Add arguments "--update-image-index" to identify ImageIndex within the device
  in command line.
* Add arguments "-j JSONFILE" to support multiple payloads and embedded drivers
  with JSON file.

The update is in a backwards compatible manner, so all command line options to
support single payload are still supported. But all the options associated with
multiple payloads should be provided in a JSON file.

Cc: Bob Feng <bob.c.feng@intel.com>
Cc: Liming Gao <liming.gao@intel.com>
Cc: Kinney, Michael D <michael.d.kinney@intel.com>
Signed-off-by: Eric Jin <eric.jin@intel.com>
---
 BaseTools/Source/Python/Capsule/GenerateCapsule.py              | 961 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 BaseTools/Source/Python/Common/Uefi/Capsule/FmpAuthHeader.py    |  14 +++++++++++++-
 BaseTools/Source/Python/Common/Uefi/Capsule/FmpCapsuleHeader.py |  12 +++++++-----
 3 files changed, 730 insertions(+), 257 deletions(-)

diff --git a/BaseTools/Source/Python/Capsule/GenerateCapsule.py b/BaseTools/Source/Python/Capsule/GenerateCapsule.py
index 4de3635298..ee95c4cc2e 100644
--- a/BaseTools/Source/Python/Capsule/GenerateCapsule.py
+++ b/BaseTools/Source/Python/Capsule/GenerateCapsule.py
@@ -1,18 +1,16 @@
 ## @file

 # Generate a capsule.

 #

-# This tool generates a UEFI Capsule around an FMP Capsule.  The capsule payload

+# This tool generates a UEFI Capsule around an FMP Capsule. The capsule payload

 # be signed using signtool or OpenSSL and if it is signed the signed content

 # includes an FMP Payload Header.

 #

 # This tool is intended to be used to generate UEFI Capsules to update the

-# system firmware or device firmware for integrated devices.  In order to

+# system firmware or device firmware for integrated devices. In order to

 # keep the tool as simple as possible, it has the following limitations:

-#   * Do not support multiple payloads in a capsule.

-#   * Do not support optional drivers in a capsule.

 #   * Do not support vendor code bytes in a capsule.

 #

-# Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>

+# Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<BR>

 # SPDX-License-Identifier: BSD-2-Clause-Patent

 #

 

@@ -29,6 +27,7 @@ import os
 import tempfile

 import shutil

 import platform

+import json

 from Common.Uefi.Capsule.UefiCapsuleHeader import UefiCapsuleHeaderClass

 from Common.Uefi.Capsule.FmpCapsuleHeader  import FmpCapsuleHeaderClass

 from Common.Uefi.Capsule.FmpAuthHeader     import FmpAuthHeaderClass

@@ -42,7 +41,7 @@ __version__     = '0.9'
 __copyright__   = 'Copyright (c) 2018, Intel Corporation. All rights reserved.'

 __description__ = 'Generate a capsule.\n'

 

-def SignPayloadSignTool (Payload, ToolPath, PfxFile):

+def SignPayloadSignTool (Payload, ToolPath, PfxFile, Verbose = False):

     #

     # Create a temporary directory

     #

@@ -75,6 +74,8 @@ def SignPayloadSignTool (Payload, ToolPath, PfxFile):
     Command = Command + '/p7 {TempDir} '.format (TempDir = TempDirectoryName)

     Command = Command + '/f {PfxFile} '.format (PfxFile = PfxFile)

     Command = Command + TempFileName

+    if Verbose:

+        print (Command)

 

     #

     # Sign the input file using the specified private key

@@ -88,7 +89,7 @@ def SignPayloadSignTool (Payload, ToolPath, PfxFile):
 

     if Process.returncode != 0:

         shutil.rmtree (TempDirectoryName)

-        print (Result[1].decode(encoding='utf-8', errors='ignore'))

+        print (Result[1].decode())

         raise ValueError ('GenerateCapsule: error: signtool failed.')

 

     #

@@ -105,11 +106,11 @@ def SignPayloadSignTool (Payload, ToolPath, PfxFile):
     shutil.rmtree (TempDirectoryName)

     return Signature

 

-def VerifyPayloadSignTool (Payload, CertData, ToolPath, PfxFile):

+def VerifyPayloadSignTool (Payload, CertData, ToolPath, PfxFile, Verbose = False):

     print ('signtool verify is not supported.')

     raise ValueError ('GenerateCapsule: error: signtool verify is not supported.')

 

-def SignPayloadOpenSsl (Payload, ToolPath, SignerPrivateCertFile, OtherPublicCertFile, TrustedPublicCertFile):

+def SignPayloadOpenSsl (Payload, ToolPath, SignerPrivateCertFile, OtherPublicCertFile, TrustedPublicCertFile, Verbose = False):

     #

     # Build openssl command

     #

@@ -119,6 +120,8 @@ def SignPayloadOpenSsl (Payload, ToolPath, SignerPrivateCertFile, OtherPublicCer
     Command = Command + '"{Path}" '.format (Path = os.path.join (ToolPath, 'openssl'))

     Command = Command + 'smime -sign -binary -outform DER -md sha256 '

     Command = Command + '-signer "{Private}" -certfile "{Public}"'.format (Private = SignerPrivateCertFile, Public = OtherPublicCertFile)

+    if Verbose:

+        print (Command)

 

     #

     # Sign the input file using the specified private key and capture signature from STDOUT

@@ -131,12 +134,12 @@ def SignPayloadOpenSsl (Payload, ToolPath, SignerPrivateCertFile, OtherPublicCer
         raise ValueError ('GenerateCapsule: error: can not run openssl.')

 

     if Process.returncode != 0:

-        print (Result[1].decode(encoding='utf-8', errors='ignore'))

+        print (Result[1].decode())

         raise ValueError ('GenerateCapsule: error: openssl failed.')

 

     return Signature

 

-def VerifyPayloadOpenSsl (Payload, CertData, ToolPath, SignerPrivateCertFile, OtherPublicCertFile, TrustedPublicCertFile):

+def VerifyPayloadOpenSsl (Payload, CertData, ToolPath, SignerPrivateCertFile, OtherPublicCertFile, TrustedPublicCertFile, Verbose = False):

     #

     # Create a temporary directory

     #

@@ -167,6 +170,8 @@ def VerifyPayloadOpenSsl (Payload, CertData, ToolPath, SignerPrivateCertFile, Ot
     Command = Command + '"{Path}" '.format (Path = os.path.join (ToolPath, 'openssl'))

     Command = Command + 'smime -verify -inform DER '

     Command = Command + '-content {Content} -CAfile "{Public}"'.format (Content = TempFileName, Public = TrustedPublicCertFile)

+    if Verbose:

+        print (Command)

 

     #

     # Verify signature

@@ -180,7 +185,7 @@ def VerifyPayloadOpenSsl (Payload, CertData, ToolPath, SignerPrivateCertFile, Ot
 

     if Process.returncode != 0:

         shutil.rmtree (TempDirectoryName)

-        print (Result[1].decode(encoding='utf-8', errors='ignore'))

+        print (Result[1].decode())

         raise ValueError ('GenerateCapsule: error: openssl failed.')

 

     shutil.rmtree (TempDirectoryName)

@@ -212,6 +217,660 @@ if __name__ == '__main__':
             raise argparse.ArgumentTypeError (Message)

         return Value

 

+    def ConvertJsonValue (Config, FieldName, Convert, Required = True, Default = None, Open = False):

+        if FieldName not in Config:

+            if Required:

+                print ('GenerateCapsule: error: Payload descriptor invalid syntax. Could not find {Key} in payload descriptor.'.format(Key = FieldName))

+                sys.exit (1)

+            return Default

+        try:

+            Value = Convert (Config[FieldName])

+        except Exception as Message:

+            print ('GenerateCapsule: error: {Key} in payload descriptor has invalid syntax.  '.format (Key = FieldName) + str(Message))

+            sys.exit (1)

+        if Open:

+            try:

+                Value = open (Value, "rb")

+            except:

+                print ('GenerateCapsule: error: can not open file {File}'.format (File = FieldName))

+                sys.exit (1)

+        return Value

+

+    def DecodeJsonFileParse (Json):

+        if 'Payloads' not in Json:

+            print ('GenerateCapsule: error "Payloads" section not found in JSON file {File}'.format (File = args.JsonFile.name))

+            sys.exit (1)

+        for Config in Json['Payloads']:

+            #

+            # Parse fields from JSON

+            #

+            PayloadFile                  = ConvertJsonValue (Config, 'Payload', os.path.expandvars, Required = False)

+            Guid                         = ConvertJsonValue (Config, 'Guid', ValidateRegistryFormatGuid, Required = False)

+            FwVersion                    = ConvertJsonValue (Config, 'FwVersion', ValidateUnsignedInteger, Required = False)

+            LowestSupportedVersion       = ConvertJsonValue (Config, 'LowestSupportedVersion', ValidateUnsignedInteger, Required = False)

+            HardwareInstance             = ConvertJsonValue (Config, 'HardwareInstance', ValidateUnsignedInteger, Required = False, Default = 0)

+            MonotonicCount               = ConvertJsonValue (Config, 'MonotonicCount', ValidateUnsignedInteger, Required = False, Default = 0)

+            SignToolPfxFile              = ConvertJsonValue (Config, 'SignToolPfxFile', os.path.expandvars, Required = False, Default = None, Open = True)

+            OpenSslSignerPrivateCertFile = ConvertJsonValue (Config, 'OpenSslSignerPrivateCertFile', os.path.expandvars, Required = False, Default = None, Open = True)

+            OpenSslOtherPublicCertFile   = ConvertJsonValue (Config, 'OpenSslOtherPublicCertFile', os.path.expandvars, Required = False, Default = None, Open = True)

+            OpenSslTrustedPublicCertFile = ConvertJsonValue (Config, 'OpenSslTrustedPublicCertFile', os.path.expandvars, Required = False, Default = None, Open = True)

+            SigningToolPath              = ConvertJsonValue (Config, 'SigningToolPath', os.path.expandvars, Required = False, Default = None)

+            UpdateImageIndex             = ConvertJsonValue (Config, 'UpdateImageIndex', ValidateUnsignedInteger, Required = False, Default = 1)

+

+            PayloadDescriptorList.append (PayloadDescriptor (

+                                            PayloadFile,

+                                            Guid,

+                                            FwVersion,

+                                            LowestSupportedVersion,

+                                            MonotonicCount,

+                                            HardwareInstance,

+                                            UpdateImageIndex,

+                                            SignToolPfxFile,

+                                            OpenSslSignerPrivateCertFile,

+                                            OpenSslOtherPublicCertFile,

+                                            OpenSslTrustedPublicCertFile,

+                                            SigningToolPath

+                                            ))

+

+    def EncodeJsonFileParse (Json):

+        if 'EmbeddedDrivers' not in Json:

+            print ('GenerateCapsule: warning "EmbeddedDrivers" section not found in JSON file {File}'.format (File = args.JsonFile.name))

+        else:

+            for Config in Json['EmbeddedDrivers']:

+                EmbeddedDriverFile      = ConvertJsonValue(Config, 'Driver', os.path.expandvars, Open = True)

+                #

+                #Read EmbeddedDriver file

+                #

+                try:

+                    if args.Verbose:

+                        print ('Read EmbeddedDriver file {File}'.format (File = EmbeddedDriverFile.name))

+                    Driver = EmbeddedDriverFile.read()

+                except:

+                    print ('GenerateCapsule: error: can not read EmbeddedDriver file {File}'.format (File = EmbeddedDriverFile.name))

+                    sys.exit(1)

+                EmbeddedDriverDescriptorList.append (Driver)

+

+        if 'Payloads' not in Json:

+            print ('GenerateCapsule: error: "Payloads" section not found in JSON file {File}'.format (File = args.JsonFile.name))

+            sys.exit (1)

+        for Config in Json['Payloads']:

+            #

+            # Parse fields from JSON

+            #

+            PayloadFile                  = ConvertJsonValue (Config, 'Payload', os.path.expandvars, Open = True)

+            Guid                         = ConvertJsonValue (Config, 'Guid', ValidateRegistryFormatGuid)

+            FwVersion                    = ConvertJsonValue (Config, 'FwVersion', ValidateUnsignedInteger)

+            LowestSupportedVersion       = ConvertJsonValue (Config, 'LowestSupportedVersion', ValidateUnsignedInteger)

+            HardwareInstance             = ConvertJsonValue (Config, 'HardwareInstance', ValidateUnsignedInteger, Required = False, Default = 0)

+            UpdateImageIndex             = ConvertJsonValue (Config, 'UpdateImageIndex', ValidateUnsignedInteger, Required = False, Default = 1)

+            MonotonicCount               = ConvertJsonValue (Config, 'MonotonicCount', ValidateUnsignedInteger, Required = False, Default = 0)

+            SignToolPfxFile              = ConvertJsonValue (Config, 'SignToolPfxFile', os.path.expandvars, Required = False, Default = None, Open = True)

+            OpenSslSignerPrivateCertFile = ConvertJsonValue (Config, 'OpenSslSignerPrivateCertFile', os.path.expandvars, Required = False, Default = None, Open = True)

+            OpenSslOtherPublicCertFile   = ConvertJsonValue (Config, 'OpenSslOtherPublicCertFile', os.path.expandvars, Required = False, Default = None, Open = True)

+            OpenSslTrustedPublicCertFile = ConvertJsonValue (Config, 'OpenSslTrustedPublicCertFile', os.path.expandvars, Required = False, Default = None, Open = True)

+            SigningToolPath              = ConvertJsonValue (Config, 'SigningToolPath', os.path.expandvars, Required = False, Default = None)

+

+            #

+            # Read binary input file

+            #

+            try:

+                if args.Verbose:

+                    print ('Read binary input file {File}'.format (File = PayloadFile.name))

+                Payload = PayloadFile.read()

+            except:

+                print ('GenerateCapsule: error: can not read binary input file {File}'.format (File = PayloadFile.name))

+                sys.exit (1)

+            PayloadDescriptorList.append (PayloadDescriptor (

+                                            Payload,

+                                            Guid,

+                                            FwVersion,

+                                            LowestSupportedVersion,

+                                            MonotonicCount,

+                                            HardwareInstance,

+                                            UpdateImageIndex,

+                                            SignToolPfxFile,

+                                            OpenSslSignerPrivateCertFile,

+                                            OpenSslOtherPublicCertFile,

+                                            OpenSslTrustedPublicCertFile,

+                                            SigningToolPath

+                                            ))

+

+    def GenerateOutputJson (PayloadJsonDescriptorList):

+        PayloadJson = {

+                          "Payloads" : [

+                              {

+                                  "Guid": str(PayloadDescriptor.Guid).upper(),

+                                  "FwVersion": str(PayloadDescriptor.FwVersion),

+                                  "LowestSupportedVersion": str(PayloadDescriptor.LowestSupportedVersion),

+                                  "MonotonicCount": str(PayloadDescriptor.MonotonicCount),

+                                  "Payload": PayloadDescriptor.Payload,

+                                  "HardwareInstance": str(PayloadDescriptor.HardwareInstance),

+                                  "UpdateImageIndex": str(PayloadDescriptor.UpdateImageIndex),

+                                  "SignToolPfxFile": str(PayloadDescriptor.SignToolPfxFile),

+                                  "OpenSslSignerPrivateCertFile": str(PayloadDescriptor.OpenSslSignerPrivateCertFile),

+                                  "OpenSslOtherPublicCertFile": str(PayloadDescriptor.OpenSslOtherPublicCertFile),

+                                  "OpenSslTrustedPublicCertFile": str(PayloadDescriptor.OpenSslTrustedPublicCertFile),

+                                  "SigningToolPath": str(PayloadDescriptor.SigningToolPath)

+                              }for PayloadDescriptor in PayloadJsonDescriptorList

+                          ]

+                      }

+        OutputJsonFile = args.OutputFile.name + '.json'

+        if 'Payloads' in PayloadJson:

+            PayloadSection = PayloadJson ['Payloads']

+        Index = 0

+        for PayloadField in PayloadSection:

+            if PayloadJsonDescriptorList[Index].SignToolPfxFile is None:

+                del PayloadField ['SignToolPfxFile']

+            if PayloadJsonDescriptorList[Index].OpenSslSignerPrivateCertFile is None:

+                del PayloadField ['OpenSslSignerPrivateCertFile']

+            if PayloadJsonDescriptorList[Index].OpenSslOtherPublicCertFile is None:

+                del PayloadField ['OpenSslOtherPublicCertFile']

+            if PayloadJsonDescriptorList[Index].OpenSslTrustedPublicCertFile is None:

+                del PayloadField ['OpenSslTrustedPublicCertFile']

+            if PayloadJsonDescriptorList[Index].SigningToolPath is None:

+                del PayloadField ['SigningToolPath']

+            Index = Index + 1

+        Result = json.dumps (PayloadJson, indent=4, sort_keys=True, separators=(',', ': '))

+        OutputFile = open (OutputJsonFile, 'w')

+        OutputFile.write (Result)

+        OutputFile.close ()

+

+    def CheckArgumentConflict (args):

+        if args.Encode:

+            if args.InputFile:

+                print ('GenerateCapsule: error: Argument InputFile conflicts with Argument -j')

+                sys.exit (1)

+            if args.EmbeddedDriver:

+                print ('GenerateCapsule: error: Argument --embedded-driver conflicts with Argument -j')

+                sys.exit (1)

+        if args.Guid:

+            print ('GenerateCapsule: error: Argument --guid conflicts with Argument -j')

+            sys.exit (1)

+        if args.FwVersion:

+            print ('GenerateCapsule: error: Argument --fw-version conflicts with Argument -j')

+            sys.exit (1)

+        if args.LowestSupportedVersion:

+            print ('GenerateCapsule: error: Argument --lsv conflicts with Argument -j')

+            sys.exit (1)

+        if args.MonotonicCount:

+            print ('GenerateCapsule: error: Argument --monotonic-count conflicts with Argument -j')

+            sys.exit (1)

+        if args.HardwareInstance:

+            print ('GenerateCapsule: error: Argument --hardware-instance conflicts with Argument -j')

+            sys.exit (1)

+        if args.SignToolPfxFile:

+            print ('GenerateCapsule: error: Argument --pfx-file conflicts with Argument -j')

+            sys.exit (1)

+        if args.OpenSslSignerPrivateCertFile:

+            print ('GenerateCapsule: error: Argument --signer-private-cert conflicts with Argument -j')

+            sys.exit (1)

+        if args.OpenSslOtherPublicCertFile:

+            print ('GenerateCapsule: error: Argument --other-public-cert conflicts with Argument -j')

+            sys.exit (1)   

+        if args.OpenSslTrustedPublicCertFile:

+            print ('GenerateCapsule: error: Argument --trusted-public-cert conflicts with Argument -j')

+            sys.exit (1)   

+        if args.SigningToolPath:

+            print ('GenerateCapsule: error: Argument --signing-tool-path conflicts with Argument -j')

+            sys.exit (1)

+

+    class PayloadDescriptor (object):

+        def __init__(self,

+                     Payload,

+                     Guid,

+                     FwVersion,

+                     LowestSupportedVersion,

+                     MonotonicCount               = 0,

+                     HardwareInstance             = 0,

+                     UpdateImageIndex             = 1,

+                     SignToolPfxFile              = None,

+                     OpenSslSignerPrivateCertFile = None,

+                     OpenSslOtherPublicCertFile   = None,

+                     OpenSslTrustedPublicCertFile = None,

+                     SigningToolPath              = None

+                     ):

+            self.Payload                      = Payload

+            self.Guid                         = Guid

+            self.FwVersion                    = FwVersion

+            self.LowestSupportedVersion       = LowestSupportedVersion

+            self.MonotonicCount               = MonotonicCount

+            self.HardwareInstance             = HardwareInstance

+            self.UpdateImageIndex             = UpdateImageIndex

+            self.SignToolPfxFile              = SignToolPfxFile

+            self.OpenSslSignerPrivateCertFile = OpenSslSignerPrivateCertFile

+            self.OpenSslOtherPublicCertFile   = OpenSslOtherPublicCertFile

+            self.OpenSslTrustedPublicCertFile = OpenSslTrustedPublicCertFile

+            self.SigningToolPath              = SigningToolPath

+

+            self.UseSignTool = self.SignToolPfxFile is not None

+            self.UseOpenSsl  = (self.OpenSslSignerPrivateCertFile is not None and

+                                self.OpenSslOtherPublicCertFile is not None and

+                                self.OpenSslTrustedPublicCertFile is not None)

+            self.AnyOpenSsl  = (self.OpenSslSignerPrivateCertFile is not None or

+                                self.OpenSslOtherPublicCertFile is not None or

+                                self.OpenSslTrustedPublicCertFile is not None)

+

+        def Validate(self, args):

+            if self.UseSignTool and self.AnyOpenSsl:

+                raise argparse.ArgumentTypeError ('Providing both signtool and OpenSSL options is not supported')

+            if not self.UseSignTool and not self.UseOpenSsl and self.AnyOpenSsl:

+                if args.JsonFile:

+                    raise argparse.ArgumentTypeError ('the following JSON fields are required for OpenSSL: OpenSslSignerPrivateCertFile, OpenSslOtherPublicCertFile, OpenSslTrustedPublicCertFile')

+                else:

+                    raise argparse.ArgumentTypeError ('the following options are required for OpenSSL: --signer-private-cert, --other-public-cert, --trusted-public-cert')

+            if self.UseSignTool and platform.system() != 'Windows':

+                raise argparse.ArgumentTypeError ('Use of signtool is not supported on this operating system.')

+            if args.Encode:

+                if self.FwVersion is None or self.LowestSupportedVersion is None:

+                    if args.JsonFile:

+                        raise argparse.ArgumentTypeError ('the following JSON fields are required: FwVersion, LowestSupportedVersion')

+                    else:

+                        raise argparse.ArgumentTypeError ('the following options are required: --fw-version, --lsv')

+                if self.FwVersion > 0xFFFFFFFF:

+                    if args.JsonFile:

+                        raise argparse.ArgumentTypeError ('JSON field FwVersion must be an integer in range 0x0..0xffffffff')

+                    else:

+                        raise argparse.ArgumentTypeError ('--fw-version must be an integer in range 0x0..0xffffffff')

+                if self.LowestSupportedVersion > 0xFFFFFFFF:

+                    if args.JsonFile:

+                        raise argparse.ArgumentTypeError ('JSON field LowestSupportedVersion must be an integer in range 0x0..0xffffffff')

+                    else:

+                        raise argparse.ArgumentTypeError ('--lsv must be an integer in range 0x0..0xffffffff')

+

+            if args.Encode:

+                if self.Guid is None:

+                    if args.JsonFile:

+                        raise argparse.ArgumentTypeError ('the following JSON field is required: Guid')

+                    else:

+                        raise argparse.ArgumentTypeError ('the following option is required: --guid')

+                if self.HardwareInstance > 0xFFFFFFFFFFFFFFFF:

+                    if args.JsonFile:

+                        raise argparse.ArgumentTypeError ('JSON field HardwareInstance must be an integer in range 0x0..0xffffffffffffffff')

+                    else:

+                        raise argparse.ArgumentTypeError ('--hardware-instance must be an integer in range 0x0..0xffffffffffffffff')

+                if self.MonotonicCount > 0xFFFFFFFFFFFFFFFF:

+                    if args.JsonFile:

+                        raise argparse.ArgumentTypeError ('JSON field MonotonicCount must be an integer in range 0x0..0xffffffffffffffff')

+                    else:

+                        raise argparse.ArgumentTypeError ('--monotonic-count must be an integer in range 0x0..0xffffffffffffffff')

+                if self.UpdateImageIndex >0xFF:

+                    if args.JsonFile:

+                        raise argparse.ArgumentTypeError ('JSON field UpdateImageIndex must be an integer in range 0x0..0xff')

+                    else:

+                        raise argparse.ArgumentTypeError ('--update-image-index must be an integer in range 0x0..0xff')

+

+            if self.UseSignTool:

+                self.SignToolPfxFile.close()

+                self.SignToolPfxFile = self.SignToolPfxFile.name

+            if self.UseOpenSsl:

+                self.OpenSslSignerPrivateCertFile.close()

+                self.OpenSslOtherPublicCertFile.close()

+                self.OpenSslTrustedPublicCertFile.close()

+                self.OpenSslSignerPrivateCertFile = self.OpenSslSignerPrivateCertFile.name

+                self.OpenSslOtherPublicCertFile   = self.OpenSslOtherPublicCertFile.name

+                self.OpenSslTrustedPublicCertFile = self.OpenSslTrustedPublicCertFile.name

+

+            #

+            # Perform additional argument verification

+            #

+            if args.Encode:

+                if 'PersistAcrossReset' not in args.CapsuleFlag:

+                    if 'InitiateReset' in args.CapsuleFlag:

+                        raise argparse.ArgumentTypeError ('--capflag InitiateReset also requires --capflag PersistAcrossReset')

+                if args.CapsuleOemFlag > 0xFFFF:

+                    raise argparse.ArgumentTypeError ('--capoemflag must be an integer between 0x0000 and 0xffff')

+

+            return True

+

+

+    def Encode (PayloadDescriptorList, EmbeddedDriverDescriptorList, Buffer):

+        if args.JsonFile:

+            CheckArgumentConflict(args)

+            try:

+                Json = json.loads (args.JsonFile.read ())

+            except Exception as Message:

+                print ('GenerateCapsule: error: ' + str(Message))

+                sys.exit (1)

+            EncodeJsonFileParse(Json)

+        else:

+            for Driver in args.EmbeddedDriver:

+                EmbeddedDriverDescriptorList.append (Driver.read())

+            PayloadDescriptorList.append (PayloadDescriptor (

+                                            Buffer,

+                                            args.Guid,

+                                            args.FwVersion,

+                                            args.LowestSupportedVersion,

+                                            args.MonotonicCount,

+                                            args.HardwareInstance,

+                                            args.UpdateImageIndex,

+                                            args.SignToolPfxFile,

+                                            args.OpenSslSignerPrivateCertFile,

+                                            args.OpenSslOtherPublicCertFile,

+                                            args.OpenSslTrustedPublicCertFile,

+                                            args.SigningToolPath

+                                            ))

+        for SinglePayloadDescriptor in PayloadDescriptorList:

+            try:

+                SinglePayloadDescriptor.Validate (args)

+            except Exception as Message:

+                print ('GenerateCapsule: error: ' + str(Message))

+                sys.exit (1)

+        for SinglePayloadDescriptor in PayloadDescriptorList:

+            Result = SinglePayloadDescriptor.Payload

+            try:

+                FmpPayloadHeader.FwVersion              = SinglePayloadDescriptor.FwVersion

+                FmpPayloadHeader.LowestSupportedVersion = SinglePayloadDescriptor.LowestSupportedVersion

+                FmpPayloadHeader.Payload                = SinglePayloadDescriptor.Payload

+                Result = FmpPayloadHeader.Encode ()

+                if args.Verbose:

+                    FmpPayloadHeader.DumpInfo ()

+            except:

+                raise

+                print ('GenerateCapsule: error: can not encode FMP Payload Header')

+                sys.exit (1)

+            if SinglePayloadDescriptor.UseOpenSsl or SinglePayloadDescriptor.UseSignTool:

+                #

+                # Sign image with 64-bit MonotonicCount appended to end of image

+                #

+                try:

+                    if SinglePayloadDescriptor.UseSignTool:

+                        CertData = SignPayloadSignTool (

+                            Result + struct.pack ('<Q', SinglePayloadDescriptor.MonotonicCount),

+                            SinglePayloadDescriptor.SigningToolPath,

+                            SinglePayloadDescriptor.SignToolPfxFile,

+                            Verbose = args.Verbose

+                        )

+                    else:

+                        CertData = SignPayloadOpenSsl (

+                            Result + struct.pack ('<Q', SinglePayloadDescriptor.MonotonicCount),

+                            SinglePayloadDescriptor.SigningToolPath,

+                            SinglePayloadDescriptor.OpenSslSignerPrivateCertFile,

+                            SinglePayloadDescriptor.OpenSslOtherPublicCertFile,

+                            SinglePayloadDescriptor.OpenSslTrustedPublicCertFile,

+                            Verbose = args.Verbose

+                        )

+                except:

+                    print ('GenerateCapsule: error: can not sign payload')

+                    sys.exit (1)

+

+                try:

+                    FmpAuthHeader.MonotonicCount = SinglePayloadDescriptor.MonotonicCount

+                    FmpAuthHeader.CertData       = CertData

+                    FmpAuthHeader.Payload        = Result

+                    Result = FmpAuthHeader.Encode ()

+                    if args.Verbose:

+                        FmpAuthHeader.DumpInfo ()

+                except:

+                    print ('GenerateCapsule: error: can not encode FMP Auth Header')

+                    sys.exit (1)

+            FmpCapsuleHeader.AddPayload (SinglePayloadDescriptor.Guid, Result, HardwareInstance = SinglePayloadDescriptor.HardwareInstance, UpdateImageIndex = SinglePayloadDescriptor.UpdateImageIndex)

+        try:

+            for EmbeddedDriver in EmbeddedDriverDescriptorList:

+                FmpCapsuleHeader.AddEmbeddedDriver(EmbeddedDriver)

+

+            Result = FmpCapsuleHeader.Encode ()

+            if args.Verbose:

+                FmpCapsuleHeader.DumpInfo ()

+        except:

+            print ('GenerateCapsule: error: can not encode FMP Capsule Header')

+            sys.exit (1)

+

+        try:

+            UefiCapsuleHeader.OemFlags            = args.CapsuleOemFlag

+            UefiCapsuleHeader.PersistAcrossReset  = 'PersistAcrossReset'  in args.CapsuleFlag

+            UefiCapsuleHeader.PopulateSystemTable = False

+            UefiCapsuleHeader.InitiateReset       = 'InitiateReset'       in args.CapsuleFlag

+            UefiCapsuleHeader.Payload             = Result

+            Result = UefiCapsuleHeader.Encode ()

+            if args.Verbose:

+                UefiCapsuleHeader.DumpInfo ()

+        except:

+            print ('GenerateCapsule: error: can not encode UEFI Capsule Header')

+            sys.exit (1)

+        try:

+            if args.Verbose:

+                print ('Write binary output file {File}'.format (File = args.OutputFile.name))

+            args.OutputFile.write (Result)

+            args.OutputFile.close ()

+        except:

+            print ('GenerateCapsule: error: can not write binary output file {File}'.format (File = args.OutputFile.name))

+            sys.exit (1)

+

+    def Decode (PayloadDescriptorList, PayloadJsonDescriptorList, Buffer):

+        if args.JsonFile:

+            CheckArgumentConflict(args)

+        #

+        # Parse payload descriptors from JSON

+        #

+            try:

+                Json = json.loads (args.JsonFile.read())

+            except Exception as Message:

+                print ('GenerateCapsule: error: ' + str(Message))

+                sys.exit (1)

+            DecodeJsonFileParse (Json)    

+        else:

+            PayloadDescriptorList.append (PayloadDescriptor (

+                                            Buffer,

+                                            args.Guid,

+                                            args.FwVersion,

+                                            args.LowestSupportedVersion,

+                                            args.MonotonicCount,

+                                            args.HardwareInstance,

+                                            args.UpdateImageIndex,

+                                            args.SignToolPfxFile,

+                                            args.OpenSslSignerPrivateCertFile,

+                                            args.OpenSslOtherPublicCertFile,

+                                            args.OpenSslTrustedPublicCertFile,

+                                            args.SigningToolPath

+                                            ))

+        #

+        # Perform additional verification on payload descriptors

+        #

+        for SinglePayloadDescriptor in PayloadDescriptorList:

+            try:

+                SinglePayloadDescriptor.Validate (args)

+            except Exception as Message:

+                print ('GenerateCapsule: error: ' + str(Message))

+                sys.exit (1)

+        try:

+            Result = UefiCapsuleHeader.Decode (Buffer)

+            if len (Result) > 0:

+                Result = FmpCapsuleHeader.Decode (Result)

+                if args.JsonFile:

+                    if FmpCapsuleHeader.PayloadItemCount != len (PayloadDescriptorList):

+                        CapsulePayloadNum = FmpCapsuleHeader.PayloadItemCount

+                        JsonPayloadNum = len (PayloadDescriptorList)

+                        print ('GenerateCapsule: Decode error: {JsonPayloadNumber} payloads in JSON file {File} and {CapsulePayloadNumber} payloads in Capsule {CapsuleName}'.format (JsonPayloadNumber = JsonPayloadNum, File = args.JsonFile.name, CapsulePayloadNumber = CapsulePayloadNum, CapsuleName = args.InputFile.name))

+                        sys.exit (1)

+                    for Index in range (0, FmpCapsuleHeader.PayloadItemCount):

+                        if Index < len (PayloadDescriptorList):

+                            GUID = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).UpdateImageTypeId

+                            HardwareInstance = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).UpdateHardwareInstance

+                            UpdateImageIndex = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).UpdateImageIndex

+                            if PayloadDescriptorList[Index].Guid != GUID or PayloadDescriptorList[Index].HardwareInstance != HardwareInstance:

+                                print ('GenerateCapsule: Decode error: Guid or HardwareInstance pair in input JSON file {File} does not match the payload {PayloadIndex} in Capsule {InputCapsule}'.format (File = args.JsonFile.name, PayloadIndex = Index + 1, InputCapsule = args.InputFile.name))

+                                sys.exit (1)

+                            PayloadDescriptorList[Index].Payload = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).Payload

+                            DecodeJsonOutput = args.OutputFile.name + '.Payload.{Index:d}.bin'.format (Index = Index + 1)

+                            PayloadJsonDescriptorList.append (PayloadDescriptor (

+                                                                DecodeJsonOutput,

+                                                                GUID,

+                                                                None,

+                                                                None,

+                                                                None,

+                                                                HardwareInstance,

+                                                                UpdateImageIndex,

+                                                                PayloadDescriptorList[Index].SignToolPfxFile,

+                                                                PayloadDescriptorList[Index].OpenSslSignerPrivateCertFile,

+                                                                PayloadDescriptorList[Index].OpenSslOtherPublicCertFile,

+                                                                PayloadDescriptorList[Index].OpenSslTrustedPublicCertFile,

+                                                                PayloadDescriptorList[Index].SigningToolPath

+                                                                ))

+                else:

+                    PayloadDescriptorList[0].Payload = FmpCapsuleHeader.GetFmpCapsuleImageHeader (0).Payload

+                    for Index in range (0, FmpCapsuleHeader.PayloadItemCount):

+                        if Index > 0:

+                            PayloadDecodeFile = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).Payload

+                            PayloadDescriptorList.append (PayloadDescriptor (PayloadDecodeFile,

+                                                            None,

+                                                            None,

+                                                            None,

+                                                            None,

+                                                            None,

+                                                            None,

+                                                            None,

+                                                            None,

+                                                            None,

+                                                            None,

+                                                            None

+                                                            ))

+                        GUID = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).UpdateImageTypeId

+                        HardwareInstance = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).UpdateHardwareInstance

+                        UpdateImageIndex = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).UpdateImageIndex

+                        DecodeJsonOutput = args.OutputFile.name + '.Payload.{Index:d}.bin'.format (Index = Index + 1)

+                        PayloadJsonDescriptorList.append (PayloadDescriptor (

+                                                            DecodeJsonOutput,

+                                                            GUID,

+                                                            None,

+                                                            None,

+                                                            None,

+                                                            HardwareInstance,

+                                                            UpdateImageIndex,

+                                                            PayloadDescriptorList[Index].SignToolPfxFile,

+                                                            PayloadDescriptorList[Index].OpenSslSignerPrivateCertFile,

+                                                            PayloadDescriptorList[Index].OpenSslOtherPublicCertFile,

+                                                            PayloadDescriptorList[Index].OpenSslTrustedPublicCertFile,

+                                                            PayloadDescriptorList[Index].SigningToolPath

+                                                            ))

+                JsonIndex = 0

+                for SinglePayloadDescriptor in PayloadDescriptorList:

+                    if args.Verbose:

+                        print ('========')

+                        UefiCapsuleHeader.DumpInfo ()

+                        print ('--------')

+                        FmpCapsuleHeader.DumpInfo ()

+                    if FmpAuthHeader.IsSigned(SinglePayloadDescriptor.Payload):

+                        if not SinglePayloadDescriptor.UseOpenSsl and not SinglePayloadDescriptor.UseSignTool:

+                            print ('GenerateCapsule: decode warning: can not verify singed payload without cert or pfx file. Index = {Index}'.format (Index = JsonIndex + 1))

+                        SinglePayloadDescriptor.Payload = FmpAuthHeader.Decode (SinglePayloadDescriptor.Payload)

+                        PayloadJsonDescriptorList[JsonIndex].MonotonicCount = FmpAuthHeader.MonotonicCount

+                        if args.Verbose:

+                            print ('--------')

+                            FmpAuthHeader.DumpInfo ()

+

+                        #

+                        # Verify Image with 64-bit MonotonicCount appended to end of image

+                        #

+                        try:

+                          if SinglePayloadDescriptor.UseSignTool:

+                              CertData = VerifyPayloadSignTool (

+                                           FmpAuthHeader.Payload + struct.pack ('<Q', FmpAuthHeader.MonotonicCount),

+                                           FmpAuthHeader.CertData,

+                                           SinglePayloadDescriptor.SigningToolPath,

+                                           SinglePayloadDescriptor.SignToolPfxFile,

+                                           Verbose = args.Verbose

+                                           )

+                          else:

+                              CertData = VerifyPayloadOpenSsl (

+                                           FmpAuthHeader.Payload + struct.pack ('<Q', FmpAuthHeader.MonotonicCount),

+                                           FmpAuthHeader.CertData,

+                                           SinglePayloadDescriptor.SigningToolPath,

+                                           SinglePayloadDescriptor.OpenSslSignerPrivateCertFile,

+                                           SinglePayloadDescriptor.OpenSslOtherPublicCertFile,

+                                           SinglePayloadDescriptor.OpenSslTrustedPublicCertFile,

+                                           Verbose = args.Verbose

+                                           )

+                        except ValueError:

+                            print ('GenerateCapsule: warning: payload verification failed Index = {Index}'.format (Index = JsonIndex + 1))

+                    else:

+                        if args.Verbose:

+                            print ('--------')

+                            print ('No EFI_FIRMWARE_IMAGE_AUTHENTICATION')

+                    try:

+                        SinglePayloadDescriptor.Payload = FmpPayloadHeader.Decode (SinglePayloadDescriptor.Payload)

+                        PayloadJsonDescriptorList[JsonIndex].FwVersion = FmpPayloadHeader.FwVersion

+                        PayloadJsonDescriptorList[JsonIndex].LowestSupportedVersion = FmpPayloadHeader.LowestSupportedVersion

+                        JsonIndex = JsonIndex + 1

+                        if args.Verbose:

+                            print ('--------')

+                            FmpPayloadHeader.DumpInfo ()

+                            print ('========')

+                    except:

+                        if args.Verbose:

+                            print ('--------')

+                            print ('No FMP_PAYLOAD_HEADER')

+                            print ('========')

+                        raise

+                #

+                # Write embedded driver file(s)

+                #

+                for Index in range (0, FmpCapsuleHeader.EmbeddedDriverCount):

+                    EmbeddedDriverBuffer = FmpCapsuleHeader.GetEmbeddedDriver (Index)

+                    EmbeddedDriverPath = args.OutputFile.name + '.EmbeddedDriver.{Index:d}.efi'.format (Index = Index + 1)

+                    try:

+                        if args.Verbose:

+                            print ('Write embedded driver file {File}'.format (File = EmbeddedDriverPath))

+                        EmbeddedDriverFile = open (EmbeddedDriverPath, 'wb')

+                        EmbeddedDriverFile.write (EmbeddedDriverBuffer)

+                        EmbeddedDriverFile.close ()

+                    except:

+                        print ('GenerateCapsule: error: can not write embedded driver file {File}'.format (File = EmbeddedDriverPath))

+                        sys.exit (1)

+

+        except:

+            raise

+            print ('GenerateCapsule: error: can not decode capsule')

+            sys.exit (1)

+        GenerateOutputJson(PayloadJsonDescriptorList)

+        PayloadIndex = 0

+        for SinglePayloadDescriptor in PayloadDescriptorList:

+            if args.OutputFile is None:

+                print ('GenerateCapsule: Decode error: OutputFile is needed for decode output')

+                sys.exit (1)

+            try:

+                if args.Verbose:

+                    print ('Write binary output file {File}'.format (File = args.OutputFile.name))

+                PayloadDecodePath = args.OutputFile.name + '.Payload.{Index:d}.bin'.format (Index = PayloadIndex + 1)

+                PayloadDecodeFile = open (PayloadDecodePath, 'wb')

+                PayloadDecodeFile.write (SinglePayloadDescriptor.Payload)

+                PayloadDecodeFile.close ()

+                PayloadIndex = PayloadIndex + 1

+            except:

+                print ('GenerateCapsule: error: can not write binary output file {File}'.format (File = SinglePayloadDescriptor.OutputFile.name))

+                sys.exit (1)

+

+    def DumpInfo (Buffer, args):

+        if args.OutputFile is not None:

+            raise argparse.ArgumentTypeError ('the following option is not supported for dumpinfo operations: --output')

+        try:

+            Result = UefiCapsuleHeader.Decode (Buffer)

+            print ('========')

+            UefiCapsuleHeader.DumpInfo ()

+            if len (Result) > 0:

+                FmpCapsuleHeader.Decode (Result)

+                print ('--------')

+                FmpCapsuleHeader.DumpInfo ()

+                for Index in range (0, FmpCapsuleHeader.PayloadItemCount):

+                    Result = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).Payload

+                    try:

+                        Result = FmpAuthHeader.Decode (Result)

+                        print ('--------')

+                        FmpAuthHeader.DumpInfo ()

+                    except:

+                        print ('--------')

+                        print ('No EFI_FIRMWARE_IMAGE_AUTHENTICATION')

+                    try:

+                        Result = FmpPayloadHeader.Decode (Result)

+                        print ('--------')

+                        FmpPayloadHeader.DumpInfo ()

+                    except:

+                        print ('--------')

+                        print ('No FMP_PAYLOAD_HEADER')

+                    print ('========')

+        except:

+            print ('GenerateCapsule: error: can not decode capsule')

+            sys.exit (1)

+

     #

     # Create command line argument parser object

     #

@@ -226,7 +885,7 @@ if __name__ == '__main__':
     #

     # Add input and output file arguments

     #

-    parser.add_argument("InputFile",  type = argparse.FileType('rb'),

+    parser.add_argument("InputFile",  type = argparse.FileType('rb'), nargs='?',

                         help = "Input binary payload filename.")

     parser.add_argument("-o", "--output", dest = 'OutputFile', type = argparse.FileType('wb'),

                         help = "Output filename.")

@@ -243,6 +902,8 @@ if __name__ == '__main__':
     #

     # Add optional arguments for this command

     #

+    parser.add_argument ("-j", "--json-file", dest = 'JsonFile', type=argparse.FileType('r'),

+                         help = "JSON configuration file for multiple payloads and embedded drivers.")

     parser.add_argument ("--capflag", dest = 'CapsuleFlag', action='append', default = [],

                          choices=['PersistAcrossReset', 'InitiateReset'],

                          help = "Capsule flag can be PersistAcrossReset or InitiateReset or not set")

@@ -250,7 +911,7 @@ if __name__ == '__main__':
                          help = "Capsule OEM Flag is an integer between 0x0000 and 0xffff.")

 

     parser.add_argument ("--guid", dest = 'Guid', type = ValidateRegistryFormatGuid,

-                         help = "The FMP/ESRT GUID in registry format.  Required for encode operations.")

+                         help = "The FMP/ESRT GUID in registry format.  Required for single payload encode operations.")

     parser.add_argument ("--hardware-instance", dest = 'HardwareInstance', type = ValidateUnsignedInteger, default = 0x0000000000000000,

                          help = "The 64-bit hardware instance.  The default is 0x0000000000000000")

 

@@ -259,9 +920,9 @@ if __name__ == '__main__':
                          help = "64-bit monotonic count value in header.  Default is 0x0000000000000000.")

 

     parser.add_argument ("--fw-version", dest = 'FwVersion', type = ValidateUnsignedInteger,

-                         help = "The 32-bit version of the binary payload (e.g. 0x11223344 or 5678).  Required for encode operations that sign a payload.")

+                         help = "The 32-bit version of the binary payload (e.g. 0x11223344 or 5678).  Required for encode operations.")

     parser.add_argument ("--lsv", dest = 'LowestSupportedVersion', type = ValidateUnsignedInteger,

-                         help = "The 32-bit lowest supported version of the binary payload (e.g. 0x11223344 or 5678).  Required for encode operations that sign a payload.")

+                         help = "The 32-bit lowest supported version of the binary payload (e.g. 0x11223344 or 5678).  Required for encode operations.")

 

     parser.add_argument ("--pfx-file", dest='SignToolPfxFile', type=argparse.FileType('rb'),

                          help="signtool PFX certificate filename.")

@@ -276,6 +937,9 @@ if __name__ == '__main__':
     parser.add_argument ("--signing-tool-path", dest = 'SigningToolPath',

                          help = "Path to signtool or OpenSSL tool.  Optional if path to tools are already in PATH.")

 

+    parser.add_argument ("--embedded-driver", dest = 'EmbeddedDriver', type = argparse.FileType('rb'), action='append', default = [],

+                         help = "Path to embedded UEFI driver to add to capsule.")

+

     #

     # Add optional arguments common to all operations

     #

@@ -286,79 +950,29 @@ if __name__ == '__main__':
                          help = "Disable all messages except fatal errors.")

     parser.add_argument ("--debug", dest = 'Debug', type = int, metavar = '[0-9]', choices = range (0, 10), default = 0,

                          help = "Set debug level")

+    parser.add_argument ("--update-image-index", dest = 'UpdateImageIndex', type = ValidateUnsignedInteger, default = 0x01, help = "unique number identifying the firmware image within the device ")

 

     #

     # Parse command line arguments

     #

     args = parser.parse_args()

 

-    #

-    # Perform additional argument verification

-    #

-    if args.Encode:

-        if args.Guid is None:

-            parser.error ('the following option is required: --guid')

-        if 'PersistAcrossReset' not in args.CapsuleFlag:

-            if 'InitiateReset' in args.CapsuleFlag:

-                parser.error ('--capflag InitiateReset also requires --capflag PersistAcrossReset')

-        if args.CapsuleOemFlag > 0xFFFF:

-            parser.error ('--capoemflag must be an integer between 0x0000 and 0xffff')

-        if args.HardwareInstance > 0xFFFFFFFFFFFFFFFF:

-            parser.error ('--hardware-instance must be an integer in range 0x0..0xffffffffffffffff')

-        if args.MonotonicCount > 0xFFFFFFFFFFFFFFFF:

-            parser.error ('--monotonic-count must be an integer in range 0x0..0xffffffffffffffff')

-

-    UseSignTool = args.SignToolPfxFile is not None

-    UseOpenSsl  = (args.OpenSslSignerPrivateCertFile is not None and

-                   args.OpenSslOtherPublicCertFile is not None and

-                   args.OpenSslTrustedPublicCertFile is not None)

-    AnyOpenSsl  = (args.OpenSslSignerPrivateCertFile is not None or

-                   args.OpenSslOtherPublicCertFile is not None or

-                   args.OpenSslTrustedPublicCertFile is not None)

-    if args.Encode or args.Decode:

-        if args.OutputFile is None:

-            parser.error ('the following option is required for all encode and decode operations: --output')

-

-        if UseSignTool and AnyOpenSsl:

-            parser.error ('Providing both signtool and OpenSSL options is not supported')

-        if not UseSignTool and not UseOpenSsl and AnyOpenSsl:

-            parser.error ('all the following options are required for OpenSSL: --signer-private-cert, --other-public-cert, --trusted-public-cert')

-        if UseSignTool and platform.system() != 'Windows':

-            parser.error ('Use of signtool is not supported on this operating system.')

-        if args.Encode and (UseSignTool or UseOpenSsl):

-            if args.FwVersion is None or args.LowestSupportedVersion is None:

-                parser.error ('the following options are required: --fw-version, --lsv')

-            if args.FwVersion > 0xFFFFFFFF:

-                parser.error ('--fw-version must be an integer in range 0x0..0xffffffff')

-            if args.LowestSupportedVersion > 0xFFFFFFFF:

-                parser.error ('--lsv must be an integer in range 0x0..0xffffffff')

-

-        if UseSignTool:

-            args.SignToolPfxFile.close()

-            args.SignToolPfxFile = args.SignToolPfxFile.name

-        if UseOpenSsl:

-            args.OpenSslSignerPrivateCertFile.close()

-            args.OpenSslOtherPublicCertFile.close()

-            args.OpenSslTrustedPublicCertFile.close()

-            args.OpenSslSignerPrivateCertFile = args.OpenSslSignerPrivateCertFile.name

-            args.OpenSslOtherPublicCertFile   = args.OpenSslOtherPublicCertFile.name

-            args.OpenSslTrustedPublicCertFile = args.OpenSslTrustedPublicCertFile.name

-

-    if args.DumpInfo:

-        if args.OutputFile is not None:

-            parser.error ('the following option is not supported for dumpinfo operations: --output')

-

     #

     # Read binary input file

     #

-    try:

-        if args.Verbose:

-            print ('Read binary input file {File}'.format (File = args.InputFile.name))

-        Buffer = args.InputFile.read ()

-        args.InputFile.close ()

-    except:

-        print ('GenerateCapsule: error: can not read binary input file {File}'.format (File = args.InputFile.name))

-        sys.exit (1)

+    Buffer = ''

+    if args.InputFile:

+        if os.path.getsize (args.InputFile.name) == 0:

+            print ('GenerateCapsule: error: InputFile {File} is empty'.format (File = args.InputFile.name))

+            sys.exit (1)

+        try:

+            if args.Verbose:

+                print ('Read binary input file {File}'.format (File = args.InputFile.name))

+            Buffer = args.InputFile.read ()

+            args.InputFile.close ()

+        except:

+            print ('GenerateCapsule: error: can not read binary input file {File}'.format (File = args.InputFile.name))

+            sys.exit (1)

 

     #

     # Create objects

@@ -368,182 +982,27 @@ if __name__ == '__main__':
     FmpAuthHeader     = FmpAuthHeaderClass ()

     FmpPayloadHeader  = FmpPayloadHeaderClass ()

 

-    if args.Encode:

-        Result = Buffer

-        if UseSignTool or UseOpenSsl:

-            try:

-                FmpPayloadHeader.FwVersion              = args.FwVersion

-                FmpPayloadHeader.LowestSupportedVersion = args.LowestSupportedVersion

-                FmpPayloadHeader.Payload                = Result

-                Result = FmpPayloadHeader.Encode ()

-                if args.Verbose:

-                    FmpPayloadHeader.DumpInfo ()

-            except:

-                print ('GenerateCapsule: error: can not encode FMP Payload Header')

-                sys.exit (1)

-

-            #

-            # Sign image with 64-bit MonotonicCount appended to end of image

-            #

-            try:

-                if UseSignTool:

-                    CertData = SignPayloadSignTool (

-                                 Result + struct.pack ('<Q', args.MonotonicCount),

-                                 args.SigningToolPath,

-                                 args.SignToolPfxFile

-                                 )

-                else:

-                    CertData = SignPayloadOpenSsl (

-                                 Result + struct.pack ('<Q', args.MonotonicCount),

-                                 args.SigningToolPath,

-                                 args.OpenSslSignerPrivateCertFile,

-                                 args.OpenSslOtherPublicCertFile,

-                                 args.OpenSslTrustedPublicCertFile

-                                 )

-            except:

-                print ('GenerateCapsule: error: can not sign payload')

-                sys.exit (1)

-

-            try:

-                FmpAuthHeader.MonotonicCount = args.MonotonicCount

-                FmpAuthHeader.CertData       = CertData

-                FmpAuthHeader.Payload        = Result

-                Result = FmpAuthHeader.Encode ()

-                if args.Verbose:

-                    FmpAuthHeader.DumpInfo ()

-            except:

-                print ('GenerateCapsule: error: can not encode FMP Auth Header')

-                sys.exit (1)

-

-        try:

-            FmpCapsuleHeader.AddPayload (args.Guid, Result, HardwareInstance = args.HardwareInstance)

-            Result = FmpCapsuleHeader.Encode ()

-            if args.Verbose:

-                FmpCapsuleHeader.DumpInfo ()

-        except:

-            print ('GenerateCapsule: error: can not encode FMP Capsule Header')

-            sys.exit (1)

-

-        try:

-            UefiCapsuleHeader.OemFlags            = args.CapsuleOemFlag

-            UefiCapsuleHeader.PersistAcrossReset  = 'PersistAcrossReset'  in args.CapsuleFlag

-            UefiCapsuleHeader.PopulateSystemTable = False

-            UefiCapsuleHeader.InitiateReset       = 'InitiateReset'       in args.CapsuleFlag

-            UefiCapsuleHeader.Payload             = Result

-            Result = UefiCapsuleHeader.Encode ()

-            if args.Verbose:

-                UefiCapsuleHeader.DumpInfo ()

-        except:

-            print ('GenerateCapsule: error: can not encode UEFI Capsule Header')

-            sys.exit (1)

-

-    elif args.Decode:

-        try:

-            Result = UefiCapsuleHeader.Decode (Buffer)

-            FmpCapsuleHeader.Decode (Result)

-            Result = FmpCapsuleHeader.GetFmpCapsuleImageHeader (0).Payload

-            if args.Verbose:

-                print ('========')

-                UefiCapsuleHeader.DumpInfo ()

-                print ('--------')

-                FmpCapsuleHeader.DumpInfo ()

-            if UseSignTool or UseOpenSsl:

-                Result = FmpAuthHeader.Decode (Result)

-                if args.Verbose:

-                    print ('--------')

-                    FmpAuthHeader.DumpInfo ()

+    EmbeddedDriverDescriptorList = []

+    PayloadDescriptorList = []

+    PayloadJsonDescriptorList = []

 

-                #

-                # Verify Image with 64-bit MonotonicCount appended to end of image

-                #

-                try:

-                  if UseSignTool:

-                      CertData = VerifyPayloadSignTool (

-                                   FmpAuthHeader.Payload + struct.pack ('<Q', FmpAuthHeader.MonotonicCount),

-                                   FmpAuthHeader.CertData,

-                                   args.SigningToolPath,

-                                   args.SignToolPfxFile

-                                   )

-                  else:

-                      CertData = VerifyPayloadOpenSsl (

-                                   FmpAuthHeader.Payload + struct.pack ('<Q', FmpAuthHeader.MonotonicCount),

-                                   FmpAuthHeader.CertData,

-                                   args.SigningToolPath,

-                                   args.OpenSslSignerPrivateCertFile,

-                                   args.OpenSslOtherPublicCertFile,

-                                   args.OpenSslTrustedPublicCertFile

-                                   )

-                except ValueError:

-                    print ('GenerateCapsule: warning: can not verify payload.')

-

-                try:

-                    Result = FmpPayloadHeader.Decode (Result)

-                    if args.Verbose:

-                        print ('--------')

-                        FmpPayloadHeader.DumpInfo ()

-                        print ('========')

-                except:

-                    if args.Verbose:

-                        print ('--------')

-                        print ('No FMP_PAYLOAD_HEADER')

-                        print ('========')

-                    raise

-            else:

-                if args.Verbose:

-                    print ('--------')

-                    print ('No EFI_FIRMWARE_IMAGE_AUTHENTICATION')

-                    print ('--------')

-                    print ('No FMP_PAYLOAD_HEADER')

-                    print ('========')

-        except:

-            print ('GenerateCapsule: error: can not decode capsule')

-            sys.exit (1)

+    #

+    #Encode Operation

+    #

+    if args.Encode:

+        Encode (PayloadDescriptorList, EmbeddedDriverDescriptorList, Buffer)

 

-    elif args.DumpInfo:

-        try:

-            Result = UefiCapsuleHeader.Decode (Buffer)

-            FmpCapsuleHeader.Decode (Result)

-            Result = FmpCapsuleHeader.GetFmpCapsuleImageHeader (0).Payload

-            print ('========')

-            UefiCapsuleHeader.DumpInfo ()

-            print ('--------')

-            FmpCapsuleHeader.DumpInfo ()

-            try:

-                Result = FmpAuthHeader.Decode (Result)

-                print ('--------')

-                FmpAuthHeader.DumpInfo ()

-                try:

-                    Result = FmpPayloadHeader.Decode (Result)

-                    print ('--------')

-                    FmpPayloadHeader.DumpInfo ()

-                except:

-                    print ('--------')

-                    print ('No FMP_PAYLOAD_HEADER')

-            except:

-                print ('--------')

-                print ('No EFI_FIRMWARE_IMAGE_AUTHENTICATION')

-                print ('--------')

-                print ('No FMP_PAYLOAD_HEADER')

-            print ('========')

-        except:

-            print ('GenerateCapsule: error: can not decode capsule')

-            sys.exit (1)

-    else:

-        print('GenerateCapsule: error: invalid options')

-        sys.exit (1)

+    #

+    #Decode Operation

+    #

+    if args.Decode:

+        Decode (PayloadDescriptorList, PayloadJsonDescriptorList, Buffer)

 

     #

-    # Write binary output file

+    #Dump Info Operation

     #

-    if args.OutputFile is not None:

-        try:

-            if args.Verbose:

-                print ('Write binary output file {File}'.format (File = args.OutputFile.name))

-            args.OutputFile.write (Result)

-            args.OutputFile.close ()

-        except:

-            print ('GenerateCapsule: error: can not write binary output file {File}'.format (File = args.OutputFile.name))

-            sys.exit (1)

+    if args.DumpInfo:

+        DumpInfo (Buffer, args)

 

     if args.Verbose:

         print('Success')

diff --git a/BaseTools/Source/Python/Common/Uefi/Capsule/FmpAuthHeader.py b/BaseTools/Source/Python/Common/Uefi/Capsule/FmpAuthHeader.py
index 4b8c6da26a..48c605faa8 100644
--- a/BaseTools/Source/Python/Common/Uefi/Capsule/FmpAuthHeader.py
+++ b/BaseTools/Source/Python/Common/Uefi/Capsule/FmpAuthHeader.py
@@ -2,7 +2,7 @@
 # Module that encodes and decodes a EFI_FIRMWARE_IMAGE_AUTHENTICATION with

 # certificate data and payload data.

 #

-# Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>

+# Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<BR>

 # SPDX-License-Identifier: BSD-2-Clause-Patent

 #

 

@@ -166,6 +166,18 @@ class FmpAuthHeaderClass (object):
         self._Valid           = True

         return self.Payload

 

+    def IsSigned (self, Buffer):

+        if len (Buffer) < self._StructSize:

+            return False

+        (MonotonicCount, dwLength, wRevision, wCertificateType, CertType) = \

+            struct.unpack (

+                     self._StructFormat,

+                     Buffer[0:self._StructSize]

+                     )

+        if CertType != self._EFI_CERT_TYPE_PKCS7_GUID.bytes_le:

+            return False

+        return True

+

     def DumpInfo (self):

         if not self._Valid:

             raise ValueError

diff --git a/BaseTools/Source/Python/Common/Uefi/Capsule/FmpCapsuleHeader.py b/BaseTools/Source/Python/Common/Uefi/Capsule/FmpCapsuleHeader.py
index c24258d047..91d24919c4 100644
--- a/BaseTools/Source/Python/Common/Uefi/Capsule/FmpCapsuleHeader.py
+++ b/BaseTools/Source/Python/Common/Uefi/Capsule/FmpCapsuleHeader.py
@@ -2,7 +2,7 @@
 # Module that encodes and decodes a EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER with

 # a payload.

 #

-# Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>

+# Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<BR>

 # SPDX-License-Identifier: BSD-2-Clause-Patent

 #

 

@@ -172,8 +172,8 @@ class FmpCapsuleHeaderClass (object):
             raise ValueError

         return self._EmbeddedDriverList[Index]

 

-    def AddPayload (self, UpdateImageTypeId, Payload = b'', VendorCodeBytes = b'', HardwareInstance = 0):

-        self._PayloadList.append ((UpdateImageTypeId, Payload, VendorCodeBytes, HardwareInstance))

+    def AddPayload (self, UpdateImageTypeId, Payload = b'', VendorCodeBytes = b'', HardwareInstance = 0, UpdateImageIndex = 1):

+        self._PayloadList.append ((UpdateImageTypeId, Payload, VendorCodeBytes, HardwareInstance, UpdateImageIndex))

 

     def GetFmpCapsuleImageHeader (self, Index):

         if Index >= len (self._FmpCapsuleImageHeaderList):

@@ -198,10 +198,10 @@ class FmpCapsuleHeaderClass (object):
             self._ItemOffsetList.append (Offset)

             Offset = Offset + len (EmbeddedDriver)

         Index = 1

-        for (UpdateImageTypeId, Payload, VendorCodeBytes, HardwareInstance) in self._PayloadList:

+        for (UpdateImageTypeId, Payload, VendorCodeBytes, HardwareInstance, UpdateImageIndex) in self._PayloadList:

             FmpCapsuleImageHeader = FmpCapsuleImageHeaderClass ()

             FmpCapsuleImageHeader.UpdateImageTypeId      = UpdateImageTypeId

-            FmpCapsuleImageHeader.UpdateImageIndex       = Index

+            FmpCapsuleImageHeader.UpdateImageIndex       = UpdateImageIndex

             FmpCapsuleImageHeader.Payload                = Payload

             FmpCapsuleImageHeader.VendorCodeBytes        = VendorCodeBytes

             FmpCapsuleImageHeader.UpdateHardwareInstance = HardwareInstance

@@ -288,6 +288,8 @@ class FmpCapsuleHeaderClass (object):
             raise ValueError

         print ('EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER.Version             = {Version:08X}'.format (Version = self.Version))

         print ('EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER.EmbeddedDriverCount = {EmbeddedDriverCount:08X}'.format (EmbeddedDriverCount = self.EmbeddedDriverCount))

+        for EmbeddedDriver in self._EmbeddedDriverList:

+            print ('  sizeof (EmbeddedDriver)                                  = {Size:08X}'.format (Size = len (EmbeddedDriver)))

         print ('EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER.PayloadItemCount    = {PayloadItemCount:08X}'.format (PayloadItemCount = self.PayloadItemCount))

         print ('EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER.ItemOffsetList      = ')

         for Offset in self._ItemOffsetList:

-- 
2.20.0.windows.1


^ permalink raw reply related	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2019-06-11  3:06 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2019-05-27  7:28 [Patch] BaseTools/Capsule: Supports UEFI Capsule with multiple payloads and embedded drivers Eric Jin
2019-05-27 13:58 ` [edk2-devel] " Liming Gao
2019-05-28  2:10   ` Eric Jin
2019-06-11  3:06 ` Bob Feng

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox