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