]>
Commit | Line | Data |
---|---|---|
8b63877a KM |
1 | ## @file\r |
2 | # Generate a capsule.\r | |
3 | #\r | |
d6f079b6 KM |
4 | # This tool generates a UEFI Capsule around an FMP Capsule. The capsule payload\r |
5 | # be signed using signtool or OpenSSL and if it is signed the signed content\r | |
6 | # includes an FMP Payload Header.\r | |
7 | #\r | |
8 | # This tool is intended to be used to generate UEFI Capsules to update the\r | |
9 | # system firmware or device firmware for integrated devices. In order to\r | |
10 | # keep the tool as simple as possible, it has the following limitations:\r | |
11 | # * Do not support multiple payloads in a capsule.\r | |
12 | # * Do not support optional drivers in a capsule.\r | |
13 | # * Do not support vendor code bytes in a capsule.\r | |
14 | #\r | |
8b63877a | 15 | # Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>\r |
2e351cbe | 16 | # SPDX-License-Identifier: BSD-2-Clause-Patent\r |
8b63877a KM |
17 | #\r |
18 | \r | |
19 | '''\r | |
20 | GenerateCapsule\r | |
21 | '''\r | |
22 | \r | |
23 | import sys\r | |
24 | import argparse\r | |
25 | import uuid\r | |
26 | import struct\r | |
27 | import subprocess\r | |
28 | import os\r | |
29 | import tempfile\r | |
30 | import shutil\r | |
31 | import platform\r | |
32 | from Common.Uefi.Capsule.UefiCapsuleHeader import UefiCapsuleHeaderClass\r | |
33 | from Common.Uefi.Capsule.FmpCapsuleHeader import FmpCapsuleHeaderClass\r | |
34 | from Common.Uefi.Capsule.FmpAuthHeader import FmpAuthHeaderClass\r | |
35 | from Common.Edk2.Capsule.FmpPayloadHeader import FmpPayloadHeaderClass\r | |
36 | \r | |
37 | #\r | |
38 | # Globals for help information\r | |
39 | #\r | |
40 | __prog__ = 'GenerateCapsule'\r | |
41 | __version__ = '0.9'\r | |
42 | __copyright__ = 'Copyright (c) 2018, Intel Corporation. All rights reserved.'\r | |
43 | __description__ = 'Generate a capsule.\n'\r | |
44 | \r | |
45 | def SignPayloadSignTool (Payload, ToolPath, PfxFile):\r | |
46 | #\r | |
47 | # Create a temporary directory\r | |
48 | #\r | |
49 | TempDirectoryName = tempfile.mkdtemp()\r | |
50 | \r | |
51 | #\r | |
52 | # Generate temp file name for the payload contents\r | |
53 | #\r | |
54 | TempFileName = os.path.join (TempDirectoryName, 'Payload.bin')\r | |
55 | \r | |
56 | #\r | |
57 | # Create temporary payload file for signing\r | |
58 | #\r | |
59 | try:\r | |
60 | File = open (TempFileName, mode='wb')\r | |
61 | File.write (Payload)\r | |
62 | File.close ()\r | |
63 | except:\r | |
64 | shutil.rmtree (TempDirectoryName)\r | |
65 | raise ValueError ('GenerateCapsule: error: can not write temporary payload file.')\r | |
66 | \r | |
67 | #\r | |
68 | # Build signtool command\r | |
69 | #\r | |
70 | if ToolPath is None:\r | |
71 | ToolPath = ''\r | |
72 | Command = ''\r | |
73 | Command = Command + '"{Path}" '.format (Path = os.path.join (ToolPath, 'signtool.exe'))\r | |
74 | Command = Command + 'sign /fd sha256 /p7ce DetachedSignedData /p7co 1.2.840.113549.1.7.2 '\r | |
75 | Command = Command + '/p7 {TempDir} '.format (TempDir = TempDirectoryName)\r | |
76 | Command = Command + '/f {PfxFile} '.format (PfxFile = PfxFile)\r | |
77 | Command = Command + TempFileName\r | |
78 | \r | |
79 | #\r | |
80 | # Sign the input file using the specified private key\r | |
81 | #\r | |
82 | try:\r | |
83 | Process = subprocess.Popen (Command, stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE, shell = True)\r | |
84 | Result = Process.communicate('')\r | |
85 | except:\r | |
86 | shutil.rmtree (TempDirectoryName)\r | |
87 | raise ValueError ('GenerateCapsule: error: can not run signtool.')\r | |
88 | \r | |
89 | if Process.returncode != 0:\r | |
90 | shutil.rmtree (TempDirectoryName)\r | |
1c27ec42 | 91 | print (Result[1].decode(encoding='utf-8', errors='ignore'))\r |
8b63877a KM |
92 | raise ValueError ('GenerateCapsule: error: signtool failed.')\r |
93 | \r | |
94 | #\r | |
95 | # Read the signature from the generated output file\r | |
96 | #\r | |
97 | try:\r | |
98 | File = open (TempFileName + '.p7', mode='rb')\r | |
99 | Signature = File.read ()\r | |
100 | File.close ()\r | |
101 | except:\r | |
102 | shutil.rmtree (TempDirectoryName)\r | |
103 | raise ValueError ('GenerateCapsule: error: can not read signature file.')\r | |
104 | \r | |
105 | shutil.rmtree (TempDirectoryName)\r | |
106 | return Signature\r | |
107 | \r | |
108 | def VerifyPayloadSignTool (Payload, CertData, ToolPath, PfxFile):\r | |
109 | print ('signtool verify is not supported.')\r | |
110 | raise ValueError ('GenerateCapsule: error: signtool verify is not supported.')\r | |
111 | \r | |
112 | def SignPayloadOpenSsl (Payload, ToolPath, SignerPrivateCertFile, OtherPublicCertFile, TrustedPublicCertFile):\r | |
113 | #\r | |
114 | # Build openssl command\r | |
115 | #\r | |
116 | if ToolPath is None:\r | |
117 | ToolPath = ''\r | |
118 | Command = ''\r | |
119 | Command = Command + '"{Path}" '.format (Path = os.path.join (ToolPath, 'openssl'))\r | |
120 | Command = Command + 'smime -sign -binary -outform DER -md sha256 '\r | |
121 | Command = Command + '-signer "{Private}" -certfile "{Public}"'.format (Private = SignerPrivateCertFile, Public = OtherPublicCertFile)\r | |
122 | \r | |
123 | #\r | |
124 | # Sign the input file using the specified private key and capture signature from STDOUT\r | |
125 | #\r | |
126 | try:\r | |
127 | Process = subprocess.Popen (Command, stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE, shell = True)\r | |
128 | Result = Process.communicate(input = Payload)\r | |
1c27ec42 | 129 | Signature = Result[0].decode(encoding='utf-8', errors='ignore')\r |
8b63877a KM |
130 | except:\r |
131 | raise ValueError ('GenerateCapsule: error: can not run openssl.')\r | |
132 | \r | |
133 | if Process.returncode != 0:\r | |
1c27ec42 | 134 | print (Result[1].decode(encoding='utf-8', errors='ignore'))\r |
8b63877a KM |
135 | raise ValueError ('GenerateCapsule: error: openssl failed.')\r |
136 | \r | |
137 | return Signature\r | |
138 | \r | |
139 | def VerifyPayloadOpenSsl (Payload, CertData, ToolPath, SignerPrivateCertFile, OtherPublicCertFile, TrustedPublicCertFile):\r | |
140 | #\r | |
141 | # Create a temporary directory\r | |
142 | #\r | |
143 | TempDirectoryName = tempfile.mkdtemp()\r | |
144 | \r | |
145 | #\r | |
146 | # Generate temp file name for the payload contents\r | |
147 | #\r | |
148 | TempFileName = os.path.join (TempDirectoryName, 'Payload.bin')\r | |
149 | \r | |
150 | #\r | |
151 | # Create temporary payload file for verification\r | |
152 | #\r | |
153 | try:\r | |
154 | File = open (TempFileName, mode='wb')\r | |
155 | File.write (Payload)\r | |
156 | File.close ()\r | |
157 | except:\r | |
158 | shutil.rmtree (TempDirectoryName)\r | |
159 | raise ValueError ('GenerateCapsule: error: can not write temporary payload file.')\r | |
160 | \r | |
161 | #\r | |
162 | # Build openssl command\r | |
163 | #\r | |
164 | if ToolPath is None:\r | |
165 | ToolPath = ''\r | |
166 | Command = ''\r | |
167 | Command = Command + '"{Path}" '.format (Path = os.path.join (ToolPath, 'openssl'))\r | |
168 | Command = Command + 'smime -verify -inform DER '\r | |
169 | Command = Command + '-content {Content} -CAfile "{Public}"'.format (Content = TempFileName, Public = TrustedPublicCertFile)\r | |
170 | \r | |
171 | #\r | |
172 | # Verify signature\r | |
173 | #\r | |
174 | try:\r | |
175 | Process = subprocess.Popen (Command, stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE, shell = True)\r | |
176 | Result = Process.communicate(input = CertData)\r | |
177 | except:\r | |
178 | shutil.rmtree (TempDirectoryName)\r | |
179 | raise ValueError ('GenerateCapsule: error: can not run openssl.')\r | |
180 | \r | |
181 | if Process.returncode != 0:\r | |
182 | shutil.rmtree (TempDirectoryName)\r | |
1c27ec42 | 183 | print (Result[1].decode(encoding='utf-8', errors='ignore'))\r |
8b63877a KM |
184 | raise ValueError ('GenerateCapsule: error: openssl failed.')\r |
185 | \r | |
186 | shutil.rmtree (TempDirectoryName)\r | |
187 | return Payload\r | |
188 | \r | |
189 | if __name__ == '__main__':\r | |
190 | def convert_arg_line_to_args(arg_line):\r | |
191 | for arg in arg_line.split():\r | |
192 | if not arg.strip():\r | |
193 | continue\r | |
194 | yield arg\r | |
195 | \r | |
196 | def ValidateUnsignedInteger (Argument):\r | |
197 | try:\r | |
198 | Value = int (Argument, 0)\r | |
199 | except:\r | |
200 | Message = '{Argument} is not a valid integer value.'.format (Argument = Argument)\r | |
201 | raise argparse.ArgumentTypeError (Message)\r | |
202 | if Value < 0:\r | |
203 | Message = '{Argument} is a negative value.'.format (Argument = Argument)\r | |
204 | raise argparse.ArgumentTypeError (Message)\r | |
205 | return Value\r | |
206 | \r | |
207 | def ValidateRegistryFormatGuid (Argument):\r | |
208 | try:\r | |
209 | Value = uuid.UUID (Argument)\r | |
210 | except:\r | |
211 | Message = '{Argument} is not a valid registry format GUID value.'.format (Argument = Argument)\r | |
212 | raise argparse.ArgumentTypeError (Message)\r | |
213 | return Value\r | |
214 | \r | |
215 | #\r | |
216 | # Create command line argument parser object\r | |
217 | #\r | |
218 | parser = argparse.ArgumentParser (\r | |
219 | prog = __prog__,\r | |
220 | description = __description__ + __copyright__,\r | |
221 | conflict_handler = 'resolve',\r | |
222 | fromfile_prefix_chars = '@'\r | |
223 | )\r | |
224 | parser.convert_arg_line_to_args = convert_arg_line_to_args\r | |
225 | \r | |
226 | #\r | |
227 | # Add input and output file arguments\r | |
228 | #\r | |
229 | parser.add_argument("InputFile", type = argparse.FileType('rb'),\r | |
230 | help = "Input binary payload filename.")\r | |
231 | parser.add_argument("-o", "--output", dest = 'OutputFile', type = argparse.FileType('wb'),\r | |
232 | help = "Output filename.")\r | |
233 | #\r | |
234 | # Add group for -e and -d flags that are mutually exclusive and required\r | |
235 | #\r | |
236 | group = parser.add_mutually_exclusive_group (required = True)\r | |
237 | group.add_argument ("-e", "--encode", dest = 'Encode', action = "store_true",\r | |
238 | help = "Encode file")\r | |
239 | group.add_argument ("-d", "--decode", dest = 'Decode', action = "store_true",\r | |
240 | help = "Decode file")\r | |
241 | group.add_argument ("--dump-info", dest = 'DumpInfo', action = "store_true",\r | |
242 | help = "Display FMP Payload Header information")\r | |
243 | #\r | |
244 | # Add optional arguments for this command\r | |
245 | #\r | |
246 | parser.add_argument ("--capflag", dest = 'CapsuleFlag', action='append', default = [],\r | |
2779c222 KM |
247 | choices=['PersistAcrossReset', 'InitiateReset'],\r |
248 | help = "Capsule flag can be PersistAcrossReset or InitiateReset or not set")\r | |
8b63877a KM |
249 | parser.add_argument ("--capoemflag", dest = 'CapsuleOemFlag', type = ValidateUnsignedInteger, default = 0x0000,\r |
250 | help = "Capsule OEM Flag is an integer between 0x0000 and 0xffff.")\r | |
251 | \r | |
252 | parser.add_argument ("--guid", dest = 'Guid', type = ValidateRegistryFormatGuid,\r | |
253 | help = "The FMP/ESRT GUID in registry format. Required for encode operations.")\r | |
254 | parser.add_argument ("--hardware-instance", dest = 'HardwareInstance', type = ValidateUnsignedInteger, default = 0x0000000000000000,\r | |
255 | help = "The 64-bit hardware instance. The default is 0x0000000000000000")\r | |
256 | \r | |
257 | \r | |
258 | parser.add_argument ("--monotonic-count", dest = 'MonotonicCount', type = ValidateUnsignedInteger, default = 0x0000000000000000,\r | |
259 | help = "64-bit monotonic count value in header. Default is 0x0000000000000000.")\r | |
260 | \r | |
261 | parser.add_argument ("--fw-version", dest = 'FwVersion', type = ValidateUnsignedInteger,\r | |
ff307fba | 262 | help = "The 32-bit version of the binary payload (e.g. 0x11223344 or 5678). Required for encode operations that sign a payload.")\r |
8b63877a | 263 | parser.add_argument ("--lsv", dest = 'LowestSupportedVersion', type = ValidateUnsignedInteger,\r |
ff307fba | 264 | 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 |
8b63877a KM |
265 | \r |
266 | parser.add_argument ("--pfx-file", dest='SignToolPfxFile', type=argparse.FileType('rb'),\r | |
267 | help="signtool PFX certificate filename.")\r | |
268 | \r | |
269 | parser.add_argument ("--signer-private-cert", dest='OpenSslSignerPrivateCertFile', type=argparse.FileType('rb'),\r | |
270 | help="OpenSSL signer private certificate filename.")\r | |
271 | parser.add_argument ("--other-public-cert", dest='OpenSslOtherPublicCertFile', type=argparse.FileType('rb'),\r | |
272 | help="OpenSSL other public certificate filename.")\r | |
273 | parser.add_argument ("--trusted-public-cert", dest='OpenSslTrustedPublicCertFile', type=argparse.FileType('rb'),\r | |
274 | help="OpenSSL trusted public certificate filename.")\r | |
275 | \r | |
276 | parser.add_argument ("--signing-tool-path", dest = 'SigningToolPath',\r | |
277 | help = "Path to signtool or OpenSSL tool. Optional if path to tools are already in PATH.")\r | |
278 | \r | |
279 | #\r | |
280 | # Add optional arguments common to all operations\r | |
281 | #\r | |
282 | parser.add_argument ('--version', action='version', version='%(prog)s ' + __version__)\r | |
283 | parser.add_argument ("-v", "--verbose", dest = 'Verbose', action = "store_true",\r | |
284 | help = "Turn on verbose output with informational messages printed, including capsule headers and warning messages.")\r | |
285 | parser.add_argument ("-q", "--quiet", dest = 'Quiet', action = "store_true",\r | |
286 | help = "Disable all messages except fatal errors.")\r | |
287 | parser.add_argument ("--debug", dest = 'Debug', type = int, metavar = '[0-9]', choices = range (0, 10), default = 0,\r | |
288 | help = "Set debug level")\r | |
289 | \r | |
290 | #\r | |
291 | # Parse command line arguments\r | |
292 | #\r | |
293 | args = parser.parse_args()\r | |
294 | \r | |
295 | #\r | |
296 | # Perform additional argument verification\r | |
297 | #\r | |
298 | if args.Encode:\r | |
299 | if args.Guid is None:\r | |
300 | parser.error ('the following option is required: --guid')\r | |
301 | if 'PersistAcrossReset' not in args.CapsuleFlag:\r | |
8b63877a KM |
302 | if 'InitiateReset' in args.CapsuleFlag:\r |
303 | parser.error ('--capflag InitiateReset also requires --capflag PersistAcrossReset')\r | |
6ed4651c KM |
304 | if args.CapsuleOemFlag > 0xFFFF:\r |
305 | parser.error ('--capoemflag must be an integer between 0x0000 and 0xffff')\r | |
306 | if args.HardwareInstance > 0xFFFFFFFFFFFFFFFF:\r | |
307 | parser.error ('--hardware-instance must be an integer in range 0x0..0xffffffffffffffff')\r | |
308 | if args.MonotonicCount > 0xFFFFFFFFFFFFFFFF:\r | |
309 | parser.error ('--monotonic-count must be an integer in range 0x0..0xffffffffffffffff')\r | |
8b63877a KM |
310 | \r |
311 | UseSignTool = args.SignToolPfxFile is not None\r | |
312 | UseOpenSsl = (args.OpenSslSignerPrivateCertFile is not None and\r | |
313 | args.OpenSslOtherPublicCertFile is not None and\r | |
314 | args.OpenSslTrustedPublicCertFile is not None)\r | |
315 | AnyOpenSsl = (args.OpenSslSignerPrivateCertFile is not None or\r | |
316 | args.OpenSslOtherPublicCertFile is not None or\r | |
317 | args.OpenSslTrustedPublicCertFile is not None)\r | |
318 | if args.Encode or args.Decode:\r | |
319 | if args.OutputFile is None:\r | |
320 | parser.error ('the following option is required for all encode and decode operations: --output')\r | |
321 | \r | |
322 | if UseSignTool and AnyOpenSsl:\r | |
323 | parser.error ('Providing both signtool and OpenSSL options is not supported')\r | |
324 | if not UseSignTool and not UseOpenSsl and AnyOpenSsl:\r | |
325 | parser.error ('all the following options are required for OpenSSL: --signer-private-cert, --other-public-cert, --trusted-public-cert')\r | |
326 | if UseSignTool and platform.system() != 'Windows':\r | |
327 | parser.error ('Use of signtool is not supported on this operating system.')\r | |
328 | if args.Encode and (UseSignTool or UseOpenSsl):\r | |
329 | if args.FwVersion is None or args.LowestSupportedVersion is None:\r | |
330 | parser.error ('the following options are required: --fw-version, --lsv')\r | |
6ed4651c KM |
331 | if args.FwVersion > 0xFFFFFFFF:\r |
332 | parser.error ('--fw-version must be an integer in range 0x0..0xffffffff')\r | |
333 | if args.LowestSupportedVersion > 0xFFFFFFFF:\r | |
334 | parser.error ('--lsv must be an integer in range 0x0..0xffffffff')\r | |
8b63877a KM |
335 | \r |
336 | if UseSignTool:\r | |
337 | args.SignToolPfxFile.close()\r | |
338 | args.SignToolPfxFile = args.SignToolPfxFile.name\r | |
339 | if UseOpenSsl:\r | |
340 | args.OpenSslSignerPrivateCertFile.close()\r | |
341 | args.OpenSslOtherPublicCertFile.close()\r | |
342 | args.OpenSslTrustedPublicCertFile.close()\r | |
343 | args.OpenSslSignerPrivateCertFile = args.OpenSslSignerPrivateCertFile.name\r | |
344 | args.OpenSslOtherPublicCertFile = args.OpenSslOtherPublicCertFile.name\r | |
345 | args.OpenSslTrustedPublicCertFile = args.OpenSslTrustedPublicCertFile.name\r | |
346 | \r | |
f33d5d68 KM |
347 | if args.DumpInfo:\r |
348 | if args.OutputFile is not None:\r | |
349 | parser.error ('the following option is not supported for dumpinfo operations: --output')\r | |
350 | \r | |
8b63877a KM |
351 | #\r |
352 | # Read binary input file\r | |
353 | #\r | |
354 | try:\r | |
355 | if args.Verbose:\r | |
356 | print ('Read binary input file {File}'.format (File = args.InputFile.name))\r | |
357 | Buffer = args.InputFile.read ()\r | |
358 | args.InputFile.close ()\r | |
359 | except:\r | |
360 | print ('GenerateCapsule: error: can not read binary input file {File}'.format (File = args.InputFile.name))\r | |
361 | sys.exit (1)\r | |
362 | \r | |
363 | #\r | |
364 | # Create objects\r | |
365 | #\r | |
366 | UefiCapsuleHeader = UefiCapsuleHeaderClass ()\r | |
367 | FmpCapsuleHeader = FmpCapsuleHeaderClass ()\r | |
368 | FmpAuthHeader = FmpAuthHeaderClass ()\r | |
369 | FmpPayloadHeader = FmpPayloadHeaderClass ()\r | |
370 | \r | |
371 | if args.Encode:\r | |
372 | Result = Buffer\r | |
373 | if UseSignTool or UseOpenSsl:\r | |
374 | try:\r | |
375 | FmpPayloadHeader.FwVersion = args.FwVersion\r | |
376 | FmpPayloadHeader.LowestSupportedVersion = args.LowestSupportedVersion\r | |
377 | FmpPayloadHeader.Payload = Result\r | |
378 | Result = FmpPayloadHeader.Encode ()\r | |
379 | if args.Verbose:\r | |
380 | FmpPayloadHeader.DumpInfo ()\r | |
381 | except:\r | |
382 | print ('GenerateCapsule: error: can not encode FMP Payload Header')\r | |
383 | sys.exit (1)\r | |
384 | \r | |
385 | #\r | |
386 | # Sign image with 64-bit MonotonicCount appended to end of image\r | |
387 | #\r | |
388 | try:\r | |
389 | if UseSignTool:\r | |
390 | CertData = SignPayloadSignTool (\r | |
391 | Result + struct.pack ('<Q', args.MonotonicCount),\r | |
392 | args.SigningToolPath,\r | |
393 | args.SignToolPfxFile\r | |
394 | )\r | |
395 | else:\r | |
396 | CertData = SignPayloadOpenSsl (\r | |
397 | Result + struct.pack ('<Q', args.MonotonicCount),\r | |
398 | args.SigningToolPath,\r | |
399 | args.OpenSslSignerPrivateCertFile,\r | |
400 | args.OpenSslOtherPublicCertFile,\r | |
401 | args.OpenSslTrustedPublicCertFile\r | |
402 | )\r | |
403 | except:\r | |
404 | print ('GenerateCapsule: error: can not sign payload')\r | |
8b63877a KM |
405 | sys.exit (1)\r |
406 | \r | |
407 | try:\r | |
408 | FmpAuthHeader.MonotonicCount = args.MonotonicCount\r | |
409 | FmpAuthHeader.CertData = CertData\r | |
410 | FmpAuthHeader.Payload = Result\r | |
411 | Result = FmpAuthHeader.Encode ()\r | |
412 | if args.Verbose:\r | |
413 | FmpAuthHeader.DumpInfo ()\r | |
414 | except:\r | |
415 | print ('GenerateCapsule: error: can not encode FMP Auth Header')\r | |
416 | sys.exit (1)\r | |
417 | \r | |
418 | try:\r | |
419 | FmpCapsuleHeader.AddPayload (args.Guid, Result, HardwareInstance = args.HardwareInstance)\r | |
420 | Result = FmpCapsuleHeader.Encode ()\r | |
421 | if args.Verbose:\r | |
422 | FmpCapsuleHeader.DumpInfo ()\r | |
423 | except:\r | |
424 | print ('GenerateCapsule: error: can not encode FMP Capsule Header')\r | |
425 | sys.exit (1)\r | |
426 | \r | |
427 | try:\r | |
428 | UefiCapsuleHeader.OemFlags = args.CapsuleOemFlag\r | |
429 | UefiCapsuleHeader.PersistAcrossReset = 'PersistAcrossReset' in args.CapsuleFlag\r | |
2779c222 | 430 | UefiCapsuleHeader.PopulateSystemTable = False\r |
8b63877a KM |
431 | UefiCapsuleHeader.InitiateReset = 'InitiateReset' in args.CapsuleFlag\r |
432 | UefiCapsuleHeader.Payload = Result\r | |
433 | Result = UefiCapsuleHeader.Encode ()\r | |
434 | if args.Verbose:\r | |
435 | UefiCapsuleHeader.DumpInfo ()\r | |
436 | except:\r | |
437 | print ('GenerateCapsule: error: can not encode UEFI Capsule Header')\r | |
438 | sys.exit (1)\r | |
439 | \r | |
440 | elif args.Decode:\r | |
441 | try:\r | |
442 | Result = UefiCapsuleHeader.Decode (Buffer)\r | |
443 | FmpCapsuleHeader.Decode (Result)\r | |
444 | Result = FmpCapsuleHeader.GetFmpCapsuleImageHeader (0).Payload\r | |
445 | if args.Verbose:\r | |
446 | print ('========')\r | |
447 | UefiCapsuleHeader.DumpInfo ()\r | |
448 | print ('--------')\r | |
449 | FmpCapsuleHeader.DumpInfo ()\r | |
450 | if UseSignTool or UseOpenSsl:\r | |
451 | Result = FmpAuthHeader.Decode (Result)\r | |
de652b14 KM |
452 | if args.Verbose:\r |
453 | print ('--------')\r | |
454 | FmpAuthHeader.DumpInfo ()\r | |
8b63877a KM |
455 | \r |
456 | #\r | |
457 | # Verify Image with 64-bit MonotonicCount appended to end of image\r | |
458 | #\r | |
459 | try:\r | |
460 | if UseSignTool:\r | |
461 | CertData = VerifyPayloadSignTool (\r | |
462 | FmpAuthHeader.Payload + struct.pack ('<Q', FmpAuthHeader.MonotonicCount),\r | |
463 | FmpAuthHeader.CertData,\r | |
464 | args.SigningToolPath,\r | |
465 | args.SignToolPfxFile\r | |
466 | )\r | |
467 | else:\r | |
468 | CertData = VerifyPayloadOpenSsl (\r | |
469 | FmpAuthHeader.Payload + struct.pack ('<Q', FmpAuthHeader.MonotonicCount),\r | |
470 | FmpAuthHeader.CertData,\r | |
471 | args.SigningToolPath,\r | |
472 | args.OpenSslSignerPrivateCertFile,\r | |
473 | args.OpenSslOtherPublicCertFile,\r | |
474 | args.OpenSslTrustedPublicCertFile\r | |
475 | )\r | |
476 | except ValueError:\r | |
477 | print ('GenerateCapsule: warning: can not verify payload.')\r | |
478 | \r | |
de652b14 KM |
479 | try:\r |
480 | Result = FmpPayloadHeader.Decode (Result)\r | |
481 | if args.Verbose:\r | |
482 | print ('--------')\r | |
483 | FmpPayloadHeader.DumpInfo ()\r | |
484 | print ('========')\r | |
485 | except:\r | |
486 | if args.Verbose:\r | |
487 | print ('--------')\r | |
488 | print ('No FMP_PAYLOAD_HEADER')\r | |
489 | print ('========')\r | |
490 | raise\r | |
8b63877a KM |
491 | else:\r |
492 | if args.Verbose:\r | |
493 | print ('--------')\r | |
494 | print ('No EFI_FIRMWARE_IMAGE_AUTHENTICATION')\r | |
495 | print ('--------')\r | |
496 | print ('No FMP_PAYLOAD_HEADER')\r | |
de652b14 | 497 | print ('========')\r |
8b63877a KM |
498 | except:\r |
499 | print ('GenerateCapsule: error: can not decode capsule')\r | |
8b63877a KM |
500 | sys.exit (1)\r |
501 | \r | |
502 | elif args.DumpInfo:\r | |
503 | try:\r | |
504 | Result = UefiCapsuleHeader.Decode (Buffer)\r | |
505 | FmpCapsuleHeader.Decode (Result)\r | |
506 | Result = FmpCapsuleHeader.GetFmpCapsuleImageHeader (0).Payload\r | |
507 | print ('========')\r | |
508 | UefiCapsuleHeader.DumpInfo ()\r | |
509 | print ('--------')\r | |
510 | FmpCapsuleHeader.DumpInfo ()\r | |
511 | try:\r | |
512 | Result = FmpAuthHeader.Decode (Result)\r | |
8b63877a KM |
513 | print ('--------')\r |
514 | FmpAuthHeader.DumpInfo ()\r | |
de652b14 KM |
515 | try:\r |
516 | Result = FmpPayloadHeader.Decode (Result)\r | |
517 | print ('--------')\r | |
518 | FmpPayloadHeader.DumpInfo ()\r | |
519 | except:\r | |
520 | print ('--------')\r | |
521 | print ('No FMP_PAYLOAD_HEADER')\r | |
8b63877a KM |
522 | except:\r |
523 | print ('--------')\r | |
524 | print ('No EFI_FIRMWARE_IMAGE_AUTHENTICATION')\r | |
525 | print ('--------')\r | |
526 | print ('No FMP_PAYLOAD_HEADER')\r | |
527 | print ('========')\r | |
528 | except:\r | |
529 | print ('GenerateCapsule: error: can not decode capsule')\r | |
530 | sys.exit (1)\r | |
531 | else:\r | |
532 | print('GenerateCapsule: error: invalid options')\r | |
533 | sys.exit (1)\r | |
534 | \r | |
535 | #\r | |
536 | # Write binary output file\r | |
537 | #\r | |
538 | if args.OutputFile is not None:\r | |
539 | try:\r | |
540 | if args.Verbose:\r | |
541 | print ('Write binary output file {File}'.format (File = args.OutputFile.name))\r | |
542 | args.OutputFile.write (Result)\r | |
543 | args.OutputFile.close ()\r | |
544 | except:\r | |
545 | print ('GenerateCapsule: error: can not write binary output file {File}'.format (File = args.OutputFile.name))\r | |
546 | sys.exit (1)\r | |
547 | \r | |
548 | if args.Verbose:\r | |
549 | print('Success')\r |