blob: 1b508204d29e4e3a39c6622ea7a9f62fa0388c0f [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 Zeuthen21e95262016-07-27 17:58:40 -04002295 def _parse_image(self, image):
2296 """Gets information about an image.
2297
2298 The image can either be a vbmeta or an image with a footer.
2299
2300 Arguments:
David Zeuthena4fee8b2016-08-22 15:20:43 -04002301 image: An ImageHandler (vbmeta or footer) with a hashtree descriptor.
David Zeuthen21e95262016-07-27 17:58:40 -04002302
2303 Returns:
2304 A tuple where the first argument is a AvbFooter (None if there
2305 is no footer on the image), the second argument is a
2306 AvbVBMetaHeader, the third argument is a list of
2307 AvbDescriptor-derived instances, and the fourth argument is the
2308 size of |image|.
2309 """
David Zeuthena4fee8b2016-08-22 15:20:43 -04002310 assert isinstance(image, ImageHandler)
David Zeuthen21e95262016-07-27 17:58:40 -04002311 footer = None
David Zeuthen09692692016-09-30 16:16:40 -04002312 image.seek(image.image_size - AvbFooter.SIZE)
David Zeuthen21e95262016-07-27 17:58:40 -04002313 try:
2314 footer = AvbFooter(image.read(AvbFooter.SIZE))
2315 except (LookupError, struct.error):
2316 # Nope, just seek back to the start.
2317 image.seek(0)
2318
2319 vbmeta_offset = 0
2320 if footer:
2321 vbmeta_offset = footer.vbmeta_offset
2322
2323 image.seek(vbmeta_offset)
2324 h = AvbVBMetaHeader(image.read(AvbVBMetaHeader.SIZE))
2325
2326 auth_block_offset = vbmeta_offset + AvbVBMetaHeader.SIZE
2327 aux_block_offset = auth_block_offset + h.authentication_data_block_size
2328 desc_start_offset = aux_block_offset + h.descriptors_offset
2329 image.seek(desc_start_offset)
2330 descriptors = parse_descriptors(image.read(h.descriptors_size))
2331
David Zeuthen09692692016-09-30 16:16:40 -04002332 return footer, h, descriptors, image.image_size
David Zeuthen21e95262016-07-27 17:58:40 -04002333
David Zeuthenb1b994d2017-03-06 18:01:31 -05002334 def _load_vbmeta_blob(self, image):
2335 """Gets the vbmeta struct and associated sections.
2336
2337 The image can either be a vbmeta.img or an image with a footer.
2338
2339 Arguments:
2340 image: An ImageHandler (vbmeta or footer).
2341
2342 Returns:
2343 A blob with the vbmeta struct and other sections.
2344 """
2345 assert isinstance(image, ImageHandler)
2346 footer = None
2347 image.seek(image.image_size - AvbFooter.SIZE)
2348 try:
2349 footer = AvbFooter(image.read(AvbFooter.SIZE))
2350 except (LookupError, struct.error):
2351 # Nope, just seek back to the start.
2352 image.seek(0)
2353
2354 vbmeta_offset = 0
2355 if footer:
2356 vbmeta_offset = footer.vbmeta_offset
2357
2358 image.seek(vbmeta_offset)
2359 h = AvbVBMetaHeader(image.read(AvbVBMetaHeader.SIZE))
2360
2361 image.seek(vbmeta_offset)
2362 data_size = AvbVBMetaHeader.SIZE
2363 data_size += h.authentication_data_block_size
2364 data_size += h.auxiliary_data_block_size
2365 return image.read(data_size)
2366
David Zeuthen73f2afa2017-05-17 16:54:11 -04002367 def _get_cmdline_descriptors_for_hashtree_descriptor(self, ht):
David Zeuthenfd41eb92016-11-17 12:24:47 -05002368 """Generate kernel cmdline descriptors for dm-verity.
David Zeuthen21e95262016-07-27 17:58:40 -04002369
2370 Arguments:
David Zeuthen73f2afa2017-05-17 16:54:11 -04002371 ht: A AvbHashtreeDescriptor
David Zeuthen21e95262016-07-27 17:58:40 -04002372
2373 Returns:
David Zeuthenfd41eb92016-11-17 12:24:47 -05002374 A list with two AvbKernelCmdlineDescriptor with dm-verity kernel cmdline
2375 instructions. There is one for when hashtree is not disabled and one for
2376 when it is.
David Zeuthen21e95262016-07-27 17:58:40 -04002377
David Zeuthen21e95262016-07-27 17:58:40 -04002378 """
2379
David Zeuthen21e95262016-07-27 17:58:40 -04002380 c = 'dm="1 vroot none ro 1,'
David Zeuthen0b7f1d32016-10-25 17:53:49 -04002381 c += '0' # start
2382 c += ' {}'.format((ht.image_size / 512)) # size (# sectors)
2383 c += ' verity {}'.format(ht.dm_verity_version) # type and version
2384 c += ' PARTUUID=$(ANDROID_SYSTEM_PARTUUID)' # data_dev
2385 c += ' PARTUUID=$(ANDROID_SYSTEM_PARTUUID)' # hash_dev
2386 c += ' {}'.format(ht.data_block_size) # data_block
2387 c += ' {}'.format(ht.hash_block_size) # hash_block
2388 c += ' {}'.format(ht.image_size / ht.data_block_size) # #blocks
2389 c += ' {}'.format(ht.image_size / ht.data_block_size) # hash_offset
2390 c += ' {}'.format(ht.hash_algorithm) # hash_alg
2391 c += ' {}'.format(str(ht.root_digest).encode('hex')) # root_digest
2392 c += ' {}'.format(str(ht.salt).encode('hex')) # salt
2393 if ht.fec_num_roots > 0:
David Zeuthena01e32f2017-01-24 17:32:38 -05002394 c += ' 10' # number of optional args
David Zeuthen1b2f7a62017-06-23 13:20:54 -04002395 c += ' $(ANDROID_VERITY_MODE)'
David Zeuthen0b7f1d32016-10-25 17:53:49 -04002396 c += ' ignore_zero_blocks'
2397 c += ' use_fec_from_device PARTUUID=$(ANDROID_SYSTEM_PARTUUID)'
2398 c += ' fec_roots {}'.format(ht.fec_num_roots)
2399 # Note that fec_blocks is the size that FEC covers, *not* the
2400 # size of the FEC data. Since we use FEC for everything up until
2401 # the FEC data, it's the same as the offset.
2402 c += ' fec_blocks {}'.format(ht.fec_offset/ht.data_block_size)
2403 c += ' fec_start {}'.format(ht.fec_offset/ht.data_block_size)
2404 else:
David Zeuthena01e32f2017-01-24 17:32:38 -05002405 c += ' 2' # number of optional args
David Zeuthen1b2f7a62017-06-23 13:20:54 -04002406 c += ' $(ANDROID_VERITY_MODE)'
David Zeuthen0b7f1d32016-10-25 17:53:49 -04002407 c += ' ignore_zero_blocks'
David Zeuthenfd9c18d2017-03-20 18:19:30 -04002408 c += '" root=/dev/dm-0'
David Zeuthen21e95262016-07-27 17:58:40 -04002409
David Zeuthenfd41eb92016-11-17 12:24:47 -05002410 # Now that we have the command-line, generate the descriptor.
David Zeuthen21e95262016-07-27 17:58:40 -04002411 desc = AvbKernelCmdlineDescriptor()
2412 desc.kernel_cmdline = c
David Zeuthenfd41eb92016-11-17 12:24:47 -05002413 desc.flags = (
2414 AvbKernelCmdlineDescriptor.FLAGS_USE_ONLY_IF_HASHTREE_NOT_DISABLED)
2415
2416 # The descriptor for when hashtree verification is disabled is a lot
2417 # simpler - we just set the root to the partition.
2418 desc_no_ht = AvbKernelCmdlineDescriptor()
2419 desc_no_ht.kernel_cmdline = 'root=PARTUUID=$(ANDROID_SYSTEM_PARTUUID)'
2420 desc_no_ht.flags = (
2421 AvbKernelCmdlineDescriptor.FLAGS_USE_ONLY_IF_HASHTREE_DISABLED)
2422
2423 return [desc, desc_no_ht]
David Zeuthen21e95262016-07-27 17:58:40 -04002424
David Zeuthen73f2afa2017-05-17 16:54:11 -04002425 def _get_cmdline_descriptors_for_dm_verity(self, image):
2426 """Generate kernel cmdline descriptors for dm-verity.
2427
2428 Arguments:
2429 image: An ImageHandler (vbmeta or footer) with a hashtree descriptor.
2430
2431 Returns:
2432 A list with two AvbKernelCmdlineDescriptor with dm-verity kernel cmdline
2433 instructions. There is one for when hashtree is not disabled and one for
2434 when it is.
2435
2436 Raises:
2437 AvbError: If |image| doesn't have a hashtree descriptor.
2438
2439 """
2440
2441 (_, _, descriptors, _) = self._parse_image(image)
2442
2443 ht = None
2444 for desc in descriptors:
2445 if isinstance(desc, AvbHashtreeDescriptor):
2446 ht = desc
2447 break
2448
2449 if not ht:
2450 raise AvbError('No hashtree descriptor in given image')
2451
2452 return self._get_cmdline_descriptors_for_hashtree_descriptor(ht)
2453
David Zeuthen21e95262016-07-27 17:58:40 -04002454 def make_vbmeta_image(self, output, chain_partitions, algorithm_name,
David Zeuthen18666ab2016-11-15 11:18:05 -05002455 key_path, public_key_metadata_path, rollback_index,
David Zeuthenfd41eb92016-11-17 12:24:47 -05002456 flags, props, props_from_file, kernel_cmdlines,
David Zeuthen5d4f4f22017-01-11 11:37:34 -05002457 setup_rootfs_from_kernel,
David Zeuthena156d3d2017-06-01 12:08:09 -04002458 include_descriptors_from_image,
2459 signing_helper,
2460 signing_helper_with_files,
David Zeuthene3cadca2017-02-22 21:25:46 -05002461 release_string,
David Zeuthen1097a782017-05-31 15:53:17 -04002462 append_to_release_string,
David Zeuthen97cb5802017-06-01 16:14:05 -04002463 print_required_libavb_version,
2464 padding_size):
David Zeuthen21e95262016-07-27 17:58:40 -04002465 """Implements the 'make_vbmeta_image' command.
2466
2467 Arguments:
2468 output: File to write the image to.
David Zeuthena5fd3a42017-02-27 16:38:54 -05002469 chain_partitions: List of partitions to chain or None.
David Zeuthen21e95262016-07-27 17:58:40 -04002470 algorithm_name: Name of algorithm to use.
2471 key_path: Path to key to use or None.
David Zeuthen18666ab2016-11-15 11:18:05 -05002472 public_key_metadata_path: Path to public key metadata or None.
David Zeuthen21e95262016-07-27 17:58:40 -04002473 rollback_index: The rollback index to use.
David Zeuthenfd41eb92016-11-17 12:24:47 -05002474 flags: Flags value to use in the image.
David Zeuthen21e95262016-07-27 17:58:40 -04002475 props: Properties to insert (list of strings of the form 'key:value').
2476 props_from_file: Properties to insert (list of strings 'key:<path>').
2477 kernel_cmdlines: Kernel cmdlines to insert (list of strings).
David Zeuthen5d4f4f22017-01-11 11:37:34 -05002478 setup_rootfs_from_kernel: None or file to generate from.
David Zeuthen21e95262016-07-27 17:58:40 -04002479 include_descriptors_from_image: List of file objects with descriptors.
Dzmitry Yatsushkevich4e552792016-12-15 10:27:48 -08002480 signing_helper: Program which signs a hash and return signature.
David Zeuthena156d3d2017-06-01 12:08:09 -04002481 signing_helper_with_files: Same as signing_helper but uses files instead.
David Zeuthene3cadca2017-02-22 21:25:46 -05002482 release_string: None or avbtool release string to use instead of default.
2483 append_to_release_string: None or string to append.
David Zeuthen1097a782017-05-31 15:53:17 -04002484 print_required_libavb_version: True to only print required libavb version.
David Zeuthen97cb5802017-06-01 16:14:05 -04002485 padding_size: If not 0, pads output so size is a multiple of the number.
David Zeuthen21e95262016-07-27 17:58:40 -04002486
2487 Raises:
2488 AvbError: If a chained partition is malformed.
2489 """
2490
David Zeuthen1097a782017-05-31 15:53:17 -04002491 # If we're asked to calculate minimum required libavb version, we're done.
David Zeuthen1097a782017-05-31 15:53:17 -04002492 if print_required_libavb_version:
Darren Krahnfd0ba0d2018-02-01 18:06:34 -08002493 if include_descriptors_from_image:
2494 # Use the bump logic in AvbVBMetaHeader to calculate the max required
2495 # version of all included descriptors.
2496 tmp_header = AvbVBMetaHeader()
2497 for image in include_descriptors_from_image:
2498 (_, image_header, _, _) = self._parse_image(ImageHandler(image.name))
2499 tmp_header.bump_required_libavb_version_minor(
2500 image_header.required_libavb_version_minor)
2501 print '1.{}'.format(tmp_header.required_libavb_version_minor)
2502 else:
2503 # Descriptors aside, all vbmeta features are supported in 1.0.
2504 print '1.0'
David Zeuthen1097a782017-05-31 15:53:17 -04002505 return
2506
2507 if not output:
2508 raise AvbError('No output file given')
2509
David Zeuthen21e95262016-07-27 17:58:40 -04002510 descriptors = []
David Zeuthen73f2afa2017-05-17 16:54:11 -04002511 ht_desc_to_setup = None
David Zeuthen21e95262016-07-27 17:58:40 -04002512 vbmeta_blob = self._generate_vbmeta_blob(
David Zeuthen18666ab2016-11-15 11:18:05 -05002513 algorithm_name, key_path, public_key_metadata_path, descriptors,
David Zeuthena5fd3a42017-02-27 16:38:54 -05002514 chain_partitions, rollback_index, flags, props, props_from_file,
David Zeuthen73f2afa2017-05-17 16:54:11 -04002515 kernel_cmdlines, setup_rootfs_from_kernel, ht_desc_to_setup,
David Zeuthena156d3d2017-06-01 12:08:09 -04002516 include_descriptors_from_image, signing_helper,
2517 signing_helper_with_files, release_string,
Darren Krahnfd0ba0d2018-02-01 18:06:34 -08002518 append_to_release_string, 0)
David Zeuthen21e95262016-07-27 17:58:40 -04002519
2520 # Write entire vbmeta blob (header, authentication, auxiliary).
2521 output.seek(0)
2522 output.write(vbmeta_blob)
2523
David Zeuthen97cb5802017-06-01 16:14:05 -04002524 if padding_size > 0:
2525 padded_size = round_to_multiple(len(vbmeta_blob), padding_size)
2526 padding_needed = padded_size - len(vbmeta_blob)
2527 output.write('\0' * padding_needed)
2528
David Zeuthen18666ab2016-11-15 11:18:05 -05002529 def _generate_vbmeta_blob(self, algorithm_name, key_path,
2530 public_key_metadata_path, descriptors,
David Zeuthena5fd3a42017-02-27 16:38:54 -05002531 chain_partitions,
David Zeuthenfd41eb92016-11-17 12:24:47 -05002532 rollback_index, flags, props, props_from_file,
David Zeuthen21e95262016-07-27 17:58:40 -04002533 kernel_cmdlines,
David Zeuthen5d4f4f22017-01-11 11:37:34 -05002534 setup_rootfs_from_kernel,
David Zeuthen73f2afa2017-05-17 16:54:11 -04002535 ht_desc_to_setup,
David Zeuthene3cadca2017-02-22 21:25:46 -05002536 include_descriptors_from_image, signing_helper,
David Zeuthena156d3d2017-06-01 12:08:09 -04002537 signing_helper_with_files,
Darren Krahnfd0ba0d2018-02-01 18:06:34 -08002538 release_string, append_to_release_string,
2539 required_libavb_version_minor):
David Zeuthen21e95262016-07-27 17:58:40 -04002540 """Generates a VBMeta blob.
2541
2542 This blob contains the header (struct AvbVBMetaHeader), the
2543 authentication data block (which contains the hash and signature
2544 for the header and auxiliary block), and the auxiliary block
2545 (which contains descriptors, the public key used, and other data).
2546
2547 The |key| parameter can |None| only if the |algorithm_name| is
2548 'NONE'.
2549
2550 Arguments:
2551 algorithm_name: The algorithm name as per the ALGORITHMS dict.
2552 key_path: The path to the .pem file used to sign the blob.
David Zeuthen18666ab2016-11-15 11:18:05 -05002553 public_key_metadata_path: Path to public key metadata or None.
David Zeuthen21e95262016-07-27 17:58:40 -04002554 descriptors: A list of descriptors to insert or None.
David Zeuthena5fd3a42017-02-27 16:38:54 -05002555 chain_partitions: List of partitions to chain or None.
David Zeuthen21e95262016-07-27 17:58:40 -04002556 rollback_index: The rollback index to use.
David Zeuthenfd41eb92016-11-17 12:24:47 -05002557 flags: Flags to use in the image.
David Zeuthen21e95262016-07-27 17:58:40 -04002558 props: Properties to insert (List of strings of the form 'key:value').
2559 props_from_file: Properties to insert (List of strings 'key:<path>').
2560 kernel_cmdlines: Kernel cmdlines to insert (list of strings).
David Zeuthen5d4f4f22017-01-11 11:37:34 -05002561 setup_rootfs_from_kernel: None or file to generate
David Zeuthen21e95262016-07-27 17:58:40 -04002562 dm-verity kernel cmdline from.
David Zeuthen73f2afa2017-05-17 16:54:11 -04002563 ht_desc_to_setup: If not None, an AvbHashtreeDescriptor to
2564 generate dm-verity kernel cmdline descriptors from.
David Zeuthen21e95262016-07-27 17:58:40 -04002565 include_descriptors_from_image: List of file objects for which
2566 to insert descriptors from.
Dzmitry Yatsushkevich4e552792016-12-15 10:27:48 -08002567 signing_helper: Program which signs a hash and return signature.
David Zeuthena156d3d2017-06-01 12:08:09 -04002568 signing_helper_with_files: Same as signing_helper but uses files instead.
David Zeuthene3cadca2017-02-22 21:25:46 -05002569 release_string: None or avbtool release string.
2570 append_to_release_string: None or string to append.
Darren Krahnfd0ba0d2018-02-01 18:06:34 -08002571 required_libavb_version_minor: Use at least this required minor version.
David Zeuthen21e95262016-07-27 17:58:40 -04002572
2573 Returns:
2574 A bytearray() with the VBMeta blob.
2575
2576 Raises:
2577 Exception: If the |algorithm_name| is not found, if no key has
2578 been given and the given algorithm requires one, or the key is
2579 of the wrong size.
2580
2581 """
2582 try:
2583 alg = ALGORITHMS[algorithm_name]
2584 except KeyError:
2585 raise AvbError('Unknown algorithm with name {}'.format(algorithm_name))
2586
David Zeuthena5fd3a42017-02-27 16:38:54 -05002587 if not descriptors:
2588 descriptors = []
2589
Darren Krahnfd0ba0d2018-02-01 18:06:34 -08002590 h = AvbVBMetaHeader()
2591 h.bump_required_libavb_version_minor(required_libavb_version_minor)
2592
David Zeuthena5fd3a42017-02-27 16:38:54 -05002593 # Insert chained partition descriptors, if any
2594 if chain_partitions:
David Zeuthend8e48582017-04-21 11:31:51 -04002595 used_locations = {}
David Zeuthena5fd3a42017-02-27 16:38:54 -05002596 for cp in chain_partitions:
2597 cp_tokens = cp.split(':')
2598 if len(cp_tokens) != 3:
2599 raise AvbError('Malformed chained partition "{}".'.format(cp))
David Zeuthend8e48582017-04-21 11:31:51 -04002600 partition_name = cp_tokens[0]
2601 rollback_index_location = int(cp_tokens[1])
2602 file_path = cp_tokens[2]
2603 # Check that the same rollback location isn't being used by
2604 # multiple chained partitions.
2605 if used_locations.get(rollback_index_location):
2606 raise AvbError('Rollback Index Location {} is already in use.'.format(
2607 rollback_index_location))
2608 used_locations[rollback_index_location] = True
David Zeuthena5fd3a42017-02-27 16:38:54 -05002609 desc = AvbChainPartitionDescriptor()
David Zeuthend8e48582017-04-21 11:31:51 -04002610 desc.partition_name = partition_name
2611 desc.rollback_index_location = rollback_index_location
David Zeuthena5fd3a42017-02-27 16:38:54 -05002612 if desc.rollback_index_location < 1:
2613 raise AvbError('Rollback index location must be 1 or larger.')
David Zeuthena5fd3a42017-02-27 16:38:54 -05002614 desc.public_key = open(file_path, 'rb').read()
2615 descriptors.append(desc)
2616
David Zeuthen21e95262016-07-27 17:58:40 -04002617 # Descriptors.
2618 encoded_descriptors = bytearray()
David Zeuthena5fd3a42017-02-27 16:38:54 -05002619 for desc in descriptors:
2620 encoded_descriptors.extend(desc.encode())
David Zeuthen21e95262016-07-27 17:58:40 -04002621
2622 # Add properties.
2623 if props:
2624 for prop in props:
2625 idx = prop.find(':')
2626 if idx == -1:
2627 raise AvbError('Malformed property "{}".'.format(prop))
2628 desc = AvbPropertyDescriptor()
2629 desc.key = prop[0:idx]
2630 desc.value = prop[(idx + 1):]
2631 encoded_descriptors.extend(desc.encode())
2632 if props_from_file:
2633 for prop in props_from_file:
2634 idx = prop.find(':')
2635 if idx == -1:
2636 raise AvbError('Malformed property "{}".'.format(prop))
2637 desc = AvbPropertyDescriptor()
2638 desc.key = prop[0:idx]
2639 desc.value = prop[(idx + 1):]
2640 file_path = prop[(idx + 1):]
2641 desc.value = open(file_path, 'rb').read()
2642 encoded_descriptors.extend(desc.encode())
2643
David Zeuthen73f2afa2017-05-17 16:54:11 -04002644 # Add AvbKernelCmdline descriptor for dm-verity from an image, if requested.
David Zeuthen5d4f4f22017-01-11 11:37:34 -05002645 if setup_rootfs_from_kernel:
David Zeuthena4fee8b2016-08-22 15:20:43 -04002646 image_handler = ImageHandler(
David Zeuthen5d4f4f22017-01-11 11:37:34 -05002647 setup_rootfs_from_kernel.name)
David Zeuthenfd41eb92016-11-17 12:24:47 -05002648 cmdline_desc = self._get_cmdline_descriptors_for_dm_verity(image_handler)
2649 encoded_descriptors.extend(cmdline_desc[0].encode())
2650 encoded_descriptors.extend(cmdline_desc[1].encode())
David Zeuthen21e95262016-07-27 17:58:40 -04002651
David Zeuthen73f2afa2017-05-17 16:54:11 -04002652 # Add AvbKernelCmdline descriptor for dm-verity from desc, if requested.
2653 if ht_desc_to_setup:
2654 cmdline_desc = self._get_cmdline_descriptors_for_hashtree_descriptor(
2655 ht_desc_to_setup)
2656 encoded_descriptors.extend(cmdline_desc[0].encode())
2657 encoded_descriptors.extend(cmdline_desc[1].encode())
2658
David Zeuthen21e95262016-07-27 17:58:40 -04002659 # Add kernel command-lines.
2660 if kernel_cmdlines:
2661 for i in kernel_cmdlines:
2662 desc = AvbKernelCmdlineDescriptor()
2663 desc.kernel_cmdline = i
2664 encoded_descriptors.extend(desc.encode())
2665
2666 # Add descriptors from other images.
2667 if include_descriptors_from_image:
Sen Jiang2a3d6bc2018-04-04 14:13:28 -07002668 descriptors_dict = dict()
David Zeuthen21e95262016-07-27 17:58:40 -04002669 for image in include_descriptors_from_image:
David Zeuthena4fee8b2016-08-22 15:20:43 -04002670 image_handler = ImageHandler(image.name)
Darren Krahnfd0ba0d2018-02-01 18:06:34 -08002671 (_, image_vbmeta_header, image_descriptors, _) = self._parse_image(
2672 image_handler)
2673 # Bump the required libavb version to support all included descriptors.
2674 h.bump_required_libavb_version_minor(
2675 image_vbmeta_header.required_libavb_version_minor)
David Zeuthen21e95262016-07-27 17:58:40 -04002676 for desc in image_descriptors:
Sen Jiang2a3d6bc2018-04-04 14:13:28 -07002677 # The --include_descriptors_from_image option is used in some setups
2678 # with images A and B where both A and B contain a descriptor
2679 # for a partition with the same name. Since it's not meaningful
2680 # to include both descriptors, only include the last seen descriptor.
2681 # See bug 76386656 for details.
2682 if hasattr(desc, 'partition_name'):
2683 key = type(desc).__name__ + '_' + desc.partition_name
2684 descriptors_dict[key] = desc.encode()
2685 else:
2686 encoded_descriptors.extend(desc.encode())
2687 for key in sorted(descriptors_dict.keys()):
2688 encoded_descriptors.extend(descriptors_dict[key])
David Zeuthen21e95262016-07-27 17:58:40 -04002689
David Zeuthen18666ab2016-11-15 11:18:05 -05002690 # Load public key metadata blob, if requested.
2691 pkmd_blob = []
2692 if public_key_metadata_path:
2693 with open(public_key_metadata_path) as f:
2694 pkmd_blob = f.read()
2695
David Zeuthen21e95262016-07-27 17:58:40 -04002696 key = None
2697 encoded_key = bytearray()
2698 if alg.public_key_num_bytes > 0:
2699 if not key_path:
2700 raise AvbError('Key is required for algorithm {}'.format(
2701 algorithm_name))
David Zeuthenc68f0822017-03-31 17:22:35 -04002702 encoded_key = encode_rsa_key(key_path)
David Zeuthen21e95262016-07-27 17:58:40 -04002703 if len(encoded_key) != alg.public_key_num_bytes:
2704 raise AvbError('Key is wrong size for algorithm {}'.format(
2705 algorithm_name))
2706
David Zeuthene3cadca2017-02-22 21:25:46 -05002707 # Override release string, if requested.
2708 if isinstance(release_string, (str, unicode)):
2709 h.release_string = release_string
2710
2711 # Append to release string, if requested. Also insert a space before.
2712 if isinstance(append_to_release_string, (str, unicode)):
2713 h.release_string += ' ' + append_to_release_string
2714
David Zeuthen18666ab2016-11-15 11:18:05 -05002715 # For the Auxiliary data block, descriptors are stored at offset 0,
2716 # followed by the public key, followed by the public key metadata blob.
David Zeuthen21e95262016-07-27 17:58:40 -04002717 h.auxiliary_data_block_size = round_to_multiple(
David Zeuthen18666ab2016-11-15 11:18:05 -05002718 len(encoded_descriptors) + len(encoded_key) + len(pkmd_blob), 64)
David Zeuthen21e95262016-07-27 17:58:40 -04002719 h.descriptors_offset = 0
2720 h.descriptors_size = len(encoded_descriptors)
2721 h.public_key_offset = h.descriptors_size
2722 h.public_key_size = len(encoded_key)
David Zeuthen18666ab2016-11-15 11:18:05 -05002723 h.public_key_metadata_offset = h.public_key_offset + h.public_key_size
2724 h.public_key_metadata_size = len(pkmd_blob)
David Zeuthen21e95262016-07-27 17:58:40 -04002725
2726 # For the Authentication data block, the hash is first and then
2727 # the signature.
2728 h.authentication_data_block_size = round_to_multiple(
David Zeuthend5db21d2017-01-24 10:11:38 -05002729 alg.hash_num_bytes + alg.signature_num_bytes, 64)
David Zeuthen21e95262016-07-27 17:58:40 -04002730 h.algorithm_type = alg.algorithm_type
2731 h.hash_offset = 0
2732 h.hash_size = alg.hash_num_bytes
2733 # Signature offset and size - it's stored right after the hash
2734 # (in Authentication data block).
2735 h.signature_offset = alg.hash_num_bytes
2736 h.signature_size = alg.signature_num_bytes
2737
2738 h.rollback_index = rollback_index
David Zeuthenfd41eb92016-11-17 12:24:47 -05002739 h.flags = flags
David Zeuthen21e95262016-07-27 17:58:40 -04002740
2741 # Generate Header data block.
2742 header_data_blob = h.encode()
2743
2744 # Generate Auxiliary data block.
2745 aux_data_blob = bytearray()
2746 aux_data_blob.extend(encoded_descriptors)
2747 aux_data_blob.extend(encoded_key)
David Zeuthen18666ab2016-11-15 11:18:05 -05002748 aux_data_blob.extend(pkmd_blob)
David Zeuthen21e95262016-07-27 17:58:40 -04002749 padding_bytes = h.auxiliary_data_block_size - len(aux_data_blob)
2750 aux_data_blob.extend('\0' * padding_bytes)
2751
2752 # Calculate the hash.
2753 binary_hash = bytearray()
2754 binary_signature = bytearray()
2755 if algorithm_name != 'NONE':
David Zeuthenb623d8b2017-04-04 16:05:53 -04002756 ha = hashlib.new(alg.hash_name)
David Zeuthen21e95262016-07-27 17:58:40 -04002757 ha.update(header_data_blob)
2758 ha.update(aux_data_blob)
2759 binary_hash.extend(ha.digest())
2760
2761 # Calculate the signature.
David Zeuthen21e95262016-07-27 17:58:40 -04002762 padding_and_hash = str(bytearray(alg.padding)) + binary_hash
David Zeuthena156d3d2017-06-01 12:08:09 -04002763 binary_signature.extend(raw_sign(signing_helper,
2764 signing_helper_with_files,
2765 algorithm_name,
Esun Kimff44f232017-03-30 10:34:54 +09002766 alg.signature_num_bytes, key_path,
Darren Krahn147b08d2016-12-20 16:38:29 -08002767 padding_and_hash))
David Zeuthen21e95262016-07-27 17:58:40 -04002768
2769 # Generate Authentication data block.
2770 auth_data_blob = bytearray()
2771 auth_data_blob.extend(binary_hash)
2772 auth_data_blob.extend(binary_signature)
2773 padding_bytes = h.authentication_data_block_size - len(auth_data_blob)
2774 auth_data_blob.extend('\0' * padding_bytes)
2775
2776 return header_data_blob + auth_data_blob + aux_data_blob
2777
2778 def extract_public_key(self, key_path, output):
2779 """Implements the 'extract_public_key' command.
2780
2781 Arguments:
2782 key_path: The path to a RSA private key file.
2783 output: The file to write to.
2784 """
David Zeuthenc68f0822017-03-31 17:22:35 -04002785 output.write(encode_rsa_key(key_path))
David Zeuthen21e95262016-07-27 17:58:40 -04002786
David Zeuthenb1b994d2017-03-06 18:01:31 -05002787 def append_vbmeta_image(self, image_filename, vbmeta_image_filename,
2788 partition_size):
2789 """Implementation of the append_vbmeta_image command.
2790
2791 Arguments:
2792 image_filename: File to add the footer to.
2793 vbmeta_image_filename: File to get vbmeta struct from.
2794 partition_size: Size of partition.
2795
2796 Raises:
2797 AvbError: If an argument is incorrect.
2798 """
2799 image = ImageHandler(image_filename)
2800
2801 if partition_size % image.block_size != 0:
2802 raise AvbError('Partition size of {} is not a multiple of the image '
2803 'block size {}.'.format(partition_size,
2804 image.block_size))
2805
2806 # If there's already a footer, truncate the image to its original
2807 # size. This way 'avbtool append_vbmeta_image' is idempotent.
Lonnie Liu6b5a33e2017-10-31 18:01:09 -07002808 if image.image_size >= AvbFooter.SIZE:
2809 image.seek(image.image_size - AvbFooter.SIZE)
2810 try:
2811 footer = AvbFooter(image.read(AvbFooter.SIZE))
2812 # Existing footer found. Just truncate.
2813 original_image_size = footer.original_image_size
2814 image.truncate(footer.original_image_size)
2815 except (LookupError, struct.error):
2816 original_image_size = image.image_size
2817 else:
2818 # Image size is too small to possibly contain a footer.
David Zeuthenb1b994d2017-03-06 18:01:31 -05002819 original_image_size = image.image_size
2820
2821 # If anything goes wrong from here-on, restore the image back to
2822 # its original size.
2823 try:
2824 vbmeta_image_handler = ImageHandler(vbmeta_image_filename)
2825 vbmeta_blob = self._load_vbmeta_blob(vbmeta_image_handler)
2826
2827 # If the image isn't sparse, its size might not be a multiple of
2828 # the block size. This will screw up padding later so just grow it.
2829 if image.image_size % image.block_size != 0:
2830 assert not image.is_sparse
2831 padding_needed = image.block_size - (image.image_size%image.block_size)
2832 image.truncate(image.image_size + padding_needed)
2833
2834 # The append_raw() method requires content with size being a
2835 # multiple of |block_size| so add padding as needed. Also record
2836 # where this is written to since we'll need to put that in the
2837 # footer.
2838 vbmeta_offset = image.image_size
2839 padding_needed = (round_to_multiple(len(vbmeta_blob), image.block_size) -
2840 len(vbmeta_blob))
2841 vbmeta_blob_with_padding = vbmeta_blob + '\0'*padding_needed
2842
2843 # Append vbmeta blob and footer
2844 image.append_raw(vbmeta_blob_with_padding)
2845 vbmeta_end_offset = vbmeta_offset + len(vbmeta_blob_with_padding)
2846
2847 # Now insert a DONT_CARE chunk with enough bytes such that the
2848 # final Footer block is at the end of partition_size..
2849 image.append_dont_care(partition_size - vbmeta_end_offset -
2850 1*image.block_size)
2851
2852 # Generate the Footer that tells where the VBMeta footer
2853 # is. Also put enough padding in the front of the footer since
2854 # we'll write out an entire block.
2855 footer = AvbFooter()
2856 footer.original_image_size = original_image_size
2857 footer.vbmeta_offset = vbmeta_offset
2858 footer.vbmeta_size = len(vbmeta_blob)
2859 footer_blob = footer.encode()
2860 footer_blob_with_padding = ('\0'*(image.block_size - AvbFooter.SIZE) +
2861 footer_blob)
2862 image.append_raw(footer_blob_with_padding)
2863
2864 except:
2865 # Truncate back to original size, then re-raise
2866 image.truncate(original_image_size)
2867 raise
2868
David Zeuthena4fee8b2016-08-22 15:20:43 -04002869 def add_hash_footer(self, image_filename, partition_size, partition_name,
David Zeuthena5fd3a42017-02-27 16:38:54 -05002870 hash_algorithm, salt, chain_partitions, algorithm_name,
2871 key_path,
2872 public_key_metadata_path, rollback_index, flags, props,
David Zeuthen18666ab2016-11-15 11:18:05 -05002873 props_from_file, kernel_cmdlines,
David Zeuthen5d4f4f22017-01-11 11:37:34 -05002874 setup_rootfs_from_kernel,
David Zeuthenbf562452017-05-17 18:04:43 -04002875 include_descriptors_from_image, calc_max_image_size,
David Zeuthena156d3d2017-06-01 12:08:09 -04002876 signing_helper, signing_helper_with_files,
2877 release_string, append_to_release_string,
David Zeuthen1097a782017-05-31 15:53:17 -04002878 output_vbmeta_image, do_not_append_vbmeta_image,
Darren Krahnfd0ba0d2018-02-01 18:06:34 -08002879 print_required_libavb_version, use_persistent_digest,
2880 do_not_use_ab):
David Zeuthena4fee8b2016-08-22 15:20:43 -04002881 """Implementation of the add_hash_footer on unsparse images.
David Zeuthen21e95262016-07-27 17:58:40 -04002882
2883 Arguments:
David Zeuthena4fee8b2016-08-22 15:20:43 -04002884 image_filename: File to add the footer to.
David Zeuthen21e95262016-07-27 17:58:40 -04002885 partition_size: Size of partition.
2886 partition_name: Name of partition (without A/B suffix).
2887 hash_algorithm: Hash algorithm to use.
2888 salt: Salt to use as a hexadecimal string or None to use /dev/urandom.
David Zeuthena5fd3a42017-02-27 16:38:54 -05002889 chain_partitions: List of partitions to chain.
David Zeuthen21e95262016-07-27 17:58:40 -04002890 algorithm_name: Name of algorithm to use.
2891 key_path: Path to key to use or None.
David Zeuthen18666ab2016-11-15 11:18:05 -05002892 public_key_metadata_path: Path to public key metadata or None.
David Zeuthen21e95262016-07-27 17:58:40 -04002893 rollback_index: Rollback index.
David Zeuthena5fd3a42017-02-27 16:38:54 -05002894 flags: Flags value to use in the image.
David Zeuthen21e95262016-07-27 17:58:40 -04002895 props: Properties to insert (List of strings of the form 'key:value').
2896 props_from_file: Properties to insert (List of strings 'key:<path>').
2897 kernel_cmdlines: Kernel cmdlines to insert (list of strings).
David Zeuthen5d4f4f22017-01-11 11:37:34 -05002898 setup_rootfs_from_kernel: None or file to generate
David Zeuthen21e95262016-07-27 17:58:40 -04002899 dm-verity kernel cmdline from.
2900 include_descriptors_from_image: List of file objects for which
2901 to insert descriptors from.
David Zeuthenbf562452017-05-17 18:04:43 -04002902 calc_max_image_size: Don't store the footer - instead calculate the
2903 maximum image size leaving enough room for metadata with the
2904 given |partition_size|.
Dzmitry Yatsushkevich4e552792016-12-15 10:27:48 -08002905 signing_helper: Program which signs a hash and return signature.
David Zeuthena156d3d2017-06-01 12:08:09 -04002906 signing_helper_with_files: Same as signing_helper but uses files instead.
David Zeuthene3cadca2017-02-22 21:25:46 -05002907 release_string: None or avbtool release string.
2908 append_to_release_string: None or string to append.
David Zeuthend247fcb2017-02-16 12:09:27 -05002909 output_vbmeta_image: If not None, also write vbmeta struct to this file.
2910 do_not_append_vbmeta_image: If True, don't append vbmeta struct.
David Zeuthen1097a782017-05-31 15:53:17 -04002911 print_required_libavb_version: True to only print required libavb version.
Darren Krahnfd0ba0d2018-02-01 18:06:34 -08002912 use_persistent_digest: Use a persistent digest on device.
2913 do_not_use_ab: This partition does not use A/B.
David Zeuthena4fee8b2016-08-22 15:20:43 -04002914
2915 Raises:
2916 AvbError: If an argument is incorrect.
David Zeuthen21e95262016-07-27 17:58:40 -04002917 """
David Zeuthen1097a782017-05-31 15:53:17 -04002918
Darren Krahnfd0ba0d2018-02-01 18:06:34 -08002919 required_libavb_version_minor = 0
2920 if use_persistent_digest or do_not_use_ab:
2921 required_libavb_version_minor = 1
2922
David Zeuthen1097a782017-05-31 15:53:17 -04002923 # If we're asked to calculate minimum required libavb version, we're done.
David Zeuthen1097a782017-05-31 15:53:17 -04002924 if print_required_libavb_version:
Darren Krahnfd0ba0d2018-02-01 18:06:34 -08002925 print '1.{}'.format(required_libavb_version_minor)
David Zeuthen1097a782017-05-31 15:53:17 -04002926 return
2927
David Zeuthenbf562452017-05-17 18:04:43 -04002928 # First, calculate the maximum image size such that an image
2929 # this size + metadata (footer + vbmeta struct) fits in
2930 # |partition_size|.
2931 max_metadata_size = self.MAX_VBMETA_SIZE + self.MAX_FOOTER_SIZE
Lonnie Liu6b5a33e2017-10-31 18:01:09 -07002932 if partition_size < max_metadata_size:
2933 raise AvbError('Parition size of {} is too small. '
2934 'Needs to be at least {}'.format(
2935 partition_size, max_metadata_size))
David Zeuthenbf562452017-05-17 18:04:43 -04002936 max_image_size = partition_size - max_metadata_size
2937
2938 # If we're asked to only calculate the maximum image size, we're done.
2939 if calc_max_image_size:
2940 print '{}'.format(max_image_size)
2941 return
2942
David Zeuthena4fee8b2016-08-22 15:20:43 -04002943 image = ImageHandler(image_filename)
2944
2945 if partition_size % image.block_size != 0:
2946 raise AvbError('Partition size of {} is not a multiple of the image '
2947 'block size {}.'.format(partition_size,
2948 image.block_size))
2949
David Zeuthen21e95262016-07-27 17:58:40 -04002950 # If there's already a footer, truncate the image to its original
2951 # size. This way 'avbtool add_hash_footer' is idempotent (modulo
2952 # salts).
Lonnie Liu6b5a33e2017-10-31 18:01:09 -07002953 if image.image_size >= AvbFooter.SIZE:
2954 image.seek(image.image_size - AvbFooter.SIZE)
2955 try:
2956 footer = AvbFooter(image.read(AvbFooter.SIZE))
2957 # Existing footer found. Just truncate.
2958 original_image_size = footer.original_image_size
2959 image.truncate(footer.original_image_size)
2960 except (LookupError, struct.error):
2961 original_image_size = image.image_size
2962 else:
2963 # Image size is too small to possibly contain a footer.
David Zeuthen09692692016-09-30 16:16:40 -04002964 original_image_size = image.image_size
David Zeuthen21e95262016-07-27 17:58:40 -04002965
2966 # If anything goes wrong from here-on, restore the image back to
2967 # its original size.
2968 try:
David Zeuthen09692692016-09-30 16:16:40 -04002969 # If image size exceeds the maximum image size, fail.
2970 if image.image_size > max_image_size:
2971 raise AvbError('Image size of {} exceeds maximum image '
2972 'size of {} in order to fit in a partition '
2973 'size of {}.'.format(image.image_size, max_image_size,
2974 partition_size))
2975
David Zeuthen21e95262016-07-27 17:58:40 -04002976 digest_size = len(hashlib.new(name=hash_algorithm).digest())
2977 if salt:
2978 salt = salt.decode('hex')
2979 else:
2980 if salt is None:
2981 # If salt is not explicitly specified, choose a hash
2982 # that's the same size as the hash size.
2983 hash_size = digest_size
2984 salt = open('/dev/urandom').read(hash_size)
2985 else:
2986 salt = ''
2987
2988 hasher = hashlib.new(name=hash_algorithm, string=salt)
2989 # TODO(zeuthen): might want to read this in chunks to avoid
2990 # memory pressure, then again, this is only supposed to be used
2991 # on kernel/initramfs partitions. Possible optimization.
2992 image.seek(0)
David Zeuthen09692692016-09-30 16:16:40 -04002993 hasher.update(image.read(image.image_size))
David Zeuthen21e95262016-07-27 17:58:40 -04002994 digest = hasher.digest()
2995
2996 h_desc = AvbHashDescriptor()
David Zeuthen09692692016-09-30 16:16:40 -04002997 h_desc.image_size = image.image_size
David Zeuthen21e95262016-07-27 17:58:40 -04002998 h_desc.hash_algorithm = hash_algorithm
2999 h_desc.partition_name = partition_name
3000 h_desc.salt = salt
Darren Krahnfd0ba0d2018-02-01 18:06:34 -08003001 h_desc.flags = 0
3002 if do_not_use_ab:
3003 h_desc.flags |= 1 # AVB_HASH_DESCRIPTOR_FLAGS_DO_NOT_USE_AB
3004 if not use_persistent_digest:
3005 h_desc.digest = digest
David Zeuthen21e95262016-07-27 17:58:40 -04003006
3007 # Generate the VBMeta footer.
David Zeuthen73f2afa2017-05-17 16:54:11 -04003008 ht_desc_to_setup = None
David Zeuthen21e95262016-07-27 17:58:40 -04003009 vbmeta_blob = self._generate_vbmeta_blob(
David Zeuthen18666ab2016-11-15 11:18:05 -05003010 algorithm_name, key_path, public_key_metadata_path, [h_desc],
David Zeuthena5fd3a42017-02-27 16:38:54 -05003011 chain_partitions, rollback_index, flags, props, props_from_file,
David Zeuthen73f2afa2017-05-17 16:54:11 -04003012 kernel_cmdlines, setup_rootfs_from_kernel, ht_desc_to_setup,
David Zeuthena156d3d2017-06-01 12:08:09 -04003013 include_descriptors_from_image, signing_helper,
3014 signing_helper_with_files, release_string,
Darren Krahnfd0ba0d2018-02-01 18:06:34 -08003015 append_to_release_string, required_libavb_version_minor)
David Zeuthen21e95262016-07-27 17:58:40 -04003016
David Zeuthend247fcb2017-02-16 12:09:27 -05003017 # Write vbmeta blob, if requested.
3018 if output_vbmeta_image:
3019 output_vbmeta_image.write(vbmeta_blob)
David Zeuthena4fee8b2016-08-22 15:20:43 -04003020
David Zeuthend247fcb2017-02-16 12:09:27 -05003021 # Append vbmeta blob and footer, unless requested not to.
3022 if not do_not_append_vbmeta_image:
Lonnie Liu6b5a33e2017-10-31 18:01:09 -07003023 # If the image isn't sparse, its size might not be a multiple of
3024 # the block size. This will screw up padding later so just grow it.
3025 if image.image_size % image.block_size != 0:
3026 assert not image.is_sparse
3027 padding_needed = image.block_size - (
3028 image.image_size % image.block_size)
3029 image.truncate(image.image_size + padding_needed)
3030
3031 # The append_raw() method requires content with size being a
3032 # multiple of |block_size| so add padding as needed. Also record
3033 # where this is written to since we'll need to put that in the
3034 # footer.
3035 vbmeta_offset = image.image_size
3036 padding_needed = (
3037 round_to_multiple(len(vbmeta_blob), image.block_size) -
3038 len(vbmeta_blob))
3039 vbmeta_blob_with_padding = vbmeta_blob + '\0' * padding_needed
3040
David Zeuthend247fcb2017-02-16 12:09:27 -05003041 image.append_raw(vbmeta_blob_with_padding)
3042 vbmeta_end_offset = vbmeta_offset + len(vbmeta_blob_with_padding)
3043
3044 # Now insert a DONT_CARE chunk with enough bytes such that the
3045 # final Footer block is at the end of partition_size..
3046 image.append_dont_care(partition_size - vbmeta_end_offset -
3047 1*image.block_size)
3048
3049 # Generate the Footer that tells where the VBMeta footer
3050 # is. Also put enough padding in the front of the footer since
3051 # we'll write out an entire block.
3052 footer = AvbFooter()
3053 footer.original_image_size = original_image_size
3054 footer.vbmeta_offset = vbmeta_offset
3055 footer.vbmeta_size = len(vbmeta_blob)
3056 footer_blob = footer.encode()
3057 footer_blob_with_padding = ('\0'*(image.block_size - AvbFooter.SIZE) +
3058 footer_blob)
3059 image.append_raw(footer_blob_with_padding)
David Zeuthena4fee8b2016-08-22 15:20:43 -04003060
David Zeuthen21e95262016-07-27 17:58:40 -04003061 except:
3062 # Truncate back to original size, then re-raise
3063 image.truncate(original_image_size)
3064 raise
3065
David Zeuthena4fee8b2016-08-22 15:20:43 -04003066 def add_hashtree_footer(self, image_filename, partition_size, partition_name,
David Zeuthen0b7f1d32016-10-25 17:53:49 -04003067 generate_fec, fec_num_roots, hash_algorithm,
David Zeuthena5fd3a42017-02-27 16:38:54 -05003068 block_size, salt, chain_partitions, algorithm_name,
3069 key_path,
3070 public_key_metadata_path, rollback_index, flags,
David Zeuthenfd41eb92016-11-17 12:24:47 -05003071 props, props_from_file, kernel_cmdlines,
David Zeuthen5d4f4f22017-01-11 11:37:34 -05003072 setup_rootfs_from_kernel,
David Zeuthen73f2afa2017-05-17 16:54:11 -04003073 setup_as_rootfs_from_kernel,
David Zeuthen09692692016-09-30 16:16:40 -04003074 include_descriptors_from_image,
David Zeuthend247fcb2017-02-16 12:09:27 -05003075 calc_max_image_size, signing_helper,
David Zeuthena156d3d2017-06-01 12:08:09 -04003076 signing_helper_with_files,
David Zeuthene3cadca2017-02-22 21:25:46 -05003077 release_string, append_to_release_string,
David Zeuthen1097a782017-05-31 15:53:17 -04003078 output_vbmeta_image, do_not_append_vbmeta_image,
Darren Krahnfd0ba0d2018-02-01 18:06:34 -08003079 print_required_libavb_version,
3080 use_persistent_root_digest, do_not_use_ab):
David Zeuthen21e95262016-07-27 17:58:40 -04003081 """Implements the 'add_hashtree_footer' command.
3082
3083 See https://gitlab.com/cryptsetup/cryptsetup/wikis/DMVerity for
3084 more information about dm-verity and these hashes.
3085
3086 Arguments:
David Zeuthena4fee8b2016-08-22 15:20:43 -04003087 image_filename: File to add the footer to.
David Zeuthen21e95262016-07-27 17:58:40 -04003088 partition_size: Size of partition.
3089 partition_name: Name of partition (without A/B suffix).
David Zeuthen0b7f1d32016-10-25 17:53:49 -04003090 generate_fec: If True, generate FEC codes.
3091 fec_num_roots: Number of roots for FEC.
David Zeuthen21e95262016-07-27 17:58:40 -04003092 hash_algorithm: Hash algorithm to use.
3093 block_size: Block size to use.
3094 salt: Salt to use as a hexadecimal string or None to use /dev/urandom.
David Zeuthena5fd3a42017-02-27 16:38:54 -05003095 chain_partitions: List of partitions to chain.
David Zeuthen21e95262016-07-27 17:58:40 -04003096 algorithm_name: Name of algorithm to use.
3097 key_path: Path to key to use or None.
David Zeuthen18666ab2016-11-15 11:18:05 -05003098 public_key_metadata_path: Path to public key metadata or None.
David Zeuthen21e95262016-07-27 17:58:40 -04003099 rollback_index: Rollback index.
David Zeuthena5fd3a42017-02-27 16:38:54 -05003100 flags: Flags value to use in the image.
David Zeuthen21e95262016-07-27 17:58:40 -04003101 props: Properties to insert (List of strings of the form 'key:value').
3102 props_from_file: Properties to insert (List of strings 'key:<path>').
3103 kernel_cmdlines: Kernel cmdlines to insert (list of strings).
David Zeuthen5d4f4f22017-01-11 11:37:34 -05003104 setup_rootfs_from_kernel: None or file to generate
David Zeuthen21e95262016-07-27 17:58:40 -04003105 dm-verity kernel cmdline from.
David Zeuthen73f2afa2017-05-17 16:54:11 -04003106 setup_as_rootfs_from_kernel: If True, generate dm-verity kernel
3107 cmdline to set up rootfs.
David Zeuthen21e95262016-07-27 17:58:40 -04003108 include_descriptors_from_image: List of file objects for which
3109 to insert descriptors from.
David Zeuthen09692692016-09-30 16:16:40 -04003110 calc_max_image_size: Don't store the hashtree or footer - instead
3111 calculate the maximum image size leaving enough room for hashtree
3112 and metadata with the given |partition_size|.
Dzmitry Yatsushkevich4e552792016-12-15 10:27:48 -08003113 signing_helper: Program which signs a hash and return signature.
David Zeuthena156d3d2017-06-01 12:08:09 -04003114 signing_helper_with_files: Same as signing_helper but uses files instead.
David Zeuthene3cadca2017-02-22 21:25:46 -05003115 release_string: None or avbtool release string.
3116 append_to_release_string: None or string to append.
David Zeuthend247fcb2017-02-16 12:09:27 -05003117 output_vbmeta_image: If not None, also write vbmeta struct to this file.
3118 do_not_append_vbmeta_image: If True, don't append vbmeta struct.
David Zeuthen1097a782017-05-31 15:53:17 -04003119 print_required_libavb_version: True to only print required libavb version.
Darren Krahnfd0ba0d2018-02-01 18:06:34 -08003120 use_persistent_root_digest: Use a persistent root digest on device.
3121 do_not_use_ab: The partition does not use A/B.
David Zeuthena4fee8b2016-08-22 15:20:43 -04003122
3123 Raises:
3124 AvbError: If an argument is incorrect.
David Zeuthen21e95262016-07-27 17:58:40 -04003125 """
David Zeuthen1097a782017-05-31 15:53:17 -04003126
Darren Krahnfd0ba0d2018-02-01 18:06:34 -08003127 required_libavb_version_minor = 0
3128 if use_persistent_root_digest or do_not_use_ab:
3129 required_libavb_version_minor = 1
3130
David Zeuthen1097a782017-05-31 15:53:17 -04003131 # If we're asked to calculate minimum required libavb version, we're done.
David Zeuthen1097a782017-05-31 15:53:17 -04003132 if print_required_libavb_version:
Darren Krahnfd0ba0d2018-02-01 18:06:34 -08003133 print '1.{}'.format(required_libavb_version_minor)
David Zeuthen1097a782017-05-31 15:53:17 -04003134 return
3135
David Zeuthen09692692016-09-30 16:16:40 -04003136 digest_size = len(hashlib.new(name=hash_algorithm).digest())
3137 digest_padding = round_to_pow2(digest_size) - digest_size
3138
3139 # First, calculate the maximum image size such that an image
3140 # this size + the hashtree + metadata (footer + vbmeta struct)
3141 # fits in |partition_size|. We use very conservative figures for
3142 # metadata.
3143 (_, max_tree_size) = calc_hash_level_offsets(
3144 partition_size, block_size, digest_size + digest_padding)
David Zeuthen0b7f1d32016-10-25 17:53:49 -04003145 max_fec_size = 0
3146 if generate_fec:
3147 max_fec_size = calc_fec_data_size(partition_size, fec_num_roots)
3148 max_metadata_size = (max_fec_size + max_tree_size +
3149 self.MAX_VBMETA_SIZE +
David Zeuthen09692692016-09-30 16:16:40 -04003150 self.MAX_FOOTER_SIZE)
3151 max_image_size = partition_size - max_metadata_size
3152
3153 # If we're asked to only calculate the maximum image size, we're done.
3154 if calc_max_image_size:
3155 print '{}'.format(max_image_size)
3156 return
3157
David Zeuthena4fee8b2016-08-22 15:20:43 -04003158 image = ImageHandler(image_filename)
3159
3160 if partition_size % image.block_size != 0:
3161 raise AvbError('Partition size of {} is not a multiple of the image '
3162 'block size {}.'.format(partition_size,
3163 image.block_size))
3164
David Zeuthen21e95262016-07-27 17:58:40 -04003165 # If there's already a footer, truncate the image to its original
3166 # size. This way 'avbtool add_hashtree_footer' is idempotent
3167 # (modulo salts).
Lonnie Liu6b5a33e2017-10-31 18:01:09 -07003168 if image.image_size >= AvbFooter.SIZE:
3169 image.seek(image.image_size - AvbFooter.SIZE)
3170 try:
3171 footer = AvbFooter(image.read(AvbFooter.SIZE))
3172 # Existing footer found. Just truncate.
3173 original_image_size = footer.original_image_size
3174 image.truncate(footer.original_image_size)
3175 except (LookupError, struct.error):
3176 original_image_size = image.image_size
3177 else:
3178 # Image size is too small to possibly contain a footer.
David Zeuthen09692692016-09-30 16:16:40 -04003179 original_image_size = image.image_size
David Zeuthen21e95262016-07-27 17:58:40 -04003180
3181 # If anything goes wrong from here-on, restore the image back to
3182 # its original size.
3183 try:
3184 # Ensure image is multiple of block_size.
David Zeuthen09692692016-09-30 16:16:40 -04003185 rounded_image_size = round_to_multiple(image.image_size, block_size)
3186 if rounded_image_size > image.image_size:
3187 image.append_raw('\0' * (rounded_image_size - image.image_size))
David Zeuthen21e95262016-07-27 17:58:40 -04003188
David Zeuthen09692692016-09-30 16:16:40 -04003189 # If image size exceeds the maximum image size, fail.
3190 if image.image_size > max_image_size:
3191 raise AvbError('Image size of {} exceeds maximum image '
3192 'size of {} in order to fit in a partition '
3193 'size of {}.'.format(image.image_size, max_image_size,
3194 partition_size))
David Zeuthen21e95262016-07-27 17:58:40 -04003195
3196 if salt:
3197 salt = salt.decode('hex')
3198 else:
3199 if salt is None:
3200 # If salt is not explicitly specified, choose a hash
3201 # that's the same size as the hash size.
3202 hash_size = digest_size
3203 salt = open('/dev/urandom').read(hash_size)
3204 else:
3205 salt = ''
3206
David Zeuthena4fee8b2016-08-22 15:20:43 -04003207 # Hashes are stored upside down so we need to calculate hash
David Zeuthen21e95262016-07-27 17:58:40 -04003208 # offsets in advance.
3209 (hash_level_offsets, tree_size) = calc_hash_level_offsets(
David Zeuthen09692692016-09-30 16:16:40 -04003210 image.image_size, block_size, digest_size + digest_padding)
David Zeuthen21e95262016-07-27 17:58:40 -04003211
David Zeuthena4fee8b2016-08-22 15:20:43 -04003212 # If the image isn't sparse, its size might not be a multiple of
3213 # the block size. This will screw up padding later so just grow it.
David Zeuthen09692692016-09-30 16:16:40 -04003214 if image.image_size % image.block_size != 0:
David Zeuthena4fee8b2016-08-22 15:20:43 -04003215 assert not image.is_sparse
David Zeuthen09692692016-09-30 16:16:40 -04003216 padding_needed = image.block_size - (image.image_size%image.block_size)
3217 image.truncate(image.image_size + padding_needed)
David Zeuthen21e95262016-07-27 17:58:40 -04003218
David Zeuthena4fee8b2016-08-22 15:20:43 -04003219 # Generate the tree and add padding as needed.
David Zeuthen09692692016-09-30 16:16:40 -04003220 tree_offset = image.image_size
3221 root_digest, hash_tree = generate_hash_tree(image, image.image_size,
David Zeuthena4fee8b2016-08-22 15:20:43 -04003222 block_size,
3223 hash_algorithm, salt,
3224 digest_padding,
3225 hash_level_offsets,
3226 tree_size)
David Zeuthena4fee8b2016-08-22 15:20:43 -04003227
3228 # Generate HashtreeDescriptor with details about the tree we
3229 # just generated.
David Zeuthen21e95262016-07-27 17:58:40 -04003230 ht_desc = AvbHashtreeDescriptor()
3231 ht_desc.dm_verity_version = 1
David Zeuthen09692692016-09-30 16:16:40 -04003232 ht_desc.image_size = image.image_size
David Zeuthen21e95262016-07-27 17:58:40 -04003233 ht_desc.tree_offset = tree_offset
3234 ht_desc.tree_size = tree_size
3235 ht_desc.data_block_size = block_size
3236 ht_desc.hash_block_size = block_size
3237 ht_desc.hash_algorithm = hash_algorithm
3238 ht_desc.partition_name = partition_name
3239 ht_desc.salt = salt
Darren Krahnfd0ba0d2018-02-01 18:06:34 -08003240 if do_not_use_ab:
3241 ht_desc.flags |= 1 # AVB_HASHTREE_DESCRIPTOR_FLAGS_DO_NOT_USE_AB
3242 if not use_persistent_root_digest:
3243 ht_desc.root_digest = root_digest
David Zeuthen21e95262016-07-27 17:58:40 -04003244
David Zeuthen09692692016-09-30 16:16:40 -04003245 # Write the hash tree
3246 padding_needed = (round_to_multiple(len(hash_tree), image.block_size) -
3247 len(hash_tree))
3248 hash_tree_with_padding = hash_tree + '\0'*padding_needed
3249 image.append_raw(hash_tree_with_padding)
David Zeuthen0b7f1d32016-10-25 17:53:49 -04003250 len_hashtree_and_fec = len(hash_tree_with_padding)
3251
3252 # Generate FEC codes, if requested.
3253 if generate_fec:
3254 fec_data = generate_fec_data(image_filename, fec_num_roots)
3255 padding_needed = (round_to_multiple(len(fec_data), image.block_size) -
3256 len(fec_data))
3257 fec_data_with_padding = fec_data + '\0'*padding_needed
3258 fec_offset = image.image_size
3259 image.append_raw(fec_data_with_padding)
3260 len_hashtree_and_fec += len(fec_data_with_padding)
3261 # Update the hashtree descriptor.
3262 ht_desc.fec_num_roots = fec_num_roots
3263 ht_desc.fec_offset = fec_offset
3264 ht_desc.fec_size = len(fec_data)
David Zeuthen09692692016-09-30 16:16:40 -04003265
David Zeuthen73f2afa2017-05-17 16:54:11 -04003266 ht_desc_to_setup = None
3267 if setup_as_rootfs_from_kernel:
3268 ht_desc_to_setup = ht_desc
3269
David Zeuthena4fee8b2016-08-22 15:20:43 -04003270 # Generate the VBMeta footer and add padding as needed.
David Zeuthen0b7f1d32016-10-25 17:53:49 -04003271 vbmeta_offset = tree_offset + len_hashtree_and_fec
David Zeuthen21e95262016-07-27 17:58:40 -04003272 vbmeta_blob = self._generate_vbmeta_blob(
David Zeuthen18666ab2016-11-15 11:18:05 -05003273 algorithm_name, key_path, public_key_metadata_path, [ht_desc],
David Zeuthena5fd3a42017-02-27 16:38:54 -05003274 chain_partitions, rollback_index, flags, props, props_from_file,
David Zeuthen73f2afa2017-05-17 16:54:11 -04003275 kernel_cmdlines, setup_rootfs_from_kernel, ht_desc_to_setup,
David Zeuthena156d3d2017-06-01 12:08:09 -04003276 include_descriptors_from_image, signing_helper,
3277 signing_helper_with_files, release_string,
Darren Krahnfd0ba0d2018-02-01 18:06:34 -08003278 append_to_release_string, required_libavb_version_minor)
David Zeuthena4fee8b2016-08-22 15:20:43 -04003279 padding_needed = (round_to_multiple(len(vbmeta_blob), image.block_size) -
3280 len(vbmeta_blob))
3281 vbmeta_blob_with_padding = vbmeta_blob + '\0'*padding_needed
David Zeuthen21e95262016-07-27 17:58:40 -04003282
David Zeuthend247fcb2017-02-16 12:09:27 -05003283 # Write vbmeta blob, if requested.
3284 if output_vbmeta_image:
3285 output_vbmeta_image.write(vbmeta_blob)
David Zeuthen21e95262016-07-27 17:58:40 -04003286
David Zeuthend247fcb2017-02-16 12:09:27 -05003287 # Append vbmeta blob and footer, unless requested not to.
3288 if not do_not_append_vbmeta_image:
3289 image.append_raw(vbmeta_blob_with_padding)
3290
3291 # Now insert a DONT_CARE chunk with enough bytes such that the
3292 # final Footer block is at the end of partition_size..
3293 image.append_dont_care(partition_size - image.image_size -
3294 1*image.block_size)
3295
3296 # Generate the Footer that tells where the VBMeta footer
3297 # is. Also put enough padding in the front of the footer since
3298 # we'll write out an entire block.
3299 footer = AvbFooter()
3300 footer.original_image_size = original_image_size
3301 footer.vbmeta_offset = vbmeta_offset
3302 footer.vbmeta_size = len(vbmeta_blob)
3303 footer_blob = footer.encode()
3304 footer_blob_with_padding = ('\0'*(image.block_size - AvbFooter.SIZE) +
3305 footer_blob)
3306 image.append_raw(footer_blob_with_padding)
David Zeuthena4fee8b2016-08-22 15:20:43 -04003307
David Zeuthen21e95262016-07-27 17:58:40 -04003308 except:
David Zeuthen09692692016-09-30 16:16:40 -04003309 # Truncate back to original size, then re-raise.
David Zeuthen21e95262016-07-27 17:58:40 -04003310 image.truncate(original_image_size)
3311 raise
3312
David Zeuthenc68f0822017-03-31 17:22:35 -04003313 def make_atx_certificate(self, output, authority_key_path, subject_key_path,
Darren Krahn147b08d2016-12-20 16:38:29 -08003314 subject_key_version, subject,
Darren Krahnfccd64e2018-01-16 17:39:35 -08003315 is_intermediate_authority, usage, signing_helper,
David Zeuthena156d3d2017-06-01 12:08:09 -04003316 signing_helper_with_files):
Darren Krahn147b08d2016-12-20 16:38:29 -08003317 """Implements the 'make_atx_certificate' command.
3318
3319 Android Things certificates are required for Android Things public key
3320 metadata. They chain the vbmeta signing key for a particular product back to
3321 a fused, permanent root key. These certificates are fixed-length and fixed-
3322 format with the explicit goal of not parsing ASN.1 in bootloader code.
3323
3324 Arguments:
3325 output: Certificate will be written to this file on success.
3326 authority_key_path: A PEM file path with the authority private key.
3327 If None, then a certificate will be created without a
3328 signature. The signature can be created out-of-band
3329 and appended.
David Zeuthenc68f0822017-03-31 17:22:35 -04003330 subject_key_path: Path to a PEM or DER subject public key.
Darren Krahn147b08d2016-12-20 16:38:29 -08003331 subject_key_version: A 64-bit version value. If this is None, the number
3332 of seconds since the epoch is used.
3333 subject: A subject identifier. For Product Signing Key certificates this
3334 should be the same Product ID found in the permanent attributes.
3335 is_intermediate_authority: True if the certificate is for an intermediate
3336 authority.
Darren Krahnfccd64e2018-01-16 17:39:35 -08003337 usage: If not empty, overrides the cert usage with a hash of this value.
Darren Krahn147b08d2016-12-20 16:38:29 -08003338 signing_helper: Program which signs a hash and returns the signature.
David Zeuthena156d3d2017-06-01 12:08:09 -04003339 signing_helper_with_files: Same as signing_helper but uses files instead.
Darren Krahn147b08d2016-12-20 16:38:29 -08003340 """
3341 signed_data = bytearray()
3342 signed_data.extend(struct.pack('<I', 1)) # Format Version
David Zeuthenc68f0822017-03-31 17:22:35 -04003343 signed_data.extend(encode_rsa_key(subject_key_path))
Darren Krahn147b08d2016-12-20 16:38:29 -08003344 hasher = hashlib.sha256()
3345 hasher.update(subject)
3346 signed_data.extend(hasher.digest())
Darren Krahnfccd64e2018-01-16 17:39:35 -08003347 if not usage:
3348 usage = 'com.google.android.things.vboot'
3349 if is_intermediate_authority:
3350 usage += '.ca'
Darren Krahn147b08d2016-12-20 16:38:29 -08003351 hasher = hashlib.sha256()
3352 hasher.update(usage)
3353 signed_data.extend(hasher.digest())
3354 if not subject_key_version:
3355 subject_key_version = int(time.time())
3356 signed_data.extend(struct.pack('<Q', subject_key_version))
3357 signature = bytearray()
3358 if authority_key_path:
3359 padding_and_hash = bytearray()
Darren Krahn43e12d82017-02-24 16:26:31 -08003360 algorithm_name = 'SHA512_RSA4096'
Esun Kimff44f232017-03-30 10:34:54 +09003361 alg = ALGORITHMS[algorithm_name]
Darren Krahn43e12d82017-02-24 16:26:31 -08003362 hasher = hashlib.sha512()
Esun Kimff44f232017-03-30 10:34:54 +09003363 padding_and_hash.extend(alg.padding)
Darren Krahn147b08d2016-12-20 16:38:29 -08003364 hasher.update(signed_data)
3365 padding_and_hash.extend(hasher.digest())
David Zeuthena156d3d2017-06-01 12:08:09 -04003366 signature.extend(raw_sign(signing_helper, signing_helper_with_files,
3367 algorithm_name,
Esun Kimff44f232017-03-30 10:34:54 +09003368 alg.signature_num_bytes, authority_key_path,
3369 padding_and_hash))
Darren Krahn147b08d2016-12-20 16:38:29 -08003370 output.write(signed_data)
3371 output.write(signature)
3372
David Zeuthenc68f0822017-03-31 17:22:35 -04003373 def make_atx_permanent_attributes(self, output, root_authority_key_path,
Darren Krahn147b08d2016-12-20 16:38:29 -08003374 product_id):
3375 """Implements the 'make_atx_permanent_attributes' command.
3376
3377 Android Things permanent attributes are designed to be permanent for a
3378 particular product and a hash of these attributes should be fused into
3379 hardware to enforce this.
3380
3381 Arguments:
3382 output: Attributes will be written to this file on success.
David Zeuthenc68f0822017-03-31 17:22:35 -04003383 root_authority_key_path: Path to a PEM or DER public key for
3384 the root authority.
Darren Krahn147b08d2016-12-20 16:38:29 -08003385 product_id: A 16-byte Product ID.
3386
3387 Raises:
3388 AvbError: If an argument is incorrect.
3389 """
Darren Krahn43e12d82017-02-24 16:26:31 -08003390 EXPECTED_PRODUCT_ID_SIZE = 16
3391 if len(product_id) != EXPECTED_PRODUCT_ID_SIZE:
Darren Krahn147b08d2016-12-20 16:38:29 -08003392 raise AvbError('Invalid Product ID length.')
3393 output.write(struct.pack('<I', 1)) # Format Version
David Zeuthenc68f0822017-03-31 17:22:35 -04003394 output.write(encode_rsa_key(root_authority_key_path))
Darren Krahn147b08d2016-12-20 16:38:29 -08003395 output.write(product_id)
3396
3397 def make_atx_metadata(self, output, intermediate_key_certificate,
Darren Krahn43e12d82017-02-24 16:26:31 -08003398 product_key_certificate):
Darren Krahn147b08d2016-12-20 16:38:29 -08003399 """Implements the 'make_atx_metadata' command.
3400
3401 Android Things metadata are included in vbmeta images to facilitate
3402 verification. The output of this command can be used as the
3403 public_key_metadata argument to other commands.
3404
3405 Arguments:
3406 output: Metadata will be written to this file on success.
3407 intermediate_key_certificate: A certificate file as output by
3408 make_atx_certificate with
3409 is_intermediate_authority set to true.
3410 product_key_certificate: A certificate file as output by
3411 make_atx_certificate with
3412 is_intermediate_authority set to false.
Darren Krahn147b08d2016-12-20 16:38:29 -08003413
3414 Raises:
3415 AvbError: If an argument is incorrect.
3416 """
Darren Krahn43e12d82017-02-24 16:26:31 -08003417 EXPECTED_CERTIFICATE_SIZE = 1620
3418 if len(intermediate_key_certificate) != EXPECTED_CERTIFICATE_SIZE:
Darren Krahn147b08d2016-12-20 16:38:29 -08003419 raise AvbError('Invalid intermediate key certificate length.')
Darren Krahn43e12d82017-02-24 16:26:31 -08003420 if len(product_key_certificate) != EXPECTED_CERTIFICATE_SIZE:
Darren Krahn147b08d2016-12-20 16:38:29 -08003421 raise AvbError('Invalid product key certificate length.')
3422 output.write(struct.pack('<I', 1)) # Format Version
3423 output.write(intermediate_key_certificate)
3424 output.write(product_key_certificate)
Darren Krahn147b08d2016-12-20 16:38:29 -08003425
Darren Krahnfccd64e2018-01-16 17:39:35 -08003426 def make_atx_unlock_credential(self, output, intermediate_key_certificate,
3427 unlock_key_certificate, challenge_path,
3428 unlock_key_path, signing_helper,
3429 signing_helper_with_files):
3430 """Implements the 'make_atx_unlock_credential' command.
3431
3432 Android Things unlock credentials can be used to authorize the unlock of AVB
3433 on a device. These credentials are presented to an Android Things bootloader
3434 via the fastboot interface in response to a 16-byte challenge. This method
3435 creates all fields of the credential except the challenge signature field
3436 (which is the last field) and can optionally create the challenge signature
3437 field as well if a challenge and the unlock_key_path is provided.
3438
3439 Arguments:
3440 output: The credential will be written to this file on success.
3441 intermediate_key_certificate: A certificate file as output by
3442 make_atx_certificate with
3443 is_intermediate_authority set to true.
3444 unlock_key_certificate: A certificate file as output by
3445 make_atx_certificate with
3446 is_intermediate_authority set to false and the
3447 usage set to
3448 'com.google.android.things.vboot.unlock'.
3449 challenge_path: [optional] A path to the challenge to sign.
3450 unlock_key_path: [optional] A PEM file path with the unlock private key.
3451 signing_helper: Program which signs a hash and returns the signature.
3452 signing_helper_with_files: Same as signing_helper but uses files instead.
3453
3454 Raises:
3455 AvbError: If an argument is incorrect.
3456 """
3457 EXPECTED_CERTIFICATE_SIZE = 1620
3458 EXPECTED_CHALLENGE_SIZE = 16
3459 if len(intermediate_key_certificate) != EXPECTED_CERTIFICATE_SIZE:
3460 raise AvbError('Invalid intermediate key certificate length.')
3461 if len(unlock_key_certificate) != EXPECTED_CERTIFICATE_SIZE:
3462 raise AvbError('Invalid product key certificate length.')
3463 challenge = bytearray()
3464 if challenge_path:
3465 with open(challenge_path, 'r') as f:
3466 challenge = f.read()
3467 if len(challenge) != EXPECTED_CHALLENGE_SIZE:
3468 raise AvbError('Invalid unlock challenge length.')
3469 output.write(struct.pack('<I', 1)) # Format Version
3470 output.write(intermediate_key_certificate)
3471 output.write(unlock_key_certificate)
3472 if challenge_path and unlock_key_path:
3473 signature = bytearray()
3474 padding_and_hash = bytearray()
3475 algorithm_name = 'SHA512_RSA4096'
3476 alg = ALGORITHMS[algorithm_name]
3477 hasher = hashlib.sha512()
3478 padding_and_hash.extend(alg.padding)
3479 hasher.update(challenge)
3480 padding_and_hash.extend(hasher.digest())
3481 signature.extend(raw_sign(signing_helper, signing_helper_with_files,
3482 algorithm_name,
3483 alg.signature_num_bytes, unlock_key_path,
3484 padding_and_hash))
3485 output.write(signature)
3486
David Zeuthen21e95262016-07-27 17:58:40 -04003487
3488def calc_hash_level_offsets(image_size, block_size, digest_size):
3489 """Calculate the offsets of all the hash-levels in a Merkle-tree.
3490
3491 Arguments:
3492 image_size: The size of the image to calculate a Merkle-tree for.
3493 block_size: The block size, e.g. 4096.
3494 digest_size: The size of each hash, e.g. 32 for SHA-256.
3495
3496 Returns:
3497 A tuple where the first argument is an array of offsets and the
3498 second is size of the tree, in bytes.
3499 """
3500 level_offsets = []
3501 level_sizes = []
3502 tree_size = 0
3503
3504 num_levels = 0
3505 size = image_size
3506 while size > block_size:
3507 num_blocks = (size + block_size - 1) / block_size
3508 level_size = round_to_multiple(num_blocks * digest_size, block_size)
3509
3510 level_sizes.append(level_size)
3511 tree_size += level_size
3512 num_levels += 1
3513
3514 size = level_size
3515
3516 for n in range(0, num_levels):
3517 offset = 0
3518 for m in range(n + 1, num_levels):
3519 offset += level_sizes[m]
3520 level_offsets.append(offset)
3521
David Zeuthena4fee8b2016-08-22 15:20:43 -04003522 return level_offsets, tree_size
David Zeuthen21e95262016-07-27 17:58:40 -04003523
3524
David Zeuthen0b7f1d32016-10-25 17:53:49 -04003525# See system/extras/libfec/include/fec/io.h for these definitions.
3526FEC_FOOTER_FORMAT = '<LLLLLQ32s'
3527FEC_MAGIC = 0xfecfecfe
3528
3529
3530def calc_fec_data_size(image_size, num_roots):
3531 """Calculates how much space FEC data will take.
3532
3533 Args:
3534 image_size: The size of the image.
3535 num_roots: Number of roots.
3536
3537 Returns:
3538 The number of bytes needed for FEC for an image of the given size
3539 and with the requested number of FEC roots.
3540
3541 Raises:
3542 ValueError: If output from the 'fec' tool is invalid.
3543
3544 """
3545 p = subprocess.Popen(
3546 ['fec', '--print-fec-size', str(image_size), '--roots', str(num_roots)],
3547 stdout=subprocess.PIPE,
3548 stderr=subprocess.PIPE)
3549 (pout, perr) = p.communicate()
3550 retcode = p.wait()
3551 if retcode != 0:
3552 raise ValueError('Error invoking fec: {}'.format(perr))
3553 return int(pout)
3554
3555
3556def generate_fec_data(image_filename, num_roots):
3557 """Generate FEC codes for an image.
3558
3559 Args:
3560 image_filename: The filename of the image.
3561 num_roots: Number of roots.
3562
3563 Returns:
3564 The FEC data blob.
3565
3566 Raises:
3567 ValueError: If output from the 'fec' tool is invalid.
3568 """
3569 fec_tmpfile = tempfile.NamedTemporaryFile()
3570 subprocess.check_call(
3571 ['fec', '--encode', '--roots', str(num_roots), image_filename,
3572 fec_tmpfile.name],
3573 stderr=open(os.devnull))
3574 fec_data = fec_tmpfile.read()
3575 footer_size = struct.calcsize(FEC_FOOTER_FORMAT)
3576 footer_data = fec_data[-footer_size:]
3577 (magic, _, _, num_roots, fec_size, _, _) = struct.unpack(FEC_FOOTER_FORMAT,
3578 footer_data)
3579 if magic != FEC_MAGIC:
3580 raise ValueError('Unexpected magic in FEC footer')
3581 return fec_data[0:fec_size]
3582
3583
David Zeuthen21e95262016-07-27 17:58:40 -04003584def generate_hash_tree(image, image_size, block_size, hash_alg_name, salt,
David Zeuthena4fee8b2016-08-22 15:20:43 -04003585 digest_padding, hash_level_offsets, tree_size):
David Zeuthen21e95262016-07-27 17:58:40 -04003586 """Generates a Merkle-tree for a file.
3587
3588 Args:
3589 image: The image, as a file.
3590 image_size: The size of the image.
3591 block_size: The block size, e.g. 4096.
3592 hash_alg_name: The hash algorithm, e.g. 'sha256' or 'sha1'.
3593 salt: The salt to use.
3594 digest_padding: The padding for each digest.
David Zeuthen21e95262016-07-27 17:58:40 -04003595 hash_level_offsets: The offsets from calc_hash_level_offsets().
David Zeuthena4fee8b2016-08-22 15:20:43 -04003596 tree_size: The size of the tree, in number of bytes.
David Zeuthen21e95262016-07-27 17:58:40 -04003597
3598 Returns:
David Zeuthena4fee8b2016-08-22 15:20:43 -04003599 A tuple where the first element is the top-level hash and the
3600 second element is the hash-tree.
David Zeuthen21e95262016-07-27 17:58:40 -04003601 """
David Zeuthena4fee8b2016-08-22 15:20:43 -04003602 hash_ret = bytearray(tree_size)
David Zeuthen21e95262016-07-27 17:58:40 -04003603 hash_src_offset = 0
3604 hash_src_size = image_size
3605 level_num = 0
3606 while hash_src_size > block_size:
3607 level_output = ''
David Zeuthen21e95262016-07-27 17:58:40 -04003608 remaining = hash_src_size
3609 while remaining > 0:
3610 hasher = hashlib.new(name=hash_alg_name, string=salt)
David Zeuthena4fee8b2016-08-22 15:20:43 -04003611 # Only read from the file for the first level - for subsequent
3612 # levels, access the array we're building.
3613 if level_num == 0:
3614 image.seek(hash_src_offset + hash_src_size - remaining)
3615 data = image.read(min(remaining, block_size))
3616 else:
3617 offset = hash_level_offsets[level_num - 1] + hash_src_size - remaining
3618 data = hash_ret[offset:offset + block_size]
David Zeuthen21e95262016-07-27 17:58:40 -04003619 hasher.update(data)
David Zeuthena4fee8b2016-08-22 15:20:43 -04003620
3621 remaining -= len(data)
David Zeuthen21e95262016-07-27 17:58:40 -04003622 if len(data) < block_size:
3623 hasher.update('\0' * (block_size - len(data)))
3624 level_output += hasher.digest()
3625 if digest_padding > 0:
3626 level_output += '\0' * digest_padding
3627
3628 padding_needed = (round_to_multiple(
3629 len(level_output), block_size) - len(level_output))
3630 level_output += '\0' * padding_needed
3631
David Zeuthena4fee8b2016-08-22 15:20:43 -04003632 # Copy level-output into resulting tree.
3633 offset = hash_level_offsets[level_num]
3634 hash_ret[offset:offset + len(level_output)] = level_output
David Zeuthen21e95262016-07-27 17:58:40 -04003635
David Zeuthena4fee8b2016-08-22 15:20:43 -04003636 # Continue on to the next level.
David Zeuthen21e95262016-07-27 17:58:40 -04003637 hash_src_size = len(level_output)
David Zeuthen21e95262016-07-27 17:58:40 -04003638 level_num += 1
3639
3640 hasher = hashlib.new(name=hash_alg_name, string=salt)
3641 hasher.update(level_output)
David Zeuthena4fee8b2016-08-22 15:20:43 -04003642 return hasher.digest(), hash_ret
David Zeuthen21e95262016-07-27 17:58:40 -04003643
3644
3645class AvbTool(object):
3646 """Object for avbtool command-line tool."""
3647
3648 def __init__(self):
3649 """Initializer method."""
3650 self.avb = Avb()
3651
3652 def _add_common_args(self, sub_parser):
3653 """Adds arguments used by several sub-commands.
3654
3655 Arguments:
3656 sub_parser: The parser to add arguments to.
3657 """
3658 sub_parser.add_argument('--algorithm',
3659 help='Algorithm to use (default: NONE)',
3660 metavar='ALGORITHM',
3661 default='NONE')
3662 sub_parser.add_argument('--key',
3663 help='Path to RSA private key file',
3664 metavar='KEY',
3665 required=False)
Dzmitry Yatsushkevich4e552792016-12-15 10:27:48 -08003666 sub_parser.add_argument('--signing_helper',
3667 help='Path to helper used for signing',
3668 metavar='APP',
3669 default=None,
3670 required=False)
David Zeuthena156d3d2017-06-01 12:08:09 -04003671 sub_parser.add_argument('--signing_helper_with_files',
3672 help='Path to helper used for signing using files',
3673 metavar='APP',
3674 default=None,
3675 required=False)
David Zeuthen18666ab2016-11-15 11:18:05 -05003676 sub_parser.add_argument('--public_key_metadata',
3677 help='Path to public key metadata file',
3678 metavar='KEY_METADATA',
3679 required=False)
David Zeuthen21e95262016-07-27 17:58:40 -04003680 sub_parser.add_argument('--rollback_index',
3681 help='Rollback Index',
3682 type=parse_number,
3683 default=0)
David Zeuthene3cadca2017-02-22 21:25:46 -05003684 # This is used internally for unit tests. Do not include in --help output.
3685 sub_parser.add_argument('--internal_release_string',
3686 help=argparse.SUPPRESS)
3687 sub_parser.add_argument('--append_to_release_string',
3688 help='Text to append to release string',
3689 metavar='STR')
David Zeuthen21e95262016-07-27 17:58:40 -04003690 sub_parser.add_argument('--prop',
3691 help='Add property',
3692 metavar='KEY:VALUE',
3693 action='append')
3694 sub_parser.add_argument('--prop_from_file',
3695 help='Add property from file',
3696 metavar='KEY:PATH',
3697 action='append')
3698 sub_parser.add_argument('--kernel_cmdline',
3699 help='Add kernel cmdline',
3700 metavar='CMDLINE',
3701 action='append')
David Zeuthen5d4f4f22017-01-11 11:37:34 -05003702 # TODO(zeuthen): the --setup_rootfs_from_kernel option used to be called
3703 # --generate_dm_verity_cmdline_from_hashtree. Remove support for the latter
3704 # at some future point.
3705 sub_parser.add_argument('--setup_rootfs_from_kernel',
3706 '--generate_dm_verity_cmdline_from_hashtree',
David Zeuthen21e95262016-07-27 17:58:40 -04003707 metavar='IMAGE',
David Zeuthen5d4f4f22017-01-11 11:37:34 -05003708 help='Adds kernel cmdline to set up IMAGE',
David Zeuthen21e95262016-07-27 17:58:40 -04003709 type=argparse.FileType('rb'))
3710 sub_parser.add_argument('--include_descriptors_from_image',
3711 help='Include descriptors from image',
3712 metavar='IMAGE',
3713 action='append',
3714 type=argparse.FileType('rb'))
David Zeuthen1097a782017-05-31 15:53:17 -04003715 sub_parser.add_argument('--print_required_libavb_version',
3716 help=('Don\'t store the footer - '
3717 'instead calculate the required libavb '
3718 'version for the given options.'),
3719 action='store_true')
David Zeuthena5fd3a42017-02-27 16:38:54 -05003720 # These are only allowed from top-level vbmeta and boot-in-lieu-of-vbmeta.
3721 sub_parser.add_argument('--chain_partition',
3722 help='Allow signed integrity-data for partition',
3723 metavar='PART_NAME:ROLLBACK_SLOT:KEY_PATH',
3724 action='append')
3725 sub_parser.add_argument('--flags',
3726 help='VBMeta flags',
3727 type=parse_number,
3728 default=0)
3729 sub_parser.add_argument('--set_hashtree_disabled_flag',
3730 help='Set the HASHTREE_DISABLED flag',
3731 action='store_true')
3732
Darren Krahnfd0ba0d2018-02-01 18:06:34 -08003733 def _add_common_footer_args(self, sub_parser):
3734 """Adds arguments used by add_*_footer sub-commands.
3735
3736 Arguments:
3737 sub_parser: The parser to add arguments to.
3738 """
3739 sub_parser.add_argument('--use_persistent_digest',
3740 help='Use a persistent digest on device instead of '
3741 'storing the digest in the descriptor. This '
3742 'cannot be used with A/B so must be combined '
3743 'with --do_not_use_ab when an A/B suffix is '
3744 'expected at runtime.',
3745 action='store_true')
3746 sub_parser.add_argument('--do_not_use_ab',
3747 help='The partition does not use A/B even when an '
3748 'A/B suffix is present. This must not be used '
3749 'for vbmeta or chained partitions.',
3750 action='store_true')
3751
David Zeuthena5fd3a42017-02-27 16:38:54 -05003752 def _fixup_common_args(self, args):
3753 """Common fixups needed by subcommands.
3754
3755 Arguments:
3756 args: Arguments to modify.
3757
3758 Returns:
3759 The modified arguments.
3760 """
3761 if args.set_hashtree_disabled_flag:
3762 args.flags |= AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED
3763 return args
David Zeuthen21e95262016-07-27 17:58:40 -04003764
3765 def run(self, argv):
3766 """Command-line processor.
3767
3768 Arguments:
3769 argv: Pass sys.argv from main.
3770 """
3771 parser = argparse.ArgumentParser()
3772 subparsers = parser.add_subparsers(title='subcommands')
3773
3774 sub_parser = subparsers.add_parser('version',
3775 help='Prints version of avbtool.')
3776 sub_parser.set_defaults(func=self.version)
3777
3778 sub_parser = subparsers.add_parser('extract_public_key',
3779 help='Extract public key.')
3780 sub_parser.add_argument('--key',
3781 help='Path to RSA private key file',
3782 required=True)
3783 sub_parser.add_argument('--output',
3784 help='Output file name',
3785 type=argparse.FileType('wb'),
3786 required=True)
3787 sub_parser.set_defaults(func=self.extract_public_key)
3788
3789 sub_parser = subparsers.add_parser('make_vbmeta_image',
3790 help='Makes a vbmeta image.')
3791 sub_parser.add_argument('--output',
3792 help='Output file name',
David Zeuthen1097a782017-05-31 15:53:17 -04003793 type=argparse.FileType('wb'))
David Zeuthen97cb5802017-06-01 16:14:05 -04003794 sub_parser.add_argument('--padding_size',
3795 metavar='NUMBER',
3796 help='If non-zero, pads output with NUL bytes so '
3797 'its size is a multiple of NUMBER (default: 0)',
3798 type=parse_number,
3799 default=0)
David Zeuthen21e95262016-07-27 17:58:40 -04003800 self._add_common_args(sub_parser)
David Zeuthen21e95262016-07-27 17:58:40 -04003801 sub_parser.set_defaults(func=self.make_vbmeta_image)
3802
3803 sub_parser = subparsers.add_parser('add_hash_footer',
3804 help='Add hashes and footer to image.')
3805 sub_parser.add_argument('--image',
David Zeuthen8b6973b2016-09-20 12:39:49 -04003806 help='Image to add hashes to',
David Zeuthen21e95262016-07-27 17:58:40 -04003807 type=argparse.FileType('rab+'))
3808 sub_parser.add_argument('--partition_size',
3809 help='Partition size',
David Zeuthen1097a782017-05-31 15:53:17 -04003810 type=parse_number)
David Zeuthen21e95262016-07-27 17:58:40 -04003811 sub_parser.add_argument('--partition_name',
3812 help='Partition name',
David Zeuthenbf562452017-05-17 18:04:43 -04003813 default=None)
David Zeuthen21e95262016-07-27 17:58:40 -04003814 sub_parser.add_argument('--hash_algorithm',
3815 help='Hash algorithm to use (default: sha256)',
3816 default='sha256')
3817 sub_parser.add_argument('--salt',
3818 help='Salt in hex (default: /dev/urandom)')
David Zeuthenbf562452017-05-17 18:04:43 -04003819 sub_parser.add_argument('--calc_max_image_size',
3820 help=('Don\'t store the footer - '
3821 'instead calculate the maximum image size '
3822 'leaving enough room for metadata with '
3823 'the given partition size.'),
3824 action='store_true')
David Zeuthend247fcb2017-02-16 12:09:27 -05003825 sub_parser.add_argument('--output_vbmeta_image',
3826 help='Also write vbmeta struct to file',
3827 type=argparse.FileType('wb'))
3828 sub_parser.add_argument('--do_not_append_vbmeta_image',
3829 help=('Do not append vbmeta struct or footer '
3830 'to the image'),
3831 action='store_true')
David Zeuthen21e95262016-07-27 17:58:40 -04003832 self._add_common_args(sub_parser)
Darren Krahnfd0ba0d2018-02-01 18:06:34 -08003833 self._add_common_footer_args(sub_parser)
David Zeuthen21e95262016-07-27 17:58:40 -04003834 sub_parser.set_defaults(func=self.add_hash_footer)
3835
David Zeuthenb1b994d2017-03-06 18:01:31 -05003836 sub_parser = subparsers.add_parser('append_vbmeta_image',
3837 help='Append vbmeta image to image.')
3838 sub_parser.add_argument('--image',
3839 help='Image to append vbmeta blob to',
3840 type=argparse.FileType('rab+'))
3841 sub_parser.add_argument('--partition_size',
3842 help='Partition size',
3843 type=parse_number,
3844 required=True)
3845 sub_parser.add_argument('--vbmeta_image',
3846 help='Image with vbmeta blob to append',
3847 type=argparse.FileType('rb'))
3848 sub_parser.set_defaults(func=self.append_vbmeta_image)
3849
David Zeuthen21e95262016-07-27 17:58:40 -04003850 sub_parser = subparsers.add_parser('add_hashtree_footer',
3851 help='Add hashtree and footer to image.')
3852 sub_parser.add_argument('--image',
David Zeuthen8b6973b2016-09-20 12:39:49 -04003853 help='Image to add hashtree to',
David Zeuthen21e95262016-07-27 17:58:40 -04003854 type=argparse.FileType('rab+'))
3855 sub_parser.add_argument('--partition_size',
3856 help='Partition size',
David Zeuthen1097a782017-05-31 15:53:17 -04003857 type=parse_number)
David Zeuthen21e95262016-07-27 17:58:40 -04003858 sub_parser.add_argument('--partition_name',
3859 help='Partition name',
David Zeuthen09692692016-09-30 16:16:40 -04003860 default=None)
David Zeuthen21e95262016-07-27 17:58:40 -04003861 sub_parser.add_argument('--hash_algorithm',
3862 help='Hash algorithm to use (default: sha1)',
3863 default='sha1')
3864 sub_parser.add_argument('--salt',
3865 help='Salt in hex (default: /dev/urandom)')
3866 sub_parser.add_argument('--block_size',
3867 help='Block size (default: 4096)',
3868 type=parse_number,
3869 default=4096)
David Zeuthenbce9a292017-05-10 17:18:04 -04003870 # TODO(zeuthen): The --generate_fec option was removed when we
3871 # moved to generating FEC by default. To avoid breaking existing
3872 # users needing to transition we simply just print a warning below
3873 # in add_hashtree_footer(). Remove this option and the warning at
3874 # some point in the future.
David Zeuthen0b7f1d32016-10-25 17:53:49 -04003875 sub_parser.add_argument('--generate_fec',
David Zeuthenbce9a292017-05-10 17:18:04 -04003876 help=argparse.SUPPRESS,
3877 action='store_true')
3878 sub_parser.add_argument('--do_not_generate_fec',
3879 help='Do not generate forward-error-correction codes',
David Zeuthen0b7f1d32016-10-25 17:53:49 -04003880 action='store_true')
3881 sub_parser.add_argument('--fec_num_roots',
3882 help='Number of roots for FEC (default: 2)',
3883 type=parse_number,
3884 default=2)
David Zeuthen09692692016-09-30 16:16:40 -04003885 sub_parser.add_argument('--calc_max_image_size',
3886 help=('Don\'t store the hashtree or footer - '
3887 'instead calculate the maximum image size '
3888 'leaving enough room for hashtree '
3889 'and metadata with the given partition '
3890 'size.'),
3891 action='store_true')
David Zeuthend247fcb2017-02-16 12:09:27 -05003892 sub_parser.add_argument('--output_vbmeta_image',
3893 help='Also write vbmeta struct to file',
3894 type=argparse.FileType('wb'))
3895 sub_parser.add_argument('--do_not_append_vbmeta_image',
3896 help=('Do not append vbmeta struct or footer '
3897 'to the image'),
3898 action='store_true')
David Zeuthen73f2afa2017-05-17 16:54:11 -04003899 # This is different from --setup_rootfs_from_kernel insofar that
3900 # it doesn't take an IMAGE, the generated cmdline will be for the
3901 # hashtree we're adding.
3902 sub_parser.add_argument('--setup_as_rootfs_from_kernel',
3903 action='store_true',
3904 help='Adds kernel cmdline for setting up rootfs')
David Zeuthen21e95262016-07-27 17:58:40 -04003905 self._add_common_args(sub_parser)
Darren Krahnfd0ba0d2018-02-01 18:06:34 -08003906 self._add_common_footer_args(sub_parser)
David Zeuthen21e95262016-07-27 17:58:40 -04003907 sub_parser.set_defaults(func=self.add_hashtree_footer)
3908
3909 sub_parser = subparsers.add_parser('erase_footer',
3910 help='Erase footer from an image.')
3911 sub_parser.add_argument('--image',
David Zeuthen8b6973b2016-09-20 12:39:49 -04003912 help='Image with a footer',
David Zeuthen21e95262016-07-27 17:58:40 -04003913 type=argparse.FileType('rwb+'),
3914 required=True)
3915 sub_parser.add_argument('--keep_hashtree',
David Zeuthenfbb61fa2017-02-02 12:11:49 -05003916 help='Keep the hashtree and FEC in the image',
David Zeuthen21e95262016-07-27 17:58:40 -04003917 action='store_true')
3918 sub_parser.set_defaults(func=self.erase_footer)
3919
David Zeuthen49936b42018-08-07 17:38:58 -04003920 sub_parser = subparsers.add_parser('extract_vbmeta_image',
3921 help='Extracts vbmeta from an image with a footer.')
3922 sub_parser.add_argument('--image',
3923 help='Image with footer',
3924 type=argparse.FileType('rb'),
3925 required=True)
3926 sub_parser.add_argument('--output',
3927 help='Output file name',
3928 type=argparse.FileType('wb'))
3929 sub_parser.add_argument('--padding_size',
3930 metavar='NUMBER',
3931 help='If non-zero, pads output with NUL bytes so '
3932 'its size is a multiple of NUMBER (default: 0)',
3933 type=parse_number,
3934 default=0)
3935 sub_parser.set_defaults(func=self.extract_vbmeta_image)
3936
David Zeuthen2bc232b2017-04-19 14:25:19 -04003937 sub_parser = subparsers.add_parser('resize_image',
3938 help='Resize image with a footer.')
3939 sub_parser.add_argument('--image',
3940 help='Image with a footer',
3941 type=argparse.FileType('rwb+'),
3942 required=True)
3943 sub_parser.add_argument('--partition_size',
3944 help='New partition size',
3945 type=parse_number)
3946 sub_parser.set_defaults(func=self.resize_image)
3947
David Zeuthen21e95262016-07-27 17:58:40 -04003948 sub_parser = subparsers.add_parser(
3949 'info_image',
3950 help='Show information about vbmeta or footer.')
3951 sub_parser.add_argument('--image',
David Zeuthen8b6973b2016-09-20 12:39:49 -04003952 help='Image to show information about',
David Zeuthen21e95262016-07-27 17:58:40 -04003953 type=argparse.FileType('rb'),
3954 required=True)
3955 sub_parser.add_argument('--output',
3956 help='Write info to file',
3957 type=argparse.FileType('wt'),
3958 default=sys.stdout)
3959 sub_parser.set_defaults(func=self.info_image)
3960
David Zeuthenb623d8b2017-04-04 16:05:53 -04003961 sub_parser = subparsers.add_parser(
3962 'verify_image',
3963 help='Verify an image.')
3964 sub_parser.add_argument('--image',
3965 help='Image to verify',
3966 type=argparse.FileType('rb'),
3967 required=True)
David Zeuthen5dfb4e92017-05-24 14:49:32 -04003968 sub_parser.add_argument('--key',
3969 help='Check embedded public key matches KEY',
3970 metavar='KEY',
3971 required=False)
3972 sub_parser.add_argument('--expected_chain_partition',
3973 help='Expected chain partition',
3974 metavar='PART_NAME:ROLLBACK_SLOT:KEY_PATH',
3975 action='append')
David Zeuthenb623d8b2017-04-04 16:05:53 -04003976 sub_parser.set_defaults(func=self.verify_image)
3977
David Zeuthenb8643c02018-05-17 17:21:18 -04003978 sub_parser = subparsers.add_parser(
3979 'calculate_vbmeta_digest',
3980 help='Calculate vbmeta digest.')
3981 sub_parser.add_argument('--image',
3982 help='Image to calculate digest for',
3983 type=argparse.FileType('rb'),
3984 required=True)
3985 sub_parser.add_argument('--hash_algorithm',
3986 help='Hash algorithm to use (default: sha256)',
3987 default='sha256')
3988 sub_parser.add_argument('--output',
3989 help='Write hex digest to file (default: stdout)',
3990 type=argparse.FileType('wt'),
3991 default=sys.stdout)
3992 sub_parser.set_defaults(func=self.calculate_vbmeta_digest)
3993
David Zeuthen8b6973b2016-09-20 12:39:49 -04003994 sub_parser = subparsers.add_parser('set_ab_metadata',
3995 help='Set A/B metadata.')
3996 sub_parser.add_argument('--misc_image',
3997 help=('The misc image to modify. If the image does '
3998 'not exist, it will be created.'),
3999 type=argparse.FileType('r+b'),
4000 required=True)
4001 sub_parser.add_argument('--slot_data',
4002 help=('Slot data of the form "priority", '
4003 '"tries_remaining", "sucessful_boot" for '
4004 'slot A followed by the same for slot B, '
4005 'separated by colons. The default value '
4006 'is 15:7:0:14:7:0.'),
4007 default='15:7:0:14:7:0')
4008 sub_parser.set_defaults(func=self.set_ab_metadata)
4009
Darren Krahn147b08d2016-12-20 16:38:29 -08004010 sub_parser = subparsers.add_parser(
4011 'make_atx_certificate',
4012 help='Create an Android Things eXtension (ATX) certificate.')
4013 sub_parser.add_argument('--output',
4014 help='Write certificate to file',
4015 type=argparse.FileType('wb'),
4016 default=sys.stdout)
4017 sub_parser.add_argument('--subject',
4018 help=('Path to subject file'),
4019 type=argparse.FileType('rb'),
4020 required=True)
4021 sub_parser.add_argument('--subject_key',
4022 help=('Path to subject RSA public key file'),
4023 type=argparse.FileType('rb'),
4024 required=True)
4025 sub_parser.add_argument('--subject_key_version',
4026 help=('Version of the subject key'),
4027 type=parse_number,
4028 required=False)
4029 sub_parser.add_argument('--subject_is_intermediate_authority',
4030 help=('Generate an intermediate authority '
4031 'certificate'),
4032 action='store_true')
Darren Krahnfccd64e2018-01-16 17:39:35 -08004033 sub_parser.add_argument('--usage',
Darren Krahn2367b462018-06-19 00:53:32 -07004034 help=('Override usage with a hash of the provided '
Darren Krahnfccd64e2018-01-16 17:39:35 -08004035 'string'),
4036 required=False)
Darren Krahn147b08d2016-12-20 16:38:29 -08004037 sub_parser.add_argument('--authority_key',
4038 help='Path to authority RSA private key file',
4039 required=False)
4040 sub_parser.add_argument('--signing_helper',
4041 help='Path to helper used for signing',
4042 metavar='APP',
4043 default=None,
4044 required=False)
David Zeuthena156d3d2017-06-01 12:08:09 -04004045 sub_parser.add_argument('--signing_helper_with_files',
4046 help='Path to helper used for signing using files',
4047 metavar='APP',
4048 default=None,
4049 required=False)
Darren Krahn147b08d2016-12-20 16:38:29 -08004050 sub_parser.set_defaults(func=self.make_atx_certificate)
4051
4052 sub_parser = subparsers.add_parser(
4053 'make_atx_permanent_attributes',
4054 help='Create Android Things eXtension (ATX) permanent attributes.')
4055 sub_parser.add_argument('--output',
4056 help='Write attributes to file',
4057 type=argparse.FileType('wb'),
4058 default=sys.stdout)
4059 sub_parser.add_argument('--root_authority_key',
4060 help='Path to authority RSA public key file',
4061 type=argparse.FileType('rb'),
4062 required=True)
4063 sub_parser.add_argument('--product_id',
4064 help=('Path to Product ID file'),
4065 type=argparse.FileType('rb'),
4066 required=True)
4067 sub_parser.set_defaults(func=self.make_atx_permanent_attributes)
4068
4069 sub_parser = subparsers.add_parser(
4070 'make_atx_metadata',
4071 help='Create Android Things eXtension (ATX) metadata.')
4072 sub_parser.add_argument('--output',
4073 help='Write metadata to file',
4074 type=argparse.FileType('wb'),
4075 default=sys.stdout)
4076 sub_parser.add_argument('--intermediate_key_certificate',
4077 help='Path to intermediate key certificate file',
4078 type=argparse.FileType('rb'),
4079 required=True)
4080 sub_parser.add_argument('--product_key_certificate',
4081 help='Path to product key certificate file',
4082 type=argparse.FileType('rb'),
4083 required=True)
Darren Krahn147b08d2016-12-20 16:38:29 -08004084 sub_parser.set_defaults(func=self.make_atx_metadata)
4085
Darren Krahnfccd64e2018-01-16 17:39:35 -08004086 sub_parser = subparsers.add_parser(
4087 'make_atx_unlock_credential',
4088 help='Create an Android Things eXtension (ATX) unlock credential.')
4089 sub_parser.add_argument('--output',
4090 help='Write credential to file',
4091 type=argparse.FileType('wb'),
4092 default=sys.stdout)
4093 sub_parser.add_argument('--intermediate_key_certificate',
4094 help='Path to intermediate key certificate file',
4095 type=argparse.FileType('rb'),
4096 required=True)
4097 sub_parser.add_argument('--unlock_key_certificate',
4098 help='Path to unlock key certificate file',
4099 type=argparse.FileType('rb'),
4100 required=True)
4101 sub_parser.add_argument('--challenge',
4102 help='Path to the challenge to sign (optional). If '
4103 'this is not provided the challenge signature '
4104 'field is omitted and can be concatenated '
4105 'later.',
4106 required=False)
4107 sub_parser.add_argument('--unlock_key',
4108 help='Path to unlock key (optional). Must be '
4109 'provided if using --challenge.',
4110 required=False)
4111 sub_parser.add_argument('--signing_helper',
4112 help='Path to helper used for signing',
4113 metavar='APP',
4114 default=None,
4115 required=False)
4116 sub_parser.add_argument('--signing_helper_with_files',
4117 help='Path to helper used for signing using files',
4118 metavar='APP',
4119 default=None,
4120 required=False)
4121 sub_parser.set_defaults(func=self.make_atx_unlock_credential)
4122
David Zeuthen21e95262016-07-27 17:58:40 -04004123 args = parser.parse_args(argv[1:])
4124 try:
4125 args.func(args)
4126 except AvbError as e:
David Zeuthena4fee8b2016-08-22 15:20:43 -04004127 sys.stderr.write('{}: {}\n'.format(argv[0], e.message))
David Zeuthen21e95262016-07-27 17:58:40 -04004128 sys.exit(1)
4129
4130 def version(self, _):
4131 """Implements the 'version' sub-command."""
David Zeuthene3cadca2017-02-22 21:25:46 -05004132 print get_release_string()
David Zeuthen21e95262016-07-27 17:58:40 -04004133
4134 def extract_public_key(self, args):
4135 """Implements the 'extract_public_key' sub-command."""
4136 self.avb.extract_public_key(args.key, args.output)
4137
4138 def make_vbmeta_image(self, args):
4139 """Implements the 'make_vbmeta_image' sub-command."""
David Zeuthena5fd3a42017-02-27 16:38:54 -05004140 args = self._fixup_common_args(args)
David Zeuthen21e95262016-07-27 17:58:40 -04004141 self.avb.make_vbmeta_image(args.output, args.chain_partition,
David Zeuthen18666ab2016-11-15 11:18:05 -05004142 args.algorithm, args.key,
4143 args.public_key_metadata, args.rollback_index,
David Zeuthenfd41eb92016-11-17 12:24:47 -05004144 args.flags, args.prop, args.prop_from_file,
David Zeuthen21e95262016-07-27 17:58:40 -04004145 args.kernel_cmdline,
David Zeuthen5d4f4f22017-01-11 11:37:34 -05004146 args.setup_rootfs_from_kernel,
David Zeuthend247fcb2017-02-16 12:09:27 -05004147 args.include_descriptors_from_image,
David Zeuthene3cadca2017-02-22 21:25:46 -05004148 args.signing_helper,
David Zeuthena156d3d2017-06-01 12:08:09 -04004149 args.signing_helper_with_files,
David Zeuthene3cadca2017-02-22 21:25:46 -05004150 args.internal_release_string,
David Zeuthen1097a782017-05-31 15:53:17 -04004151 args.append_to_release_string,
David Zeuthen97cb5802017-06-01 16:14:05 -04004152 args.print_required_libavb_version,
4153 args.padding_size)
David Zeuthen21e95262016-07-27 17:58:40 -04004154
David Zeuthenb1b994d2017-03-06 18:01:31 -05004155 def append_vbmeta_image(self, args):
4156 """Implements the 'append_vbmeta_image' sub-command."""
4157 self.avb.append_vbmeta_image(args.image.name, args.vbmeta_image.name,
4158 args.partition_size)
4159
David Zeuthen21e95262016-07-27 17:58:40 -04004160 def add_hash_footer(self, args):
4161 """Implements the 'add_hash_footer' sub-command."""
David Zeuthena5fd3a42017-02-27 16:38:54 -05004162 args = self._fixup_common_args(args)
David Zeuthenbf562452017-05-17 18:04:43 -04004163 self.avb.add_hash_footer(args.image.name if args.image else None,
4164 args.partition_size,
David Zeuthen21e95262016-07-27 17:58:40 -04004165 args.partition_name, args.hash_algorithm,
David Zeuthena5fd3a42017-02-27 16:38:54 -05004166 args.salt, args.chain_partition, args.algorithm,
4167 args.key,
David Zeuthen18666ab2016-11-15 11:18:05 -05004168 args.public_key_metadata, args.rollback_index,
David Zeuthena5fd3a42017-02-27 16:38:54 -05004169 args.flags, args.prop, args.prop_from_file,
David Zeuthen18666ab2016-11-15 11:18:05 -05004170 args.kernel_cmdline,
David Zeuthen5d4f4f22017-01-11 11:37:34 -05004171 args.setup_rootfs_from_kernel,
David Zeuthend247fcb2017-02-16 12:09:27 -05004172 args.include_descriptors_from_image,
David Zeuthena156d3d2017-06-01 12:08:09 -04004173 args.calc_max_image_size,
4174 args.signing_helper,
4175 args.signing_helper_with_files,
David Zeuthene3cadca2017-02-22 21:25:46 -05004176 args.internal_release_string,
4177 args.append_to_release_string,
David Zeuthend247fcb2017-02-16 12:09:27 -05004178 args.output_vbmeta_image,
David Zeuthen1097a782017-05-31 15:53:17 -04004179 args.do_not_append_vbmeta_image,
Darren Krahnfd0ba0d2018-02-01 18:06:34 -08004180 args.print_required_libavb_version,
4181 args.use_persistent_digest,
4182 args.do_not_use_ab)
David Zeuthen21e95262016-07-27 17:58:40 -04004183
4184 def add_hashtree_footer(self, args):
4185 """Implements the 'add_hashtree_footer' sub-command."""
David Zeuthena5fd3a42017-02-27 16:38:54 -05004186 args = self._fixup_common_args(args)
David Zeuthenbce9a292017-05-10 17:18:04 -04004187 # TODO(zeuthen): Remove when removing support for the
4188 # '--generate_fec' option above.
4189 if args.generate_fec:
4190 sys.stderr.write('The --generate_fec option is deprecated since FEC '
4191 'is now generated by default. Use the option '
4192 '--do_not_generate_fec to not generate FEC.\n')
David Zeuthen09692692016-09-30 16:16:40 -04004193 self.avb.add_hashtree_footer(args.image.name if args.image else None,
4194 args.partition_size,
4195 args.partition_name,
David Zeuthenbce9a292017-05-10 17:18:04 -04004196 not args.do_not_generate_fec, args.fec_num_roots,
David Zeuthen09692692016-09-30 16:16:40 -04004197 args.hash_algorithm, args.block_size,
David Zeuthena5fd3a42017-02-27 16:38:54 -05004198 args.salt, args.chain_partition, args.algorithm,
4199 args.key, args.public_key_metadata,
4200 args.rollback_index, args.flags, args.prop,
David Zeuthen09692692016-09-30 16:16:40 -04004201 args.prop_from_file,
4202 args.kernel_cmdline,
David Zeuthen5d4f4f22017-01-11 11:37:34 -05004203 args.setup_rootfs_from_kernel,
David Zeuthen73f2afa2017-05-17 16:54:11 -04004204 args.setup_as_rootfs_from_kernel,
David Zeuthen09692692016-09-30 16:16:40 -04004205 args.include_descriptors_from_image,
David Zeuthena156d3d2017-06-01 12:08:09 -04004206 args.calc_max_image_size,
4207 args.signing_helper,
4208 args.signing_helper_with_files,
David Zeuthene3cadca2017-02-22 21:25:46 -05004209 args.internal_release_string,
4210 args.append_to_release_string,
David Zeuthend247fcb2017-02-16 12:09:27 -05004211 args.output_vbmeta_image,
David Zeuthen1097a782017-05-31 15:53:17 -04004212 args.do_not_append_vbmeta_image,
Darren Krahnfd0ba0d2018-02-01 18:06:34 -08004213 args.print_required_libavb_version,
4214 args.use_persistent_digest,
4215 args.do_not_use_ab)
David Zeuthend247fcb2017-02-16 12:09:27 -05004216
David Zeuthen21e95262016-07-27 17:58:40 -04004217 def erase_footer(self, args):
4218 """Implements the 'erase_footer' sub-command."""
David Zeuthena4fee8b2016-08-22 15:20:43 -04004219 self.avb.erase_footer(args.image.name, args.keep_hashtree)
David Zeuthen21e95262016-07-27 17:58:40 -04004220
David Zeuthen49936b42018-08-07 17:38:58 -04004221 def extract_vbmeta_image(self, args):
4222 """Implements the 'extract_vbmeta_image' sub-command."""
4223 self.avb.extract_vbmeta_image(args.output, args.image.name,
4224 args.padding_size)
4225
David Zeuthen2bc232b2017-04-19 14:25:19 -04004226 def resize_image(self, args):
4227 """Implements the 'resize_image' sub-command."""
4228 self.avb.resize_image(args.image.name, args.partition_size)
4229
David Zeuthen8b6973b2016-09-20 12:39:49 -04004230 def set_ab_metadata(self, args):
4231 """Implements the 'set_ab_metadata' sub-command."""
4232 self.avb.set_ab_metadata(args.misc_image, args.slot_data)
4233
David Zeuthen21e95262016-07-27 17:58:40 -04004234 def info_image(self, args):
4235 """Implements the 'info_image' sub-command."""
David Zeuthena4fee8b2016-08-22 15:20:43 -04004236 self.avb.info_image(args.image.name, args.output)
David Zeuthen21e95262016-07-27 17:58:40 -04004237
David Zeuthenb623d8b2017-04-04 16:05:53 -04004238 def verify_image(self, args):
4239 """Implements the 'verify_image' sub-command."""
David Zeuthen5dfb4e92017-05-24 14:49:32 -04004240 self.avb.verify_image(args.image.name, args.key,
4241 args.expected_chain_partition)
David Zeuthenb623d8b2017-04-04 16:05:53 -04004242
David Zeuthenb8643c02018-05-17 17:21:18 -04004243 def calculate_vbmeta_digest(self, args):
4244 """Implements the 'calculate_vbmeta_digest' sub-command."""
4245 self.avb.calculate_vbmeta_digest(args.image.name, args.hash_algorithm,
4246 args.output)
4247
Darren Krahn147b08d2016-12-20 16:38:29 -08004248 def make_atx_certificate(self, args):
4249 """Implements the 'make_atx_certificate' sub-command."""
4250 self.avb.make_atx_certificate(args.output, args.authority_key,
David Zeuthenc68f0822017-03-31 17:22:35 -04004251 args.subject_key.name,
Darren Krahn147b08d2016-12-20 16:38:29 -08004252 args.subject_key_version,
4253 args.subject.read(),
4254 args.subject_is_intermediate_authority,
Darren Krahnfccd64e2018-01-16 17:39:35 -08004255 args.usage,
David Zeuthena156d3d2017-06-01 12:08:09 -04004256 args.signing_helper,
4257 args.signing_helper_with_files)
Darren Krahn147b08d2016-12-20 16:38:29 -08004258
4259 def make_atx_permanent_attributes(self, args):
4260 """Implements the 'make_atx_permanent_attributes' sub-command."""
4261 self.avb.make_atx_permanent_attributes(args.output,
David Zeuthenc68f0822017-03-31 17:22:35 -04004262 args.root_authority_key.name,
Darren Krahn147b08d2016-12-20 16:38:29 -08004263 args.product_id.read())
4264
4265 def make_atx_metadata(self, args):
4266 """Implements the 'make_atx_metadata' sub-command."""
4267 self.avb.make_atx_metadata(args.output,
4268 args.intermediate_key_certificate.read(),
Darren Krahn43e12d82017-02-24 16:26:31 -08004269 args.product_key_certificate.read())
Darren Krahn147b08d2016-12-20 16:38:29 -08004270
Darren Krahnfccd64e2018-01-16 17:39:35 -08004271 def make_atx_unlock_credential(self, args):
4272 """Implements the 'make_atx_unlock_credential' sub-command."""
4273 self.avb.make_atx_unlock_credential(
4274 args.output,
4275 args.intermediate_key_certificate.read(),
4276 args.unlock_key_certificate.read(),
4277 args.challenge,
4278 args.unlock_key,
4279 args.signing_helper,
4280 args.signing_helper_with_files)
4281
David Zeuthen21e95262016-07-27 17:58:40 -04004282
4283if __name__ == '__main__':
4284 tool = AvbTool()
4285 tool.run(sys.argv)