1#!/usr/bin/env python
2
3# Copyright 2016, The Android Open Source Project
4#
5# Permission is hereby granted, free of charge, to any person
6# obtaining a copy of this software and associated documentation
7# files (the "Software"), to deal in the Software without
8# restriction, including without limitation the rights to use, copy,
9# modify, merge, publish, distribute, sublicense, and/or sell copies
10# of the Software, and to permit persons to whom the Software is
11# furnished to do so, subject to the following conditions:
12#
13# The above copyright notice and this permission notice shall be
14# included in all copies or substantial portions of the Software.
15#
16# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23# SOFTWARE.
24#
25"""Command-line tool for working with Android Verified Boot images."""
26
27import argparse
28import binascii
29import bisect
30import hashlib
31import math
32import os
33import struct
34import subprocess
35import sys
36import tempfile
37import time
38
39# Keep in sync with libavb/avb_version.h.
40AVB_VERSION_MAJOR = 1
41AVB_VERSION_MINOR = 1
42AVB_VERSION_SUB = 0
43
44# Keep in sync with libavb/avb_footer.h.
45AVB_FOOTER_VERSION_MAJOR = 1
46AVB_FOOTER_VERSION_MINOR = 0
47
48AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED = 1
49
50
51class AvbError(Exception):
52  """Application-specific errors.
53
54  These errors represent issues for which a stack-trace should not be
55  presented.
56
57  Attributes:
58    message: Error message.
59  """
60
61  def __init__(self, message):
62    Exception.__init__(self, message)
63
64
65class Algorithm(object):
66  """Contains details about an algorithm.
67
68  See the avb_vbmeta_image.h file for more details about algorithms.
69
70  The constant |ALGORITHMS| is a dictionary from human-readable
71  names (e.g 'SHA256_RSA2048') to instances of this class.
72
73  Attributes:
74    algorithm_type: Integer code corresponding to |AvbAlgorithmType|.
75    hash_name: Empty or a name from |hashlib.algorithms|.
76    hash_num_bytes: Number of bytes used to store the hash.
77    signature_num_bytes: Number of bytes used to store the signature.
78    public_key_num_bytes: Number of bytes used to store the public key.
79    padding: Padding used for signature, if any.
80  """
81
82  def __init__(self, algorithm_type, hash_name, hash_num_bytes,
83               signature_num_bytes, public_key_num_bytes, padding):
84    self.algorithm_type = algorithm_type
85    self.hash_name = hash_name
86    self.hash_num_bytes = hash_num_bytes
87    self.signature_num_bytes = signature_num_bytes
88    self.public_key_num_bytes = public_key_num_bytes
89    self.padding = padding
90
91
92# This must be kept in sync with the avb_crypto.h file.
93#
94# The PKC1-v1.5 padding is a blob of binary DER of ASN.1 and is
95# obtained from section 5.2.2 of RFC 4880.
96ALGORITHMS = {
97    'NONE': Algorithm(
98        algorithm_type=0,        # AVB_ALGORITHM_TYPE_NONE
99        hash_name='',
100        hash_num_bytes=0,
101        signature_num_bytes=0,
102        public_key_num_bytes=0,
103        padding=[]),
104    'SHA256_RSA2048': Algorithm(
105        algorithm_type=1,        # AVB_ALGORITHM_TYPE_SHA256_RSA2048
106        hash_name='sha256',
107        hash_num_bytes=32,
108        signature_num_bytes=256,
109        public_key_num_bytes=8 + 2*2048/8,
110        padding=[
111            # PKCS1-v1_5 padding
112            0x00, 0x01] + [0xff]*202 + [0x00] + [
113                # ASN.1 header
114                0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
115                0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05,
116                0x00, 0x04, 0x20,
117            ]),
118    'SHA256_RSA4096': Algorithm(
119        algorithm_type=2,        # AVB_ALGORITHM_TYPE_SHA256_RSA4096
120        hash_name='sha256',
121        hash_num_bytes=32,
122        signature_num_bytes=512,
123        public_key_num_bytes=8 + 2*4096/8,
124        padding=[
125            # PKCS1-v1_5 padding
126            0x00, 0x01] + [0xff]*458 + [0x00] + [
127                # ASN.1 header
128                0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
129                0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05,
130                0x00, 0x04, 0x20,
131            ]),
132    'SHA256_RSA8192': Algorithm(
133        algorithm_type=3,        # AVB_ALGORITHM_TYPE_SHA256_RSA8192
134        hash_name='sha256',
135        hash_num_bytes=32,
136        signature_num_bytes=1024,
137        public_key_num_bytes=8 + 2*8192/8,
138        padding=[
139            # PKCS1-v1_5 padding
140            0x00, 0x01] + [0xff]*970 + [0x00] + [
141                # ASN.1 header
142                0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
143                0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05,
144                0x00, 0x04, 0x20,
145            ]),
146    'SHA512_RSA2048': Algorithm(
147        algorithm_type=4,        # AVB_ALGORITHM_TYPE_SHA512_RSA2048
148        hash_name='sha512',
149        hash_num_bytes=64,
150        signature_num_bytes=256,
151        public_key_num_bytes=8 + 2*2048/8,
152        padding=[
153            # PKCS1-v1_5 padding
154            0x00, 0x01] + [0xff]*170 + [0x00] + [
155                # ASN.1 header
156                0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
157                0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05,
158                0x00, 0x04, 0x40
159            ]),
160    'SHA512_RSA4096': Algorithm(
161        algorithm_type=5,        # AVB_ALGORITHM_TYPE_SHA512_RSA4096
162        hash_name='sha512',
163        hash_num_bytes=64,
164        signature_num_bytes=512,
165        public_key_num_bytes=8 + 2*4096/8,
166        padding=[
167            # PKCS1-v1_5 padding
168            0x00, 0x01] + [0xff]*426 + [0x00] + [
169                # ASN.1 header
170                0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
171                0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05,
172                0x00, 0x04, 0x40
173            ]),
174    'SHA512_RSA8192': Algorithm(
175        algorithm_type=6,        # AVB_ALGORITHM_TYPE_SHA512_RSA8192
176        hash_name='sha512',
177        hash_num_bytes=64,
178        signature_num_bytes=1024,
179        public_key_num_bytes=8 + 2*8192/8,
180        padding=[
181            # PKCS1-v1_5 padding
182            0x00, 0x01] + [0xff]*938 + [0x00] + [
183                # ASN.1 header
184                0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
185                0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05,
186                0x00, 0x04, 0x40
187            ]),
188}
189
190
191def get_release_string():
192  """Calculates the release string to use in the VBMeta struct."""
193  # Keep in sync with libavb/avb_version.c:avb_version_string().
194  return 'avbtool {}.{}.{}'.format(AVB_VERSION_MAJOR,
195                                   AVB_VERSION_MINOR,
196                                   AVB_VERSION_SUB)
197
198
199def round_to_multiple(number, size):
200  """Rounds a number up to nearest multiple of another number.
201
202  Args:
203    number: The number to round up.
204    size: The multiple to round up to.
205
206  Returns:
207    If |number| is a multiple of |size|, returns |number|, otherwise
208    returns |number| + |size|.
209  """
210  remainder = number % size
211  if remainder == 0:
212    return number
213  return number + size - remainder
214
215
216def round_to_pow2(number):
217  """Rounds a number up to the next power of 2.
218
219  Args:
220    number: The number to round up.
221
222  Returns:
223    If |number| is already a power of 2 then |number| is
224    returned. Otherwise the smallest power of 2 greater than |number|
225    is returned.
226  """
227  return 2**((number - 1).bit_length())
228
229
230def encode_long(num_bits, value):
231  """Encodes a long to a bytearray() using a given amount of bits.
232
233  This number is written big-endian, e.g. with the most significant
234  bit first.
235
236  This is the reverse of decode_long().
237
238  Arguments:
239    num_bits: The number of bits to write, e.g. 2048.
240    value: The value to write.
241
242  Returns:
243    A bytearray() with the encoded long.
244  """
245  ret = bytearray()
246  for bit_pos in range(num_bits, 0, -8):
247    octet = (value >> (bit_pos - 8)) & 0xff
248    ret.extend(struct.pack('!B', octet))
249  return ret
250
251
252def decode_long(blob):
253  """Decodes a long from a bytearray() using a given amount of bits.
254
255  This number is expected to be in big-endian, e.g. with the most
256  significant bit first.
257
258  This is the reverse of encode_long().
259
260  Arguments:
261    value: A bytearray() with the encoded long.
262
263  Returns:
264    The decoded value.
265  """
266  ret = 0
267  for b in bytearray(blob):
268    ret *= 256
269    ret += b
270  return ret
271
272
273def egcd(a, b):
274  """Calculate greatest common divisor of two numbers.
275
276  This implementation uses a recursive version of the extended
277  Euclidian algorithm.
278
279  Arguments:
280    a: First number.
281    b: Second number.
282
283  Returns:
284    A tuple (gcd, x, y) that where |gcd| is the greatest common
285    divisor of |a| and |b| and |a|*|x| + |b|*|y| = |gcd|.
286  """
287  if a == 0:
288    return (b, 0, 1)
289  else:
290    g, y, x = egcd(b % a, a)
291    return (g, x - (b // a) * y, y)
292
293
294def modinv(a, m):
295  """Calculate modular multiplicative inverse of |a| modulo |m|.
296
297  This calculates the number |x| such that |a| * |x| == 1 (modulo
298  |m|). This number only exists if |a| and |m| are co-prime - |None|
299  is returned if this isn't true.
300
301  Arguments:
302    a: The number to calculate a modular inverse of.
303    m: The modulo to use.
304
305  Returns:
306    The modular multiplicative inverse of |a| and |m| or |None| if
307    these numbers are not co-prime.
308  """
309  gcd, x, _ = egcd(a, m)
310  if gcd != 1:
311    return None  # modular inverse does not exist
312  else:
313    return x % m
314
315
316def parse_number(string):
317  """Parse a string as a number.
318
319  This is just a short-hand for int(string, 0) suitable for use in the
320  |type| parameter of |ArgumentParser|'s add_argument() function. An
321  improvement to just using type=int is that this function supports
322  numbers in other bases, e.g. "0x1234".
323
324  Arguments:
325    string: The string to parse.
326
327  Returns:
328    The parsed integer.
329
330  Raises:
331    ValueError: If the number could not be parsed.
332  """
333  return int(string, 0)
334
335
336class RSAPublicKey(object):
337  """Data structure used for a RSA public key.
338
339  Attributes:
340    exponent: The key exponent.
341    modulus: The key modulus.
342    num_bits: The key size.
343  """
344
345  MODULUS_PREFIX = 'modulus='
346
347  def __init__(self, key_path):
348    """Loads and parses an RSA key from either a private or public key file.
349
350    Arguments:
351      key_path: The path to a key file.
352    """
353    # We used to have something as simple as this:
354    #
355    #  key = Crypto.PublicKey.RSA.importKey(open(key_path).read())
356    #  self.exponent = key.e
357    #  self.modulus = key.n
358    #  self.num_bits = key.size() + 1
359    #
360    # but unfortunately PyCrypto is not available in the builder. So
361    # instead just parse openssl(1) output to get this
362    # information. It's ugly but...
363    args = ['openssl', 'rsa', '-in', key_path, '-modulus', '-noout']
364    p = subprocess.Popen(args,
365                         stdin=subprocess.PIPE,
366                         stdout=subprocess.PIPE,
367                         stderr=subprocess.PIPE)
368    (pout, perr) = p.communicate()
369    if p.wait() != 0:
370      # Could be just a public key is passed, try that.
371      args.append('-pubin')
372      p = subprocess.Popen(args,
373                           stdin=subprocess.PIPE,
374                           stdout=subprocess.PIPE,
375                           stderr=subprocess.PIPE)
376      (pout, perr) = p.communicate()
377      if p.wait() != 0:
378        raise AvbError('Error getting public key: {}'.format(perr))
379
380    if not pout.lower().startswith(self.MODULUS_PREFIX):
381      raise AvbError('Unexpected modulus output')
382
383    modulus_hexstr = pout[len(self.MODULUS_PREFIX):]
384
385    # The exponent is assumed to always be 65537 and the number of
386    # bits can be derived from the modulus by rounding up to the
387    # nearest power of 2.
388    self.modulus = int(modulus_hexstr, 16)
389    self.num_bits = round_to_pow2(int(math.ceil(math.log(self.modulus, 2))))
390    self.exponent = 65537
391
392
393def encode_rsa_key(key_path):
394  """Encodes a public RSA key in |AvbRSAPublicKeyHeader| format.
395
396  This creates a |AvbRSAPublicKeyHeader| as well as the two large
397  numbers (|key_num_bits| bits long) following it.
398
399  Arguments:
400    key_path: The path to a key file.
401
402  Returns:
403    A bytearray() with the |AvbRSAPublicKeyHeader|.
404  """
405  key = RSAPublicKey(key_path)
406  if key.exponent != 65537:
407    raise AvbError('Only RSA keys with exponent 65537 are supported.')
408  ret = bytearray()
409  # Calculate n0inv = -1/n[0] (mod 2^32)
410  b = 2L**32
411  n0inv = b - modinv(key.modulus, b)
412  # Calculate rr = r^2 (mod N), where r = 2^(# of key bits)
413  r = 2L**key.modulus.bit_length()
414  rrmodn = r * r % key.modulus
415  ret.extend(struct.pack('!II', key.num_bits, n0inv))
416  ret.extend(encode_long(key.num_bits, key.modulus))
417  ret.extend(encode_long(key.num_bits, rrmodn))
418  return ret
419
420
421def lookup_algorithm_by_type(alg_type):
422  """Looks up algorithm by type.
423
424  Arguments:
425    alg_type: The integer representing the type.
426
427  Returns:
428    A tuple with the algorithm name and an |Algorithm| instance.
429
430  Raises:
431    Exception: If the algorithm cannot be found
432  """
433  for alg_name in ALGORITHMS:
434    alg_data = ALGORITHMS[alg_name]
435    if alg_data.algorithm_type == alg_type:
436      return (alg_name, alg_data)
437  raise AvbError('Unknown algorithm type {}'.format(alg_type))
438
439
440def raw_sign(signing_helper, signing_helper_with_files,
441             algorithm_name, signature_num_bytes, key_path,
442             raw_data_to_sign):
443  """Computes a raw RSA signature using |signing_helper| or openssl.
444
445  Arguments:
446    signing_helper: Program which signs a hash and returns the signature.
447    signing_helper_with_files: Same as signing_helper but uses files instead.
448    algorithm_name: The algorithm name as per the ALGORITHMS dict.
449    signature_num_bytes: Number of bytes used to store the signature.
450    key_path: Path to the private key file. Must be PEM format.
451    raw_data_to_sign: Data to sign (bytearray or str expected).
452
453  Returns:
454    A bytearray containing the signature.
455
456  Raises:
457    Exception: If an error occurs.
458  """
459  p = None
460  if signing_helper_with_files is not None:
461    signing_file = tempfile.NamedTemporaryFile()
462    signing_file.write(str(raw_data_to_sign))
463    signing_file.flush()
464    p = subprocess.Popen(
465      [signing_helper_with_files, algorithm_name, key_path, signing_file.name])
466    retcode = p.wait()
467    if retcode != 0:
468      raise AvbError('Error signing')
469    signing_file.seek(0)
470    signature = bytearray(signing_file.read())
471  else:
472    if signing_helper is not None:
473      p = subprocess.Popen(
474          [signing_helper, algorithm_name, key_path],
475          stdin=subprocess.PIPE,
476          stdout=subprocess.PIPE,
477          stderr=subprocess.PIPE)
478    else:
479      p = subprocess.Popen(
480          ['openssl', 'rsautl', '-sign', '-inkey', key_path, '-raw'],
481          stdin=subprocess.PIPE,
482          stdout=subprocess.PIPE,
483          stderr=subprocess.PIPE)
484    (pout, perr) = p.communicate(str(raw_data_to_sign))
485    retcode = p.wait()
486    if retcode != 0:
487      raise AvbError('Error signing: {}'.format(perr))
488    signature = bytearray(pout)
489  if len(signature) != signature_num_bytes:
490    raise AvbError('Error signing: Invalid length of signature')
491  return signature
492
493
494def verify_vbmeta_signature(vbmeta_header, vbmeta_blob):
495  """Checks that the signature in a vbmeta blob was made by
496     the embedded public key.
497
498  Arguments:
499    vbmeta_header: A AvbVBMetaHeader.
500    vbmeta_blob: The whole vbmeta blob, including the header.
501
502  Returns:
503    True if the signature is valid and corresponds to the embedded
504    public key. Also returns True if the vbmeta blob is not signed.
505  """
506  (_, alg) = lookup_algorithm_by_type(vbmeta_header.algorithm_type)
507  if alg.hash_name == '':
508    return True
509  header_blob = vbmeta_blob[0:256]
510  auth_offset = 256
511  aux_offset = auth_offset + vbmeta_header.authentication_data_block_size
512  aux_size = vbmeta_header.auxiliary_data_block_size
513  aux_blob = vbmeta_blob[aux_offset:aux_offset + aux_size]
514  pubkey_offset = aux_offset + vbmeta_header.public_key_offset
515  pubkey_size = vbmeta_header.public_key_size
516  pubkey_blob = vbmeta_blob[pubkey_offset:pubkey_offset + pubkey_size]
517
518  digest_offset = auth_offset + vbmeta_header.hash_offset
519  digest_size = vbmeta_header.hash_size
520  digest_blob = vbmeta_blob[digest_offset:digest_offset + digest_size]
521
522  sig_offset = auth_offset + vbmeta_header.signature_offset
523  sig_size = vbmeta_header.signature_size
524  sig_blob = vbmeta_blob[sig_offset:sig_offset + sig_size]
525
526  # Now that we've got the stored digest, public key, and signature
527  # all we need to do is to verify. This is the exactly the same
528  # steps as performed in the avb_vbmeta_image_verify() function in
529  # libavb/avb_vbmeta_image.c.
530
531  ha = hashlib.new(alg.hash_name)
532  ha.update(header_blob)
533  ha.update(aux_blob)
534  computed_digest = ha.digest()
535
536  if computed_digest != digest_blob:
537    return False
538
539  padding_and_digest = bytearray(alg.padding)
540  padding_and_digest.extend(computed_digest)
541
542  (num_bits,) = struct.unpack('!I', pubkey_blob[0:4])
543  modulus_blob = pubkey_blob[8:8 + num_bits/8]
544  modulus = decode_long(modulus_blob)
545  exponent = 65537
546
547  # For now, just use Crypto.PublicKey.RSA to verify the signature. This
548  # is OK since 'avbtool verify_image' is not expected to run on the
549  # Android builders (see bug #36809096).
550  import Crypto.PublicKey.RSA
551  key = Crypto.PublicKey.RSA.construct((modulus, long(exponent)))
552  if not key.verify(decode_long(padding_and_digest),
553                    (decode_long(sig_blob), None)):
554    return False
555  return True
556
557
558class ImageChunk(object):
559  """Data structure used for representing chunks in Android sparse files.
560
561  Attributes:
562    chunk_type: One of TYPE_RAW, TYPE_FILL, or TYPE_DONT_CARE.
563    chunk_offset: Offset in the sparse file where this chunk begins.
564    output_offset: Offset in de-sparsified file where output begins.
565    output_size: Number of bytes in output.
566    input_offset: Offset in sparse file for data if TYPE_RAW otherwise None.
567    fill_data: Blob with data to fill if TYPE_FILL otherwise None.
568  """
569
570  FORMAT = '<2H2I'
571  TYPE_RAW = 0xcac1
572  TYPE_FILL = 0xcac2
573  TYPE_DONT_CARE = 0xcac3
574  TYPE_CRC32 = 0xcac4
575
576  def __init__(self, chunk_type, chunk_offset, output_offset, output_size,
577               input_offset, fill_data):
578    """Initializes an ImageChunk object.
579
580    Arguments:
581      chunk_type: One of TYPE_RAW, TYPE_FILL, or TYPE_DONT_CARE.
582      chunk_offset: Offset in the sparse file where this chunk begins.
583      output_offset: Offset in de-sparsified file.
584      output_size: Number of bytes in output.
585      input_offset: Offset in sparse file if TYPE_RAW otherwise None.
586      fill_data: Blob with data to fill if TYPE_FILL otherwise None.
587
588    Raises:
589      ValueError: If data is not well-formed.
590    """
591    self.chunk_type = chunk_type
592    self.chunk_offset = chunk_offset
593    self.output_offset = output_offset
594    self.output_size = output_size
595    self.input_offset = input_offset
596    self.fill_data = fill_data
597    # Check invariants.
598    if self.chunk_type == self.TYPE_RAW:
599      if self.fill_data is not None:
600        raise ValueError('RAW chunk cannot have fill_data set.')
601      if not self.input_offset:
602        raise ValueError('RAW chunk must have input_offset set.')
603    elif self.chunk_type == self.TYPE_FILL:
604      if self.fill_data is None:
605        raise ValueError('FILL chunk must have fill_data set.')
606      if self.input_offset:
607        raise ValueError('FILL chunk cannot have input_offset set.')
608    elif self.chunk_type == self.TYPE_DONT_CARE:
609      if self.fill_data is not None:
610        raise ValueError('DONT_CARE chunk cannot have fill_data set.')
611      if self.input_offset:
612        raise ValueError('DONT_CARE chunk cannot have input_offset set.')
613    else:
614      raise ValueError('Invalid chunk type')
615
616
617class ImageHandler(object):
618  """Abstraction for image I/O with support for Android sparse images.
619
620  This class provides an interface for working with image files that
621  may be using the Android Sparse Image format. When an instance is
622  constructed, we test whether it's an Android sparse file. If so,
623  operations will be on the sparse file by interpreting the sparse
624  format, otherwise they will be directly on the file. Either way the
625  operations do the same.
626
627  For reading, this interface mimics a file object - it has seek(),
628  tell(), and read() methods. For writing, only truncation
629  (truncate()) and appending is supported (append_raw() and
630  append_dont_care()). Additionally, data can only be written in units
631  of the block size.
632
633  Attributes:
634    filename: Name of file.
635    is_sparse: Whether the file being operated on is sparse.
636    block_size: The block size, typically 4096.
637    image_size: The size of the unsparsified file.
638  """
639  # See system/core/libsparse/sparse_format.h for details.
640  MAGIC = 0xed26ff3a
641  HEADER_FORMAT = '<I4H4I'
642
643  # These are formats and offset of just the |total_chunks| and
644  # |total_blocks| fields.
645  NUM_CHUNKS_AND_BLOCKS_FORMAT = '<II'
646  NUM_CHUNKS_AND_BLOCKS_OFFSET = 16
647
648  def __init__(self, image_filename):
649    """Initializes an image handler.
650
651    Arguments:
652      image_filename: The name of the file to operate on.
653
654    Raises:
655      ValueError: If data in the file is invalid.
656    """
657    self.filename = image_filename
658    self._read_header()
659
660  def _read_header(self):
661    """Initializes internal data structures used for reading file.
662
663    This may be called multiple times and is typically called after
664    modifying the file (e.g. appending, truncation).
665
666    Raises:
667      ValueError: If data in the file is invalid.
668    """
669    self.is_sparse = False
670    self.block_size = 4096
671    self._file_pos = 0
672    self._image = open(self.filename, 'r+b')
673    self._image.seek(0, os.SEEK_END)
674    self.image_size = self._image.tell()
675
676    self._image.seek(0, os.SEEK_SET)
677    header_bin = self._image.read(struct.calcsize(self.HEADER_FORMAT))
678    (magic, major_version, minor_version, file_hdr_sz, chunk_hdr_sz,
679     block_size, self._num_total_blocks, self._num_total_chunks,
680     _) = struct.unpack(self.HEADER_FORMAT, header_bin)
681    if magic != self.MAGIC:
682      # Not a sparse image, our job here is done.
683      return
684    if not (major_version == 1 and minor_version == 0):
685      raise ValueError('Encountered sparse image format version {}.{} but '
686                       'only 1.0 is supported'.format(major_version,
687                                                      minor_version))
688    if file_hdr_sz != struct.calcsize(self.HEADER_FORMAT):
689      raise ValueError('Unexpected file_hdr_sz value {}.'.
690                       format(file_hdr_sz))
691    if chunk_hdr_sz != struct.calcsize(ImageChunk.FORMAT):
692      raise ValueError('Unexpected chunk_hdr_sz value {}.'.
693                       format(chunk_hdr_sz))
694
695    self.block_size = block_size
696
697    # Build an list of chunks by parsing the file.
698    self._chunks = []
699
700    # Find the smallest offset where only "Don't care" chunks
701    # follow. This will be the size of the content in the sparse
702    # image.
703    offset = 0
704    output_offset = 0
705    for _ in xrange(1, self._num_total_chunks + 1):
706      chunk_offset = self._image.tell()
707
708      header_bin = self._image.read(struct.calcsize(ImageChunk.FORMAT))
709      (chunk_type, _, chunk_sz, total_sz) = struct.unpack(ImageChunk.FORMAT,
710                                                          header_bin)
711      data_sz = total_sz - struct.calcsize(ImageChunk.FORMAT)
712
713      if chunk_type == ImageChunk.TYPE_RAW:
714        if data_sz != (chunk_sz * self.block_size):
715          raise ValueError('Raw chunk input size ({}) does not match output '
716                           'size ({})'.
717                           format(data_sz, chunk_sz*self.block_size))
718        self._chunks.append(ImageChunk(ImageChunk.TYPE_RAW,
719                                       chunk_offset,
720                                       output_offset,
721                                       chunk_sz*self.block_size,
722                                       self._image.tell(),
723                                       None))
724        self._image.seek(data_sz, os.SEEK_CUR)
725
726      elif chunk_type == ImageChunk.TYPE_FILL:
727        if data_sz != 4:
728          raise ValueError('Fill chunk should have 4 bytes of fill, but this '
729                           'has {}'.format(data_sz))
730        fill_data = self._image.read(4)
731        self._chunks.append(ImageChunk(ImageChunk.TYPE_FILL,
732                                       chunk_offset,
733                                       output_offset,
734                                       chunk_sz*self.block_size,
735                                       None,
736                                       fill_data))
737      elif chunk_type == ImageChunk.TYPE_DONT_CARE:
738        if data_sz != 0:
739          raise ValueError('Don\'t care chunk input size is non-zero ({})'.
740                           format(data_sz))
741        self._chunks.append(ImageChunk(ImageChunk.TYPE_DONT_CARE,
742                                       chunk_offset,
743                                       output_offset,
744                                       chunk_sz*self.block_size,
745                                       None,
746                                       None))
747      elif chunk_type == ImageChunk.TYPE_CRC32:
748        if data_sz != 4:
749          raise ValueError('CRC32 chunk should have 4 bytes of CRC, but '
750                           'this has {}'.format(data_sz))
751        self._image.read(4)
752      else:
753        raise ValueError('Unknown chunk type {}'.format(chunk_type))
754
755      offset += chunk_sz
756      output_offset += chunk_sz*self.block_size
757
758    # Record where sparse data end.
759    self._sparse_end = self._image.tell()
760
761    # Now that we've traversed all chunks, sanity check.
762    if self._num_total_blocks != offset:
763      raise ValueError('The header said we should have {} output blocks, '
764                       'but we saw {}'.format(self._num_total_blocks, offset))
765    junk_len = len(self._image.read())
766    if junk_len > 0:
767      raise ValueError('There were {} bytes of extra data at the end of the '
768                       'file.'.format(junk_len))
769
770    # Assign |image_size|.
771    self.image_size = output_offset
772
773    # This is used when bisecting in read() to find the initial slice.
774    self._chunk_output_offsets = [i.output_offset for i in self._chunks]
775
776    self.is_sparse = True
777
778  def _update_chunks_and_blocks(self):
779    """Helper function to update the image header.
780
781    The the |total_chunks| and |total_blocks| fields in the header
782    will be set to value of the |_num_total_blocks| and
783    |_num_total_chunks| attributes.
784
785    """
786    self._image.seek(self.NUM_CHUNKS_AND_BLOCKS_OFFSET, os.SEEK_SET)
787    self._image.write(struct.pack(self.NUM_CHUNKS_AND_BLOCKS_FORMAT,
788                                  self._num_total_blocks,
789                                  self._num_total_chunks))
790
791  def append_dont_care(self, num_bytes):
792    """Appends a DONT_CARE chunk to the sparse file.
793
794    The given number of bytes must be a multiple of the block size.
795
796    Arguments:
797      num_bytes: Size in number of bytes of the DONT_CARE chunk.
798    """
799    assert num_bytes % self.block_size == 0
800
801    if not self.is_sparse:
802      self._image.seek(0, os.SEEK_END)
803      # This is more efficient that writing NUL bytes since it'll add
804      # a hole on file systems that support sparse files (native
805      # sparse, not Android sparse).
806      self._image.truncate(self._image.tell() + num_bytes)
807      self._read_header()
808      return
809
810    self._num_total_chunks += 1
811    self._num_total_blocks += num_bytes / self.block_size
812    self._update_chunks_and_blocks()
813
814    self._image.seek(self._sparse_end, os.SEEK_SET)
815    self._image.write(struct.pack(ImageChunk.FORMAT,
816                                  ImageChunk.TYPE_DONT_CARE,
817                                  0,  # Reserved
818                                  num_bytes / self.block_size,
819                                  struct.calcsize(ImageChunk.FORMAT)))
820    self._read_header()
821
822  def append_raw(self, data):
823    """Appends a RAW chunk to the sparse file.
824
825    The length of the given data must be a multiple of the block size.
826
827    Arguments:
828      data: Data to append.
829    """
830    assert len(data) % self.block_size == 0
831
832    if not self.is_sparse:
833      self._image.seek(0, os.SEEK_END)
834      self._image.write(data)
835      self._read_header()
836      return
837
838    self._num_total_chunks += 1
839    self._num_total_blocks += len(data) / self.block_size
840    self._update_chunks_and_blocks()
841
842    self._image.seek(self._sparse_end, os.SEEK_SET)
843    self._image.write(struct.pack(ImageChunk.FORMAT,
844                                  ImageChunk.TYPE_RAW,
845                                  0,  # Reserved
846                                  len(data) / self.block_size,
847                                  len(data) +
848                                  struct.calcsize(ImageChunk.FORMAT)))
849    self._image.write(data)
850    self._read_header()
851
852  def append_fill(self, fill_data, size):
853    """Appends a fill chunk to the sparse file.
854
855    The total length of the fill data must be a multiple of the block size.
856
857    Arguments:
858      fill_data: Fill data to append - must be four bytes.
859      size: Number of chunk - must be a multiple of four and the block size.
860    """
861    assert len(fill_data) == 4
862    assert size % 4 == 0
863    assert size % self.block_size == 0
864
865    if not self.is_sparse:
866      self._image.seek(0, os.SEEK_END)
867      self._image.write(fill_data * (size/4))
868      self._read_header()
869      return
870
871    self._num_total_chunks += 1
872    self._num_total_blocks += size / self.block_size
873    self._update_chunks_and_blocks()
874
875    self._image.seek(self._sparse_end, os.SEEK_SET)
876    self._image.write(struct.pack(ImageChunk.FORMAT,
877                                  ImageChunk.TYPE_FILL,
878                                  0,  # Reserved
879                                  size / self.block_size,
880                                  4 + struct.calcsize(ImageChunk.FORMAT)))
881    self._image.write(fill_data)
882    self._read_header()
883
884  def seek(self, offset):
885    """Sets the cursor position for reading from unsparsified file.
886
887    Arguments:
888      offset: Offset to seek to from the beginning of the file.
889    """
890    if offset < 0:
891      raise RuntimeError("Seeking with negative offset: %d" % offset)
892    self._file_pos = offset
893
894  def read(self, size):
895    """Reads data from the unsparsified file.
896
897    This method may return fewer than |size| bytes of data if the end
898    of the file was encountered.
899
900    The file cursor for reading is advanced by the number of bytes
901    read.
902
903    Arguments:
904      size: Number of bytes to read.
905
906    Returns:
907      The data.
908
909    """
910    if not self.is_sparse:
911      self._image.seek(self._file_pos)
912      data = self._image.read(size)
913      self._file_pos += len(data)
914      return data
915
916    # Iterate over all chunks.
917    chunk_idx = bisect.bisect_right(self._chunk_output_offsets,
918                                    self._file_pos) - 1
919    data = bytearray()
920    to_go = size
921    while to_go > 0:
922      chunk = self._chunks[chunk_idx]
923      chunk_pos_offset = self._file_pos - chunk.output_offset
924      chunk_pos_to_go = min(chunk.output_size - chunk_pos_offset, to_go)
925
926      if chunk.chunk_type == ImageChunk.TYPE_RAW:
927        self._image.seek(chunk.input_offset + chunk_pos_offset)
928        data.extend(self._image.read(chunk_pos_to_go))
929      elif chunk.chunk_type == ImageChunk.TYPE_FILL:
930        all_data = chunk.fill_data*(chunk_pos_to_go/len(chunk.fill_data) + 2)
931        offset_mod = chunk_pos_offset % len(chunk.fill_data)
932        data.extend(all_data[offset_mod:(offset_mod + chunk_pos_to_go)])
933      else:
934        assert chunk.chunk_type == ImageChunk.TYPE_DONT_CARE
935        data.extend('\0' * chunk_pos_to_go)
936
937      to_go -= chunk_pos_to_go
938      self._file_pos += chunk_pos_to_go
939      chunk_idx += 1
940      # Generate partial read in case of EOF.
941      if chunk_idx >= len(self._chunks):
942        break
943
944    return data
945
946  def tell(self):
947    """Returns the file cursor position for reading from unsparsified file.
948
949    Returns:
950      The file cursor position for reading.
951    """
952    return self._file_pos
953
954  def truncate(self, size):
955    """Truncates the unsparsified file.
956
957    Arguments:
958      size: Desired size of unsparsified file.
959
960    Raises:
961      ValueError: If desired size isn't a multiple of the block size.
962    """
963    if not self.is_sparse:
964      self._image.truncate(size)
965      self._read_header()
966      return
967
968    if size % self.block_size != 0:
969      raise ValueError('Cannot truncate to a size which is not a multiple '
970                       'of the block size')
971
972    if size == self.image_size:
973      # Trivial where there's nothing to do.
974      return
975    elif size < self.image_size:
976      chunk_idx = bisect.bisect_right(self._chunk_output_offsets, size) - 1
977      chunk = self._chunks[chunk_idx]
978      if chunk.output_offset != size:
979        # Truncation in the middle of a trunk - need to keep the chunk
980        # and modify it.
981        chunk_idx_for_update = chunk_idx + 1
982        num_to_keep = size - chunk.output_offset
983        assert num_to_keep % self.block_size == 0
984        if chunk.chunk_type == ImageChunk.TYPE_RAW:
985          truncate_at = (chunk.chunk_offset +
986                         struct.calcsize(ImageChunk.FORMAT) + num_to_keep)
987          data_sz = num_to_keep
988        elif chunk.chunk_type == ImageChunk.TYPE_FILL:
989          truncate_at = (chunk.chunk_offset +
990                         struct.calcsize(ImageChunk.FORMAT) + 4)
991          data_sz = 4
992        else:
993          assert chunk.chunk_type == ImageChunk.TYPE_DONT_CARE
994          truncate_at = chunk.chunk_offset + struct.calcsize(ImageChunk.FORMAT)
995          data_sz = 0
996        chunk_sz = num_to_keep/self.block_size
997        total_sz = data_sz + struct.calcsize(ImageChunk.FORMAT)
998        self._image.seek(chunk.chunk_offset)
999        self._image.write(struct.pack(ImageChunk.FORMAT,
1000                                      chunk.chunk_type,
1001                                      0,  # Reserved
1002                                      chunk_sz,
1003                                      total_sz))
1004        chunk.output_size = num_to_keep
1005      else:
1006        # Truncation at trunk boundary.
1007        truncate_at = chunk.chunk_offset
1008        chunk_idx_for_update = chunk_idx
1009
1010      self._num_total_chunks = chunk_idx_for_update
1011      self._num_total_blocks = 0
1012      for i in range(0, chunk_idx_for_update):
1013        self._num_total_blocks += self._chunks[i].output_size / self.block_size
1014      self._update_chunks_and_blocks()
1015      self._image.truncate(truncate_at)
1016
1017      # We've modified the file so re-read all data.
1018      self._read_header()
1019    else:
1020      # Truncating to grow - just add a DONT_CARE section.
1021      self.append_dont_care(size - self.image_size)
1022
1023
1024class AvbDescriptor(object):
1025  """Class for AVB descriptor.
1026
1027  See the |AvbDescriptor| C struct for more information.
1028
1029  Attributes:
1030    tag: The tag identifying what kind of descriptor this is.
1031    data: The data in the descriptor.
1032  """
1033
1034  SIZE = 16
1035  FORMAT_STRING = ('!QQ')  # tag, num_bytes_following (descriptor header)
1036
1037  def __init__(self, data):
1038    """Initializes a new property descriptor.
1039
1040    Arguments:
1041      data: If not None, must be a bytearray().
1042
1043    Raises:
1044      LookupError: If the given descriptor is malformed.
1045    """
1046    assert struct.calcsize(self.FORMAT_STRING) == self.SIZE
1047
1048    if data:
1049      (self.tag, num_bytes_following) = (
1050          struct.unpack(self.FORMAT_STRING, data[0:self.SIZE]))
1051      self.data = data[self.SIZE:self.SIZE + num_bytes_following]
1052    else:
1053      self.tag = None
1054      self.data = None
1055
1056  def print_desc(self, o):
1057    """Print the descriptor.
1058
1059    Arguments:
1060      o: The object to write the output to.
1061    """
1062    o.write('    Unknown descriptor:\n')
1063    o.write('      Tag:  {}\n'.format(self.tag))
1064    if len(self.data) < 256:
1065      o.write('      Data: {} ({} bytes)\n'.format(
1066          repr(str(self.data)), len(self.data)))
1067    else:
1068      o.write('      Data: {} bytes\n'.format(len(self.data)))
1069
1070  def encode(self):
1071    """Serializes the descriptor.
1072
1073    Returns:
1074      A bytearray() with the descriptor data.
1075    """
1076    num_bytes_following = len(self.data)
1077    nbf_with_padding = round_to_multiple(num_bytes_following, 8)
1078    padding_size = nbf_with_padding - num_bytes_following
1079    desc = struct.pack(self.FORMAT_STRING, self.tag, nbf_with_padding)
1080    padding = struct.pack(str(padding_size) + 'x')
1081    ret = desc + self.data + padding
1082    return bytearray(ret)
1083
1084  def verify(self, image_dir, image_ext, expected_chain_partitions_map,
1085             image_containing_descriptor):
1086    """Verifies contents of the descriptor - used in verify_image sub-command.
1087
1088    Arguments:
1089      image_dir: The directory of the file being verified.
1090      image_ext: The extension of the file being verified (e.g. '.img').
1091      expected_chain_partitions_map: A map from partition name to the
1092        tuple (rollback_index_location, key_blob).
1093      image_containing_descriptor: The image the descriptor is in.
1094
1095    Returns:
1096      True if the descriptor verifies, False otherwise.
1097    """
1098    # Nothing to do.
1099    return True
1100
1101class AvbPropertyDescriptor(AvbDescriptor):
1102  """A class for property descriptors.
1103
1104  See the |AvbPropertyDescriptor| C struct for more information.
1105
1106  Attributes:
1107    key: The key.
1108    value: The key.
1109  """
1110
1111  TAG = 0
1112  SIZE = 32
1113  FORMAT_STRING = ('!QQ'  # tag, num_bytes_following (descriptor header)
1114                   'Q'  # key size (bytes)
1115                   'Q')  # value size (bytes)
1116
1117  def __init__(self, data=None):
1118    """Initializes a new property descriptor.
1119
1120    Arguments:
1121      data: If not None, must be a bytearray of size |SIZE|.
1122
1123    Raises:
1124      LookupError: If the given descriptor is malformed.
1125    """
1126    AvbDescriptor.__init__(self, None)
1127    assert struct.calcsize(self.FORMAT_STRING) == self.SIZE
1128
1129    if data:
1130      (tag, num_bytes_following, key_size,
1131       value_size) = struct.unpack(self.FORMAT_STRING, data[0:self.SIZE])
1132      expected_size = round_to_multiple(
1133          self.SIZE - 16 + key_size + 1 + value_size + 1, 8)
1134      if tag != self.TAG or num_bytes_following != expected_size:
1135        raise LookupError('Given data does not look like a property '
1136                          'descriptor.')
1137      self.key = data[self.SIZE:(self.SIZE + key_size)]
1138      self.value = data[(self.SIZE + key_size + 1):(self.SIZE + key_size + 1 +
1139                                                    value_size)]
1140    else:
1141      self.key = ''
1142      self.value = ''
1143
1144  def print_desc(self, o):
1145    """Print the descriptor.
1146
1147    Arguments:
1148      o: The object to write the output to.
1149    """
1150    if len(self.value) < 256:
1151      o.write('    Prop: {} -> {}\n'.format(self.key, repr(str(self.value))))
1152    else:
1153      o.write('    Prop: {} -> ({} bytes)\n'.format(self.key, len(self.value)))
1154
1155  def encode(self):
1156    """Serializes the descriptor.
1157
1158    Returns:
1159      A bytearray() with the descriptor data.
1160    """
1161    num_bytes_following = self.SIZE + len(self.key) + len(self.value) + 2 - 16
1162    nbf_with_padding = round_to_multiple(num_bytes_following, 8)
1163    padding_size = nbf_with_padding - num_bytes_following
1164    desc = struct.pack(self.FORMAT_STRING, self.TAG, nbf_with_padding,
1165                       len(self.key), len(self.value))
1166    padding = struct.pack(str(padding_size) + 'x')
1167    ret = desc + self.key + '\0' + self.value + '\0' + padding
1168    return bytearray(ret)
1169
1170  def verify(self, image_dir, image_ext, expected_chain_partitions_map,
1171             image_containing_descriptor):
1172    """Verifies contents of the descriptor - used in verify_image sub-command.
1173
1174    Arguments:
1175      image_dir: The directory of the file being verified.
1176      image_ext: The extension of the file being verified (e.g. '.img').
1177      expected_chain_partitions_map: A map from partition name to the
1178        tuple (rollback_index_location, key_blob).
1179      image_containing_descriptor: The image the descriptor is in.
1180
1181    Returns:
1182      True if the descriptor verifies, False otherwise.
1183    """
1184    # Nothing to do.
1185    return True
1186
1187class AvbHashtreeDescriptor(AvbDescriptor):
1188  """A class for hashtree descriptors.
1189
1190  See the |AvbHashtreeDescriptor| C struct for more information.
1191
1192  Attributes:
1193    dm_verity_version: dm-verity version used.
1194    image_size: Size of the image, after rounding up to |block_size|.
1195    tree_offset: Offset of the hash tree in the file.
1196    tree_size: Size of the tree.
1197    data_block_size: Data block size
1198    hash_block_size: Hash block size
1199    fec_num_roots: Number of roots used for FEC (0 if FEC is not used).
1200    fec_offset: Offset of FEC data (0 if FEC is not used).
1201    fec_size: Size of FEC data (0 if FEC is not used).
1202    hash_algorithm: Hash algorithm used.
1203    partition_name: Partition name.
1204    salt: Salt used.
1205    root_digest: Root digest.
1206    flags: Descriptor flags (see avb_hashtree_descriptor.h).
1207  """
1208
1209  TAG = 1
1210  RESERVED = 60
1211  SIZE = 120 + RESERVED
1212  FORMAT_STRING = ('!QQ'  # tag, num_bytes_following (descriptor header)
1213                   'L'  # dm-verity version used
1214                   'Q'  # image size (bytes)
1215                   'Q'  # tree offset (bytes)
1216                   'Q'  # tree size (bytes)
1217                   'L'  # data block size (bytes)
1218                   'L'  # hash block size (bytes)
1219                   'L'  # FEC number of roots
1220                   'Q'  # FEC offset (bytes)
1221                   'Q'  # FEC size (bytes)
1222                   '32s'  # hash algorithm used
1223                   'L'  # partition name (bytes)
1224                   'L'  # salt length (bytes)
1225                   'L'  # root digest length (bytes)
1226                   'L' +  # flags
1227                   str(RESERVED) + 's')  # reserved
1228
1229  def __init__(self, data=None):
1230    """Initializes a new hashtree descriptor.
1231
1232    Arguments:
1233      data: If not None, must be a bytearray of size |SIZE|.
1234
1235    Raises:
1236      LookupError: If the given descriptor is malformed.
1237    """
1238    AvbDescriptor.__init__(self, None)
1239    assert struct.calcsize(self.FORMAT_STRING) == self.SIZE
1240
1241    if data:
1242      (tag, num_bytes_following, self.dm_verity_version, self.image_size,
1243       self.tree_offset, self.tree_size, self.data_block_size,
1244       self.hash_block_size, self.fec_num_roots, self.fec_offset, self.fec_size,
1245       self.hash_algorithm, partition_name_len, salt_len,
1246       root_digest_len, self.flags, _) = struct.unpack(self.FORMAT_STRING,
1247                                                       data[0:self.SIZE])
1248      expected_size = round_to_multiple(
1249          self.SIZE - 16 + partition_name_len + salt_len + root_digest_len, 8)
1250      if tag != self.TAG or num_bytes_following != expected_size:
1251        raise LookupError('Given data does not look like a hashtree '
1252                          'descriptor.')
1253      # Nuke NUL-bytes at the end.
1254      self.hash_algorithm = self.hash_algorithm.split('\0', 1)[0]
1255      o = 0
1256      self.partition_name = str(data[(self.SIZE + o):(self.SIZE + o +
1257                                                      partition_name_len)])
1258      # Validate UTF-8 - decode() raises UnicodeDecodeError if not valid UTF-8.
1259      self.partition_name.decode('utf-8')
1260      o += partition_name_len
1261      self.salt = data[(self.SIZE + o):(self.SIZE + o + salt_len)]
1262      o += salt_len
1263      self.root_digest = data[(self.SIZE + o):(self.SIZE + o + root_digest_len)]
1264      if root_digest_len != len(hashlib.new(name=self.hash_algorithm).digest()):
1265        if root_digest_len != 0:
1266          raise LookupError('root_digest_len doesn\'t match hash algorithm')
1267
1268    else:
1269      self.dm_verity_version = 0
1270      self.image_size = 0
1271      self.tree_offset = 0
1272      self.tree_size = 0
1273      self.data_block_size = 0
1274      self.hash_block_size = 0
1275      self.fec_num_roots = 0
1276      self.fec_offset = 0
1277      self.fec_size = 0
1278      self.hash_algorithm = ''
1279      self.partition_name = ''
1280      self.salt = bytearray()
1281      self.root_digest = bytearray()
1282      self.flags = 0
1283
1284  def print_desc(self, o):
1285    """Print the descriptor.
1286
1287    Arguments:
1288      o: The object to write the output to.
1289    """
1290    o.write('    Hashtree descriptor:\n')
1291    o.write('      Version of dm-verity:  {}\n'.format(self.dm_verity_version))
1292    o.write('      Image Size:            {} bytes\n'.format(self.image_size))
1293    o.write('      Tree Offset:           {}\n'.format(self.tree_offset))
1294    o.write('      Tree Size:             {} bytes\n'.format(self.tree_size))
1295    o.write('      Data Block Size:       {} bytes\n'.format(
1296        self.data_block_size))
1297    o.write('      Hash Block Size:       {} bytes\n'.format(
1298        self.hash_block_size))
1299    o.write('      FEC num roots:         {}\n'.format(self.fec_num_roots))
1300    o.write('      FEC offset:            {}\n'.format(self.fec_offset))
1301    o.write('      FEC size:              {} bytes\n'.format(self.fec_size))
1302    o.write('      Hash Algorithm:        {}\n'.format(self.hash_algorithm))
1303    o.write('      Partition Name:        {}\n'.format(self.partition_name))
1304    o.write('      Salt:                  {}\n'.format(str(self.salt).encode(
1305        'hex')))
1306    o.write('      Root Digest:           {}\n'.format(str(
1307        self.root_digest).encode('hex')))
1308    o.write('      Flags:                 {}\n'.format(self.flags))
1309
1310  def encode(self):
1311    """Serializes the descriptor.
1312
1313    Returns:
1314      A bytearray() with the descriptor data.
1315    """
1316    encoded_name = self.partition_name.encode('utf-8')
1317    num_bytes_following = (self.SIZE + len(encoded_name) + len(self.salt) +
1318                           len(self.root_digest) - 16)
1319    nbf_with_padding = round_to_multiple(num_bytes_following, 8)
1320    padding_size = nbf_with_padding - num_bytes_following
1321    desc = struct.pack(self.FORMAT_STRING, self.TAG, nbf_with_padding,
1322                       self.dm_verity_version, self.image_size,
1323                       self.tree_offset, self.tree_size, self.data_block_size,
1324                       self.hash_block_size, self.fec_num_roots,
1325                       self.fec_offset, self.fec_size, self.hash_algorithm,
1326                       len(encoded_name), len(self.salt), len(self.root_digest),
1327                       self.flags, self.RESERVED*'\0')
1328    padding = struct.pack(str(padding_size) + 'x')
1329    ret = desc + encoded_name + self.salt + self.root_digest + padding
1330    return bytearray(ret)
1331
1332  def verify(self, image_dir, image_ext, expected_chain_partitions_map,
1333             image_containing_descriptor):
1334    """Verifies contents of the descriptor - used in verify_image sub-command.
1335
1336    Arguments:
1337      image_dir: The directory of the file being verified.
1338      image_ext: The extension of the file being verified (e.g. '.img').
1339      expected_chain_partitions_map: A map from partition name to the
1340        tuple (rollback_index_location, key_blob).
1341      image_containing_descriptor: The image the descriptor is in.
1342
1343    Returns:
1344      True if the descriptor verifies, False otherwise.
1345    """
1346    if self.partition_name == '':
1347      image = image_containing_descriptor
1348    else:
1349      image_filename = os.path.join(image_dir, self.partition_name + image_ext)
1350      image = ImageHandler(image_filename)
1351    # Generate the hashtree and checks that it matches what's in the file.
1352    digest_size = len(hashlib.new(name=self.hash_algorithm).digest())
1353    digest_padding = round_to_pow2(digest_size) - digest_size
1354    (hash_level_offsets, tree_size) = calc_hash_level_offsets(
1355      self.image_size, self.data_block_size, digest_size + digest_padding)
1356    root_digest, hash_tree = generate_hash_tree(image, self.image_size,
1357                                                self.data_block_size,
1358                                                self.hash_algorithm, self.salt,
1359                                                digest_padding,
1360                                                hash_level_offsets,
1361                                                tree_size)
1362    # The root digest must match unless it is not embedded in the descriptor.
1363    if len(self.root_digest) != 0 and root_digest != self.root_digest:
1364      sys.stderr.write('hashtree of {} does not match descriptor\n'.
1365                       format(image_filename))
1366      return False
1367    # ... also check that the on-disk hashtree matches
1368    image.seek(self.tree_offset)
1369    hash_tree_ondisk = image.read(self.tree_size)
1370    if hash_tree != hash_tree_ondisk:
1371      sys.stderr.write('hashtree of {} contains invalid data\n'.
1372                       format(image_filename))
1373      return False
1374    # TODO: we could also verify that the FEC stored in the image is
1375    # correct but this a) currently requires the 'fec' binary; and b)
1376    # takes a long time; and c) is not strictly needed for
1377    # verification purposes as we've already verified the root hash.
1378    print ('{}: Successfully verified {} hashtree of {} for image of {} bytes'
1379           .format(self.partition_name, self.hash_algorithm, image.filename,
1380                   self.image_size))
1381    return True
1382
1383
1384class AvbHashDescriptor(AvbDescriptor):
1385  """A class for hash descriptors.
1386
1387  See the |AvbHashDescriptor| C struct for more information.
1388
1389  Attributes:
1390    image_size: Image size, in bytes.
1391    hash_algorithm: Hash algorithm used.
1392    partition_name: Partition name.
1393    salt: Salt used.
1394    digest: The hash value of salt and data combined.
1395    flags: The descriptor flags (see avb_hash_descriptor.h).
1396  """
1397
1398  TAG = 2
1399  RESERVED = 60
1400  SIZE = 72 + RESERVED
1401  FORMAT_STRING = ('!QQ'  # tag, num_bytes_following (descriptor header)
1402                   'Q'  # image size (bytes)
1403                   '32s'  # hash algorithm used
1404                   'L'  # partition name (bytes)
1405                   'L'  # salt length (bytes)
1406                   'L'  # digest length (bytes)
1407                   'L' +  # flags
1408                   str(RESERVED) + 's')  # reserved
1409
1410  def __init__(self, data=None):
1411    """Initializes a new hash descriptor.
1412
1413    Arguments:
1414      data: If not None, must be a bytearray of size |SIZE|.
1415
1416    Raises:
1417      LookupError: If the given descriptor is malformed.
1418    """
1419    AvbDescriptor.__init__(self, None)
1420    assert struct.calcsize(self.FORMAT_STRING) == self.SIZE
1421
1422    if data:
1423      (tag, num_bytes_following, self.image_size, self.hash_algorithm,
1424       partition_name_len, salt_len,
1425       digest_len, self.flags, _) = struct.unpack(self.FORMAT_STRING,
1426                                                  data[0:self.SIZE])
1427      expected_size = round_to_multiple(
1428          self.SIZE - 16 + partition_name_len + salt_len + digest_len, 8)
1429      if tag != self.TAG or num_bytes_following != expected_size:
1430        raise LookupError('Given data does not look like a hash ' 'descriptor.')
1431      # Nuke NUL-bytes at the end.
1432      self.hash_algorithm = self.hash_algorithm.split('\0', 1)[0]
1433      o = 0
1434      self.partition_name = str(data[(self.SIZE + o):(self.SIZE + o +
1435                                                      partition_name_len)])
1436      # Validate UTF-8 - decode() raises UnicodeDecodeError if not valid UTF-8.
1437      self.partition_name.decode('utf-8')
1438      o += partition_name_len
1439      self.salt = data[(self.SIZE + o):(self.SIZE + o + salt_len)]
1440      o += salt_len
1441      self.digest = data[(self.SIZE + o):(self.SIZE + o + digest_len)]
1442      if digest_len != len(hashlib.new(name=self.hash_algorithm).digest()):
1443        if digest_len != 0:
1444          raise LookupError('digest_len doesn\'t match hash algorithm')
1445
1446    else:
1447      self.image_size = 0
1448      self.hash_algorithm = ''
1449      self.partition_name = ''
1450      self.salt = bytearray()
1451      self.digest = bytearray()
1452      self.flags = 0
1453
1454  def print_desc(self, o):
1455    """Print the descriptor.
1456
1457    Arguments:
1458      o: The object to write the output to.
1459    """
1460    o.write('    Hash descriptor:\n')
1461    o.write('      Image Size:            {} bytes\n'.format(self.image_size))
1462    o.write('      Hash Algorithm:        {}\n'.format(self.hash_algorithm))
1463    o.write('      Partition Name:        {}\n'.format(self.partition_name))
1464    o.write('      Salt:                  {}\n'.format(str(self.salt).encode(
1465        'hex')))
1466    o.write('      Digest:                {}\n'.format(str(self.digest).encode(
1467        'hex')))
1468    o.write('      Flags:                 {}\n'.format(self.flags))
1469
1470  def encode(self):
1471    """Serializes the descriptor.
1472
1473    Returns:
1474      A bytearray() with the descriptor data.
1475    """
1476    encoded_name = self.partition_name.encode('utf-8')
1477    num_bytes_following = (
1478        self.SIZE + len(encoded_name) + len(self.salt) + len(self.digest) - 16)
1479    nbf_with_padding = round_to_multiple(num_bytes_following, 8)
1480    padding_size = nbf_with_padding - num_bytes_following
1481    desc = struct.pack(self.FORMAT_STRING, self.TAG, nbf_with_padding,
1482                       self.image_size, self.hash_algorithm, len(encoded_name),
1483                       len(self.salt), len(self.digest), self.flags,
1484                       self.RESERVED*'\0')
1485    padding = struct.pack(str(padding_size) + 'x')
1486    ret = desc + encoded_name + self.salt + self.digest + padding
1487    return bytearray(ret)
1488
1489  def verify(self, image_dir, image_ext, expected_chain_partitions_map,
1490             image_containing_descriptor):
1491    """Verifies contents of the descriptor - used in verify_image sub-command.
1492
1493    Arguments:
1494      image_dir: The directory of the file being verified.
1495      image_ext: The extension of the file being verified (e.g. '.img').
1496      expected_chain_partitions_map: A map from partition name to the
1497        tuple (rollback_index_location, key_blob).
1498      image_containing_descriptor: The image the descriptor is in.
1499
1500    Returns:
1501      True if the descriptor verifies, False otherwise.
1502    """
1503    if self.partition_name == '':
1504      image = image_containing_descriptor
1505    else:
1506      image_filename = os.path.join(image_dir, self.partition_name + image_ext)
1507      image = ImageHandler(image_filename)
1508    data = image.read(self.image_size)
1509    ha = hashlib.new(self.hash_algorithm)
1510    ha.update(self.salt)
1511    ha.update(data)
1512    digest = ha.digest()
1513    # The digest must match unless there is no digest in the descriptor.
1514    if len(self.digest) != 0 and digest != self.digest:
1515      sys.stderr.write('{} digest of {} does not match digest in descriptor\n'.
1516                       format(self.hash_algorithm, image_filename))
1517      return False
1518    print ('{}: Successfully verified {} hash of {} for image of {} bytes'
1519           .format(self.partition_name, self.hash_algorithm, image.filename,
1520                   self.image_size))
1521    return True
1522
1523
1524class AvbKernelCmdlineDescriptor(AvbDescriptor):
1525  """A class for kernel command-line descriptors.
1526
1527  See the |AvbKernelCmdlineDescriptor| C struct for more information.
1528
1529  Attributes:
1530    flags: Flags.
1531    kernel_cmdline: The kernel command-line.
1532  """
1533
1534  TAG = 3
1535  SIZE = 24
1536  FORMAT_STRING = ('!QQ'  # tag, num_bytes_following (descriptor header)
1537                   'L'  # flags
1538                   'L')  # cmdline length (bytes)
1539
1540  FLAGS_USE_ONLY_IF_HASHTREE_NOT_DISABLED = (1 << 0)
1541  FLAGS_USE_ONLY_IF_HASHTREE_DISABLED = (1 << 1)
1542
1543  def __init__(self, data=None):
1544    """Initializes a new kernel cmdline descriptor.
1545
1546    Arguments:
1547      data: If not None, must be a bytearray of size |SIZE|.
1548
1549    Raises:
1550      LookupError: If the given descriptor is malformed.
1551    """
1552    AvbDescriptor.__init__(self, None)
1553    assert struct.calcsize(self.FORMAT_STRING) == self.SIZE
1554
1555    if data:
1556      (tag, num_bytes_following, self.flags, kernel_cmdline_length) = (
1557          struct.unpack(self.FORMAT_STRING, data[0:self.SIZE]))
1558      expected_size = round_to_multiple(self.SIZE - 16 + kernel_cmdline_length,
1559                                        8)
1560      if tag != self.TAG or num_bytes_following != expected_size:
1561        raise LookupError('Given data does not look like a kernel cmdline '
1562                          'descriptor.')
1563      # Nuke NUL-bytes at the end.
1564      self.kernel_cmdline = str(data[self.SIZE:(self.SIZE +
1565                                                kernel_cmdline_length)])
1566      # Validate UTF-8 - decode() raises UnicodeDecodeError if not valid UTF-8.
1567      self.kernel_cmdline.decode('utf-8')
1568    else:
1569      self.flags = 0
1570      self.kernel_cmdline = ''
1571
1572  def print_desc(self, o):
1573    """Print the descriptor.
1574
1575    Arguments:
1576      o: The object to write the output to.
1577    """
1578    o.write('    Kernel Cmdline descriptor:\n')
1579    o.write('      Flags:                 {}\n'.format(self.flags))
1580    o.write('      Kernel Cmdline:        {}\n'.format(repr(
1581        self.kernel_cmdline)))
1582
1583  def encode(self):
1584    """Serializes the descriptor.
1585
1586    Returns:
1587      A bytearray() with the descriptor data.
1588    """
1589    encoded_str = self.kernel_cmdline.encode('utf-8')
1590    num_bytes_following = (self.SIZE + len(encoded_str) - 16)
1591    nbf_with_padding = round_to_multiple(num_bytes_following, 8)
1592    padding_size = nbf_with_padding - num_bytes_following
1593    desc = struct.pack(self.FORMAT_STRING, self.TAG, nbf_with_padding,
1594                       self.flags, len(encoded_str))
1595    padding = struct.pack(str(padding_size) + 'x')
1596    ret = desc + encoded_str + padding
1597    return bytearray(ret)
1598
1599  def verify(self, image_dir, image_ext, expected_chain_partitions_map,
1600             image_containing_descriptor):
1601    """Verifies contents of the descriptor - used in verify_image sub-command.
1602
1603    Arguments:
1604      image_dir: The directory of the file being verified.
1605      image_ext: The extension of the file being verified (e.g. '.img').
1606      expected_chain_partitions_map: A map from partition name to the
1607        tuple (rollback_index_location, key_blob).
1608      image_containing_descriptor: The image the descriptor is in.
1609
1610    Returns:
1611      True if the descriptor verifies, False otherwise.
1612    """
1613    # Nothing to verify.
1614    return True
1615
1616class AvbChainPartitionDescriptor(AvbDescriptor):
1617  """A class for chained partition descriptors.
1618
1619  See the |AvbChainPartitionDescriptor| C struct for more information.
1620
1621  Attributes:
1622    rollback_index_location: The rollback index location to use.
1623    partition_name: Partition name.
1624    public_key: Bytes for the public key.
1625  """
1626
1627  TAG = 4
1628  RESERVED = 64
1629  SIZE = 28 + RESERVED
1630  FORMAT_STRING = ('!QQ'  # tag, num_bytes_following (descriptor header)
1631                   'L'  # rollback_index_location
1632                   'L'  # partition_name_size (bytes)
1633                   'L' +  # public_key_size (bytes)
1634                   str(RESERVED) + 's')  # reserved
1635
1636  def __init__(self, data=None):
1637    """Initializes a new chain partition descriptor.
1638
1639    Arguments:
1640      data: If not None, must be a bytearray of size |SIZE|.
1641
1642    Raises:
1643      LookupError: If the given descriptor is malformed.
1644    """
1645    AvbDescriptor.__init__(self, None)
1646    assert struct.calcsize(self.FORMAT_STRING) == self.SIZE
1647
1648    if data:
1649      (tag, num_bytes_following, self.rollback_index_location,
1650       partition_name_len,
1651       public_key_len, _) = struct.unpack(self.FORMAT_STRING, data[0:self.SIZE])
1652      expected_size = round_to_multiple(
1653          self.SIZE - 16 + partition_name_len + public_key_len, 8)
1654      if tag != self.TAG or num_bytes_following != expected_size:
1655        raise LookupError('Given data does not look like a chain partition '
1656                          'descriptor.')
1657      o = 0
1658      self.partition_name = str(data[(self.SIZE + o):(self.SIZE + o +
1659                                                      partition_name_len)])
1660      # Validate UTF-8 - decode() raises UnicodeDecodeError if not valid UTF-8.
1661      self.partition_name.decode('utf-8')
1662      o += partition_name_len
1663      self.public_key = data[(self.SIZE + o):(self.SIZE + o + public_key_len)]
1664
1665    else:
1666      self.rollback_index_location = 0
1667      self.partition_name = ''
1668      self.public_key = bytearray()
1669
1670  def print_desc(self, o):
1671    """Print the descriptor.
1672
1673    Arguments:
1674      o: The object to write the output to.
1675    """
1676    o.write('    Chain Partition descriptor:\n')
1677    o.write('      Partition Name:          {}\n'.format(self.partition_name))
1678    o.write('      Rollback Index Location: {}\n'.format(
1679        self.rollback_index_location))
1680    # Just show the SHA1 of the key, for size reasons.
1681    hexdig = hashlib.sha1(self.public_key).hexdigest()
1682    o.write('      Public key (sha1):       {}\n'.format(hexdig))
1683
1684  def encode(self):
1685    """Serializes the descriptor.
1686
1687    Returns:
1688      A bytearray() with the descriptor data.
1689    """
1690    encoded_name = self.partition_name.encode('utf-8')
1691    num_bytes_following = (
1692        self.SIZE + len(encoded_name) + len(self.public_key) - 16)
1693    nbf_with_padding = round_to_multiple(num_bytes_following, 8)
1694    padding_size = nbf_with_padding - num_bytes_following
1695    desc = struct.pack(self.FORMAT_STRING, self.TAG, nbf_with_padding,
1696                       self.rollback_index_location, len(encoded_name),
1697                       len(self.public_key), self.RESERVED*'\0')
1698    padding = struct.pack(str(padding_size) + 'x')
1699    ret = desc + encoded_name + self.public_key + padding
1700    return bytearray(ret)
1701
1702  def verify(self, image_dir, image_ext, expected_chain_partitions_map,
1703             image_containing_descriptor):
1704    """Verifies contents of the descriptor - used in verify_image sub-command.
1705
1706    Arguments:
1707      image_dir: The directory of the file being verified.
1708      image_ext: The extension of the file being verified (e.g. '.img').
1709      expected_chain_partitions_map: A map from partition name to the
1710        tuple (rollback_index_location, key_blob).
1711      image_containing_descriptor: The image the descriptor is in.
1712
1713    Returns:
1714      True if the descriptor verifies, False otherwise.
1715    """
1716    value = expected_chain_partitions_map.get(self.partition_name)
1717    if not value:
1718      sys.stderr.write('No expected chain partition for partition {}. Use '
1719                       '--expected_chain_partition to specify expected '
1720                       'contents.\n'.
1721                       format(self.partition_name))
1722      return False
1723    rollback_index_location, pk_blob = value
1724
1725    if self.rollback_index_location != rollback_index_location:
1726      sys.stderr.write('Expected rollback_index_location {} does not '
1727                       'match {} in descriptor for partition {}\n'.
1728                       format(rollback_index_location,
1729                              self.rollback_index_location,
1730                              self.partition_name))
1731      return False
1732
1733    if self.public_key != pk_blob:
1734      sys.stderr.write('Expected public key blob does not match public '
1735                       'key blob in descriptor for partition {}\n'.
1736                       format(self.partition_name))
1737      return False
1738
1739    print ('{}: Successfully verified chain partition descriptor matches '
1740           'expected data'.format(self.partition_name))
1741
1742    return True
1743
1744DESCRIPTOR_CLASSES = [
1745    AvbPropertyDescriptor, AvbHashtreeDescriptor, AvbHashDescriptor,
1746    AvbKernelCmdlineDescriptor, AvbChainPartitionDescriptor
1747]
1748
1749
1750def parse_descriptors(data):
1751  """Parses a blob of data into descriptors.
1752
1753  Arguments:
1754    data: A bytearray() with encoded descriptors.
1755
1756  Returns:
1757    A list of instances of objects derived from AvbDescriptor. For
1758    unknown descriptors, the class AvbDescriptor is used.
1759  """
1760  o = 0
1761  ret = []
1762  while o < len(data):
1763    tag, nb_following = struct.unpack('!2Q', data[o:o + 16])
1764    if tag < len(DESCRIPTOR_CLASSES):
1765      c = DESCRIPTOR_CLASSES[tag]
1766    else:
1767      c = AvbDescriptor
1768    ret.append(c(bytearray(data[o:o + 16 + nb_following])))
1769    o += 16 + nb_following
1770  return ret
1771
1772
1773class AvbFooter(object):
1774  """A class for parsing and writing footers.
1775
1776  Footers are stored at the end of partitions and point to where the
1777  AvbVBMeta blob is located. They also contain the original size of
1778  the image before AVB information was added.
1779
1780  Attributes:
1781    magic: Magic for identifying the footer, see |MAGIC|.
1782    version_major: The major version of avbtool that wrote the footer.
1783    version_minor: The minor version of avbtool that wrote the footer.
1784    original_image_size: Original image size.
1785    vbmeta_offset: Offset of where the AvbVBMeta blob is stored.
1786    vbmeta_size: Size of the AvbVBMeta blob.
1787  """
1788
1789  MAGIC = 'AVBf'
1790  SIZE = 64
1791  RESERVED = 28
1792  FOOTER_VERSION_MAJOR = AVB_FOOTER_VERSION_MAJOR
1793  FOOTER_VERSION_MINOR = AVB_FOOTER_VERSION_MINOR
1794  FORMAT_STRING = ('!4s2L'  # magic, 2 x version.
1795                   'Q'  # Original image size.
1796                   'Q'  # Offset of VBMeta blob.
1797                   'Q' +  # Size of VBMeta blob.
1798                   str(RESERVED) + 'x')  # padding for reserved bytes
1799
1800  def __init__(self, data=None):
1801    """Initializes a new footer object.
1802
1803    Arguments:
1804      data: If not None, must be a bytearray of size 4096.
1805
1806    Raises:
1807      LookupError: If the given footer is malformed.
1808      struct.error: If the given data has no footer.
1809    """
1810    assert struct.calcsize(self.FORMAT_STRING) == self.SIZE
1811
1812    if data:
1813      (self.magic, self.version_major, self.version_minor,
1814       self.original_image_size, self.vbmeta_offset,
1815       self.vbmeta_size) = struct.unpack(self.FORMAT_STRING, data)
1816      if self.magic != self.MAGIC:
1817        raise LookupError('Given data does not look like a AVB footer.')
1818    else:
1819      self.magic = self.MAGIC
1820      self.version_major = self.FOOTER_VERSION_MAJOR
1821      self.version_minor = self.FOOTER_VERSION_MINOR
1822      self.original_image_size = 0
1823      self.vbmeta_offset = 0
1824      self.vbmeta_size = 0
1825
1826  def encode(self):
1827    """Gets a string representing the binary encoding of the footer.
1828
1829    Returns:
1830      A bytearray() with a binary representation of the footer.
1831    """
1832    return struct.pack(self.FORMAT_STRING, self.magic, self.version_major,
1833                       self.version_minor, self.original_image_size,
1834                       self.vbmeta_offset, self.vbmeta_size)
1835
1836
1837class AvbVBMetaHeader(object):
1838  """A class for parsing and writing AVB vbmeta images.
1839
1840  Attributes:
1841    The attributes correspond to the |AvbVBMetaImageHeader| struct defined in
1842    avb_vbmeta_image.h.
1843  """
1844
1845  SIZE = 256
1846
1847  # Keep in sync with |reserved0| and |reserved| field of
1848  # |AvbVBMetaImageHeader|.
1849  RESERVED0 = 4
1850  RESERVED = 80
1851
1852  # Keep in sync with |AvbVBMetaImageHeader|.
1853  FORMAT_STRING = ('!4s2L'  # magic, 2 x version
1854                   '2Q'  # 2 x block size
1855                   'L'  # algorithm type
1856                   '2Q'  # offset, size (hash)
1857                   '2Q'  # offset, size (signature)
1858                   '2Q'  # offset, size (public key)
1859                   '2Q'  # offset, size (public key metadata)
1860                   '2Q'  # offset, size (descriptors)
1861                   'Q'  # rollback_index
1862                   'L' +  # flags
1863                   str(RESERVED0) + 'x' +  # padding for reserved bytes
1864                   '47sx' +  # NUL-terminated release string
1865                   str(RESERVED) + 'x')  # padding for reserved bytes
1866
1867  def __init__(self, data=None):
1868    """Initializes a new header object.
1869
1870    Arguments:
1871      data: If not None, must be a bytearray of size 8192.
1872
1873    Raises:
1874      Exception: If the given data is malformed.
1875    """
1876    assert struct.calcsize(self.FORMAT_STRING) == self.SIZE
1877
1878    if data:
1879      (self.magic, self.required_libavb_version_major,
1880       self.required_libavb_version_minor,
1881       self.authentication_data_block_size, self.auxiliary_data_block_size,
1882       self.algorithm_type, self.hash_offset, self.hash_size,
1883       self.signature_offset, self.signature_size, self.public_key_offset,
1884       self.public_key_size, self.public_key_metadata_offset,
1885       self.public_key_metadata_size, self.descriptors_offset,
1886       self.descriptors_size,
1887       self.rollback_index,
1888       self.flags,
1889       self.release_string) = struct.unpack(self.FORMAT_STRING, data)
1890      # Nuke NUL-bytes at the end of the string.
1891      if self.magic != 'AVB0':
1892        raise AvbError('Given image does not look like a vbmeta image.')
1893    else:
1894      self.magic = 'AVB0'
1895      # Start by just requiring version 1.0. Code that adds features
1896      # in a future version can use bump_required_libavb_version_minor() to
1897      # bump the minor.
1898      self.required_libavb_version_major = AVB_VERSION_MAJOR
1899      self.required_libavb_version_minor = 0
1900      self.authentication_data_block_size = 0
1901      self.auxiliary_data_block_size = 0
1902      self.algorithm_type = 0
1903      self.hash_offset = 0
1904      self.hash_size = 0
1905      self.signature_offset = 0
1906      self.signature_size = 0
1907      self.public_key_offset = 0
1908      self.public_key_size = 0
1909      self.public_key_metadata_offset = 0
1910      self.public_key_metadata_size = 0
1911      self.descriptors_offset = 0
1912      self.descriptors_size = 0
1913      self.rollback_index = 0
1914      self.flags = 0
1915      self.release_string = get_release_string()
1916
1917  def bump_required_libavb_version_minor(self, minor):
1918    """Function to bump required_libavb_version_minor.
1919
1920    Call this when writing data that requires a specific libavb
1921    version to parse it.
1922
1923    Arguments:
1924      minor: The minor version of libavb that has support for the feature.
1925    """
1926    self.required_libavb_version_minor = (
1927        max(self.required_libavb_version_minor, minor))
1928
1929  def save(self, output):
1930    """Serializes the header (256 bytes) to disk.
1931
1932    Arguments:
1933      output: The object to write the output to.
1934    """
1935    output.write(struct.pack(
1936        self.FORMAT_STRING, self.magic, self.required_libavb_version_major,
1937        self.required_libavb_version_minor, self.authentication_data_block_size,
1938        self.auxiliary_data_block_size, self.algorithm_type, self.hash_offset,
1939        self.hash_size, self.signature_offset, self.signature_size,
1940        self.public_key_offset, self.public_key_size,
1941        self.public_key_metadata_offset, self.public_key_metadata_size,
1942        self.descriptors_offset, self.descriptors_size, self.rollback_index,
1943        self.flags, self.release_string))
1944
1945  def encode(self):
1946    """Serializes the header (256) to a bytearray().
1947
1948    Returns:
1949      A bytearray() with the encoded header.
1950    """
1951    return struct.pack(self.FORMAT_STRING, self.magic,
1952                       self.required_libavb_version_major,
1953                       self.required_libavb_version_minor,
1954                       self.authentication_data_block_size,
1955                       self.auxiliary_data_block_size, self.algorithm_type,
1956                       self.hash_offset, self.hash_size, self.signature_offset,
1957                       self.signature_size, self.public_key_offset,
1958                       self.public_key_size, self.public_key_metadata_offset,
1959                       self.public_key_metadata_size, self.descriptors_offset,
1960                       self.descriptors_size, self.rollback_index, self.flags,
1961                       self.release_string)
1962
1963
1964class Avb(object):
1965  """Business logic for avbtool command-line tool."""
1966
1967  # Keep in sync with avb_ab_flow.h.
1968  AB_FORMAT_NO_CRC = '!4sBB2xBBBxBBBx12x'
1969  AB_MAGIC = '\0AB0'
1970  AB_MAJOR_VERSION = 1
1971  AB_MINOR_VERSION = 0
1972  AB_MISC_METADATA_OFFSET = 2048
1973
1974  # Constants for maximum metadata size. These are used to give
1975  # meaningful errors if the value passed in via --partition_size is
1976  # too small and when --calc_max_image_size is used. We use
1977  # conservative figures.
1978  MAX_VBMETA_SIZE = 64 * 1024
1979  MAX_FOOTER_SIZE = 4096
1980
1981  def extract_vbmeta_image(self, output, image_filename, padding_size):
1982    """Implements the 'extract_vbmeta_image' command.
1983
1984    Arguments:
1985      output: Write vbmeta struct to this file.
1986      image_filename: File to extract vbmeta data from (with a footer).
1987      padding_size: If not 0, pads output so size is a multiple of the number.
1988
1989    Raises:
1990      AvbError: If there's no footer in the image.
1991    """
1992    image = ImageHandler(image_filename)
1993
1994    (footer, _, _, _) = self._parse_image(image)
1995
1996    if not footer:
1997      raise AvbError('Given image does not have a footer.')
1998
1999    image.seek(footer.vbmeta_offset)
2000    vbmeta_blob = image.read(footer.vbmeta_size)
2001    output.write(vbmeta_blob)
2002
2003    if padding_size > 0:
2004      padded_size = round_to_multiple(len(vbmeta_blob), padding_size)
2005      padding_needed = padded_size - len(vbmeta_blob)
2006      output.write('\0' * padding_needed)
2007
2008  def erase_footer(self, image_filename, keep_hashtree):
2009    """Implements the 'erase_footer' command.
2010
2011    Arguments:
2012      image_filename: File to erase a footer from.
2013      keep_hashtree: If True, keep the hashtree and FEC around.
2014
2015    Raises:
2016      AvbError: If there's no footer in the image.
2017    """
2018
2019    image = ImageHandler(image_filename)
2020
2021    (footer, _, descriptors, _) = self._parse_image(image)
2022
2023    if not footer:
2024      raise AvbError('Given image does not have a footer.')
2025
2026    new_image_size = None
2027    if not keep_hashtree:
2028      new_image_size = footer.original_image_size
2029    else:
2030      # If requested to keep the hashtree, search for a hashtree
2031      # descriptor to figure out the location and size of the hashtree
2032      # and FEC.
2033      for desc in descriptors:
2034        if isinstance(desc, AvbHashtreeDescriptor):
2035          # The hashtree is always just following the main data so the
2036          # new size is easily derived.
2037          new_image_size = desc.tree_offset + desc.tree_size
2038          # If the image has FEC codes, also keep those.
2039          if desc.fec_offset > 0:
2040            fec_end = desc.fec_offset + desc.fec_size
2041            new_image_size = max(new_image_size, fec_end)
2042          break
2043      if not new_image_size:
2044        raise AvbError('Requested to keep hashtree but no hashtree '
2045                       'descriptor was found.')
2046
2047    # And cut...
2048    image.truncate(new_image_size)
2049
2050  def resize_image(self, image_filename, partition_size):
2051    """Implements the 'resize_image' command.
2052
2053    Arguments:
2054      image_filename: File with footer to resize.
2055      partition_size: The new size of the image.
2056
2057    Raises:
2058      AvbError: If there's no footer in the image.
2059    """
2060
2061    image = ImageHandler(image_filename)
2062
2063    if partition_size % image.block_size != 0:
2064      raise AvbError('Partition size of {} is not a multiple of the image '
2065                     'block size {}.'.format(partition_size,
2066                                             image.block_size))
2067
2068    (footer, vbmeta_header, descriptors, _) = self._parse_image(image)
2069
2070    if not footer:
2071      raise AvbError('Given image does not have a footer.')
2072
2073    # The vbmeta blob is always at the end of the data so resizing an
2074    # image amounts to just moving the footer around.
2075
2076    vbmeta_end_offset = footer.vbmeta_offset + footer.vbmeta_size
2077    if vbmeta_end_offset % image.block_size != 0:
2078      vbmeta_end_offset += image.block_size - (vbmeta_end_offset % image.block_size)
2079
2080    if partition_size < vbmeta_end_offset + 1*image.block_size:
2081      raise AvbError('Requested size of {} is too small for an image '
2082                     'of size {}.'
2083                     .format(partition_size,
2084                             vbmeta_end_offset + 1*image.block_size))
2085
2086    # Cut at the end of the vbmeta blob and insert a DONT_CARE chunk
2087    # with enough bytes such that the final Footer block is at the end
2088    # of partition_size.
2089    image.truncate(vbmeta_end_offset)
2090    image.append_dont_care(partition_size - vbmeta_end_offset -
2091                           1*image.block_size)
2092
2093    # Just reuse the same footer - only difference is that we're
2094    # writing it in a different place.
2095    footer_blob = footer.encode()
2096    footer_blob_with_padding = ('\0'*(image.block_size - AvbFooter.SIZE) +
2097                                footer_blob)
2098    image.append_raw(footer_blob_with_padding)
2099
2100  def set_ab_metadata(self, misc_image, slot_data):
2101    """Implements the 'set_ab_metadata' command.
2102
2103    The |slot_data| argument must be of the form 'A_priority:A_tries_remaining:
2104    A_successful_boot:B_priority:B_tries_remaining:B_successful_boot'.
2105
2106    Arguments:
2107      misc_image: The misc image to write to.
2108      slot_data: Slot data as a string
2109
2110    Raises:
2111      AvbError: If slot data is malformed.
2112    """
2113    tokens = slot_data.split(':')
2114    if len(tokens) != 6:
2115      raise AvbError('Malformed slot data "{}".'.format(slot_data))
2116    a_priority = int(tokens[0])
2117    a_tries_remaining = int(tokens[1])
2118    a_success = True if int(tokens[2]) != 0 else False
2119    b_priority = int(tokens[3])
2120    b_tries_remaining = int(tokens[4])
2121    b_success = True if int(tokens[5]) != 0 else False
2122
2123    ab_data_no_crc = struct.pack(self.AB_FORMAT_NO_CRC,
2124                                 self.AB_MAGIC,
2125                                 self.AB_MAJOR_VERSION, self.AB_MINOR_VERSION,
2126                                 a_priority, a_tries_remaining, a_success,
2127                                 b_priority, b_tries_remaining, b_success)
2128    # Force CRC to be unsigned, see https://bugs.python.org/issue4903 for why.
2129    crc_value = binascii.crc32(ab_data_no_crc) & 0xffffffff
2130    ab_data = ab_data_no_crc + struct.pack('!I', crc_value)
2131    misc_image.seek(self.AB_MISC_METADATA_OFFSET)
2132    misc_image.write(ab_data)
2133
2134  def info_image(self, image_filename, output):
2135    """Implements the 'info_image' command.
2136
2137    Arguments:
2138      image_filename: Image file to get information from (file object).
2139      output: Output file to write human-readable information to (file object).
2140    """
2141
2142    image = ImageHandler(image_filename)
2143
2144    o = output
2145
2146    (footer, header, descriptors, image_size) = self._parse_image(image)
2147
2148    if footer:
2149      o.write('Footer version:           {}.{}\n'.format(footer.version_major,
2150                                                         footer.version_minor))
2151      o.write('Image size:               {} bytes\n'.format(image_size))
2152      o.write('Original image size:      {} bytes\n'.format(
2153          footer.original_image_size))
2154      o.write('VBMeta offset:            {}\n'.format(footer.vbmeta_offset))
2155      o.write('VBMeta size:              {} bytes\n'.format(footer.vbmeta_size))
2156      o.write('--\n')
2157
2158    (alg_name, _) = lookup_algorithm_by_type(header.algorithm_type)
2159
2160    o.write('Minimum libavb version:   {}.{}{}\n'.format(
2161        header.required_libavb_version_major,
2162        header.required_libavb_version_minor,
2163        ' (Sparse)' if image.is_sparse else ''))
2164    o.write('Header Block:             {} bytes\n'.format(AvbVBMetaHeader.SIZE))
2165    o.write('Authentication Block:     {} bytes\n'.format(
2166        header.authentication_data_block_size))
2167    o.write('Auxiliary Block:          {} bytes\n'.format(
2168        header.auxiliary_data_block_size))
2169    o.write('Algorithm:                {}\n'.format(alg_name))
2170    o.write('Rollback Index:           {}\n'.format(header.rollback_index))
2171    o.write('Flags:                    {}\n'.format(header.flags))
2172    o.write('Release String:           \'{}\'\n'.format(
2173        header.release_string.rstrip('\0')))
2174
2175    # Print descriptors.
2176    num_printed = 0
2177    o.write('Descriptors:\n')
2178    for desc in descriptors:
2179      desc.print_desc(o)
2180      num_printed += 1
2181    if num_printed == 0:
2182      o.write('    (none)\n')
2183
2184  def verify_image(self, image_filename, key_path, expected_chain_partitions):
2185    """Implements the 'verify_image' command.
2186
2187    Arguments:
2188      image_filename: Image file to get information from (file object).
2189      key_path: None or check that embedded public key matches key at given path.
2190      expected_chain_partitions: List of chain partitions to check or None.
2191    """
2192
2193    expected_chain_partitions_map = {}
2194    if expected_chain_partitions:
2195      used_locations = {}
2196      for cp in expected_chain_partitions:
2197        cp_tokens = cp.split(':')
2198        if len(cp_tokens) != 3:
2199          raise AvbError('Malformed chained partition "{}".'.format(cp))
2200        partition_name = cp_tokens[0]
2201        rollback_index_location = int(cp_tokens[1])
2202        file_path = cp_tokens[2]
2203        pk_blob = open(file_path).read()
2204        expected_chain_partitions_map[partition_name] = (rollback_index_location, pk_blob)
2205
2206    image_dir = os.path.dirname(image_filename)
2207    image_ext = os.path.splitext(image_filename)[1]
2208
2209    key_blob = None
2210    if key_path:
2211      print 'Verifying image {} using key at {}'.format(image_filename, key_path)
2212      key_blob = encode_rsa_key(key_path)
2213    else:
2214      print 'Verifying image {} using embedded public key'.format(image_filename)
2215
2216    image = ImageHandler(image_filename)
2217    (footer, header, descriptors, image_size) = self._parse_image(image)
2218    offset = 0
2219    if footer:
2220      offset = footer.vbmeta_offset
2221
2222    image.seek(offset)
2223    vbmeta_blob = image.read(header.SIZE + header.authentication_data_block_size +
2224                             header.auxiliary_data_block_size)
2225
2226    alg_name, _ = lookup_algorithm_by_type(header.algorithm_type)
2227    if not verify_vbmeta_signature(header, vbmeta_blob):
2228      raise AvbError('Signature check failed for {} vbmeta struct {}'
2229                     .format(alg_name, image_filename))
2230
2231    if key_blob:
2232      # The embedded public key is in the auxiliary block at an offset.
2233      key_offset = AvbVBMetaHeader.SIZE
2234      key_offset += header.authentication_data_block_size
2235      key_offset += header.public_key_offset
2236      key_blob_in_vbmeta = vbmeta_blob[key_offset:key_offset + header.public_key_size]
2237      if key_blob != key_blob_in_vbmeta:
2238        raise AvbError('Embedded public key does not match given key.')
2239
2240    if footer:
2241      print ('vbmeta: Successfully verified footer and {} vbmeta struct in {}'
2242             .format(alg_name, image.filename))
2243    else:
2244      print ('vbmeta: Successfully verified {} vbmeta struct in {}'
2245             .format(alg_name, image.filename))
2246
2247    for desc in descriptors:
2248      if not desc.verify(image_dir, image_ext, expected_chain_partitions_map, image):
2249        raise AvbError('Error verifying descriptor.')
2250      # Note how AvbDescriptor.verify() method verifies only the descriptor
2251      # contents which in the case of chain descriptors means checking only its
2252      # contents matches what is in |expected_chain_partitions_map|.
2253      #
2254      # Specifically AvbHashtreeDescriptor.verify(), doesn't follow chain
2255      # descriptors e.g. if it's a chain descriptor for 'system' it will not try
2256      # to verify system.img. Why?  Because the whole idea of chain descriptors
2257      # is separate organizations. That is, when they are used it's assumed that
2258      # all you have is the public key, not an actual image (because if you had
2259      # the image you wouldn't need to use a chain partition in the first
2260      # place).
2261      #
2262      # However in certain situations you do have the image so it would be nice
2263      # to add something like a --follow_chain_descriptors option for 'avbtool
2264      # verify_image' which will look for and follow images specified by chain
2265      # descriptors. Maybe it should be on a per-partition basis and specificied
2266      # as part of the --expected_chain_partition paramter, maybe if the
2267      # partition name ends with a '+' or something. Something to think about.
2268
2269
2270  def calculate_vbmeta_digest(self, image_filename, hash_algorithm, output):
2271    """Implements the 'calculate_vbmeta_digest' command.
2272
2273    Arguments:
2274      image_filename: Image file to get information from (file object).
2275      hash_algorithm: Hash algorithm used.
2276      output: Output file to write human-readable information to (file object).
2277    """
2278
2279    image_dir = os.path.dirname(image_filename)
2280    image_ext = os.path.splitext(image_filename)[1]
2281
2282    image = ImageHandler(image_filename)
2283    (footer, header, descriptors, image_size) = self._parse_image(image)
2284    offset = 0
2285    if footer:
2286      offset = footer.vbmeta_offset
2287    size = (header.SIZE + header.authentication_data_block_size +
2288            header.auxiliary_data_block_size)
2289    image.seek(offset)
2290    vbmeta_blob = image.read(size)
2291
2292    hasher = hashlib.new(name=hash_algorithm)
2293    hasher.update(vbmeta_blob)
2294
2295    for desc in descriptors:
2296      if isinstance(desc, AvbChainPartitionDescriptor):
2297        ch_image_filename = os.path.join(image_dir, desc.partition_name + image_ext)
2298        ch_image = ImageHandler(ch_image_filename)
2299        (ch_footer, ch_header, ch_descriptors, ch_image_size) = self._parse_image(ch_image)
2300        ch_offset = 0
2301        ch_size = (ch_header.SIZE + ch_header.authentication_data_block_size +
2302                   ch_header.auxiliary_data_block_size)
2303        if ch_footer:
2304          ch_offset = ch_footer.vbmeta_offset
2305        ch_image.seek(ch_offset)
2306        ch_vbmeta_blob = ch_image.read(ch_size)
2307        hasher.update(ch_vbmeta_blob)
2308
2309    digest = hasher.digest()
2310    output.write('{}\n'.format(digest.encode('hex')))
2311
2312
2313  def calculate_kernel_cmdline(self, image_filename, hashtree_disabled, output):
2314    """Implements the 'calculate_kernel_cmdline' command.
2315
2316    Arguments:
2317      image_filename: Image file to get information from (file object).
2318      hashtree_disabled: If True, returns the cmdline for hashtree disabled.
2319      output: Output file to write human-readable information to (file object).
2320    """
2321
2322    image = ImageHandler(image_filename)
2323    _, _, descriptors, _ = self._parse_image(image)
2324
2325    image_dir = os.path.dirname(image_filename)
2326    image_ext = os.path.splitext(image_filename)[1]
2327
2328    cmdline_descriptors = []
2329    for desc in descriptors:
2330      if isinstance(desc, AvbChainPartitionDescriptor):
2331        ch_image_filename = os.path.join(image_dir, desc.partition_name + image_ext)
2332        ch_image = ImageHandler(ch_image_filename)
2333        _, _, ch_descriptors, _ = self._parse_image(ch_image)
2334        for ch_desc in ch_descriptors:
2335          if isinstance(ch_desc, AvbKernelCmdlineDescriptor):
2336            cmdline_descriptors.append(ch_desc)
2337      elif isinstance(desc, AvbKernelCmdlineDescriptor):
2338        cmdline_descriptors.append(desc)
2339
2340    kernel_cmdline_snippets = []
2341    for desc in cmdline_descriptors:
2342      use_cmdline = True
2343      if (desc.flags & AvbKernelCmdlineDescriptor.FLAGS_USE_ONLY_IF_HASHTREE_NOT_DISABLED) != 0:
2344        if hashtree_disabled:
2345          use_cmdline = False
2346      if (desc.flags & AvbKernelCmdlineDescriptor.FLAGS_USE_ONLY_IF_HASHTREE_DISABLED) != 0:
2347        if not hashtree_disabled:
2348          use_cmdline = False
2349      if use_cmdline:
2350        kernel_cmdline_snippets.append(desc.kernel_cmdline)
2351    output.write(' '.join(kernel_cmdline_snippets))
2352
2353
2354  def _parse_image(self, image):
2355    """Gets information about an image.
2356
2357    The image can either be a vbmeta or an image with a footer.
2358
2359    Arguments:
2360      image: An ImageHandler (vbmeta or footer) with a hashtree descriptor.
2361
2362    Returns:
2363      A tuple where the first argument is a AvbFooter (None if there
2364      is no footer on the image), the second argument is a
2365      AvbVBMetaHeader, the third argument is a list of
2366      AvbDescriptor-derived instances, and the fourth argument is the
2367      size of |image|.
2368    """
2369    assert isinstance(image, ImageHandler)
2370    footer = None
2371    image.seek(image.image_size - AvbFooter.SIZE)
2372    try:
2373      footer = AvbFooter(image.read(AvbFooter.SIZE))
2374    except (LookupError, struct.error):
2375      # Nope, just seek back to the start.
2376      image.seek(0)
2377
2378    vbmeta_offset = 0
2379    if footer:
2380      vbmeta_offset = footer.vbmeta_offset
2381
2382    image.seek(vbmeta_offset)
2383    h = AvbVBMetaHeader(image.read(AvbVBMetaHeader.SIZE))
2384
2385    auth_block_offset = vbmeta_offset + AvbVBMetaHeader.SIZE
2386    aux_block_offset = auth_block_offset + h.authentication_data_block_size
2387    desc_start_offset = aux_block_offset + h.descriptors_offset
2388    image.seek(desc_start_offset)
2389    descriptors = parse_descriptors(image.read(h.descriptors_size))
2390
2391    return footer, h, descriptors, image.image_size
2392
2393  def _load_vbmeta_blob(self, image):
2394    """Gets the vbmeta struct and associated sections.
2395
2396    The image can either be a vbmeta.img or an image with a footer.
2397
2398    Arguments:
2399      image: An ImageHandler (vbmeta or footer).
2400
2401    Returns:
2402      A blob with the vbmeta struct and other sections.
2403    """
2404    assert isinstance(image, ImageHandler)
2405    footer = None
2406    image.seek(image.image_size - AvbFooter.SIZE)
2407    try:
2408      footer = AvbFooter(image.read(AvbFooter.SIZE))
2409    except (LookupError, struct.error):
2410      # Nope, just seek back to the start.
2411      image.seek(0)
2412
2413    vbmeta_offset = 0
2414    if footer:
2415      vbmeta_offset = footer.vbmeta_offset
2416
2417    image.seek(vbmeta_offset)
2418    h = AvbVBMetaHeader(image.read(AvbVBMetaHeader.SIZE))
2419
2420    image.seek(vbmeta_offset)
2421    data_size = AvbVBMetaHeader.SIZE
2422    data_size += h.authentication_data_block_size
2423    data_size += h.auxiliary_data_block_size
2424    return image.read(data_size)
2425
2426  def _get_cmdline_descriptors_for_hashtree_descriptor(self, ht):
2427    """Generate kernel cmdline descriptors for dm-verity.
2428
2429    Arguments:
2430      ht: A AvbHashtreeDescriptor
2431
2432    Returns:
2433      A list with two AvbKernelCmdlineDescriptor with dm-verity kernel cmdline
2434      instructions. There is one for when hashtree is not disabled and one for
2435      when it is.
2436
2437    """
2438
2439    c = 'dm="1 vroot none ro 1,'
2440    c += '0'  # start
2441    c += ' {}'.format((ht.image_size / 512))  # size (# sectors)
2442    c += ' verity {}'.format(ht.dm_verity_version)  # type and version
2443    c += ' PARTUUID=$(ANDROID_SYSTEM_PARTUUID)'  # data_dev
2444    c += ' PARTUUID=$(ANDROID_SYSTEM_PARTUUID)'  # hash_dev
2445    c += ' {}'.format(ht.data_block_size)  # data_block
2446    c += ' {}'.format(ht.hash_block_size)  # hash_block
2447    c += ' {}'.format(ht.image_size / ht.data_block_size)  # #blocks
2448    c += ' {}'.format(ht.image_size / ht.data_block_size)  # hash_offset
2449    c += ' {}'.format(ht.hash_algorithm)  # hash_alg
2450    c += ' {}'.format(str(ht.root_digest).encode('hex'))  # root_digest
2451    c += ' {}'.format(str(ht.salt).encode('hex'))  # salt
2452    if ht.fec_num_roots > 0:
2453      c += ' 10'  # number of optional args
2454      c += ' $(ANDROID_VERITY_MODE)'
2455      c += ' ignore_zero_blocks'
2456      c += ' use_fec_from_device PARTUUID=$(ANDROID_SYSTEM_PARTUUID)'
2457      c += ' fec_roots {}'.format(ht.fec_num_roots)
2458      # Note that fec_blocks is the size that FEC covers, *not* the
2459      # size of the FEC data. Since we use FEC for everything up until
2460      # the FEC data, it's the same as the offset.
2461      c += ' fec_blocks {}'.format(ht.fec_offset/ht.data_block_size)
2462      c += ' fec_start {}'.format(ht.fec_offset/ht.data_block_size)
2463    else:
2464      c += ' 2'  # number of optional args
2465      c += ' $(ANDROID_VERITY_MODE)'
2466      c += ' ignore_zero_blocks'
2467    c += '" root=/dev/dm-0'
2468
2469    # Now that we have the command-line, generate the descriptor.
2470    desc = AvbKernelCmdlineDescriptor()
2471    desc.kernel_cmdline = c
2472    desc.flags = (
2473        AvbKernelCmdlineDescriptor.FLAGS_USE_ONLY_IF_HASHTREE_NOT_DISABLED)
2474
2475    # The descriptor for when hashtree verification is disabled is a lot
2476    # simpler - we just set the root to the partition.
2477    desc_no_ht = AvbKernelCmdlineDescriptor()
2478    desc_no_ht.kernel_cmdline = 'root=PARTUUID=$(ANDROID_SYSTEM_PARTUUID)'
2479    desc_no_ht.flags = (
2480        AvbKernelCmdlineDescriptor.FLAGS_USE_ONLY_IF_HASHTREE_DISABLED)
2481
2482    return [desc, desc_no_ht]
2483
2484  def _get_cmdline_descriptors_for_dm_verity(self, image):
2485    """Generate kernel cmdline descriptors for dm-verity.
2486
2487    Arguments:
2488      image: An ImageHandler (vbmeta or footer) with a hashtree descriptor.
2489
2490    Returns:
2491      A list with two AvbKernelCmdlineDescriptor with dm-verity kernel cmdline
2492      instructions. There is one for when hashtree is not disabled and one for
2493      when it is.
2494
2495    Raises:
2496      AvbError: If  |image| doesn't have a hashtree descriptor.
2497
2498    """
2499
2500    (_, _, descriptors, _) = self._parse_image(image)
2501
2502    ht = None
2503    for desc in descriptors:
2504      if isinstance(desc, AvbHashtreeDescriptor):
2505        ht = desc
2506        break
2507
2508    if not ht:
2509      raise AvbError('No hashtree descriptor in given image')
2510
2511    return self._get_cmdline_descriptors_for_hashtree_descriptor(ht)
2512
2513  def make_vbmeta_image(self, output, chain_partitions, algorithm_name,
2514                        key_path, public_key_metadata_path, rollback_index,
2515                        flags, props, props_from_file, kernel_cmdlines,
2516                        setup_rootfs_from_kernel,
2517                        include_descriptors_from_image,
2518                        signing_helper,
2519                        signing_helper_with_files,
2520                        release_string,
2521                        append_to_release_string,
2522                        print_required_libavb_version,
2523                        padding_size):
2524    """Implements the 'make_vbmeta_image' command.
2525
2526    Arguments:
2527      output: File to write the image to.
2528      chain_partitions: List of partitions to chain or None.
2529      algorithm_name: Name of algorithm to use.
2530      key_path: Path to key to use or None.
2531      public_key_metadata_path: Path to public key metadata or None.
2532      rollback_index: The rollback index to use.
2533      flags: Flags value to use in the image.
2534      props: Properties to insert (list of strings of the form 'key:value').
2535      props_from_file: Properties to insert (list of strings 'key:<path>').
2536      kernel_cmdlines: Kernel cmdlines to insert (list of strings).
2537      setup_rootfs_from_kernel: None or file to generate from.
2538      include_descriptors_from_image: List of file objects with descriptors.
2539      signing_helper: Program which signs a hash and return signature.
2540      signing_helper_with_files: Same as signing_helper but uses files instead.
2541      release_string: None or avbtool release string to use instead of default.
2542      append_to_release_string: None or string to append.
2543      print_required_libavb_version: True to only print required libavb version.
2544      padding_size: If not 0, pads output so size is a multiple of the number.
2545
2546    Raises:
2547      AvbError: If a chained partition is malformed.
2548    """
2549
2550    # If we're asked to calculate minimum required libavb version, we're done.
2551    if print_required_libavb_version:
2552      if include_descriptors_from_image:
2553        # Use the bump logic in AvbVBMetaHeader to calculate the max required
2554        # version of all included descriptors.
2555        tmp_header = AvbVBMetaHeader()
2556        for image in include_descriptors_from_image:
2557          (_, image_header, _, _) = self._parse_image(ImageHandler(image.name))
2558          tmp_header.bump_required_libavb_version_minor(
2559              image_header.required_libavb_version_minor)
2560        print '1.{}'.format(tmp_header.required_libavb_version_minor)
2561      else:
2562        # Descriptors aside, all vbmeta features are supported in 1.0.
2563        print '1.0'
2564      return
2565
2566    if not output:
2567      raise AvbError('No output file given')
2568
2569    descriptors = []
2570    ht_desc_to_setup = None
2571    vbmeta_blob = self._generate_vbmeta_blob(
2572        algorithm_name, key_path, public_key_metadata_path, descriptors,
2573        chain_partitions, rollback_index, flags, props, props_from_file,
2574        kernel_cmdlines, setup_rootfs_from_kernel, ht_desc_to_setup,
2575        include_descriptors_from_image, signing_helper,
2576        signing_helper_with_files, release_string,
2577        append_to_release_string, 0)
2578
2579    # Write entire vbmeta blob (header, authentication, auxiliary).
2580    output.seek(0)
2581    output.write(vbmeta_blob)
2582
2583    if padding_size > 0:
2584      padded_size = round_to_multiple(len(vbmeta_blob), padding_size)
2585      padding_needed = padded_size - len(vbmeta_blob)
2586      output.write('\0' * padding_needed)
2587
2588  def _generate_vbmeta_blob(self, algorithm_name, key_path,
2589                            public_key_metadata_path, descriptors,
2590                            chain_partitions,
2591                            rollback_index, flags, props, props_from_file,
2592                            kernel_cmdlines,
2593                            setup_rootfs_from_kernel,
2594                            ht_desc_to_setup,
2595                            include_descriptors_from_image, signing_helper,
2596                            signing_helper_with_files,
2597                            release_string, append_to_release_string,
2598                            required_libavb_version_minor):
2599    """Generates a VBMeta blob.
2600
2601    This blob contains the header (struct AvbVBMetaHeader), the
2602    authentication data block (which contains the hash and signature
2603    for the header and auxiliary block), and the auxiliary block
2604    (which contains descriptors, the public key used, and other data).
2605
2606    The |key| parameter can |None| only if the |algorithm_name| is
2607    'NONE'.
2608
2609    Arguments:
2610      algorithm_name: The algorithm name as per the ALGORITHMS dict.
2611      key_path: The path to the .pem file used to sign the blob.
2612      public_key_metadata_path: Path to public key metadata or None.
2613      descriptors: A list of descriptors to insert or None.
2614      chain_partitions: List of partitions to chain or None.
2615      rollback_index: The rollback index to use.
2616      flags: Flags to use in the image.
2617      props: Properties to insert (List of strings of the form 'key:value').
2618      props_from_file: Properties to insert (List of strings 'key:<path>').
2619      kernel_cmdlines: Kernel cmdlines to insert (list of strings).
2620      setup_rootfs_from_kernel: None or file to generate
2621        dm-verity kernel cmdline from.
2622      ht_desc_to_setup: If not None, an AvbHashtreeDescriptor to
2623        generate dm-verity kernel cmdline descriptors from.
2624      include_descriptors_from_image: List of file objects for which
2625        to insert descriptors from.
2626      signing_helper: Program which signs a hash and return signature.
2627      signing_helper_with_files: Same as signing_helper but uses files instead.
2628      release_string: None or avbtool release string.
2629      append_to_release_string: None or string to append.
2630      required_libavb_version_minor: Use at least this required minor version.
2631
2632    Returns:
2633      A bytearray() with the VBMeta blob.
2634
2635    Raises:
2636      Exception: If the |algorithm_name| is not found, if no key has
2637        been given and the given algorithm requires one, or the key is
2638        of the wrong size.
2639
2640    """
2641    try:
2642      alg = ALGORITHMS[algorithm_name]
2643    except KeyError:
2644      raise AvbError('Unknown algorithm with name {}'.format(algorithm_name))
2645
2646    if not descriptors:
2647      descriptors = []
2648
2649    h = AvbVBMetaHeader()
2650    h.bump_required_libavb_version_minor(required_libavb_version_minor)
2651
2652    # Insert chained partition descriptors, if any
2653    if chain_partitions:
2654      used_locations = {}
2655      for cp in chain_partitions:
2656        cp_tokens = cp.split(':')
2657        if len(cp_tokens) != 3:
2658          raise AvbError('Malformed chained partition "{}".'.format(cp))
2659        partition_name = cp_tokens[0]
2660        rollback_index_location = int(cp_tokens[1])
2661        file_path = cp_tokens[2]
2662        # Check that the same rollback location isn't being used by
2663        # multiple chained partitions.
2664        if used_locations.get(rollback_index_location):
2665          raise AvbError('Rollback Index Location {} is already in use.'.format(
2666              rollback_index_location))
2667        used_locations[rollback_index_location] = True
2668        desc = AvbChainPartitionDescriptor()
2669        desc.partition_name = partition_name
2670        desc.rollback_index_location = rollback_index_location
2671        if desc.rollback_index_location < 1:
2672          raise AvbError('Rollback index location must be 1 or larger.')
2673        desc.public_key = open(file_path, 'rb').read()
2674        descriptors.append(desc)
2675
2676    # Descriptors.
2677    encoded_descriptors = bytearray()
2678    for desc in descriptors:
2679      encoded_descriptors.extend(desc.encode())
2680
2681    # Add properties.
2682    if props:
2683      for prop in props:
2684        idx = prop.find(':')
2685        if idx == -1:
2686          raise AvbError('Malformed property "{}".'.format(prop))
2687        desc = AvbPropertyDescriptor()
2688        desc.key = prop[0:idx]
2689        desc.value = prop[(idx + 1):]
2690        encoded_descriptors.extend(desc.encode())
2691    if props_from_file:
2692      for prop in props_from_file:
2693        idx = prop.find(':')
2694        if idx == -1:
2695          raise AvbError('Malformed property "{}".'.format(prop))
2696        desc = AvbPropertyDescriptor()
2697        desc.key = prop[0:idx]
2698        desc.value = prop[(idx + 1):]
2699        file_path = prop[(idx + 1):]
2700        desc.value = open(file_path, 'rb').read()
2701        encoded_descriptors.extend(desc.encode())
2702
2703    # Add AvbKernelCmdline descriptor for dm-verity from an image, if requested.
2704    if setup_rootfs_from_kernel:
2705      image_handler = ImageHandler(
2706          setup_rootfs_from_kernel.name)
2707      cmdline_desc = self._get_cmdline_descriptors_for_dm_verity(image_handler)
2708      encoded_descriptors.extend(cmdline_desc[0].encode())
2709      encoded_descriptors.extend(cmdline_desc[1].encode())
2710
2711    # Add AvbKernelCmdline descriptor for dm-verity from desc, if requested.
2712    if ht_desc_to_setup:
2713      cmdline_desc = self._get_cmdline_descriptors_for_hashtree_descriptor(
2714          ht_desc_to_setup)
2715      encoded_descriptors.extend(cmdline_desc[0].encode())
2716      encoded_descriptors.extend(cmdline_desc[1].encode())
2717
2718    # Add kernel command-lines.
2719    if kernel_cmdlines:
2720      for i in kernel_cmdlines:
2721        desc = AvbKernelCmdlineDescriptor()
2722        desc.kernel_cmdline = i
2723        encoded_descriptors.extend(desc.encode())
2724
2725    # Add descriptors from other images.
2726    if include_descriptors_from_image:
2727      descriptors_dict = dict()
2728      for image in include_descriptors_from_image:
2729        image_handler = ImageHandler(image.name)
2730        (_, image_vbmeta_header, image_descriptors, _) = self._parse_image(
2731            image_handler)
2732        # Bump the required libavb version to support all included descriptors.
2733        h.bump_required_libavb_version_minor(
2734            image_vbmeta_header.required_libavb_version_minor)
2735        for desc in image_descriptors:
2736          # The --include_descriptors_from_image option is used in some setups
2737          # with images A and B where both A and B contain a descriptor
2738          # for a partition with the same name. Since it's not meaningful
2739          # to include both descriptors, only include the last seen descriptor.
2740          # See bug 76386656 for details.
2741          if hasattr(desc, 'partition_name'):
2742            key = type(desc).__name__ + '_' + desc.partition_name
2743            descriptors_dict[key] = desc.encode()
2744          else:
2745            encoded_descriptors.extend(desc.encode())
2746      for key in sorted(descriptors_dict.keys()):
2747        encoded_descriptors.extend(descriptors_dict[key])
2748
2749    # Load public key metadata blob, if requested.
2750    pkmd_blob = []
2751    if public_key_metadata_path:
2752      with open(public_key_metadata_path) as f:
2753        pkmd_blob = f.read()
2754
2755    key = None
2756    encoded_key = bytearray()
2757    if alg.public_key_num_bytes > 0:
2758      if not key_path:
2759        raise AvbError('Key is required for algorithm {}'.format(
2760            algorithm_name))
2761      encoded_key = encode_rsa_key(key_path)
2762      if len(encoded_key) != alg.public_key_num_bytes:
2763        raise AvbError('Key is wrong size for algorithm {}'.format(
2764            algorithm_name))
2765
2766    # Override release string, if requested.
2767    if isinstance(release_string, (str, unicode)):
2768      h.release_string = release_string
2769
2770    # Append to release string, if requested. Also insert a space before.
2771    if isinstance(append_to_release_string, (str, unicode)):
2772      h.release_string += ' ' + append_to_release_string
2773
2774    # For the Auxiliary data block, descriptors are stored at offset 0,
2775    # followed by the public key, followed by the public key metadata blob.
2776    h.auxiliary_data_block_size = round_to_multiple(
2777        len(encoded_descriptors) + len(encoded_key) + len(pkmd_blob), 64)
2778    h.descriptors_offset = 0
2779    h.descriptors_size = len(encoded_descriptors)
2780    h.public_key_offset = h.descriptors_size
2781    h.public_key_size = len(encoded_key)
2782    h.public_key_metadata_offset = h.public_key_offset + h.public_key_size
2783    h.public_key_metadata_size = len(pkmd_blob)
2784
2785    # For the Authentication data block, the hash is first and then
2786    # the signature.
2787    h.authentication_data_block_size = round_to_multiple(
2788        alg.hash_num_bytes + alg.signature_num_bytes, 64)
2789    h.algorithm_type = alg.algorithm_type
2790    h.hash_offset = 0
2791    h.hash_size = alg.hash_num_bytes
2792    # Signature offset and size - it's stored right after the hash
2793    # (in Authentication data block).
2794    h.signature_offset = alg.hash_num_bytes
2795    h.signature_size = alg.signature_num_bytes
2796
2797    h.rollback_index = rollback_index
2798    h.flags = flags
2799
2800    # Generate Header data block.
2801    header_data_blob = h.encode()
2802
2803    # Generate Auxiliary data block.
2804    aux_data_blob = bytearray()
2805    aux_data_blob.extend(encoded_descriptors)
2806    aux_data_blob.extend(encoded_key)
2807    aux_data_blob.extend(pkmd_blob)
2808    padding_bytes = h.auxiliary_data_block_size - len(aux_data_blob)
2809    aux_data_blob.extend('\0' * padding_bytes)
2810
2811    # Calculate the hash.
2812    binary_hash = bytearray()
2813    binary_signature = bytearray()
2814    if algorithm_name != 'NONE':
2815      ha = hashlib.new(alg.hash_name)
2816      ha.update(header_data_blob)
2817      ha.update(aux_data_blob)
2818      binary_hash.extend(ha.digest())
2819
2820      # Calculate the signature.
2821      padding_and_hash = str(bytearray(alg.padding)) + binary_hash
2822      binary_signature.extend(raw_sign(signing_helper,
2823                                       signing_helper_with_files,
2824                                       algorithm_name,
2825                                       alg.signature_num_bytes, key_path,
2826                                       padding_and_hash))
2827
2828    # Generate Authentication data block.
2829    auth_data_blob = bytearray()
2830    auth_data_blob.extend(binary_hash)
2831    auth_data_blob.extend(binary_signature)
2832    padding_bytes = h.authentication_data_block_size - len(auth_data_blob)
2833    auth_data_blob.extend('\0' * padding_bytes)
2834
2835    return header_data_blob + auth_data_blob + aux_data_blob
2836
2837  def extract_public_key(self, key_path, output):
2838    """Implements the 'extract_public_key' command.
2839
2840    Arguments:
2841      key_path: The path to a RSA private key file.
2842      output: The file to write to.
2843    """
2844    output.write(encode_rsa_key(key_path))
2845
2846  def append_vbmeta_image(self, image_filename, vbmeta_image_filename,
2847                          partition_size):
2848    """Implementation of the append_vbmeta_image command.
2849
2850    Arguments:
2851      image_filename: File to add the footer to.
2852      vbmeta_image_filename: File to get vbmeta struct from.
2853      partition_size: Size of partition.
2854
2855    Raises:
2856      AvbError: If an argument is incorrect.
2857    """
2858    image = ImageHandler(image_filename)
2859
2860    if partition_size % image.block_size != 0:
2861      raise AvbError('Partition size of {} is not a multiple of the image '
2862                     'block size {}.'.format(partition_size,
2863                                             image.block_size))
2864
2865    # If there's already a footer, truncate the image to its original
2866    # size. This way 'avbtool append_vbmeta_image' is idempotent.
2867    if image.image_size >= AvbFooter.SIZE:
2868      image.seek(image.image_size - AvbFooter.SIZE)
2869      try:
2870        footer = AvbFooter(image.read(AvbFooter.SIZE))
2871        # Existing footer found. Just truncate.
2872        original_image_size = footer.original_image_size
2873        image.truncate(footer.original_image_size)
2874      except (LookupError, struct.error):
2875        original_image_size = image.image_size
2876    else:
2877      # Image size is too small to possibly contain a footer.
2878      original_image_size = image.image_size
2879
2880    # If anything goes wrong from here-on, restore the image back to
2881    # its original size.
2882    try:
2883      vbmeta_image_handler = ImageHandler(vbmeta_image_filename)
2884      vbmeta_blob = self._load_vbmeta_blob(vbmeta_image_handler)
2885
2886      # If the image isn't sparse, its size might not be a multiple of
2887      # the block size. This will screw up padding later so just grow it.
2888      if image.image_size % image.block_size != 0:
2889        assert not image.is_sparse
2890        padding_needed = image.block_size - (image.image_size%image.block_size)
2891        image.truncate(image.image_size + padding_needed)
2892
2893      # The append_raw() method requires content with size being a
2894      # multiple of |block_size| so add padding as needed. Also record
2895      # where this is written to since we'll need to put that in the
2896      # footer.
2897      vbmeta_offset = image.image_size
2898      padding_needed = (round_to_multiple(len(vbmeta_blob), image.block_size) -
2899                        len(vbmeta_blob))
2900      vbmeta_blob_with_padding = vbmeta_blob + '\0'*padding_needed
2901
2902      # Append vbmeta blob and footer
2903      image.append_raw(vbmeta_blob_with_padding)
2904      vbmeta_end_offset = vbmeta_offset + len(vbmeta_blob_with_padding)
2905
2906      # Now insert a DONT_CARE chunk with enough bytes such that the
2907      # final Footer block is at the end of partition_size..
2908      image.append_dont_care(partition_size - vbmeta_end_offset -
2909                             1*image.block_size)
2910
2911      # Generate the Footer that tells where the VBMeta footer
2912      # is. Also put enough padding in the front of the footer since
2913      # we'll write out an entire block.
2914      footer = AvbFooter()
2915      footer.original_image_size = original_image_size
2916      footer.vbmeta_offset = vbmeta_offset
2917      footer.vbmeta_size = len(vbmeta_blob)
2918      footer_blob = footer.encode()
2919      footer_blob_with_padding = ('\0'*(image.block_size - AvbFooter.SIZE) +
2920                                  footer_blob)
2921      image.append_raw(footer_blob_with_padding)
2922
2923    except:
2924      # Truncate back to original size, then re-raise
2925      image.truncate(original_image_size)
2926      raise
2927
2928  def add_hash_footer(self, image_filename, partition_size, partition_name,
2929                      hash_algorithm, salt, chain_partitions, algorithm_name,
2930                      key_path,
2931                      public_key_metadata_path, rollback_index, flags, props,
2932                      props_from_file, kernel_cmdlines,
2933                      setup_rootfs_from_kernel,
2934                      include_descriptors_from_image, calc_max_image_size,
2935                      signing_helper, signing_helper_with_files,
2936                      release_string, append_to_release_string,
2937                      output_vbmeta_image, do_not_append_vbmeta_image,
2938                      print_required_libavb_version, use_persistent_digest,
2939                      do_not_use_ab):
2940    """Implementation of the add_hash_footer on unsparse images.
2941
2942    Arguments:
2943      image_filename: File to add the footer to.
2944      partition_size: Size of partition.
2945      partition_name: Name of partition (without A/B suffix).
2946      hash_algorithm: Hash algorithm to use.
2947      salt: Salt to use as a hexadecimal string or None to use /dev/urandom.
2948      chain_partitions: List of partitions to chain.
2949      algorithm_name: Name of algorithm to use.
2950      key_path: Path to key to use or None.
2951      public_key_metadata_path: Path to public key metadata or None.
2952      rollback_index: Rollback index.
2953      flags: Flags value to use in the image.
2954      props: Properties to insert (List of strings of the form 'key:value').
2955      props_from_file: Properties to insert (List of strings 'key:<path>').
2956      kernel_cmdlines: Kernel cmdlines to insert (list of strings).
2957      setup_rootfs_from_kernel: None or file to generate
2958        dm-verity kernel cmdline from.
2959      include_descriptors_from_image: List of file objects for which
2960        to insert descriptors from.
2961      calc_max_image_size: Don't store the footer - instead calculate the
2962        maximum image size leaving enough room for metadata with the
2963        given |partition_size|.
2964      signing_helper: Program which signs a hash and return signature.
2965      signing_helper_with_files: Same as signing_helper but uses files instead.
2966      release_string: None or avbtool release string.
2967      append_to_release_string: None or string to append.
2968      output_vbmeta_image: If not None, also write vbmeta struct to this file.
2969      do_not_append_vbmeta_image: If True, don't append vbmeta struct.
2970      print_required_libavb_version: True to only print required libavb version.
2971      use_persistent_digest: Use a persistent digest on device.
2972      do_not_use_ab: This partition does not use A/B.
2973
2974    Raises:
2975      AvbError: If an argument is incorrect.
2976    """
2977
2978    required_libavb_version_minor = 0
2979    if use_persistent_digest or do_not_use_ab:
2980      required_libavb_version_minor = 1
2981
2982    # If we're asked to calculate minimum required libavb version, we're done.
2983    if print_required_libavb_version:
2984      print '1.{}'.format(required_libavb_version_minor)
2985      return
2986
2987    # First, calculate the maximum image size such that an image
2988    # this size + metadata (footer + vbmeta struct) fits in
2989    # |partition_size|.
2990    max_metadata_size = self.MAX_VBMETA_SIZE + self.MAX_FOOTER_SIZE
2991    if partition_size < max_metadata_size:
2992      raise AvbError('Parition size of {} is too small. '
2993                     'Needs to be at least {}'.format(
2994                         partition_size, max_metadata_size))
2995    max_image_size = partition_size - max_metadata_size
2996
2997    # If we're asked to only calculate the maximum image size, we're done.
2998    if calc_max_image_size:
2999      print '{}'.format(max_image_size)
3000      return
3001
3002    image = ImageHandler(image_filename)
3003
3004    if partition_size % image.block_size != 0:
3005      raise AvbError('Partition size of {} is not a multiple of the image '
3006                     'block size {}.'.format(partition_size,
3007                                             image.block_size))
3008
3009    # If there's already a footer, truncate the image to its original
3010    # size. This way 'avbtool add_hash_footer' is idempotent (modulo
3011    # salts).
3012    if image.image_size >= AvbFooter.SIZE:
3013      image.seek(image.image_size - AvbFooter.SIZE)
3014      try:
3015        footer = AvbFooter(image.read(AvbFooter.SIZE))
3016        # Existing footer found. Just truncate.
3017        original_image_size = footer.original_image_size
3018        image.truncate(footer.original_image_size)
3019      except (LookupError, struct.error):
3020        original_image_size = image.image_size
3021    else:
3022      # Image size is too small to possibly contain a footer.
3023      original_image_size = image.image_size
3024
3025    # If anything goes wrong from here-on, restore the image back to
3026    # its original size.
3027    try:
3028      # If image size exceeds the maximum image size, fail.
3029      if image.image_size > max_image_size:
3030        raise AvbError('Image size of {} exceeds maximum image '
3031                       'size of {} in order to fit in a partition '
3032                       'size of {}.'.format(image.image_size, max_image_size,
3033                                            partition_size))
3034
3035      digest_size = len(hashlib.new(name=hash_algorithm).digest())
3036      if salt:
3037        salt = salt.decode('hex')
3038      else:
3039        if salt is None:
3040          # If salt is not explicitly specified, choose a hash
3041          # that's the same size as the hash size.
3042          hash_size = digest_size
3043          salt = open('/dev/urandom').read(hash_size)
3044        else:
3045          salt = ''
3046
3047      hasher = hashlib.new(name=hash_algorithm, string=salt)
3048      # TODO(zeuthen): might want to read this in chunks to avoid
3049      # memory pressure, then again, this is only supposed to be used
3050      # on kernel/initramfs partitions. Possible optimization.
3051      image.seek(0)
3052      hasher.update(image.read(image.image_size))
3053      digest = hasher.digest()
3054
3055      h_desc = AvbHashDescriptor()
3056      h_desc.image_size = image.image_size
3057      h_desc.hash_algorithm = hash_algorithm
3058      h_desc.partition_name = partition_name
3059      h_desc.salt = salt
3060      h_desc.flags = 0
3061      if do_not_use_ab:
3062        h_desc.flags |= 1  # AVB_HASH_DESCRIPTOR_FLAGS_DO_NOT_USE_AB
3063      if not use_persistent_digest:
3064        h_desc.digest = digest
3065
3066      # Generate the VBMeta footer.
3067      ht_desc_to_setup = None
3068      vbmeta_blob = self._generate_vbmeta_blob(
3069          algorithm_name, key_path, public_key_metadata_path, [h_desc],
3070          chain_partitions, rollback_index, flags, props, props_from_file,
3071          kernel_cmdlines, setup_rootfs_from_kernel, ht_desc_to_setup,
3072          include_descriptors_from_image, signing_helper,
3073          signing_helper_with_files, release_string,
3074          append_to_release_string, required_libavb_version_minor)
3075
3076      # Write vbmeta blob, if requested.
3077      if output_vbmeta_image:
3078        output_vbmeta_image.write(vbmeta_blob)
3079
3080      # Append vbmeta blob and footer, unless requested not to.
3081      if not do_not_append_vbmeta_image:
3082        # If the image isn't sparse, its size might not be a multiple of
3083        # the block size. This will screw up padding later so just grow it.
3084        if image.image_size % image.block_size != 0:
3085          assert not image.is_sparse
3086          padding_needed = image.block_size - (
3087              image.image_size % image.block_size)
3088          image.truncate(image.image_size + padding_needed)
3089
3090        # The append_raw() method requires content with size being a
3091        # multiple of |block_size| so add padding as needed. Also record
3092        # where this is written to since we'll need to put that in the
3093        # footer.
3094        vbmeta_offset = image.image_size
3095        padding_needed = (
3096            round_to_multiple(len(vbmeta_blob), image.block_size) -
3097            len(vbmeta_blob))
3098        vbmeta_blob_with_padding = vbmeta_blob + '\0' * padding_needed
3099
3100        image.append_raw(vbmeta_blob_with_padding)
3101        vbmeta_end_offset = vbmeta_offset + len(vbmeta_blob_with_padding)
3102
3103        # Now insert a DONT_CARE chunk with enough bytes such that the
3104        # final Footer block is at the end of partition_size..
3105        image.append_dont_care(partition_size - vbmeta_end_offset -
3106                               1*image.block_size)
3107
3108        # Generate the Footer that tells where the VBMeta footer
3109        # is. Also put enough padding in the front of the footer since
3110        # we'll write out an entire block.
3111        footer = AvbFooter()
3112        footer.original_image_size = original_image_size
3113        footer.vbmeta_offset = vbmeta_offset
3114        footer.vbmeta_size = len(vbmeta_blob)
3115        footer_blob = footer.encode()
3116        footer_blob_with_padding = ('\0'*(image.block_size - AvbFooter.SIZE) +
3117                                    footer_blob)
3118        image.append_raw(footer_blob_with_padding)
3119
3120    except:
3121      # Truncate back to original size, then re-raise
3122      image.truncate(original_image_size)
3123      raise
3124
3125  def add_hashtree_footer(self, image_filename, partition_size, partition_name,
3126                          generate_fec, fec_num_roots, hash_algorithm,
3127                          block_size, salt, chain_partitions, algorithm_name,
3128                          key_path,
3129                          public_key_metadata_path, rollback_index, flags,
3130                          props, props_from_file, kernel_cmdlines,
3131                          setup_rootfs_from_kernel,
3132                          setup_as_rootfs_from_kernel,
3133                          include_descriptors_from_image,
3134                          calc_max_image_size, signing_helper,
3135                          signing_helper_with_files,
3136                          release_string, append_to_release_string,
3137                          output_vbmeta_image, do_not_append_vbmeta_image,
3138                          print_required_libavb_version,
3139                          use_persistent_root_digest, do_not_use_ab):
3140    """Implements the 'add_hashtree_footer' command.
3141
3142    See https://gitlab.com/cryptsetup/cryptsetup/wikis/DMVerity for
3143    more information about dm-verity and these hashes.
3144
3145    Arguments:
3146      image_filename: File to add the footer to.
3147      partition_size: Size of partition or 0 to put it right at the end.
3148      partition_name: Name of partition (without A/B suffix).
3149      generate_fec: If True, generate FEC codes.
3150      fec_num_roots: Number of roots for FEC.
3151      hash_algorithm: Hash algorithm to use.
3152      block_size: Block size to use.
3153      salt: Salt to use as a hexadecimal string or None to use /dev/urandom.
3154      chain_partitions: List of partitions to chain.
3155      algorithm_name: Name of algorithm to use.
3156      key_path: Path to key to use or None.
3157      public_key_metadata_path: Path to public key metadata or None.
3158      rollback_index: Rollback index.
3159      flags: Flags value to use in the image.
3160      props: Properties to insert (List of strings of the form 'key:value').
3161      props_from_file: Properties to insert (List of strings 'key:<path>').
3162      kernel_cmdlines: Kernel cmdlines to insert (list of strings).
3163      setup_rootfs_from_kernel: None or file to generate
3164        dm-verity kernel cmdline from.
3165      setup_as_rootfs_from_kernel: If True, generate dm-verity kernel
3166        cmdline to set up rootfs.
3167      include_descriptors_from_image: List of file objects for which
3168        to insert descriptors from.
3169      calc_max_image_size: Don't store the hashtree or footer - instead
3170        calculate the maximum image size leaving enough room for hashtree
3171        and metadata with the given |partition_size|.
3172      signing_helper: Program which signs a hash and return signature.
3173      signing_helper_with_files: Same as signing_helper but uses files instead.
3174      release_string: None or avbtool release string.
3175      append_to_release_string: None or string to append.
3176      output_vbmeta_image: If not None, also write vbmeta struct to this file.
3177      do_not_append_vbmeta_image: If True, don't append vbmeta struct.
3178      print_required_libavb_version: True to only print required libavb version.
3179      use_persistent_root_digest: Use a persistent root digest on device.
3180      do_not_use_ab: The partition does not use A/B.
3181
3182    Raises:
3183      AvbError: If an argument is incorrect.
3184    """
3185
3186    required_libavb_version_minor = 0
3187    if use_persistent_root_digest or do_not_use_ab:
3188      required_libavb_version_minor = 1
3189
3190    # If we're asked to calculate minimum required libavb version, we're done.
3191    if print_required_libavb_version:
3192      print '1.{}'.format(required_libavb_version_minor)
3193      return
3194
3195    digest_size = len(hashlib.new(name=hash_algorithm).digest())
3196    digest_padding = round_to_pow2(digest_size) - digest_size
3197
3198    # If |partition_size| is given (e.g. not 0), calculate the maximum image
3199    # size such that an image this size + the hashtree + metadata (footer +
3200    # vbmeta struct) fits in |partition_size|. We use very conservative figures
3201    # for metadata.
3202    if partition_size > 0:
3203      (_, max_tree_size) = calc_hash_level_offsets(
3204          partition_size, block_size, digest_size + digest_padding)
3205      max_fec_size = 0
3206      if generate_fec:
3207        max_fec_size = calc_fec_data_size(partition_size, fec_num_roots)
3208      max_metadata_size = (max_fec_size + max_tree_size +
3209                           self.MAX_VBMETA_SIZE +
3210                           self.MAX_FOOTER_SIZE)
3211      max_image_size = partition_size - max_metadata_size
3212    else:
3213      max_image_size = 0
3214
3215    # If we're asked to only calculate the maximum image size, we're done.
3216    if calc_max_image_size:
3217      print '{}'.format(max_image_size)
3218      return
3219
3220    image = ImageHandler(image_filename)
3221
3222    if partition_size > 0:
3223      if partition_size % image.block_size != 0:
3224        raise AvbError('Partition size of {} is not a multiple of the image '
3225                       'block size {}.'.format(partition_size,
3226                                               image.block_size))
3227    else:
3228      if image.image_size % image.block_size != 0:
3229        raise AvbError('File size of {} is not a multiple of the image '
3230                       'block size {}.'.format(image.image_size,
3231                                               image.block_size))
3232
3233    # If there's already a footer, truncate the image to its original
3234    # size. This way 'avbtool add_hashtree_footer' is idempotent
3235    # (modulo salts).
3236    if image.image_size >= AvbFooter.SIZE:
3237      image.seek(image.image_size - AvbFooter.SIZE)
3238      try:
3239        footer = AvbFooter(image.read(AvbFooter.SIZE))
3240        # Existing footer found. Just truncate.
3241        original_image_size = footer.original_image_size
3242        image.truncate(footer.original_image_size)
3243      except (LookupError, struct.error):
3244        original_image_size = image.image_size
3245    else:
3246      # Image size is too small to possibly contain a footer.
3247      original_image_size = image.image_size
3248
3249    # If anything goes wrong from here-on, restore the image back to
3250    # its original size.
3251    try:
3252      # Ensure image is multiple of block_size.
3253      rounded_image_size = round_to_multiple(image.image_size, block_size)
3254      if rounded_image_size > image.image_size:
3255        image.append_raw('\0' * (rounded_image_size - image.image_size))
3256
3257      # If image size exceeds the maximum image size, fail.
3258      if partition_size > 0:
3259        if image.image_size > max_image_size:
3260          raise AvbError('Image size of {} exceeds maximum image '
3261                         'size of {} in order to fit in a partition '
3262                         'size of {}.'.format(image.image_size, max_image_size,
3263                                              partition_size))
3264
3265      if salt:
3266        salt = salt.decode('hex')
3267      else:
3268        if salt is None:
3269          # If salt is not explicitly specified, choose a hash
3270          # that's the same size as the hash size.
3271          hash_size = digest_size
3272          salt = open('/dev/urandom').read(hash_size)
3273        else:
3274          salt = ''
3275
3276      # Hashes are stored upside down so we need to calculate hash
3277      # offsets in advance.
3278      (hash_level_offsets, tree_size) = calc_hash_level_offsets(
3279          image.image_size, block_size, digest_size + digest_padding)
3280
3281      # If the image isn't sparse, its size might not be a multiple of
3282      # the block size. This will screw up padding later so just grow it.
3283      if image.image_size % image.block_size != 0:
3284        assert not image.is_sparse
3285        padding_needed = image.block_size - (image.image_size%image.block_size)
3286        image.truncate(image.image_size + padding_needed)
3287
3288      # Generate the tree and add padding as needed.
3289      tree_offset = image.image_size
3290      root_digest, hash_tree = generate_hash_tree(image, image.image_size,
3291                                                  block_size,
3292                                                  hash_algorithm, salt,
3293                                                  digest_padding,
3294                                                  hash_level_offsets,
3295                                                  tree_size)
3296
3297      # Generate HashtreeDescriptor with details about the tree we
3298      # just generated.
3299      ht_desc = AvbHashtreeDescriptor()
3300      ht_desc.dm_verity_version = 1
3301      ht_desc.image_size = image.image_size
3302      ht_desc.tree_offset = tree_offset
3303      ht_desc.tree_size = tree_size
3304      ht_desc.data_block_size = block_size
3305      ht_desc.hash_block_size = block_size
3306      ht_desc.hash_algorithm = hash_algorithm
3307      ht_desc.partition_name = partition_name
3308      ht_desc.salt = salt
3309      if do_not_use_ab:
3310        ht_desc.flags |= 1  # AVB_HASHTREE_DESCRIPTOR_FLAGS_DO_NOT_USE_AB
3311      if not use_persistent_root_digest:
3312        ht_desc.root_digest = root_digest
3313
3314      # Write the hash tree
3315      padding_needed = (round_to_multiple(len(hash_tree), image.block_size) -
3316                        len(hash_tree))
3317      hash_tree_with_padding = hash_tree + '\0'*padding_needed
3318      image.append_raw(hash_tree_with_padding)
3319      len_hashtree_and_fec = len(hash_tree_with_padding)
3320
3321      # Generate FEC codes, if requested.
3322      if generate_fec:
3323        fec_data = generate_fec_data(image_filename, fec_num_roots)
3324        padding_needed = (round_to_multiple(len(fec_data), image.block_size) -
3325                          len(fec_data))
3326        fec_data_with_padding = fec_data + '\0'*padding_needed
3327        fec_offset = image.image_size
3328        image.append_raw(fec_data_with_padding)
3329        len_hashtree_and_fec += len(fec_data_with_padding)
3330        # Update the hashtree descriptor.
3331        ht_desc.fec_num_roots = fec_num_roots
3332        ht_desc.fec_offset = fec_offset
3333        ht_desc.fec_size = len(fec_data)
3334
3335      ht_desc_to_setup = None
3336      if setup_as_rootfs_from_kernel:
3337        ht_desc_to_setup = ht_desc
3338
3339      # Generate the VBMeta footer and add padding as needed.
3340      vbmeta_offset = tree_offset + len_hashtree_and_fec
3341      vbmeta_blob = self._generate_vbmeta_blob(
3342          algorithm_name, key_path, public_key_metadata_path, [ht_desc],
3343          chain_partitions, rollback_index, flags, props, props_from_file,
3344          kernel_cmdlines, setup_rootfs_from_kernel, ht_desc_to_setup,
3345          include_descriptors_from_image, signing_helper,
3346          signing_helper_with_files, release_string,
3347          append_to_release_string, required_libavb_version_minor)
3348      padding_needed = (round_to_multiple(len(vbmeta_blob), image.block_size) -
3349                        len(vbmeta_blob))
3350      vbmeta_blob_with_padding = vbmeta_blob + '\0'*padding_needed
3351
3352      # Write vbmeta blob, if requested.
3353      if output_vbmeta_image:
3354        output_vbmeta_image.write(vbmeta_blob)
3355
3356      # Append vbmeta blob and footer, unless requested not to.
3357      if not do_not_append_vbmeta_image:
3358        image.append_raw(vbmeta_blob_with_padding)
3359
3360        # Now insert a DONT_CARE chunk with enough bytes such that the
3361        # final Footer block is at the end of partition_size..
3362        if partition_size > 0:
3363          image.append_dont_care(partition_size - image.image_size -
3364                                 1*image.block_size)
3365
3366        # Generate the Footer that tells where the VBMeta footer
3367        # is. Also put enough padding in the front of the footer since
3368        # we'll write out an entire block.
3369        footer = AvbFooter()
3370        footer.original_image_size = original_image_size
3371        footer.vbmeta_offset = vbmeta_offset
3372        footer.vbmeta_size = len(vbmeta_blob)
3373        footer_blob = footer.encode()
3374        footer_blob_with_padding = ('\0'*(image.block_size - AvbFooter.SIZE) +
3375                                    footer_blob)
3376        image.append_raw(footer_blob_with_padding)
3377
3378    except:
3379      # Truncate back to original size, then re-raise.
3380      image.truncate(original_image_size)
3381      raise
3382
3383  def make_atx_certificate(self, output, authority_key_path, subject_key_path,
3384                           subject_key_version, subject,
3385                           is_intermediate_authority, usage, signing_helper,
3386                           signing_helper_with_files):
3387    """Implements the 'make_atx_certificate' command.
3388
3389    Android Things certificates are required for Android Things public key
3390    metadata. They chain the vbmeta signing key for a particular product back to
3391    a fused, permanent root key. These certificates are fixed-length and fixed-
3392    format with the explicit goal of not parsing ASN.1 in bootloader code.
3393
3394    Arguments:
3395      output: Certificate will be written to this file on success.
3396      authority_key_path: A PEM file path with the authority private key.
3397                          If None, then a certificate will be created without a
3398                          signature. The signature can be created out-of-band
3399                          and appended.
3400      subject_key_path: Path to a PEM or DER subject public key.
3401      subject_key_version: A 64-bit version value. If this is None, the number
3402                           of seconds since the epoch is used.
3403      subject: A subject identifier. For Product Signing Key certificates this
3404               should be the same Product ID found in the permanent attributes.
3405      is_intermediate_authority: True if the certificate is for an intermediate
3406                                 authority.
3407      usage: If not empty, overrides the cert usage with a hash of this value.
3408      signing_helper: Program which signs a hash and returns the signature.
3409      signing_helper_with_files: Same as signing_helper but uses files instead.
3410    """
3411    signed_data = bytearray()
3412    signed_data.extend(struct.pack('<I', 1))  # Format Version
3413    signed_data.extend(encode_rsa_key(subject_key_path))
3414    hasher = hashlib.sha256()
3415    hasher.update(subject)
3416    signed_data.extend(hasher.digest())
3417    if not usage:
3418      usage = 'com.google.android.things.vboot'
3419      if is_intermediate_authority:
3420        usage += '.ca'
3421    hasher = hashlib.sha256()
3422    hasher.update(usage)
3423    signed_data.extend(hasher.digest())
3424    if not subject_key_version:
3425      subject_key_version = int(time.time())
3426    signed_data.extend(struct.pack('<Q', subject_key_version))
3427    signature = bytearray()
3428    if authority_key_path:
3429      padding_and_hash = bytearray()
3430      algorithm_name = 'SHA512_RSA4096'
3431      alg = ALGORITHMS[algorithm_name]
3432      hasher = hashlib.sha512()
3433      padding_and_hash.extend(alg.padding)
3434      hasher.update(signed_data)
3435      padding_and_hash.extend(hasher.digest())
3436      signature.extend(raw_sign(signing_helper, signing_helper_with_files,
3437                                algorithm_name,
3438                                alg.signature_num_bytes, authority_key_path,
3439                                padding_and_hash))
3440    output.write(signed_data)
3441    output.write(signature)
3442
3443  def make_atx_permanent_attributes(self, output, root_authority_key_path,
3444                                    product_id):
3445    """Implements the 'make_atx_permanent_attributes' command.
3446
3447    Android Things permanent attributes are designed to be permanent for a
3448    particular product and a hash of these attributes should be fused into
3449    hardware to enforce this.
3450
3451    Arguments:
3452      output: Attributes will be written to this file on success.
3453      root_authority_key_path: Path to a PEM or DER public key for
3454        the root authority.
3455      product_id: A 16-byte Product ID.
3456
3457    Raises:
3458      AvbError: If an argument is incorrect.
3459    """
3460    EXPECTED_PRODUCT_ID_SIZE = 16
3461    if len(product_id) != EXPECTED_PRODUCT_ID_SIZE:
3462      raise AvbError('Invalid Product ID length.')
3463    output.write(struct.pack('<I', 1))  # Format Version
3464    output.write(encode_rsa_key(root_authority_key_path))
3465    output.write(product_id)
3466
3467  def make_atx_metadata(self, output, intermediate_key_certificate,
3468                        product_key_certificate):
3469    """Implements the 'make_atx_metadata' command.
3470
3471    Android Things metadata are included in vbmeta images to facilitate
3472    verification. The output of this command can be used as the
3473    public_key_metadata argument to other commands.
3474
3475    Arguments:
3476      output: Metadata will be written to this file on success.
3477      intermediate_key_certificate: A certificate file as output by
3478                                    make_atx_certificate with
3479                                    is_intermediate_authority set to true.
3480      product_key_certificate: A certificate file as output by
3481                               make_atx_certificate with
3482                               is_intermediate_authority set to false.
3483
3484    Raises:
3485      AvbError: If an argument is incorrect.
3486    """
3487    EXPECTED_CERTIFICATE_SIZE = 1620
3488    if len(intermediate_key_certificate) != EXPECTED_CERTIFICATE_SIZE:
3489      raise AvbError('Invalid intermediate key certificate length.')
3490    if len(product_key_certificate) != EXPECTED_CERTIFICATE_SIZE:
3491      raise AvbError('Invalid product key certificate length.')
3492    output.write(struct.pack('<I', 1))  # Format Version
3493    output.write(intermediate_key_certificate)
3494    output.write(product_key_certificate)
3495
3496  def make_atx_unlock_credential(self, output, intermediate_key_certificate,
3497                                 unlock_key_certificate, challenge_path,
3498                                 unlock_key_path, signing_helper,
3499                                 signing_helper_with_files):
3500    """Implements the 'make_atx_unlock_credential' command.
3501
3502    Android Things unlock credentials can be used to authorize the unlock of AVB
3503    on a device. These credentials are presented to an Android Things bootloader
3504    via the fastboot interface in response to a 16-byte challenge. This method
3505    creates all fields of the credential except the challenge signature field
3506    (which is the last field) and can optionally create the challenge signature
3507    field as well if a challenge and the unlock_key_path is provided.
3508
3509    Arguments:
3510      output: The credential will be written to this file on success.
3511      intermediate_key_certificate: A certificate file as output by
3512                                    make_atx_certificate with
3513                                    is_intermediate_authority set to true.
3514      unlock_key_certificate: A certificate file as output by
3515                              make_atx_certificate with
3516                              is_intermediate_authority set to false and the
3517                              usage set to
3518                              'com.google.android.things.vboot.unlock'.
3519      challenge_path: [optional] A path to the challenge to sign.
3520      unlock_key_path: [optional] A PEM file path with the unlock private key.
3521      signing_helper: Program which signs a hash and returns the signature.
3522      signing_helper_with_files: Same as signing_helper but uses files instead.
3523
3524    Raises:
3525      AvbError: If an argument is incorrect.
3526    """
3527    EXPECTED_CERTIFICATE_SIZE = 1620
3528    EXPECTED_CHALLENGE_SIZE = 16
3529    if len(intermediate_key_certificate) != EXPECTED_CERTIFICATE_SIZE:
3530      raise AvbError('Invalid intermediate key certificate length.')
3531    if len(unlock_key_certificate) != EXPECTED_CERTIFICATE_SIZE:
3532      raise AvbError('Invalid product key certificate length.')
3533    challenge = bytearray()
3534    if challenge_path:
3535      with open(challenge_path, 'r') as f:
3536        challenge = f.read()
3537      if len(challenge) != EXPECTED_CHALLENGE_SIZE:
3538        raise AvbError('Invalid unlock challenge length.')
3539    output.write(struct.pack('<I', 1))  # Format Version
3540    output.write(intermediate_key_certificate)
3541    output.write(unlock_key_certificate)
3542    if challenge_path and unlock_key_path:
3543      signature = bytearray()
3544      padding_and_hash = bytearray()
3545      algorithm_name = 'SHA512_RSA4096'
3546      alg = ALGORITHMS[algorithm_name]
3547      hasher = hashlib.sha512()
3548      padding_and_hash.extend(alg.padding)
3549      hasher.update(challenge)
3550      padding_and_hash.extend(hasher.digest())
3551      signature.extend(raw_sign(signing_helper, signing_helper_with_files,
3552                                algorithm_name,
3553                                alg.signature_num_bytes, unlock_key_path,
3554                                padding_and_hash))
3555      output.write(signature)
3556
3557
3558def calc_hash_level_offsets(image_size, block_size, digest_size):
3559  """Calculate the offsets of all the hash-levels in a Merkle-tree.
3560
3561  Arguments:
3562    image_size: The size of the image to calculate a Merkle-tree for.
3563    block_size: The block size, e.g. 4096.
3564    digest_size: The size of each hash, e.g. 32 for SHA-256.
3565
3566  Returns:
3567    A tuple where the first argument is an array of offsets and the
3568    second is size of the tree, in bytes.
3569  """
3570  level_offsets = []
3571  level_sizes = []
3572  tree_size = 0
3573
3574  num_levels = 0
3575  size = image_size
3576  while size > block_size:
3577    num_blocks = (size + block_size - 1) / block_size
3578    level_size = round_to_multiple(num_blocks * digest_size, block_size)
3579
3580    level_sizes.append(level_size)
3581    tree_size += level_size
3582    num_levels += 1
3583
3584    size = level_size
3585
3586  for n in range(0, num_levels):
3587    offset = 0
3588    for m in range(n + 1, num_levels):
3589      offset += level_sizes[m]
3590    level_offsets.append(offset)
3591
3592  return level_offsets, tree_size
3593
3594
3595# See system/extras/libfec/include/fec/io.h for these definitions.
3596FEC_FOOTER_FORMAT = '<LLLLLQ32s'
3597FEC_MAGIC = 0xfecfecfe
3598
3599
3600def calc_fec_data_size(image_size, num_roots):
3601  """Calculates how much space FEC data will take.
3602
3603  Args:
3604    image_size: The size of the image.
3605    num_roots: Number of roots.
3606
3607  Returns:
3608    The number of bytes needed for FEC for an image of the given size
3609    and with the requested number of FEC roots.
3610
3611  Raises:
3612    ValueError: If output from the 'fec' tool is invalid.
3613
3614  """
3615  p = subprocess.Popen(
3616      ['fec', '--print-fec-size', str(image_size), '--roots', str(num_roots)],
3617      stdout=subprocess.PIPE,
3618      stderr=subprocess.PIPE)
3619  (pout, perr) = p.communicate()
3620  retcode = p.wait()
3621  if retcode != 0:
3622    raise ValueError('Error invoking fec: {}'.format(perr))
3623  return int(pout)
3624
3625
3626def generate_fec_data(image_filename, num_roots):
3627  """Generate FEC codes for an image.
3628
3629  Args:
3630    image_filename: The filename of the image.
3631    num_roots: Number of roots.
3632
3633  Returns:
3634    The FEC data blob.
3635
3636  Raises:
3637    ValueError: If output from the 'fec' tool is invalid.
3638  """
3639  fec_tmpfile = tempfile.NamedTemporaryFile()
3640  subprocess.check_call(
3641      ['fec', '--encode', '--roots', str(num_roots), image_filename,
3642       fec_tmpfile.name],
3643      stderr=open(os.devnull))
3644  fec_data = fec_tmpfile.read()
3645  footer_size = struct.calcsize(FEC_FOOTER_FORMAT)
3646  footer_data = fec_data[-footer_size:]
3647  (magic, _, _, num_roots, fec_size, _, _) = struct.unpack(FEC_FOOTER_FORMAT,
3648                                                           footer_data)
3649  if magic != FEC_MAGIC:
3650    raise ValueError('Unexpected magic in FEC footer')
3651  return fec_data[0:fec_size]
3652
3653
3654def generate_hash_tree(image, image_size, block_size, hash_alg_name, salt,
3655                       digest_padding, hash_level_offsets, tree_size):
3656  """Generates a Merkle-tree for a file.
3657
3658  Args:
3659    image: The image, as a file.
3660    image_size: The size of the image.
3661    block_size: The block size, e.g. 4096.
3662    hash_alg_name: The hash algorithm, e.g. 'sha256' or 'sha1'.
3663    salt: The salt to use.
3664    digest_padding: The padding for each digest.
3665    hash_level_offsets: The offsets from calc_hash_level_offsets().
3666    tree_size: The size of the tree, in number of bytes.
3667
3668  Returns:
3669    A tuple where the first element is the top-level hash and the
3670    second element is the hash-tree.
3671  """
3672  hash_ret = bytearray(tree_size)
3673  hash_src_offset = 0
3674  hash_src_size = image_size
3675  level_num = 0
3676  while hash_src_size > block_size:
3677    level_output = ''
3678    remaining = hash_src_size
3679    while remaining > 0:
3680      hasher = hashlib.new(name=hash_alg_name, string=salt)
3681      # Only read from the file for the first level - for subsequent
3682      # levels, access the array we're building.
3683      if level_num == 0:
3684        image.seek(hash_src_offset + hash_src_size - remaining)
3685        data = image.read(min(remaining, block_size))
3686      else:
3687        offset = hash_level_offsets[level_num - 1] + hash_src_size - remaining
3688        data = hash_ret[offset:offset + block_size]
3689      hasher.update(data)
3690
3691      remaining -= len(data)
3692      if len(data) < block_size:
3693        hasher.update('\0' * (block_size - len(data)))
3694      level_output += hasher.digest()
3695      if digest_padding > 0:
3696        level_output += '\0' * digest_padding
3697
3698    padding_needed = (round_to_multiple(
3699        len(level_output), block_size) - len(level_output))
3700    level_output += '\0' * padding_needed
3701
3702    # Copy level-output into resulting tree.
3703    offset = hash_level_offsets[level_num]
3704    hash_ret[offset:offset + len(level_output)] = level_output
3705
3706    # Continue on to the next level.
3707    hash_src_size = len(level_output)
3708    level_num += 1
3709
3710  hasher = hashlib.new(name=hash_alg_name, string=salt)
3711  hasher.update(level_output)
3712  return hasher.digest(), hash_ret
3713
3714
3715class AvbTool(object):
3716  """Object for avbtool command-line tool."""
3717
3718  def __init__(self):
3719    """Initializer method."""
3720    self.avb = Avb()
3721
3722  def _add_common_args(self, sub_parser):
3723    """Adds arguments used by several sub-commands.
3724
3725    Arguments:
3726      sub_parser: The parser to add arguments to.
3727    """
3728    sub_parser.add_argument('--algorithm',
3729                            help='Algorithm to use (default: NONE)',
3730                            metavar='ALGORITHM',
3731                            default='NONE')
3732    sub_parser.add_argument('--key',
3733                            help='Path to RSA private key file',
3734                            metavar='KEY',
3735                            required=False)
3736    sub_parser.add_argument('--signing_helper',
3737                            help='Path to helper used for signing',
3738                            metavar='APP',
3739                            default=None,
3740                            required=False)
3741    sub_parser.add_argument('--signing_helper_with_files',
3742                            help='Path to helper used for signing using files',
3743                            metavar='APP',
3744                            default=None,
3745                            required=False)
3746    sub_parser.add_argument('--public_key_metadata',
3747                            help='Path to public key metadata file',
3748                            metavar='KEY_METADATA',
3749                            required=False)
3750    sub_parser.add_argument('--rollback_index',
3751                            help='Rollback Index',
3752                            type=parse_number,
3753                            default=0)
3754    # This is used internally for unit tests. Do not include in --help output.
3755    sub_parser.add_argument('--internal_release_string',
3756                            help=argparse.SUPPRESS)
3757    sub_parser.add_argument('--append_to_release_string',
3758                            help='Text to append to release string',
3759                            metavar='STR')
3760    sub_parser.add_argument('--prop',
3761                            help='Add property',
3762                            metavar='KEY:VALUE',
3763                            action='append')
3764    sub_parser.add_argument('--prop_from_file',
3765                            help='Add property from file',
3766                            metavar='KEY:PATH',
3767                            action='append')
3768    sub_parser.add_argument('--kernel_cmdline',
3769                            help='Add kernel cmdline',
3770                            metavar='CMDLINE',
3771                            action='append')
3772    # TODO(zeuthen): the --setup_rootfs_from_kernel option used to be called
3773    # --generate_dm_verity_cmdline_from_hashtree. Remove support for the latter
3774    # at some future point.
3775    sub_parser.add_argument('--setup_rootfs_from_kernel',
3776                            '--generate_dm_verity_cmdline_from_hashtree',
3777                            metavar='IMAGE',
3778                            help='Adds kernel cmdline to set up IMAGE',
3779                            type=argparse.FileType('rb'))
3780    sub_parser.add_argument('--include_descriptors_from_image',
3781                            help='Include descriptors from image',
3782                            metavar='IMAGE',
3783                            action='append',
3784                            type=argparse.FileType('rb'))
3785    sub_parser.add_argument('--print_required_libavb_version',
3786                            help=('Don\'t store the footer - '
3787                                  'instead calculate the required libavb '
3788                                  'version for the given options.'),
3789                            action='store_true')
3790    # These are only allowed from top-level vbmeta and boot-in-lieu-of-vbmeta.
3791    sub_parser.add_argument('--chain_partition',
3792                            help='Allow signed integrity-data for partition',
3793                            metavar='PART_NAME:ROLLBACK_SLOT:KEY_PATH',
3794                            action='append')
3795    sub_parser.add_argument('--flags',
3796                            help='VBMeta flags',
3797                            type=parse_number,
3798                            default=0)
3799    sub_parser.add_argument('--set_hashtree_disabled_flag',
3800                            help='Set the HASHTREE_DISABLED flag',
3801                            action='store_true')
3802
3803  def _add_common_footer_args(self, sub_parser):
3804    """Adds arguments used by add_*_footer sub-commands.
3805
3806    Arguments:
3807      sub_parser: The parser to add arguments to.
3808    """
3809    sub_parser.add_argument('--use_persistent_digest',
3810                            help='Use a persistent digest on device instead of '
3811                                 'storing the digest in the descriptor. This '
3812                                 'cannot be used with A/B so must be combined '
3813                                 'with --do_not_use_ab when an A/B suffix is '
3814                                 'expected at runtime.',
3815                            action='store_true')
3816    sub_parser.add_argument('--do_not_use_ab',
3817                            help='The partition does not use A/B even when an '
3818                                 'A/B suffix is present. This must not be used '
3819                                 'for vbmeta or chained partitions.',
3820                            action='store_true')
3821
3822  def _fixup_common_args(self, args):
3823    """Common fixups needed by subcommands.
3824
3825    Arguments:
3826      args: Arguments to modify.
3827
3828    Returns:
3829      The modified arguments.
3830    """
3831    if args.set_hashtree_disabled_flag:
3832      args.flags |= AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED
3833    return args
3834
3835  def run(self, argv):
3836    """Command-line processor.
3837
3838    Arguments:
3839      argv: Pass sys.argv from main.
3840    """
3841    parser = argparse.ArgumentParser()
3842    subparsers = parser.add_subparsers(title='subcommands')
3843
3844    sub_parser = subparsers.add_parser('version',
3845                                       help='Prints version of avbtool.')
3846    sub_parser.set_defaults(func=self.version)
3847
3848    sub_parser = subparsers.add_parser('extract_public_key',
3849                                       help='Extract public key.')
3850    sub_parser.add_argument('--key',
3851                            help='Path to RSA private key file',
3852                            required=True)
3853    sub_parser.add_argument('--output',
3854                            help='Output file name',
3855                            type=argparse.FileType('wb'),
3856                            required=True)
3857    sub_parser.set_defaults(func=self.extract_public_key)
3858
3859    sub_parser = subparsers.add_parser('make_vbmeta_image',
3860                                       help='Makes a vbmeta image.')
3861    sub_parser.add_argument('--output',
3862                            help='Output file name',
3863                            type=argparse.FileType('wb'))
3864    sub_parser.add_argument('--padding_size',
3865                            metavar='NUMBER',
3866                            help='If non-zero, pads output with NUL bytes so '
3867                                 'its size is a multiple of NUMBER (default: 0)',
3868                            type=parse_number,
3869                            default=0)
3870    self._add_common_args(sub_parser)
3871    sub_parser.set_defaults(func=self.make_vbmeta_image)
3872
3873    sub_parser = subparsers.add_parser('add_hash_footer',
3874                                       help='Add hashes and footer to image.')
3875    sub_parser.add_argument('--image',
3876                            help='Image to add hashes to',
3877                            type=argparse.FileType('rab+'))
3878    sub_parser.add_argument('--partition_size',
3879                            help='Partition size',
3880                            type=parse_number)
3881    sub_parser.add_argument('--partition_name',
3882                            help='Partition name',
3883                            default=None)
3884    sub_parser.add_argument('--hash_algorithm',
3885                            help='Hash algorithm to use (default: sha256)',
3886                            default='sha256')
3887    sub_parser.add_argument('--salt',
3888                            help='Salt in hex (default: /dev/urandom)')
3889    sub_parser.add_argument('--calc_max_image_size',
3890                            help=('Don\'t store the footer - '
3891                                  'instead calculate the maximum image size '
3892                                  'leaving enough room for metadata with '
3893                                  'the given partition size.'),
3894                            action='store_true')
3895    sub_parser.add_argument('--output_vbmeta_image',
3896                            help='Also write vbmeta struct to file',
3897                            type=argparse.FileType('wb'))
3898    sub_parser.add_argument('--do_not_append_vbmeta_image',
3899                            help=('Do not append vbmeta struct or footer '
3900                                  'to the image'),
3901                            action='store_true')
3902    self._add_common_args(sub_parser)
3903    self._add_common_footer_args(sub_parser)
3904    sub_parser.set_defaults(func=self.add_hash_footer)
3905
3906    sub_parser = subparsers.add_parser('append_vbmeta_image',
3907                                       help='Append vbmeta image to image.')
3908    sub_parser.add_argument('--image',
3909                            help='Image to append vbmeta blob to',
3910                            type=argparse.FileType('rab+'))
3911    sub_parser.add_argument('--partition_size',
3912                            help='Partition size',
3913                            type=parse_number,
3914                            required=True)
3915    sub_parser.add_argument('--vbmeta_image',
3916                            help='Image with vbmeta blob to append',
3917                            type=argparse.FileType('rb'))
3918    sub_parser.set_defaults(func=self.append_vbmeta_image)
3919
3920    sub_parser = subparsers.add_parser('add_hashtree_footer',
3921                                       help='Add hashtree and footer to image.')
3922    sub_parser.add_argument('--image',
3923                            help='Image to add hashtree to',
3924                            type=argparse.FileType('rab+'))
3925    sub_parser.add_argument('--partition_size',
3926                            help='Partition size',
3927                            default=0,
3928                            type=parse_number)
3929    sub_parser.add_argument('--partition_name',
3930                            help='Partition name',
3931                            default='')
3932    sub_parser.add_argument('--hash_algorithm',
3933                            help='Hash algorithm to use (default: sha1)',
3934                            default='sha1')
3935    sub_parser.add_argument('--salt',
3936                            help='Salt in hex (default: /dev/urandom)')
3937    sub_parser.add_argument('--block_size',
3938                            help='Block size (default: 4096)',
3939                            type=parse_number,
3940                            default=4096)
3941    # TODO(zeuthen): The --generate_fec option was removed when we
3942    # moved to generating FEC by default. To avoid breaking existing
3943    # users needing to transition we simply just print a warning below
3944    # in add_hashtree_footer(). Remove this option and the warning at
3945    # some point in the future.
3946    sub_parser.add_argument('--generate_fec',
3947                            help=argparse.SUPPRESS,
3948                            action='store_true')
3949    sub_parser.add_argument('--do_not_generate_fec',
3950                            help='Do not generate forward-error-correction codes',
3951                            action='store_true')
3952    sub_parser.add_argument('--fec_num_roots',
3953                            help='Number of roots for FEC (default: 2)',
3954                            type=parse_number,
3955                            default=2)
3956    sub_parser.add_argument('--calc_max_image_size',
3957                            help=('Don\'t store the hashtree or footer - '
3958                                  'instead calculate the maximum image size '
3959                                  'leaving enough room for hashtree '
3960                                  'and metadata with the given partition '
3961                                  'size.'),
3962                            action='store_true')
3963    sub_parser.add_argument('--output_vbmeta_image',
3964                            help='Also write vbmeta struct to file',
3965                            type=argparse.FileType('wb'))
3966    sub_parser.add_argument('--do_not_append_vbmeta_image',
3967                            help=('Do not append vbmeta struct or footer '
3968                                  'to the image'),
3969                            action='store_true')
3970    # This is different from --setup_rootfs_from_kernel insofar that
3971    # it doesn't take an IMAGE, the generated cmdline will be for the
3972    # hashtree we're adding.
3973    sub_parser.add_argument('--setup_as_rootfs_from_kernel',
3974                            action='store_true',
3975                            help='Adds kernel cmdline for setting up rootfs')
3976    self._add_common_args(sub_parser)
3977    self._add_common_footer_args(sub_parser)
3978    sub_parser.set_defaults(func=self.add_hashtree_footer)
3979
3980    sub_parser = subparsers.add_parser('erase_footer',
3981                                       help='Erase footer from an image.')
3982    sub_parser.add_argument('--image',
3983                            help='Image with a footer',
3984                            type=argparse.FileType('rwb+'),
3985                            required=True)
3986    sub_parser.add_argument('--keep_hashtree',
3987                            help='Keep the hashtree and FEC in the image',
3988                            action='store_true')
3989    sub_parser.set_defaults(func=self.erase_footer)
3990
3991    sub_parser = subparsers.add_parser('extract_vbmeta_image',
3992                                       help='Extracts vbmeta from an image with a footer.')
3993    sub_parser.add_argument('--image',
3994                            help='Image with footer',
3995                            type=argparse.FileType('rb'),
3996                            required=True)
3997    sub_parser.add_argument('--output',
3998                            help='Output file name',
3999                            type=argparse.FileType('wb'))
4000    sub_parser.add_argument('--padding_size',
4001                            metavar='NUMBER',
4002                            help='If non-zero, pads output with NUL bytes so '
4003                                 'its size is a multiple of NUMBER (default: 0)',
4004                            type=parse_number,
4005                            default=0)
4006    sub_parser.set_defaults(func=self.extract_vbmeta_image)
4007
4008    sub_parser = subparsers.add_parser('resize_image',
4009                                       help='Resize image with a footer.')
4010    sub_parser.add_argument('--image',
4011                            help='Image with a footer',
4012                            type=argparse.FileType('rwb+'),
4013                            required=True)
4014    sub_parser.add_argument('--partition_size',
4015                            help='New partition size',
4016                            type=parse_number)
4017    sub_parser.set_defaults(func=self.resize_image)
4018
4019    sub_parser = subparsers.add_parser(
4020        'info_image',
4021        help='Show information about vbmeta or footer.')
4022    sub_parser.add_argument('--image',
4023                            help='Image to show information about',
4024                            type=argparse.FileType('rb'),
4025                            required=True)
4026    sub_parser.add_argument('--output',
4027                            help='Write info to file',
4028                            type=argparse.FileType('wt'),
4029                            default=sys.stdout)
4030    sub_parser.set_defaults(func=self.info_image)
4031
4032    sub_parser = subparsers.add_parser(
4033        'verify_image',
4034        help='Verify an image.')
4035    sub_parser.add_argument('--image',
4036                            help='Image to verify',
4037                            type=argparse.FileType('rb'),
4038                            required=True)
4039    sub_parser.add_argument('--key',
4040                            help='Check embedded public key matches KEY',
4041                            metavar='KEY',
4042                            required=False)
4043    sub_parser.add_argument('--expected_chain_partition',
4044                            help='Expected chain partition',
4045                            metavar='PART_NAME:ROLLBACK_SLOT:KEY_PATH',
4046                            action='append')
4047    sub_parser.set_defaults(func=self.verify_image)
4048
4049    sub_parser = subparsers.add_parser(
4050        'calculate_vbmeta_digest',
4051        help='Calculate vbmeta digest.')
4052    sub_parser.add_argument('--image',
4053                            help='Image to calculate digest for',
4054                            type=argparse.FileType('rb'),
4055                            required=True)
4056    sub_parser.add_argument('--hash_algorithm',
4057                            help='Hash algorithm to use (default: sha256)',
4058                            default='sha256')
4059    sub_parser.add_argument('--output',
4060                            help='Write hex digest to file (default: stdout)',
4061                            type=argparse.FileType('wt'),
4062                            default=sys.stdout)
4063    sub_parser.set_defaults(func=self.calculate_vbmeta_digest)
4064
4065    sub_parser = subparsers.add_parser(
4066        'calculate_kernel_cmdline',
4067        help='Calculate kernel cmdline.')
4068    sub_parser.add_argument('--image',
4069                            help='Image to calculate kernel cmdline for',
4070                            type=argparse.FileType('rb'),
4071                            required=True)
4072    sub_parser.add_argument('--hashtree_disabled',
4073                            help='Return the cmdline for hashtree disabled',
4074                            action='store_true')
4075    sub_parser.add_argument('--output',
4076                            help='Write cmdline to file (default: stdout)',
4077                            type=argparse.FileType('wt'),
4078                            default=sys.stdout)
4079    sub_parser.set_defaults(func=self.calculate_kernel_cmdline)
4080
4081    sub_parser = subparsers.add_parser('set_ab_metadata',
4082                                       help='Set A/B metadata.')
4083    sub_parser.add_argument('--misc_image',
4084                            help=('The misc image to modify. If the image does '
4085                                  'not exist, it will be created.'),
4086                            type=argparse.FileType('r+b'),
4087                            required=True)
4088    sub_parser.add_argument('--slot_data',
4089                            help=('Slot data of the form "priority", '
4090                                  '"tries_remaining", "sucessful_boot" for '
4091                                  'slot A followed by the same for slot B, '
4092                                  'separated by colons. The default value '
4093                                  'is 15:7:0:14:7:0.'),
4094                            default='15:7:0:14:7:0')
4095    sub_parser.set_defaults(func=self.set_ab_metadata)
4096
4097    sub_parser = subparsers.add_parser(
4098        'make_atx_certificate',
4099        help='Create an Android Things eXtension (ATX) certificate.')
4100    sub_parser.add_argument('--output',
4101                            help='Write certificate to file',
4102                            type=argparse.FileType('wb'),
4103                            default=sys.stdout)
4104    sub_parser.add_argument('--subject',
4105                            help=('Path to subject file'),
4106                            type=argparse.FileType('rb'),
4107                            required=True)
4108    sub_parser.add_argument('--subject_key',
4109                            help=('Path to subject RSA public key file'),
4110                            type=argparse.FileType('rb'),
4111                            required=True)
4112    sub_parser.add_argument('--subject_key_version',
4113                            help=('Version of the subject key'),
4114                            type=parse_number,
4115                            required=False)
4116    sub_parser.add_argument('--subject_is_intermediate_authority',
4117                            help=('Generate an intermediate authority '
4118                                  'certificate'),
4119                            action='store_true')
4120    sub_parser.add_argument('--usage',
4121                            help=('Override usage with a hash of the provided '
4122                                  'string'),
4123                            required=False)
4124    sub_parser.add_argument('--authority_key',
4125                            help='Path to authority RSA private key file',
4126                            required=False)
4127    sub_parser.add_argument('--signing_helper',
4128                            help='Path to helper used for signing',
4129                            metavar='APP',
4130                            default=None,
4131                            required=False)
4132    sub_parser.add_argument('--signing_helper_with_files',
4133                            help='Path to helper used for signing using files',
4134                            metavar='APP',
4135                            default=None,
4136                            required=False)
4137    sub_parser.set_defaults(func=self.make_atx_certificate)
4138
4139    sub_parser = subparsers.add_parser(
4140        'make_atx_permanent_attributes',
4141        help='Create Android Things eXtension (ATX) permanent attributes.')
4142    sub_parser.add_argument('--output',
4143                            help='Write attributes to file',
4144                            type=argparse.FileType('wb'),
4145                            default=sys.stdout)
4146    sub_parser.add_argument('--root_authority_key',
4147                            help='Path to authority RSA public key file',
4148                            type=argparse.FileType('rb'),
4149                            required=True)
4150    sub_parser.add_argument('--product_id',
4151                            help=('Path to Product ID file'),
4152                            type=argparse.FileType('rb'),
4153                            required=True)
4154    sub_parser.set_defaults(func=self.make_atx_permanent_attributes)
4155
4156    sub_parser = subparsers.add_parser(
4157        'make_atx_metadata',
4158        help='Create Android Things eXtension (ATX) metadata.')
4159    sub_parser.add_argument('--output',
4160                            help='Write metadata to file',
4161                            type=argparse.FileType('wb'),
4162                            default=sys.stdout)
4163    sub_parser.add_argument('--intermediate_key_certificate',
4164                            help='Path to intermediate key certificate file',
4165                            type=argparse.FileType('rb'),
4166                            required=True)
4167    sub_parser.add_argument('--product_key_certificate',
4168                            help='Path to product key certificate file',
4169                            type=argparse.FileType('rb'),
4170                            required=True)
4171    sub_parser.set_defaults(func=self.make_atx_metadata)
4172
4173    sub_parser = subparsers.add_parser(
4174        'make_atx_unlock_credential',
4175        help='Create an Android Things eXtension (ATX) unlock credential.')
4176    sub_parser.add_argument('--output',
4177                            help='Write credential to file',
4178                            type=argparse.FileType('wb'),
4179                            default=sys.stdout)
4180    sub_parser.add_argument('--intermediate_key_certificate',
4181                            help='Path to intermediate key certificate file',
4182                            type=argparse.FileType('rb'),
4183                            required=True)
4184    sub_parser.add_argument('--unlock_key_certificate',
4185                            help='Path to unlock key certificate file',
4186                            type=argparse.FileType('rb'),
4187                            required=True)
4188    sub_parser.add_argument('--challenge',
4189                            help='Path to the challenge to sign (optional). If '
4190                                 'this is not provided the challenge signature '
4191                                 'field is omitted and can be concatenated '
4192                                 'later.',
4193                            required=False)
4194    sub_parser.add_argument('--unlock_key',
4195                            help='Path to unlock key (optional). Must be '
4196                                 'provided if using --challenge.',
4197                            required=False)
4198    sub_parser.add_argument('--signing_helper',
4199                            help='Path to helper used for signing',
4200                            metavar='APP',
4201                            default=None,
4202                            required=False)
4203    sub_parser.add_argument('--signing_helper_with_files',
4204                            help='Path to helper used for signing using files',
4205                            metavar='APP',
4206                            default=None,
4207                            required=False)
4208    sub_parser.set_defaults(func=self.make_atx_unlock_credential)
4209
4210    args = parser.parse_args(argv[1:])
4211    try:
4212      args.func(args)
4213    except AvbError as e:
4214      sys.stderr.write('{}: {}\n'.format(argv[0], e.message))
4215      sys.exit(1)
4216
4217  def version(self, _):
4218    """Implements the 'version' sub-command."""
4219    print get_release_string()
4220
4221  def extract_public_key(self, args):
4222    """Implements the 'extract_public_key' sub-command."""
4223    self.avb.extract_public_key(args.key, args.output)
4224
4225  def make_vbmeta_image(self, args):
4226    """Implements the 'make_vbmeta_image' sub-command."""
4227    args = self._fixup_common_args(args)
4228    self.avb.make_vbmeta_image(args.output, args.chain_partition,
4229                               args.algorithm, args.key,
4230                               args.public_key_metadata, args.rollback_index,
4231                               args.flags, args.prop, args.prop_from_file,
4232                               args.kernel_cmdline,
4233                               args.setup_rootfs_from_kernel,
4234                               args.include_descriptors_from_image,
4235                               args.signing_helper,
4236                               args.signing_helper_with_files,
4237                               args.internal_release_string,
4238                               args.append_to_release_string,
4239                               args.print_required_libavb_version,
4240                               args.padding_size)
4241
4242  def append_vbmeta_image(self, args):
4243    """Implements the 'append_vbmeta_image' sub-command."""
4244    self.avb.append_vbmeta_image(args.image.name, args.vbmeta_image.name,
4245                                 args.partition_size)
4246
4247  def add_hash_footer(self, args):
4248    """Implements the 'add_hash_footer' sub-command."""
4249    args = self._fixup_common_args(args)
4250    self.avb.add_hash_footer(args.image.name if args.image else None,
4251                             args.partition_size,
4252                             args.partition_name, args.hash_algorithm,
4253                             args.salt, args.chain_partition, args.algorithm,
4254                             args.key,
4255                             args.public_key_metadata, args.rollback_index,
4256                             args.flags, args.prop, args.prop_from_file,
4257                             args.kernel_cmdline,
4258                             args.setup_rootfs_from_kernel,
4259                             args.include_descriptors_from_image,
4260                             args.calc_max_image_size,
4261                             args.signing_helper,
4262                             args.signing_helper_with_files,
4263                             args.internal_release_string,
4264                             args.append_to_release_string,
4265                             args.output_vbmeta_image,
4266                             args.do_not_append_vbmeta_image,
4267                             args.print_required_libavb_version,
4268                             args.use_persistent_digest,
4269                             args.do_not_use_ab)
4270
4271  def add_hashtree_footer(self, args):
4272    """Implements the 'add_hashtree_footer' sub-command."""
4273    args = self._fixup_common_args(args)
4274    # TODO(zeuthen): Remove when removing support for the
4275    # '--generate_fec' option above.
4276    if args.generate_fec:
4277      sys.stderr.write('The --generate_fec option is deprecated since FEC '
4278                       'is now generated by default. Use the option '
4279                       '--do_not_generate_fec to not generate FEC.\n')
4280    self.avb.add_hashtree_footer(args.image.name if args.image else None,
4281                                 args.partition_size,
4282                                 args.partition_name,
4283                                 not args.do_not_generate_fec, args.fec_num_roots,
4284                                 args.hash_algorithm, args.block_size,
4285                                 args.salt, args.chain_partition, args.algorithm,
4286                                 args.key, args.public_key_metadata,
4287                                 args.rollback_index, args.flags, args.prop,
4288                                 args.prop_from_file,
4289                                 args.kernel_cmdline,
4290                                 args.setup_rootfs_from_kernel,
4291                                 args.setup_as_rootfs_from_kernel,
4292                                 args.include_descriptors_from_image,
4293                                 args.calc_max_image_size,
4294                                 args.signing_helper,
4295                                 args.signing_helper_with_files,
4296                                 args.internal_release_string,
4297                                 args.append_to_release_string,
4298                                 args.output_vbmeta_image,
4299                                 args.do_not_append_vbmeta_image,
4300                                 args.print_required_libavb_version,
4301                                 args.use_persistent_digest,
4302                                 args.do_not_use_ab)
4303
4304  def erase_footer(self, args):
4305    """Implements the 'erase_footer' sub-command."""
4306    self.avb.erase_footer(args.image.name, args.keep_hashtree)
4307
4308  def extract_vbmeta_image(self, args):
4309    """Implements the 'extract_vbmeta_image' sub-command."""
4310    self.avb.extract_vbmeta_image(args.output, args.image.name,
4311                                  args.padding_size)
4312
4313  def resize_image(self, args):
4314    """Implements the 'resize_image' sub-command."""
4315    self.avb.resize_image(args.image.name, args.partition_size)
4316
4317  def set_ab_metadata(self, args):
4318    """Implements the 'set_ab_metadata' sub-command."""
4319    self.avb.set_ab_metadata(args.misc_image, args.slot_data)
4320
4321  def info_image(self, args):
4322    """Implements the 'info_image' sub-command."""
4323    self.avb.info_image(args.image.name, args.output)
4324
4325  def verify_image(self, args):
4326    """Implements the 'verify_image' sub-command."""
4327    self.avb.verify_image(args.image.name, args.key,
4328                          args.expected_chain_partition)
4329
4330  def calculate_vbmeta_digest(self, args):
4331    """Implements the 'calculate_vbmeta_digest' sub-command."""
4332    self.avb.calculate_vbmeta_digest(args.image.name, args.hash_algorithm,
4333                                     args.output)
4334
4335  def calculate_kernel_cmdline(self, args):
4336    """Implements the 'calculate_kernel_cmdline' sub-command."""
4337    self.avb.calculate_kernel_cmdline(args.image.name, args.hashtree_disabled, args.output)
4338
4339  def make_atx_certificate(self, args):
4340    """Implements the 'make_atx_certificate' sub-command."""
4341    self.avb.make_atx_certificate(args.output, args.authority_key,
4342                                  args.subject_key.name,
4343                                  args.subject_key_version,
4344                                  args.subject.read(),
4345                                  args.subject_is_intermediate_authority,
4346                                  args.usage,
4347                                  args.signing_helper,
4348                                  args.signing_helper_with_files)
4349
4350  def make_atx_permanent_attributes(self, args):
4351    """Implements the 'make_atx_permanent_attributes' sub-command."""
4352    self.avb.make_atx_permanent_attributes(args.output,
4353                                           args.root_authority_key.name,
4354                                           args.product_id.read())
4355
4356  def make_atx_metadata(self, args):
4357    """Implements the 'make_atx_metadata' sub-command."""
4358    self.avb.make_atx_metadata(args.output,
4359                               args.intermediate_key_certificate.read(),
4360                               args.product_key_certificate.read())
4361
4362  def make_atx_unlock_credential(self, args):
4363    """Implements the 'make_atx_unlock_credential' sub-command."""
4364    self.avb.make_atx_unlock_credential(
4365        args.output,
4366        args.intermediate_key_certificate.read(),
4367        args.unlock_key_certificate.read(),
4368        args.challenge,
4369        args.unlock_key,
4370        args.signing_helper,
4371        args.signing_helper_with_files)
4372
4373
4374if __name__ == '__main__':
4375  tool = AvbTool()
4376  tool.run(sys.argv)
4377