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