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