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