]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/Python/Capsule/GenerateCapsule.py
BaseTools/Capsule: Do not support -o with --dump-info
[mirror_edk2.git] / BaseTools / Source / Python / Capsule / GenerateCapsule.py
CommitLineData
8b63877a
KM
1## @file\r
2# Generate a capsule.\r
3#\r
4# Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>\r
5# This program and the accompanying materials\r
6# are licensed and made available under the terms and conditions of the BSD License\r
7# which accompanies this distribution. The full text of the license may be found at\r
8# http://opensource.org/licenses/bsd-license.php\r
9#\r
10# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12#\r
13\r
14'''\r
15GenerateCapsule\r
16'''\r
17\r
18import sys\r
19import argparse\r
20import uuid\r
21import struct\r
22import subprocess\r
23import os\r
24import tempfile\r
25import shutil\r
26import platform\r
27from Common.Uefi.Capsule.UefiCapsuleHeader import UefiCapsuleHeaderClass\r
28from Common.Uefi.Capsule.FmpCapsuleHeader import FmpCapsuleHeaderClass\r
29from Common.Uefi.Capsule.FmpAuthHeader import FmpAuthHeaderClass\r
30from Common.Edk2.Capsule.FmpPayloadHeader import FmpPayloadHeaderClass\r
31\r
32#\r
33# Globals for help information\r
34#\r
35__prog__ = 'GenerateCapsule'\r
36__version__ = '0.9'\r
37__copyright__ = 'Copyright (c) 2018, Intel Corporation. All rights reserved.'\r
38__description__ = 'Generate a capsule.\n'\r
39\r
40def SignPayloadSignTool (Payload, ToolPath, PfxFile):\r
41 #\r
42 # Create a temporary directory\r
43 #\r
44 TempDirectoryName = tempfile.mkdtemp()\r
45\r
46 #\r
47 # Generate temp file name for the payload contents\r
48 #\r
49 TempFileName = os.path.join (TempDirectoryName, 'Payload.bin')\r
50\r
51 #\r
52 # Create temporary payload file for signing\r
53 #\r
54 try:\r
55 File = open (TempFileName, mode='wb')\r
56 File.write (Payload)\r
57 File.close ()\r
58 except:\r
59 shutil.rmtree (TempDirectoryName)\r
60 raise ValueError ('GenerateCapsule: error: can not write temporary payload file.')\r
61\r
62 #\r
63 # Build signtool command\r
64 #\r
65 if ToolPath is None:\r
66 ToolPath = ''\r
67 Command = ''\r
68 Command = Command + '"{Path}" '.format (Path = os.path.join (ToolPath, 'signtool.exe'))\r
69 Command = Command + 'sign /fd sha256 /p7ce DetachedSignedData /p7co 1.2.840.113549.1.7.2 '\r
70 Command = Command + '/p7 {TempDir} '.format (TempDir = TempDirectoryName)\r
71 Command = Command + '/f {PfxFile} '.format (PfxFile = PfxFile)\r
72 Command = Command + TempFileName\r
73\r
74 #\r
75 # Sign the input file using the specified private key\r
76 #\r
77 try:\r
78 Process = subprocess.Popen (Command, stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE, shell = True)\r
79 Result = Process.communicate('')\r
80 except:\r
81 shutil.rmtree (TempDirectoryName)\r
82 raise ValueError ('GenerateCapsule: error: can not run signtool.')\r
83\r
84 if Process.returncode != 0:\r
85 shutil.rmtree (TempDirectoryName)\r
86 print (Result[1].decode())\r
87 raise ValueError ('GenerateCapsule: error: signtool failed.')\r
88\r
89 #\r
90 # Read the signature from the generated output file\r
91 #\r
92 try:\r
93 File = open (TempFileName + '.p7', mode='rb')\r
94 Signature = File.read ()\r
95 File.close ()\r
96 except:\r
97 shutil.rmtree (TempDirectoryName)\r
98 raise ValueError ('GenerateCapsule: error: can not read signature file.')\r
99\r
100 shutil.rmtree (TempDirectoryName)\r
101 return Signature\r
102\r
103def VerifyPayloadSignTool (Payload, CertData, ToolPath, PfxFile):\r
104 print ('signtool verify is not supported.')\r
105 raise ValueError ('GenerateCapsule: error: signtool verify is not supported.')\r
106\r
107def SignPayloadOpenSsl (Payload, ToolPath, SignerPrivateCertFile, OtherPublicCertFile, TrustedPublicCertFile):\r
108 #\r
109 # Build openssl command\r
110 #\r
111 if ToolPath is None:\r
112 ToolPath = ''\r
113 Command = ''\r
114 Command = Command + '"{Path}" '.format (Path = os.path.join (ToolPath, 'openssl'))\r
115 Command = Command + 'smime -sign -binary -outform DER -md sha256 '\r
116 Command = Command + '-signer "{Private}" -certfile "{Public}"'.format (Private = SignerPrivateCertFile, Public = OtherPublicCertFile)\r
117\r
118 #\r
119 # Sign the input file using the specified private key and capture signature from STDOUT\r
120 #\r
121 try:\r
122 Process = subprocess.Popen (Command, stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE, shell = True)\r
123 Result = Process.communicate(input = Payload)\r
124 Signature = Result[0]\r
125 except:\r
126 raise ValueError ('GenerateCapsule: error: can not run openssl.')\r
127\r
128 if Process.returncode != 0:\r
129 print (Result[1].decode())\r
130 raise ValueError ('GenerateCapsule: error: openssl failed.')\r
131\r
132 return Signature\r
133\r
134def VerifyPayloadOpenSsl (Payload, CertData, ToolPath, SignerPrivateCertFile, OtherPublicCertFile, TrustedPublicCertFile):\r
135 #\r
136 # Create a temporary directory\r
137 #\r
138 TempDirectoryName = tempfile.mkdtemp()\r
139\r
140 #\r
141 # Generate temp file name for the payload contents\r
142 #\r
143 TempFileName = os.path.join (TempDirectoryName, 'Payload.bin')\r
144\r
145 #\r
146 # Create temporary payload file for verification\r
147 #\r
148 try:\r
149 File = open (TempFileName, mode='wb')\r
150 File.write (Payload)\r
151 File.close ()\r
152 except:\r
153 shutil.rmtree (TempDirectoryName)\r
154 raise ValueError ('GenerateCapsule: error: can not write temporary payload file.')\r
155\r
156 #\r
157 # Build openssl command\r
158 #\r
159 if ToolPath is None:\r
160 ToolPath = ''\r
161 Command = ''\r
162 Command = Command + '"{Path}" '.format (Path = os.path.join (ToolPath, 'openssl'))\r
163 Command = Command + 'smime -verify -inform DER '\r
164 Command = Command + '-content {Content} -CAfile "{Public}"'.format (Content = TempFileName, Public = TrustedPublicCertFile)\r
165\r
166 #\r
167 # Verify signature\r
168 #\r
169 try:\r
170 Process = subprocess.Popen (Command, stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE, shell = True)\r
171 Result = Process.communicate(input = CertData)\r
172 except:\r
173 shutil.rmtree (TempDirectoryName)\r
174 raise ValueError ('GenerateCapsule: error: can not run openssl.')\r
175\r
176 if Process.returncode != 0:\r
177 shutil.rmtree (TempDirectoryName)\r
178 print (Result[1].decode())\r
179 raise ValueError ('GenerateCapsule: error: openssl failed.')\r
180\r
181 shutil.rmtree (TempDirectoryName)\r
182 return Payload\r
183\r
184if __name__ == '__main__':\r
185 def convert_arg_line_to_args(arg_line):\r
186 for arg in arg_line.split():\r
187 if not arg.strip():\r
188 continue\r
189 yield arg\r
190\r
191 def ValidateUnsignedInteger (Argument):\r
192 try:\r
193 Value = int (Argument, 0)\r
194 except:\r
195 Message = '{Argument} is not a valid integer value.'.format (Argument = Argument)\r
196 raise argparse.ArgumentTypeError (Message)\r
197 if Value < 0:\r
198 Message = '{Argument} is a negative value.'.format (Argument = Argument)\r
199 raise argparse.ArgumentTypeError (Message)\r
200 return Value\r
201\r
202 def ValidateRegistryFormatGuid (Argument):\r
203 try:\r
204 Value = uuid.UUID (Argument)\r
205 except:\r
206 Message = '{Argument} is not a valid registry format GUID value.'.format (Argument = Argument)\r
207 raise argparse.ArgumentTypeError (Message)\r
208 return Value\r
209\r
210 #\r
211 # Create command line argument parser object\r
212 #\r
213 parser = argparse.ArgumentParser (\r
214 prog = __prog__,\r
215 description = __description__ + __copyright__,\r
216 conflict_handler = 'resolve',\r
217 fromfile_prefix_chars = '@'\r
218 )\r
219 parser.convert_arg_line_to_args = convert_arg_line_to_args\r
220\r
221 #\r
222 # Add input and output file arguments\r
223 #\r
224 parser.add_argument("InputFile", type = argparse.FileType('rb'),\r
225 help = "Input binary payload filename.")\r
226 parser.add_argument("-o", "--output", dest = 'OutputFile', type = argparse.FileType('wb'),\r
227 help = "Output filename.")\r
228 #\r
229 # Add group for -e and -d flags that are mutually exclusive and required\r
230 #\r
231 group = parser.add_mutually_exclusive_group (required = True)\r
232 group.add_argument ("-e", "--encode", dest = 'Encode', action = "store_true",\r
233 help = "Encode file")\r
234 group.add_argument ("-d", "--decode", dest = 'Decode', action = "store_true",\r
235 help = "Decode file")\r
236 group.add_argument ("--dump-info", dest = 'DumpInfo', action = "store_true",\r
237 help = "Display FMP Payload Header information")\r
238 #\r
239 # Add optional arguments for this command\r
240 #\r
241 parser.add_argument ("--capflag", dest = 'CapsuleFlag', action='append', default = [],\r
2779c222
KM
242 choices=['PersistAcrossReset', 'InitiateReset'],\r
243 help = "Capsule flag can be PersistAcrossReset or InitiateReset or not set")\r
8b63877a
KM
244 parser.add_argument ("--capoemflag", dest = 'CapsuleOemFlag', type = ValidateUnsignedInteger, default = 0x0000,\r
245 help = "Capsule OEM Flag is an integer between 0x0000 and 0xffff.")\r
246\r
247 parser.add_argument ("--guid", dest = 'Guid', type = ValidateRegistryFormatGuid,\r
248 help = "The FMP/ESRT GUID in registry format. Required for encode operations.")\r
249 parser.add_argument ("--hardware-instance", dest = 'HardwareInstance', type = ValidateUnsignedInteger, default = 0x0000000000000000,\r
250 help = "The 64-bit hardware instance. The default is 0x0000000000000000")\r
251\r
252\r
253 parser.add_argument ("--monotonic-count", dest = 'MonotonicCount', type = ValidateUnsignedInteger, default = 0x0000000000000000,\r
254 help = "64-bit monotonic count value in header. Default is 0x0000000000000000.")\r
255\r
256 parser.add_argument ("--fw-version", dest = 'FwVersion', type = ValidateUnsignedInteger,\r
257 help = "The 32-bit version of the binary payload (e.g. 0x11223344 or 5678).")\r
258 parser.add_argument ("--lsv", dest = 'LowestSupportedVersion', type = ValidateUnsignedInteger,\r
259 help = "The 32-bit lowest supported version of the binary payload (e.g. 0x11223344 or 5678).")\r
260\r
261 parser.add_argument ("--pfx-file", dest='SignToolPfxFile', type=argparse.FileType('rb'),\r
262 help="signtool PFX certificate filename.")\r
263\r
264 parser.add_argument ("--signer-private-cert", dest='OpenSslSignerPrivateCertFile', type=argparse.FileType('rb'),\r
265 help="OpenSSL signer private certificate filename.")\r
266 parser.add_argument ("--other-public-cert", dest='OpenSslOtherPublicCertFile', type=argparse.FileType('rb'),\r
267 help="OpenSSL other public certificate filename.")\r
268 parser.add_argument ("--trusted-public-cert", dest='OpenSslTrustedPublicCertFile', type=argparse.FileType('rb'),\r
269 help="OpenSSL trusted public certificate filename.")\r
270\r
271 parser.add_argument ("--signing-tool-path", dest = 'SigningToolPath',\r
272 help = "Path to signtool or OpenSSL tool. Optional if path to tools are already in PATH.")\r
273\r
274 #\r
275 # Add optional arguments common to all operations\r
276 #\r
277 parser.add_argument ('--version', action='version', version='%(prog)s ' + __version__)\r
278 parser.add_argument ("-v", "--verbose", dest = 'Verbose', action = "store_true",\r
279 help = "Turn on verbose output with informational messages printed, including capsule headers and warning messages.")\r
280 parser.add_argument ("-q", "--quiet", dest = 'Quiet', action = "store_true",\r
281 help = "Disable all messages except fatal errors.")\r
282 parser.add_argument ("--debug", dest = 'Debug', type = int, metavar = '[0-9]', choices = range (0, 10), default = 0,\r
283 help = "Set debug level")\r
284\r
285 #\r
286 # Parse command line arguments\r
287 #\r
288 args = parser.parse_args()\r
289\r
290 #\r
291 # Perform additional argument verification\r
292 #\r
293 if args.Encode:\r
294 if args.Guid is None:\r
295 parser.error ('the following option is required: --guid')\r
296 if 'PersistAcrossReset' not in args.CapsuleFlag:\r
8b63877a
KM
297 if 'InitiateReset' in args.CapsuleFlag:\r
298 parser.error ('--capflag InitiateReset also requires --capflag PersistAcrossReset')\r
6ed4651c
KM
299 if args.CapsuleOemFlag > 0xFFFF:\r
300 parser.error ('--capoemflag must be an integer between 0x0000 and 0xffff')\r
301 if args.HardwareInstance > 0xFFFFFFFFFFFFFFFF:\r
302 parser.error ('--hardware-instance must be an integer in range 0x0..0xffffffffffffffff')\r
303 if args.MonotonicCount > 0xFFFFFFFFFFFFFFFF:\r
304 parser.error ('--monotonic-count must be an integer in range 0x0..0xffffffffffffffff')\r
8b63877a
KM
305\r
306 UseSignTool = args.SignToolPfxFile is not None\r
307 UseOpenSsl = (args.OpenSslSignerPrivateCertFile is not None and\r
308 args.OpenSslOtherPublicCertFile is not None and\r
309 args.OpenSslTrustedPublicCertFile is not None)\r
310 AnyOpenSsl = (args.OpenSslSignerPrivateCertFile is not None or\r
311 args.OpenSslOtherPublicCertFile is not None or\r
312 args.OpenSslTrustedPublicCertFile is not None)\r
313 if args.Encode or args.Decode:\r
314 if args.OutputFile is None:\r
315 parser.error ('the following option is required for all encode and decode operations: --output')\r
316\r
317 if UseSignTool and AnyOpenSsl:\r
318 parser.error ('Providing both signtool and OpenSSL options is not supported')\r
319 if not UseSignTool and not UseOpenSsl and AnyOpenSsl:\r
320 parser.error ('all the following options are required for OpenSSL: --signer-private-cert, --other-public-cert, --trusted-public-cert')\r
321 if UseSignTool and platform.system() != 'Windows':\r
322 parser.error ('Use of signtool is not supported on this operating system.')\r
323 if args.Encode and (UseSignTool or UseOpenSsl):\r
324 if args.FwVersion is None or args.LowestSupportedVersion is None:\r
325 parser.error ('the following options are required: --fw-version, --lsv')\r
6ed4651c
KM
326 if args.FwVersion > 0xFFFFFFFF:\r
327 parser.error ('--fw-version must be an integer in range 0x0..0xffffffff')\r
328 if args.LowestSupportedVersion > 0xFFFFFFFF:\r
329 parser.error ('--lsv must be an integer in range 0x0..0xffffffff')\r
8b63877a
KM
330\r
331 if UseSignTool:\r
332 args.SignToolPfxFile.close()\r
333 args.SignToolPfxFile = args.SignToolPfxFile.name\r
334 if UseOpenSsl:\r
335 args.OpenSslSignerPrivateCertFile.close()\r
336 args.OpenSslOtherPublicCertFile.close()\r
337 args.OpenSslTrustedPublicCertFile.close()\r
338 args.OpenSslSignerPrivateCertFile = args.OpenSslSignerPrivateCertFile.name\r
339 args.OpenSslOtherPublicCertFile = args.OpenSslOtherPublicCertFile.name\r
340 args.OpenSslTrustedPublicCertFile = args.OpenSslTrustedPublicCertFile.name\r
341\r
f33d5d68
KM
342 if args.DumpInfo:\r
343 if args.OutputFile is not None:\r
344 parser.error ('the following option is not supported for dumpinfo operations: --output')\r
345\r
8b63877a
KM
346 #\r
347 # Read binary input file\r
348 #\r
349 try:\r
350 if args.Verbose:\r
351 print ('Read binary input file {File}'.format (File = args.InputFile.name))\r
352 Buffer = args.InputFile.read ()\r
353 args.InputFile.close ()\r
354 except:\r
355 print ('GenerateCapsule: error: can not read binary input file {File}'.format (File = args.InputFile.name))\r
356 sys.exit (1)\r
357\r
358 #\r
359 # Create objects\r
360 #\r
361 UefiCapsuleHeader = UefiCapsuleHeaderClass ()\r
362 FmpCapsuleHeader = FmpCapsuleHeaderClass ()\r
363 FmpAuthHeader = FmpAuthHeaderClass ()\r
364 FmpPayloadHeader = FmpPayloadHeaderClass ()\r
365\r
366 if args.Encode:\r
367 Result = Buffer\r
368 if UseSignTool or UseOpenSsl:\r
369 try:\r
370 FmpPayloadHeader.FwVersion = args.FwVersion\r
371 FmpPayloadHeader.LowestSupportedVersion = args.LowestSupportedVersion\r
372 FmpPayloadHeader.Payload = Result\r
373 Result = FmpPayloadHeader.Encode ()\r
374 if args.Verbose:\r
375 FmpPayloadHeader.DumpInfo ()\r
376 except:\r
377 print ('GenerateCapsule: error: can not encode FMP Payload Header')\r
378 sys.exit (1)\r
379\r
380 #\r
381 # Sign image with 64-bit MonotonicCount appended to end of image\r
382 #\r
383 try:\r
384 if UseSignTool:\r
385 CertData = SignPayloadSignTool (\r
386 Result + struct.pack ('<Q', args.MonotonicCount),\r
387 args.SigningToolPath,\r
388 args.SignToolPfxFile\r
389 )\r
390 else:\r
391 CertData = SignPayloadOpenSsl (\r
392 Result + struct.pack ('<Q', args.MonotonicCount),\r
393 args.SigningToolPath,\r
394 args.OpenSslSignerPrivateCertFile,\r
395 args.OpenSslOtherPublicCertFile,\r
396 args.OpenSslTrustedPublicCertFile\r
397 )\r
398 except:\r
399 print ('GenerateCapsule: error: can not sign payload')\r
400 raise\r
401 sys.exit (1)\r
402\r
403 try:\r
404 FmpAuthHeader.MonotonicCount = args.MonotonicCount\r
405 FmpAuthHeader.CertData = CertData\r
406 FmpAuthHeader.Payload = Result\r
407 Result = FmpAuthHeader.Encode ()\r
408 if args.Verbose:\r
409 FmpAuthHeader.DumpInfo ()\r
410 except:\r
411 print ('GenerateCapsule: error: can not encode FMP Auth Header')\r
412 sys.exit (1)\r
413\r
414 try:\r
415 FmpCapsuleHeader.AddPayload (args.Guid, Result, HardwareInstance = args.HardwareInstance)\r
416 Result = FmpCapsuleHeader.Encode ()\r
417 if args.Verbose:\r
418 FmpCapsuleHeader.DumpInfo ()\r
419 except:\r
420 print ('GenerateCapsule: error: can not encode FMP Capsule Header')\r
421 sys.exit (1)\r
422\r
423 try:\r
424 UefiCapsuleHeader.OemFlags = args.CapsuleOemFlag\r
425 UefiCapsuleHeader.PersistAcrossReset = 'PersistAcrossReset' in args.CapsuleFlag\r
2779c222 426 UefiCapsuleHeader.PopulateSystemTable = False\r
8b63877a
KM
427 UefiCapsuleHeader.InitiateReset = 'InitiateReset' in args.CapsuleFlag\r
428 UefiCapsuleHeader.Payload = Result\r
429 Result = UefiCapsuleHeader.Encode ()\r
430 if args.Verbose:\r
431 UefiCapsuleHeader.DumpInfo ()\r
432 except:\r
433 print ('GenerateCapsule: error: can not encode UEFI Capsule Header')\r
434 sys.exit (1)\r
435\r
436 elif args.Decode:\r
437 try:\r
438 Result = UefiCapsuleHeader.Decode (Buffer)\r
439 FmpCapsuleHeader.Decode (Result)\r
440 Result = FmpCapsuleHeader.GetFmpCapsuleImageHeader (0).Payload\r
441 if args.Verbose:\r
442 print ('========')\r
443 UefiCapsuleHeader.DumpInfo ()\r
444 print ('--------')\r
445 FmpCapsuleHeader.DumpInfo ()\r
446 if UseSignTool or UseOpenSsl:\r
447 Result = FmpAuthHeader.Decode (Result)\r
448\r
449 #\r
450 # Verify Image with 64-bit MonotonicCount appended to end of image\r
451 #\r
452 try:\r
453 if UseSignTool:\r
454 CertData = VerifyPayloadSignTool (\r
455 FmpAuthHeader.Payload + struct.pack ('<Q', FmpAuthHeader.MonotonicCount),\r
456 FmpAuthHeader.CertData,\r
457 args.SigningToolPath,\r
458 args.SignToolPfxFile\r
459 )\r
460 else:\r
461 CertData = VerifyPayloadOpenSsl (\r
462 FmpAuthHeader.Payload + struct.pack ('<Q', FmpAuthHeader.MonotonicCount),\r
463 FmpAuthHeader.CertData,\r
464 args.SigningToolPath,\r
465 args.OpenSslSignerPrivateCertFile,\r
466 args.OpenSslOtherPublicCertFile,\r
467 args.OpenSslTrustedPublicCertFile\r
468 )\r
469 except ValueError:\r
470 print ('GenerateCapsule: warning: can not verify payload.')\r
471\r
472 Result = FmpPayloadHeader.Decode (Result)\r
473 if args.Verbose:\r
474 print ('--------')\r
475 FmpAuthHeader.DumpInfo ()\r
476 print ('--------')\r
477 FmpPayloadHeader.DumpInfo ()\r
478 else:\r
479 if args.Verbose:\r
480 print ('--------')\r
481 print ('No EFI_FIRMWARE_IMAGE_AUTHENTICATION')\r
482 print ('--------')\r
483 print ('No FMP_PAYLOAD_HEADER')\r
484 if args.Verbose:\r
485 print ('========')\r
486 except:\r
487 print ('GenerateCapsule: error: can not decode capsule')\r
488 raise\r
489 sys.exit (1)\r
490\r
491 elif args.DumpInfo:\r
492 try:\r
493 Result = UefiCapsuleHeader.Decode (Buffer)\r
494 FmpCapsuleHeader.Decode (Result)\r
495 Result = FmpCapsuleHeader.GetFmpCapsuleImageHeader (0).Payload\r
496 print ('========')\r
497 UefiCapsuleHeader.DumpInfo ()\r
498 print ('--------')\r
499 FmpCapsuleHeader.DumpInfo ()\r
500 try:\r
501 Result = FmpAuthHeader.Decode (Result)\r
502 Result = FmpPayloadHeader.Decode (Result)\r
503 print ('--------')\r
504 FmpAuthHeader.DumpInfo ()\r
505 print ('--------')\r
506 FmpPayloadHeader.DumpInfo ()\r
507 except:\r
508 print ('--------')\r
509 print ('No EFI_FIRMWARE_IMAGE_AUTHENTICATION')\r
510 print ('--------')\r
511 print ('No FMP_PAYLOAD_HEADER')\r
512 print ('========')\r
513 except:\r
514 print ('GenerateCapsule: error: can not decode capsule')\r
515 sys.exit (1)\r
516 else:\r
517 print('GenerateCapsule: error: invalid options')\r
518 sys.exit (1)\r
519\r
520 #\r
521 # Write binary output file\r
522 #\r
523 if args.OutputFile is not None:\r
524 try:\r
525 if args.Verbose:\r
526 print ('Write binary output file {File}'.format (File = args.OutputFile.name))\r
527 args.OutputFile.write (Result)\r
528 args.OutputFile.close ()\r
529 except:\r
530 print ('GenerateCapsule: error: can not write binary output file {File}'.format (File = args.OutputFile.name))\r
531 sys.exit (1)\r
532\r
533 if args.Verbose:\r
534 print('Success')\r