]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/Python/Capsule/GenerateCapsule.py
BaseTools/Capsule: Add capsule dependency support
[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
564 Result = SinglePayloadDescriptor.Payload\r
565 try:\r
566 FmpPayloadHeader.FwVersion = SinglePayloadDescriptor.FwVersion\r
567 FmpPayloadHeader.LowestSupportedVersion = SinglePayloadDescriptor.LowestSupportedVersion\r
568 FmpPayloadHeader.Payload = SinglePayloadDescriptor.Payload\r
569 Result = FmpPayloadHeader.Encode ()\r
570 if args.Verbose:\r
571 FmpPayloadHeader.DumpInfo ()\r
572 except:\r
573 print ('GenerateCapsule: error: can not encode FMP Payload Header')\r
574 sys.exit (1)\r
f6f66e0c
LA
575 if SinglePayloadDescriptor.UseDependency:\r
576 CapsuleDependency.Payload = Result\r
577 CapsuleDependency.DepexExp = SinglePayloadDescriptor.DepexExp\r
578 Result = CapsuleDependency.Encode ()\r
579 if args.Verbose:\r
580 CapsuleDependency.DumpInfo ()\r
104a1aa1
JE
581 if SinglePayloadDescriptor.UseOpenSsl or SinglePayloadDescriptor.UseSignTool:\r
582 #\r
583 # Sign image with 64-bit MonotonicCount appended to end of image\r
584 #\r
585 try:\r
586 if SinglePayloadDescriptor.UseSignTool:\r
587 CertData = SignPayloadSignTool (\r
588 Result + struct.pack ('<Q', SinglePayloadDescriptor.MonotonicCount),\r
589 SinglePayloadDescriptor.SigningToolPath,\r
590 SinglePayloadDescriptor.SignToolPfxFile,\r
591 Verbose = args.Verbose\r
592 )\r
593 else:\r
594 CertData = SignPayloadOpenSsl (\r
595 Result + struct.pack ('<Q', SinglePayloadDescriptor.MonotonicCount),\r
596 SinglePayloadDescriptor.SigningToolPath,\r
597 SinglePayloadDescriptor.OpenSslSignerPrivateCertFile,\r
598 SinglePayloadDescriptor.OpenSslOtherPublicCertFile,\r
599 SinglePayloadDescriptor.OpenSslTrustedPublicCertFile,\r
600 Verbose = args.Verbose\r
601 )\r
602 except Exception as Msg:\r
603 print ('GenerateCapsule: error: can not sign payload \n' + str(Msg))\r
604 sys.exit (1)\r
605\r
606 try:\r
607 FmpAuthHeader.MonotonicCount = SinglePayloadDescriptor.MonotonicCount\r
608 FmpAuthHeader.CertData = CertData\r
609 FmpAuthHeader.Payload = Result\r
610 Result = FmpAuthHeader.Encode ()\r
611 if args.Verbose:\r
612 FmpAuthHeader.DumpInfo ()\r
613 except:\r
614 print ('GenerateCapsule: error: can not encode FMP Auth Header')\r
615 sys.exit (1)\r
616 FmpCapsuleHeader.AddPayload (SinglePayloadDescriptor.Guid, Result, HardwareInstance = SinglePayloadDescriptor.HardwareInstance, UpdateImageIndex = SinglePayloadDescriptor.UpdateImageIndex)\r
617 try:\r
618 for EmbeddedDriver in EmbeddedDriverDescriptorList:\r
619 FmpCapsuleHeader.AddEmbeddedDriver(EmbeddedDriver)\r
620\r
621 Result = FmpCapsuleHeader.Encode ()\r
622 if args.Verbose:\r
623 FmpCapsuleHeader.DumpInfo ()\r
624 except:\r
625 print ('GenerateCapsule: error: can not encode FMP Capsule Header')\r
626 sys.exit (1)\r
627\r
628 try:\r
629 UefiCapsuleHeader.OemFlags = args.CapsuleOemFlag\r
630 UefiCapsuleHeader.PersistAcrossReset = 'PersistAcrossReset' in args.CapsuleFlag\r
631 UefiCapsuleHeader.PopulateSystemTable = False\r
632 UefiCapsuleHeader.InitiateReset = 'InitiateReset' in args.CapsuleFlag\r
633 UefiCapsuleHeader.Payload = Result\r
634 Result = UefiCapsuleHeader.Encode ()\r
635 if args.Verbose:\r
636 UefiCapsuleHeader.DumpInfo ()\r
637 except:\r
638 print ('GenerateCapsule: error: can not encode UEFI Capsule Header')\r
639 sys.exit (1)\r
640 try:\r
641 if args.Verbose:\r
642 print ('Write binary output file {File}'.format (File = args.OutputFile.name))\r
643 args.OutputFile.write (Result)\r
644 args.OutputFile.close ()\r
645 except:\r
646 print ('GenerateCapsule: error: can not write binary output file {File}'.format (File = args.OutputFile.name))\r
647 sys.exit (1)\r
648\r
649 def Decode (PayloadDescriptorList, PayloadJsonDescriptorList, Buffer):\r
650 if args.JsonFile:\r
651 CheckArgumentConflict(args)\r
652 #\r
653 # Parse payload descriptors from JSON\r
654 #\r
655 try:\r
656 Json = json.loads (args.JsonFile.read())\r
657 except:\r
658 print ('GenerateCapsule: error: {JSONFile} loads failure. '.format (JSONFile = args.JsonFile))\r
659 sys.exit (1)\r
660 DecodeJsonFileParse (Json)\r
661 else:\r
662 PayloadDescriptorList.append (PayloadDescriptor (\r
663 Buffer,\r
664 args.Guid,\r
665 args.FwVersion,\r
666 args.LowestSupportedVersion,\r
667 args.MonotonicCount,\r
668 args.HardwareInstance,\r
669 args.UpdateImageIndex,\r
670 args.SignToolPfxFile,\r
671 args.OpenSslSignerPrivateCertFile,\r
672 args.OpenSslOtherPublicCertFile,\r
673 args.OpenSslTrustedPublicCertFile,\r
f6f66e0c
LA
674 args.SigningToolPath,\r
675 None\r
104a1aa1
JE
676 ))\r
677 #\r
678 # Perform additional verification on payload descriptors\r
679 #\r
680 for SinglePayloadDescriptor in PayloadDescriptorList:\r
681 try:\r
682 SinglePayloadDescriptor.Validate (args)\r
683 except Exception as Msg:\r
684 print ('GenerateCapsule: error:' + str(Msg))\r
685 sys.exit (1)\r
686 try:\r
687 Result = UefiCapsuleHeader.Decode (Buffer)\r
688 if len (Result) > 0:\r
689 Result = FmpCapsuleHeader.Decode (Result)\r
690 if args.JsonFile:\r
691 if FmpCapsuleHeader.PayloadItemCount != len (PayloadDescriptorList):\r
692 CapsulePayloadNum = FmpCapsuleHeader.PayloadItemCount\r
693 JsonPayloadNum = len (PayloadDescriptorList)\r
694 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
695 sys.exit (1)\r
696 for Index in range (0, FmpCapsuleHeader.PayloadItemCount):\r
697 if Index < len (PayloadDescriptorList):\r
698 GUID = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).UpdateImageTypeId\r
699 HardwareInstance = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).UpdateHardwareInstance\r
700 UpdateImageIndex = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).UpdateImageIndex\r
701 if PayloadDescriptorList[Index].Guid != GUID or PayloadDescriptorList[Index].HardwareInstance != HardwareInstance:\r
702 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
703 sys.exit (1)\r
704 PayloadDescriptorList[Index].Payload = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).Payload\r
705 DecodeJsonOutput = args.OutputFile.name + '.Payload.{Index:d}.bin'.format (Index = Index + 1)\r
706 PayloadJsonDescriptorList.append (PayloadDescriptor (\r
707 DecodeJsonOutput,\r
708 GUID,\r
709 None,\r
710 None,\r
711 None,\r
712 HardwareInstance,\r
713 UpdateImageIndex,\r
714 PayloadDescriptorList[Index].SignToolPfxFile,\r
715 PayloadDescriptorList[Index].OpenSslSignerPrivateCertFile,\r
716 PayloadDescriptorList[Index].OpenSslOtherPublicCertFile,\r
717 PayloadDescriptorList[Index].OpenSslTrustedPublicCertFile,\r
f6f66e0c
LA
718 PayloadDescriptorList[Index].SigningToolPath,\r
719 None\r
104a1aa1
JE
720 ))\r
721 else:\r
722 PayloadDescriptorList[0].Payload = FmpCapsuleHeader.GetFmpCapsuleImageHeader (0).Payload\r
723 for Index in range (0, FmpCapsuleHeader.PayloadItemCount):\r
724 if Index > 0:\r
725 PayloadDecodeFile = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).Payload\r
726 PayloadDescriptorList.append (PayloadDescriptor (PayloadDecodeFile,\r
727 None,\r
728 None,\r
729 None,\r
730 None,\r
731 None,\r
732 None,\r
733 None,\r
734 None,\r
735 None,\r
736 None,\r
f6f66e0c 737 None,\r
104a1aa1
JE
738 None\r
739 ))\r
740 GUID = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).UpdateImageTypeId\r
741 HardwareInstance = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).UpdateHardwareInstance\r
742 UpdateImageIndex = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).UpdateImageIndex\r
743 DecodeJsonOutput = args.OutputFile.name + '.Payload.{Index:d}.bin'.format (Index = Index + 1)\r
744 PayloadJsonDescriptorList.append (PayloadDescriptor (\r
745 DecodeJsonOutput,\r
746 GUID,\r
747 None,\r
748 None,\r
749 None,\r
750 HardwareInstance,\r
751 UpdateImageIndex,\r
752 PayloadDescriptorList[Index].SignToolPfxFile,\r
753 PayloadDescriptorList[Index].OpenSslSignerPrivateCertFile,\r
754 PayloadDescriptorList[Index].OpenSslOtherPublicCertFile,\r
755 PayloadDescriptorList[Index].OpenSslTrustedPublicCertFile,\r
f6f66e0c
LA
756 PayloadDescriptorList[Index].SigningToolPath,\r
757 None\r
104a1aa1
JE
758 ))\r
759 JsonIndex = 0\r
760 for SinglePayloadDescriptor in PayloadDescriptorList:\r
761 if args.Verbose:\r
762 print ('========')\r
763 UefiCapsuleHeader.DumpInfo ()\r
764 print ('--------')\r
765 FmpCapsuleHeader.DumpInfo ()\r
766 if FmpAuthHeader.IsSigned(SinglePayloadDescriptor.Payload):\r
767 if not SinglePayloadDescriptor.UseOpenSsl and not SinglePayloadDescriptor.UseSignTool:\r
768 print ('GenerateCapsule: decode warning: can not verify singed payload without cert or pfx file. Index = {Index}'.format (Index = JsonIndex + 1))\r
769 SinglePayloadDescriptor.Payload = FmpAuthHeader.Decode (SinglePayloadDescriptor.Payload)\r
770 PayloadJsonDescriptorList[JsonIndex].MonotonicCount = FmpAuthHeader.MonotonicCount\r
771 if args.Verbose:\r
772 print ('--------')\r
773 FmpAuthHeader.DumpInfo ()\r
774\r
775 #\r
776 # Verify Image with 64-bit MonotonicCount appended to end of image\r
777 #\r
778 try:\r
779 if SinglePayloadDescriptor.UseSignTool:\r
780 CertData = VerifyPayloadSignTool (\r
781 FmpAuthHeader.Payload + struct.pack ('<Q', FmpAuthHeader.MonotonicCount),\r
782 FmpAuthHeader.CertData,\r
783 SinglePayloadDescriptor.SigningToolPath,\r
784 SinglePayloadDescriptor.SignToolPfxFile,\r
785 Verbose = args.Verbose\r
786 )\r
787 else:\r
788 CertData = VerifyPayloadOpenSsl (\r
789 FmpAuthHeader.Payload + struct.pack ('<Q', FmpAuthHeader.MonotonicCount),\r
790 FmpAuthHeader.CertData,\r
791 SinglePayloadDescriptor.SigningToolPath,\r
792 SinglePayloadDescriptor.OpenSslSignerPrivateCertFile,\r
793 SinglePayloadDescriptor.OpenSslOtherPublicCertFile,\r
794 SinglePayloadDescriptor.OpenSslTrustedPublicCertFile,\r
795 Verbose = args.Verbose\r
796 )\r
797 except Exception as Msg:\r
798 print ('GenerateCapsule: warning: payload verification failed Index = {Index} \n'.format (Index = JsonIndex + 1) + str(Msg))\r
799 else:\r
800 if args.Verbose:\r
801 print ('--------')\r
802 print ('No EFI_FIRMWARE_IMAGE_AUTHENTICATION')\r
f6f66e0c
LA
803\r
804 PayloadSignature = struct.unpack ('<I', SinglePayloadDescriptor.Payload[0:4])\r
805 if PayloadSignature != FmpPayloadHeader.Signature:\r
806 SinglePayloadDescriptor.UseDependency = True\r
807 try:\r
808 SinglePayloadDescriptor.Payload = CapsuleDependency.Decode (SinglePayloadDescriptor.Payload)\r
809 PayloadJsonDescriptorList[JsonIndex].DepexExp = CapsuleDependency.DepexExp\r
810 if args.Verbose:\r
811 print ('--------')\r
812 CapsuleDependency.DumpInfo ()\r
813 except Exception as Msg:\r
814 print ('GenerateCapsule: error: invalid dependency expression')\r
815 else:\r
816 if args.Verbose:\r
817 print ('--------')\r
818 print ('No EFI_FIRMWARE_IMAGE_DEP')\r
819\r
104a1aa1
JE
820 try:\r
821 SinglePayloadDescriptor.Payload = FmpPayloadHeader.Decode (SinglePayloadDescriptor.Payload)\r
822 PayloadJsonDescriptorList[JsonIndex].FwVersion = FmpPayloadHeader.FwVersion\r
823 PayloadJsonDescriptorList[JsonIndex].LowestSupportedVersion = FmpPayloadHeader.LowestSupportedVersion\r
824 JsonIndex = JsonIndex + 1\r
825 if args.Verbose:\r
826 print ('--------')\r
827 FmpPayloadHeader.DumpInfo ()\r
828 print ('========')\r
829 except:\r
830 if args.Verbose:\r
831 print ('--------')\r
832 print ('No FMP_PAYLOAD_HEADER')\r
833 print ('========')\r
834 sys.exit (1)\r
835 #\r
836 # Write embedded driver file(s)\r
837 #\r
838 for Index in range (0, FmpCapsuleHeader.EmbeddedDriverCount):\r
839 EmbeddedDriverBuffer = FmpCapsuleHeader.GetEmbeddedDriver (Index)\r
840 EmbeddedDriverPath = args.OutputFile.name + '.EmbeddedDriver.{Index:d}.efi'.format (Index = Index + 1)\r
841 try:\r
842 if args.Verbose:\r
843 print ('Write embedded driver file {File}'.format (File = EmbeddedDriverPath))\r
844 with open (EmbeddedDriverPath, 'wb') as EmbeddedDriverFile:\r
845 EmbeddedDriverFile.write (EmbeddedDriverBuffer)\r
846 except:\r
847 print ('GenerateCapsule: error: can not write embedded driver file {File}'.format (File = EmbeddedDriverPath))\r
848 sys.exit (1)\r
849\r
850 except:\r
851 print ('GenerateCapsule: error: can not decode capsule')\r
852 sys.exit (1)\r
853 GenerateOutputJson(PayloadJsonDescriptorList)\r
854 PayloadIndex = 0\r
855 for SinglePayloadDescriptor in PayloadDescriptorList:\r
856 if args.OutputFile is None:\r
857 print ('GenerateCapsule: Decode error: OutputFile is needed for decode output')\r
858 sys.exit (1)\r
859 try:\r
860 if args.Verbose:\r
861 print ('Write binary output file {File}'.format (File = args.OutputFile.name))\r
862 PayloadDecodePath = args.OutputFile.name + '.Payload.{Index:d}.bin'.format (Index = PayloadIndex + 1)\r
863 with open (PayloadDecodePath, 'wb') as PayloadDecodeFile:\r
864 PayloadDecodeFile.write (SinglePayloadDescriptor.Payload)\r
865 PayloadIndex = PayloadIndex + 1\r
866 except:\r
867 print ('GenerateCapsule: error: can not write binary output file {File}'.format (File = SinglePayloadDescriptor.OutputFile.name))\r
868 sys.exit (1)\r
869\r
870 def DumpInfo (Buffer, args):\r
871 if args.OutputFile is not None:\r
872 raise argparse.ArgumentTypeError ('the following option is not supported for dumpinfo operations: --output')\r
873 try:\r
874 Result = UefiCapsuleHeader.Decode (Buffer)\r
875 print ('========')\r
876 UefiCapsuleHeader.DumpInfo ()\r
877 if len (Result) > 0:\r
878 FmpCapsuleHeader.Decode (Result)\r
879 print ('--------')\r
880 FmpCapsuleHeader.DumpInfo ()\r
881 for Index in range (0, FmpCapsuleHeader.PayloadItemCount):\r
882 Result = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).Payload\r
883 try:\r
884 Result = FmpAuthHeader.Decode (Result)\r
885 print ('--------')\r
886 FmpAuthHeader.DumpInfo ()\r
887 except:\r
888 print ('--------')\r
889 print ('No EFI_FIRMWARE_IMAGE_AUTHENTICATION')\r
f6f66e0c
LA
890\r
891 PayloadSignature = struct.unpack ('<I', Result[0:4])\r
892 if PayloadSignature != FmpPayloadHeader.Signature:\r
893 try:\r
894 Result = CapsuleDependency.Decode (Result)\r
895 print ('--------')\r
896 CapsuleDependency.DumpInfo ()\r
897 except:\r
898 print ('GenerateCapsule: error: invalid dependency expression')\r
899 else:\r
900 print ('--------')\r
901 print ('No EFI_FIRMWARE_IMAGE_DEP')\r
104a1aa1
JE
902 try:\r
903 Result = FmpPayloadHeader.Decode (Result)\r
904 print ('--------')\r
905 FmpPayloadHeader.DumpInfo ()\r
906 except:\r
907 print ('--------')\r
908 print ('No FMP_PAYLOAD_HEADER')\r
909 print ('========')\r
910 except:\r
911 print ('GenerateCapsule: error: can not decode capsule')\r
912 sys.exit (1)\r
8b63877a
KM
913 #\r
914 # Create command line argument parser object\r
915 #\r
916 parser = argparse.ArgumentParser (\r
917 prog = __prog__,\r
918 description = __description__ + __copyright__,\r
919 conflict_handler = 'resolve',\r
920 fromfile_prefix_chars = '@'\r
921 )\r
922 parser.convert_arg_line_to_args = convert_arg_line_to_args\r
923\r
924 #\r
925 # Add input and output file arguments\r
926 #\r
104a1aa1 927 parser.add_argument("InputFile", type = argparse.FileType('rb'), nargs='?',\r
8b63877a
KM
928 help = "Input binary payload filename.")\r
929 parser.add_argument("-o", "--output", dest = 'OutputFile', type = argparse.FileType('wb'),\r
930 help = "Output filename.")\r
931 #\r
932 # Add group for -e and -d flags that are mutually exclusive and required\r
933 #\r
934 group = parser.add_mutually_exclusive_group (required = True)\r
935 group.add_argument ("-e", "--encode", dest = 'Encode', action = "store_true",\r
936 help = "Encode file")\r
937 group.add_argument ("-d", "--decode", dest = 'Decode', action = "store_true",\r
938 help = "Decode file")\r
939 group.add_argument ("--dump-info", dest = 'DumpInfo', action = "store_true",\r
940 help = "Display FMP Payload Header information")\r
941 #\r
942 # Add optional arguments for this command\r
943 #\r
104a1aa1
JE
944 parser.add_argument ("-j", "--json-file", dest = 'JsonFile', type=argparse.FileType('r'),\r
945 help = "JSON configuration file for multiple payloads and embedded drivers.")\r
8b63877a 946 parser.add_argument ("--capflag", dest = 'CapsuleFlag', action='append', default = [],\r
2779c222
KM
947 choices=['PersistAcrossReset', 'InitiateReset'],\r
948 help = "Capsule flag can be PersistAcrossReset or InitiateReset or not set")\r
8b63877a
KM
949 parser.add_argument ("--capoemflag", dest = 'CapsuleOemFlag', type = ValidateUnsignedInteger, default = 0x0000,\r
950 help = "Capsule OEM Flag is an integer between 0x0000 and 0xffff.")\r
951\r
952 parser.add_argument ("--guid", dest = 'Guid', type = ValidateRegistryFormatGuid,\r
104a1aa1 953 help = "The FMP/ESRT GUID in registry format. Required for single payload encode operations.")\r
8b63877a
KM
954 parser.add_argument ("--hardware-instance", dest = 'HardwareInstance', type = ValidateUnsignedInteger, default = 0x0000000000000000,\r
955 help = "The 64-bit hardware instance. The default is 0x0000000000000000")\r
956\r
957\r
958 parser.add_argument ("--monotonic-count", dest = 'MonotonicCount', type = ValidateUnsignedInteger, default = 0x0000000000000000,\r
959 help = "64-bit monotonic count value in header. Default is 0x0000000000000000.")\r
960\r
961 parser.add_argument ("--fw-version", dest = 'FwVersion', type = ValidateUnsignedInteger,\r
104a1aa1 962 help = "The 32-bit version of the binary payload (e.g. 0x11223344 or 5678). Required for encode operations.")\r
8b63877a 963 parser.add_argument ("--lsv", dest = 'LowestSupportedVersion', type = ValidateUnsignedInteger,\r
104a1aa1 964 help = "The 32-bit lowest supported version of the binary payload (e.g. 0x11223344 or 5678). Required for encode operations.")\r
8b63877a
KM
965\r
966 parser.add_argument ("--pfx-file", dest='SignToolPfxFile', type=argparse.FileType('rb'),\r
967 help="signtool PFX certificate filename.")\r
968\r
969 parser.add_argument ("--signer-private-cert", dest='OpenSslSignerPrivateCertFile', type=argparse.FileType('rb'),\r
970 help="OpenSSL signer private certificate filename.")\r
971 parser.add_argument ("--other-public-cert", dest='OpenSslOtherPublicCertFile', type=argparse.FileType('rb'),\r
972 help="OpenSSL other public certificate filename.")\r
973 parser.add_argument ("--trusted-public-cert", dest='OpenSslTrustedPublicCertFile', type=argparse.FileType('rb'),\r
974 help="OpenSSL trusted public certificate filename.")\r
975\r
976 parser.add_argument ("--signing-tool-path", dest = 'SigningToolPath',\r
977 help = "Path to signtool or OpenSSL tool. Optional if path to tools are already in PATH.")\r
978\r
104a1aa1
JE
979 parser.add_argument ("--embedded-driver", dest = 'EmbeddedDriver', type = argparse.FileType('rb'), action='append', default = [],\r
980 help = "Path to embedded UEFI driver to add to capsule.")\r
981\r
8b63877a
KM
982 #\r
983 # Add optional arguments common to all operations\r
984 #\r
985 parser.add_argument ('--version', action='version', version='%(prog)s ' + __version__)\r
986 parser.add_argument ("-v", "--verbose", dest = 'Verbose', action = "store_true",\r
987 help = "Turn on verbose output with informational messages printed, including capsule headers and warning messages.")\r
988 parser.add_argument ("-q", "--quiet", dest = 'Quiet', action = "store_true",\r
989 help = "Disable all messages except fatal errors.")\r
990 parser.add_argument ("--debug", dest = 'Debug', type = int, metavar = '[0-9]', choices = range (0, 10), default = 0,\r
991 help = "Set debug level")\r
104a1aa1 992 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
993\r
994 #\r
995 # Parse command line arguments\r
996 #\r
997 args = parser.parse_args()\r
998\r
8b63877a
KM
999 #\r
1000 # Read binary input file\r
1001 #\r
104a1aa1
JE
1002 Buffer = ''\r
1003 if args.InputFile:\r
1004 if os.path.getsize (args.InputFile.name) == 0:\r
1005 print ('GenerateCapsule: error: InputFile {File} is empty'.format (File = args.InputFile.name))\r
1006 sys.exit (1)\r
1007 try:\r
1008 if args.Verbose:\r
1009 print ('Read binary input file {File}'.format (File = args.InputFile.name))\r
1010 Buffer = args.InputFile.read ()\r
1011 args.InputFile.close ()\r
1012 except:\r
1013 print ('GenerateCapsule: error: can not read binary input file {File}'.format (File = args.InputFile.name))\r
1014 sys.exit (1)\r
8b63877a
KM
1015\r
1016 #\r
1017 # Create objects\r
1018 #\r
1019 UefiCapsuleHeader = UefiCapsuleHeaderClass ()\r
1020 FmpCapsuleHeader = FmpCapsuleHeaderClass ()\r
1021 FmpAuthHeader = FmpAuthHeaderClass ()\r
1022 FmpPayloadHeader = FmpPayloadHeaderClass ()\r
f6f66e0c 1023 CapsuleDependency = CapsuleDependencyClass ()\r
8b63877a 1024\r
104a1aa1
JE
1025 EmbeddedDriverDescriptorList = []\r
1026 PayloadDescriptorList = []\r
1027 PayloadJsonDescriptorList = []\r
8b63877a 1028\r
104a1aa1
JE
1029 #\r
1030 #Encode Operation\r
1031 #\r
1032 if args.Encode:\r
1033 Encode (PayloadDescriptorList, EmbeddedDriverDescriptorList, Buffer)\r
8b63877a 1034\r
104a1aa1
JE
1035 #\r
1036 #Decode Operation\r
1037 #\r
1038 if args.Decode:\r
1039 Decode (PayloadDescriptorList, PayloadJsonDescriptorList, Buffer)\r
8b63877a
KM
1040\r
1041 #\r
104a1aa1 1042 #Dump Info Operation\r
8b63877a 1043 #\r
104a1aa1
JE
1044 if args.DumpInfo:\r
1045 DumpInfo (Buffer, args)\r
8b63877a
KM
1046\r
1047 if args.Verbose:\r
1048 print('Success')\r