blob: 287019201a414bf6459c4266cee08ea048ad00c6 [file] [log] [blame]
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +08001# Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +08005"""A module to support automated testing of ChromeOS firmware.
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +08006
7Utilizes services provided by saft_flashrom_util.py read/write the
8flashrom chip and to parse the flash rom image.
9
10See docstring for FlashromHandler class below.
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +080011"""
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +080012
13import hashlib
14import os
15import struct
16
17class FvSection(object):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +080018 """An object to hold information about a firmware section.
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +080019
20 This includes file names for the signature header and the body, and the
21 version number.
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +080022 """
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +080023
24 def __init__(self, sig_name, body_name):
25 self._sig_name = sig_name
26 self._body_name = body_name
27 self._version = -1 # Is not set on construction.
28 self._flags = 0 # Is not set on construction.
29 self._sha = None # Is not set on construction.
30 self._datakey_version = -1 # Is not set on construction.
31 self._kernel_subkey_version = -1 # Is not set on construction.
32
33 def names(self):
34 return (self._sig_name, self._body_name)
35
36 def get_sig_name(self):
37 return self._sig_name
38
39 def get_body_name(self):
40 return self._body_name
41
42 def get_version(self):
43 return self._version
44
45 def get_flags(self):
46 return self._flags
47
48 def get_sha(self):
49 return self._sha
50
51 def get_datakey_version(self):
52 return self._datakey_version
53
54 def get_kernel_subkey_version(self):
55 return self._kernel_subkey_version
56
57 def set_version(self, version):
58 self._version = version
59
60 def set_flags(self, flags):
61 self._flags = flags
62
63 def set_sha(self, sha):
64 self._sha = sha
65
66 def set_datakey_version(self, version):
67 self._datakey_version = version
68
69 def set_kernel_subkey_version(self, version):
70 self._kernel_subkey_version = version
71
72class FlashromHandlerError(Exception):
73 pass
74
75
76class FlashromHandler(object):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +080077 """An object to provide logical services for automated flashrom testing."""
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +080078
79 DELTA = 1 # value to add to a byte to corrupt a section contents
80
81 # File in the state directory to store public root key.
82 PUB_KEY_FILE_NAME = 'root.pubkey'
83 FW_KEYBLOCK_FILE_NAME = 'firmware.keyblock'
84 FW_PRIV_DATA_KEY_FILE_NAME = 'firmware_data_key.vbprivk'
85 KERNEL_SUBKEY_FILE_NAME = 'kernel_subkey.vbpubk'
86
87 def __init__(self):
88 # make sure it does not accidentally overwrite the image.
89 self.fum = None
90 self.chros_if = None
91 self.image = ''
92 self.pub_key_file = ''
93
94 def init(self, flashrom_util_module,
95 chros_if,
96 pub_key_file=None,
97 dev_key_path='./',
98 target='bios'):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +080099 """Flashrom handler initializer.
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800100
101 Args:
102 flashrom_util_module - a module providing flashrom access utilities.
103 chros_if - a module providing interface to Chromium OS services
104 pub_key_file - a string, name of the file contaning a public key to
105 use for verifying both existing and new firmware.
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800106 """
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800107 if target == 'bios':
108 self.fum = flashrom_util_module.flashrom_util(target_is_ec=False)
109 self.fv_sections = {
110 'a': FvSection('VBOOTA', 'FVMAIN'),
111 'b': FvSection('VBOOTB', 'FVMAINB'),
112 }
113 elif target == 'ec':
114 self.fum = flashrom_util_module.flashrom_util(target_is_ec=True)
115 self.fv_sections = {
116 'rw': FvSection(None, 'EC_RW'),
117 }
118 else:
119 raise FlashromHandlerError("Invalid target.")
120 self.chros_if = chros_if
121 self.pub_key_file = pub_key_file
122 self.dev_key_path = dev_key_path
123
124 def new_image(self, image_file=None):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800125 """Parse the full flashrom image and store sections into files.
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800126
127 Args:
128 image_file - a string, the name of the file contaning full ChromeOS
129 flashrom image. If not passed in or empty - the actual
130 flashrom is read and its contents are saved into a
131 temporary file which is used instead.
132
133 The input file is parsed and the sections of importance (as defined in
134 self.fv_sections) are saved in separate files in the state directory
135 as defined in the chros_if object.
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800136 """
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800137
138 if image_file:
139 self.image = open(image_file, 'rb').read()
140 self.fum.set_firmware_layout(image_file)
141 else:
142 self.image = self.fum.read_whole()
143
144 for section in self.fv_sections.itervalues():
145 for subsection_name in section.names():
146 if not subsection_name:
147 continue
148 f = open(self.chros_if.state_dir_file(subsection_name), 'wb')
149 f.write(self.fum.get_section(self.image, subsection_name))
150 f.close()
151
152 s = hashlib.sha1()
153 s.update(self.fum.get_section(self.image, section.get_body_name()))
154 section.set_sha(s.hexdigest())
155
156 # If there is no "sig" subsection, skip reading version and flags.
157 if not section.get_sig_name():
158 continue
159
160 # Now determine this section's version number.
161 vb_section = self.fum.get_section(
162 self.image, section.get_sig_name())
163
164 section.set_version(self.chros_if.retrieve_body_version(vb_section))
165 section.set_flags(self.chros_if.retrieve_preamble_flags(vb_section))
166 section.set_datakey_version(
167 self.chros_if.retrieve_datakey_version(vb_section))
168 section.set_kernel_subkey_version(
169 self.chros_if.retrieve_kernel_subkey_version(vb_section))
170
171 if not self.pub_key_file:
172 self._retrieve_pub_key()
173
174 def _retrieve_pub_key(self):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800175 """Retrieve root public key from the firmware GBB section."""
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800176
177 gbb_header_format = '<4s20s2I'
178 pubk_header_format = '<2Q'
179
180 gbb_section = self.fum.get_section(self.image, 'FV_GBB')
181
182 # do some sanity checks
183 try:
184 sig, _, rootk_offs, rootk_size = struct.unpack_from(
185 gbb_header_format, gbb_section)
186 except struct.error, e:
187 raise FlashromHandlerError(e)
188
189 if sig != '$GBB' or (rootk_offs + rootk_size) > len(gbb_section):
190 raise FlashromHandlerError('Bad gbb header')
191
192 key_body_offset, key_body_size = struct.unpack_from(
193 pubk_header_format, gbb_section, rootk_offs)
194
195 # Generally speaking the offset field can be anything, but in case of
196 # GBB section the key is stored as a standalone entity, so the offset
197 # of the key body is expected to be equal to the key header size of
198 # 0x20.
199 # Should this convention change, the check below would fail, which
200 # would be a good prompt for revisiting this test's behavior and
201 # algorithms.
202 if key_body_offset != 0x20 or key_body_size > rootk_size:
203 raise FlashromHandlerError('Bad public key format')
204
205 # All checks passed, let's store the key in a file.
206 self.pub_key_file = self.chros_if.state_dir_file(self.PUB_KEY_FILE_NAME)
207 keyf = open(self.pub_key_file, 'w')
208 key = gbb_section[
209 rootk_offs:rootk_offs + key_body_offset + key_body_size]
210 keyf.write(key)
211 keyf.close()
212
213 def verify_image(self):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800214 """Confirm the image's validity.
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800215
216 Using the file supplied to init() as the public key container verify
217 the two sections' (FirmwareA and FirmwareB) integrity. The contents of
218 the sections is taken from the files created by new_image()
219
220 In case there is an integrity error raises FlashromHandlerError
221 exception with the appropriate error message text.
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800222 """
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800223
224 for section in self.fv_sections.itervalues():
225 cmd = 'vbutil_firmware --verify %s --signpubkey %s --fv %s' % (
226 self.chros_if.state_dir_file(section.get_sig_name()),
227 self.pub_key_file,
228 self.chros_if.state_dir_file(section.get_body_name()))
229 self.chros_if.run_shell_command(cmd)
230
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800231 def _modify_section(self, section, delta, body_or_sig=False,
232 corrupt_all=False):
233 """Modify a firmware section inside the image, either body or signature.
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800234
235 If corrupt_all is set, the passed in delta is added to all bytes in the
236 section. Otherwise, the delta is added to the value located at 2% offset
237 into the section blob, either body or signature.
238
239 Calling this function again for the same section the complimentary
240 delta value would restore the section contents.
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800241 """
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800242
243 if not self.image:
244 raise FlashromHandlerError(
245 'Attempt at using an uninitialized object')
246 if section not in self.fv_sections:
247 raise FlashromHandlerError('Unknown FW section %s'
248 % section)
249
250 # Get the appropriate section of the image.
251 if body_or_sig:
252 subsection_name = self.fv_sections[section].get_body_name()
253 else:
254 subsection_name = self.fv_sections[section].get_sig_name()
255 blob = self.fum.get_section(self.image, subsection_name)
256
257 # Modify the byte in it within 2% of the section blob.
258 modified_index = len(blob) / 50
259 if corrupt_all:
260 blob_list = [('%c' % ((ord(x) + delta) % 0x100)) for x in blob]
261 else:
262 blob_list = list(blob)
263 blob_list[modified_index] = ('%c' %
264 ((ord(blob[modified_index]) + delta) % 0x100))
265 self.image = self.fum.put_section(self.image,
266 subsection_name, ''.join(blob_list))
267
268 return subsection_name
269
270 def corrupt_section(self, section, corrupt_all=False):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800271 """Corrupt a section signature of the image"""
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800272
273 return self._modify_section(section, self.DELTA, body_or_sig=False,
274 corrupt_all=corrupt_all)
275
276 def corrupt_section_body(self, section, corrupt_all=False):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800277 """Corrupt a section body of the image"""
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800278
279 return self._modify_section(section, self.DELTA, body_or_sig=True,
280 corrupt_all=corrupt_all)
281
282 def restore_section(self, section, restore_all=False):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800283 """Restore a previously corrupted section signature of the image."""
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800284
285 return self._modify_section(section, -self.DELTA, body_or_sig=False,
286 corrupt_all=restore_all)
287
288 def restore_section_body(self, section, restore_all=False):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800289 """Restore a previously corrupted section body of the image."""
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800290
291 return self._modify_section(section, -self.DELTA, body_or_sig=True,
292 corrupt_all=restore_all)
293
294 def corrupt_firmware(self, section, corrupt_all=False):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800295 """Corrupt a section signature in the FLASHROM!!!"""
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800296
297 subsection_name = self.corrupt_section(section, corrupt_all=corrupt_all)
298 self.fum.write_partial(self.image, (subsection_name, ))
299
300 def corrupt_firmware_body(self, section, corrupt_all=False):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800301 """Corrupt a section body in the FLASHROM!!!"""
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800302
303 subsection_name = self.corrupt_section_body(section,
304 corrupt_all=corrupt_all)
305 self.fum.write_partial(self.image, (subsection_name, ))
306
307 def restore_firmware(self, section, restore_all=False):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800308 """Restore the previously corrupted section sig in the FLASHROM!!!"""
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800309
310 subsection_name = self.restore_section(section, restore_all=restore_all)
311 self.fum.write_partial(self.image, (subsection_name, ))
312
313 def restore_firmware_body(self, section, restore_all=False):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800314 """Restore the previously corrupted section body in the FLASHROM!!!"""
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800315
316 subsection_name = self.restore_section_body(section,
317 restore_all=False)
318 self.fum.write_partial(self.image, (subsection_name, ))
319
320 def firmware_sections_equal(self):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800321 """Check if firmware sections A and B are equal.
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800322
323 This function presumes that the entire BIOS image integrity has been
324 verified, so different signature sections mean different images and
325 vice versa.
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800326 """
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800327 sig_a = self.fum.get_section(self.image,
328 self.fv_sections['a'].get_sig_name())
329 sig_b = self.fum.get_section(self.image,
330 self.fv_sections['b'].get_sig_name())
331 return sig_a == sig_b
332
333 def copy_from_to(self, src, dst):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800334 """Copy one firmware image section to another.
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800335
336 This function copies both signature and body of one firmware section
337 into another. After this function runs both sections are identical.
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800338 """
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800339 src_sect = self.fv_sections[src]
340 dst_sect = self.fv_sections[dst]
341 self.image = self.fum.put_section(
342 self.image,
343 dst_sect.get_body_name(),
344 self.fum.get_section(self.image, src_sect.get_body_name()))
345 self.image = self.fum.put_section(
346 self.image,
347 dst_sect.get_sig_name(),
348 self.fum.get_section(self.image, src_sect.get_sig_name()))
349
350 def write_whole(self):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800351 """Write the whole image into the flashrom."""
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800352
353 if not self.image:
354 raise FlashromHandlerError(
355 'Attempt at using an uninitialized object')
356 self.fum.write_whole(self.image)
357
358 def dump_whole(self, filename):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800359 """Write the whole image into a file."""
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800360
361 if not self.image:
362 raise FlashromHandlerError(
363 'Attempt at using an uninitialized object')
364 open(filename, 'w').write(self.image)
365
366 def dump_partial(self, subsection_name, filename):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800367 """Write the subsection part into a file."""
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800368
369 if not self.image:
370 raise FlashromHandlerError(
371 'Attempt at using an uninitialized object')
372 blob = self.fum.get_section(self.image, subsection_name)
373 open(filename, 'w').write(blob)
374
375 def get_gbb_flags(self):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800376 """Retrieve the GBB flags"""
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800377 gbb_header_format = '<12sL'
378 gbb_section = self.fum.get_section(self.image, 'FV_GBB')
379 try:
380 _, gbb_flags = struct.unpack_from(gbb_header_format, gbb_section)
381 except struct.error, e:
382 raise FlashromHandlerError(e)
383 return gbb_flags
384
385 def get_section_sha(self, section):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800386 """Retrieve SHA1 hash of a firmware body section"""
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800387 return self.fv_sections[section].get_sha()
388
389 def get_section_version(self, section):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800390 """Retrieve version number of a firmware section"""
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800391 return self.fv_sections[section].get_version()
392
393 def get_section_flags(self, section):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800394 """Retrieve preamble flags of a firmware section"""
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800395 return self.fv_sections[section].get_flags()
396
397 def get_section_datakey_version(self, section):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800398 """Retrieve data key version number of a firmware section"""
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800399 return self.fv_sections[section].get_datakey_version()
400
401 def get_section_kernel_subkey_version(self, section):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800402 """Retrieve kernel subkey version number of a firmware section"""
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800403 return self.fv_sections[section].get_kernel_subkey_version()
404
405 def get_section_body(self, section):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800406 """Retrieve body of a firmware section"""
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800407 subsection_name = self.fv_sections[section].get_body_name()
408 blob = self.fum.get_section(self.image, subsection_name)
409 return blob
410
411 def _find_ecbin_offset(self, blob):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800412 """Return the offset of EC binary from the given firmware blob"""
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800413 # The RW firmware is concatenated from u-boot, dtb, and ecbin.
414 # Search the magic of dtb to locate the dtb bloc.
415 dtb_offset = blob.index("\xD0\x0D\xFE\xED\x00")
416 # The dtb size is a 32-bit integer which follows the magic.
417 _, dtb_size = struct.unpack_from(">2L", blob, dtb_offset)
418 # The ecbin part is aligned to 4-byte.
419 ecbin_offset = (dtb_offset + dtb_size + 3) & ~3
420 return ecbin_offset
421
422 def _find_ecbin_size_offset_on_dtb(self, blob):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800423 """Return the offset of EC binary size on the DTB blob"""
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800424 # We now temporarily use this hack to find the offset.
425 # TODO(waihong@chromium.org): Should use fdtget to get the field and
426 # fdtput to change it.
427 dtb_offset = blob.index("\xD0\x0D\xFE\xED\x00")
428 prop_offset = blob.index("blob boot,dtb,ecbin", dtb_offset) + 0x18
429 ecbin_size_offset = blob.index("ecbin", prop_offset) + 0x18
430 return ecbin_size_offset
431
432 def get_section_ecbin(self, section):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800433 """Retrieve EC binary of a firmware section"""
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800434 blob = self.get_section_body(section)
435 ecbin_offset = self._find_ecbin_offset(blob)
436 # Remove the pads of ecbin.
437 pad = blob[-1]
438 ecbin = blob[ecbin_offset :].rstrip(pad)
439 return ecbin
440
441 def set_section_body(self, section, blob):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800442 """Put the supplied blob to the body of the firmware section"""
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800443 subsection_name = self.fv_sections[section].get_body_name()
444 self.image = self.fum.put_section(self.image, subsection_name, blob)
445
446 def set_section_ecbin(self, section, ecbin, write_through=False):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800447 """Put the supplied EC binary to the firwmare section.
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800448
449 Note that the updated firmware image is not signed yet. Should call
450 set_section_version() afterward.
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800451 """
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800452 # Remove unncessary padding bytes.
453 pad = '\xff'
454 ecbin_align = 4
455 ecbin = ecbin.rstrip(pad)
456 ecbin += pad * ((ecbin_align - 1) - (len(ecbin) - 1) % ecbin_align)
457 ecbin_size = len(ecbin)
458
459 # Put the ecbin into the firmware body.
460 old_blob = self.get_section_body(section)
461 ecbin_offset = self._find_ecbin_offset(old_blob)
462 pad = old_blob[-1]
463 pad_size = len(old_blob) - ecbin_offset - ecbin_size
464 new_blob = old_blob[0 : ecbin_offset] + ecbin + pad * pad_size
465
466 # Modify the ecbin size on dtb.
467 size_offset = self._find_ecbin_size_offset_on_dtb(new_blob)
468 new_blob = (new_blob[0 : size_offset] + struct.pack('>L', ecbin_size) +
469 new_blob[size_offset + 4 :])
470
471 self.set_section_body(section, new_blob)
472 if write_through:
473 subsection_name = self.fv_sections[section].get_body_name()
474 self.dump_partial(subsection_name,
475 self.chros_if.state_dir_file(subsection_name))
476 self.fum.write_partial(self.image, (subsection_name, ))
477
478 def set_section_version(self, section, version, flags,
479 write_through=False):
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800480 """
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800481 Re-sign the firmware section using the supplied version number and
482 flag.
Tom Wai-Hong Tambe153282012-09-13 13:56:16 +0800483 """
Tom Wai-Hong Tamc0168912012-09-13 13:24:02 +0800484 if (self.get_section_version(section) == version and
485 self.get_section_flags(section) == flags):
486 return # No version or flag change, nothing to do.
487 if version < 0:
488 raise FlashromHandlerError(
489 'Attempt to set version %d on section %s' % (version, section))
490 fv_section = self.fv_sections[section]
491 sig_name = self.chros_if.state_dir_file(fv_section.get_sig_name())
492 sig_size = os.path.getsize(sig_name)
493
494 # Construct the command line
495 args = ['--vblock %s' % sig_name]
496 args.append('--keyblock %s' % os.path.join(
497 self.dev_key_path, self.FW_KEYBLOCK_FILE_NAME))
498 args.append('--fv %s' % self.chros_if.state_dir_file(
499 fv_section.get_body_name()))
500 args.append('--version %d' % version)
501 args.append('--kernelkey %s' % os.path.join(
502 self.dev_key_path, self.KERNEL_SUBKEY_FILE_NAME))
503 args.append('--signprivate %s' % os.path.join(
504 self.dev_key_path, self.FW_PRIV_DATA_KEY_FILE_NAME))
505 args.append('--flags %d' % flags)
506 cmd = 'vbutil_firmware %s' % ' '.join(args)
507 self.chros_if.run_shell_command(cmd)
508
509 # Pad the new signature.
510 new_sig = open(sig_name, 'a')
511 pad = ('%c' % 0xff) * (sig_size - os.path.getsize(sig_name))
512 new_sig.write(pad)
513 new_sig.close()
514
515 # Inject the new signature block into the image
516 new_sig = open(sig_name, 'r').read()
517 self.image = self.fum.put_section(
518 self.image, fv_section.get_sig_name(), new_sig)
519 if write_through:
520 self.fum.write_partial(self.image, (fv_section.get_sig_name(), ))