blob: dd54011cb8abe18353a20b319a91440e81efedf5 [file] [log] [blame]
David Zeuthen21e95262016-07-27 17:58:40 -04001#!/usr/bin/env python
2
3# Copyright 2016, The Android Open Source Project
4#
David Zeuthenc612e2e2016-09-16 16:44:08 -04005# Permission is hereby granted, free of charge, to any person
6# obtaining a copy of this software and associated documentation
7# files (the "Software"), to deal in the Software without
8# restriction, including without limitation the rights to use, copy,
9# modify, merge, publish, distribute, sublicense, and/or sell copies
10# of the Software, and to permit persons to whom the Software is
11# furnished to do so, subject to the following conditions:
David Zeuthen21e95262016-07-27 17:58:40 -040012#
David Zeuthenc612e2e2016-09-16 16:44:08 -040013# The above copyright notice and this permission notice shall be
14# included in all copies or substantial portions of the Software.
David Zeuthen21e95262016-07-27 17:58:40 -040015#
David Zeuthenc612e2e2016-09-16 16:44:08 -040016# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23# SOFTWARE.
David Zeuthen21e95262016-07-27 17:58:40 -040024#
David Zeuthen8b6973b2016-09-20 12:39:49 -040025"""Command-line tool for working with Android Verified Boot images."""
David Zeuthen21e95262016-07-27 17:58:40 -040026
27import argparse
David Zeuthen8b6973b2016-09-20 12:39:49 -040028import binascii
David Zeuthena4fee8b2016-08-22 15:20:43 -040029import bisect
David Zeuthen21e95262016-07-27 17:58:40 -040030import hashlib
David Zeuthenc68f0822017-03-31 17:22:35 -040031import math
David Zeuthen21e95262016-07-27 17:58:40 -040032import os
33import struct
34import subprocess
35import sys
David Zeuthen0b7f1d32016-10-25 17:53:49 -040036import tempfile
Darren Krahn147b08d2016-12-20 16:38:29 -080037import time
David Zeuthen21e95262016-07-27 17:58:40 -040038
David Zeuthene3cadca2017-02-22 21:25:46 -050039# Keep in sync with libavb/avb_version.h.
David Zeuthen21e95262016-07-27 17:58:40 -040040AVB_VERSION_MAJOR = 1
Darren Krahnfd0ba0d2018-02-01 18:06:34 -080041AVB_VERSION_MINOR = 1
David Zeuthene3cadca2017-02-22 21:25:46 -050042AVB_VERSION_SUB = 0
43
Darren Krahnfd0ba0d2018-02-01 18:06:34 -080044# Keep in sync with libavb/avb_footer.h.
45AVB_FOOTER_VERSION_MAJOR = 1
46AVB_FOOTER_VERSION_MINOR = 0
47
David Zeuthen58305522017-01-11 17:42:47 -050048AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED = 1
David Zeuthen21e95262016-07-27 17:58:40 -040049
David Zeuthene3cadca2017-02-22 21:25:46 -050050
David Zeuthen21e95262016-07-27 17:58:40 -040051class AvbError(Exception):
52 """Application-specific errors.
53
54 These errors represent issues for which a stack-trace should not be
55 presented.
56
57 Attributes:
58 message: Error message.
59 """
60
61 def __init__(self, message):
62 Exception.__init__(self, message)
63
64
65class Algorithm(object):
66 """Contains details about an algorithm.
67
Tao Bao80418a52018-07-20 11:41:22 -070068 See the avb_vbmeta_image.h file for more details about algorithms.
David Zeuthen21e95262016-07-27 17:58:40 -040069
70 The constant |ALGORITHMS| is a dictionary from human-readable
71 names (e.g 'SHA256_RSA2048') to instances of this class.
72
73 Attributes:
74 algorithm_type: Integer code corresponding to |AvbAlgorithmType|.
David Zeuthenb623d8b2017-04-04 16:05:53 -040075 hash_name: Empty or a name from |hashlib.algorithms|.
David Zeuthen21e95262016-07-27 17:58:40 -040076 hash_num_bytes: Number of bytes used to store the hash.
77 signature_num_bytes: Number of bytes used to store the signature.
78 public_key_num_bytes: Number of bytes used to store the public key.
79 padding: Padding used for signature, if any.
80 """
81
David Zeuthenb623d8b2017-04-04 16:05:53 -040082 def __init__(self, algorithm_type, hash_name, hash_num_bytes,
83 signature_num_bytes, public_key_num_bytes, padding):
David Zeuthen21e95262016-07-27 17:58:40 -040084 self.algorithm_type = algorithm_type
David Zeuthenb623d8b2017-04-04 16:05:53 -040085 self.hash_name = hash_name
David Zeuthen21e95262016-07-27 17:58:40 -040086 self.hash_num_bytes = hash_num_bytes
87 self.signature_num_bytes = signature_num_bytes
88 self.public_key_num_bytes = public_key_num_bytes
89 self.padding = padding
90
David Zeuthenb623d8b2017-04-04 16:05:53 -040091
David Zeuthen21e95262016-07-27 17:58:40 -040092# This must be kept in sync with the avb_crypto.h file.
93#
94# The PKC1-v1.5 padding is a blob of binary DER of ASN.1 and is
95# obtained from section 5.2.2 of RFC 4880.
96ALGORITHMS = {
97 'NONE': Algorithm(
98 algorithm_type=0, # AVB_ALGORITHM_TYPE_NONE
David Zeuthenb623d8b2017-04-04 16:05:53 -040099 hash_name='',
David Zeuthen21e95262016-07-27 17:58:40 -0400100 hash_num_bytes=0,
101 signature_num_bytes=0,
102 public_key_num_bytes=0,
103 padding=[]),
104 'SHA256_RSA2048': Algorithm(
105 algorithm_type=1, # AVB_ALGORITHM_TYPE_SHA256_RSA2048
David Zeuthenb623d8b2017-04-04 16:05:53 -0400106 hash_name='sha256',
David Zeuthen21e95262016-07-27 17:58:40 -0400107 hash_num_bytes=32,
108 signature_num_bytes=256,
109 public_key_num_bytes=8 + 2*2048/8,
110 padding=[
111 # PKCS1-v1_5 padding
112 0x00, 0x01] + [0xff]*202 + [0x00] + [
113 # ASN.1 header
114 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
115 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05,
116 0x00, 0x04, 0x20,
117 ]),
118 'SHA256_RSA4096': Algorithm(
119 algorithm_type=2, # AVB_ALGORITHM_TYPE_SHA256_RSA4096
David Zeuthenb623d8b2017-04-04 16:05:53 -0400120 hash_name='sha256',
David Zeuthen21e95262016-07-27 17:58:40 -0400121 hash_num_bytes=32,
122 signature_num_bytes=512,
123 public_key_num_bytes=8 + 2*4096/8,
124 padding=[
125 # PKCS1-v1_5 padding
126 0x00, 0x01] + [0xff]*458 + [0x00] + [
127 # ASN.1 header
128 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
129 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05,
130 0x00, 0x04, 0x20,
131 ]),
132 'SHA256_RSA8192': Algorithm(
133 algorithm_type=3, # AVB_ALGORITHM_TYPE_SHA256_RSA8192
David Zeuthenb623d8b2017-04-04 16:05:53 -0400134 hash_name='sha256',
David Zeuthen21e95262016-07-27 17:58:40 -0400135 hash_num_bytes=32,
136 signature_num_bytes=1024,
137 public_key_num_bytes=8 + 2*8192/8,
138 padding=[
139 # PKCS1-v1_5 padding
140 0x00, 0x01] + [0xff]*970 + [0x00] + [
141 # ASN.1 header
142 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
143 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05,
144 0x00, 0x04, 0x20,
145 ]),
146 'SHA512_RSA2048': Algorithm(
147 algorithm_type=4, # AVB_ALGORITHM_TYPE_SHA512_RSA2048
David Zeuthenb623d8b2017-04-04 16:05:53 -0400148 hash_name='sha512',
David Zeuthen21e95262016-07-27 17:58:40 -0400149 hash_num_bytes=64,
150 signature_num_bytes=256,
151 public_key_num_bytes=8 + 2*2048/8,
152 padding=[
153 # PKCS1-v1_5 padding
154 0x00, 0x01] + [0xff]*170 + [0x00] + [
155 # ASN.1 header
156 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
157 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05,
158 0x00, 0x04, 0x40
159 ]),
160 'SHA512_RSA4096': Algorithm(
161 algorithm_type=5, # AVB_ALGORITHM_TYPE_SHA512_RSA4096
David Zeuthenb623d8b2017-04-04 16:05:53 -0400162 hash_name='sha512',
David Zeuthen21e95262016-07-27 17:58:40 -0400163 hash_num_bytes=64,
164 signature_num_bytes=512,
165 public_key_num_bytes=8 + 2*4096/8,
166 padding=[
167 # PKCS1-v1_5 padding
168 0x00, 0x01] + [0xff]*426 + [0x00] + [
169 # ASN.1 header
170 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
171 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05,
172 0x00, 0x04, 0x40
173 ]),
174 'SHA512_RSA8192': Algorithm(
175 algorithm_type=6, # AVB_ALGORITHM_TYPE_SHA512_RSA8192
David Zeuthenb623d8b2017-04-04 16:05:53 -0400176 hash_name='sha512',
David Zeuthen21e95262016-07-27 17:58:40 -0400177 hash_num_bytes=64,
178 signature_num_bytes=1024,
179 public_key_num_bytes=8 + 2*8192/8,
180 padding=[
181 # PKCS1-v1_5 padding
182 0x00, 0x01] + [0xff]*938 + [0x00] + [
183 # ASN.1 header
184 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
185 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05,
186 0x00, 0x04, 0x40
187 ]),
188}
189
190
David Zeuthene3cadca2017-02-22 21:25:46 -0500191def get_release_string():
192 """Calculates the release string to use in the VBMeta struct."""
193 # Keep in sync with libavb/avb_version.c:avb_version_string().
194 return 'avbtool {}.{}.{}'.format(AVB_VERSION_MAJOR,
195 AVB_VERSION_MINOR,
196 AVB_VERSION_SUB)
197
198
David Zeuthen21e95262016-07-27 17:58:40 -0400199def round_to_multiple(number, size):
200 """Rounds a number up to nearest multiple of another number.
201
202 Args:
203 number: The number to round up.
204 size: The multiple to round up to.
205
206 Returns:
207 If |number| is a multiple of |size|, returns |number|, otherwise
208 returns |number| + |size|.
209 """
210 remainder = number % size
211 if remainder == 0:
212 return number
213 return number + size - remainder
214
215
216def round_to_pow2(number):
217 """Rounds a number up to the next power of 2.
218
219 Args:
220 number: The number to round up.
221
222 Returns:
223 If |number| is already a power of 2 then |number| is
224 returned. Otherwise the smallest power of 2 greater than |number|
225 is returned.
226 """
227 return 2**((number - 1).bit_length())
228
229
David Zeuthen21e95262016-07-27 17:58:40 -0400230def encode_long(num_bits, value):
231 """Encodes a long to a bytearray() using a given amount of bits.
232
233 This number is written big-endian, e.g. with the most significant
234 bit first.
235
David Zeuthenb623d8b2017-04-04 16:05:53 -0400236 This is the reverse of decode_long().
237
David Zeuthen21e95262016-07-27 17:58:40 -0400238 Arguments:
239 num_bits: The number of bits to write, e.g. 2048.
240 value: The value to write.
241
242 Returns:
243 A bytearray() with the encoded long.
244 """
245 ret = bytearray()
246 for bit_pos in range(num_bits, 0, -8):
247 octet = (value >> (bit_pos - 8)) & 0xff
248 ret.extend(struct.pack('!B', octet))
249 return ret
250
251
David Zeuthenb623d8b2017-04-04 16:05:53 -0400252def decode_long(blob):
253 """Decodes a long from a bytearray() using a given amount of bits.
254
255 This number is expected to be in big-endian, e.g. with the most
256 significant bit first.
257
258 This is the reverse of encode_long().
259
260 Arguments:
261 value: A bytearray() with the encoded long.
262
263 Returns:
264 The decoded value.
265 """
266 ret = 0
267 for b in bytearray(blob):
268 ret *= 256
269 ret += b
270 return ret
271
272
David Zeuthen21e95262016-07-27 17:58:40 -0400273def egcd(a, b):
274 """Calculate greatest common divisor of two numbers.
275
276 This implementation uses a recursive version of the extended
277 Euclidian algorithm.
278
279 Arguments:
280 a: First number.
281 b: Second number.
282
283 Returns:
284 A tuple (gcd, x, y) that where |gcd| is the greatest common
285 divisor of |a| and |b| and |a|*|x| + |b|*|y| = |gcd|.
286 """
287 if a == 0:
288 return (b, 0, 1)
289 else:
290 g, y, x = egcd(b % a, a)
291 return (g, x - (b // a) * y, y)
292
293
294def modinv(a, m):
295 """Calculate modular multiplicative inverse of |a| modulo |m|.
296
297 This calculates the number |x| such that |a| * |x| == 1 (modulo
298 |m|). This number only exists if |a| and |m| are co-prime - |None|
299 is returned if this isn't true.
300
301 Arguments:
302 a: The number to calculate a modular inverse of.
303 m: The modulo to use.
304
305 Returns:
306 The modular multiplicative inverse of |a| and |m| or |None| if
307 these numbers are not co-prime.
308 """
309 gcd, x, _ = egcd(a, m)
310 if gcd != 1:
311 return None # modular inverse does not exist
312 else:
313 return x % m
314
315
316def parse_number(string):
317 """Parse a string as a number.
318
319 This is just a short-hand for int(string, 0) suitable for use in the
320 |type| parameter of |ArgumentParser|'s add_argument() function. An
321 improvement to just using type=int is that this function supports
322 numbers in other bases, e.g. "0x1234".
323
324 Arguments:
325 string: The string to parse.
326
327 Returns:
328 The parsed integer.
329
330 Raises:
331 ValueError: If the number could not be parsed.
332 """
333 return int(string, 0)
334
335
David Zeuthenc68f0822017-03-31 17:22:35 -0400336class RSAPublicKey(object):
337 """Data structure used for a RSA public key.
David Zeuthen21e95262016-07-27 17:58:40 -0400338
David Zeuthenc68f0822017-03-31 17:22:35 -0400339 Attributes:
340 exponent: The key exponent.
341 modulus: The key modulus.
342 num_bits: The key size.
David Zeuthen21e95262016-07-27 17:58:40 -0400343 """
David Zeuthenc68f0822017-03-31 17:22:35 -0400344
345 MODULUS_PREFIX = 'modulus='
346
347 def __init__(self, key_path):
348 """Loads and parses an RSA key from either a private or public key file.
349
350 Arguments:
351 key_path: The path to a key file.
352 """
353 # We used to have something as simple as this:
354 #
355 # key = Crypto.PublicKey.RSA.importKey(open(key_path).read())
356 # self.exponent = key.e
357 # self.modulus = key.n
358 # self.num_bits = key.size() + 1
359 #
360 # but unfortunately PyCrypto is not available in the builder. So
361 # instead just parse openssl(1) output to get this
362 # information. It's ugly but...
363 args = ['openssl', 'rsa', '-in', key_path, '-modulus', '-noout']
364 p = subprocess.Popen(args,
365 stdin=subprocess.PIPE,
366 stdout=subprocess.PIPE,
367 stderr=subprocess.PIPE)
368 (pout, perr) = p.communicate()
369 if p.wait() != 0:
370 # Could be just a public key is passed, try that.
371 args.append('-pubin')
372 p = subprocess.Popen(args,
373 stdin=subprocess.PIPE,
374 stdout=subprocess.PIPE,
375 stderr=subprocess.PIPE)
376 (pout, perr) = p.communicate()
377 if p.wait() != 0:
378 raise AvbError('Error getting public key: {}'.format(perr))
379
380 if not pout.lower().startswith(self.MODULUS_PREFIX):
381 raise AvbError('Unexpected modulus output')
382
383 modulus_hexstr = pout[len(self.MODULUS_PREFIX):]
384
385 # The exponent is assumed to always be 65537 and the number of
386 # bits can be derived from the modulus by rounding up to the
387 # nearest power of 2.
388 self.modulus = int(modulus_hexstr, 16)
389 self.num_bits = round_to_pow2(int(math.ceil(math.log(self.modulus, 2))))
390 self.exponent = 65537
David Zeuthen21e95262016-07-27 17:58:40 -0400391
392
David Zeuthenc68f0822017-03-31 17:22:35 -0400393def encode_rsa_key(key_path):
David Zeuthen21e95262016-07-27 17:58:40 -0400394 """Encodes a public RSA key in |AvbRSAPublicKeyHeader| format.
395
396 This creates a |AvbRSAPublicKeyHeader| as well as the two large
397 numbers (|key_num_bits| bits long) following it.
398
399 Arguments:
David Zeuthenc68f0822017-03-31 17:22:35 -0400400 key_path: The path to a key file.
David Zeuthen21e95262016-07-27 17:58:40 -0400401
402 Returns:
403 A bytearray() with the |AvbRSAPublicKeyHeader|.
404 """
David Zeuthenc68f0822017-03-31 17:22:35 -0400405 key = RSAPublicKey(key_path)
406 if key.exponent != 65537:
407 raise AvbError('Only RSA keys with exponent 65537 are supported.')
David Zeuthen21e95262016-07-27 17:58:40 -0400408 ret = bytearray()
David Zeuthen21e95262016-07-27 17:58:40 -0400409 # Calculate n0inv = -1/n[0] (mod 2^32)
410 b = 2L**32
David Zeuthenc68f0822017-03-31 17:22:35 -0400411 n0inv = b - modinv(key.modulus, b)
David Zeuthen21e95262016-07-27 17:58:40 -0400412 # Calculate rr = r^2 (mod N), where r = 2^(# of key bits)
David Zeuthenc68f0822017-03-31 17:22:35 -0400413 r = 2L**key.modulus.bit_length()
414 rrmodn = r * r % key.modulus
415 ret.extend(struct.pack('!II', key.num_bits, n0inv))
416 ret.extend(encode_long(key.num_bits, key.modulus))
417 ret.extend(encode_long(key.num_bits, rrmodn))
David Zeuthen21e95262016-07-27 17:58:40 -0400418 return ret
419
420
421def lookup_algorithm_by_type(alg_type):
422 """Looks up algorithm by type.
423
424 Arguments:
425 alg_type: The integer representing the type.
426
427 Returns:
428 A tuple with the algorithm name and an |Algorithm| instance.
429
430 Raises:
431 Exception: If the algorithm cannot be found
432 """
433 for alg_name in ALGORITHMS:
434 alg_data = ALGORITHMS[alg_name]
435 if alg_data.algorithm_type == alg_type:
436 return (alg_name, alg_data)
437 raise AvbError('Unknown algorithm type {}'.format(alg_type))
438
439
David Zeuthena156d3d2017-06-01 12:08:09 -0400440def raw_sign(signing_helper, signing_helper_with_files,
441 algorithm_name, signature_num_bytes, key_path,
Esun Kimff44f232017-03-30 10:34:54 +0900442 raw_data_to_sign):
Darren Krahn147b08d2016-12-20 16:38:29 -0800443 """Computes a raw RSA signature using |signing_helper| or openssl.
444
445 Arguments:
446 signing_helper: Program which signs a hash and returns the signature.
David Zeuthena156d3d2017-06-01 12:08:09 -0400447 signing_helper_with_files: Same as signing_helper but uses files instead.
Darren Krahn147b08d2016-12-20 16:38:29 -0800448 algorithm_name: The algorithm name as per the ALGORITHMS dict.
Esun Kimff44f232017-03-30 10:34:54 +0900449 signature_num_bytes: Number of bytes used to store the signature.
Darren Krahn147b08d2016-12-20 16:38:29 -0800450 key_path: Path to the private key file. Must be PEM format.
451 raw_data_to_sign: Data to sign (bytearray or str expected).
452
453 Returns:
454 A bytearray containing the signature.
455
456 Raises:
457 Exception: If an error occurs.
458 """
459 p = None
David Zeuthena156d3d2017-06-01 12:08:09 -0400460 if signing_helper_with_files is not None:
461 signing_file = tempfile.NamedTemporaryFile()
462 signing_file.write(str(raw_data_to_sign))
463 signing_file.flush()
David Zeuthene3cadca2017-02-22 21:25:46 -0500464 p = subprocess.Popen(
David Zeuthena156d3d2017-06-01 12:08:09 -0400465 [signing_helper_with_files, algorithm_name, key_path, signing_file.name])
466 retcode = p.wait()
467 if retcode != 0:
468 raise AvbError('Error signing')
469 signing_file.seek(0)
470 signature = bytearray(signing_file.read())
Darren Krahn147b08d2016-12-20 16:38:29 -0800471 else:
David Zeuthena156d3d2017-06-01 12:08:09 -0400472 if signing_helper is not None:
473 p = subprocess.Popen(
474 [signing_helper, algorithm_name, key_path],
475 stdin=subprocess.PIPE,
476 stdout=subprocess.PIPE,
477 stderr=subprocess.PIPE)
478 else:
479 p = subprocess.Popen(
480 ['openssl', 'rsautl', '-sign', '-inkey', key_path, '-raw'],
481 stdin=subprocess.PIPE,
482 stdout=subprocess.PIPE,
483 stderr=subprocess.PIPE)
484 (pout, perr) = p.communicate(str(raw_data_to_sign))
485 retcode = p.wait()
486 if retcode != 0:
487 raise AvbError('Error signing: {}'.format(perr))
488 signature = bytearray(pout)
Esun Kimff44f232017-03-30 10:34:54 +0900489 if len(signature) != signature_num_bytes:
490 raise AvbError('Error signing: Invalid length of signature')
491 return signature
Darren Krahn147b08d2016-12-20 16:38:29 -0800492
493
David Zeuthenb623d8b2017-04-04 16:05:53 -0400494def verify_vbmeta_signature(vbmeta_header, vbmeta_blob):
495 """Checks that the signature in a vbmeta blob was made by
496 the embedded public key.
497
498 Arguments:
499 vbmeta_header: A AvbVBMetaHeader.
500 vbmeta_blob: The whole vbmeta blob, including the header.
501
502 Returns:
503 True if the signature is valid and corresponds to the embedded
504 public key. Also returns True if the vbmeta blob is not signed.
505 """
506 (_, alg) = lookup_algorithm_by_type(vbmeta_header.algorithm_type)
507 if alg.hash_name == '':
508 return True
509 header_blob = vbmeta_blob[0:256]
510 auth_offset = 256
511 aux_offset = auth_offset + vbmeta_header.authentication_data_block_size
512 aux_size = vbmeta_header.auxiliary_data_block_size
513 aux_blob = vbmeta_blob[aux_offset:aux_offset + aux_size]
514 pubkey_offset = aux_offset + vbmeta_header.public_key_offset
515 pubkey_size = vbmeta_header.public_key_size
516 pubkey_blob = vbmeta_blob[pubkey_offset:pubkey_offset + pubkey_size]
517
518 digest_offset = auth_offset + vbmeta_header.hash_offset
519 digest_size = vbmeta_header.hash_size
520 digest_blob = vbmeta_blob[digest_offset:digest_offset + digest_size]
521
522 sig_offset = auth_offset + vbmeta_header.signature_offset
523 sig_size = vbmeta_header.signature_size
524 sig_blob = vbmeta_blob[sig_offset:sig_offset + sig_size]
525
526 # Now that we've got the stored digest, public key, and signature
527 # all we need to do is to verify. This is the exactly the same
528 # steps as performed in the avb_vbmeta_image_verify() function in
529 # libavb/avb_vbmeta_image.c.
530
531 ha = hashlib.new(alg.hash_name)
532 ha.update(header_blob)
533 ha.update(aux_blob)
534 computed_digest = ha.digest()
535
536 if computed_digest != digest_blob:
537 return False
538
539 padding_and_digest = bytearray(alg.padding)
540 padding_and_digest.extend(computed_digest)
541
542 (num_bits,) = struct.unpack('!I', pubkey_blob[0:4])
543 modulus_blob = pubkey_blob[8:8 + num_bits/8]
544 modulus = decode_long(modulus_blob)
545 exponent = 65537
546
547 # For now, just use Crypto.PublicKey.RSA to verify the signature. This
548 # is OK since 'avbtool verify_image' is not expected to run on the
549 # Android builders (see bug #36809096).
550 import Crypto.PublicKey.RSA
551 key = Crypto.PublicKey.RSA.construct((modulus, long(exponent)))
552 if not key.verify(decode_long(padding_and_digest),
553 (decode_long(sig_blob), None)):
554 return False
555 return True
556
557
David Zeuthena4fee8b2016-08-22 15:20:43 -0400558class ImageChunk(object):
559 """Data structure used for representing chunks in Android sparse files.
560
561 Attributes:
562 chunk_type: One of TYPE_RAW, TYPE_FILL, or TYPE_DONT_CARE.
563 chunk_offset: Offset in the sparse file where this chunk begins.
564 output_offset: Offset in de-sparsified file where output begins.
565 output_size: Number of bytes in output.
566 input_offset: Offset in sparse file for data if TYPE_RAW otherwise None.
567 fill_data: Blob with data to fill if TYPE_FILL otherwise None.
568 """
569
570 FORMAT = '<2H2I'
571 TYPE_RAW = 0xcac1
572 TYPE_FILL = 0xcac2
573 TYPE_DONT_CARE = 0xcac3
574 TYPE_CRC32 = 0xcac4
575
576 def __init__(self, chunk_type, chunk_offset, output_offset, output_size,
577 input_offset, fill_data):
578 """Initializes an ImageChunk object.
579
580 Arguments:
581 chunk_type: One of TYPE_RAW, TYPE_FILL, or TYPE_DONT_CARE.
582 chunk_offset: Offset in the sparse file where this chunk begins.
583 output_offset: Offset in de-sparsified file.
584 output_size: Number of bytes in output.
585 input_offset: Offset in sparse file if TYPE_RAW otherwise None.
586 fill_data: Blob with data to fill if TYPE_FILL otherwise None.
587
588 Raises:
589 ValueError: If data is not well-formed.
590 """
591 self.chunk_type = chunk_type
592 self.chunk_offset = chunk_offset
593 self.output_offset = output_offset
594 self.output_size = output_size
595 self.input_offset = input_offset
596 self.fill_data = fill_data
597 # Check invariants.
598 if self.chunk_type == self.TYPE_RAW:
599 if self.fill_data is not None:
600 raise ValueError('RAW chunk cannot have fill_data set.')
601 if not self.input_offset:
602 raise ValueError('RAW chunk must have input_offset set.')
603 elif self.chunk_type == self.TYPE_FILL:
604 if self.fill_data is None:
605 raise ValueError('FILL chunk must have fill_data set.')
606 if self.input_offset:
607 raise ValueError('FILL chunk cannot have input_offset set.')
608 elif self.chunk_type == self.TYPE_DONT_CARE:
609 if self.fill_data is not None:
610 raise ValueError('DONT_CARE chunk cannot have fill_data set.')
611 if self.input_offset:
612 raise ValueError('DONT_CARE chunk cannot have input_offset set.')
613 else:
614 raise ValueError('Invalid chunk type')
615
616
617class ImageHandler(object):
618 """Abstraction for image I/O with support for Android sparse images.
619
620 This class provides an interface for working with image files that
621 may be using the Android Sparse Image format. When an instance is
622 constructed, we test whether it's an Android sparse file. If so,
623 operations will be on the sparse file by interpreting the sparse
624 format, otherwise they will be directly on the file. Either way the
625 operations do the same.
626
627 For reading, this interface mimics a file object - it has seek(),
628 tell(), and read() methods. For writing, only truncation
629 (truncate()) and appending is supported (append_raw() and
630 append_dont_care()). Additionally, data can only be written in units
631 of the block size.
632
633 Attributes:
David Zeuthen49936b42018-08-07 17:38:58 -0400634 filename: Name of file.
David Zeuthena4fee8b2016-08-22 15:20:43 -0400635 is_sparse: Whether the file being operated on is sparse.
636 block_size: The block size, typically 4096.
637 image_size: The size of the unsparsified file.
David Zeuthena4fee8b2016-08-22 15:20:43 -0400638 """
639 # See system/core/libsparse/sparse_format.h for details.
640 MAGIC = 0xed26ff3a
641 HEADER_FORMAT = '<I4H4I'
642
643 # These are formats and offset of just the |total_chunks| and
644 # |total_blocks| fields.
645 NUM_CHUNKS_AND_BLOCKS_FORMAT = '<II'
646 NUM_CHUNKS_AND_BLOCKS_OFFSET = 16
647
648 def __init__(self, image_filename):
649 """Initializes an image handler.
650
651 Arguments:
652 image_filename: The name of the file to operate on.
653
654 Raises:
655 ValueError: If data in the file is invalid.
656 """
David Zeuthen49936b42018-08-07 17:38:58 -0400657 self.filename = image_filename
David Zeuthena4fee8b2016-08-22 15:20:43 -0400658 self._read_header()
659
660 def _read_header(self):
661 """Initializes internal data structures used for reading file.
662
663 This may be called multiple times and is typically called after
664 modifying the file (e.g. appending, truncation).
665
666 Raises:
667 ValueError: If data in the file is invalid.
668 """
669 self.is_sparse = False
670 self.block_size = 4096
671 self._file_pos = 0
David Zeuthen49936b42018-08-07 17:38:58 -0400672 self._image = open(self.filename, 'r+b')
David Zeuthena4fee8b2016-08-22 15:20:43 -0400673 self._image.seek(0, os.SEEK_END)
David Zeuthena4fee8b2016-08-22 15:20:43 -0400674 self.image_size = self._image.tell()
675
676 self._image.seek(0, os.SEEK_SET)
677 header_bin = self._image.read(struct.calcsize(self.HEADER_FORMAT))
678 (magic, major_version, minor_version, file_hdr_sz, chunk_hdr_sz,
679 block_size, self._num_total_blocks, self._num_total_chunks,
680 _) = struct.unpack(self.HEADER_FORMAT, header_bin)
681 if magic != self.MAGIC:
682 # Not a sparse image, our job here is done.
683 return
684 if not (major_version == 1 and minor_version == 0):
685 raise ValueError('Encountered sparse image format version {}.{} but '
686 'only 1.0 is supported'.format(major_version,
687 minor_version))
688 if file_hdr_sz != struct.calcsize(self.HEADER_FORMAT):
689 raise ValueError('Unexpected file_hdr_sz value {}.'.
690 format(file_hdr_sz))
691 if chunk_hdr_sz != struct.calcsize(ImageChunk.FORMAT):
692 raise ValueError('Unexpected chunk_hdr_sz value {}.'.
693 format(chunk_hdr_sz))
694
695 self.block_size = block_size
696
697 # Build an list of chunks by parsing the file.
698 self._chunks = []
699
700 # Find the smallest offset where only "Don't care" chunks
701 # follow. This will be the size of the content in the sparse
702 # image.
703 offset = 0
704 output_offset = 0
David Zeuthena4fee8b2016-08-22 15:20:43 -0400705 for _ in xrange(1, self._num_total_chunks + 1):
706 chunk_offset = self._image.tell()
707
708 header_bin = self._image.read(struct.calcsize(ImageChunk.FORMAT))
709 (chunk_type, _, chunk_sz, total_sz) = struct.unpack(ImageChunk.FORMAT,
710 header_bin)
711 data_sz = total_sz - struct.calcsize(ImageChunk.FORMAT)
712
David Zeuthena4fee8b2016-08-22 15:20:43 -0400713 if chunk_type == ImageChunk.TYPE_RAW:
714 if data_sz != (chunk_sz * self.block_size):
715 raise ValueError('Raw chunk input size ({}) does not match output '
716 'size ({})'.
717 format(data_sz, chunk_sz*self.block_size))
718 self._chunks.append(ImageChunk(ImageChunk.TYPE_RAW,
719 chunk_offset,
720 output_offset,
721 chunk_sz*self.block_size,
722 self._image.tell(),
723 None))
Dan Willemsen8e306ae2018-09-17 20:03:23 -0700724 self._image.seek(data_sz, os.SEEK_CUR)
David Zeuthena4fee8b2016-08-22 15:20:43 -0400725
726 elif chunk_type == ImageChunk.TYPE_FILL:
727 if data_sz != 4:
728 raise ValueError('Fill chunk should have 4 bytes of fill, but this '
729 'has {}'.format(data_sz))
730 fill_data = self._image.read(4)
731 self._chunks.append(ImageChunk(ImageChunk.TYPE_FILL,
732 chunk_offset,
733 output_offset,
734 chunk_sz*self.block_size,
735 None,
736 fill_data))
737 elif chunk_type == ImageChunk.TYPE_DONT_CARE:
738 if data_sz != 0:
739 raise ValueError('Don\'t care chunk input size is non-zero ({})'.
740 format(data_sz))
David Zeuthena4fee8b2016-08-22 15:20:43 -0400741 self._chunks.append(ImageChunk(ImageChunk.TYPE_DONT_CARE,
742 chunk_offset,
743 output_offset,
744 chunk_sz*self.block_size,
745 None,
746 None))
747 elif chunk_type == ImageChunk.TYPE_CRC32:
748 if data_sz != 4:
749 raise ValueError('CRC32 chunk should have 4 bytes of CRC, but '
750 'this has {}'.format(data_sz))
751 self._image.read(4)
752 else:
753 raise ValueError('Unknown chunk type {}'.format(chunk_type))
754
755 offset += chunk_sz
756 output_offset += chunk_sz*self.block_size
757
758 # Record where sparse data end.
759 self._sparse_end = self._image.tell()
760
761 # Now that we've traversed all chunks, sanity check.
762 if self._num_total_blocks != offset:
763 raise ValueError('The header said we should have {} output blocks, '
764 'but we saw {}'.format(self._num_total_blocks, offset))
765 junk_len = len(self._image.read())
766 if junk_len > 0:
767 raise ValueError('There were {} bytes of extra data at the end of the '
768 'file.'.format(junk_len))
769
David Zeuthen09692692016-09-30 16:16:40 -0400770 # Assign |image_size|.
David Zeuthena4fee8b2016-08-22 15:20:43 -0400771 self.image_size = output_offset
David Zeuthena4fee8b2016-08-22 15:20:43 -0400772
773 # This is used when bisecting in read() to find the initial slice.
774 self._chunk_output_offsets = [i.output_offset for i in self._chunks]
775
776 self.is_sparse = True
777
778 def _update_chunks_and_blocks(self):
779 """Helper function to update the image header.
780
781 The the |total_chunks| and |total_blocks| fields in the header
782 will be set to value of the |_num_total_blocks| and
783 |_num_total_chunks| attributes.
784
785 """
786 self._image.seek(self.NUM_CHUNKS_AND_BLOCKS_OFFSET, os.SEEK_SET)
787 self._image.write(struct.pack(self.NUM_CHUNKS_AND_BLOCKS_FORMAT,
788 self._num_total_blocks,
789 self._num_total_chunks))
790
791 def append_dont_care(self, num_bytes):
792 """Appends a DONT_CARE chunk to the sparse file.
793
794 The given number of bytes must be a multiple of the block size.
795
796 Arguments:
797 num_bytes: Size in number of bytes of the DONT_CARE chunk.
798 """
799 assert num_bytes % self.block_size == 0
800
801 if not self.is_sparse:
802 self._image.seek(0, os.SEEK_END)
803 # This is more efficient that writing NUL bytes since it'll add
804 # a hole on file systems that support sparse files (native
805 # sparse, not Android sparse).
806 self._image.truncate(self._image.tell() + num_bytes)
807 self._read_header()
808 return
809
810 self._num_total_chunks += 1
811 self._num_total_blocks += num_bytes / self.block_size
812 self._update_chunks_and_blocks()
813
814 self._image.seek(self._sparse_end, os.SEEK_SET)
815 self._image.write(struct.pack(ImageChunk.FORMAT,
816 ImageChunk.TYPE_DONT_CARE,
817 0, # Reserved
818 num_bytes / self.block_size,
819 struct.calcsize(ImageChunk.FORMAT)))
820 self._read_header()
821
822 def append_raw(self, data):
823 """Appends a RAW chunk to the sparse file.
824
825 The length of the given data must be a multiple of the block size.
826
827 Arguments:
828 data: Data to append.
829 """
830 assert len(data) % self.block_size == 0
831
832 if not self.is_sparse:
833 self._image.seek(0, os.SEEK_END)
834 self._image.write(data)
835 self._read_header()
836 return
837
838 self._num_total_chunks += 1
839 self._num_total_blocks += len(data) / self.block_size
840 self._update_chunks_and_blocks()
841
842 self._image.seek(self._sparse_end, os.SEEK_SET)
843 self._image.write(struct.pack(ImageChunk.FORMAT,
844 ImageChunk.TYPE_RAW,
845 0, # Reserved
846 len(data) / self.block_size,
847 len(data) +
848 struct.calcsize(ImageChunk.FORMAT)))
849 self._image.write(data)
850 self._read_header()
851
852 def append_fill(self, fill_data, size):
853 """Appends a fill chunk to the sparse file.
854
855 The total length of the fill data must be a multiple of the block size.
856
857 Arguments:
858 fill_data: Fill data to append - must be four bytes.
859 size: Number of chunk - must be a multiple of four and the block size.
860 """
861 assert len(fill_data) == 4
862 assert size % 4 == 0
863 assert size % self.block_size == 0
864
865 if not self.is_sparse:
866 self._image.seek(0, os.SEEK_END)
867 self._image.write(fill_data * (size/4))
868 self._read_header()
869 return
870
871 self._num_total_chunks += 1
872 self._num_total_blocks += size / self.block_size
873 self._update_chunks_and_blocks()
874
875 self._image.seek(self._sparse_end, os.SEEK_SET)
876 self._image.write(struct.pack(ImageChunk.FORMAT,
877 ImageChunk.TYPE_FILL,
878 0, # Reserved
879 size / self.block_size,
880 4 + struct.calcsize(ImageChunk.FORMAT)))
881 self._image.write(fill_data)
882 self._read_header()
883
884 def seek(self, offset):
885 """Sets the cursor position for reading from unsparsified file.
886
887 Arguments:
888 offset: Offset to seek to from the beginning of the file.
889 """
Lonnie Liu6b5a33e2017-10-31 18:01:09 -0700890 if offset < 0:
891 raise RuntimeError("Seeking with negative offset: %d" % offset)
David Zeuthena4fee8b2016-08-22 15:20:43 -0400892 self._file_pos = offset
893
894 def read(self, size):
895 """Reads data from the unsparsified file.
896
897 This method may return fewer than |size| bytes of data if the end
898 of the file was encountered.
899
900 The file cursor for reading is advanced by the number of bytes
901 read.
902
903 Arguments:
904 size: Number of bytes to read.
905
906 Returns:
907 The data.
908
909 """
910 if not self.is_sparse:
911 self._image.seek(self._file_pos)
912 data = self._image.read(size)
913 self._file_pos += len(data)
914 return data
915
916 # Iterate over all chunks.
917 chunk_idx = bisect.bisect_right(self._chunk_output_offsets,
918 self._file_pos) - 1
919 data = bytearray()
920 to_go = size
921 while to_go > 0:
922 chunk = self._chunks[chunk_idx]
923 chunk_pos_offset = self._file_pos - chunk.output_offset
924 chunk_pos_to_go = min(chunk.output_size - chunk_pos_offset, to_go)
925
926 if chunk.chunk_type == ImageChunk.TYPE_RAW:
927 self._image.seek(chunk.input_offset + chunk_pos_offset)
928 data.extend(self._image.read(chunk_pos_to_go))
929 elif chunk.chunk_type == ImageChunk.TYPE_FILL:
930 all_data = chunk.fill_data*(chunk_pos_to_go/len(chunk.fill_data) + 2)
931 offset_mod = chunk_pos_offset % len(chunk.fill_data)
932 data.extend(all_data[offset_mod:(offset_mod + chunk_pos_to_go)])
933 else:
934 assert chunk.chunk_type == ImageChunk.TYPE_DONT_CARE
935 data.extend('\0' * chunk_pos_to_go)
936
937 to_go -= chunk_pos_to_go
938 self._file_pos += chunk_pos_to_go
939 chunk_idx += 1
940 # Generate partial read in case of EOF.
941 if chunk_idx >= len(self._chunks):
942 break
943
944 return data
945
946 def tell(self):
947 """Returns the file cursor position for reading from unsparsified file.
948
949 Returns:
950 The file cursor position for reading.
951 """
952 return self._file_pos
953
954 def truncate(self, size):
955 """Truncates the unsparsified file.
956
957 Arguments:
958 size: Desired size of unsparsified file.
959
960 Raises:
961 ValueError: If desired size isn't a multiple of the block size.
962 """
963 if not self.is_sparse:
964 self._image.truncate(size)
965 self._read_header()
966 return
967
968 if size % self.block_size != 0:
969 raise ValueError('Cannot truncate to a size which is not a multiple '
970 'of the block size')
971
972 if size == self.image_size:
973 # Trivial where there's nothing to do.
974 return
975 elif size < self.image_size:
976 chunk_idx = bisect.bisect_right(self._chunk_output_offsets, size) - 1
977 chunk = self._chunks[chunk_idx]
978 if chunk.output_offset != size:
979 # Truncation in the middle of a trunk - need to keep the chunk
980 # and modify it.
981 chunk_idx_for_update = chunk_idx + 1
982 num_to_keep = size - chunk.output_offset
983 assert num_to_keep % self.block_size == 0
984 if chunk.chunk_type == ImageChunk.TYPE_RAW:
985 truncate_at = (chunk.chunk_offset +
986 struct.calcsize(ImageChunk.FORMAT) + num_to_keep)
987 data_sz = num_to_keep
988 elif chunk.chunk_type == ImageChunk.TYPE_FILL:
989 truncate_at = (chunk.chunk_offset +
990 struct.calcsize(ImageChunk.FORMAT) + 4)
991 data_sz = 4
992 else:
993 assert chunk.chunk_type == ImageChunk.TYPE_DONT_CARE
994 truncate_at = chunk.chunk_offset + struct.calcsize(ImageChunk.FORMAT)
995 data_sz = 0
996 chunk_sz = num_to_keep/self.block_size
997 total_sz = data_sz + struct.calcsize(ImageChunk.FORMAT)
998 self._image.seek(chunk.chunk_offset)
999 self._image.write(struct.pack(ImageChunk.FORMAT,
1000 chunk.chunk_type,
1001 0, # Reserved
1002 chunk_sz,
1003 total_sz))
1004 chunk.output_size = num_to_keep
1005 else:
1006 # Truncation at trunk boundary.
1007 truncate_at = chunk.chunk_offset
1008 chunk_idx_for_update = chunk_idx
1009
1010 self._num_total_chunks = chunk_idx_for_update
1011 self._num_total_blocks = 0
1012 for i in range(0, chunk_idx_for_update):
1013 self._num_total_blocks += self._chunks[i].output_size / self.block_size
1014 self._update_chunks_and_blocks()
1015 self._image.truncate(truncate_at)
1016
1017 # We've modified the file so re-read all data.
1018 self._read_header()
1019 else:
1020 # Truncating to grow - just add a DONT_CARE section.
1021 self.append_dont_care(size - self.image_size)
1022
1023
David Zeuthen21e95262016-07-27 17:58:40 -04001024class AvbDescriptor(object):
1025 """Class for AVB descriptor.
1026
1027 See the |AvbDescriptor| C struct for more information.
1028
1029 Attributes:
1030 tag: The tag identifying what kind of descriptor this is.
1031 data: The data in the descriptor.
1032 """
1033
1034 SIZE = 16
1035 FORMAT_STRING = ('!QQ') # tag, num_bytes_following (descriptor header)
1036
1037 def __init__(self, data):
1038 """Initializes a new property descriptor.
1039
1040 Arguments:
1041 data: If not None, must be a bytearray().
1042
1043 Raises:
1044 LookupError: If the given descriptor is malformed.
1045 """
1046 assert struct.calcsize(self.FORMAT_STRING) == self.SIZE
1047
1048 if data:
1049 (self.tag, num_bytes_following) = (
1050 struct.unpack(self.FORMAT_STRING, data[0:self.SIZE]))
1051 self.data = data[self.SIZE:self.SIZE + num_bytes_following]
1052 else:
1053 self.tag = None
1054 self.data = None
1055
1056 def print_desc(self, o):
1057 """Print the descriptor.
1058
1059 Arguments:
1060 o: The object to write the output to.
1061 """
1062 o.write(' Unknown descriptor:\n')
1063 o.write(' Tag: {}\n'.format(self.tag))
1064 if len(self.data) < 256:
1065 o.write(' Data: {} ({} bytes)\n'.format(
1066 repr(str(self.data)), len(self.data)))
1067 else:
1068 o.write(' Data: {} bytes\n'.format(len(self.data)))
1069
1070 def encode(self):
1071 """Serializes the descriptor.
1072
1073 Returns:
1074 A bytearray() with the descriptor data.
1075 """
1076 num_bytes_following = len(self.data)
1077 nbf_with_padding = round_to_multiple(num_bytes_following, 8)
1078 padding_size = nbf_with_padding - num_bytes_following
1079 desc = struct.pack(self.FORMAT_STRING, self.tag, nbf_with_padding)
1080 padding = struct.pack(str(padding_size) + 'x')
1081 ret = desc + self.data + padding
1082 return bytearray(ret)
1083
David Zeuthen5dfb4e92017-05-24 14:49:32 -04001084 def verify(self, image_dir, image_ext, expected_chain_partitions_map):
1085 """Verifies contents of the descriptor - used in verify_image sub-command.
1086
1087 Arguments:
1088 image_dir: The directory of the file being verified.
1089 image_ext: The extension of the file being verified (e.g. '.img').
1090 expected_chain_partitions_map: A map from partition name to the
1091 tuple (rollback_index_location, key_blob).
1092
1093 Returns:
1094 True if the descriptor verifies, False otherwise.
1095 """
1096 # Nothing to do.
1097 return True
David Zeuthen21e95262016-07-27 17:58:40 -04001098
1099class AvbPropertyDescriptor(AvbDescriptor):
1100 """A class for property descriptors.
1101
1102 See the |AvbPropertyDescriptor| C struct for more information.
1103
1104 Attributes:
1105 key: The key.
1106 value: The key.
1107 """
1108
1109 TAG = 0
1110 SIZE = 32
1111 FORMAT_STRING = ('!QQ' # tag, num_bytes_following (descriptor header)
1112 'Q' # key size (bytes)
1113 'Q') # value size (bytes)
1114
1115 def __init__(self, data=None):
1116 """Initializes a new property descriptor.
1117
1118 Arguments:
1119 data: If not None, must be a bytearray of size |SIZE|.
1120
1121 Raises:
1122 LookupError: If the given descriptor is malformed.
1123 """
1124 AvbDescriptor.__init__(self, None)
1125 assert struct.calcsize(self.FORMAT_STRING) == self.SIZE
1126
1127 if data:
1128 (tag, num_bytes_following, key_size,
1129 value_size) = struct.unpack(self.FORMAT_STRING, data[0:self.SIZE])
1130 expected_size = round_to_multiple(
1131 self.SIZE - 16 + key_size + 1 + value_size + 1, 8)
1132 if tag != self.TAG or num_bytes_following != expected_size:
1133 raise LookupError('Given data does not look like a property '
1134 'descriptor.')
1135 self.key = data[self.SIZE:(self.SIZE + key_size)]
1136 self.value = data[(self.SIZE + key_size + 1):(self.SIZE + key_size + 1 +
1137 value_size)]
1138 else:
1139 self.key = ''
1140 self.value = ''
1141
1142 def print_desc(self, o):
1143 """Print the descriptor.
1144
1145 Arguments:
1146 o: The object to write the output to.
1147 """
1148 if len(self.value) < 256:
1149 o.write(' Prop: {} -> {}\n'.format(self.key, repr(str(self.value))))
1150 else:
1151 o.write(' Prop: {} -> ({} bytes)\n'.format(self.key, len(self.value)))
1152
1153 def encode(self):
1154 """Serializes the descriptor.
1155
1156 Returns:
1157 A bytearray() with the descriptor data.
1158 """
1159 num_bytes_following = self.SIZE + len(self.key) + len(self.value) + 2 - 16
1160 nbf_with_padding = round_to_multiple(num_bytes_following, 8)
1161 padding_size = nbf_with_padding - num_bytes_following
1162 desc = struct.pack(self.FORMAT_STRING, self.TAG, nbf_with_padding,
1163 len(self.key), len(self.value))
1164 padding = struct.pack(str(padding_size) + 'x')
1165 ret = desc + self.key + '\0' + self.value + '\0' + padding
1166 return bytearray(ret)
1167
David Zeuthen5dfb4e92017-05-24 14:49:32 -04001168 def verify(self, image_dir, image_ext, expected_chain_partitions_map):
1169 """Verifies contents of the descriptor - used in verify_image sub-command.
1170
1171 Arguments:
1172 image_dir: The directory of the file being verified.
1173 image_ext: The extension of the file being verified (e.g. '.img').
1174 expected_chain_partitions_map: A map from partition name to the
1175 tuple (rollback_index_location, key_blob).
1176
1177 Returns:
1178 True if the descriptor verifies, False otherwise.
1179 """
1180 # Nothing to do.
1181 return True
David Zeuthen21e95262016-07-27 17:58:40 -04001182
1183class AvbHashtreeDescriptor(AvbDescriptor):
1184 """A class for hashtree descriptors.
1185
1186 See the |AvbHashtreeDescriptor| C struct for more information.
1187
1188 Attributes:
1189 dm_verity_version: dm-verity version used.
1190 image_size: Size of the image, after rounding up to |block_size|.
1191 tree_offset: Offset of the hash tree in the file.
1192 tree_size: Size of the tree.
1193 data_block_size: Data block size
1194 hash_block_size: Hash block size
David Zeuthen0b7f1d32016-10-25 17:53:49 -04001195 fec_num_roots: Number of roots used for FEC (0 if FEC is not used).
1196 fec_offset: Offset of FEC data (0 if FEC is not used).
1197 fec_size: Size of FEC data (0 if FEC is not used).
David Zeuthen21e95262016-07-27 17:58:40 -04001198 hash_algorithm: Hash algorithm used.
1199 partition_name: Partition name.
1200 salt: Salt used.
1201 root_digest: Root digest.
Darren Krahnfd0ba0d2018-02-01 18:06:34 -08001202 flags: Descriptor flags (see avb_hashtree_descriptor.h).
David Zeuthen21e95262016-07-27 17:58:40 -04001203 """
1204
1205 TAG = 1
Darren Krahnfd0ba0d2018-02-01 18:06:34 -08001206 RESERVED = 60
1207 SIZE = 120 + RESERVED
David Zeuthen21e95262016-07-27 17:58:40 -04001208 FORMAT_STRING = ('!QQ' # tag, num_bytes_following (descriptor header)
1209 'L' # dm-verity version used
1210 'Q' # image size (bytes)
1211 'Q' # tree offset (bytes)
1212 'Q' # tree size (bytes)
1213 'L' # data block size (bytes)
1214 'L' # hash block size (bytes)
David Zeuthen0b7f1d32016-10-25 17:53:49 -04001215 'L' # FEC number of roots
1216 'Q' # FEC offset (bytes)
1217 'Q' # FEC size (bytes)
David Zeuthen21e95262016-07-27 17:58:40 -04001218 '32s' # hash algorithm used
1219 'L' # partition name (bytes)
1220 'L' # salt length (bytes)
Darren Krahnfd0ba0d2018-02-01 18:06:34 -08001221 'L' # root digest length (bytes)
1222 'L' + # flags
David Zeuthen5cb2db92016-10-27 15:14:14 -04001223 str(RESERVED) + 's') # reserved
David Zeuthen21e95262016-07-27 17:58:40 -04001224
1225 def __init__(self, data=None):
1226 """Initializes a new hashtree descriptor.
1227
1228 Arguments:
1229 data: If not None, must be a bytearray of size |SIZE|.
1230
1231 Raises:
1232 LookupError: If the given descriptor is malformed.
1233 """
1234 AvbDescriptor.__init__(self, None)
1235 assert struct.calcsize(self.FORMAT_STRING) == self.SIZE
1236
1237 if data:
1238 (tag, num_bytes_following, self.dm_verity_version, self.image_size,
1239 self.tree_offset, self.tree_size, self.data_block_size,
David Zeuthen0b7f1d32016-10-25 17:53:49 -04001240 self.hash_block_size, self.fec_num_roots, self.fec_offset, self.fec_size,
1241 self.hash_algorithm, partition_name_len, salt_len,
Darren Krahnfd0ba0d2018-02-01 18:06:34 -08001242 root_digest_len, self.flags, _) = struct.unpack(self.FORMAT_STRING,
1243 data[0:self.SIZE])
David Zeuthen21e95262016-07-27 17:58:40 -04001244 expected_size = round_to_multiple(
1245 self.SIZE - 16 + partition_name_len + salt_len + root_digest_len, 8)
1246 if tag != self.TAG or num_bytes_following != expected_size:
1247 raise LookupError('Given data does not look like a hashtree '
1248 'descriptor.')
1249 # Nuke NUL-bytes at the end.
1250 self.hash_algorithm = self.hash_algorithm.split('\0', 1)[0]
1251 o = 0
1252 self.partition_name = str(data[(self.SIZE + o):(self.SIZE + o +
1253 partition_name_len)])
1254 # Validate UTF-8 - decode() raises UnicodeDecodeError if not valid UTF-8.
1255 self.partition_name.decode('utf-8')
1256 o += partition_name_len
1257 self.salt = data[(self.SIZE + o):(self.SIZE + o + salt_len)]
1258 o += salt_len
1259 self.root_digest = data[(self.SIZE + o):(self.SIZE + o + root_digest_len)]
1260 if root_digest_len != len(hashlib.new(name=self.hash_algorithm).digest()):
Darren Krahnfd0ba0d2018-02-01 18:06:34 -08001261 if root_digest_len != 0:
1262 raise LookupError('root_digest_len doesn\'t match hash algorithm')
David Zeuthen21e95262016-07-27 17:58:40 -04001263
1264 else:
1265 self.dm_verity_version = 0
1266 self.image_size = 0
1267 self.tree_offset = 0
1268 self.tree_size = 0
1269 self.data_block_size = 0
1270 self.hash_block_size = 0
David Zeuthen0b7f1d32016-10-25 17:53:49 -04001271 self.fec_num_roots = 0
1272 self.fec_offset = 0
1273 self.fec_size = 0
David Zeuthen21e95262016-07-27 17:58:40 -04001274 self.hash_algorithm = ''
1275 self.partition_name = ''
1276 self.salt = bytearray()
1277 self.root_digest = bytearray()
Darren Krahnfd0ba0d2018-02-01 18:06:34 -08001278 self.flags = 0
David Zeuthen21e95262016-07-27 17:58:40 -04001279
1280 def print_desc(self, o):
1281 """Print the descriptor.
1282
1283 Arguments:
1284 o: The object to write the output to.
1285 """
1286 o.write(' Hashtree descriptor:\n')
1287 o.write(' Version of dm-verity: {}\n'.format(self.dm_verity_version))
1288 o.write(' Image Size: {} bytes\n'.format(self.image_size))
1289 o.write(' Tree Offset: {}\n'.format(self.tree_offset))
1290 o.write(' Tree Size: {} bytes\n'.format(self.tree_size))
1291 o.write(' Data Block Size: {} bytes\n'.format(
1292 self.data_block_size))
1293 o.write(' Hash Block Size: {} bytes\n'.format(
1294 self.hash_block_size))
David Zeuthen0b7f1d32016-10-25 17:53:49 -04001295 o.write(' FEC num roots: {}\n'.format(self.fec_num_roots))
1296 o.write(' FEC offset: {}\n'.format(self.fec_offset))
1297 o.write(' FEC size: {} bytes\n'.format(self.fec_size))
David Zeuthen21e95262016-07-27 17:58:40 -04001298 o.write(' Hash Algorithm: {}\n'.format(self.hash_algorithm))
1299 o.write(' Partition Name: {}\n'.format(self.partition_name))
1300 o.write(' Salt: {}\n'.format(str(self.salt).encode(
1301 'hex')))
1302 o.write(' Root Digest: {}\n'.format(str(
1303 self.root_digest).encode('hex')))
Darren Krahnfd0ba0d2018-02-01 18:06:34 -08001304 o.write(' Flags: {}\n'.format(self.flags))
David Zeuthen21e95262016-07-27 17:58:40 -04001305
1306 def encode(self):
1307 """Serializes the descriptor.
1308
1309 Returns:
1310 A bytearray() with the descriptor data.
1311 """
1312 encoded_name = self.partition_name.encode('utf-8')
1313 num_bytes_following = (self.SIZE + len(encoded_name) + len(self.salt) +
1314 len(self.root_digest) - 16)
1315 nbf_with_padding = round_to_multiple(num_bytes_following, 8)
1316 padding_size = nbf_with_padding - num_bytes_following
1317 desc = struct.pack(self.FORMAT_STRING, self.TAG, nbf_with_padding,
1318 self.dm_verity_version, self.image_size,
1319 self.tree_offset, self.tree_size, self.data_block_size,
David Zeuthen0b7f1d32016-10-25 17:53:49 -04001320 self.hash_block_size, self.fec_num_roots,
1321 self.fec_offset, self.fec_size, self.hash_algorithm,
David Zeuthen5cb2db92016-10-27 15:14:14 -04001322 len(encoded_name), len(self.salt), len(self.root_digest),
Darren Krahnfd0ba0d2018-02-01 18:06:34 -08001323 self.flags, self.RESERVED*'\0')
David Zeuthen21e95262016-07-27 17:58:40 -04001324 padding = struct.pack(str(padding_size) + 'x')
1325 ret = desc + encoded_name + self.salt + self.root_digest + padding
1326 return bytearray(ret)
1327
David Zeuthen5dfb4e92017-05-24 14:49:32 -04001328 def verify(self, image_dir, image_ext, expected_chain_partitions_map):
1329 """Verifies contents of the descriptor - used in verify_image sub-command.
1330
1331 Arguments:
1332 image_dir: The directory of the file being verified.
1333 image_ext: The extension of the file being verified (e.g. '.img').
1334 expected_chain_partitions_map: A map from partition name to the
1335 tuple (rollback_index_location, key_blob).
1336
1337 Returns:
1338 True if the descriptor verifies, False otherwise.
1339 """
1340 image_filename = os.path.join(image_dir, self.partition_name + image_ext)
1341 image = ImageHandler(image_filename)
1342 # Generate the hashtree and checks that it matches what's in the file.
1343 digest_size = len(hashlib.new(name=self.hash_algorithm).digest())
1344 digest_padding = round_to_pow2(digest_size) - digest_size
1345 (hash_level_offsets, tree_size) = calc_hash_level_offsets(
1346 self.image_size, self.data_block_size, digest_size + digest_padding)
1347 root_digest, hash_tree = generate_hash_tree(image, self.image_size,
1348 self.data_block_size,
1349 self.hash_algorithm, self.salt,
1350 digest_padding,
1351 hash_level_offsets,
1352 tree_size)
Darren Krahnfd0ba0d2018-02-01 18:06:34 -08001353 # The root digest must match unless it is not embedded in the descriptor.
1354 if len(self.root_digest) != 0 and root_digest != self.root_digest:
David Zeuthen5dfb4e92017-05-24 14:49:32 -04001355 sys.stderr.write('hashtree of {} does not match descriptor\n'.
1356 format(image_filename))
1357 return False
1358 # ... also check that the on-disk hashtree matches
1359 image.seek(self.tree_offset)
1360 hash_tree_ondisk = image.read(self.tree_size)
1361 if hash_tree != hash_tree_ondisk:
1362 sys.stderr.write('hashtree of {} contains invalid data\n'.
1363 format(image_filename))
1364 return False
1365 # TODO: we could also verify that the FEC stored in the image is
1366 # correct but this a) currently requires the 'fec' binary; and b)
1367 # takes a long time; and c) is not strictly needed for
1368 # verification purposes as we've already verified the root hash.
1369 print ('{}: Successfully verified {} hashtree of {} for image of {} bytes'
1370 .format(self.partition_name, self.hash_algorithm, image_filename,
1371 self.image_size))
1372 return True
1373
David Zeuthen21e95262016-07-27 17:58:40 -04001374
1375class AvbHashDescriptor(AvbDescriptor):
1376 """A class for hash descriptors.
1377
1378 See the |AvbHashDescriptor| C struct for more information.
1379
1380 Attributes:
1381 image_size: Image size, in bytes.
1382 hash_algorithm: Hash algorithm used.
1383 partition_name: Partition name.
1384 salt: Salt used.
1385 digest: The hash value of salt and data combined.
Darren Krahnfd0ba0d2018-02-01 18:06:34 -08001386 flags: The descriptor flags (see avb_hash_descriptor.h).
David Zeuthen21e95262016-07-27 17:58:40 -04001387 """
1388
1389 TAG = 2
Darren Krahnfd0ba0d2018-02-01 18:06:34 -08001390 RESERVED = 60
1391 SIZE = 72 + RESERVED
David Zeuthen21e95262016-07-27 17:58:40 -04001392 FORMAT_STRING = ('!QQ' # tag, num_bytes_following (descriptor header)
1393 'Q' # image size (bytes)
1394 '32s' # hash algorithm used
1395 'L' # partition name (bytes)
1396 'L' # salt length (bytes)
Darren Krahnfd0ba0d2018-02-01 18:06:34 -08001397 'L' # digest length (bytes)
1398 'L' + # flags
David Zeuthen5cb2db92016-10-27 15:14:14 -04001399 str(RESERVED) + 's') # reserved
David Zeuthen21e95262016-07-27 17:58:40 -04001400
1401 def __init__(self, data=None):
1402 """Initializes a new hash descriptor.
1403
1404 Arguments:
1405 data: If not None, must be a bytearray of size |SIZE|.
1406
1407 Raises:
1408 LookupError: If the given descriptor is malformed.
1409 """
1410 AvbDescriptor.__init__(self, None)
1411 assert struct.calcsize(self.FORMAT_STRING) == self.SIZE
1412
1413 if data:
1414 (tag, num_bytes_following, self.image_size, self.hash_algorithm,
1415 partition_name_len, salt_len,
Darren Krahnfd0ba0d2018-02-01 18:06:34 -08001416 digest_len, self.flags, _) = struct.unpack(self.FORMAT_STRING,
1417 data[0:self.SIZE])
David Zeuthen21e95262016-07-27 17:58:40 -04001418 expected_size = round_to_multiple(
1419 self.SIZE - 16 + partition_name_len + salt_len + digest_len, 8)
1420 if tag != self.TAG or num_bytes_following != expected_size:
1421 raise LookupError('Given data does not look like a hash ' 'descriptor.')
1422 # Nuke NUL-bytes at the end.
1423 self.hash_algorithm = self.hash_algorithm.split('\0', 1)[0]
1424 o = 0
1425 self.partition_name = str(data[(self.SIZE + o):(self.SIZE + o +
1426 partition_name_len)])
1427 # Validate UTF-8 - decode() raises UnicodeDecodeError if not valid UTF-8.
1428 self.partition_name.decode('utf-8')
1429 o += partition_name_len
1430 self.salt = data[(self.SIZE + o):(self.SIZE + o + salt_len)]
1431 o += salt_len
1432 self.digest = data[(self.SIZE + o):(self.SIZE + o + digest_len)]
1433 if digest_len != len(hashlib.new(name=self.hash_algorithm).digest()):
Darren Krahnfd0ba0d2018-02-01 18:06:34 -08001434 if digest_len != 0:
1435 raise LookupError('digest_len doesn\'t match hash algorithm')
David Zeuthen21e95262016-07-27 17:58:40 -04001436
1437 else:
1438 self.image_size = 0
1439 self.hash_algorithm = ''
1440 self.partition_name = ''
1441 self.salt = bytearray()
1442 self.digest = bytearray()
Darren Krahnfd0ba0d2018-02-01 18:06:34 -08001443 self.flags = 0
David Zeuthen21e95262016-07-27 17:58:40 -04001444
1445 def print_desc(self, o):
1446 """Print the descriptor.
1447
1448 Arguments:
1449 o: The object to write the output to.
1450 """
1451 o.write(' Hash descriptor:\n')
1452 o.write(' Image Size: {} bytes\n'.format(self.image_size))
1453 o.write(' Hash Algorithm: {}\n'.format(self.hash_algorithm))
1454 o.write(' Partition Name: {}\n'.format(self.partition_name))
1455 o.write(' Salt: {}\n'.format(str(self.salt).encode(
1456 'hex')))
1457 o.write(' Digest: {}\n'.format(str(self.digest).encode(
1458 'hex')))
Darren Krahnfd0ba0d2018-02-01 18:06:34 -08001459 o.write(' Flags: {}\n'.format(self.flags))
David Zeuthen21e95262016-07-27 17:58:40 -04001460
1461 def encode(self):
1462 """Serializes the descriptor.
1463
1464 Returns:
1465 A bytearray() with the descriptor data.
1466 """
1467 encoded_name = self.partition_name.encode('utf-8')
1468 num_bytes_following = (
1469 self.SIZE + len(encoded_name) + len(self.salt) + len(self.digest) - 16)
1470 nbf_with_padding = round_to_multiple(num_bytes_following, 8)
1471 padding_size = nbf_with_padding - num_bytes_following
1472 desc = struct.pack(self.FORMAT_STRING, self.TAG, nbf_with_padding,
1473 self.image_size, self.hash_algorithm, len(encoded_name),
Darren Krahnfd0ba0d2018-02-01 18:06:34 -08001474 len(self.salt), len(self.digest), self.flags,
1475 self.RESERVED*'\0')
David Zeuthen21e95262016-07-27 17:58:40 -04001476 padding = struct.pack(str(padding_size) + 'x')
1477 ret = desc + encoded_name + self.salt + self.digest + padding
1478 return bytearray(ret)
1479
David Zeuthen5dfb4e92017-05-24 14:49:32 -04001480 def verify(self, image_dir, image_ext, expected_chain_partitions_map):
1481 """Verifies contents of the descriptor - used in verify_image sub-command.
1482
1483 Arguments:
1484 image_dir: The directory of the file being verified.
1485 image_ext: The extension of the file being verified (e.g. '.img').
1486 expected_chain_partitions_map: A map from partition name to the
1487 tuple (rollback_index_location, key_blob).
1488
1489 Returns:
1490 True if the descriptor verifies, False otherwise.
1491 """
1492 image_filename = os.path.join(image_dir, self.partition_name + image_ext)
1493 image = ImageHandler(image_filename)
1494 data = image.read(self.image_size)
1495 ha = hashlib.new(self.hash_algorithm)
1496 ha.update(self.salt)
1497 ha.update(data)
1498 digest = ha.digest()
Darren Krahnfd0ba0d2018-02-01 18:06:34 -08001499 # The digest must match unless there is no digest in the descriptor.
1500 if len(self.digest) != 0 and digest != self.digest:
David Zeuthen5dfb4e92017-05-24 14:49:32 -04001501 sys.stderr.write('{} digest of {} does not match digest in descriptor\n'.
1502 format(self.hash_algorithm, image_filename))
1503 return False
1504 print ('{}: Successfully verified {} hash of {} for image of {} bytes'
1505 .format(self.partition_name, self.hash_algorithm, image_filename,
1506 self.image_size))
1507 return True
1508
David Zeuthen21e95262016-07-27 17:58:40 -04001509
1510class AvbKernelCmdlineDescriptor(AvbDescriptor):
1511 """A class for kernel command-line descriptors.
1512
1513 See the |AvbKernelCmdlineDescriptor| C struct for more information.
1514
1515 Attributes:
David Zeuthenfd41eb92016-11-17 12:24:47 -05001516 flags: Flags.
David Zeuthen21e95262016-07-27 17:58:40 -04001517 kernel_cmdline: The kernel command-line.
1518 """
1519
1520 TAG = 3
David Zeuthenfd41eb92016-11-17 12:24:47 -05001521 SIZE = 24
David Zeuthen21e95262016-07-27 17:58:40 -04001522 FORMAT_STRING = ('!QQ' # tag, num_bytes_following (descriptor header)
David Zeuthenfd41eb92016-11-17 12:24:47 -05001523 'L' # flags
David Zeuthen21e95262016-07-27 17:58:40 -04001524 'L') # cmdline length (bytes)
1525
David Zeuthenfd41eb92016-11-17 12:24:47 -05001526 FLAGS_USE_ONLY_IF_HASHTREE_NOT_DISABLED = (1 << 0)
1527 FLAGS_USE_ONLY_IF_HASHTREE_DISABLED = (1 << 1)
1528
David Zeuthen21e95262016-07-27 17:58:40 -04001529 def __init__(self, data=None):
1530 """Initializes a new kernel cmdline descriptor.
1531
1532 Arguments:
1533 data: If not None, must be a bytearray of size |SIZE|.
1534
1535 Raises:
1536 LookupError: If the given descriptor is malformed.
1537 """
1538 AvbDescriptor.__init__(self, None)
1539 assert struct.calcsize(self.FORMAT_STRING) == self.SIZE
1540
1541 if data:
David Zeuthenfd41eb92016-11-17 12:24:47 -05001542 (tag, num_bytes_following, self.flags, kernel_cmdline_length) = (
David Zeuthen21e95262016-07-27 17:58:40 -04001543 struct.unpack(self.FORMAT_STRING, data[0:self.SIZE]))
1544 expected_size = round_to_multiple(self.SIZE - 16 + kernel_cmdline_length,
1545 8)
1546 if tag != self.TAG or num_bytes_following != expected_size:
1547 raise LookupError('Given data does not look like a kernel cmdline '
1548 'descriptor.')
1549 # Nuke NUL-bytes at the end.
1550 self.kernel_cmdline = str(data[self.SIZE:(self.SIZE +
1551 kernel_cmdline_length)])
1552 # Validate UTF-8 - decode() raises UnicodeDecodeError if not valid UTF-8.
1553 self.kernel_cmdline.decode('utf-8')
1554 else:
David Zeuthenfd41eb92016-11-17 12:24:47 -05001555 self.flags = 0
David Zeuthen21e95262016-07-27 17:58:40 -04001556 self.kernel_cmdline = ''
1557
1558 def print_desc(self, o):
1559 """Print the descriptor.
1560
1561 Arguments:
1562 o: The object to write the output to.
1563 """
1564 o.write(' Kernel Cmdline descriptor:\n')
David Zeuthenfd41eb92016-11-17 12:24:47 -05001565 o.write(' Flags: {}\n'.format(self.flags))
David Zeuthen21e95262016-07-27 17:58:40 -04001566 o.write(' Kernel Cmdline: {}\n'.format(repr(
1567 self.kernel_cmdline)))
1568
1569 def encode(self):
1570 """Serializes the descriptor.
1571
1572 Returns:
1573 A bytearray() with the descriptor data.
1574 """
1575 encoded_str = self.kernel_cmdline.encode('utf-8')
1576 num_bytes_following = (self.SIZE + len(encoded_str) - 16)
1577 nbf_with_padding = round_to_multiple(num_bytes_following, 8)
1578 padding_size = nbf_with_padding - num_bytes_following
1579 desc = struct.pack(self.FORMAT_STRING, self.TAG, nbf_with_padding,
David Zeuthenfd41eb92016-11-17 12:24:47 -05001580 self.flags, len(encoded_str))
David Zeuthen21e95262016-07-27 17:58:40 -04001581 padding = struct.pack(str(padding_size) + 'x')
1582 ret = desc + encoded_str + padding
1583 return bytearray(ret)
1584
David Zeuthen5dfb4e92017-05-24 14:49:32 -04001585 def verify(self, image_dir, image_ext, expected_chain_partitions_map):
1586 """Verifies contents of the descriptor - used in verify_image sub-command.
1587
1588 Arguments:
1589 image_dir: The directory of the file being verified.
1590 image_ext: The extension of the file being verified (e.g. '.img').
1591 expected_chain_partitions_map: A map from partition name to the
1592 tuple (rollback_index_location, key_blob).
1593
1594 Returns:
1595 True if the descriptor verifies, False otherwise.
1596 """
1597 # Nothing to verify.
1598 return True
David Zeuthen21e95262016-07-27 17:58:40 -04001599
1600class AvbChainPartitionDescriptor(AvbDescriptor):
1601 """A class for chained partition descriptors.
1602
1603 See the |AvbChainPartitionDescriptor| C struct for more information.
1604
1605 Attributes:
David Zeuthen40ee1da2016-11-23 15:14:49 -05001606 rollback_index_location: The rollback index location to use.
David Zeuthen21e95262016-07-27 17:58:40 -04001607 partition_name: Partition name.
1608 public_key: Bytes for the public key.
1609 """
1610
1611 TAG = 4
David Zeuthen5cb2db92016-10-27 15:14:14 -04001612 RESERVED = 64
1613 SIZE = 28 + RESERVED
David Zeuthen21e95262016-07-27 17:58:40 -04001614 FORMAT_STRING = ('!QQ' # tag, num_bytes_following (descriptor header)
David Zeuthen40ee1da2016-11-23 15:14:49 -05001615 'L' # rollback_index_location
David Zeuthen21e95262016-07-27 17:58:40 -04001616 'L' # partition_name_size (bytes)
David Zeuthen5cb2db92016-10-27 15:14:14 -04001617 'L' + # public_key_size (bytes)
1618 str(RESERVED) + 's') # reserved
David Zeuthen21e95262016-07-27 17:58:40 -04001619
1620 def __init__(self, data=None):
1621 """Initializes a new chain partition descriptor.
1622
1623 Arguments:
1624 data: If not None, must be a bytearray of size |SIZE|.
1625
1626 Raises:
1627 LookupError: If the given descriptor is malformed.
1628 """
1629 AvbDescriptor.__init__(self, None)
1630 assert struct.calcsize(self.FORMAT_STRING) == self.SIZE
1631
1632 if data:
David Zeuthen40ee1da2016-11-23 15:14:49 -05001633 (tag, num_bytes_following, self.rollback_index_location,
1634 partition_name_len,
David Zeuthen5cb2db92016-10-27 15:14:14 -04001635 public_key_len, _) = struct.unpack(self.FORMAT_STRING, data[0:self.SIZE])
David Zeuthen21e95262016-07-27 17:58:40 -04001636 expected_size = round_to_multiple(
1637 self.SIZE - 16 + partition_name_len + public_key_len, 8)
1638 if tag != self.TAG or num_bytes_following != expected_size:
1639 raise LookupError('Given data does not look like a chain partition '
1640 'descriptor.')
1641 o = 0
1642 self.partition_name = str(data[(self.SIZE + o):(self.SIZE + o +
1643 partition_name_len)])
1644 # Validate UTF-8 - decode() raises UnicodeDecodeError if not valid UTF-8.
1645 self.partition_name.decode('utf-8')
1646 o += partition_name_len
1647 self.public_key = data[(self.SIZE + o):(self.SIZE + o + public_key_len)]
1648
1649 else:
David Zeuthen40ee1da2016-11-23 15:14:49 -05001650 self.rollback_index_location = 0
David Zeuthen21e95262016-07-27 17:58:40 -04001651 self.partition_name = ''
1652 self.public_key = bytearray()
1653
1654 def print_desc(self, o):
1655 """Print the descriptor.
1656
1657 Arguments:
1658 o: The object to write the output to.
1659 """
1660 o.write(' Chain Partition descriptor:\n')
David Zeuthen40ee1da2016-11-23 15:14:49 -05001661 o.write(' Partition Name: {}\n'.format(self.partition_name))
1662 o.write(' Rollback Index Location: {}\n'.format(
1663 self.rollback_index_location))
David Zeuthen21e95262016-07-27 17:58:40 -04001664 # Just show the SHA1 of the key, for size reasons.
1665 hexdig = hashlib.sha1(self.public_key).hexdigest()
David Zeuthen40ee1da2016-11-23 15:14:49 -05001666 o.write(' Public key (sha1): {}\n'.format(hexdig))
David Zeuthen21e95262016-07-27 17:58:40 -04001667
1668 def encode(self):
1669 """Serializes the descriptor.
1670
1671 Returns:
1672 A bytearray() with the descriptor data.
1673 """
1674 encoded_name = self.partition_name.encode('utf-8')
1675 num_bytes_following = (
1676 self.SIZE + len(encoded_name) + len(self.public_key) - 16)
1677 nbf_with_padding = round_to_multiple(num_bytes_following, 8)
1678 padding_size = nbf_with_padding - num_bytes_following
1679 desc = struct.pack(self.FORMAT_STRING, self.TAG, nbf_with_padding,
David Zeuthen40ee1da2016-11-23 15:14:49 -05001680 self.rollback_index_location, len(encoded_name),
David Zeuthen5cb2db92016-10-27 15:14:14 -04001681 len(self.public_key), self.RESERVED*'\0')
David Zeuthen21e95262016-07-27 17:58:40 -04001682 padding = struct.pack(str(padding_size) + 'x')
1683 ret = desc + encoded_name + self.public_key + padding
1684 return bytearray(ret)
1685
David Zeuthen5dfb4e92017-05-24 14:49:32 -04001686 def verify(self, image_dir, image_ext, expected_chain_partitions_map):
1687 """Verifies contents of the descriptor - used in verify_image sub-command.
1688
1689 Arguments:
1690 image_dir: The directory of the file being verified.
1691 image_ext: The extension of the file being verified (e.g. '.img').
1692 expected_chain_partitions_map: A map from partition name to the
1693 tuple (rollback_index_location, key_blob).
1694
1695 Returns:
1696 True if the descriptor verifies, False otherwise.
1697 """
1698 value = expected_chain_partitions_map.get(self.partition_name)
1699 if not value:
1700 sys.stderr.write('No expected chain partition for partition {}. Use '
1701 '--expected_chain_partition to specify expected '
1702 'contents.\n'.
1703 format(self.partition_name))
1704 return False
1705 rollback_index_location, pk_blob = value
1706
1707 if self.rollback_index_location != rollback_index_location:
1708 sys.stderr.write('Expected rollback_index_location {} does not '
1709 'match {} in descriptor for partition {}\n'.
1710 format(rollback_index_location,
1711 self.rollback_index_location,
1712 self.partition_name))
1713 return False
1714
1715 if self.public_key != pk_blob:
1716 sys.stderr.write('Expected public key blob does not match public '
1717 'key blob in descriptor for partition {}\n'.
1718 format(self.partition_name))
1719 return False
1720
1721 print ('{}: Successfully verified chain partition descriptor matches '
1722 'expected data'.format(self.partition_name))
1723
1724 return True
David Zeuthen21e95262016-07-27 17:58:40 -04001725
1726DESCRIPTOR_CLASSES = [
1727 AvbPropertyDescriptor, AvbHashtreeDescriptor, AvbHashDescriptor,
1728 AvbKernelCmdlineDescriptor, AvbChainPartitionDescriptor
1729]
1730
1731
1732def parse_descriptors(data):
1733 """Parses a blob of data into descriptors.
1734
1735 Arguments:
1736 data: A bytearray() with encoded descriptors.
1737
1738 Returns:
1739 A list of instances of objects derived from AvbDescriptor. For
1740 unknown descriptors, the class AvbDescriptor is used.
1741 """
1742 o = 0
1743 ret = []
1744 while o < len(data):
1745 tag, nb_following = struct.unpack('!2Q', data[o:o + 16])
1746 if tag < len(DESCRIPTOR_CLASSES):
1747 c = DESCRIPTOR_CLASSES[tag]
1748 else:
1749 c = AvbDescriptor
1750 ret.append(c(bytearray(data[o:o + 16 + nb_following])))
1751 o += 16 + nb_following
1752 return ret
1753
1754
1755class AvbFooter(object):
1756 """A class for parsing and writing footers.
1757
1758 Footers are stored at the end of partitions and point to where the
1759 AvbVBMeta blob is located. They also contain the original size of
1760 the image before AVB information was added.
1761
1762 Attributes:
1763 magic: Magic for identifying the footer, see |MAGIC|.
1764 version_major: The major version of avbtool that wrote the footer.
1765 version_minor: The minor version of avbtool that wrote the footer.
1766 original_image_size: Original image size.
1767 vbmeta_offset: Offset of where the AvbVBMeta blob is stored.
1768 vbmeta_size: Size of the AvbVBMeta blob.
1769 """
1770
1771 MAGIC = 'AVBf'
1772 SIZE = 64
1773 RESERVED = 28
Darren Krahnfd0ba0d2018-02-01 18:06:34 -08001774 FOOTER_VERSION_MAJOR = AVB_FOOTER_VERSION_MAJOR
1775 FOOTER_VERSION_MINOR = AVB_FOOTER_VERSION_MINOR
David Zeuthen21e95262016-07-27 17:58:40 -04001776 FORMAT_STRING = ('!4s2L' # magic, 2 x version.
1777 'Q' # Original image size.
1778 'Q' # Offset of VBMeta blob.
1779 'Q' + # Size of VBMeta blob.
1780 str(RESERVED) + 'x') # padding for reserved bytes
1781
1782 def __init__(self, data=None):
1783 """Initializes a new footer object.
1784
1785 Arguments:
1786 data: If not None, must be a bytearray of size 4096.
1787
1788 Raises:
1789 LookupError: If the given footer is malformed.
1790 struct.error: If the given data has no footer.
1791 """
1792 assert struct.calcsize(self.FORMAT_STRING) == self.SIZE
1793
1794 if data:
1795 (self.magic, self.version_major, self.version_minor,
1796 self.original_image_size, self.vbmeta_offset,
1797 self.vbmeta_size) = struct.unpack(self.FORMAT_STRING, data)
1798 if self.magic != self.MAGIC:
David Zeuthen8b6973b2016-09-20 12:39:49 -04001799 raise LookupError('Given data does not look like a AVB footer.')
David Zeuthen21e95262016-07-27 17:58:40 -04001800 else:
1801 self.magic = self.MAGIC
David Zeuthene3cadca2017-02-22 21:25:46 -05001802 self.version_major = self.FOOTER_VERSION_MAJOR
1803 self.version_minor = self.FOOTER_VERSION_MINOR
David Zeuthen21e95262016-07-27 17:58:40 -04001804 self.original_image_size = 0
1805 self.vbmeta_offset = 0
1806 self.vbmeta_size = 0
1807
David Zeuthena4fee8b2016-08-22 15:20:43 -04001808 def encode(self):
1809 """Gets a string representing the binary encoding of the footer.
David Zeuthen21e95262016-07-27 17:58:40 -04001810
David Zeuthena4fee8b2016-08-22 15:20:43 -04001811 Returns:
1812 A bytearray() with a binary representation of the footer.
David Zeuthen21e95262016-07-27 17:58:40 -04001813 """
David Zeuthena4fee8b2016-08-22 15:20:43 -04001814 return struct.pack(self.FORMAT_STRING, self.magic, self.version_major,
1815 self.version_minor, self.original_image_size,
1816 self.vbmeta_offset, self.vbmeta_size)
David Zeuthen21e95262016-07-27 17:58:40 -04001817
1818
1819class AvbVBMetaHeader(object):
David Zeuthen8b6973b2016-09-20 12:39:49 -04001820 """A class for parsing and writing AVB vbmeta images.
David Zeuthen21e95262016-07-27 17:58:40 -04001821
1822 Attributes:
Tao Bao80418a52018-07-20 11:41:22 -07001823 The attributes correspond to the |AvbVBMetaImageHeader| struct defined in
1824 avb_vbmeta_image.h.
David Zeuthen21e95262016-07-27 17:58:40 -04001825 """
1826
1827 SIZE = 256
1828
David Zeuthene3cadca2017-02-22 21:25:46 -05001829 # Keep in sync with |reserved0| and |reserved| field of
1830 # |AvbVBMetaImageHeader|.
1831 RESERVED0 = 4
1832 RESERVED = 80
David Zeuthen21e95262016-07-27 17:58:40 -04001833
1834 # Keep in sync with |AvbVBMetaImageHeader|.
1835 FORMAT_STRING = ('!4s2L' # magic, 2 x version
1836 '2Q' # 2 x block size
1837 'L' # algorithm type
1838 '2Q' # offset, size (hash)
1839 '2Q' # offset, size (signature)
1840 '2Q' # offset, size (public key)
David Zeuthen18666ab2016-11-15 11:18:05 -05001841 '2Q' # offset, size (public key metadata)
David Zeuthen21e95262016-07-27 17:58:40 -04001842 '2Q' # offset, size (descriptors)
David Zeuthenfd41eb92016-11-17 12:24:47 -05001843 'Q' # rollback_index
1844 'L' + # flags
David Zeuthene3cadca2017-02-22 21:25:46 -05001845 str(RESERVED0) + 'x' + # padding for reserved bytes
1846 '47sx' + # NUL-terminated release string
David Zeuthen21e95262016-07-27 17:58:40 -04001847 str(RESERVED) + 'x') # padding for reserved bytes
1848
1849 def __init__(self, data=None):
1850 """Initializes a new header object.
1851
1852 Arguments:
1853 data: If not None, must be a bytearray of size 8192.
1854
1855 Raises:
1856 Exception: If the given data is malformed.
1857 """
1858 assert struct.calcsize(self.FORMAT_STRING) == self.SIZE
1859
1860 if data:
David Zeuthene3cadca2017-02-22 21:25:46 -05001861 (self.magic, self.required_libavb_version_major,
1862 self.required_libavb_version_minor,
David Zeuthen21e95262016-07-27 17:58:40 -04001863 self.authentication_data_block_size, self.auxiliary_data_block_size,
1864 self.algorithm_type, self.hash_offset, self.hash_size,
1865 self.signature_offset, self.signature_size, self.public_key_offset,
David Zeuthen18666ab2016-11-15 11:18:05 -05001866 self.public_key_size, self.public_key_metadata_offset,
1867 self.public_key_metadata_size, self.descriptors_offset,
1868 self.descriptors_size,
David Zeuthenfd41eb92016-11-17 12:24:47 -05001869 self.rollback_index,
David Zeuthene3cadca2017-02-22 21:25:46 -05001870 self.flags,
1871 self.release_string) = struct.unpack(self.FORMAT_STRING, data)
David Zeuthen21e95262016-07-27 17:58:40 -04001872 # Nuke NUL-bytes at the end of the string.
1873 if self.magic != 'AVB0':
David Zeuthen8b6973b2016-09-20 12:39:49 -04001874 raise AvbError('Given image does not look like a vbmeta image.')
David Zeuthen21e95262016-07-27 17:58:40 -04001875 else:
1876 self.magic = 'AVB0'
David Zeuthene3cadca2017-02-22 21:25:46 -05001877 # Start by just requiring version 1.0. Code that adds features
1878 # in a future version can use bump_required_libavb_version_minor() to
1879 # bump the minor.
1880 self.required_libavb_version_major = AVB_VERSION_MAJOR
1881 self.required_libavb_version_minor = 0
David Zeuthen21e95262016-07-27 17:58:40 -04001882 self.authentication_data_block_size = 0
1883 self.auxiliary_data_block_size = 0
1884 self.algorithm_type = 0
1885 self.hash_offset = 0
1886 self.hash_size = 0
1887 self.signature_offset = 0
1888 self.signature_size = 0
1889 self.public_key_offset = 0
1890 self.public_key_size = 0
David Zeuthen18666ab2016-11-15 11:18:05 -05001891 self.public_key_metadata_offset = 0
1892 self.public_key_metadata_size = 0
David Zeuthen21e95262016-07-27 17:58:40 -04001893 self.descriptors_offset = 0
1894 self.descriptors_size = 0
1895 self.rollback_index = 0
David Zeuthenfd41eb92016-11-17 12:24:47 -05001896 self.flags = 0
David Zeuthene3cadca2017-02-22 21:25:46 -05001897 self.release_string = get_release_string()
1898
1899 def bump_required_libavb_version_minor(self, minor):
1900 """Function to bump required_libavb_version_minor.
1901
1902 Call this when writing data that requires a specific libavb
1903 version to parse it.
1904
1905 Arguments:
1906 minor: The minor version of libavb that has support for the feature.
1907 """
1908 self.required_libavb_version_minor = (
Darren Krahnfd0ba0d2018-02-01 18:06:34 -08001909 max(self.required_libavb_version_minor, minor))
David Zeuthen21e95262016-07-27 17:58:40 -04001910
1911 def save(self, output):
1912 """Serializes the header (256 bytes) to disk.
1913
1914 Arguments:
1915 output: The object to write the output to.
1916 """
1917 output.write(struct.pack(
David Zeuthene3cadca2017-02-22 21:25:46 -05001918 self.FORMAT_STRING, self.magic, self.required_libavb_version_major,
1919 self.required_libavb_version_minor, self.authentication_data_block_size,
David Zeuthen21e95262016-07-27 17:58:40 -04001920 self.auxiliary_data_block_size, self.algorithm_type, self.hash_offset,
1921 self.hash_size, self.signature_offset, self.signature_size,
David Zeuthen18666ab2016-11-15 11:18:05 -05001922 self.public_key_offset, self.public_key_size,
1923 self.public_key_metadata_offset, self.public_key_metadata_size,
David Zeuthenfd41eb92016-11-17 12:24:47 -05001924 self.descriptors_offset, self.descriptors_size, self.rollback_index,
David Zeuthene3cadca2017-02-22 21:25:46 -05001925 self.flags, self.release_string))
David Zeuthen21e95262016-07-27 17:58:40 -04001926
1927 def encode(self):
1928 """Serializes the header (256) to a bytearray().
1929
1930 Returns:
1931 A bytearray() with the encoded header.
1932 """
1933 return struct.pack(self.FORMAT_STRING, self.magic,
David Zeuthene3cadca2017-02-22 21:25:46 -05001934 self.required_libavb_version_major,
1935 self.required_libavb_version_minor,
David Zeuthen21e95262016-07-27 17:58:40 -04001936 self.authentication_data_block_size,
1937 self.auxiliary_data_block_size, self.algorithm_type,
1938 self.hash_offset, self.hash_size, self.signature_offset,
1939 self.signature_size, self.public_key_offset,
David Zeuthen18666ab2016-11-15 11:18:05 -05001940 self.public_key_size, self.public_key_metadata_offset,
1941 self.public_key_metadata_size, self.descriptors_offset,
David Zeuthene3cadca2017-02-22 21:25:46 -05001942 self.descriptors_size, self.rollback_index, self.flags,
1943 self.release_string)
David Zeuthen21e95262016-07-27 17:58:40 -04001944
1945
1946class Avb(object):
1947 """Business logic for avbtool command-line tool."""
1948
David Zeuthen8b6973b2016-09-20 12:39:49 -04001949 # Keep in sync with avb_ab_flow.h.
1950 AB_FORMAT_NO_CRC = '!4sBB2xBBBxBBBx12x'
1951 AB_MAGIC = '\0AB0'
1952 AB_MAJOR_VERSION = 1
1953 AB_MINOR_VERSION = 0
1954 AB_MISC_METADATA_OFFSET = 2048
1955
David Zeuthen09692692016-09-30 16:16:40 -04001956 # Constants for maximum metadata size. These are used to give
1957 # meaningful errors if the value passed in via --partition_size is
1958 # too small and when --calc_max_image_size is used. We use
1959 # conservative figures.
1960 MAX_VBMETA_SIZE = 64 * 1024
1961 MAX_FOOTER_SIZE = 4096
1962
David Zeuthen49936b42018-08-07 17:38:58 -04001963 def extract_vbmeta_image(self, output, image_filename, padding_size):
1964 """Implements the 'extract_vbmeta_image' command.
1965
1966 Arguments:
1967 output: Write vbmeta struct to this file.
1968 image_filename: File to extract vbmeta data from (with a footer).
1969 padding_size: If not 0, pads output so size is a multiple of the number.
1970
1971 Raises:
1972 AvbError: If there's no footer in the image.
1973 """
1974 image = ImageHandler(image_filename)
1975
1976 (footer, _, _, _) = self._parse_image(image)
1977
1978 if not footer:
1979 raise AvbError('Given image does not have a footer.')
1980
1981 image.seek(footer.vbmeta_offset)
1982 vbmeta_blob = image.read(footer.vbmeta_size)
1983 output.write(vbmeta_blob)
1984
1985 if padding_size > 0:
1986 padded_size = round_to_multiple(len(vbmeta_blob), padding_size)
1987 padding_needed = padded_size - len(vbmeta_blob)
1988 output.write('\0' * padding_needed)
1989
David Zeuthena4fee8b2016-08-22 15:20:43 -04001990 def erase_footer(self, image_filename, keep_hashtree):
David Zeuthen21e95262016-07-27 17:58:40 -04001991 """Implements the 'erase_footer' command.
1992
1993 Arguments:
David Zeuthena4fee8b2016-08-22 15:20:43 -04001994 image_filename: File to erase a footer from.
David Zeuthenfbb61fa2017-02-02 12:11:49 -05001995 keep_hashtree: If True, keep the hashtree and FEC around.
David Zeuthen21e95262016-07-27 17:58:40 -04001996
1997 Raises:
1998 AvbError: If there's no footer in the image.
1999 """
2000
David Zeuthena4fee8b2016-08-22 15:20:43 -04002001 image = ImageHandler(image_filename)
2002
David Zeuthen21e95262016-07-27 17:58:40 -04002003 (footer, _, descriptors, _) = self._parse_image(image)
2004
2005 if not footer:
2006 raise AvbError('Given image does not have a footer.')
2007
2008 new_image_size = None
2009 if not keep_hashtree:
2010 new_image_size = footer.original_image_size
2011 else:
2012 # If requested to keep the hashtree, search for a hashtree
David Zeuthenfbb61fa2017-02-02 12:11:49 -05002013 # descriptor to figure out the location and size of the hashtree
2014 # and FEC.
David Zeuthen21e95262016-07-27 17:58:40 -04002015 for desc in descriptors:
2016 if isinstance(desc, AvbHashtreeDescriptor):
2017 # The hashtree is always just following the main data so the
2018 # new size is easily derived.
2019 new_image_size = desc.tree_offset + desc.tree_size
David Zeuthenfbb61fa2017-02-02 12:11:49 -05002020 # If the image has FEC codes, also keep those.
2021 if desc.fec_offset > 0:
2022 fec_end = desc.fec_offset + desc.fec_size
2023 new_image_size = max(new_image_size, fec_end)
David Zeuthen21e95262016-07-27 17:58:40 -04002024 break
2025 if not new_image_size:
2026 raise AvbError('Requested to keep hashtree but no hashtree '
2027 'descriptor was found.')
2028
2029 # And cut...
2030 image.truncate(new_image_size)
2031
David Zeuthen2bc232b2017-04-19 14:25:19 -04002032 def resize_image(self, image_filename, partition_size):
2033 """Implements the 'resize_image' command.
2034
2035 Arguments:
2036 image_filename: File with footer to resize.
2037 partition_size: The new size of the image.
2038
2039 Raises:
2040 AvbError: If there's no footer in the image.
2041 """
2042
2043 image = ImageHandler(image_filename)
2044
2045 if partition_size % image.block_size != 0:
2046 raise AvbError('Partition size of {} is not a multiple of the image '
2047 'block size {}.'.format(partition_size,
2048 image.block_size))
2049
2050 (footer, vbmeta_header, descriptors, _) = self._parse_image(image)
2051
2052 if not footer:
2053 raise AvbError('Given image does not have a footer.')
2054
2055 # The vbmeta blob is always at the end of the data so resizing an
2056 # image amounts to just moving the footer around.
2057
2058 vbmeta_end_offset = footer.vbmeta_offset + footer.vbmeta_size
2059 if vbmeta_end_offset % image.block_size != 0:
2060 vbmeta_end_offset += image.block_size - (vbmeta_end_offset % image.block_size)
2061
2062 if partition_size < vbmeta_end_offset + 1*image.block_size:
Lonnie Liu6b5a33e2017-10-31 18:01:09 -07002063 raise AvbError('Requested size of {} is too small for an image '
2064 'of size {}.'
2065 .format(partition_size,
2066 vbmeta_end_offset + 1*image.block_size))
David Zeuthen2bc232b2017-04-19 14:25:19 -04002067
2068 # Cut at the end of the vbmeta blob and insert a DONT_CARE chunk
2069 # with enough bytes such that the final Footer block is at the end
2070 # of partition_size.
2071 image.truncate(vbmeta_end_offset)
2072 image.append_dont_care(partition_size - vbmeta_end_offset -
2073 1*image.block_size)
2074
2075 # Just reuse the same footer - only difference is that we're
2076 # writing it in a different place.
2077 footer_blob = footer.encode()
2078 footer_blob_with_padding = ('\0'*(image.block_size - AvbFooter.SIZE) +
2079 footer_blob)
2080 image.append_raw(footer_blob_with_padding)
2081
David Zeuthen8b6973b2016-09-20 12:39:49 -04002082 def set_ab_metadata(self, misc_image, slot_data):
2083 """Implements the 'set_ab_metadata' command.
2084
2085 The |slot_data| argument must be of the form 'A_priority:A_tries_remaining:
2086 A_successful_boot:B_priority:B_tries_remaining:B_successful_boot'.
2087
2088 Arguments:
2089 misc_image: The misc image to write to.
2090 slot_data: Slot data as a string
2091
2092 Raises:
2093 AvbError: If slot data is malformed.
2094 """
2095 tokens = slot_data.split(':')
2096 if len(tokens) != 6:
2097 raise AvbError('Malformed slot data "{}".'.format(slot_data))
2098 a_priority = int(tokens[0])
2099 a_tries_remaining = int(tokens[1])
2100 a_success = True if int(tokens[2]) != 0 else False
2101 b_priority = int(tokens[3])
2102 b_tries_remaining = int(tokens[4])
2103 b_success = True if int(tokens[5]) != 0 else False
2104
2105 ab_data_no_crc = struct.pack(self.AB_FORMAT_NO_CRC,
2106 self.AB_MAGIC,
2107 self.AB_MAJOR_VERSION, self.AB_MINOR_VERSION,
2108 a_priority, a_tries_remaining, a_success,
2109 b_priority, b_tries_remaining, b_success)
2110 # Force CRC to be unsigned, see https://bugs.python.org/issue4903 for why.
2111 crc_value = binascii.crc32(ab_data_no_crc) & 0xffffffff
2112 ab_data = ab_data_no_crc + struct.pack('!I', crc_value)
2113 misc_image.seek(self.AB_MISC_METADATA_OFFSET)
2114 misc_image.write(ab_data)
2115
David Zeuthena4fee8b2016-08-22 15:20:43 -04002116 def info_image(self, image_filename, output):
David Zeuthen21e95262016-07-27 17:58:40 -04002117 """Implements the 'info_image' command.
2118
2119 Arguments:
David Zeuthena4fee8b2016-08-22 15:20:43 -04002120 image_filename: Image file to get information from (file object).
David Zeuthen21e95262016-07-27 17:58:40 -04002121 output: Output file to write human-readable information to (file object).
2122 """
2123
David Zeuthena4fee8b2016-08-22 15:20:43 -04002124 image = ImageHandler(image_filename)
2125
David Zeuthen21e95262016-07-27 17:58:40 -04002126 o = output
2127
2128 (footer, header, descriptors, image_size) = self._parse_image(image)
2129
2130 if footer:
2131 o.write('Footer version: {}.{}\n'.format(footer.version_major,
2132 footer.version_minor))
2133 o.write('Image size: {} bytes\n'.format(image_size))
2134 o.write('Original image size: {} bytes\n'.format(
2135 footer.original_image_size))
2136 o.write('VBMeta offset: {}\n'.format(footer.vbmeta_offset))
2137 o.write('VBMeta size: {} bytes\n'.format(footer.vbmeta_size))
2138 o.write('--\n')
2139
2140 (alg_name, _) = lookup_algorithm_by_type(header.algorithm_type)
2141
David Zeuthene3cadca2017-02-22 21:25:46 -05002142 o.write('Minimum libavb version: {}.{}{}\n'.format(
2143 header.required_libavb_version_major,
2144 header.required_libavb_version_minor,
David Zeuthena4fee8b2016-08-22 15:20:43 -04002145 ' (Sparse)' if image.is_sparse else ''))
David Zeuthen21e95262016-07-27 17:58:40 -04002146 o.write('Header Block: {} bytes\n'.format(AvbVBMetaHeader.SIZE))
2147 o.write('Authentication Block: {} bytes\n'.format(
2148 header.authentication_data_block_size))
2149 o.write('Auxiliary Block: {} bytes\n'.format(
2150 header.auxiliary_data_block_size))
2151 o.write('Algorithm: {}\n'.format(alg_name))
2152 o.write('Rollback Index: {}\n'.format(header.rollback_index))
David Zeuthenfd41eb92016-11-17 12:24:47 -05002153 o.write('Flags: {}\n'.format(header.flags))
David Zeuthene3cadca2017-02-22 21:25:46 -05002154 o.write('Release String: \'{}\'\n'.format(
2155 header.release_string.rstrip('\0')))
David Zeuthen21e95262016-07-27 17:58:40 -04002156
2157 # Print descriptors.
2158 num_printed = 0
2159 o.write('Descriptors:\n')
2160 for desc in descriptors:
2161 desc.print_desc(o)
2162 num_printed += 1
2163 if num_printed == 0:
2164 o.write(' (none)\n')
2165
David Zeuthen5dfb4e92017-05-24 14:49:32 -04002166 def verify_image(self, image_filename, key_path, expected_chain_partitions):
David Zeuthenb623d8b2017-04-04 16:05:53 -04002167 """Implements the 'verify_image' command.
2168
2169 Arguments:
2170 image_filename: Image file to get information from (file object).
David Zeuthen5dfb4e92017-05-24 14:49:32 -04002171 key_path: None or check that embedded public key matches key at given path.
2172 expected_chain_partitions: List of chain partitions to check or None.
David Zeuthenb623d8b2017-04-04 16:05:53 -04002173 """
2174
David Zeuthen5dfb4e92017-05-24 14:49:32 -04002175 expected_chain_partitions_map = {}
2176 if expected_chain_partitions:
2177 used_locations = {}
2178 for cp in expected_chain_partitions:
2179 cp_tokens = cp.split(':')
2180 if len(cp_tokens) != 3:
2181 raise AvbError('Malformed chained partition "{}".'.format(cp))
2182 partition_name = cp_tokens[0]
2183 rollback_index_location = int(cp_tokens[1])
2184 file_path = cp_tokens[2]
2185 pk_blob = open(file_path).read()
2186 expected_chain_partitions_map[partition_name] = (rollback_index_location, pk_blob)
2187
2188 image_dir = os.path.dirname(image_filename)
2189 image_ext = os.path.splitext(image_filename)[1]
2190
2191 key_blob = None
2192 if key_path:
2193 print 'Verifying image {} using key at {}'.format(image_filename, key_path)
2194 key_blob = encode_rsa_key(key_path)
2195 else:
2196 print 'Verifying image {} using embedded public key'.format(image_filename)
2197
David Zeuthenb623d8b2017-04-04 16:05:53 -04002198 image = ImageHandler(image_filename)
2199 (footer, header, descriptors, image_size) = self._parse_image(image)
2200 offset = 0
2201 if footer:
2202 offset = footer.vbmeta_offset
David Zeuthen49936b42018-08-07 17:38:58 -04002203
David Zeuthenb623d8b2017-04-04 16:05:53 -04002204 image.seek(offset)
David Zeuthen49936b42018-08-07 17:38:58 -04002205 vbmeta_blob = image.read(header.SIZE + header.authentication_data_block_size +
2206 header.auxiliary_data_block_size)
2207
David Zeuthen5dfb4e92017-05-24 14:49:32 -04002208 alg_name, _ = lookup_algorithm_by_type(header.algorithm_type)
David Zeuthenb623d8b2017-04-04 16:05:53 -04002209 if not verify_vbmeta_signature(header, vbmeta_blob):
David Zeuthen5dfb4e92017-05-24 14:49:32 -04002210 raise AvbError('Signature check failed for {} vbmeta struct {}'
2211 .format(alg_name, image_filename))
2212
2213 if key_blob:
2214 # The embedded public key is in the auxiliary block at an offset.
2215 key_offset = AvbVBMetaHeader.SIZE
David Zeuthen49936b42018-08-07 17:38:58 -04002216 key_offset += header.authentication_data_block_size
2217 key_offset += header.public_key_offset
2218 key_blob_in_vbmeta = vbmeta_blob[key_offset:key_offset + header.public_key_size]
David Zeuthen5dfb4e92017-05-24 14:49:32 -04002219 if key_blob != key_blob_in_vbmeta:
2220 raise AvbError('Embedded public key does not match given key.')
2221
2222 if footer:
2223 print ('vbmeta: Successfully verified footer and {} vbmeta struct in {}'
David Zeuthen49936b42018-08-07 17:38:58 -04002224 .format(alg_name, image.filename))
David Zeuthen5dfb4e92017-05-24 14:49:32 -04002225 else:
2226 print ('vbmeta: Successfully verified {} vbmeta struct in {}'
David Zeuthen49936b42018-08-07 17:38:58 -04002227 .format(alg_name, image.filename))
David Zeuthen5dfb4e92017-05-24 14:49:32 -04002228
2229 for desc in descriptors:
2230 if not desc.verify(image_dir, image_ext, expected_chain_partitions_map):
2231 raise AvbError('Error verifying descriptor.')
David Zeuthen49936b42018-08-07 17:38:58 -04002232 # Note how AvbDescriptor.verify() method verifies only the descriptor
2233 # contents which in the case of chain descriptors means checking only its
2234 # contents matches what is in |expected_chain_partitions_map|.
2235 #
2236 # Specifically AvbHashtreeDescriptor.verify(), doesn't follow chain
2237 # descriptors e.g. if it's a chain descriptor for 'system' it will not try
2238 # to verify system.img. Why? Because the whole idea of chain descriptors
2239 # is separate organizations. That is, when they are used it's assumed that
2240 # all you have is the public key, not an actual image (because if you had
2241 # the image you wouldn't need to use a chain partition in the first
2242 # place).
2243 #
2244 # However in certain situations you do have the image so it would be nice
2245 # to add something like a --follow_chain_descriptors option for 'avbtool
2246 # verify_image' which will look for and follow images specified by chain
2247 # descriptors. Maybe it should be on a per-partition basis and specificied
2248 # as part of the --expected_chain_partition paramter, maybe if the
2249 # partition name ends with a '+' or something. Something to think about.
David Zeuthen5dfb4e92017-05-24 14:49:32 -04002250
David Zeuthenb623d8b2017-04-04 16:05:53 -04002251
David Zeuthenb8643c02018-05-17 17:21:18 -04002252 def calculate_vbmeta_digest(self, image_filename, hash_algorithm, output):
2253 """Implements the 'calculate_vbmeta_digest' command.
2254
2255 Arguments:
2256 image_filename: Image file to get information from (file object).
2257 hash_algorithm: Hash algorithm used.
2258 output: Output file to write human-readable information to (file object).
2259 """
2260
2261 image_dir = os.path.dirname(image_filename)
2262 image_ext = os.path.splitext(image_filename)[1]
2263
2264 image = ImageHandler(image_filename)
2265 (footer, header, descriptors, image_size) = self._parse_image(image)
2266 offset = 0
2267 if footer:
2268 offset = footer.vbmeta_offset
2269 size = (header.SIZE + header.authentication_data_block_size +
2270 header.auxiliary_data_block_size)
2271 image.seek(offset)
2272 vbmeta_blob = image.read(size)
2273
2274 hasher = hashlib.new(name=hash_algorithm)
2275 hasher.update(vbmeta_blob)
2276
2277 for desc in descriptors:
2278 if isinstance(desc, AvbChainPartitionDescriptor):
2279 ch_image_filename = os.path.join(image_dir, desc.partition_name + image_ext)
2280 ch_image = ImageHandler(ch_image_filename)
2281 (ch_footer, ch_header, ch_descriptors, ch_image_size) = self._parse_image(ch_image)
2282 ch_offset = 0
David Zeuthen49936b42018-08-07 17:38:58 -04002283 ch_size = (ch_header.SIZE + ch_header.authentication_data_block_size +
2284 ch_header.auxiliary_data_block_size)
David Zeuthenb8643c02018-05-17 17:21:18 -04002285 if ch_footer:
2286 ch_offset = ch_footer.vbmeta_offset
David Zeuthenb8643c02018-05-17 17:21:18 -04002287 ch_image.seek(ch_offset)
2288 ch_vbmeta_blob = ch_image.read(ch_size)
2289 hasher.update(ch_vbmeta_blob)
2290
2291 digest = hasher.digest()
2292 output.write('{}\n'.format(digest.encode('hex')))
2293
2294
David Zeuthenf7d2e752018-09-20 13:30:41 -04002295 def calculate_kernel_cmdline(self, image_filename, hashtree_disabled, output):
2296 """Implements the 'calculate_kernel_cmdline' command.
2297
2298 Arguments:
2299 image_filename: Image file to get information from (file object).
2300 hashtree_disabled: If True, returns the cmdline for hashtree disabled.
2301 output: Output file to write human-readable information to (file object).
2302 """
2303
2304 image = ImageHandler(image_filename)
2305 _, _, descriptors, _ = self._parse_image(image)
2306
2307 image_dir = os.path.dirname(image_filename)
2308 image_ext = os.path.splitext(image_filename)[1]
2309
2310 cmdline_descriptors = []
2311 for desc in descriptors:
2312 if isinstance(desc, AvbChainPartitionDescriptor):
2313 ch_image_filename = os.path.join(image_dir, desc.partition_name + image_ext)
2314 ch_image = ImageHandler(ch_image_filename)
2315 _, _, ch_descriptors, _ = self._parse_image(ch_image)
2316 for ch_desc in ch_descriptors:
2317 if isinstance(ch_desc, AvbKernelCmdlineDescriptor):
2318 cmdline_descriptors.append(ch_desc)
2319 elif isinstance(desc, AvbKernelCmdlineDescriptor):
2320 cmdline_descriptors.append(desc)
2321
2322 kernel_cmdline_snippets = []
2323 for desc in cmdline_descriptors:
2324 use_cmdline = True
2325 if (desc.flags & AvbKernelCmdlineDescriptor.FLAGS_USE_ONLY_IF_HASHTREE_NOT_DISABLED) != 0:
2326 if hashtree_disabled:
2327 use_cmdline = False
2328 if (desc.flags & AvbKernelCmdlineDescriptor.FLAGS_USE_ONLY_IF_HASHTREE_DISABLED) != 0:
2329 if not hashtree_disabled:
2330 use_cmdline = False
2331 if use_cmdline:
2332 kernel_cmdline_snippets.append(desc.kernel_cmdline)
2333 output.write(' '.join(kernel_cmdline_snippets))
2334
2335
David Zeuthen21e95262016-07-27 17:58:40 -04002336 def _parse_image(self, image):
2337 """Gets information about an image.
2338
2339 The image can either be a vbmeta or an image with a footer.
2340
2341 Arguments:
David Zeuthena4fee8b2016-08-22 15:20:43 -04002342 image: An ImageHandler (vbmeta or footer) with a hashtree descriptor.
David Zeuthen21e95262016-07-27 17:58:40 -04002343
2344 Returns:
2345 A tuple where the first argument is a AvbFooter (None if there
2346 is no footer on the image), the second argument is a
2347 AvbVBMetaHeader, the third argument is a list of
2348 AvbDescriptor-derived instances, and the fourth argument is the
2349 size of |image|.
2350 """
David Zeuthena4fee8b2016-08-22 15:20:43 -04002351 assert isinstance(image, ImageHandler)
David Zeuthen21e95262016-07-27 17:58:40 -04002352 footer = None
David Zeuthen09692692016-09-30 16:16:40 -04002353 image.seek(image.image_size - AvbFooter.SIZE)
David Zeuthen21e95262016-07-27 17:58:40 -04002354 try:
2355 footer = AvbFooter(image.read(AvbFooter.SIZE))
2356 except (LookupError, struct.error):
2357 # Nope, just seek back to the start.
2358 image.seek(0)
2359
2360 vbmeta_offset = 0
2361 if footer:
2362 vbmeta_offset = footer.vbmeta_offset
2363
2364 image.seek(vbmeta_offset)
2365 h = AvbVBMetaHeader(image.read(AvbVBMetaHeader.SIZE))
2366
2367 auth_block_offset = vbmeta_offset + AvbVBMetaHeader.SIZE
2368 aux_block_offset = auth_block_offset + h.authentication_data_block_size
2369 desc_start_offset = aux_block_offset + h.descriptors_offset
2370 image.seek(desc_start_offset)
2371 descriptors = parse_descriptors(image.read(h.descriptors_size))
2372
David Zeuthen09692692016-09-30 16:16:40 -04002373 return footer, h, descriptors, image.image_size
David Zeuthen21e95262016-07-27 17:58:40 -04002374
David Zeuthenb1b994d2017-03-06 18:01:31 -05002375 def _load_vbmeta_blob(self, image):
2376 """Gets the vbmeta struct and associated sections.
2377
2378 The image can either be a vbmeta.img or an image with a footer.
2379
2380 Arguments:
2381 image: An ImageHandler (vbmeta or footer).
2382
2383 Returns:
2384 A blob with the vbmeta struct and other sections.
2385 """
2386 assert isinstance(image, ImageHandler)
2387 footer = None
2388 image.seek(image.image_size - AvbFooter.SIZE)
2389 try:
2390 footer = AvbFooter(image.read(AvbFooter.SIZE))
2391 except (LookupError, struct.error):
2392 # Nope, just seek back to the start.
2393 image.seek(0)
2394
2395 vbmeta_offset = 0
2396 if footer:
2397 vbmeta_offset = footer.vbmeta_offset
2398
2399 image.seek(vbmeta_offset)
2400 h = AvbVBMetaHeader(image.read(AvbVBMetaHeader.SIZE))
2401
2402 image.seek(vbmeta_offset)
2403 data_size = AvbVBMetaHeader.SIZE
2404 data_size += h.authentication_data_block_size
2405 data_size += h.auxiliary_data_block_size
2406 return image.read(data_size)
2407
David Zeuthen73f2afa2017-05-17 16:54:11 -04002408 def _get_cmdline_descriptors_for_hashtree_descriptor(self, ht):
David Zeuthenfd41eb92016-11-17 12:24:47 -05002409 """Generate kernel cmdline descriptors for dm-verity.
David Zeuthen21e95262016-07-27 17:58:40 -04002410
2411 Arguments:
David Zeuthen73f2afa2017-05-17 16:54:11 -04002412 ht: A AvbHashtreeDescriptor
David Zeuthen21e95262016-07-27 17:58:40 -04002413
2414 Returns:
David Zeuthenfd41eb92016-11-17 12:24:47 -05002415 A list with two AvbKernelCmdlineDescriptor with dm-verity kernel cmdline
2416 instructions. There is one for when hashtree is not disabled and one for
2417 when it is.
David Zeuthen21e95262016-07-27 17:58:40 -04002418
David Zeuthen21e95262016-07-27 17:58:40 -04002419 """
2420
David Zeuthen21e95262016-07-27 17:58:40 -04002421 c = 'dm="1 vroot none ro 1,'
David Zeuthen0b7f1d32016-10-25 17:53:49 -04002422 c += '0' # start
2423 c += ' {}'.format((ht.image_size / 512)) # size (# sectors)
2424 c += ' verity {}'.format(ht.dm_verity_version) # type and version
2425 c += ' PARTUUID=$(ANDROID_SYSTEM_PARTUUID)' # data_dev
2426 c += ' PARTUUID=$(ANDROID_SYSTEM_PARTUUID)' # hash_dev
2427 c += ' {}'.format(ht.data_block_size) # data_block
2428 c += ' {}'.format(ht.hash_block_size) # hash_block
2429 c += ' {}'.format(ht.image_size / ht.data_block_size) # #blocks
2430 c += ' {}'.format(ht.image_size / ht.data_block_size) # hash_offset
2431 c += ' {}'.format(ht.hash_algorithm) # hash_alg
2432 c += ' {}'.format(str(ht.root_digest).encode('hex')) # root_digest
2433 c += ' {}'.format(str(ht.salt).encode('hex')) # salt
2434 if ht.fec_num_roots > 0:
David Zeuthena01e32f2017-01-24 17:32:38 -05002435 c += ' 10' # number of optional args
David Zeuthen1b2f7a62017-06-23 13:20:54 -04002436 c += ' $(ANDROID_VERITY_MODE)'
David Zeuthen0b7f1d32016-10-25 17:53:49 -04002437 c += ' ignore_zero_blocks'
2438 c += ' use_fec_from_device PARTUUID=$(ANDROID_SYSTEM_PARTUUID)'
2439 c += ' fec_roots {}'.format(ht.fec_num_roots)
2440 # Note that fec_blocks is the size that FEC covers, *not* the
2441 # size of the FEC data. Since we use FEC for everything up until
2442 # the FEC data, it's the same as the offset.
2443 c += ' fec_blocks {}'.format(ht.fec_offset/ht.data_block_size)
2444 c += ' fec_start {}'.format(ht.fec_offset/ht.data_block_size)
2445 else:
David Zeuthena01e32f2017-01-24 17:32:38 -05002446 c += ' 2' # number of optional args
David Zeuthen1b2f7a62017-06-23 13:20:54 -04002447 c += ' $(ANDROID_VERITY_MODE)'
David Zeuthen0b7f1d32016-10-25 17:53:49 -04002448 c += ' ignore_zero_blocks'
David Zeuthenfd9c18d2017-03-20 18:19:30 -04002449 c += '" root=/dev/dm-0'
David Zeuthen21e95262016-07-27 17:58:40 -04002450
David Zeuthenfd41eb92016-11-17 12:24:47 -05002451 # Now that we have the command-line, generate the descriptor.
David Zeuthen21e95262016-07-27 17:58:40 -04002452 desc = AvbKernelCmdlineDescriptor()
2453 desc.kernel_cmdline = c
David Zeuthenfd41eb92016-11-17 12:24:47 -05002454 desc.flags = (
2455 AvbKernelCmdlineDescriptor.FLAGS_USE_ONLY_IF_HASHTREE_NOT_DISABLED)
2456
2457 # The descriptor for when hashtree verification is disabled is a lot
2458 # simpler - we just set the root to the partition.
2459 desc_no_ht = AvbKernelCmdlineDescriptor()
2460 desc_no_ht.kernel_cmdline = 'root=PARTUUID=$(ANDROID_SYSTEM_PARTUUID)'
2461 desc_no_ht.flags = (
2462 AvbKernelCmdlineDescriptor.FLAGS_USE_ONLY_IF_HASHTREE_DISABLED)
2463
2464 return [desc, desc_no_ht]
David Zeuthen21e95262016-07-27 17:58:40 -04002465
David Zeuthen73f2afa2017-05-17 16:54:11 -04002466 def _get_cmdline_descriptors_for_dm_verity(self, image):
2467 """Generate kernel cmdline descriptors for dm-verity.
2468
2469 Arguments:
2470 image: An ImageHandler (vbmeta or footer) with a hashtree descriptor.
2471
2472 Returns:
2473 A list with two AvbKernelCmdlineDescriptor with dm-verity kernel cmdline
2474 instructions. There is one for when hashtree is not disabled and one for
2475 when it is.
2476
2477 Raises:
2478 AvbError: If |image| doesn't have a hashtree descriptor.
2479
2480 """
2481
2482 (_, _, descriptors, _) = self._parse_image(image)
2483
2484 ht = None
2485 for desc in descriptors:
2486 if isinstance(desc, AvbHashtreeDescriptor):
2487 ht = desc
2488 break
2489
2490 if not ht:
2491 raise AvbError('No hashtree descriptor in given image')
2492
2493 return self._get_cmdline_descriptors_for_hashtree_descriptor(ht)
2494
David Zeuthen21e95262016-07-27 17:58:40 -04002495 def make_vbmeta_image(self, output, chain_partitions, algorithm_name,
David Zeuthen18666ab2016-11-15 11:18:05 -05002496 key_path, public_key_metadata_path, rollback_index,
David Zeuthenfd41eb92016-11-17 12:24:47 -05002497 flags, props, props_from_file, kernel_cmdlines,
David Zeuthen5d4f4f22017-01-11 11:37:34 -05002498 setup_rootfs_from_kernel,
David Zeuthena156d3d2017-06-01 12:08:09 -04002499 include_descriptors_from_image,
2500 signing_helper,
2501 signing_helper_with_files,
David Zeuthene3cadca2017-02-22 21:25:46 -05002502 release_string,
David Zeuthen1097a782017-05-31 15:53:17 -04002503 append_to_release_string,
David Zeuthen97cb5802017-06-01 16:14:05 -04002504 print_required_libavb_version,
2505 padding_size):
David Zeuthen21e95262016-07-27 17:58:40 -04002506 """Implements the 'make_vbmeta_image' command.
2507
2508 Arguments:
2509 output: File to write the image to.
David Zeuthena5fd3a42017-02-27 16:38:54 -05002510 chain_partitions: List of partitions to chain or None.
David Zeuthen21e95262016-07-27 17:58:40 -04002511 algorithm_name: Name of algorithm to use.
2512 key_path: Path to key to use or None.
David Zeuthen18666ab2016-11-15 11:18:05 -05002513 public_key_metadata_path: Path to public key metadata or None.
David Zeuthen21e95262016-07-27 17:58:40 -04002514 rollback_index: The rollback index to use.
David Zeuthenfd41eb92016-11-17 12:24:47 -05002515 flags: Flags value to use in the image.
David Zeuthen21e95262016-07-27 17:58:40 -04002516 props: Properties to insert (list of strings of the form 'key:value').
2517 props_from_file: Properties to insert (list of strings 'key:<path>').
2518 kernel_cmdlines: Kernel cmdlines to insert (list of strings).
David Zeuthen5d4f4f22017-01-11 11:37:34 -05002519 setup_rootfs_from_kernel: None or file to generate from.
David Zeuthen21e95262016-07-27 17:58:40 -04002520 include_descriptors_from_image: List of file objects with descriptors.
Dzmitry Yatsushkevich4e552792016-12-15 10:27:48 -08002521 signing_helper: Program which signs a hash and return signature.
David Zeuthena156d3d2017-06-01 12:08:09 -04002522 signing_helper_with_files: Same as signing_helper but uses files instead.
David Zeuthene3cadca2017-02-22 21:25:46 -05002523 release_string: None or avbtool release string to use instead of default.
2524 append_to_release_string: None or string to append.
David Zeuthen1097a782017-05-31 15:53:17 -04002525 print_required_libavb_version: True to only print required libavb version.
David Zeuthen97cb5802017-06-01 16:14:05 -04002526 padding_size: If not 0, pads output so size is a multiple of the number.
David Zeuthen21e95262016-07-27 17:58:40 -04002527
2528 Raises:
2529 AvbError: If a chained partition is malformed.
2530 """
2531
David Zeuthen1097a782017-05-31 15:53:17 -04002532 # If we're asked to calculate minimum required libavb version, we're done.
David Zeuthen1097a782017-05-31 15:53:17 -04002533 if print_required_libavb_version:
Darren Krahnfd0ba0d2018-02-01 18:06:34 -08002534 if include_descriptors_from_image:
2535 # Use the bump logic in AvbVBMetaHeader to calculate the max required
2536 # version of all included descriptors.
2537 tmp_header = AvbVBMetaHeader()
2538 for image in include_descriptors_from_image:
2539 (_, image_header, _, _) = self._parse_image(ImageHandler(image.name))
2540 tmp_header.bump_required_libavb_version_minor(
2541 image_header.required_libavb_version_minor)
2542 print '1.{}'.format(tmp_header.required_libavb_version_minor)
2543 else:
2544 # Descriptors aside, all vbmeta features are supported in 1.0.
2545 print '1.0'
David Zeuthen1097a782017-05-31 15:53:17 -04002546 return
2547
2548 if not output:
2549 raise AvbError('No output file given')
2550
David Zeuthen21e95262016-07-27 17:58:40 -04002551 descriptors = []
David Zeuthen73f2afa2017-05-17 16:54:11 -04002552 ht_desc_to_setup = None
David Zeuthen21e95262016-07-27 17:58:40 -04002553 vbmeta_blob = self._generate_vbmeta_blob(
David Zeuthen18666ab2016-11-15 11:18:05 -05002554 algorithm_name, key_path, public_key_metadata_path, descriptors,
David Zeuthena5fd3a42017-02-27 16:38:54 -05002555 chain_partitions, rollback_index, flags, props, props_from_file,
David Zeuthen73f2afa2017-05-17 16:54:11 -04002556 kernel_cmdlines, setup_rootfs_from_kernel, ht_desc_to_setup,
David Zeuthena156d3d2017-06-01 12:08:09 -04002557 include_descriptors_from_image, signing_helper,
2558 signing_helper_with_files, release_string,
Darren Krahnfd0ba0d2018-02-01 18:06:34 -08002559 append_to_release_string, 0)
David Zeuthen21e95262016-07-27 17:58:40 -04002560
2561 # Write entire vbmeta blob (header, authentication, auxiliary).
2562 output.seek(0)
2563 output.write(vbmeta_blob)
2564
David Zeuthen97cb5802017-06-01 16:14:05 -04002565 if padding_size > 0:
2566 padded_size = round_to_multiple(len(vbmeta_blob), padding_size)
2567 padding_needed = padded_size - len(vbmeta_blob)
2568 output.write('\0' * padding_needed)
2569
David Zeuthen18666ab2016-11-15 11:18:05 -05002570 def _generate_vbmeta_blob(self, algorithm_name, key_path,
2571 public_key_metadata_path, descriptors,
David Zeuthena5fd3a42017-02-27 16:38:54 -05002572 chain_partitions,
David Zeuthenfd41eb92016-11-17 12:24:47 -05002573 rollback_index, flags, props, props_from_file,
David Zeuthen21e95262016-07-27 17:58:40 -04002574 kernel_cmdlines,
David Zeuthen5d4f4f22017-01-11 11:37:34 -05002575 setup_rootfs_from_kernel,
David Zeuthen73f2afa2017-05-17 16:54:11 -04002576 ht_desc_to_setup,
David Zeuthene3cadca2017-02-22 21:25:46 -05002577 include_descriptors_from_image, signing_helper,
David Zeuthena156d3d2017-06-01 12:08:09 -04002578 signing_helper_with_files,
Darren Krahnfd0ba0d2018-02-01 18:06:34 -08002579 release_string, append_to_release_string,
2580 required_libavb_version_minor):
David Zeuthen21e95262016-07-27 17:58:40 -04002581 """Generates a VBMeta blob.
2582
2583 This blob contains the header (struct AvbVBMetaHeader), the
2584 authentication data block (which contains the hash and signature
2585 for the header and auxiliary block), and the auxiliary block
2586 (which contains descriptors, the public key used, and other data).
2587
2588 The |key| parameter can |None| only if the |algorithm_name| is
2589 'NONE'.
2590
2591 Arguments:
2592 algorithm_name: The algorithm name as per the ALGORITHMS dict.
2593 key_path: The path to the .pem file used to sign the blob.
David Zeuthen18666ab2016-11-15 11:18:05 -05002594 public_key_metadata_path: Path to public key metadata or None.
David Zeuthen21e95262016-07-27 17:58:40 -04002595 descriptors: A list of descriptors to insert or None.
David Zeuthena5fd3a42017-02-27 16:38:54 -05002596 chain_partitions: List of partitions to chain or None.
David Zeuthen21e95262016-07-27 17:58:40 -04002597 rollback_index: The rollback index to use.
David Zeuthenfd41eb92016-11-17 12:24:47 -05002598 flags: Flags to use in the image.
David Zeuthen21e95262016-07-27 17:58:40 -04002599 props: Properties to insert (List of strings of the form 'key:value').
2600 props_from_file: Properties to insert (List of strings 'key:<path>').
2601 kernel_cmdlines: Kernel cmdlines to insert (list of strings).
David Zeuthen5d4f4f22017-01-11 11:37:34 -05002602 setup_rootfs_from_kernel: None or file to generate
David Zeuthen21e95262016-07-27 17:58:40 -04002603 dm-verity kernel cmdline from.
David Zeuthen73f2afa2017-05-17 16:54:11 -04002604 ht_desc_to_setup: If not None, an AvbHashtreeDescriptor to
2605 generate dm-verity kernel cmdline descriptors from.
David Zeuthen21e95262016-07-27 17:58:40 -04002606 include_descriptors_from_image: List of file objects for which
2607 to insert descriptors from.
Dzmitry Yatsushkevich4e552792016-12-15 10:27:48 -08002608 signing_helper: Program which signs a hash and return signature.
David Zeuthena156d3d2017-06-01 12:08:09 -04002609 signing_helper_with_files: Same as signing_helper but uses files instead.
David Zeuthene3cadca2017-02-22 21:25:46 -05002610 release_string: None or avbtool release string.
2611 append_to_release_string: None or string to append.
Darren Krahnfd0ba0d2018-02-01 18:06:34 -08002612 required_libavb_version_minor: Use at least this required minor version.
David Zeuthen21e95262016-07-27 17:58:40 -04002613
2614 Returns:
2615 A bytearray() with the VBMeta blob.
2616
2617 Raises:
2618 Exception: If the |algorithm_name| is not found, if no key has
2619 been given and the given algorithm requires one, or the key is
2620 of the wrong size.
2621
2622 """
2623 try:
2624 alg = ALGORITHMS[algorithm_name]
2625 except KeyError:
2626 raise AvbError('Unknown algorithm with name {}'.format(algorithm_name))
2627
David Zeuthena5fd3a42017-02-27 16:38:54 -05002628 if not descriptors:
2629 descriptors = []
2630
Darren Krahnfd0ba0d2018-02-01 18:06:34 -08002631 h = AvbVBMetaHeader()
2632 h.bump_required_libavb_version_minor(required_libavb_version_minor)
2633
David Zeuthena5fd3a42017-02-27 16:38:54 -05002634 # Insert chained partition descriptors, if any
2635 if chain_partitions:
David Zeuthend8e48582017-04-21 11:31:51 -04002636 used_locations = {}
David Zeuthena5fd3a42017-02-27 16:38:54 -05002637 for cp in chain_partitions:
2638 cp_tokens = cp.split(':')
2639 if len(cp_tokens) != 3:
2640 raise AvbError('Malformed chained partition "{}".'.format(cp))
David Zeuthend8e48582017-04-21 11:31:51 -04002641 partition_name = cp_tokens[0]
2642 rollback_index_location = int(cp_tokens[1])
2643 file_path = cp_tokens[2]
2644 # Check that the same rollback location isn't being used by
2645 # multiple chained partitions.
2646 if used_locations.get(rollback_index_location):
2647 raise AvbError('Rollback Index Location {} is already in use.'.format(
2648 rollback_index_location))
2649 used_locations[rollback_index_location] = True
David Zeuthena5fd3a42017-02-27 16:38:54 -05002650 desc = AvbChainPartitionDescriptor()
David Zeuthend8e48582017-04-21 11:31:51 -04002651 desc.partition_name = partition_name
2652 desc.rollback_index_location = rollback_index_location
David Zeuthena5fd3a42017-02-27 16:38:54 -05002653 if desc.rollback_index_location < 1:
2654 raise AvbError('Rollback index location must be 1 or larger.')
David Zeuthena5fd3a42017-02-27 16:38:54 -05002655 desc.public_key = open(file_path, 'rb').read()
2656 descriptors.append(desc)
2657
David Zeuthen21e95262016-07-27 17:58:40 -04002658 # Descriptors.
2659 encoded_descriptors = bytearray()
David Zeuthena5fd3a42017-02-27 16:38:54 -05002660 for desc in descriptors:
2661 encoded_descriptors.extend(desc.encode())
David Zeuthen21e95262016-07-27 17:58:40 -04002662
2663 # Add properties.
2664 if props:
2665 for prop in props:
2666 idx = prop.find(':')
2667 if idx == -1:
2668 raise AvbError('Malformed property "{}".'.format(prop))
2669 desc = AvbPropertyDescriptor()
2670 desc.key = prop[0:idx]
2671 desc.value = prop[(idx + 1):]
2672 encoded_descriptors.extend(desc.encode())
2673 if props_from_file:
2674 for prop in props_from_file:
2675 idx = prop.find(':')
2676 if idx == -1:
2677 raise AvbError('Malformed property "{}".'.format(prop))
2678 desc = AvbPropertyDescriptor()
2679 desc.key = prop[0:idx]
2680 desc.value = prop[(idx + 1):]
2681 file_path = prop[(idx + 1):]
2682 desc.value = open(file_path, 'rb').read()
2683 encoded_descriptors.extend(desc.encode())
2684
David Zeuthen73f2afa2017-05-17 16:54:11 -04002685 # Add AvbKernelCmdline descriptor for dm-verity from an image, if requested.
David Zeuthen5d4f4f22017-01-11 11:37:34 -05002686 if setup_rootfs_from_kernel:
David Zeuthena4fee8b2016-08-22 15:20:43 -04002687 image_handler = ImageHandler(
David Zeuthen5d4f4f22017-01-11 11:37:34 -05002688 setup_rootfs_from_kernel.name)
David Zeuthenfd41eb92016-11-17 12:24:47 -05002689 cmdline_desc = self._get_cmdline_descriptors_for_dm_verity(image_handler)
2690 encoded_descriptors.extend(cmdline_desc[0].encode())
2691 encoded_descriptors.extend(cmdline_desc[1].encode())
David Zeuthen21e95262016-07-27 17:58:40 -04002692
David Zeuthen73f2afa2017-05-17 16:54:11 -04002693 # Add AvbKernelCmdline descriptor for dm-verity from desc, if requested.
2694 if ht_desc_to_setup:
2695 cmdline_desc = self._get_cmdline_descriptors_for_hashtree_descriptor(
2696 ht_desc_to_setup)
2697 encoded_descriptors.extend(cmdline_desc[0].encode())
2698 encoded_descriptors.extend(cmdline_desc[1].encode())
2699
David Zeuthen21e95262016-07-27 17:58:40 -04002700 # Add kernel command-lines.
2701 if kernel_cmdlines:
2702 for i in kernel_cmdlines:
2703 desc = AvbKernelCmdlineDescriptor()
2704 desc.kernel_cmdline = i
2705 encoded_descriptors.extend(desc.encode())
2706
2707 # Add descriptors from other images.
2708 if include_descriptors_from_image:
Sen Jiang2a3d6bc2018-04-04 14:13:28 -07002709 descriptors_dict = dict()
David Zeuthen21e95262016-07-27 17:58:40 -04002710 for image in include_descriptors_from_image:
David Zeuthena4fee8b2016-08-22 15:20:43 -04002711 image_handler = ImageHandler(image.name)
Darren Krahnfd0ba0d2018-02-01 18:06:34 -08002712 (_, image_vbmeta_header, image_descriptors, _) = self._parse_image(
2713 image_handler)
2714 # Bump the required libavb version to support all included descriptors.
2715 h.bump_required_libavb_version_minor(
2716 image_vbmeta_header.required_libavb_version_minor)
David Zeuthen21e95262016-07-27 17:58:40 -04002717 for desc in image_descriptors:
Sen Jiang2a3d6bc2018-04-04 14:13:28 -07002718 # The --include_descriptors_from_image option is used in some setups
2719 # with images A and B where both A and B contain a descriptor
2720 # for a partition with the same name. Since it's not meaningful
2721 # to include both descriptors, only include the last seen descriptor.
2722 # See bug 76386656 for details.
2723 if hasattr(desc, 'partition_name'):
2724 key = type(desc).__name__ + '_' + desc.partition_name
2725 descriptors_dict[key] = desc.encode()
2726 else:
2727 encoded_descriptors.extend(desc.encode())
2728 for key in sorted(descriptors_dict.keys()):
2729 encoded_descriptors.extend(descriptors_dict[key])
David Zeuthen21e95262016-07-27 17:58:40 -04002730
David Zeuthen18666ab2016-11-15 11:18:05 -05002731 # Load public key metadata blob, if requested.
2732 pkmd_blob = []
2733 if public_key_metadata_path:
2734 with open(public_key_metadata_path) as f:
2735 pkmd_blob = f.read()
2736
David Zeuthen21e95262016-07-27 17:58:40 -04002737 key = None
2738 encoded_key = bytearray()
2739 if alg.public_key_num_bytes > 0:
2740 if not key_path:
2741 raise AvbError('Key is required for algorithm {}'.format(
2742 algorithm_name))
David Zeuthenc68f0822017-03-31 17:22:35 -04002743 encoded_key = encode_rsa_key(key_path)
David Zeuthen21e95262016-07-27 17:58:40 -04002744 if len(encoded_key) != alg.public_key_num_bytes:
2745 raise AvbError('Key is wrong size for algorithm {}'.format(
2746 algorithm_name))
2747
David Zeuthene3cadca2017-02-22 21:25:46 -05002748 # Override release string, if requested.
2749 if isinstance(release_string, (str, unicode)):
2750 h.release_string = release_string
2751
2752 # Append to release string, if requested. Also insert a space before.
2753 if isinstance(append_to_release_string, (str, unicode)):
2754 h.release_string += ' ' + append_to_release_string
2755
David Zeuthen18666ab2016-11-15 11:18:05 -05002756 # For the Auxiliary data block, descriptors are stored at offset 0,
2757 # followed by the public key, followed by the public key metadata blob.
David Zeuthen21e95262016-07-27 17:58:40 -04002758 h.auxiliary_data_block_size = round_to_multiple(
David Zeuthen18666ab2016-11-15 11:18:05 -05002759 len(encoded_descriptors) + len(encoded_key) + len(pkmd_blob), 64)
David Zeuthen21e95262016-07-27 17:58:40 -04002760 h.descriptors_offset = 0
2761 h.descriptors_size = len(encoded_descriptors)
2762 h.public_key_offset = h.descriptors_size
2763 h.public_key_size = len(encoded_key)
David Zeuthen18666ab2016-11-15 11:18:05 -05002764 h.public_key_metadata_offset = h.public_key_offset + h.public_key_size
2765 h.public_key_metadata_size = len(pkmd_blob)
David Zeuthen21e95262016-07-27 17:58:40 -04002766
2767 # For the Authentication data block, the hash is first and then
2768 # the signature.
2769 h.authentication_data_block_size = round_to_multiple(
David Zeuthend5db21d2017-01-24 10:11:38 -05002770 alg.hash_num_bytes + alg.signature_num_bytes, 64)
David Zeuthen21e95262016-07-27 17:58:40 -04002771 h.algorithm_type = alg.algorithm_type
2772 h.hash_offset = 0
2773 h.hash_size = alg.hash_num_bytes
2774 # Signature offset and size - it's stored right after the hash
2775 # (in Authentication data block).
2776 h.signature_offset = alg.hash_num_bytes
2777 h.signature_size = alg.signature_num_bytes
2778
2779 h.rollback_index = rollback_index
David Zeuthenfd41eb92016-11-17 12:24:47 -05002780 h.flags = flags
David Zeuthen21e95262016-07-27 17:58:40 -04002781
2782 # Generate Header data block.
2783 header_data_blob = h.encode()
2784
2785 # Generate Auxiliary data block.
2786 aux_data_blob = bytearray()
2787 aux_data_blob.extend(encoded_descriptors)
2788 aux_data_blob.extend(encoded_key)
David Zeuthen18666ab2016-11-15 11:18:05 -05002789 aux_data_blob.extend(pkmd_blob)
David Zeuthen21e95262016-07-27 17:58:40 -04002790 padding_bytes = h.auxiliary_data_block_size - len(aux_data_blob)
2791 aux_data_blob.extend('\0' * padding_bytes)
2792
2793 # Calculate the hash.
2794 binary_hash = bytearray()
2795 binary_signature = bytearray()
2796 if algorithm_name != 'NONE':
David Zeuthenb623d8b2017-04-04 16:05:53 -04002797 ha = hashlib.new(alg.hash_name)
David Zeuthen21e95262016-07-27 17:58:40 -04002798 ha.update(header_data_blob)
2799 ha.update(aux_data_blob)
2800 binary_hash.extend(ha.digest())
2801
2802 # Calculate the signature.
David Zeuthen21e95262016-07-27 17:58:40 -04002803 padding_and_hash = str(bytearray(alg.padding)) + binary_hash
David Zeuthena156d3d2017-06-01 12:08:09 -04002804 binary_signature.extend(raw_sign(signing_helper,
2805 signing_helper_with_files,
2806 algorithm_name,
Esun Kimff44f232017-03-30 10:34:54 +09002807 alg.signature_num_bytes, key_path,
Darren Krahn147b08d2016-12-20 16:38:29 -08002808 padding_and_hash))
David Zeuthen21e95262016-07-27 17:58:40 -04002809
2810 # Generate Authentication data block.
2811 auth_data_blob = bytearray()
2812 auth_data_blob.extend(binary_hash)
2813 auth_data_blob.extend(binary_signature)
2814 padding_bytes = h.authentication_data_block_size - len(auth_data_blob)
2815 auth_data_blob.extend('\0' * padding_bytes)
2816
2817 return header_data_blob + auth_data_blob + aux_data_blob
2818
2819 def extract_public_key(self, key_path, output):
2820 """Implements the 'extract_public_key' command.
2821
2822 Arguments:
2823 key_path: The path to a RSA private key file.
2824 output: The file to write to.
2825 """
David Zeuthenc68f0822017-03-31 17:22:35 -04002826 output.write(encode_rsa_key(key_path))
David Zeuthen21e95262016-07-27 17:58:40 -04002827
David Zeuthenb1b994d2017-03-06 18:01:31 -05002828 def append_vbmeta_image(self, image_filename, vbmeta_image_filename,
2829 partition_size):
2830 """Implementation of the append_vbmeta_image command.
2831
2832 Arguments:
2833 image_filename: File to add the footer to.
2834 vbmeta_image_filename: File to get vbmeta struct from.
2835 partition_size: Size of partition.
2836
2837 Raises:
2838 AvbError: If an argument is incorrect.
2839 """
2840 image = ImageHandler(image_filename)
2841
2842 if partition_size % image.block_size != 0:
2843 raise AvbError('Partition size of {} is not a multiple of the image '
2844 'block size {}.'.format(partition_size,
2845 image.block_size))
2846
2847 # If there's already a footer, truncate the image to its original
2848 # size. This way 'avbtool append_vbmeta_image' is idempotent.
Lonnie Liu6b5a33e2017-10-31 18:01:09 -07002849 if image.image_size >= AvbFooter.SIZE:
2850 image.seek(image.image_size - AvbFooter.SIZE)
2851 try:
2852 footer = AvbFooter(image.read(AvbFooter.SIZE))
2853 # Existing footer found. Just truncate.
2854 original_image_size = footer.original_image_size
2855 image.truncate(footer.original_image_size)
2856 except (LookupError, struct.error):
2857 original_image_size = image.image_size
2858 else:
2859 # Image size is too small to possibly contain a footer.
David Zeuthenb1b994d2017-03-06 18:01:31 -05002860 original_image_size = image.image_size
2861
2862 # If anything goes wrong from here-on, restore the image back to
2863 # its original size.
2864 try:
2865 vbmeta_image_handler = ImageHandler(vbmeta_image_filename)
2866 vbmeta_blob = self._load_vbmeta_blob(vbmeta_image_handler)
2867
2868 # If the image isn't sparse, its size might not be a multiple of
2869 # the block size. This will screw up padding later so just grow it.
2870 if image.image_size % image.block_size != 0:
2871 assert not image.is_sparse
2872 padding_needed = image.block_size - (image.image_size%image.block_size)
2873 image.truncate(image.image_size + padding_needed)
2874
2875 # The append_raw() method requires content with size being a
2876 # multiple of |block_size| so add padding as needed. Also record
2877 # where this is written to since we'll need to put that in the
2878 # footer.
2879 vbmeta_offset = image.image_size
2880 padding_needed = (round_to_multiple(len(vbmeta_blob), image.block_size) -
2881 len(vbmeta_blob))
2882 vbmeta_blob_with_padding = vbmeta_blob + '\0'*padding_needed
2883
2884 # Append vbmeta blob and footer
2885 image.append_raw(vbmeta_blob_with_padding)
2886 vbmeta_end_offset = vbmeta_offset + len(vbmeta_blob_with_padding)
2887
2888 # Now insert a DONT_CARE chunk with enough bytes such that the
2889 # final Footer block is at the end of partition_size..
2890 image.append_dont_care(partition_size - vbmeta_end_offset -
2891 1*image.block_size)
2892
2893 # Generate the Footer that tells where the VBMeta footer
2894 # is. Also put enough padding in the front of the footer since
2895 # we'll write out an entire block.
2896 footer = AvbFooter()
2897 footer.original_image_size = original_image_size
2898 footer.vbmeta_offset = vbmeta_offset
2899 footer.vbmeta_size = len(vbmeta_blob)
2900 footer_blob = footer.encode()
2901 footer_blob_with_padding = ('\0'*(image.block_size - AvbFooter.SIZE) +
2902 footer_blob)
2903 image.append_raw(footer_blob_with_padding)
2904
2905 except:
2906 # Truncate back to original size, then re-raise
2907 image.truncate(original_image_size)
2908 raise
2909
David Zeuthena4fee8b2016-08-22 15:20:43 -04002910 def add_hash_footer(self, image_filename, partition_size, partition_name,
David Zeuthena5fd3a42017-02-27 16:38:54 -05002911 hash_algorithm, salt, chain_partitions, algorithm_name,
2912 key_path,
2913 public_key_metadata_path, rollback_index, flags, props,
David Zeuthen18666ab2016-11-15 11:18:05 -05002914 props_from_file, kernel_cmdlines,
David Zeuthen5d4f4f22017-01-11 11:37:34 -05002915 setup_rootfs_from_kernel,
David Zeuthenbf562452017-05-17 18:04:43 -04002916 include_descriptors_from_image, calc_max_image_size,
David Zeuthena156d3d2017-06-01 12:08:09 -04002917 signing_helper, signing_helper_with_files,
2918 release_string, append_to_release_string,
David Zeuthen1097a782017-05-31 15:53:17 -04002919 output_vbmeta_image, do_not_append_vbmeta_image,
Darren Krahnfd0ba0d2018-02-01 18:06:34 -08002920 print_required_libavb_version, use_persistent_digest,
2921 do_not_use_ab):
David Zeuthena4fee8b2016-08-22 15:20:43 -04002922 """Implementation of the add_hash_footer on unsparse images.
David Zeuthen21e95262016-07-27 17:58:40 -04002923
2924 Arguments:
David Zeuthena4fee8b2016-08-22 15:20:43 -04002925 image_filename: File to add the footer to.
David Zeuthen21e95262016-07-27 17:58:40 -04002926 partition_size: Size of partition.
2927 partition_name: Name of partition (without A/B suffix).
2928 hash_algorithm: Hash algorithm to use.
2929 salt: Salt to use as a hexadecimal string or None to use /dev/urandom.
David Zeuthena5fd3a42017-02-27 16:38:54 -05002930 chain_partitions: List of partitions to chain.
David Zeuthen21e95262016-07-27 17:58:40 -04002931 algorithm_name: Name of algorithm to use.
2932 key_path: Path to key to use or None.
David Zeuthen18666ab2016-11-15 11:18:05 -05002933 public_key_metadata_path: Path to public key metadata or None.
David Zeuthen21e95262016-07-27 17:58:40 -04002934 rollback_index: Rollback index.
David Zeuthena5fd3a42017-02-27 16:38:54 -05002935 flags: Flags value to use in the image.
David Zeuthen21e95262016-07-27 17:58:40 -04002936 props: Properties to insert (List of strings of the form 'key:value').
2937 props_from_file: Properties to insert (List of strings 'key:<path>').
2938 kernel_cmdlines: Kernel cmdlines to insert (list of strings).
David Zeuthen5d4f4f22017-01-11 11:37:34 -05002939 setup_rootfs_from_kernel: None or file to generate
David Zeuthen21e95262016-07-27 17:58:40 -04002940 dm-verity kernel cmdline from.
2941 include_descriptors_from_image: List of file objects for which
2942 to insert descriptors from.
David Zeuthenbf562452017-05-17 18:04:43 -04002943 calc_max_image_size: Don't store the footer - instead calculate the
2944 maximum image size leaving enough room for metadata with the
2945 given |partition_size|.
Dzmitry Yatsushkevich4e552792016-12-15 10:27:48 -08002946 signing_helper: Program which signs a hash and return signature.
David Zeuthena156d3d2017-06-01 12:08:09 -04002947 signing_helper_with_files: Same as signing_helper but uses files instead.
David Zeuthene3cadca2017-02-22 21:25:46 -05002948 release_string: None or avbtool release string.
2949 append_to_release_string: None or string to append.
David Zeuthend247fcb2017-02-16 12:09:27 -05002950 output_vbmeta_image: If not None, also write vbmeta struct to this file.
2951 do_not_append_vbmeta_image: If True, don't append vbmeta struct.
David Zeuthen1097a782017-05-31 15:53:17 -04002952 print_required_libavb_version: True to only print required libavb version.
Darren Krahnfd0ba0d2018-02-01 18:06:34 -08002953 use_persistent_digest: Use a persistent digest on device.
2954 do_not_use_ab: This partition does not use A/B.
David Zeuthena4fee8b2016-08-22 15:20:43 -04002955
2956 Raises:
2957 AvbError: If an argument is incorrect.
David Zeuthen21e95262016-07-27 17:58:40 -04002958 """
David Zeuthen1097a782017-05-31 15:53:17 -04002959
Darren Krahnfd0ba0d2018-02-01 18:06:34 -08002960 required_libavb_version_minor = 0
2961 if use_persistent_digest or do_not_use_ab:
2962 required_libavb_version_minor = 1
2963
David Zeuthen1097a782017-05-31 15:53:17 -04002964 # If we're asked to calculate minimum required libavb version, we're done.
David Zeuthen1097a782017-05-31 15:53:17 -04002965 if print_required_libavb_version:
Darren Krahnfd0ba0d2018-02-01 18:06:34 -08002966 print '1.{}'.format(required_libavb_version_minor)
David Zeuthen1097a782017-05-31 15:53:17 -04002967 return
2968
David Zeuthenbf562452017-05-17 18:04:43 -04002969 # First, calculate the maximum image size such that an image
2970 # this size + metadata (footer + vbmeta struct) fits in
2971 # |partition_size|.
2972 max_metadata_size = self.MAX_VBMETA_SIZE + self.MAX_FOOTER_SIZE
Lonnie Liu6b5a33e2017-10-31 18:01:09 -07002973 if partition_size < max_metadata_size:
2974 raise AvbError('Parition size of {} is too small. '
2975 'Needs to be at least {}'.format(
2976 partition_size, max_metadata_size))
David Zeuthenbf562452017-05-17 18:04:43 -04002977 max_image_size = partition_size - max_metadata_size
2978
2979 # If we're asked to only calculate the maximum image size, we're done.
2980 if calc_max_image_size:
2981 print '{}'.format(max_image_size)
2982 return
2983
David Zeuthena4fee8b2016-08-22 15:20:43 -04002984 image = ImageHandler(image_filename)
2985
2986 if partition_size % image.block_size != 0:
2987 raise AvbError('Partition size of {} is not a multiple of the image '
2988 'block size {}.'.format(partition_size,
2989 image.block_size))
2990
David Zeuthen21e95262016-07-27 17:58:40 -04002991 # If there's already a footer, truncate the image to its original
2992 # size. This way 'avbtool add_hash_footer' is idempotent (modulo
2993 # salts).
Lonnie Liu6b5a33e2017-10-31 18:01:09 -07002994 if image.image_size >= AvbFooter.SIZE:
2995 image.seek(image.image_size - AvbFooter.SIZE)
2996 try:
2997 footer = AvbFooter(image.read(AvbFooter.SIZE))
2998 # Existing footer found. Just truncate.
2999 original_image_size = footer.original_image_size
3000 image.truncate(footer.original_image_size)
3001 except (LookupError, struct.error):
3002 original_image_size = image.image_size
3003 else:
3004 # Image size is too small to possibly contain a footer.
David Zeuthen09692692016-09-30 16:16:40 -04003005 original_image_size = image.image_size
David Zeuthen21e95262016-07-27 17:58:40 -04003006
3007 # If anything goes wrong from here-on, restore the image back to
3008 # its original size.
3009 try:
David Zeuthen09692692016-09-30 16:16:40 -04003010 # If image size exceeds the maximum image size, fail.
3011 if image.image_size > max_image_size:
3012 raise AvbError('Image size of {} exceeds maximum image '
3013 'size of {} in order to fit in a partition '
3014 'size of {}.'.format(image.image_size, max_image_size,
3015 partition_size))
3016
David Zeuthen21e95262016-07-27 17:58:40 -04003017 digest_size = len(hashlib.new(name=hash_algorithm).digest())
3018 if salt:
3019 salt = salt.decode('hex')
3020 else:
3021 if salt is None:
3022 # If salt is not explicitly specified, choose a hash
3023 # that's the same size as the hash size.
3024 hash_size = digest_size
3025 salt = open('/dev/urandom').read(hash_size)
3026 else:
3027 salt = ''
3028
3029 hasher = hashlib.new(name=hash_algorithm, string=salt)
3030 # TODO(zeuthen): might want to read this in chunks to avoid
3031 # memory pressure, then again, this is only supposed to be used
3032 # on kernel/initramfs partitions. Possible optimization.
3033 image.seek(0)
David Zeuthen09692692016-09-30 16:16:40 -04003034 hasher.update(image.read(image.image_size))
David Zeuthen21e95262016-07-27 17:58:40 -04003035 digest = hasher.digest()
3036
3037 h_desc = AvbHashDescriptor()
David Zeuthen09692692016-09-30 16:16:40 -04003038 h_desc.image_size = image.image_size
David Zeuthen21e95262016-07-27 17:58:40 -04003039 h_desc.hash_algorithm = hash_algorithm
3040 h_desc.partition_name = partition_name
3041 h_desc.salt = salt
Darren Krahnfd0ba0d2018-02-01 18:06:34 -08003042 h_desc.flags = 0
3043 if do_not_use_ab:
3044 h_desc.flags |= 1 # AVB_HASH_DESCRIPTOR_FLAGS_DO_NOT_USE_AB
3045 if not use_persistent_digest:
3046 h_desc.digest = digest
David Zeuthen21e95262016-07-27 17:58:40 -04003047
3048 # Generate the VBMeta footer.
David Zeuthen73f2afa2017-05-17 16:54:11 -04003049 ht_desc_to_setup = None
David Zeuthen21e95262016-07-27 17:58:40 -04003050 vbmeta_blob = self._generate_vbmeta_blob(
David Zeuthen18666ab2016-11-15 11:18:05 -05003051 algorithm_name, key_path, public_key_metadata_path, [h_desc],
David Zeuthena5fd3a42017-02-27 16:38:54 -05003052 chain_partitions, rollback_index, flags, props, props_from_file,
David Zeuthen73f2afa2017-05-17 16:54:11 -04003053 kernel_cmdlines, setup_rootfs_from_kernel, ht_desc_to_setup,
David Zeuthena156d3d2017-06-01 12:08:09 -04003054 include_descriptors_from_image, signing_helper,
3055 signing_helper_with_files, release_string,
Darren Krahnfd0ba0d2018-02-01 18:06:34 -08003056 append_to_release_string, required_libavb_version_minor)
David Zeuthen21e95262016-07-27 17:58:40 -04003057
David Zeuthend247fcb2017-02-16 12:09:27 -05003058 # Write vbmeta blob, if requested.
3059 if output_vbmeta_image:
3060 output_vbmeta_image.write(vbmeta_blob)
David Zeuthena4fee8b2016-08-22 15:20:43 -04003061
David Zeuthend247fcb2017-02-16 12:09:27 -05003062 # Append vbmeta blob and footer, unless requested not to.
3063 if not do_not_append_vbmeta_image:
Lonnie Liu6b5a33e2017-10-31 18:01:09 -07003064 # If the image isn't sparse, its size might not be a multiple of
3065 # the block size. This will screw up padding later so just grow it.
3066 if image.image_size % image.block_size != 0:
3067 assert not image.is_sparse
3068 padding_needed = image.block_size - (
3069 image.image_size % image.block_size)
3070 image.truncate(image.image_size + padding_needed)
3071
3072 # The append_raw() method requires content with size being a
3073 # multiple of |block_size| so add padding as needed. Also record
3074 # where this is written to since we'll need to put that in the
3075 # footer.
3076 vbmeta_offset = image.image_size
3077 padding_needed = (
3078 round_to_multiple(len(vbmeta_blob), image.block_size) -
3079 len(vbmeta_blob))
3080 vbmeta_blob_with_padding = vbmeta_blob + '\0' * padding_needed
3081
David Zeuthend247fcb2017-02-16 12:09:27 -05003082 image.append_raw(vbmeta_blob_with_padding)
3083 vbmeta_end_offset = vbmeta_offset + len(vbmeta_blob_with_padding)
3084
3085 # Now insert a DONT_CARE chunk with enough bytes such that the
3086 # final Footer block is at the end of partition_size..
3087 image.append_dont_care(partition_size - vbmeta_end_offset -
3088 1*image.block_size)
3089
3090 # Generate the Footer that tells where the VBMeta footer
3091 # is. Also put enough padding in the front of the footer since
3092 # we'll write out an entire block.
3093 footer = AvbFooter()
3094 footer.original_image_size = original_image_size
3095 footer.vbmeta_offset = vbmeta_offset
3096 footer.vbmeta_size = len(vbmeta_blob)
3097 footer_blob = footer.encode()
3098 footer_blob_with_padding = ('\0'*(image.block_size - AvbFooter.SIZE) +
3099 footer_blob)
3100 image.append_raw(footer_blob_with_padding)
David Zeuthena4fee8b2016-08-22 15:20:43 -04003101
David Zeuthen21e95262016-07-27 17:58:40 -04003102 except:
3103 # Truncate back to original size, then re-raise
3104 image.truncate(original_image_size)
3105 raise
3106
David Zeuthena4fee8b2016-08-22 15:20:43 -04003107 def add_hashtree_footer(self, image_filename, partition_size, partition_name,
David Zeuthen0b7f1d32016-10-25 17:53:49 -04003108 generate_fec, fec_num_roots, hash_algorithm,
David Zeuthena5fd3a42017-02-27 16:38:54 -05003109 block_size, salt, chain_partitions, algorithm_name,
3110 key_path,
3111 public_key_metadata_path, rollback_index, flags,
David Zeuthenfd41eb92016-11-17 12:24:47 -05003112 props, props_from_file, kernel_cmdlines,
David Zeuthen5d4f4f22017-01-11 11:37:34 -05003113 setup_rootfs_from_kernel,
David Zeuthen73f2afa2017-05-17 16:54:11 -04003114 setup_as_rootfs_from_kernel,
David Zeuthen09692692016-09-30 16:16:40 -04003115 include_descriptors_from_image,
David Zeuthend247fcb2017-02-16 12:09:27 -05003116 calc_max_image_size, signing_helper,
David Zeuthena156d3d2017-06-01 12:08:09 -04003117 signing_helper_with_files,
David Zeuthene3cadca2017-02-22 21:25:46 -05003118 release_string, append_to_release_string,
David Zeuthen1097a782017-05-31 15:53:17 -04003119 output_vbmeta_image, do_not_append_vbmeta_image,
Darren Krahnfd0ba0d2018-02-01 18:06:34 -08003120 print_required_libavb_version,
3121 use_persistent_root_digest, do_not_use_ab):
David Zeuthen21e95262016-07-27 17:58:40 -04003122 """Implements the 'add_hashtree_footer' command.
3123
3124 See https://gitlab.com/cryptsetup/cryptsetup/wikis/DMVerity for
3125 more information about dm-verity and these hashes.
3126
3127 Arguments:
David Zeuthena4fee8b2016-08-22 15:20:43 -04003128 image_filename: File to add the footer to.
David Zeuthen21e95262016-07-27 17:58:40 -04003129 partition_size: Size of partition.
3130 partition_name: Name of partition (without A/B suffix).
David Zeuthen0b7f1d32016-10-25 17:53:49 -04003131 generate_fec: If True, generate FEC codes.
3132 fec_num_roots: Number of roots for FEC.
David Zeuthen21e95262016-07-27 17:58:40 -04003133 hash_algorithm: Hash algorithm to use.
3134 block_size: Block size to use.
3135 salt: Salt to use as a hexadecimal string or None to use /dev/urandom.
David Zeuthena5fd3a42017-02-27 16:38:54 -05003136 chain_partitions: List of partitions to chain.
David Zeuthen21e95262016-07-27 17:58:40 -04003137 algorithm_name: Name of algorithm to use.
3138 key_path: Path to key to use or None.
David Zeuthen18666ab2016-11-15 11:18:05 -05003139 public_key_metadata_path: Path to public key metadata or None.
David Zeuthen21e95262016-07-27 17:58:40 -04003140 rollback_index: Rollback index.
David Zeuthena5fd3a42017-02-27 16:38:54 -05003141 flags: Flags value to use in the image.
David Zeuthen21e95262016-07-27 17:58:40 -04003142 props: Properties to insert (List of strings of the form 'key:value').
3143 props_from_file: Properties to insert (List of strings 'key:<path>').
3144 kernel_cmdlines: Kernel cmdlines to insert (list of strings).
David Zeuthen5d4f4f22017-01-11 11:37:34 -05003145 setup_rootfs_from_kernel: None or file to generate
David Zeuthen21e95262016-07-27 17:58:40 -04003146 dm-verity kernel cmdline from.
David Zeuthen73f2afa2017-05-17 16:54:11 -04003147 setup_as_rootfs_from_kernel: If True, generate dm-verity kernel
3148 cmdline to set up rootfs.
David Zeuthen21e95262016-07-27 17:58:40 -04003149 include_descriptors_from_image: List of file objects for which
3150 to insert descriptors from.
David Zeuthen09692692016-09-30 16:16:40 -04003151 calc_max_image_size: Don't store the hashtree or footer - instead
3152 calculate the maximum image size leaving enough room for hashtree
3153 and metadata with the given |partition_size|.
Dzmitry Yatsushkevich4e552792016-12-15 10:27:48 -08003154 signing_helper: Program which signs a hash and return signature.
David Zeuthena156d3d2017-06-01 12:08:09 -04003155 signing_helper_with_files: Same as signing_helper but uses files instead.
David Zeuthene3cadca2017-02-22 21:25:46 -05003156 release_string: None or avbtool release string.
3157 append_to_release_string: None or string to append.
David Zeuthend247fcb2017-02-16 12:09:27 -05003158 output_vbmeta_image: If not None, also write vbmeta struct to this file.
3159 do_not_append_vbmeta_image: If True, don't append vbmeta struct.
David Zeuthen1097a782017-05-31 15:53:17 -04003160 print_required_libavb_version: True to only print required libavb version.
Darren Krahnfd0ba0d2018-02-01 18:06:34 -08003161 use_persistent_root_digest: Use a persistent root digest on device.
3162 do_not_use_ab: The partition does not use A/B.
David Zeuthena4fee8b2016-08-22 15:20:43 -04003163
3164 Raises:
3165 AvbError: If an argument is incorrect.
David Zeuthen21e95262016-07-27 17:58:40 -04003166 """
David Zeuthen1097a782017-05-31 15:53:17 -04003167
Darren Krahnfd0ba0d2018-02-01 18:06:34 -08003168 required_libavb_version_minor = 0
3169 if use_persistent_root_digest or do_not_use_ab:
3170 required_libavb_version_minor = 1
3171
David Zeuthen1097a782017-05-31 15:53:17 -04003172 # If we're asked to calculate minimum required libavb version, we're done.
David Zeuthen1097a782017-05-31 15:53:17 -04003173 if print_required_libavb_version:
Darren Krahnfd0ba0d2018-02-01 18:06:34 -08003174 print '1.{}'.format(required_libavb_version_minor)
David Zeuthen1097a782017-05-31 15:53:17 -04003175 return
3176
David Zeuthen09692692016-09-30 16:16:40 -04003177 digest_size = len(hashlib.new(name=hash_algorithm).digest())
3178 digest_padding = round_to_pow2(digest_size) - digest_size
3179
3180 # First, calculate the maximum image size such that an image
3181 # this size + the hashtree + metadata (footer + vbmeta struct)
3182 # fits in |partition_size|. We use very conservative figures for
3183 # metadata.
3184 (_, max_tree_size) = calc_hash_level_offsets(
3185 partition_size, block_size, digest_size + digest_padding)
David Zeuthen0b7f1d32016-10-25 17:53:49 -04003186 max_fec_size = 0
3187 if generate_fec:
3188 max_fec_size = calc_fec_data_size(partition_size, fec_num_roots)
3189 max_metadata_size = (max_fec_size + max_tree_size +
3190 self.MAX_VBMETA_SIZE +
David Zeuthen09692692016-09-30 16:16:40 -04003191 self.MAX_FOOTER_SIZE)
3192 max_image_size = partition_size - max_metadata_size
3193
3194 # If we're asked to only calculate the maximum image size, we're done.
3195 if calc_max_image_size:
3196 print '{}'.format(max_image_size)
3197 return
3198
David Zeuthena4fee8b2016-08-22 15:20:43 -04003199 image = ImageHandler(image_filename)
3200
3201 if partition_size % image.block_size != 0:
3202 raise AvbError('Partition size of {} is not a multiple of the image '
3203 'block size {}.'.format(partition_size,
3204 image.block_size))
3205
David Zeuthen21e95262016-07-27 17:58:40 -04003206 # If there's already a footer, truncate the image to its original
3207 # size. This way 'avbtool add_hashtree_footer' is idempotent
3208 # (modulo salts).
Lonnie Liu6b5a33e2017-10-31 18:01:09 -07003209 if image.image_size >= AvbFooter.SIZE:
3210 image.seek(image.image_size - AvbFooter.SIZE)
3211 try:
3212 footer = AvbFooter(image.read(AvbFooter.SIZE))
3213 # Existing footer found. Just truncate.
3214 original_image_size = footer.original_image_size
3215 image.truncate(footer.original_image_size)
3216 except (LookupError, struct.error):
3217 original_image_size = image.image_size
3218 else:
3219 # Image size is too small to possibly contain a footer.
David Zeuthen09692692016-09-30 16:16:40 -04003220 original_image_size = image.image_size
David Zeuthen21e95262016-07-27 17:58:40 -04003221
3222 # If anything goes wrong from here-on, restore the image back to
3223 # its original size.
3224 try:
3225 # Ensure image is multiple of block_size.
David Zeuthen09692692016-09-30 16:16:40 -04003226 rounded_image_size = round_to_multiple(image.image_size, block_size)
3227 if rounded_image_size > image.image_size:
3228 image.append_raw('\0' * (rounded_image_size - image.image_size))
David Zeuthen21e95262016-07-27 17:58:40 -04003229
David Zeuthen09692692016-09-30 16:16:40 -04003230 # If image size exceeds the maximum image size, fail.
3231 if image.image_size > max_image_size:
3232 raise AvbError('Image size of {} exceeds maximum image '
3233 'size of {} in order to fit in a partition '
3234 'size of {}.'.format(image.image_size, max_image_size,
3235 partition_size))
David Zeuthen21e95262016-07-27 17:58:40 -04003236
3237 if salt:
3238 salt = salt.decode('hex')
3239 else:
3240 if salt is None:
3241 # If salt is not explicitly specified, choose a hash
3242 # that's the same size as the hash size.
3243 hash_size = digest_size
3244 salt = open('/dev/urandom').read(hash_size)
3245 else:
3246 salt = ''
3247
David Zeuthena4fee8b2016-08-22 15:20:43 -04003248 # Hashes are stored upside down so we need to calculate hash
David Zeuthen21e95262016-07-27 17:58:40 -04003249 # offsets in advance.
3250 (hash_level_offsets, tree_size) = calc_hash_level_offsets(
David Zeuthen09692692016-09-30 16:16:40 -04003251 image.image_size, block_size, digest_size + digest_padding)
David Zeuthen21e95262016-07-27 17:58:40 -04003252
David Zeuthena4fee8b2016-08-22 15:20:43 -04003253 # If the image isn't sparse, its size might not be a multiple of
3254 # the block size. This will screw up padding later so just grow it.
David Zeuthen09692692016-09-30 16:16:40 -04003255 if image.image_size % image.block_size != 0:
David Zeuthena4fee8b2016-08-22 15:20:43 -04003256 assert not image.is_sparse
David Zeuthen09692692016-09-30 16:16:40 -04003257 padding_needed = image.block_size - (image.image_size%image.block_size)
3258 image.truncate(image.image_size + padding_needed)
David Zeuthen21e95262016-07-27 17:58:40 -04003259
David Zeuthena4fee8b2016-08-22 15:20:43 -04003260 # Generate the tree and add padding as needed.
David Zeuthen09692692016-09-30 16:16:40 -04003261 tree_offset = image.image_size
3262 root_digest, hash_tree = generate_hash_tree(image, image.image_size,
David Zeuthena4fee8b2016-08-22 15:20:43 -04003263 block_size,
3264 hash_algorithm, salt,
3265 digest_padding,
3266 hash_level_offsets,
3267 tree_size)
David Zeuthena4fee8b2016-08-22 15:20:43 -04003268
3269 # Generate HashtreeDescriptor with details about the tree we
3270 # just generated.
David Zeuthen21e95262016-07-27 17:58:40 -04003271 ht_desc = AvbHashtreeDescriptor()
3272 ht_desc.dm_verity_version = 1
David Zeuthen09692692016-09-30 16:16:40 -04003273 ht_desc.image_size = image.image_size
David Zeuthen21e95262016-07-27 17:58:40 -04003274 ht_desc.tree_offset = tree_offset
3275 ht_desc.tree_size = tree_size
3276 ht_desc.data_block_size = block_size
3277 ht_desc.hash_block_size = block_size
3278 ht_desc.hash_algorithm = hash_algorithm
3279 ht_desc.partition_name = partition_name
3280 ht_desc.salt = salt
Darren Krahnfd0ba0d2018-02-01 18:06:34 -08003281 if do_not_use_ab:
3282 ht_desc.flags |= 1 # AVB_HASHTREE_DESCRIPTOR_FLAGS_DO_NOT_USE_AB
3283 if not use_persistent_root_digest:
3284 ht_desc.root_digest = root_digest
David Zeuthen21e95262016-07-27 17:58:40 -04003285
David Zeuthen09692692016-09-30 16:16:40 -04003286 # Write the hash tree
3287 padding_needed = (round_to_multiple(len(hash_tree), image.block_size) -
3288 len(hash_tree))
3289 hash_tree_with_padding = hash_tree + '\0'*padding_needed
3290 image.append_raw(hash_tree_with_padding)
David Zeuthen0b7f1d32016-10-25 17:53:49 -04003291 len_hashtree_and_fec = len(hash_tree_with_padding)
3292
3293 # Generate FEC codes, if requested.
3294 if generate_fec:
3295 fec_data = generate_fec_data(image_filename, fec_num_roots)
3296 padding_needed = (round_to_multiple(len(fec_data), image.block_size) -
3297 len(fec_data))
3298 fec_data_with_padding = fec_data + '\0'*padding_needed
3299 fec_offset = image.image_size
3300 image.append_raw(fec_data_with_padding)
3301 len_hashtree_and_fec += len(fec_data_with_padding)
3302 # Update the hashtree descriptor.
3303 ht_desc.fec_num_roots = fec_num_roots
3304 ht_desc.fec_offset = fec_offset
3305 ht_desc.fec_size = len(fec_data)
David Zeuthen09692692016-09-30 16:16:40 -04003306
David Zeuthen73f2afa2017-05-17 16:54:11 -04003307 ht_desc_to_setup = None
3308 if setup_as_rootfs_from_kernel:
3309 ht_desc_to_setup = ht_desc
3310
David Zeuthena4fee8b2016-08-22 15:20:43 -04003311 # Generate the VBMeta footer and add padding as needed.
David Zeuthen0b7f1d32016-10-25 17:53:49 -04003312 vbmeta_offset = tree_offset + len_hashtree_and_fec
David Zeuthen21e95262016-07-27 17:58:40 -04003313 vbmeta_blob = self._generate_vbmeta_blob(
David Zeuthen18666ab2016-11-15 11:18:05 -05003314 algorithm_name, key_path, public_key_metadata_path, [ht_desc],
David Zeuthena5fd3a42017-02-27 16:38:54 -05003315 chain_partitions, rollback_index, flags, props, props_from_file,
David Zeuthen73f2afa2017-05-17 16:54:11 -04003316 kernel_cmdlines, setup_rootfs_from_kernel, ht_desc_to_setup,
David Zeuthena156d3d2017-06-01 12:08:09 -04003317 include_descriptors_from_image, signing_helper,
3318 signing_helper_with_files, release_string,
Darren Krahnfd0ba0d2018-02-01 18:06:34 -08003319 append_to_release_string, required_libavb_version_minor)
David Zeuthena4fee8b2016-08-22 15:20:43 -04003320 padding_needed = (round_to_multiple(len(vbmeta_blob), image.block_size) -
3321 len(vbmeta_blob))
3322 vbmeta_blob_with_padding = vbmeta_blob + '\0'*padding_needed
David Zeuthen21e95262016-07-27 17:58:40 -04003323
David Zeuthend247fcb2017-02-16 12:09:27 -05003324 # Write vbmeta blob, if requested.
3325 if output_vbmeta_image:
3326 output_vbmeta_image.write(vbmeta_blob)
David Zeuthen21e95262016-07-27 17:58:40 -04003327
David Zeuthend247fcb2017-02-16 12:09:27 -05003328 # Append vbmeta blob and footer, unless requested not to.
3329 if not do_not_append_vbmeta_image:
3330 image.append_raw(vbmeta_blob_with_padding)
3331
3332 # Now insert a DONT_CARE chunk with enough bytes such that the
3333 # final Footer block is at the end of partition_size..
3334 image.append_dont_care(partition_size - image.image_size -
3335 1*image.block_size)
3336
3337 # Generate the Footer that tells where the VBMeta footer
3338 # is. Also put enough padding in the front of the footer since
3339 # we'll write out an entire block.
3340 footer = AvbFooter()
3341 footer.original_image_size = original_image_size
3342 footer.vbmeta_offset = vbmeta_offset
3343 footer.vbmeta_size = len(vbmeta_blob)
3344 footer_blob = footer.encode()
3345 footer_blob_with_padding = ('\0'*(image.block_size - AvbFooter.SIZE) +
3346 footer_blob)
3347 image.append_raw(footer_blob_with_padding)
David Zeuthena4fee8b2016-08-22 15:20:43 -04003348
David Zeuthen21e95262016-07-27 17:58:40 -04003349 except:
David Zeuthen09692692016-09-30 16:16:40 -04003350 # Truncate back to original size, then re-raise.
David Zeuthen21e95262016-07-27 17:58:40 -04003351 image.truncate(original_image_size)
3352 raise
3353
David Zeuthenc68f0822017-03-31 17:22:35 -04003354 def make_atx_certificate(self, output, authority_key_path, subject_key_path,
Darren Krahn147b08d2016-12-20 16:38:29 -08003355 subject_key_version, subject,
Darren Krahnfccd64e2018-01-16 17:39:35 -08003356 is_intermediate_authority, usage, signing_helper,
David Zeuthena156d3d2017-06-01 12:08:09 -04003357 signing_helper_with_files):
Darren Krahn147b08d2016-12-20 16:38:29 -08003358 """Implements the 'make_atx_certificate' command.
3359
3360 Android Things certificates are required for Android Things public key
3361 metadata. They chain the vbmeta signing key for a particular product back to
3362 a fused, permanent root key. These certificates are fixed-length and fixed-
3363 format with the explicit goal of not parsing ASN.1 in bootloader code.
3364
3365 Arguments:
3366 output: Certificate will be written to this file on success.
3367 authority_key_path: A PEM file path with the authority private key.
3368 If None, then a certificate will be created without a
3369 signature. The signature can be created out-of-band
3370 and appended.
David Zeuthenc68f0822017-03-31 17:22:35 -04003371 subject_key_path: Path to a PEM or DER subject public key.
Darren Krahn147b08d2016-12-20 16:38:29 -08003372 subject_key_version: A 64-bit version value. If this is None, the number
3373 of seconds since the epoch is used.
3374 subject: A subject identifier. For Product Signing Key certificates this
3375 should be the same Product ID found in the permanent attributes.
3376 is_intermediate_authority: True if the certificate is for an intermediate
3377 authority.
Darren Krahnfccd64e2018-01-16 17:39:35 -08003378 usage: If not empty, overrides the cert usage with a hash of this value.
Darren Krahn147b08d2016-12-20 16:38:29 -08003379 signing_helper: Program which signs a hash and returns the signature.
David Zeuthena156d3d2017-06-01 12:08:09 -04003380 signing_helper_with_files: Same as signing_helper but uses files instead.
Darren Krahn147b08d2016-12-20 16:38:29 -08003381 """
3382 signed_data = bytearray()
3383 signed_data.extend(struct.pack('<I', 1)) # Format Version
David Zeuthenc68f0822017-03-31 17:22:35 -04003384 signed_data.extend(encode_rsa_key(subject_key_path))
Darren Krahn147b08d2016-12-20 16:38:29 -08003385 hasher = hashlib.sha256()
3386 hasher.update(subject)
3387 signed_data.extend(hasher.digest())
Darren Krahnfccd64e2018-01-16 17:39:35 -08003388 if not usage:
3389 usage = 'com.google.android.things.vboot'
3390 if is_intermediate_authority:
3391 usage += '.ca'
Darren Krahn147b08d2016-12-20 16:38:29 -08003392 hasher = hashlib.sha256()
3393 hasher.update(usage)
3394 signed_data.extend(hasher.digest())
3395 if not subject_key_version:
3396 subject_key_version = int(time.time())
3397 signed_data.extend(struct.pack('<Q', subject_key_version))
3398 signature = bytearray()
3399 if authority_key_path:
3400 padding_and_hash = bytearray()
Darren Krahn43e12d82017-02-24 16:26:31 -08003401 algorithm_name = 'SHA512_RSA4096'
Esun Kimff44f232017-03-30 10:34:54 +09003402 alg = ALGORITHMS[algorithm_name]
Darren Krahn43e12d82017-02-24 16:26:31 -08003403 hasher = hashlib.sha512()
Esun Kimff44f232017-03-30 10:34:54 +09003404 padding_and_hash.extend(alg.padding)
Darren Krahn147b08d2016-12-20 16:38:29 -08003405 hasher.update(signed_data)
3406 padding_and_hash.extend(hasher.digest())
David Zeuthena156d3d2017-06-01 12:08:09 -04003407 signature.extend(raw_sign(signing_helper, signing_helper_with_files,
3408 algorithm_name,
Esun Kimff44f232017-03-30 10:34:54 +09003409 alg.signature_num_bytes, authority_key_path,
3410 padding_and_hash))
Darren Krahn147b08d2016-12-20 16:38:29 -08003411 output.write(signed_data)
3412 output.write(signature)
3413
David Zeuthenc68f0822017-03-31 17:22:35 -04003414 def make_atx_permanent_attributes(self, output, root_authority_key_path,
Darren Krahn147b08d2016-12-20 16:38:29 -08003415 product_id):
3416 """Implements the 'make_atx_permanent_attributes' command.
3417
3418 Android Things permanent attributes are designed to be permanent for a
3419 particular product and a hash of these attributes should be fused into
3420 hardware to enforce this.
3421
3422 Arguments:
3423 output: Attributes will be written to this file on success.
David Zeuthenc68f0822017-03-31 17:22:35 -04003424 root_authority_key_path: Path to a PEM or DER public key for
3425 the root authority.
Darren Krahn147b08d2016-12-20 16:38:29 -08003426 product_id: A 16-byte Product ID.
3427
3428 Raises:
3429 AvbError: If an argument is incorrect.
3430 """
Darren Krahn43e12d82017-02-24 16:26:31 -08003431 EXPECTED_PRODUCT_ID_SIZE = 16
3432 if len(product_id) != EXPECTED_PRODUCT_ID_SIZE:
Darren Krahn147b08d2016-12-20 16:38:29 -08003433 raise AvbError('Invalid Product ID length.')
3434 output.write(struct.pack('<I', 1)) # Format Version
David Zeuthenc68f0822017-03-31 17:22:35 -04003435 output.write(encode_rsa_key(root_authority_key_path))
Darren Krahn147b08d2016-12-20 16:38:29 -08003436 output.write(product_id)
3437
3438 def make_atx_metadata(self, output, intermediate_key_certificate,
Darren Krahn43e12d82017-02-24 16:26:31 -08003439 product_key_certificate):
Darren Krahn147b08d2016-12-20 16:38:29 -08003440 """Implements the 'make_atx_metadata' command.
3441
3442 Android Things metadata are included in vbmeta images to facilitate
3443 verification. The output of this command can be used as the
3444 public_key_metadata argument to other commands.
3445
3446 Arguments:
3447 output: Metadata will be written to this file on success.
3448 intermediate_key_certificate: A certificate file as output by
3449 make_atx_certificate with
3450 is_intermediate_authority set to true.
3451 product_key_certificate: A certificate file as output by
3452 make_atx_certificate with
3453 is_intermediate_authority set to false.
Darren Krahn147b08d2016-12-20 16:38:29 -08003454
3455 Raises:
3456 AvbError: If an argument is incorrect.
3457 """
Darren Krahn43e12d82017-02-24 16:26:31 -08003458 EXPECTED_CERTIFICATE_SIZE = 1620
3459 if len(intermediate_key_certificate) != EXPECTED_CERTIFICATE_SIZE:
Darren Krahn147b08d2016-12-20 16:38:29 -08003460 raise AvbError('Invalid intermediate key certificate length.')
Darren Krahn43e12d82017-02-24 16:26:31 -08003461 if len(product_key_certificate) != EXPECTED_CERTIFICATE_SIZE:
Darren Krahn147b08d2016-12-20 16:38:29 -08003462 raise AvbError('Invalid product key certificate length.')
3463 output.write(struct.pack('<I', 1)) # Format Version
3464 output.write(intermediate_key_certificate)
3465 output.write(product_key_certificate)
Darren Krahn147b08d2016-12-20 16:38:29 -08003466
Darren Krahnfccd64e2018-01-16 17:39:35 -08003467 def make_atx_unlock_credential(self, output, intermediate_key_certificate,
3468 unlock_key_certificate, challenge_path,
3469 unlock_key_path, signing_helper,
3470 signing_helper_with_files):
3471 """Implements the 'make_atx_unlock_credential' command.
3472
3473 Android Things unlock credentials can be used to authorize the unlock of AVB
3474 on a device. These credentials are presented to an Android Things bootloader
3475 via the fastboot interface in response to a 16-byte challenge. This method
3476 creates all fields of the credential except the challenge signature field
3477 (which is the last field) and can optionally create the challenge signature
3478 field as well if a challenge and the unlock_key_path is provided.
3479
3480 Arguments:
3481 output: The credential will be written to this file on success.
3482 intermediate_key_certificate: A certificate file as output by
3483 make_atx_certificate with
3484 is_intermediate_authority set to true.
3485 unlock_key_certificate: A certificate file as output by
3486 make_atx_certificate with
3487 is_intermediate_authority set to false and the
3488 usage set to
3489 'com.google.android.things.vboot.unlock'.
3490 challenge_path: [optional] A path to the challenge to sign.
3491 unlock_key_path: [optional] A PEM file path with the unlock private key.
3492 signing_helper: Program which signs a hash and returns the signature.
3493 signing_helper_with_files: Same as signing_helper but uses files instead.
3494
3495 Raises:
3496 AvbError: If an argument is incorrect.
3497 """
3498 EXPECTED_CERTIFICATE_SIZE = 1620
3499 EXPECTED_CHALLENGE_SIZE = 16
3500 if len(intermediate_key_certificate) != EXPECTED_CERTIFICATE_SIZE:
3501 raise AvbError('Invalid intermediate key certificate length.')
3502 if len(unlock_key_certificate) != EXPECTED_CERTIFICATE_SIZE:
3503 raise AvbError('Invalid product key certificate length.')
3504 challenge = bytearray()
3505 if challenge_path:
3506 with open(challenge_path, 'r') as f:
3507 challenge = f.read()
3508 if len(challenge) != EXPECTED_CHALLENGE_SIZE:
3509 raise AvbError('Invalid unlock challenge length.')
3510 output.write(struct.pack('<I', 1)) # Format Version
3511 output.write(intermediate_key_certificate)
3512 output.write(unlock_key_certificate)
3513 if challenge_path and unlock_key_path:
3514 signature = bytearray()
3515 padding_and_hash = bytearray()
3516 algorithm_name = 'SHA512_RSA4096'
3517 alg = ALGORITHMS[algorithm_name]
3518 hasher = hashlib.sha512()
3519 padding_and_hash.extend(alg.padding)
3520 hasher.update(challenge)
3521 padding_and_hash.extend(hasher.digest())
3522 signature.extend(raw_sign(signing_helper, signing_helper_with_files,
3523 algorithm_name,
3524 alg.signature_num_bytes, unlock_key_path,
3525 padding_and_hash))
3526 output.write(signature)
3527
David Zeuthen21e95262016-07-27 17:58:40 -04003528
3529def calc_hash_level_offsets(image_size, block_size, digest_size):
3530 """Calculate the offsets of all the hash-levels in a Merkle-tree.
3531
3532 Arguments:
3533 image_size: The size of the image to calculate a Merkle-tree for.
3534 block_size: The block size, e.g. 4096.
3535 digest_size: The size of each hash, e.g. 32 for SHA-256.
3536
3537 Returns:
3538 A tuple where the first argument is an array of offsets and the
3539 second is size of the tree, in bytes.
3540 """
3541 level_offsets = []
3542 level_sizes = []
3543 tree_size = 0
3544
3545 num_levels = 0
3546 size = image_size
3547 while size > block_size:
3548 num_blocks = (size + block_size - 1) / block_size
3549 level_size = round_to_multiple(num_blocks * digest_size, block_size)
3550
3551 level_sizes.append(level_size)
3552 tree_size += level_size
3553 num_levels += 1
3554
3555 size = level_size
3556
3557 for n in range(0, num_levels):
3558 offset = 0
3559 for m in range(n + 1, num_levels):
3560 offset += level_sizes[m]
3561 level_offsets.append(offset)
3562
David Zeuthena4fee8b2016-08-22 15:20:43 -04003563 return level_offsets, tree_size
David Zeuthen21e95262016-07-27 17:58:40 -04003564
3565
David Zeuthen0b7f1d32016-10-25 17:53:49 -04003566# See system/extras/libfec/include/fec/io.h for these definitions.
3567FEC_FOOTER_FORMAT = '<LLLLLQ32s'
3568FEC_MAGIC = 0xfecfecfe
3569
3570
3571def calc_fec_data_size(image_size, num_roots):
3572 """Calculates how much space FEC data will take.
3573
3574 Args:
3575 image_size: The size of the image.
3576 num_roots: Number of roots.
3577
3578 Returns:
3579 The number of bytes needed for FEC for an image of the given size
3580 and with the requested number of FEC roots.
3581
3582 Raises:
3583 ValueError: If output from the 'fec' tool is invalid.
3584
3585 """
3586 p = subprocess.Popen(
3587 ['fec', '--print-fec-size', str(image_size), '--roots', str(num_roots)],
3588 stdout=subprocess.PIPE,
3589 stderr=subprocess.PIPE)
3590 (pout, perr) = p.communicate()
3591 retcode = p.wait()
3592 if retcode != 0:
3593 raise ValueError('Error invoking fec: {}'.format(perr))
3594 return int(pout)
3595
3596
3597def generate_fec_data(image_filename, num_roots):
3598 """Generate FEC codes for an image.
3599
3600 Args:
3601 image_filename: The filename of the image.
3602 num_roots: Number of roots.
3603
3604 Returns:
3605 The FEC data blob.
3606
3607 Raises:
3608 ValueError: If output from the 'fec' tool is invalid.
3609 """
3610 fec_tmpfile = tempfile.NamedTemporaryFile()
3611 subprocess.check_call(
3612 ['fec', '--encode', '--roots', str(num_roots), image_filename,
3613 fec_tmpfile.name],
3614 stderr=open(os.devnull))
3615 fec_data = fec_tmpfile.read()
3616 footer_size = struct.calcsize(FEC_FOOTER_FORMAT)
3617 footer_data = fec_data[-footer_size:]
3618 (magic, _, _, num_roots, fec_size, _, _) = struct.unpack(FEC_FOOTER_FORMAT,
3619 footer_data)
3620 if magic != FEC_MAGIC:
3621 raise ValueError('Unexpected magic in FEC footer')
3622 return fec_data[0:fec_size]
3623
3624
David Zeuthen21e95262016-07-27 17:58:40 -04003625def generate_hash_tree(image, image_size, block_size, hash_alg_name, salt,
David Zeuthena4fee8b2016-08-22 15:20:43 -04003626 digest_padding, hash_level_offsets, tree_size):
David Zeuthen21e95262016-07-27 17:58:40 -04003627 """Generates a Merkle-tree for a file.
3628
3629 Args:
3630 image: The image, as a file.
3631 image_size: The size of the image.
3632 block_size: The block size, e.g. 4096.
3633 hash_alg_name: The hash algorithm, e.g. 'sha256' or 'sha1'.
3634 salt: The salt to use.
3635 digest_padding: The padding for each digest.
David Zeuthen21e95262016-07-27 17:58:40 -04003636 hash_level_offsets: The offsets from calc_hash_level_offsets().
David Zeuthena4fee8b2016-08-22 15:20:43 -04003637 tree_size: The size of the tree, in number of bytes.
David Zeuthen21e95262016-07-27 17:58:40 -04003638
3639 Returns:
David Zeuthena4fee8b2016-08-22 15:20:43 -04003640 A tuple where the first element is the top-level hash and the
3641 second element is the hash-tree.
David Zeuthen21e95262016-07-27 17:58:40 -04003642 """
David Zeuthena4fee8b2016-08-22 15:20:43 -04003643 hash_ret = bytearray(tree_size)
David Zeuthen21e95262016-07-27 17:58:40 -04003644 hash_src_offset = 0
3645 hash_src_size = image_size
3646 level_num = 0
3647 while hash_src_size > block_size:
3648 level_output = ''
David Zeuthen21e95262016-07-27 17:58:40 -04003649 remaining = hash_src_size
3650 while remaining > 0:
3651 hasher = hashlib.new(name=hash_alg_name, string=salt)
David Zeuthena4fee8b2016-08-22 15:20:43 -04003652 # Only read from the file for the first level - for subsequent
3653 # levels, access the array we're building.
3654 if level_num == 0:
3655 image.seek(hash_src_offset + hash_src_size - remaining)
3656 data = image.read(min(remaining, block_size))
3657 else:
3658 offset = hash_level_offsets[level_num - 1] + hash_src_size - remaining
3659 data = hash_ret[offset:offset + block_size]
David Zeuthen21e95262016-07-27 17:58:40 -04003660 hasher.update(data)
David Zeuthena4fee8b2016-08-22 15:20:43 -04003661
3662 remaining -= len(data)
David Zeuthen21e95262016-07-27 17:58:40 -04003663 if len(data) < block_size:
3664 hasher.update('\0' * (block_size - len(data)))
3665 level_output += hasher.digest()
3666 if digest_padding > 0:
3667 level_output += '\0' * digest_padding
3668
3669 padding_needed = (round_to_multiple(
3670 len(level_output), block_size) - len(level_output))
3671 level_output += '\0' * padding_needed
3672
David Zeuthena4fee8b2016-08-22 15:20:43 -04003673 # Copy level-output into resulting tree.
3674 offset = hash_level_offsets[level_num]
3675 hash_ret[offset:offset + len(level_output)] = level_output
David Zeuthen21e95262016-07-27 17:58:40 -04003676
David Zeuthena4fee8b2016-08-22 15:20:43 -04003677 # Continue on to the next level.
David Zeuthen21e95262016-07-27 17:58:40 -04003678 hash_src_size = len(level_output)
David Zeuthen21e95262016-07-27 17:58:40 -04003679 level_num += 1
3680
3681 hasher = hashlib.new(name=hash_alg_name, string=salt)
3682 hasher.update(level_output)
David Zeuthena4fee8b2016-08-22 15:20:43 -04003683 return hasher.digest(), hash_ret
David Zeuthen21e95262016-07-27 17:58:40 -04003684
3685
3686class AvbTool(object):
3687 """Object for avbtool command-line tool."""
3688
3689 def __init__(self):
3690 """Initializer method."""
3691 self.avb = Avb()
3692
3693 def _add_common_args(self, sub_parser):
3694 """Adds arguments used by several sub-commands.
3695
3696 Arguments:
3697 sub_parser: The parser to add arguments to.
3698 """
3699 sub_parser.add_argument('--algorithm',
3700 help='Algorithm to use (default: NONE)',
3701 metavar='ALGORITHM',
3702 default='NONE')
3703 sub_parser.add_argument('--key',
3704 help='Path to RSA private key file',
3705 metavar='KEY',
3706 required=False)
Dzmitry Yatsushkevich4e552792016-12-15 10:27:48 -08003707 sub_parser.add_argument('--signing_helper',
3708 help='Path to helper used for signing',
3709 metavar='APP',
3710 default=None,
3711 required=False)
David Zeuthena156d3d2017-06-01 12:08:09 -04003712 sub_parser.add_argument('--signing_helper_with_files',
3713 help='Path to helper used for signing using files',
3714 metavar='APP',
3715 default=None,
3716 required=False)
David Zeuthen18666ab2016-11-15 11:18:05 -05003717 sub_parser.add_argument('--public_key_metadata',
3718 help='Path to public key metadata file',
3719 metavar='KEY_METADATA',
3720 required=False)
David Zeuthen21e95262016-07-27 17:58:40 -04003721 sub_parser.add_argument('--rollback_index',
3722 help='Rollback Index',
3723 type=parse_number,
3724 default=0)
David Zeuthene3cadca2017-02-22 21:25:46 -05003725 # This is used internally for unit tests. Do not include in --help output.
3726 sub_parser.add_argument('--internal_release_string',
3727 help=argparse.SUPPRESS)
3728 sub_parser.add_argument('--append_to_release_string',
3729 help='Text to append to release string',
3730 metavar='STR')
David Zeuthen21e95262016-07-27 17:58:40 -04003731 sub_parser.add_argument('--prop',
3732 help='Add property',
3733 metavar='KEY:VALUE',
3734 action='append')
3735 sub_parser.add_argument('--prop_from_file',
3736 help='Add property from file',
3737 metavar='KEY:PATH',
3738 action='append')
3739 sub_parser.add_argument('--kernel_cmdline',
3740 help='Add kernel cmdline',
3741 metavar='CMDLINE',
3742 action='append')
David Zeuthen5d4f4f22017-01-11 11:37:34 -05003743 # TODO(zeuthen): the --setup_rootfs_from_kernel option used to be called
3744 # --generate_dm_verity_cmdline_from_hashtree. Remove support for the latter
3745 # at some future point.
3746 sub_parser.add_argument('--setup_rootfs_from_kernel',
3747 '--generate_dm_verity_cmdline_from_hashtree',
David Zeuthen21e95262016-07-27 17:58:40 -04003748 metavar='IMAGE',
David Zeuthen5d4f4f22017-01-11 11:37:34 -05003749 help='Adds kernel cmdline to set up IMAGE',
David Zeuthen21e95262016-07-27 17:58:40 -04003750 type=argparse.FileType('rb'))
3751 sub_parser.add_argument('--include_descriptors_from_image',
3752 help='Include descriptors from image',
3753 metavar='IMAGE',
3754 action='append',
3755 type=argparse.FileType('rb'))
David Zeuthen1097a782017-05-31 15:53:17 -04003756 sub_parser.add_argument('--print_required_libavb_version',
3757 help=('Don\'t store the footer - '
3758 'instead calculate the required libavb '
3759 'version for the given options.'),
3760 action='store_true')
David Zeuthena5fd3a42017-02-27 16:38:54 -05003761 # These are only allowed from top-level vbmeta and boot-in-lieu-of-vbmeta.
3762 sub_parser.add_argument('--chain_partition',
3763 help='Allow signed integrity-data for partition',
3764 metavar='PART_NAME:ROLLBACK_SLOT:KEY_PATH',
3765 action='append')
3766 sub_parser.add_argument('--flags',
3767 help='VBMeta flags',
3768 type=parse_number,
3769 default=0)
3770 sub_parser.add_argument('--set_hashtree_disabled_flag',
3771 help='Set the HASHTREE_DISABLED flag',
3772 action='store_true')
3773
Darren Krahnfd0ba0d2018-02-01 18:06:34 -08003774 def _add_common_footer_args(self, sub_parser):
3775 """Adds arguments used by add_*_footer sub-commands.
3776
3777 Arguments:
3778 sub_parser: The parser to add arguments to.
3779 """
3780 sub_parser.add_argument('--use_persistent_digest',
3781 help='Use a persistent digest on device instead of '
3782 'storing the digest in the descriptor. This '
3783 'cannot be used with A/B so must be combined '
3784 'with --do_not_use_ab when an A/B suffix is '
3785 'expected at runtime.',
3786 action='store_true')
3787 sub_parser.add_argument('--do_not_use_ab',
3788 help='The partition does not use A/B even when an '
3789 'A/B suffix is present. This must not be used '
3790 'for vbmeta or chained partitions.',
3791 action='store_true')
3792
David Zeuthena5fd3a42017-02-27 16:38:54 -05003793 def _fixup_common_args(self, args):
3794 """Common fixups needed by subcommands.
3795
3796 Arguments:
3797 args: Arguments to modify.
3798
3799 Returns:
3800 The modified arguments.
3801 """
3802 if args.set_hashtree_disabled_flag:
3803 args.flags |= AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED
3804 return args
David Zeuthen21e95262016-07-27 17:58:40 -04003805
3806 def run(self, argv):
3807 """Command-line processor.
3808
3809 Arguments:
3810 argv: Pass sys.argv from main.
3811 """
3812 parser = argparse.ArgumentParser()
3813 subparsers = parser.add_subparsers(title='subcommands')
3814
3815 sub_parser = subparsers.add_parser('version',
3816 help='Prints version of avbtool.')
3817 sub_parser.set_defaults(func=self.version)
3818
3819 sub_parser = subparsers.add_parser('extract_public_key',
3820 help='Extract public key.')
3821 sub_parser.add_argument('--key',
3822 help='Path to RSA private key file',
3823 required=True)
3824 sub_parser.add_argument('--output',
3825 help='Output file name',
3826 type=argparse.FileType('wb'),
3827 required=True)
3828 sub_parser.set_defaults(func=self.extract_public_key)
3829
3830 sub_parser = subparsers.add_parser('make_vbmeta_image',
3831 help='Makes a vbmeta image.')
3832 sub_parser.add_argument('--output',
3833 help='Output file name',
David Zeuthen1097a782017-05-31 15:53:17 -04003834 type=argparse.FileType('wb'))
David Zeuthen97cb5802017-06-01 16:14:05 -04003835 sub_parser.add_argument('--padding_size',
3836 metavar='NUMBER',
3837 help='If non-zero, pads output with NUL bytes so '
3838 'its size is a multiple of NUMBER (default: 0)',
3839 type=parse_number,
3840 default=0)
David Zeuthen21e95262016-07-27 17:58:40 -04003841 self._add_common_args(sub_parser)
David Zeuthen21e95262016-07-27 17:58:40 -04003842 sub_parser.set_defaults(func=self.make_vbmeta_image)
3843
3844 sub_parser = subparsers.add_parser('add_hash_footer',
3845 help='Add hashes and footer to image.')
3846 sub_parser.add_argument('--image',
David Zeuthen8b6973b2016-09-20 12:39:49 -04003847 help='Image to add hashes to',
David Zeuthen21e95262016-07-27 17:58:40 -04003848 type=argparse.FileType('rab+'))
3849 sub_parser.add_argument('--partition_size',
3850 help='Partition size',
David Zeuthen1097a782017-05-31 15:53:17 -04003851 type=parse_number)
David Zeuthen21e95262016-07-27 17:58:40 -04003852 sub_parser.add_argument('--partition_name',
3853 help='Partition name',
David Zeuthenbf562452017-05-17 18:04:43 -04003854 default=None)
David Zeuthen21e95262016-07-27 17:58:40 -04003855 sub_parser.add_argument('--hash_algorithm',
3856 help='Hash algorithm to use (default: sha256)',
3857 default='sha256')
3858 sub_parser.add_argument('--salt',
3859 help='Salt in hex (default: /dev/urandom)')
David Zeuthenbf562452017-05-17 18:04:43 -04003860 sub_parser.add_argument('--calc_max_image_size',
3861 help=('Don\'t store the footer - '
3862 'instead calculate the maximum image size '
3863 'leaving enough room for metadata with '
3864 'the given partition size.'),
3865 action='store_true')
David Zeuthend247fcb2017-02-16 12:09:27 -05003866 sub_parser.add_argument('--output_vbmeta_image',
3867 help='Also write vbmeta struct to file',
3868 type=argparse.FileType('wb'))
3869 sub_parser.add_argument('--do_not_append_vbmeta_image',
3870 help=('Do not append vbmeta struct or footer '
3871 'to the image'),
3872 action='store_true')
David Zeuthen21e95262016-07-27 17:58:40 -04003873 self._add_common_args(sub_parser)
Darren Krahnfd0ba0d2018-02-01 18:06:34 -08003874 self._add_common_footer_args(sub_parser)
David Zeuthen21e95262016-07-27 17:58:40 -04003875 sub_parser.set_defaults(func=self.add_hash_footer)
3876
David Zeuthenb1b994d2017-03-06 18:01:31 -05003877 sub_parser = subparsers.add_parser('append_vbmeta_image',
3878 help='Append vbmeta image to image.')
3879 sub_parser.add_argument('--image',
3880 help='Image to append vbmeta blob to',
3881 type=argparse.FileType('rab+'))
3882 sub_parser.add_argument('--partition_size',
3883 help='Partition size',
3884 type=parse_number,
3885 required=True)
3886 sub_parser.add_argument('--vbmeta_image',
3887 help='Image with vbmeta blob to append',
3888 type=argparse.FileType('rb'))
3889 sub_parser.set_defaults(func=self.append_vbmeta_image)
3890
David Zeuthen21e95262016-07-27 17:58:40 -04003891 sub_parser = subparsers.add_parser('add_hashtree_footer',
3892 help='Add hashtree and footer to image.')
3893 sub_parser.add_argument('--image',
David Zeuthen8b6973b2016-09-20 12:39:49 -04003894 help='Image to add hashtree to',
David Zeuthen21e95262016-07-27 17:58:40 -04003895 type=argparse.FileType('rab+'))
3896 sub_parser.add_argument('--partition_size',
3897 help='Partition size',
David Zeuthen1097a782017-05-31 15:53:17 -04003898 type=parse_number)
David Zeuthen21e95262016-07-27 17:58:40 -04003899 sub_parser.add_argument('--partition_name',
3900 help='Partition name',
David Zeuthen09692692016-09-30 16:16:40 -04003901 default=None)
David Zeuthen21e95262016-07-27 17:58:40 -04003902 sub_parser.add_argument('--hash_algorithm',
3903 help='Hash algorithm to use (default: sha1)',
3904 default='sha1')
3905 sub_parser.add_argument('--salt',
3906 help='Salt in hex (default: /dev/urandom)')
3907 sub_parser.add_argument('--block_size',
3908 help='Block size (default: 4096)',
3909 type=parse_number,
3910 default=4096)
David Zeuthenbce9a292017-05-10 17:18:04 -04003911 # TODO(zeuthen): The --generate_fec option was removed when we
3912 # moved to generating FEC by default. To avoid breaking existing
3913 # users needing to transition we simply just print a warning below
3914 # in add_hashtree_footer(). Remove this option and the warning at
3915 # some point in the future.
David Zeuthen0b7f1d32016-10-25 17:53:49 -04003916 sub_parser.add_argument('--generate_fec',
David Zeuthenbce9a292017-05-10 17:18:04 -04003917 help=argparse.SUPPRESS,
3918 action='store_true')
3919 sub_parser.add_argument('--do_not_generate_fec',
3920 help='Do not generate forward-error-correction codes',
David Zeuthen0b7f1d32016-10-25 17:53:49 -04003921 action='store_true')
3922 sub_parser.add_argument('--fec_num_roots',
3923 help='Number of roots for FEC (default: 2)',
3924 type=parse_number,
3925 default=2)
David Zeuthen09692692016-09-30 16:16:40 -04003926 sub_parser.add_argument('--calc_max_image_size',
3927 help=('Don\'t store the hashtree or footer - '
3928 'instead calculate the maximum image size '
3929 'leaving enough room for hashtree '
3930 'and metadata with the given partition '
3931 'size.'),
3932 action='store_true')
David Zeuthend247fcb2017-02-16 12:09:27 -05003933 sub_parser.add_argument('--output_vbmeta_image',
3934 help='Also write vbmeta struct to file',
3935 type=argparse.FileType('wb'))
3936 sub_parser.add_argument('--do_not_append_vbmeta_image',
3937 help=('Do not append vbmeta struct or footer '
3938 'to the image'),
3939 action='store_true')
David Zeuthen73f2afa2017-05-17 16:54:11 -04003940 # This is different from --setup_rootfs_from_kernel insofar that
3941 # it doesn't take an IMAGE, the generated cmdline will be for the
3942 # hashtree we're adding.
3943 sub_parser.add_argument('--setup_as_rootfs_from_kernel',
3944 action='store_true',
3945 help='Adds kernel cmdline for setting up rootfs')
David Zeuthen21e95262016-07-27 17:58:40 -04003946 self._add_common_args(sub_parser)
Darren Krahnfd0ba0d2018-02-01 18:06:34 -08003947 self._add_common_footer_args(sub_parser)
David Zeuthen21e95262016-07-27 17:58:40 -04003948 sub_parser.set_defaults(func=self.add_hashtree_footer)
3949
3950 sub_parser = subparsers.add_parser('erase_footer',
3951 help='Erase footer from an image.')
3952 sub_parser.add_argument('--image',
David Zeuthen8b6973b2016-09-20 12:39:49 -04003953 help='Image with a footer',
David Zeuthen21e95262016-07-27 17:58:40 -04003954 type=argparse.FileType('rwb+'),
3955 required=True)
3956 sub_parser.add_argument('--keep_hashtree',
David Zeuthenfbb61fa2017-02-02 12:11:49 -05003957 help='Keep the hashtree and FEC in the image',
David Zeuthen21e95262016-07-27 17:58:40 -04003958 action='store_true')
3959 sub_parser.set_defaults(func=self.erase_footer)
3960
David Zeuthen49936b42018-08-07 17:38:58 -04003961 sub_parser = subparsers.add_parser('extract_vbmeta_image',
3962 help='Extracts vbmeta from an image with a footer.')
3963 sub_parser.add_argument('--image',
3964 help='Image with footer',
3965 type=argparse.FileType('rb'),
3966 required=True)
3967 sub_parser.add_argument('--output',
3968 help='Output file name',
3969 type=argparse.FileType('wb'))
3970 sub_parser.add_argument('--padding_size',
3971 metavar='NUMBER',
3972 help='If non-zero, pads output with NUL bytes so '
3973 'its size is a multiple of NUMBER (default: 0)',
3974 type=parse_number,
3975 default=0)
3976 sub_parser.set_defaults(func=self.extract_vbmeta_image)
3977
David Zeuthen2bc232b2017-04-19 14:25:19 -04003978 sub_parser = subparsers.add_parser('resize_image',
3979 help='Resize image with a footer.')
3980 sub_parser.add_argument('--image',
3981 help='Image with a footer',
3982 type=argparse.FileType('rwb+'),
3983 required=True)
3984 sub_parser.add_argument('--partition_size',
3985 help='New partition size',
3986 type=parse_number)
3987 sub_parser.set_defaults(func=self.resize_image)
3988
David Zeuthen21e95262016-07-27 17:58:40 -04003989 sub_parser = subparsers.add_parser(
3990 'info_image',
3991 help='Show information about vbmeta or footer.')
3992 sub_parser.add_argument('--image',
David Zeuthen8b6973b2016-09-20 12:39:49 -04003993 help='Image to show information about',
David Zeuthen21e95262016-07-27 17:58:40 -04003994 type=argparse.FileType('rb'),
3995 required=True)
3996 sub_parser.add_argument('--output',
3997 help='Write info to file',
3998 type=argparse.FileType('wt'),
3999 default=sys.stdout)
4000 sub_parser.set_defaults(func=self.info_image)
4001
David Zeuthenb623d8b2017-04-04 16:05:53 -04004002 sub_parser = subparsers.add_parser(
4003 'verify_image',
4004 help='Verify an image.')
4005 sub_parser.add_argument('--image',
4006 help='Image to verify',
4007 type=argparse.FileType('rb'),
4008 required=True)
David Zeuthen5dfb4e92017-05-24 14:49:32 -04004009 sub_parser.add_argument('--key',
4010 help='Check embedded public key matches KEY',
4011 metavar='KEY',
4012 required=False)
4013 sub_parser.add_argument('--expected_chain_partition',
4014 help='Expected chain partition',
4015 metavar='PART_NAME:ROLLBACK_SLOT:KEY_PATH',
4016 action='append')
David Zeuthenb623d8b2017-04-04 16:05:53 -04004017 sub_parser.set_defaults(func=self.verify_image)
4018
David Zeuthenb8643c02018-05-17 17:21:18 -04004019 sub_parser = subparsers.add_parser(
4020 'calculate_vbmeta_digest',
4021 help='Calculate vbmeta digest.')
4022 sub_parser.add_argument('--image',
4023 help='Image to calculate digest for',
4024 type=argparse.FileType('rb'),
4025 required=True)
4026 sub_parser.add_argument('--hash_algorithm',
4027 help='Hash algorithm to use (default: sha256)',
4028 default='sha256')
4029 sub_parser.add_argument('--output',
4030 help='Write hex digest to file (default: stdout)',
4031 type=argparse.FileType('wt'),
4032 default=sys.stdout)
4033 sub_parser.set_defaults(func=self.calculate_vbmeta_digest)
4034
David Zeuthenf7d2e752018-09-20 13:30:41 -04004035 sub_parser = subparsers.add_parser(
4036 'calculate_kernel_cmdline',
4037 help='Calculate kernel cmdline.')
4038 sub_parser.add_argument('--image',
4039 help='Image to calculate kernel cmdline for',
4040 type=argparse.FileType('rb'),
4041 required=True)
4042 sub_parser.add_argument('--hashtree_disabled',
4043 help='Return the cmdline for hashtree disabled',
4044 action='store_true')
4045 sub_parser.add_argument('--output',
4046 help='Write cmdline to file (default: stdout)',
4047 type=argparse.FileType('wt'),
4048 default=sys.stdout)
4049 sub_parser.set_defaults(func=self.calculate_kernel_cmdline)
4050
David Zeuthen8b6973b2016-09-20 12:39:49 -04004051 sub_parser = subparsers.add_parser('set_ab_metadata',
4052 help='Set A/B metadata.')
4053 sub_parser.add_argument('--misc_image',
4054 help=('The misc image to modify. If the image does '
4055 'not exist, it will be created.'),
4056 type=argparse.FileType('r+b'),
4057 required=True)
4058 sub_parser.add_argument('--slot_data',
4059 help=('Slot data of the form "priority", '
4060 '"tries_remaining", "sucessful_boot" for '
4061 'slot A followed by the same for slot B, '
4062 'separated by colons. The default value '
4063 'is 15:7:0:14:7:0.'),
4064 default='15:7:0:14:7:0')
4065 sub_parser.set_defaults(func=self.set_ab_metadata)
4066
Darren Krahn147b08d2016-12-20 16:38:29 -08004067 sub_parser = subparsers.add_parser(
4068 'make_atx_certificate',
4069 help='Create an Android Things eXtension (ATX) certificate.')
4070 sub_parser.add_argument('--output',
4071 help='Write certificate to file',
4072 type=argparse.FileType('wb'),
4073 default=sys.stdout)
4074 sub_parser.add_argument('--subject',
4075 help=('Path to subject file'),
4076 type=argparse.FileType('rb'),
4077 required=True)
4078 sub_parser.add_argument('--subject_key',
4079 help=('Path to subject RSA public key file'),
4080 type=argparse.FileType('rb'),
4081 required=True)
4082 sub_parser.add_argument('--subject_key_version',
4083 help=('Version of the subject key'),
4084 type=parse_number,
4085 required=False)
4086 sub_parser.add_argument('--subject_is_intermediate_authority',
4087 help=('Generate an intermediate authority '
4088 'certificate'),
4089 action='store_true')
Darren Krahnfccd64e2018-01-16 17:39:35 -08004090 sub_parser.add_argument('--usage',
Darren Krahn2367b462018-06-19 00:53:32 -07004091 help=('Override usage with a hash of the provided '
Darren Krahnfccd64e2018-01-16 17:39:35 -08004092 'string'),
4093 required=False)
Darren Krahn147b08d2016-12-20 16:38:29 -08004094 sub_parser.add_argument('--authority_key',
4095 help='Path to authority RSA private key file',
4096 required=False)
4097 sub_parser.add_argument('--signing_helper',
4098 help='Path to helper used for signing',
4099 metavar='APP',
4100 default=None,
4101 required=False)
David Zeuthena156d3d2017-06-01 12:08:09 -04004102 sub_parser.add_argument('--signing_helper_with_files',
4103 help='Path to helper used for signing using files',
4104 metavar='APP',
4105 default=None,
4106 required=False)
Darren Krahn147b08d2016-12-20 16:38:29 -08004107 sub_parser.set_defaults(func=self.make_atx_certificate)
4108
4109 sub_parser = subparsers.add_parser(
4110 'make_atx_permanent_attributes',
4111 help='Create Android Things eXtension (ATX) permanent attributes.')
4112 sub_parser.add_argument('--output',
4113 help='Write attributes to file',
4114 type=argparse.FileType('wb'),
4115 default=sys.stdout)
4116 sub_parser.add_argument('--root_authority_key',
4117 help='Path to authority RSA public key file',
4118 type=argparse.FileType('rb'),
4119 required=True)
4120 sub_parser.add_argument('--product_id',
4121 help=('Path to Product ID file'),
4122 type=argparse.FileType('rb'),
4123 required=True)
4124 sub_parser.set_defaults(func=self.make_atx_permanent_attributes)
4125
4126 sub_parser = subparsers.add_parser(
4127 'make_atx_metadata',
4128 help='Create Android Things eXtension (ATX) metadata.')
4129 sub_parser.add_argument('--output',
4130 help='Write metadata to file',
4131 type=argparse.FileType('wb'),
4132 default=sys.stdout)
4133 sub_parser.add_argument('--intermediate_key_certificate',
4134 help='Path to intermediate key certificate file',
4135 type=argparse.FileType('rb'),
4136 required=True)
4137 sub_parser.add_argument('--product_key_certificate',
4138 help='Path to product key certificate file',
4139 type=argparse.FileType('rb'),
4140 required=True)
Darren Krahn147b08d2016-12-20 16:38:29 -08004141 sub_parser.set_defaults(func=self.make_atx_metadata)
4142
Darren Krahnfccd64e2018-01-16 17:39:35 -08004143 sub_parser = subparsers.add_parser(
4144 'make_atx_unlock_credential',
4145 help='Create an Android Things eXtension (ATX) unlock credential.')
4146 sub_parser.add_argument('--output',
4147 help='Write credential to file',
4148 type=argparse.FileType('wb'),
4149 default=sys.stdout)
4150 sub_parser.add_argument('--intermediate_key_certificate',
4151 help='Path to intermediate key certificate file',
4152 type=argparse.FileType('rb'),
4153 required=True)
4154 sub_parser.add_argument('--unlock_key_certificate',
4155 help='Path to unlock key certificate file',
4156 type=argparse.FileType('rb'),
4157 required=True)
4158 sub_parser.add_argument('--challenge',
4159 help='Path to the challenge to sign (optional). If '
4160 'this is not provided the challenge signature '
4161 'field is omitted and can be concatenated '
4162 'later.',
4163 required=False)
4164 sub_parser.add_argument('--unlock_key',
4165 help='Path to unlock key (optional). Must be '
4166 'provided if using --challenge.',
4167 required=False)
4168 sub_parser.add_argument('--signing_helper',
4169 help='Path to helper used for signing',
4170 metavar='APP',
4171 default=None,
4172 required=False)
4173 sub_parser.add_argument('--signing_helper_with_files',
4174 help='Path to helper used for signing using files',
4175 metavar='APP',
4176 default=None,
4177 required=False)
4178 sub_parser.set_defaults(func=self.make_atx_unlock_credential)
4179
David Zeuthen21e95262016-07-27 17:58:40 -04004180 args = parser.parse_args(argv[1:])
4181 try:
4182 args.func(args)
4183 except AvbError as e:
David Zeuthena4fee8b2016-08-22 15:20:43 -04004184 sys.stderr.write('{}: {}\n'.format(argv[0], e.message))
David Zeuthen21e95262016-07-27 17:58:40 -04004185 sys.exit(1)
4186
4187 def version(self, _):
4188 """Implements the 'version' sub-command."""
David Zeuthene3cadca2017-02-22 21:25:46 -05004189 print get_release_string()
David Zeuthen21e95262016-07-27 17:58:40 -04004190
4191 def extract_public_key(self, args):
4192 """Implements the 'extract_public_key' sub-command."""
4193 self.avb.extract_public_key(args.key, args.output)
4194
4195 def make_vbmeta_image(self, args):
4196 """Implements the 'make_vbmeta_image' sub-command."""
David Zeuthena5fd3a42017-02-27 16:38:54 -05004197 args = self._fixup_common_args(args)
David Zeuthen21e95262016-07-27 17:58:40 -04004198 self.avb.make_vbmeta_image(args.output, args.chain_partition,
David Zeuthen18666ab2016-11-15 11:18:05 -05004199 args.algorithm, args.key,
4200 args.public_key_metadata, args.rollback_index,
David Zeuthenfd41eb92016-11-17 12:24:47 -05004201 args.flags, args.prop, args.prop_from_file,
David Zeuthen21e95262016-07-27 17:58:40 -04004202 args.kernel_cmdline,
David Zeuthen5d4f4f22017-01-11 11:37:34 -05004203 args.setup_rootfs_from_kernel,
David Zeuthend247fcb2017-02-16 12:09:27 -05004204 args.include_descriptors_from_image,
David Zeuthene3cadca2017-02-22 21:25:46 -05004205 args.signing_helper,
David Zeuthena156d3d2017-06-01 12:08:09 -04004206 args.signing_helper_with_files,
David Zeuthene3cadca2017-02-22 21:25:46 -05004207 args.internal_release_string,
David Zeuthen1097a782017-05-31 15:53:17 -04004208 args.append_to_release_string,
David Zeuthen97cb5802017-06-01 16:14:05 -04004209 args.print_required_libavb_version,
4210 args.padding_size)
David Zeuthen21e95262016-07-27 17:58:40 -04004211
David Zeuthenb1b994d2017-03-06 18:01:31 -05004212 def append_vbmeta_image(self, args):
4213 """Implements the 'append_vbmeta_image' sub-command."""
4214 self.avb.append_vbmeta_image(args.image.name, args.vbmeta_image.name,
4215 args.partition_size)
4216
David Zeuthen21e95262016-07-27 17:58:40 -04004217 def add_hash_footer(self, args):
4218 """Implements the 'add_hash_footer' sub-command."""
David Zeuthena5fd3a42017-02-27 16:38:54 -05004219 args = self._fixup_common_args(args)
David Zeuthenbf562452017-05-17 18:04:43 -04004220 self.avb.add_hash_footer(args.image.name if args.image else None,
4221 args.partition_size,
David Zeuthen21e95262016-07-27 17:58:40 -04004222 args.partition_name, args.hash_algorithm,
David Zeuthena5fd3a42017-02-27 16:38:54 -05004223 args.salt, args.chain_partition, args.algorithm,
4224 args.key,
David Zeuthen18666ab2016-11-15 11:18:05 -05004225 args.public_key_metadata, args.rollback_index,
David Zeuthena5fd3a42017-02-27 16:38:54 -05004226 args.flags, args.prop, args.prop_from_file,
David Zeuthen18666ab2016-11-15 11:18:05 -05004227 args.kernel_cmdline,
David Zeuthen5d4f4f22017-01-11 11:37:34 -05004228 args.setup_rootfs_from_kernel,
David Zeuthend247fcb2017-02-16 12:09:27 -05004229 args.include_descriptors_from_image,
David Zeuthena156d3d2017-06-01 12:08:09 -04004230 args.calc_max_image_size,
4231 args.signing_helper,
4232 args.signing_helper_with_files,
David Zeuthene3cadca2017-02-22 21:25:46 -05004233 args.internal_release_string,
4234 args.append_to_release_string,
David Zeuthend247fcb2017-02-16 12:09:27 -05004235 args.output_vbmeta_image,
David Zeuthen1097a782017-05-31 15:53:17 -04004236 args.do_not_append_vbmeta_image,
Darren Krahnfd0ba0d2018-02-01 18:06:34 -08004237 args.print_required_libavb_version,
4238 args.use_persistent_digest,
4239 args.do_not_use_ab)
David Zeuthen21e95262016-07-27 17:58:40 -04004240
4241 def add_hashtree_footer(self, args):
4242 """Implements the 'add_hashtree_footer' sub-command."""
David Zeuthena5fd3a42017-02-27 16:38:54 -05004243 args = self._fixup_common_args(args)
David Zeuthenbce9a292017-05-10 17:18:04 -04004244 # TODO(zeuthen): Remove when removing support for the
4245 # '--generate_fec' option above.
4246 if args.generate_fec:
4247 sys.stderr.write('The --generate_fec option is deprecated since FEC '
4248 'is now generated by default. Use the option '
4249 '--do_not_generate_fec to not generate FEC.\n')
David Zeuthen09692692016-09-30 16:16:40 -04004250 self.avb.add_hashtree_footer(args.image.name if args.image else None,
4251 args.partition_size,
4252 args.partition_name,
David Zeuthenbce9a292017-05-10 17:18:04 -04004253 not args.do_not_generate_fec, args.fec_num_roots,
David Zeuthen09692692016-09-30 16:16:40 -04004254 args.hash_algorithm, args.block_size,
David Zeuthena5fd3a42017-02-27 16:38:54 -05004255 args.salt, args.chain_partition, args.algorithm,
4256 args.key, args.public_key_metadata,
4257 args.rollback_index, args.flags, args.prop,
David Zeuthen09692692016-09-30 16:16:40 -04004258 args.prop_from_file,
4259 args.kernel_cmdline,
David Zeuthen5d4f4f22017-01-11 11:37:34 -05004260 args.setup_rootfs_from_kernel,
David Zeuthen73f2afa2017-05-17 16:54:11 -04004261 args.setup_as_rootfs_from_kernel,
David Zeuthen09692692016-09-30 16:16:40 -04004262 args.include_descriptors_from_image,
David Zeuthena156d3d2017-06-01 12:08:09 -04004263 args.calc_max_image_size,
4264 args.signing_helper,
4265 args.signing_helper_with_files,
David Zeuthene3cadca2017-02-22 21:25:46 -05004266 args.internal_release_string,
4267 args.append_to_release_string,
David Zeuthend247fcb2017-02-16 12:09:27 -05004268 args.output_vbmeta_image,
David Zeuthen1097a782017-05-31 15:53:17 -04004269 args.do_not_append_vbmeta_image,
Darren Krahnfd0ba0d2018-02-01 18:06:34 -08004270 args.print_required_libavb_version,
4271 args.use_persistent_digest,
4272 args.do_not_use_ab)
David Zeuthend247fcb2017-02-16 12:09:27 -05004273
David Zeuthen21e95262016-07-27 17:58:40 -04004274 def erase_footer(self, args):
4275 """Implements the 'erase_footer' sub-command."""
David Zeuthena4fee8b2016-08-22 15:20:43 -04004276 self.avb.erase_footer(args.image.name, args.keep_hashtree)
David Zeuthen21e95262016-07-27 17:58:40 -04004277
David Zeuthen49936b42018-08-07 17:38:58 -04004278 def extract_vbmeta_image(self, args):
4279 """Implements the 'extract_vbmeta_image' sub-command."""
4280 self.avb.extract_vbmeta_image(args.output, args.image.name,
4281 args.padding_size)
4282
David Zeuthen2bc232b2017-04-19 14:25:19 -04004283 def resize_image(self, args):
4284 """Implements the 'resize_image' sub-command."""
4285 self.avb.resize_image(args.image.name, args.partition_size)
4286
David Zeuthen8b6973b2016-09-20 12:39:49 -04004287 def set_ab_metadata(self, args):
4288 """Implements the 'set_ab_metadata' sub-command."""
4289 self.avb.set_ab_metadata(args.misc_image, args.slot_data)
4290
David Zeuthen21e95262016-07-27 17:58:40 -04004291 def info_image(self, args):
4292 """Implements the 'info_image' sub-command."""
David Zeuthena4fee8b2016-08-22 15:20:43 -04004293 self.avb.info_image(args.image.name, args.output)
David Zeuthen21e95262016-07-27 17:58:40 -04004294
David Zeuthenb623d8b2017-04-04 16:05:53 -04004295 def verify_image(self, args):
4296 """Implements the 'verify_image' sub-command."""
David Zeuthen5dfb4e92017-05-24 14:49:32 -04004297 self.avb.verify_image(args.image.name, args.key,
4298 args.expected_chain_partition)
David Zeuthenb623d8b2017-04-04 16:05:53 -04004299
David Zeuthenb8643c02018-05-17 17:21:18 -04004300 def calculate_vbmeta_digest(self, args):
4301 """Implements the 'calculate_vbmeta_digest' sub-command."""
4302 self.avb.calculate_vbmeta_digest(args.image.name, args.hash_algorithm,
4303 args.output)
4304
David Zeuthenf7d2e752018-09-20 13:30:41 -04004305 def calculate_kernel_cmdline(self, args):
4306 """Implements the 'calculate_kernel_cmdline' sub-command."""
4307 self.avb.calculate_kernel_cmdline(args.image.name, args.hashtree_disabled, args.output)
4308
Darren Krahn147b08d2016-12-20 16:38:29 -08004309 def make_atx_certificate(self, args):
4310 """Implements the 'make_atx_certificate' sub-command."""
4311 self.avb.make_atx_certificate(args.output, args.authority_key,
David Zeuthenc68f0822017-03-31 17:22:35 -04004312 args.subject_key.name,
Darren Krahn147b08d2016-12-20 16:38:29 -08004313 args.subject_key_version,
4314 args.subject.read(),
4315 args.subject_is_intermediate_authority,
Darren Krahnfccd64e2018-01-16 17:39:35 -08004316 args.usage,
David Zeuthena156d3d2017-06-01 12:08:09 -04004317 args.signing_helper,
4318 args.signing_helper_with_files)
Darren Krahn147b08d2016-12-20 16:38:29 -08004319
4320 def make_atx_permanent_attributes(self, args):
4321 """Implements the 'make_atx_permanent_attributes' sub-command."""
4322 self.avb.make_atx_permanent_attributes(args.output,
David Zeuthenc68f0822017-03-31 17:22:35 -04004323 args.root_authority_key.name,
Darren Krahn147b08d2016-12-20 16:38:29 -08004324 args.product_id.read())
4325
4326 def make_atx_metadata(self, args):
4327 """Implements the 'make_atx_metadata' sub-command."""
4328 self.avb.make_atx_metadata(args.output,
4329 args.intermediate_key_certificate.read(),
Darren Krahn43e12d82017-02-24 16:26:31 -08004330 args.product_key_certificate.read())
Darren Krahn147b08d2016-12-20 16:38:29 -08004331
Darren Krahnfccd64e2018-01-16 17:39:35 -08004332 def make_atx_unlock_credential(self, args):
4333 """Implements the 'make_atx_unlock_credential' sub-command."""
4334 self.avb.make_atx_unlock_credential(
4335 args.output,
4336 args.intermediate_key_certificate.read(),
4337 args.unlock_key_certificate.read(),
4338 args.challenge,
4339 args.unlock_key,
4340 args.signing_helper,
4341 args.signing_helper_with_files)
4342
David Zeuthen21e95262016-07-27 17:58:40 -04004343
4344if __name__ == '__main__':
4345 tool = AvbTool()
4346 tool.run(sys.argv)