]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/Python/Capsule/GenerateCapsule.py
BaseTools/Capsule: Supports multiple payloads and drivers in capsule
[mirror_edk2.git] / BaseTools / Source / Python / Capsule / GenerateCapsule.py
CommitLineData
8b63877a
KM
1## @file\r
2# Generate a capsule.\r
3#\r
104a1aa1 4# This tool generates a UEFI Capsule around an FMP Capsule. The capsule payload\r
d6f079b6
KM
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
104a1aa1 9# system firmware or device firmware for integrated devices. In order to\r
d6f079b6 10# keep the tool as simple as possible, it has the following limitations:\r
d6f079b6
KM
11# * Do not support vendor code bytes in a capsule.\r
12#\r
104a1aa1 13# Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<BR>\r
2e351cbe 14# SPDX-License-Identifier: BSD-2-Clause-Patent\r
8b63877a
KM
15#\r
16\r
17'''\r
18GenerateCapsule\r
19'''\r
20\r
21import sys\r
22import argparse\r
23import uuid\r
24import struct\r
25import subprocess\r
26import os\r
27import tempfile\r
28import shutil\r
29import platform\r
104a1aa1 30import json\r
8b63877a
KM
31from Common.Uefi.Capsule.UefiCapsuleHeader import UefiCapsuleHeaderClass\r
32from Common.Uefi.Capsule.FmpCapsuleHeader import FmpCapsuleHeaderClass\r
33from Common.Uefi.Capsule.FmpAuthHeader import FmpAuthHeaderClass\r
34from Common.Edk2.Capsule.FmpPayloadHeader import FmpPayloadHeaderClass\r
35\r
36#\r
37# Globals for help information\r
38#\r
39__prog__ = 'GenerateCapsule'\r
40__version__ = '0.9'\r
41__copyright__ = 'Copyright (c) 2018, Intel Corporation. All rights reserved.'\r
42__description__ = 'Generate a capsule.\n'\r
43\r
104a1aa1 44def SignPayloadSignTool (Payload, ToolPath, PfxFile, Verbose = False):\r
8b63877a
KM
45 #\r
46 # Create a temporary directory\r
47 #\r
48 TempDirectoryName = tempfile.mkdtemp()\r
49\r
50 #\r
51 # Generate temp file name for the payload contents\r
52 #\r
53 TempFileName = os.path.join (TempDirectoryName, 'Payload.bin')\r
54\r
55 #\r
56 # Create temporary payload file for signing\r
57 #\r
58 try:\r
104a1aa1
JE
59 with open (TempFileName, 'wb') as File:\r
60 File.write (Payload)\r
8b63877a
KM
61 except:\r
62 shutil.rmtree (TempDirectoryName)\r
63 raise ValueError ('GenerateCapsule: error: can not write temporary payload file.')\r
64\r
65 #\r
66 # Build signtool command\r
67 #\r
68 if ToolPath is None:\r
69 ToolPath = ''\r
70 Command = ''\r
71 Command = Command + '"{Path}" '.format (Path = os.path.join (ToolPath, 'signtool.exe'))\r
72 Command = Command + 'sign /fd sha256 /p7ce DetachedSignedData /p7co 1.2.840.113549.1.7.2 '\r
73 Command = Command + '/p7 {TempDir} '.format (TempDir = TempDirectoryName)\r
74 Command = Command + '/f {PfxFile} '.format (PfxFile = PfxFile)\r
75 Command = Command + TempFileName\r
104a1aa1
JE
76 if Verbose:\r
77 print (Command)\r
8b63877a
KM
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
104a1aa1 91 print (Result[1].decode())\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
104a1aa1
JE
98 with open (TempFileName + '.p7', 'rb') as File:\r
99 Signature = File.read ()\r
8b63877a
KM
100 except:\r
101 shutil.rmtree (TempDirectoryName)\r
102 raise ValueError ('GenerateCapsule: error: can not read signature file.')\r
103\r
104 shutil.rmtree (TempDirectoryName)\r
105 return Signature\r
106\r
104a1aa1 107def VerifyPayloadSignTool (Payload, CertData, ToolPath, PfxFile, Verbose = False):\r
8b63877a
KM
108 print ('signtool verify is not supported.')\r
109 raise ValueError ('GenerateCapsule: error: signtool verify is not supported.')\r
110\r
104a1aa1 111def SignPayloadOpenSsl (Payload, ToolPath, SignerPrivateCertFile, OtherPublicCertFile, TrustedPublicCertFile, Verbose = False):\r
8b63877a
KM
112 #\r
113 # Build openssl command\r
114 #\r
115 if ToolPath is None:\r
116 ToolPath = ''\r
117 Command = ''\r
118 Command = Command + '"{Path}" '.format (Path = os.path.join (ToolPath, 'openssl'))\r
119 Command = Command + 'smime -sign -binary -outform DER -md sha256 '\r
120 Command = Command + '-signer "{Private}" -certfile "{Public}"'.format (Private = SignerPrivateCertFile, Public = OtherPublicCertFile)\r
104a1aa1
JE
121 if Verbose:\r
122 print (Command)\r
8b63877a
KM
123\r
124 #\r
125 # Sign the input file using the specified private key and capture signature from STDOUT\r
126 #\r
127 try:\r
128 Process = subprocess.Popen (Command, stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE, shell = True)\r
129 Result = Process.communicate(input = Payload)\r
87bfb9bc 130 Signature = Result[0]\r
8b63877a
KM
131 except:\r
132 raise ValueError ('GenerateCapsule: error: can not run openssl.')\r
133\r
134 if Process.returncode != 0:\r
104a1aa1 135 print (Result[1].decode())\r
8b63877a
KM
136 raise ValueError ('GenerateCapsule: error: openssl failed.')\r
137\r
138 return Signature\r
139\r
104a1aa1 140def VerifyPayloadOpenSsl (Payload, CertData, ToolPath, SignerPrivateCertFile, OtherPublicCertFile, TrustedPublicCertFile, Verbose = False):\r
8b63877a
KM
141 #\r
142 # Create a temporary directory\r
143 #\r
144 TempDirectoryName = tempfile.mkdtemp()\r
145\r
146 #\r
147 # Generate temp file name for the payload contents\r
148 #\r
149 TempFileName = os.path.join (TempDirectoryName, 'Payload.bin')\r
150\r
151 #\r
152 # Create temporary payload file for verification\r
153 #\r
154 try:\r
104a1aa1
JE
155 with open (TempFileName, 'wb') as File:\r
156 File.write (Payload)\r
8b63877a
KM
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
104a1aa1
JE
170 if Verbose:\r
171 print (Command)\r
8b63877a
KM
172\r
173 #\r
174 # Verify signature\r
175 #\r
176 try:\r
177 Process = subprocess.Popen (Command, stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE, shell = True)\r
178 Result = Process.communicate(input = CertData)\r
179 except:\r
180 shutil.rmtree (TempDirectoryName)\r
181 raise ValueError ('GenerateCapsule: error: can not run openssl.')\r
182\r
183 if Process.returncode != 0:\r
184 shutil.rmtree (TempDirectoryName)\r
104a1aa1 185 print (Result[1].decode())\r
8b63877a
KM
186 raise ValueError ('GenerateCapsule: error: openssl failed.')\r
187\r
188 shutil.rmtree (TempDirectoryName)\r
189 return Payload\r
190\r
191if __name__ == '__main__':\r
192 def convert_arg_line_to_args(arg_line):\r
193 for arg in arg_line.split():\r
194 if not arg.strip():\r
195 continue\r
196 yield arg\r
197\r
198 def ValidateUnsignedInteger (Argument):\r
199 try:\r
200 Value = int (Argument, 0)\r
201 except:\r
202 Message = '{Argument} is not a valid integer value.'.format (Argument = Argument)\r
203 raise argparse.ArgumentTypeError (Message)\r
204 if Value < 0:\r
205 Message = '{Argument} is a negative value.'.format (Argument = Argument)\r
206 raise argparse.ArgumentTypeError (Message)\r
207 return Value\r
208\r
209 def ValidateRegistryFormatGuid (Argument):\r
210 try:\r
211 Value = uuid.UUID (Argument)\r
212 except:\r
213 Message = '{Argument} is not a valid registry format GUID value.'.format (Argument = Argument)\r
214 raise argparse.ArgumentTypeError (Message)\r
215 return Value\r
216\r
104a1aa1
JE
217 def ConvertJsonValue (Config, FieldName, Convert, Required = True, Default = None, Open = False):\r
218 if FieldName not in Config:\r
219 if Required:\r
220 print ('GenerateCapsule: error: Payload descriptor invalid syntax. Could not find {Key} in payload descriptor.'.format(Key = FieldName))\r
221 sys.exit (1)\r
222 return Default\r
223 try:\r
224 Value = Convert (Config[FieldName])\r
225 except:\r
226 print ('GenerateCapsule: error: {Key} in payload descriptor has invalid syntax.'.format (Key = FieldName))\r
227 sys.exit (1)\r
228 if Open:\r
229 try:\r
230 Value = open (Value, "rb")\r
231 except:\r
232 print ('GenerateCapsule: error: can not open file {File}'.format (File = FieldName))\r
233 sys.exit (1)\r
234 return Value\r
235\r
236 def DecodeJsonFileParse (Json):\r
237 if 'Payloads' not in Json:\r
238 print ('GenerateCapsule: error "Payloads" section not found in JSON file {File}'.format (File = args.JsonFile.name))\r
239 sys.exit (1)\r
240 for Config in Json['Payloads']:\r
241 #\r
242 # Parse fields from JSON\r
243 #\r
244 PayloadFile = ConvertJsonValue (Config, 'Payload', os.path.expandvars, Required = False)\r
245 Guid = ConvertJsonValue (Config, 'Guid', ValidateRegistryFormatGuid, Required = False)\r
246 FwVersion = ConvertJsonValue (Config, 'FwVersion', ValidateUnsignedInteger, Required = False)\r
247 LowestSupportedVersion = ConvertJsonValue (Config, 'LowestSupportedVersion', ValidateUnsignedInteger, Required = False)\r
248 HardwareInstance = ConvertJsonValue (Config, 'HardwareInstance', ValidateUnsignedInteger, Required = False, Default = 0)\r
249 MonotonicCount = ConvertJsonValue (Config, 'MonotonicCount', ValidateUnsignedInteger, Required = False, Default = 0)\r
250 SignToolPfxFile = ConvertJsonValue (Config, 'SignToolPfxFile', os.path.expandvars, Required = False, Default = None, Open = True)\r
251 OpenSslSignerPrivateCertFile = ConvertJsonValue (Config, 'OpenSslSignerPrivateCertFile', os.path.expandvars, Required = False, Default = None, Open = True)\r
252 OpenSslOtherPublicCertFile = ConvertJsonValue (Config, 'OpenSslOtherPublicCertFile', os.path.expandvars, Required = False, Default = None, Open = True)\r
253 OpenSslTrustedPublicCertFile = ConvertJsonValue (Config, 'OpenSslTrustedPublicCertFile', os.path.expandvars, Required = False, Default = None, Open = True)\r
254 SigningToolPath = ConvertJsonValue (Config, 'SigningToolPath', os.path.expandvars, Required = False, Default = None)\r
255 UpdateImageIndex = ConvertJsonValue (Config, 'UpdateImageIndex', ValidateUnsignedInteger, Required = False, Default = 1)\r
256\r
257 PayloadDescriptorList.append (PayloadDescriptor (\r
258 PayloadFile,\r
259 Guid,\r
260 FwVersion,\r
261 LowestSupportedVersion,\r
262 MonotonicCount,\r
263 HardwareInstance,\r
264 UpdateImageIndex,\r
265 SignToolPfxFile,\r
266 OpenSslSignerPrivateCertFile,\r
267 OpenSslOtherPublicCertFile,\r
268 OpenSslTrustedPublicCertFile,\r
269 SigningToolPath\r
270 ))\r
271\r
272 def EncodeJsonFileParse (Json):\r
273 if 'EmbeddedDrivers' not in Json:\r
274 print ('GenerateCapsule: warning "EmbeddedDrivers" section not found in JSON file {File}'.format (File = args.JsonFile.name))\r
275 else:\r
276 for Config in Json['EmbeddedDrivers']:\r
277 EmbeddedDriverFile = ConvertJsonValue(Config, 'Driver', os.path.expandvars, Open = True)\r
278 #\r
279 #Read EmbeddedDriver file\r
280 #\r
281 try:\r
282 if args.Verbose:\r
283 print ('Read EmbeddedDriver file {File}'.format (File = EmbeddedDriverFile.name))\r
284 Driver = EmbeddedDriverFile.read()\r
285 except:\r
286 print ('GenerateCapsule: error: can not read EmbeddedDriver file {File}'.format (File = EmbeddedDriverFile.name))\r
287 sys.exit (1)\r
288 EmbeddedDriverDescriptorList.append (Driver)\r
289\r
290 if 'Payloads' not in Json:\r
291 print ('GenerateCapsule: error: "Payloads" section not found in JSON file {File}'.format (File = args.JsonFile.name))\r
292 sys.exit (1)\r
293 for Config in Json['Payloads']:\r
294 #\r
295 # Parse fields from JSON\r
296 #\r
297 PayloadFile = ConvertJsonValue (Config, 'Payload', os.path.expandvars, Open = True)\r
298 Guid = ConvertJsonValue (Config, 'Guid', ValidateRegistryFormatGuid)\r
299 FwVersion = ConvertJsonValue (Config, 'FwVersion', ValidateUnsignedInteger)\r
300 LowestSupportedVersion = ConvertJsonValue (Config, 'LowestSupportedVersion', ValidateUnsignedInteger)\r
301 HardwareInstance = ConvertJsonValue (Config, 'HardwareInstance', ValidateUnsignedInteger, Required = False, Default = 0)\r
302 UpdateImageIndex = ConvertJsonValue (Config, 'UpdateImageIndex', ValidateUnsignedInteger, Required = False, Default = 1)\r
303 MonotonicCount = ConvertJsonValue (Config, 'MonotonicCount', ValidateUnsignedInteger, Required = False, Default = 0)\r
304 SignToolPfxFile = ConvertJsonValue (Config, 'SignToolPfxFile', os.path.expandvars, Required = False, Default = None, Open = True)\r
305 OpenSslSignerPrivateCertFile = ConvertJsonValue (Config, 'OpenSslSignerPrivateCertFile', os.path.expandvars, Required = False, Default = None, Open = True)\r
306 OpenSslOtherPublicCertFile = ConvertJsonValue (Config, 'OpenSslOtherPublicCertFile', os.path.expandvars, Required = False, Default = None, Open = True)\r
307 OpenSslTrustedPublicCertFile = ConvertJsonValue (Config, 'OpenSslTrustedPublicCertFile', os.path.expandvars, Required = False, Default = None, Open = True)\r
308 SigningToolPath = ConvertJsonValue (Config, 'SigningToolPath', os.path.expandvars, Required = False, Default = None)\r
309\r
310 #\r
311 # Read binary input file\r
312 #\r
313 try:\r
314 if args.Verbose:\r
315 print ('Read binary input file {File}'.format (File = PayloadFile.name))\r
316 Payload = PayloadFile.read()\r
317 PayloadFile.close ()\r
318 except:\r
319 print ('GenerateCapsule: error: can not read binary input file {File}'.format (File = PayloadFile.name))\r
320 sys.exit (1)\r
321 PayloadDescriptorList.append (PayloadDescriptor (\r
322 Payload,\r
323 Guid,\r
324 FwVersion,\r
325 LowestSupportedVersion,\r
326 MonotonicCount,\r
327 HardwareInstance,\r
328 UpdateImageIndex,\r
329 SignToolPfxFile,\r
330 OpenSslSignerPrivateCertFile,\r
331 OpenSslOtherPublicCertFile,\r
332 OpenSslTrustedPublicCertFile,\r
333 SigningToolPath\r
334 ))\r
335\r
336 def GenerateOutputJson (PayloadJsonDescriptorList):\r
337 PayloadJson = {\r
338 "Payloads" : [\r
339 {\r
340 "Guid": str(PayloadDescriptor.Guid).upper(),\r
341 "FwVersion": str(PayloadDescriptor.FwVersion),\r
342 "LowestSupportedVersion": str(PayloadDescriptor.LowestSupportedVersion),\r
343 "MonotonicCount": str(PayloadDescriptor.MonotonicCount),\r
344 "Payload": PayloadDescriptor.Payload,\r
345 "HardwareInstance": str(PayloadDescriptor.HardwareInstance),\r
346 "UpdateImageIndex": str(PayloadDescriptor.UpdateImageIndex),\r
347 "SignToolPfxFile": str(PayloadDescriptor.SignToolPfxFile),\r
348 "OpenSslSignerPrivateCertFile": str(PayloadDescriptor.OpenSslSignerPrivateCertFile),\r
349 "OpenSslOtherPublicCertFile": str(PayloadDescriptor.OpenSslOtherPublicCertFile),\r
350 "OpenSslTrustedPublicCertFile": str(PayloadDescriptor.OpenSslTrustedPublicCertFile),\r
351 "SigningToolPath": str(PayloadDescriptor.SigningToolPath)\r
352 }for PayloadDescriptor in PayloadJsonDescriptorList\r
353 ]\r
354 }\r
355 OutputJsonFile = args.OutputFile.name + '.json'\r
356 if 'Payloads' in PayloadJson:\r
357 PayloadSection = PayloadJson ['Payloads']\r
358 Index = 0\r
359 for PayloadField in PayloadSection:\r
360 if PayloadJsonDescriptorList[Index].SignToolPfxFile is None:\r
361 del PayloadField ['SignToolPfxFile']\r
362 if PayloadJsonDescriptorList[Index].OpenSslSignerPrivateCertFile is None:\r
363 del PayloadField ['OpenSslSignerPrivateCertFile']\r
364 if PayloadJsonDescriptorList[Index].OpenSslOtherPublicCertFile is None:\r
365 del PayloadField ['OpenSslOtherPublicCertFile']\r
366 if PayloadJsonDescriptorList[Index].OpenSslTrustedPublicCertFile is None:\r
367 del PayloadField ['OpenSslTrustedPublicCertFile']\r
368 if PayloadJsonDescriptorList[Index].SigningToolPath is None:\r
369 del PayloadField ['SigningToolPath']\r
370 Index = Index + 1\r
371 Result = json.dumps (PayloadJson, indent=4, sort_keys=True, separators=(',', ': '))\r
372 with open (OutputJsonFile, 'w') as OutputFile:\r
373 OutputFile.write (Result)\r
374\r
375 def CheckArgumentConflict (args):\r
376 if args.Encode:\r
377 if args.InputFile:\r
378 print ('GenerateCapsule: error: Argument InputFile conflicts with Argument -j')\r
379 sys.exit (1)\r
380 if args.EmbeddedDriver:\r
381 print ('GenerateCapsule: error: Argument --embedded-driver conflicts with Argument -j')\r
382 sys.exit (1)\r
383 if args.Guid:\r
384 print ('GenerateCapsule: error: Argument --guid conflicts with Argument -j')\r
385 sys.exit (1)\r
386 if args.FwVersion:\r
387 print ('GenerateCapsule: error: Argument --fw-version conflicts with Argument -j')\r
388 sys.exit (1)\r
389 if args.LowestSupportedVersion:\r
390 print ('GenerateCapsule: error: Argument --lsv conflicts with Argument -j')\r
391 sys.exit (1)\r
392 if args.MonotonicCount:\r
393 print ('GenerateCapsule: error: Argument --monotonic-count conflicts with Argument -j')\r
394 sys.exit (1)\r
395 if args.HardwareInstance:\r
396 print ('GenerateCapsule: error: Argument --hardware-instance conflicts with Argument -j')\r
397 sys.exit (1)\r
398 if args.SignToolPfxFile:\r
399 print ('GenerateCapsule: error: Argument --pfx-file conflicts with Argument -j')\r
400 sys.exit (1)\r
401 if args.OpenSslSignerPrivateCertFile:\r
402 print ('GenerateCapsule: error: Argument --signer-private-cert conflicts with Argument -j')\r
403 sys.exit (1)\r
404 if args.OpenSslOtherPublicCertFile:\r
405 print ('GenerateCapsule: error: Argument --other-public-cert conflicts with Argument -j')\r
406 sys.exit (1)\r
407 if args.OpenSslTrustedPublicCertFile:\r
408 print ('GenerateCapsule: error: Argument --trusted-public-cert conflicts with Argument -j')\r
409 sys.exit (1)\r
410 if args.SigningToolPath:\r
411 print ('GenerateCapsule: error: Argument --signing-tool-path conflicts with Argument -j')\r
412 sys.exit (1)\r
413\r
414 class PayloadDescriptor (object):\r
415 def __init__(self,\r
416 Payload,\r
417 Guid,\r
418 FwVersion,\r
419 LowestSupportedVersion,\r
420 MonotonicCount = 0,\r
421 HardwareInstance = 0,\r
422 UpdateImageIndex = 1,\r
423 SignToolPfxFile = None,\r
424 OpenSslSignerPrivateCertFile = None,\r
425 OpenSslOtherPublicCertFile = None,\r
426 OpenSslTrustedPublicCertFile = None,\r
427 SigningToolPath = None\r
428 ):\r
429 self.Payload = Payload\r
430 self.Guid = Guid\r
431 self.FwVersion = FwVersion\r
432 self.LowestSupportedVersion = LowestSupportedVersion\r
433 self.MonotonicCount = MonotonicCount\r
434 self.HardwareInstance = HardwareInstance\r
435 self.UpdateImageIndex = UpdateImageIndex\r
436 self.SignToolPfxFile = SignToolPfxFile\r
437 self.OpenSslSignerPrivateCertFile = OpenSslSignerPrivateCertFile\r
438 self.OpenSslOtherPublicCertFile = OpenSslOtherPublicCertFile\r
439 self.OpenSslTrustedPublicCertFile = OpenSslTrustedPublicCertFile\r
440 self.SigningToolPath = SigningToolPath\r
441\r
442 self.UseSignTool = self.SignToolPfxFile is not None\r
443 self.UseOpenSsl = (self.OpenSslSignerPrivateCertFile is not None and\r
444 self.OpenSslOtherPublicCertFile is not None and\r
445 self.OpenSslTrustedPublicCertFile is not None)\r
446 self.AnyOpenSsl = (self.OpenSslSignerPrivateCertFile is not None or\r
447 self.OpenSslOtherPublicCertFile is not None or\r
448 self.OpenSslTrustedPublicCertFile is not None)\r
449\r
450 def Validate(self, args):\r
451 if self.UseSignTool and self.AnyOpenSsl:\r
452 raise argparse.ArgumentTypeError ('Providing both signtool and OpenSSL options is not supported')\r
453 if not self.UseSignTool and not self.UseOpenSsl and self.AnyOpenSsl:\r
454 if args.JsonFile:\r
455 raise argparse.ArgumentTypeError ('the following JSON fields are required for OpenSSL: OpenSslSignerPrivateCertFile, OpenSslOtherPublicCertFile, OpenSslTrustedPublicCertFile')\r
456 else:\r
457 raise argparse.ArgumentTypeError ('the following options are required for OpenSSL: --signer-private-cert, --other-public-cert, --trusted-public-cert')\r
458 if self.UseSignTool and platform.system() != 'Windows':\r
459 raise argparse.ArgumentTypeError ('Use of signtool is not supported on this operating system.')\r
460 if args.Encode:\r
461 if self.FwVersion is None or self.LowestSupportedVersion is None:\r
462 if args.JsonFile:\r
463 raise argparse.ArgumentTypeError ('the following JSON fields are required: FwVersion, LowestSupportedVersion')\r
464 else:\r
465 raise argparse.ArgumentTypeError ('the following options are required: --fw-version, --lsv')\r
466 if self.FwVersion > 0xFFFFFFFF:\r
467 if args.JsonFile:\r
468 raise argparse.ArgumentTypeError ('JSON field FwVersion must be an integer in range 0x0..0xffffffff')\r
469 else:\r
470 raise argparse.ArgumentTypeError ('--fw-version must be an integer in range 0x0..0xffffffff')\r
471 if self.LowestSupportedVersion > 0xFFFFFFFF:\r
472 if args.JsonFile:\r
473 raise argparse.ArgumentTypeError ('JSON field LowestSupportedVersion must be an integer in range 0x0..0xffffffff')\r
474 else:\r
475 raise argparse.ArgumentTypeError ('--lsv must be an integer in range 0x0..0xffffffff')\r
476\r
477 if args.Encode:\r
478 if self.Guid is None:\r
479 if args.JsonFile:\r
480 raise argparse.ArgumentTypeError ('the following JSON field is required: Guid')\r
481 else:\r
482 raise argparse.ArgumentTypeError ('the following option is required: --guid')\r
483 if self.HardwareInstance > 0xFFFFFFFFFFFFFFFF:\r
484 if args.JsonFile:\r
485 raise argparse.ArgumentTypeError ('JSON field HardwareInstance must be an integer in range 0x0..0xffffffffffffffff')\r
486 else:\r
487 raise argparse.ArgumentTypeError ('--hardware-instance must be an integer in range 0x0..0xffffffffffffffff')\r
488 if self.MonotonicCount > 0xFFFFFFFFFFFFFFFF:\r
489 if args.JsonFile:\r
490 raise argparse.ArgumentTypeError ('JSON field MonotonicCount must be an integer in range 0x0..0xffffffffffffffff')\r
491 else:\r
492 raise argparse.ArgumentTypeError ('--monotonic-count must be an integer in range 0x0..0xffffffffffffffff')\r
493 if self.UpdateImageIndex >0xFF:\r
494 if args.JsonFile:\r
495 raise argparse.ArgumentTypeError ('JSON field UpdateImageIndex must be an integer in range 0x0..0xff')\r
496 else:\r
497 raise argparse.ArgumentTypeError ('--update-image-index must be an integer in range 0x0..0xff')\r
498\r
499 if self.UseSignTool:\r
500 self.SignToolPfxFile.close()\r
501 self.SignToolPfxFile = self.SignToolPfxFile.name\r
502 if self.UseOpenSsl:\r
503 self.OpenSslSignerPrivateCertFile.close()\r
504 self.OpenSslOtherPublicCertFile.close()\r
505 self.OpenSslTrustedPublicCertFile.close()\r
506 self.OpenSslSignerPrivateCertFile = self.OpenSslSignerPrivateCertFile.name\r
507 self.OpenSslOtherPublicCertFile = self.OpenSslOtherPublicCertFile.name\r
508 self.OpenSslTrustedPublicCertFile = self.OpenSslTrustedPublicCertFile.name\r
509\r
510 #\r
511 # Perform additional argument verification\r
512 #\r
513 if args.Encode:\r
514 if 'PersistAcrossReset' not in args.CapsuleFlag:\r
515 if 'InitiateReset' in args.CapsuleFlag:\r
516 raise argparse.ArgumentTypeError ('--capflag InitiateReset also requires --capflag PersistAcrossReset')\r
517 if args.CapsuleOemFlag > 0xFFFF:\r
518 raise argparse.ArgumentTypeError ('--capoemflag must be an integer between 0x0000 and 0xffff')\r
519\r
520 return True\r
521\r
522\r
523 def Encode (PayloadDescriptorList, EmbeddedDriverDescriptorList, Buffer):\r
524 if args.JsonFile:\r
525 CheckArgumentConflict(args)\r
526 try:\r
527 Json = json.loads (args.JsonFile.read ())\r
528 except:\r
529 print ('GenerateCapsule: error: {JSONFile} loads failure. '.format (JSONFile = args.JsonFile))\r
530 sys.exit (1)\r
531 EncodeJsonFileParse(Json)\r
532 else:\r
533 for Driver in args.EmbeddedDriver:\r
534 EmbeddedDriverDescriptorList.append (Driver.read())\r
535 PayloadDescriptorList.append (PayloadDescriptor (\r
536 Buffer,\r
537 args.Guid,\r
538 args.FwVersion,\r
539 args.LowestSupportedVersion,\r
540 args.MonotonicCount,\r
541 args.HardwareInstance,\r
542 args.UpdateImageIndex,\r
543 args.SignToolPfxFile,\r
544 args.OpenSslSignerPrivateCertFile,\r
545 args.OpenSslOtherPublicCertFile,\r
546 args.OpenSslTrustedPublicCertFile,\r
547 args.SigningToolPath\r
548 ))\r
549 for SinglePayloadDescriptor in PayloadDescriptorList:\r
550 try:\r
551 SinglePayloadDescriptor.Validate (args)\r
552 except Exception as Msg:\r
553 print ('GenerateCapsule: error:' + str(Msg))\r
554 sys.exit (1)\r
555 for SinglePayloadDescriptor in PayloadDescriptorList:\r
556 Result = SinglePayloadDescriptor.Payload\r
557 try:\r
558 FmpPayloadHeader.FwVersion = SinglePayloadDescriptor.FwVersion\r
559 FmpPayloadHeader.LowestSupportedVersion = SinglePayloadDescriptor.LowestSupportedVersion\r
560 FmpPayloadHeader.Payload = SinglePayloadDescriptor.Payload\r
561 Result = FmpPayloadHeader.Encode ()\r
562 if args.Verbose:\r
563 FmpPayloadHeader.DumpInfo ()\r
564 except:\r
565 print ('GenerateCapsule: error: can not encode FMP Payload Header')\r
566 sys.exit (1)\r
567 if SinglePayloadDescriptor.UseOpenSsl or SinglePayloadDescriptor.UseSignTool:\r
568 #\r
569 # Sign image with 64-bit MonotonicCount appended to end of image\r
570 #\r
571 try:\r
572 if SinglePayloadDescriptor.UseSignTool:\r
573 CertData = SignPayloadSignTool (\r
574 Result + struct.pack ('<Q', SinglePayloadDescriptor.MonotonicCount),\r
575 SinglePayloadDescriptor.SigningToolPath,\r
576 SinglePayloadDescriptor.SignToolPfxFile,\r
577 Verbose = args.Verbose\r
578 )\r
579 else:\r
580 CertData = SignPayloadOpenSsl (\r
581 Result + struct.pack ('<Q', SinglePayloadDescriptor.MonotonicCount),\r
582 SinglePayloadDescriptor.SigningToolPath,\r
583 SinglePayloadDescriptor.OpenSslSignerPrivateCertFile,\r
584 SinglePayloadDescriptor.OpenSslOtherPublicCertFile,\r
585 SinglePayloadDescriptor.OpenSslTrustedPublicCertFile,\r
586 Verbose = args.Verbose\r
587 )\r
588 except Exception as Msg:\r
589 print ('GenerateCapsule: error: can not sign payload \n' + str(Msg))\r
590 sys.exit (1)\r
591\r
592 try:\r
593 FmpAuthHeader.MonotonicCount = SinglePayloadDescriptor.MonotonicCount\r
594 FmpAuthHeader.CertData = CertData\r
595 FmpAuthHeader.Payload = Result\r
596 Result = FmpAuthHeader.Encode ()\r
597 if args.Verbose:\r
598 FmpAuthHeader.DumpInfo ()\r
599 except:\r
600 print ('GenerateCapsule: error: can not encode FMP Auth Header')\r
601 sys.exit (1)\r
602 FmpCapsuleHeader.AddPayload (SinglePayloadDescriptor.Guid, Result, HardwareInstance = SinglePayloadDescriptor.HardwareInstance, UpdateImageIndex = SinglePayloadDescriptor.UpdateImageIndex)\r
603 try:\r
604 for EmbeddedDriver in EmbeddedDriverDescriptorList:\r
605 FmpCapsuleHeader.AddEmbeddedDriver(EmbeddedDriver)\r
606\r
607 Result = FmpCapsuleHeader.Encode ()\r
608 if args.Verbose:\r
609 FmpCapsuleHeader.DumpInfo ()\r
610 except:\r
611 print ('GenerateCapsule: error: can not encode FMP Capsule Header')\r
612 sys.exit (1)\r
613\r
614 try:\r
615 UefiCapsuleHeader.OemFlags = args.CapsuleOemFlag\r
616 UefiCapsuleHeader.PersistAcrossReset = 'PersistAcrossReset' in args.CapsuleFlag\r
617 UefiCapsuleHeader.PopulateSystemTable = False\r
618 UefiCapsuleHeader.InitiateReset = 'InitiateReset' in args.CapsuleFlag\r
619 UefiCapsuleHeader.Payload = Result\r
620 Result = UefiCapsuleHeader.Encode ()\r
621 if args.Verbose:\r
622 UefiCapsuleHeader.DumpInfo ()\r
623 except:\r
624 print ('GenerateCapsule: error: can not encode UEFI Capsule Header')\r
625 sys.exit (1)\r
626 try:\r
627 if args.Verbose:\r
628 print ('Write binary output file {File}'.format (File = args.OutputFile.name))\r
629 args.OutputFile.write (Result)\r
630 args.OutputFile.close ()\r
631 except:\r
632 print ('GenerateCapsule: error: can not write binary output file {File}'.format (File = args.OutputFile.name))\r
633 sys.exit (1)\r
634\r
635 def Decode (PayloadDescriptorList, PayloadJsonDescriptorList, Buffer):\r
636 if args.JsonFile:\r
637 CheckArgumentConflict(args)\r
638 #\r
639 # Parse payload descriptors from JSON\r
640 #\r
641 try:\r
642 Json = json.loads (args.JsonFile.read())\r
643 except:\r
644 print ('GenerateCapsule: error: {JSONFile} loads failure. '.format (JSONFile = args.JsonFile))\r
645 sys.exit (1)\r
646 DecodeJsonFileParse (Json)\r
647 else:\r
648 PayloadDescriptorList.append (PayloadDescriptor (\r
649 Buffer,\r
650 args.Guid,\r
651 args.FwVersion,\r
652 args.LowestSupportedVersion,\r
653 args.MonotonicCount,\r
654 args.HardwareInstance,\r
655 args.UpdateImageIndex,\r
656 args.SignToolPfxFile,\r
657 args.OpenSslSignerPrivateCertFile,\r
658 args.OpenSslOtherPublicCertFile,\r
659 args.OpenSslTrustedPublicCertFile,\r
660 args.SigningToolPath\r
661 ))\r
662 #\r
663 # Perform additional verification on payload descriptors\r
664 #\r
665 for SinglePayloadDescriptor in PayloadDescriptorList:\r
666 try:\r
667 SinglePayloadDescriptor.Validate (args)\r
668 except Exception as Msg:\r
669 print ('GenerateCapsule: error:' + str(Msg))\r
670 sys.exit (1)\r
671 try:\r
672 Result = UefiCapsuleHeader.Decode (Buffer)\r
673 if len (Result) > 0:\r
674 Result = FmpCapsuleHeader.Decode (Result)\r
675 if args.JsonFile:\r
676 if FmpCapsuleHeader.PayloadItemCount != len (PayloadDescriptorList):\r
677 CapsulePayloadNum = FmpCapsuleHeader.PayloadItemCount\r
678 JsonPayloadNum = len (PayloadDescriptorList)\r
679 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
680 sys.exit (1)\r
681 for Index in range (0, FmpCapsuleHeader.PayloadItemCount):\r
682 if Index < len (PayloadDescriptorList):\r
683 GUID = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).UpdateImageTypeId\r
684 HardwareInstance = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).UpdateHardwareInstance\r
685 UpdateImageIndex = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).UpdateImageIndex\r
686 if PayloadDescriptorList[Index].Guid != GUID or PayloadDescriptorList[Index].HardwareInstance != HardwareInstance:\r
687 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
688 sys.exit (1)\r
689 PayloadDescriptorList[Index].Payload = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).Payload\r
690 DecodeJsonOutput = args.OutputFile.name + '.Payload.{Index:d}.bin'.format (Index = Index + 1)\r
691 PayloadJsonDescriptorList.append (PayloadDescriptor (\r
692 DecodeJsonOutput,\r
693 GUID,\r
694 None,\r
695 None,\r
696 None,\r
697 HardwareInstance,\r
698 UpdateImageIndex,\r
699 PayloadDescriptorList[Index].SignToolPfxFile,\r
700 PayloadDescriptorList[Index].OpenSslSignerPrivateCertFile,\r
701 PayloadDescriptorList[Index].OpenSslOtherPublicCertFile,\r
702 PayloadDescriptorList[Index].OpenSslTrustedPublicCertFile,\r
703 PayloadDescriptorList[Index].SigningToolPath\r
704 ))\r
705 else:\r
706 PayloadDescriptorList[0].Payload = FmpCapsuleHeader.GetFmpCapsuleImageHeader (0).Payload\r
707 for Index in range (0, FmpCapsuleHeader.PayloadItemCount):\r
708 if Index > 0:\r
709 PayloadDecodeFile = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).Payload\r
710 PayloadDescriptorList.append (PayloadDescriptor (PayloadDecodeFile,\r
711 None,\r
712 None,\r
713 None,\r
714 None,\r
715 None,\r
716 None,\r
717 None,\r
718 None,\r
719 None,\r
720 None,\r
721 None\r
722 ))\r
723 GUID = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).UpdateImageTypeId\r
724 HardwareInstance = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).UpdateHardwareInstance\r
725 UpdateImageIndex = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).UpdateImageIndex\r
726 DecodeJsonOutput = args.OutputFile.name + '.Payload.{Index:d}.bin'.format (Index = Index + 1)\r
727 PayloadJsonDescriptorList.append (PayloadDescriptor (\r
728 DecodeJsonOutput,\r
729 GUID,\r
730 None,\r
731 None,\r
732 None,\r
733 HardwareInstance,\r
734 UpdateImageIndex,\r
735 PayloadDescriptorList[Index].SignToolPfxFile,\r
736 PayloadDescriptorList[Index].OpenSslSignerPrivateCertFile,\r
737 PayloadDescriptorList[Index].OpenSslOtherPublicCertFile,\r
738 PayloadDescriptorList[Index].OpenSslTrustedPublicCertFile,\r
739 PayloadDescriptorList[Index].SigningToolPath\r
740 ))\r
741 JsonIndex = 0\r
742 for SinglePayloadDescriptor in PayloadDescriptorList:\r
743 if args.Verbose:\r
744 print ('========')\r
745 UefiCapsuleHeader.DumpInfo ()\r
746 print ('--------')\r
747 FmpCapsuleHeader.DumpInfo ()\r
748 if FmpAuthHeader.IsSigned(SinglePayloadDescriptor.Payload):\r
749 if not SinglePayloadDescriptor.UseOpenSsl and not SinglePayloadDescriptor.UseSignTool:\r
750 print ('GenerateCapsule: decode warning: can not verify singed payload without cert or pfx file. Index = {Index}'.format (Index = JsonIndex + 1))\r
751 SinglePayloadDescriptor.Payload = FmpAuthHeader.Decode (SinglePayloadDescriptor.Payload)\r
752 PayloadJsonDescriptorList[JsonIndex].MonotonicCount = FmpAuthHeader.MonotonicCount\r
753 if args.Verbose:\r
754 print ('--------')\r
755 FmpAuthHeader.DumpInfo ()\r
756\r
757 #\r
758 # Verify Image with 64-bit MonotonicCount appended to end of image\r
759 #\r
760 try:\r
761 if SinglePayloadDescriptor.UseSignTool:\r
762 CertData = VerifyPayloadSignTool (\r
763 FmpAuthHeader.Payload + struct.pack ('<Q', FmpAuthHeader.MonotonicCount),\r
764 FmpAuthHeader.CertData,\r
765 SinglePayloadDescriptor.SigningToolPath,\r
766 SinglePayloadDescriptor.SignToolPfxFile,\r
767 Verbose = args.Verbose\r
768 )\r
769 else:\r
770 CertData = VerifyPayloadOpenSsl (\r
771 FmpAuthHeader.Payload + struct.pack ('<Q', FmpAuthHeader.MonotonicCount),\r
772 FmpAuthHeader.CertData,\r
773 SinglePayloadDescriptor.SigningToolPath,\r
774 SinglePayloadDescriptor.OpenSslSignerPrivateCertFile,\r
775 SinglePayloadDescriptor.OpenSslOtherPublicCertFile,\r
776 SinglePayloadDescriptor.OpenSslTrustedPublicCertFile,\r
777 Verbose = args.Verbose\r
778 )\r
779 except Exception as Msg:\r
780 print ('GenerateCapsule: warning: payload verification failed Index = {Index} \n'.format (Index = JsonIndex + 1) + str(Msg))\r
781 else:\r
782 if args.Verbose:\r
783 print ('--------')\r
784 print ('No EFI_FIRMWARE_IMAGE_AUTHENTICATION')\r
785 try:\r
786 SinglePayloadDescriptor.Payload = FmpPayloadHeader.Decode (SinglePayloadDescriptor.Payload)\r
787 PayloadJsonDescriptorList[JsonIndex].FwVersion = FmpPayloadHeader.FwVersion\r
788 PayloadJsonDescriptorList[JsonIndex].LowestSupportedVersion = FmpPayloadHeader.LowestSupportedVersion\r
789 JsonIndex = JsonIndex + 1\r
790 if args.Verbose:\r
791 print ('--------')\r
792 FmpPayloadHeader.DumpInfo ()\r
793 print ('========')\r
794 except:\r
795 if args.Verbose:\r
796 print ('--------')\r
797 print ('No FMP_PAYLOAD_HEADER')\r
798 print ('========')\r
799 sys.exit (1)\r
800 #\r
801 # Write embedded driver file(s)\r
802 #\r
803 for Index in range (0, FmpCapsuleHeader.EmbeddedDriverCount):\r
804 EmbeddedDriverBuffer = FmpCapsuleHeader.GetEmbeddedDriver (Index)\r
805 EmbeddedDriverPath = args.OutputFile.name + '.EmbeddedDriver.{Index:d}.efi'.format (Index = Index + 1)\r
806 try:\r
807 if args.Verbose:\r
808 print ('Write embedded driver file {File}'.format (File = EmbeddedDriverPath))\r
809 with open (EmbeddedDriverPath, 'wb') as EmbeddedDriverFile:\r
810 EmbeddedDriverFile.write (EmbeddedDriverBuffer)\r
811 except:\r
812 print ('GenerateCapsule: error: can not write embedded driver file {File}'.format (File = EmbeddedDriverPath))\r
813 sys.exit (1)\r
814\r
815 except:\r
816 print ('GenerateCapsule: error: can not decode capsule')\r
817 sys.exit (1)\r
818 GenerateOutputJson(PayloadJsonDescriptorList)\r
819 PayloadIndex = 0\r
820 for SinglePayloadDescriptor in PayloadDescriptorList:\r
821 if args.OutputFile is None:\r
822 print ('GenerateCapsule: Decode error: OutputFile is needed for decode output')\r
823 sys.exit (1)\r
824 try:\r
825 if args.Verbose:\r
826 print ('Write binary output file {File}'.format (File = args.OutputFile.name))\r
827 PayloadDecodePath = args.OutputFile.name + '.Payload.{Index:d}.bin'.format (Index = PayloadIndex + 1)\r
828 with open (PayloadDecodePath, 'wb') as PayloadDecodeFile:\r
829 PayloadDecodeFile.write (SinglePayloadDescriptor.Payload)\r
830 PayloadIndex = PayloadIndex + 1\r
831 except:\r
832 print ('GenerateCapsule: error: can not write binary output file {File}'.format (File = SinglePayloadDescriptor.OutputFile.name))\r
833 sys.exit (1)\r
834\r
835 def DumpInfo (Buffer, args):\r
836 if args.OutputFile is not None:\r
837 raise argparse.ArgumentTypeError ('the following option is not supported for dumpinfo operations: --output')\r
838 try:\r
839 Result = UefiCapsuleHeader.Decode (Buffer)\r
840 print ('========')\r
841 UefiCapsuleHeader.DumpInfo ()\r
842 if len (Result) > 0:\r
843 FmpCapsuleHeader.Decode (Result)\r
844 print ('--------')\r
845 FmpCapsuleHeader.DumpInfo ()\r
846 for Index in range (0, FmpCapsuleHeader.PayloadItemCount):\r
847 Result = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).Payload\r
848 try:\r
849 Result = FmpAuthHeader.Decode (Result)\r
850 print ('--------')\r
851 FmpAuthHeader.DumpInfo ()\r
852 except:\r
853 print ('--------')\r
854 print ('No EFI_FIRMWARE_IMAGE_AUTHENTICATION')\r
855 try:\r
856 Result = FmpPayloadHeader.Decode (Result)\r
857 print ('--------')\r
858 FmpPayloadHeader.DumpInfo ()\r
859 except:\r
860 print ('--------')\r
861 print ('No FMP_PAYLOAD_HEADER')\r
862 print ('========')\r
863 except:\r
864 print ('GenerateCapsule: error: can not decode capsule')\r
865 sys.exit (1)\r
8b63877a
KM
866 #\r
867 # Create command line argument parser object\r
868 #\r
869 parser = argparse.ArgumentParser (\r
870 prog = __prog__,\r
871 description = __description__ + __copyright__,\r
872 conflict_handler = 'resolve',\r
873 fromfile_prefix_chars = '@'\r
874 )\r
875 parser.convert_arg_line_to_args = convert_arg_line_to_args\r
876\r
877 #\r
878 # Add input and output file arguments\r
879 #\r
104a1aa1 880 parser.add_argument("InputFile", type = argparse.FileType('rb'), nargs='?',\r
8b63877a
KM
881 help = "Input binary payload filename.")\r
882 parser.add_argument("-o", "--output", dest = 'OutputFile', type = argparse.FileType('wb'),\r
883 help = "Output filename.")\r
884 #\r
885 # Add group for -e and -d flags that are mutually exclusive and required\r
886 #\r
887 group = parser.add_mutually_exclusive_group (required = True)\r
888 group.add_argument ("-e", "--encode", dest = 'Encode', action = "store_true",\r
889 help = "Encode file")\r
890 group.add_argument ("-d", "--decode", dest = 'Decode', action = "store_true",\r
891 help = "Decode file")\r
892 group.add_argument ("--dump-info", dest = 'DumpInfo', action = "store_true",\r
893 help = "Display FMP Payload Header information")\r
894 #\r
895 # Add optional arguments for this command\r
896 #\r
104a1aa1
JE
897 parser.add_argument ("-j", "--json-file", dest = 'JsonFile', type=argparse.FileType('r'),\r
898 help = "JSON configuration file for multiple payloads and embedded drivers.")\r
8b63877a 899 parser.add_argument ("--capflag", dest = 'CapsuleFlag', action='append', default = [],\r
2779c222
KM
900 choices=['PersistAcrossReset', 'InitiateReset'],\r
901 help = "Capsule flag can be PersistAcrossReset or InitiateReset or not set")\r
8b63877a
KM
902 parser.add_argument ("--capoemflag", dest = 'CapsuleOemFlag', type = ValidateUnsignedInteger, default = 0x0000,\r
903 help = "Capsule OEM Flag is an integer between 0x0000 and 0xffff.")\r
904\r
905 parser.add_argument ("--guid", dest = 'Guid', type = ValidateRegistryFormatGuid,\r
104a1aa1 906 help = "The FMP/ESRT GUID in registry format. Required for single payload encode operations.")\r
8b63877a
KM
907 parser.add_argument ("--hardware-instance", dest = 'HardwareInstance', type = ValidateUnsignedInteger, default = 0x0000000000000000,\r
908 help = "The 64-bit hardware instance. The default is 0x0000000000000000")\r
909\r
910\r
911 parser.add_argument ("--monotonic-count", dest = 'MonotonicCount', type = ValidateUnsignedInteger, default = 0x0000000000000000,\r
912 help = "64-bit monotonic count value in header. Default is 0x0000000000000000.")\r
913\r
914 parser.add_argument ("--fw-version", dest = 'FwVersion', type = ValidateUnsignedInteger,\r
104a1aa1 915 help = "The 32-bit version of the binary payload (e.g. 0x11223344 or 5678). Required for encode operations.")\r
8b63877a 916 parser.add_argument ("--lsv", dest = 'LowestSupportedVersion', type = ValidateUnsignedInteger,\r
104a1aa1 917 help = "The 32-bit lowest supported version of the binary payload (e.g. 0x11223344 or 5678). Required for encode operations.")\r
8b63877a
KM
918\r
919 parser.add_argument ("--pfx-file", dest='SignToolPfxFile', type=argparse.FileType('rb'),\r
920 help="signtool PFX certificate filename.")\r
921\r
922 parser.add_argument ("--signer-private-cert", dest='OpenSslSignerPrivateCertFile', type=argparse.FileType('rb'),\r
923 help="OpenSSL signer private certificate filename.")\r
924 parser.add_argument ("--other-public-cert", dest='OpenSslOtherPublicCertFile', type=argparse.FileType('rb'),\r
925 help="OpenSSL other public certificate filename.")\r
926 parser.add_argument ("--trusted-public-cert", dest='OpenSslTrustedPublicCertFile', type=argparse.FileType('rb'),\r
927 help="OpenSSL trusted public certificate filename.")\r
928\r
929 parser.add_argument ("--signing-tool-path", dest = 'SigningToolPath',\r
930 help = "Path to signtool or OpenSSL tool. Optional if path to tools are already in PATH.")\r
931\r
104a1aa1
JE
932 parser.add_argument ("--embedded-driver", dest = 'EmbeddedDriver', type = argparse.FileType('rb'), action='append', default = [],\r
933 help = "Path to embedded UEFI driver to add to capsule.")\r
934\r
8b63877a
KM
935 #\r
936 # Add optional arguments common to all operations\r
937 #\r
938 parser.add_argument ('--version', action='version', version='%(prog)s ' + __version__)\r
939 parser.add_argument ("-v", "--verbose", dest = 'Verbose', action = "store_true",\r
940 help = "Turn on verbose output with informational messages printed, including capsule headers and warning messages.")\r
941 parser.add_argument ("-q", "--quiet", dest = 'Quiet', action = "store_true",\r
942 help = "Disable all messages except fatal errors.")\r
943 parser.add_argument ("--debug", dest = 'Debug', type = int, metavar = '[0-9]', choices = range (0, 10), default = 0,\r
944 help = "Set debug level")\r
104a1aa1 945 parser.add_argument ("--update-image-index", dest = 'UpdateImageIndex', type = ValidateUnsignedInteger, default = 0x01, help = "unique number identifying the firmware image within the device ")\r
8b63877a
KM
946\r
947 #\r
948 # Parse command line arguments\r
949 #\r
950 args = parser.parse_args()\r
951\r
8b63877a
KM
952 #\r
953 # Read binary input file\r
954 #\r
104a1aa1
JE
955 Buffer = ''\r
956 if args.InputFile:\r
957 if os.path.getsize (args.InputFile.name) == 0:\r
958 print ('GenerateCapsule: error: InputFile {File} is empty'.format (File = args.InputFile.name))\r
959 sys.exit (1)\r
960 try:\r
961 if args.Verbose:\r
962 print ('Read binary input file {File}'.format (File = args.InputFile.name))\r
963 Buffer = args.InputFile.read ()\r
964 args.InputFile.close ()\r
965 except:\r
966 print ('GenerateCapsule: error: can not read binary input file {File}'.format (File = args.InputFile.name))\r
967 sys.exit (1)\r
8b63877a
KM
968\r
969 #\r
970 # Create objects\r
971 #\r
972 UefiCapsuleHeader = UefiCapsuleHeaderClass ()\r
973 FmpCapsuleHeader = FmpCapsuleHeaderClass ()\r
974 FmpAuthHeader = FmpAuthHeaderClass ()\r
975 FmpPayloadHeader = FmpPayloadHeaderClass ()\r
976\r
104a1aa1
JE
977 EmbeddedDriverDescriptorList = []\r
978 PayloadDescriptorList = []\r
979 PayloadJsonDescriptorList = []\r
8b63877a 980\r
104a1aa1
JE
981 #\r
982 #Encode Operation\r
983 #\r
984 if args.Encode:\r
985 Encode (PayloadDescriptorList, EmbeddedDriverDescriptorList, Buffer)\r
8b63877a 986\r
104a1aa1
JE
987 #\r
988 #Decode Operation\r
989 #\r
990 if args.Decode:\r
991 Decode (PayloadDescriptorList, PayloadJsonDescriptorList, Buffer)\r
8b63877a
KM
992\r
993 #\r
104a1aa1 994 #Dump Info Operation\r
8b63877a 995 #\r
104a1aa1
JE
996 if args.DumpInfo:\r
997 DumpInfo (Buffer, args)\r
8b63877a
KM
998\r
999 if args.Verbose:\r
1000 print('Success')\r