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