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