Snap for 6533464 from 23dbe6ec9b8734aea9812e1ecd3af47e88d6360a to sdk-release
Change-Id: I578fa5d62657b7040d0204ec4e99ffc5b602f0cf
diff --git a/Android.bp b/Android.bp
index aa4897a..a9bd385 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1,5 +1,5 @@
//
-// Copyright (C) 2017 The Android Open Source Project
+// Copyright (C) 2017-2020 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -14,7 +14,10 @@
// limitations under the License.
//
-subdirs = ["test", "tools"]
+subdirs = [
+ "test",
+ "tools",
+]
cc_defaults {
name: "avb_defaults",
@@ -85,6 +88,7 @@
},
py3: {
enabled: true,
+ embedded_launcher: true,
},
},
}
@@ -93,7 +97,6 @@
name: "aftl_proto",
srcs: [
"proto/api.proto",
- "proto/aftl.proto",
"proto/crypto/sigpb/sigpb.proto",
"proto/crypto/keyspb/keyspb.proto",
"proto/trillian.proto",
@@ -243,7 +246,8 @@
name: "libavb_aftl",
defaults: [
"avb_defaults",
- "avb_sources"],
+ "avb_sources",
+ ],
host_supported: true,
recovery_available: true,
header_libs: ["avb_headers"],
@@ -252,12 +256,38 @@
"-fno-stack-protector",
],
srcs: [
- "libavb_aftl/avb_aftl_util.c",
- "libavb_aftl/avb_aftl_validate.c",
- "libavb_aftl/avb_aftl_verify.c",
+ "libavb_aftl/avb_aftl_util.c",
+ "libavb_aftl/avb_aftl_validate.c",
+ "libavb_aftl/avb_aftl_verify.c",
],
}
+cc_fuzz {
+ name: "libavb_aftl_fuzzer",
+ defaults: ["avb_defaults"],
+ // The fuzzing entry point is declared and defined in the same file.
+ // Overwrite the behaviour introduced by avb_defaults.
+ cflags: [
+ "-Wno-missing-prototypes",
+ ],
+ srcs: [
+ "test/avb_aftl_fuzz.cc",
+ ],
+ static_libs: [
+ "libavb",
+ "libavb_aftl",
+ ],
+ host_supported: true,
+ corpus: ["test/corpus/*"],
+ fuzz_config: {
+ cc: [
+ "tweek@google.com",
+ "jpm@google.com",
+ ],
+ componentid: 685985,
+ },
+}
+
cc_library_host_static {
name: "libavb_atx_host",
defaults: ["avb_defaults"],
@@ -301,7 +331,8 @@
],
data: [
"avbtool",
- "test/avbtool_signing_helper_*.py",
+ "test/avbtool_signing_helper_test.py",
+ "test/avbtool_signing_helper_with_files_test.py",
"test/data/*",
],
test_config: "test/libavb_host_unittest.xml",
@@ -321,8 +352,8 @@
"libcrypto",
],
cflags: [
- "-Wno-missing-prototypes",
- "-DAVB_AB_I_UNDERSTAND_LIBAVB_AB_IS_DEPRECATED",
+ "-Wno-missing-prototypes",
+ "-DAVB_AB_I_UNDERSTAND_LIBAVB_AB_IS_DEPRECATED",
],
srcs: [
"test/avb_ab_flow_unittest.cc",
diff --git a/METADATA b/METADATA
new file mode 100644
index 0000000..d97975c
--- /dev/null
+++ b/METADATA
@@ -0,0 +1,3 @@
+third_party {
+ license_type: NOTICE
+}
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 5789f69..0e19284 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -1,4 +1,5 @@
[Builtin Hooks]
+bpfmt = true
clang_format = true
pylint = true
diff --git a/README.md b/README.md
index 8ae645e..4c15fb3 100644
--- a/README.md
+++ b/README.md
@@ -209,6 +209,11 @@
Storing signed verification data on other images - for example
`boot.img` and `system.img` - is also done with `avbtool`.
+The minimum requirement for running `avbtool` is to either have
+Python 3.5 installed or build the avbtool with the embedded launcher
+using `m avbtool` and then run it out of the build artifact directory:
+`out/soong/host/linux-x86/bin/avbtool`
+
In addition to `avbtool`, a library - `libavb` - is provided. This
library performs all verification on the device side e.g. it starts by
loading the `vbmeta` partition, checks the signature, and then goes on
diff --git a/aftltool.py b/aftltool.py
index 0fe2d07..613e83b 100755
--- a/aftltool.py
+++ b/aftltool.py
@@ -24,10 +24,11 @@
#
"""Command-line tool for AFTL support for Android Verified Boot images."""
+import abc
import argparse
-import base64
+import enum
import hashlib
-import json
+import io
import multiprocessing
import os
import queue
@@ -46,9 +47,7 @@
# pylint: disable=wrong-import-position,import-error
import avbtool
-import aftl_pb2
import api_pb2
-from crypto.sigpb import sigpb_pb2
# pylint: enable=wrong-import-position,import-error
@@ -350,14 +349,16 @@
log_url_size: Length of the string representing the transparency log URL.
leaf_index: Leaf index in the transparency log representing this entry.
log_root_descriptor_size: Size of the transparency log's SignedLogRoot.
- fw_info_leaf_size: Size of the FirmwareInfo leaf passed to the log.
+ annotation_leaf_size: Size of the SignedVBMetaPrimaryAnnotationLeaf passed
+ to the log.
log_root_sig_size: Size in bytes of the log_root_signature
proof_hash_count: Number of hashes comprising the inclusion proof.
inc_proof_size: The total size of the inclusion proof, in bytes.
log_url: The URL for the transparency log that generated this inclusion
proof.
log_root_descriptor: The data comprising the signed tree head structure.
- fw_info_leaf: The data comprising the FirmwareInfo leaf.
+ annotation_leaf: The data comprising the SignedVBMetaPrimaryAnnotationLeaf
+ leaf.
log_root_signature: The data comprising the log root signature.
proofs: The hashes comprising the inclusion proof.
@@ -370,9 +371,8 @@
'H' # log root signature size
'B' # number of hashes in the inclusion proof
'L') # size of the inclusion proof in bytes
- # These are used to capture the log_url, log_root_descriptor,
- # fw_info leaf, log root signature, and the proofs elements for the
- # encode function.
+ # This header is followed by the log_url, log_root_descriptor,
+ # annotation leaf, log root signature, and the proofs elements.
def __init__(self, data=None):
"""Initializes a new ICP entry object.
@@ -391,7 +391,7 @@
(self._log_url_size_expected,
self.leaf_index,
self._log_root_descriptor_size_expected,
- self._fw_info_leaf_size_expected,
+ self._annotation_leaf_size_expected,
self._log_root_sig_size_expected,
self._proof_hash_count_expected,
self._inc_proof_size_expected) = struct.unpack(self.FORMAT_STRING,
@@ -401,18 +401,20 @@
expected_format_string = '{}s{}s{}s{}s{}s'.format(
self._log_url_size_expected,
self._log_root_descriptor_size_expected,
- self._fw_info_leaf_size_expected,
+ self._annotation_leaf_size_expected,
self._log_root_sig_size_expected,
self._inc_proof_size_expected)
- (log_url, log_root_descriptor_bytes, fw_info_leaf_bytes,
+ (log_url, log_root_descriptor_bytes, annotation_leaf_bytes,
self.log_root_signature, proof_bytes) = struct.unpack(
expected_format_string, data[self.SIZE:self.get_expected_size()])
self.log_url = log_url.decode('ascii')
self.log_root_descriptor = TrillianLogRootDescriptor(
log_root_descriptor_bytes)
- self.fw_info_leaf = FirmwareInfoLeaf(fw_info_leaf_bytes)
+
+ self.annotation_leaf = SignedVBMetaPrimaryAnnotationLeaf.parse(
+ annotation_leaf_bytes)
self.proofs = []
if self._proof_hash_count_expected > 0:
@@ -427,7 +429,7 @@
self.leaf_index = 0
self.log_url = ''
self.log_root_descriptor = TrillianLogRootDescriptor()
- self.fw_info_leaf = FirmwareInfoLeaf()
+ self.annotation_leaf = SignedVBMetaPrimaryAnnotationLeaf()
self.log_root_signature = b''
self.proofs = []
if not self.is_valid():
@@ -448,11 +450,11 @@
return self._log_root_descriptor_size_expected
@property
- def fw_info_leaf_size(self):
- """Gets the size of the fw_info_leaf attribute."""
- if hasattr(self, 'fw_info_leaf'):
- return self.fw_info_leaf.get_expected_size()
- return self._fw_info_leaf_size_expected
+ def annotation_leaf_size(self):
+ """Gets the size of the annotation_leaf attribute."""
+ if hasattr(self, 'annotation_leaf'):
+ return self.annotation_leaf.get_expected_size()
+ return self._annotation_leaf_size_expected
@property
def log_root_sig_size(self):
@@ -490,7 +492,7 @@
if not transparency_log_pub_key:
return False
- leaf_hash = rfc6962_hash_leaf(self.fw_info_leaf.encode())
+ leaf_hash = rfc6962_hash_leaf(self.annotation_leaf.encode())
calc_root = root_from_icp(self.leaf_index,
self.log_root_descriptor.tree_size,
self.proofs,
@@ -513,7 +515,7 @@
Returns:
True if the inclusion proof validates and the vbmeta hash of the given
- VBMeta image matches the one in the fw_info_leaf; otherwise False.
+ VBMeta image matches the one in the annotation leaf; otherwise False.
"""
if not vbmeta_image:
return False
@@ -524,13 +526,13 @@
# Validates the inclusion proof and then compare the calculated vbmeta_hash
# against the one in the inclusion proof.
return (self.verify_icp(transparency_log_pub_key)
- and self.fw_info_leaf.vbmeta_hash == vbmeta_hash)
+ and self.annotation_leaf.annotation.vbmeta_hash == vbmeta_hash)
def encode(self):
- """Serializes the header |SIZE| and data to a bytearray().
+ """Serializes the header |SIZE| and data to bytes.
Returns:
- A bytearray() with the encoded header.
+ bytes with the encoded header.
Raises:
AftlError: If invalid entry structure.
@@ -543,7 +545,7 @@
self.FORMAT_STRING,
self.log_url_size,
self.log_root_descriptor_size,
- self.fw_info_leaf_size,
+ self.annotation_leaf_size,
self.log_root_sig_size,
self.inc_proof_size)
@@ -552,30 +554,31 @@
return struct.pack(expected_format_string,
self.log_url_size, self.leaf_index,
- self.log_root_descriptor_size, self.fw_info_leaf_size,
+ self.log_root_descriptor_size, self.annotation_leaf_size,
self.log_root_sig_size, self.proof_hash_count,
self.inc_proof_size, self.log_url.encode('ascii'),
self.log_root_descriptor.encode(),
- self.fw_info_leaf.encode(),
+ self.annotation_leaf.encode(),
self.log_root_signature,
proof_bytes)
- def translate_response(self, log_url, afi_response):
- """Translates an AddFirmwareInfoResponse object to an AftlIcpEntry.
+ def translate_response(self, log_url, avbm_response):
+ """Translates an AddVBMetaResponse object to an AftlIcpEntry.
Arguments:
log_url: String representing the transparency log URL.
- afi_response: The AddFirmwareResponse object to translate.
+ avbm_response: The AddVBMetaResponse object to translate.
"""
self.log_url = log_url
- # Deserializes from AddFirmwareInfoResponse.
- self.leaf_index = afi_response.fw_info_proof.proof.leaf_index
- self.log_root_descriptor = TrillianLogRootDescriptor(
- afi_response.fw_info_proof.sth.log_root)
- self.fw_info_leaf = FirmwareInfoLeaf(afi_response.fw_info_leaf)
- self.log_root_signature = afi_response.fw_info_proof.sth.log_root_signature
- self.proofs = afi_response.fw_info_proof.proof.hashes
+ # Deserializes from AddVBMetaResponse.
+ proof = avbm_response.annotation_proof
+ self.leaf_index = proof.proof.leaf_index
+ self.log_root_descriptor = TrillianLogRootDescriptor(proof.sth.log_root)
+ self.annotation_leaf = SignedVBMetaPrimaryAnnotationLeaf.parse(
+ avbm_response.annotation_leaf)
+ self.log_root_signature = proof.sth.log_root_signature
+ self.proofs = proof.proof.hashes
def get_expected_size(self):
"""Gets the expected size of the full entry out of the header.
@@ -584,7 +587,7 @@
The expected size of the AftlIcpEntry from the header.
"""
return (self.SIZE + self.log_url_size + self.log_root_descriptor_size +
- self.fw_info_leaf_size + self.log_root_sig_size +
+ self.annotation_leaf_size + self.log_root_sig_size +
self.inc_proof_size)
def is_valid(self):
@@ -604,9 +607,9 @@
sys.stderr.write('ICP entry: invalid TrillianLogRootDescriptor.\n')
return False
- if (not self.fw_info_leaf or
- not isinstance(self.fw_info_leaf, FirmwareInfoLeaf)):
- sys.stderr.write('ICP entry: invalid FirmwareInfo.\n')
+ if (not self.annotation_leaf or
+ not isinstance(self.annotation_leaf, Leaf)):
+ sys.stderr.write('ICP entry: invalid Leaf.\n')
return False
return True
@@ -626,7 +629,7 @@
o.write(' ' * 29)
o.write('{}\n'.format(proof_hash.hex()))
self.log_root_descriptor.print_desc(o)
- self.fw_info_leaf.print_desc(o)
+ self.annotation_leaf.print_desc(o)
class TrillianLogRootDescriptor(object):
@@ -793,139 +796,268 @@
o.write(fmt.format(i, 'Metadata:', self.metadata.hex()))
-class FirmwareInfoLeaf(object):
- """A class representing the FirmwareInfo leaf.
+def tls_decode_bytes(byte_size, stream):
+ """Decodes a variable-length vector.
- AFTL returns the fw_info_leaf as a JSON blob and this class is able to
- parse the blog and provide necessary attributes needed for validation.
+ In the TLS presentation language, a variable-length vector is a pair
+ (size, value). |size| describes the size of the |value| to read
+ in bytes. All values are encoded in big-endian.
+ See https://tools.ietf.org/html/rfc8446#section-3 for more details.
+
+ Arguments:
+ byte_size: A format character as described in the struct module
+ which describes the expected length of the size. For
+ instance, "B", "H", "L" or "Q".
+ stream: a BytesIO which contains the value to decode.
+
+ Returns:
+ A bytes containing the value decoded.
+
+ Raises:
+ AftlError: If |byte_size| is not a known format character, or if not
+ enough data is available to decode the size or the value.
+ """
+ byte_size_format = "!" + byte_size
+ try:
+ byte_size_length = struct.calcsize(byte_size_format)
+ except struct.error:
+ raise AftlError("Invalid byte_size character: {}. It must be a "
+ "format supported by struct.".format(byte_size))
+ try:
+ value_size = struct.unpack(byte_size_format,
+ stream.read(byte_size_length))[0]
+ except struct.error:
+ raise AftlError("Not enough data to read size: {}".format(byte_size))
+ value = stream.read(value_size)
+ if value_size != len(value):
+ raise AftlError("Not enough data to read value: "
+ "{} != {}".format(value_size, len(value)))
+ return value
+
+def tls_encode_bytes(byte_size, value, stream):
+ """Encodes a variable-length vector.
+
+ In the TLS presentation language, a variable-length vector is a pair
+ (size, value). |size| describes the size of the |value| to read
+ in bytes. All values are encoded in big-endian.
+ See https://tools.ietf.org/html/rfc8446#section-3 for more details.
+
+ Arguments:
+ byte_size: A format character as described in the struct module
+ which describes the expected length of the size. For
+ instance, "B", "H", "L" or "Q".
+ value: the value to encode. The length of |value| must be
+ representable with |byte_size|.
+ stream: a BytesIO to which the value is encoded to.
+
+ Raises:
+ AftlError: If |byte_size| is not a known format character, or if
+ |value|'s length cannot be represent with |byte_size|.
+ """
+ byte_size_format = "!" + byte_size
+ try:
+ stream.write(struct.pack(byte_size_format, len(value)))
+ except struct.error:
+ # Whether byte_size is invalid or not large enough to represent value,
+ # struct returns an struct.error exception. Instead of matching on the
+ # exception message, capture both cases in a generic message.
+ raise AftlError("Invalid byte_size to store {} bytes".format(len(value)))
+ stream.write(value)
+
+class HashAlgorithm(enum.Enum):
+ SHA256 = 0
+
+class SignatureAlgorithm(enum.Enum):
+ RSA = 0
+ ECDSA = 1
+
+class Signature(object):
+ """Represents a signature of some data.
+
+ It is usually made using a manufacturer key and used to sign part of a leaf
+ that belongs to the transparency log. The encoding of this structure must
+ match the server expectation.
Attributes:
- vbmeta_hash: This is the SHA256 hash of vbmeta.
- version_incremental: Subcomponent of the build fingerprint as defined at
- https://source.android.com/compatibility/android-cdd#3_2_2_build_parameters.
- For example, a Pixel device with the following build fingerprint
- google/crosshatch/crosshatch:9/PQ3A.190605.003/5524043:user/release-keys,
- would have 5524043 for the version incremental.
- platform_key: Public key of the platform. This is the same key used to sign
- the vbmeta.
- manufacturer_key_hash: SHA256 of the manufacturer public key (DER-encoded,
- x509 subjectPublicKeyInfo format). The public key MUST already be in the
- list of root keys known and trusted by the AFTL.
- description: Free form description field. It can be used to annotate this
- message with further context on the build (e.g., carrier specific build).
+ hash_algorithm: the HashAlgorithm used for the signature.
+ signature_algorithm: the SignatureAlgorithm used.
+ signature: the raw signature in bytes.
"""
+ FORMAT_STRING = ('!B' # Hash algorithm
+ 'B' # Signing algorithm
+ )
+ # Followed by the raw signature, encoded as a TLS variable-length vector
+ # which size is represented using 2 bytes.
- def __init__(self, data=None):
- """Initializes a new FirmwareInfoLeaf descriptor."""
- if data:
- # We have to preserve the original fw_info_leaf bytes in order to preserve
- # hash equivalence with what is stored in the Trillian log and matches up
- # with the proofs.
- self._fw_info_leaf_bytes = data
+ def __init__(self, hash_algorithm=HashAlgorithm.SHA256,
+ signature_algorithm=SignatureAlgorithm.RSA, signature=b''):
+ self.hash_algorithm = hash_algorithm
+ self.signature_algorithm = signature_algorithm
+ self.signature = signature
- # Deserialize the JSON blob and keep only the FirmwareInfo parts.
- try:
- fw_info_leaf = json.loads(self._fw_info_leaf_bytes)
- self._fw_info_leaf_dict = (
- fw_info_leaf['Value']['FwInfo']['info']['info'])
- except (ValueError, KeyError) as e:
- raise AftlError('Invalid structure for FirmwareInfoLeaf: {}'.format(e))
- else:
- self._fw_info_leaf_bytes = b''
- self._fw_info_leaf_dict = dict()
-
- if not self.is_valid():
- raise AftlError('Invalid structure for FirmwareInfoLeaf.')
-
- @property
- def vbmeta_hash(self):
- """Gets the vbmeta_hash attribute."""
- return self._lookup_base64_attribute('vbmeta_hash')
-
- @property
- def version_incremental(self):
- """Gets the version_incremental attribute."""
- return self._fw_info_leaf_dict.get('version_incremental')
-
- @property
- def platform_key(self):
- """Gets the platform key attribute."""
- return self._lookup_base64_attribute('platform_key')
-
- @property
- def manufacturer_key_hash(self):
- """Gets the manufacturer_key_hash attribute."""
- return self._lookup_base64_attribute('manufacturer_key_hash')
-
- @property
- def description(self):
- """Gets the description attribute."""
- return self._fw_info_leaf_dict.get('description')
-
- def _lookup_base64_attribute(self, key):
- """Looks up an attribute that is Base64 encoded and decodes it.
+ @classmethod
+ def parse(cls, stream):
+ """Parses a TLS-encoded structure and returns a new Signature.
Arguments:
- key: The name of the attribute to look up.
+ stream: a BytesIO to read the signature from.
Returns:
- The attribute value or None if not defined.
+ A new Signature object.
+
+ Raises:
+ AftlError: If the hash algorithm or signature algorithm value is
+ unknown; or if the decoding failed.
"""
- result = self._fw_info_leaf_dict.get(key)
- if result:
- result = base64.b64decode(result)
- return result
+ data_length = struct.calcsize(cls.FORMAT_STRING)
+ (hash_algorithm, signature_algorithm) = struct.unpack(
+ cls.FORMAT_STRING, stream.read(data_length))
+ try:
+ hash_algorithm = HashAlgorithm(hash_algorithm)
+ except ValueError:
+ raise AftlError('unknown hash algorithm: {}'.format(hash_algorithm))
+ try:
+ signature_algorithm = SignatureAlgorithm(signature_algorithm)
+ except ValueError:
+ raise AftlError('unknown signature algorithm: {}'.format(
+ signature_algorithm))
+ signature = tls_decode_bytes('H', stream)
+ return Signature(hash_algorithm, signature_algorithm, signature)
def get_expected_size(self):
- """Gets the expected size of the JSON-serialized FirmwareInfoLeaf.
+ """Returns the size of the encoded Signature."""
+ return struct.calcsize(self.FORMAT_STRING) + \
+ struct.calcsize('H') + len(self.signature)
+
+ def encode(self, stream):
+ """Encodes the Signature.
+
+ Arguments:
+ stream: a BytesIO to which the signature is written.
+ """
+ stream.write(struct.pack(self.FORMAT_STRING, self.hash_algorithm.value,
+ self.signature_algorithm.value))
+ tls_encode_bytes('H', self.signature, stream)
+
+class VBMetaPrimaryAnnotation(object):
+ """An annotation that contains metadata about a VBMeta image.
+
+ Attributes:
+ vbmeta_hash: the SHA256 of the VBMeta it references.
+ version_incremental: the version incremental of the build, as string.
+ manufacturer_key_hash: the hash of the manufacturer key that will
+ sign this annotation.
+ description: a free-form field.
+ """
+
+ def __init__(self, vbmeta_hash=b'', version_incremental='',
+ manufacturer_key_hash=b'', description=''):
+ """Default constructor."""
+ self.vbmeta_hash = vbmeta_hash
+ self.version_incremental = version_incremental
+ self.manufacturer_key_hash = manufacturer_key_hash
+ self.description = description
+
+ @classmethod
+ def parse(cls, stream):
+ """Parses a VBMetaPrimaryAnnotation from data.
+
+ Arguments:
+ stream: an io.BytesIO to decode the annotation from.
Returns:
- The expected size of the FirmwareInfo leaf in byte or 0 if not initalized.
- """
- if not self._fw_info_leaf_bytes:
- return 0
- return len(self._fw_info_leaf_bytes)
+ A new VBMetaPrimaryAnnotation.
- def encode(self):
- """Serializes the FirmwareInfoLeaf.
+ Raises:
+ AftlError: If an error occured while parsing the annotation.
+ """
+ vbmeta_hash = tls_decode_bytes("B", stream)
+ version_incremental = tls_decode_bytes("B", stream)
+ try:
+ version_incremental = version_incremental.decode("ascii")
+ except UnicodeError:
+ raise AftlError('Failed to convert version incremental to an ASCII'
+ 'string')
+ manufacturer_key_hash = tls_decode_bytes("B", stream)
+ description = tls_decode_bytes("H", stream)
+ try:
+ description = description.decode("utf-8")
+ except UnicodeError:
+ raise AftlError('Failed to convert description to an UTF-8 string')
+ return cls(vbmeta_hash, version_incremental, manufacturer_key_hash,
+ description)
+
+ def sign(self, manufacturer_key_path, signing_helper=None,
+ signing_helper_with_files=None):
+ """Signs the annotation.
+
+ Arguments:
+ manufacturer_key_path: Path to key used to sign messages sent to the
+ transparency log servers.
+ signing_helper: Program which signs a hash and returns a signature.
+ signing_helper_with_files: Same as signing_helper but uses files instead.
Returns:
- A bytearray() with the JSON-serialized FirmwareInfoLeaf.
- """
- return self._fw_info_leaf_bytes
+ A new SignedVBMetaPrimaryAnnotation.
- def is_valid(self):
- """Ensures that values in the descritor are sane.
-
- Returns:
- True if the values are sane; otherwise False.
+ Raises:
+ AftlError: If an error occured while signing the annotation.
"""
- # Checks that the decode fw_info_leaf at max contains values defined in the
- # FirmwareInfo proto buf.
- expected_fields = set(aftl_pb2.FirmwareInfo()
- .DESCRIPTOR.fields_by_name.keys())
- actual_fields = set(self._fw_info_leaf_dict.keys())
- if actual_fields.issubset(expected_fields):
- return True
- return False
+ # AFTL supports SHA256_RSA4096 for now, more will be available.
+ algorithm_name = 'SHA256_RSA4096'
+ encoded_leaf = io.BytesIO()
+ self.encode(encoded_leaf)
+ try:
+ rsa_key = avbtool.RSAPublicKey(manufacturer_key_path)
+ raw_signature = rsa_key.sign(algorithm_name, encoded_leaf.getvalue(),
+ signing_helper, signing_helper_with_files)
+ except avbtool.AvbError as e:
+ raise AftlError('Failed to sign VBMetaPrimaryAnnotation with '
+ '--manufacturer_key: {}'.format(e))
+ signature = Signature(hash_algorithm=HashAlgorithm.SHA256,
+ signature_algorithm=SignatureAlgorithm.RSA,
+ signature=raw_signature)
+ return SignedVBMetaPrimaryAnnotation(signature=signature, annotation=self)
+
+ def encode(self, stream):
+ """Encodes the VBMetaPrimaryAnnotation.
+
+ Arguments:
+ stream: a BytesIO to which the signature is written.
+
+ Raises:
+ AftlError: If the encoding failed.
+ """
+ tls_encode_bytes("B", self.vbmeta_hash, stream)
+ try:
+ tls_encode_bytes("B", self.version_incremental.encode("ascii"), stream)
+ except UnicodeError:
+ raise AftlError('Unable to encode version incremental to ASCII')
+ tls_encode_bytes("B", self.manufacturer_key_hash, stream)
+ try:
+ tls_encode_bytes("H", self.description.encode("utf-8"), stream)
+ except UnicodeError:
+ raise AftlError('Unable to encode description to UTF-8')
+
+ def get_expected_size(self):
+ """Returns the size of the encoded annotation."""
+ b = io.BytesIO()
+ self.encode(b)
+ return len(b.getvalue())
def print_desc(self, o):
- """Print the FirmwareInfoLeaf.
+ """Print the VBMetaPrimaryAnnotation.
Arguments:
o: The object to write the output to.
"""
- o.write(' Firmware Info Leaf:\n')
- # The order of the fields is based on the definition in
- # proto.aftl_pb2.FirmwareInfo.
- i = ' ' * 6
+ o.write(' VBMeta Primary Annotation:\n')
+ i = ' ' * 8
fmt = '{}{:23}{}\n'
if self.vbmeta_hash:
o.write(fmt.format(i, 'VBMeta hash:', self.vbmeta_hash.hex()))
if self.version_incremental:
o.write(fmt.format(i, 'Version incremental:', self.version_incremental))
- if self.platform_key:
- o.write(fmt.format(i, 'Platform key:', self.platform_key))
if self.manufacturer_key_hash:
o.write(fmt.format(i, 'Manufacturer key hash:',
self.manufacturer_key_hash.hex()))
@@ -933,6 +1065,244 @@
o.write(fmt.format(i, 'Description:', self.description))
+class SignedVBMetaPrimaryAnnotation(object):
+ """A Signed VBMetaPrimaryAnnotation.
+
+ Attributes:
+ signature: a Signature.
+ annotation: a VBMetaPrimaryAnnotation.
+ """
+
+ def __init__(self, signature=None, annotation=None):
+ """Default constructor."""
+ if not signature:
+ signature = Signature()
+ self.signature = signature
+ if not annotation:
+ annotation = VBMetaPrimaryAnnotation()
+ self.annotation = annotation
+
+ @classmethod
+ def parse(cls, stream):
+ """Parses a signed annotation."""
+ signature = Signature.parse(stream)
+ annotation = VBMetaPrimaryAnnotation.parse(stream)
+ return cls(signature, annotation)
+
+ def get_expected_size(self):
+ """Returns the size of the encoded signed annotation."""
+ return self.signature.get_expected_size() + \
+ self.annotation.get_expected_size()
+
+ def encode(self, stream):
+ """Encodes the SignedVBMetaPrimaryAnnotation.
+
+ Arguments:
+ stream: a BytesIO to which the object is written.
+
+ Raises:
+ AftlError: If the encoding failed.
+ """
+ self.signature.encode(stream)
+ self.annotation.encode(stream)
+
+ def print_desc(self, o):
+ """Prints the annotation.
+
+ Arguments:
+ o: The object to write the output to.
+ """
+ self.annotation.print_desc(o)
+
+class Leaf(abc.ABC):
+ """An abstract class to represent the leaves in the transparency log."""
+ FORMAT_STRING = ('!B' # Version
+ 'Q' # Timestamp
+ 'B' # LeafType
+ )
+
+ class LeafType(enum.Enum):
+ VBMetaType = 0
+ SignedVBMetaPrimaryAnnotationType = 1
+
+ def __init__(self, version=1, timestamp=0, leaf_type=LeafType.VBMetaType):
+ """Build a new leaf."""
+ self.version = version
+ self.timestamp = timestamp
+ self.leaf_type = leaf_type
+
+ @classmethod
+ def _parse_header(cls, stream):
+ """Parses the header of a leaf.
+
+ This is called with the parse method of the subclasses.
+
+ Arguments:
+ stream: a BytesIO to read the header from.
+
+ Returns:
+ A tuple (version, timestamp, leaf_type).
+
+ Raises:
+ AftlError: If the header cannot be decoded; or if the leaf type is
+ unknown.
+ """
+ data_length = struct.calcsize(cls.FORMAT_STRING)
+ try:
+ (version, timestamp, leaf_type) = struct.unpack(
+ cls.FORMAT_STRING, stream.read(data_length))
+ except struct.error:
+ raise AftlError("Not enough data to parse leaf header")
+ try:
+ leaf_type = cls.LeafType(leaf_type)
+ except ValueError:
+ raise AftlError("Unknown leaf type: {}".format(leaf_type))
+ return version, timestamp, leaf_type
+
+ @classmethod
+ @abc.abstractmethod
+ def parse(cls, data):
+ """Parses a leaf and returned a new object.
+
+ This abstract method must be implemented by the subclass. It may use
+ _parse_header to parse the common fields.
+
+ Arguments:
+ data: a bytes-like object.
+
+ Returns:
+ An object of the type of the particular subclass.
+
+ Raises:
+ AftlError: If the leaf type is incorrect; or if the decoding failed.
+ """
+
+ @abc.abstractmethod
+ def encode(self):
+ """Encodes a leaf.
+
+ This abstract method must be implemented by the subclass. It may use
+ _encode_header to encode the common fields.
+
+ Returns:
+ A bytes with the encoded leaf.
+
+ Raises:
+ AftlError: If the encoding failed.
+ """
+
+ def _get_expected_header_size(self):
+ """Returns the size of the leaf header."""
+ return struct.calcsize(self.FORMAT_STRING)
+
+ def _encode_header(self, stream):
+ """Encodes the header of the leaf.
+
+ This method is called by the encode method in the subclass.
+
+ Arguments:
+ stream: a BytesIO to which the object is written.
+
+ Raises:
+ AftlError: If the encoding failed.
+ """
+ try:
+ stream.write(struct.pack(self.FORMAT_STRING, self.version, self.timestamp,
+ self.leaf_type.value))
+ except struct.error:
+ raise AftlError('Unable to encode the leaf header')
+
+ def print_desc(self, o):
+ """Prints the leaf header.
+
+ Arguments:
+ o: The object to write the output to.
+ """
+ i = ' ' * 6
+ fmt = '{}{:23}{}\n'
+ o.write(fmt.format(i, 'Version:', self.version))
+ o.write(fmt.format(i, 'Timestamp:', self.timestamp))
+ o.write(fmt.format(i, 'Type:', self.leaf_type))
+
+
+class SignedVBMetaPrimaryAnnotationLeaf(Leaf):
+ """A Signed VBMetaPrimaryAnnotation leaf."""
+
+ def __init__(self, version=1, timestamp=0,
+ signed_vbmeta_primary_annotation=None):
+ """Builds a new Signed VBMeta Primary Annotation leaf."""
+ super(SignedVBMetaPrimaryAnnotationLeaf, self).__init__(
+ version=version, timestamp=timestamp,
+ leaf_type=self.LeafType.SignedVBMetaPrimaryAnnotationType)
+ if not signed_vbmeta_primary_annotation:
+ signed_vbmeta_primary_annotation = SignedVBMetaPrimaryAnnotation()
+ self.signed_vbmeta_primary_annotation = signed_vbmeta_primary_annotation
+
+ @property
+ def annotation(self):
+ """Returns the VBMetaPrimaryAnnotation contained in the leaf."""
+ return self.signed_vbmeta_primary_annotation.annotation
+
+ @property
+ def signature(self):
+ """Returns the Signature contained in the leaf."""
+ return self.signed_vbmeta_primary_annotation.signature
+
+ @classmethod
+ def parse(cls, data):
+ """Parses an encoded contained in data.
+
+ Arguments:
+ data: a bytes-like object.
+
+ Returns:
+ A SignedVBMetaPrimaryAnnotationLeaf.
+
+ Raises:
+ AftlError if the leaf type is incorrect; or if the decoding failed.
+ """
+ encoded_leaf = io.BytesIO(data)
+ version, timestamp, leaf_type = Leaf._parse_header(encoded_leaf)
+ if leaf_type != Leaf.LeafType.SignedVBMetaPrimaryAnnotationType:
+ raise AftlError("Incorrect leaf type")
+ signed_annotation = SignedVBMetaPrimaryAnnotation.parse(encoded_leaf)
+ return cls(version=version, timestamp=timestamp,
+ signed_vbmeta_primary_annotation=signed_annotation)
+
+ def get_expected_size(self):
+ """Returns the size of the leaf."""
+ size = self._get_expected_header_size()
+ if self.signed_vbmeta_primary_annotation:
+ size += self.signed_vbmeta_primary_annotation.get_expected_size()
+ return size
+
+ def encode(self):
+ """Encodes the leaf.
+
+ Returns:
+ bytes which contains the encoded leaf.
+
+ Raises:
+ AftlError: If the encoding failed.
+ """
+ stream = io.BytesIO()
+ self._encode_header(stream)
+ self.signed_vbmeta_primary_annotation.encode(stream)
+ return stream.getvalue()
+
+ def print_desc(self, o):
+ """Prints the leaf.
+
+ Arguments:
+ o: The object to write the output to.
+ """
+ i = ' ' * 4
+ fmt = '{}{:25}{}\n'
+ o.write(fmt.format(i, 'Leaf:', ''))
+ super(SignedVBMetaPrimaryAnnotationLeaf, self).print_desc(o)
+ self.signed_vbmeta_primary_annotation.print_desc(o)
+
+
class AftlImage(object):
"""A class for the AFTL image, which contains the transparency log ICPs.
@@ -1087,40 +1457,40 @@
else:
self.timeout = None
- def add_firmware_info(self, request):
- """Calls the AddFirmwareInfo RPC on the AFTL server.
+ def add_vbmeta(self, request):
+ """Calls the AddVBMeta RPC on the AFTL server.
Arguments:
- request: A AddFirmwareInfoRequest message.
+ request: An AddVBMetaRequest message.
Returns:
- An AddFirmwareInfoReponse message.
+ An AddVBMetaResponse message.
Raises:
AftlError: If grpc or the proto modules cannot be loaded, if there is an
error communicating with the log.
"""
raise NotImplementedError(
- 'AddFirmwareInfo() needs to be implemented by subclass.')
+ 'add_vbmeta() needs to be implemented by subclass.')
class AftlGrpcCommunication(AftlCommunication):
"""Class that implements GRPC communication to the AFTL server."""
- def add_firmware_info(self, request):
- """Calls the AddFirmwareInfo RPC on the AFTL server.
+ def add_vbmeta(self, request):
+ """Calls the AddVBMeta RPC on the AFTL server.
Arguments:
- request: A AddFirmwareInfoRequest message.
+ request: An AddVBMetaRequest message.
Returns:
- An AddFirmwareInfoReponse message.
+ An AddVBMetaResponse message.
Raises:
AftlError: If grpc or the proto modules cannot be loaded, if there is an
error communicating with the log.
"""
- # Import grpc now to avoid global dependencies as it otherwise breakes
+ # Import grpc now to avoid global dependencies as it otherwise breaks
# running unittest with atest.
try:
import grpc # pylint: disable=import-outside-toplevel
@@ -1145,8 +1515,8 @@
'with domain {}.\n'.format(
self.transparency_log_config.target))
try:
- response = stub.AddFirmwareInfo(request, timeout=self.timeout,
- metadata=metadata)
+ response = stub.AddVBMeta(request, timeout=self.timeout,
+ metadata=metadata)
except grpc.RpcError as e:
raise AftlError('Error: grpc failure ({})'.format(e))
return response
@@ -1169,7 +1539,7 @@
"""
# Reads and parses the vbmeta image.
try:
- image = avbtool.ImageHandler(image_filename)
+ image = avbtool.ImageHandler(image_filename, read_only=True)
except (IOError, ValueError) as e:
sys.stderr.write('The image does not contain a valid VBMeta structure: '
'{}.\n'.format(e))
@@ -1212,7 +1582,7 @@
return None
try:
- image = avbtool.ImageHandler(image_filename)
+ image = avbtool.ImageHandler(image_filename, read_only=True)
except ValueError as e:
sys.stderr.write('The image does not contain a valid VBMeta structure: '
'{}.\n'.format(e))
@@ -1340,34 +1710,26 @@
# Calculate the hash of the manufacturer key data.
m_key_hash = hashlib.sha256(manufacturer_key_data).digest()
- # Create an AddFirmwareInfoRequest protobuf for transmission to AFTL.
- fw_info = aftl_pb2.FirmwareInfo(vbmeta_hash=vbmeta_hash,
- version_incremental=version_inc,
- manufacturer_key_hash=m_key_hash)
- signed_fw_info = b''
- # AFTL supports SHA256_RSA4096 for now, more will be available.
- algorithm_name = 'SHA256_RSA4096'
- try:
- rsa_key = avbtool.RSAPublicKey(manufacturer_key_path)
- signed_fw_info = rsa_key.sign(algorithm_name, fw_info.SerializeToString(),
- signing_helper, signing_helper_with_files)
- except avbtool.AvbError as e:
- raise AftlError('Failed to sign FirmwareInfo with '
- '--manufacturer_key: {}'.format(e))
- fw_info_sig = sigpb_pb2.DigitallySigned(
- hash_algorithm='SHA256',
- signature_algorithm='RSA',
- signature=signed_fw_info)
+ # Build VBMetaPrimaryAnnotation with that data.
+ annotation = VBMetaPrimaryAnnotation(
+ vbmeta_hash=vbmeta_hash, version_incremental=version_inc,
+ manufacturer_key_hash=m_key_hash)
- sfw_info = aftl_pb2.SignedFirmwareInfo(info=fw_info,
- info_signature=fw_info_sig)
- request = api_pb2.AddFirmwareInfoRequest(
- vbmeta=vbmeta_image, fw_info=sfw_info)
+ # Sign annotation and add it to the request.
+ signed_annotation = annotation.sign(
+ manufacturer_key_path, signing_helper=signing_helper,
+ signing_helper_with_files=signing_helper_with_files)
- # Submit signed FirmwareInfo to the server.
+ encoded_signed_annotation = io.BytesIO()
+ signed_annotation.encode(encoded_signed_annotation)
+ request = api_pb2.AddVBMetaRequest(
+ vbmeta=vbmeta_image,
+ signed_vbmeta_primary_annotation=encoded_signed_annotation.getvalue())
+
+ # Submit signed VBMeta annotation to the server.
if not aftl_comms:
aftl_comms = AftlGrpcCommunication(transparency_log_config, timeout)
- response = aftl_comms.add_firmware_info(request)
+ response = aftl_comms.add_vbmeta(request)
# Return an AftlIcpEntry representing this response.
icp_entry = AftlIcpEntry()
@@ -1870,14 +2232,14 @@
sub_parser.set_defaults(func=self.load_test_aftl)
args = parser.parse_args(argv[1:])
- try:
- success = args.func(args)
- except AttributeError:
+ if not 'func' in args:
# This error gets raised when the command line tool is called without any
# arguments. It mimics the original Python 2 behavior.
parser.print_usage()
print('aftltool: error: too few arguments')
sys.exit(2)
+ try:
+ success = args.func(args)
except AftlError as e:
# Signals to calling tools that an unhandled exception occured.
sys.stderr.write('Unhandled AftlError occured: {}\n'.format(e))
diff --git a/aftltool_test.py b/aftltool_test.py
index 006deb9..7c8c205 100755
--- a/aftltool_test.py
+++ b/aftltool_test.py
@@ -25,7 +25,6 @@
"""Unit tests for aftltool."""
import argparse
-import base64
import binascii
import io
import os
@@ -47,6 +46,107 @@
# TODO(b/149307145): Remove workaround once the referenced bug is fixed.
TEST_EXEC_PATH = os.path.dirname(os.path.realpath(__file__))
+class TlsDataTest(unittest.TestCase):
+
+ def test_decode(self):
+ data = io.BytesIO(b'\x01\x02')
+ value = aftltool.tls_decode_bytes('B', data)
+ self.assertEqual(value, b'\x02')
+ self.assertEqual(data.read(), b'')
+
+ data = io.BytesIO(b'\x00\x01\x03\xff')
+ value = aftltool.tls_decode_bytes('H', data)
+ self.assertEqual(value, b'\x03')
+ self.assertEqual(data.read(), b'\xff')
+
+ data = io.BytesIO(b'\x00\x00\x00\x02\x04\x05\xff\xff')
+ value = aftltool.tls_decode_bytes('L', data)
+ self.assertEqual(value, b'\x04\x05')
+ self.assertEqual(data.read(), b'\xff\xff')
+
+ def test_decode_invalid(self):
+ # Insufficient data for reading the size.
+ with self.assertRaises(aftltool.AftlError):
+ aftltool.tls_decode_bytes('B', io.BytesIO(b''))
+
+ # Invalid byte_size character.
+ with self.assertRaises(aftltool.AftlError):
+ aftltool.tls_decode_bytes('/o/', io.BytesIO(b'\x01\x02\xff'))
+
+ # Insufficient data for reading the value.
+ with self.assertRaises(aftltool.AftlError):
+ aftltool.tls_decode_bytes('B', io.BytesIO(b'\x01'))
+
+ def test_encode(self):
+ stream = io.BytesIO()
+ aftltool.tls_encode_bytes('B', b'\x01\x02\x03\x04', stream)
+ self.assertEqual(stream.getvalue(), b'\x04\x01\x02\x03\x04')
+
+ stream = io.BytesIO()
+ aftltool.tls_encode_bytes('H', b'\x01\x02\x03\x04', stream)
+ self.assertEqual(stream.getvalue(), b'\x00\x04\x01\x02\x03\x04')
+
+ def test_encode_invalid(self):
+ # Byte size is not large enough to encode the value.
+ stream = io.BytesIO()
+ with self.assertRaises(aftltool.AftlError):
+ aftltool.tls_encode_bytes('B', b'\x01'*256, stream)
+
+ # Invalid byte_size character.
+ stream = io.BytesIO()
+ with self.assertRaises(aftltool.AftlError):
+ aftltool.tls_encode_bytes('/o/', b'\x01\x02', stream)
+
+
+class VBMetaPrimaryAnnotationTest(unittest.TestCase):
+
+ def test_decode(self):
+ stream = io.BytesIO(b'\x00\x00\x00\x00\x00')
+ anno = aftltool.VBMetaPrimaryAnnotation.parse(stream)
+ self.assertEqual(anno.vbmeta_hash, b'')
+ self.assertEqual(anno.version_incremental, '')
+ self.assertEqual(anno.manufacturer_key_hash, b'')
+ self.assertEqual(anno.description, '')
+
+ def test_encode(self):
+ stream = io.BytesIO()
+ anno = aftltool.VBMetaPrimaryAnnotation()
+ anno.encode(stream)
+ self.assertEqual(stream.getvalue(), b'\x00\x00\x00\x00\x00')
+
+ def test_encode_invalid(self):
+ stream = io.BytesIO()
+ anno = aftltool.VBMetaPrimaryAnnotation()
+ # Version incremental should be ASCII only.
+ anno.version_incremental = '☃'
+ with self.assertRaises(aftltool.AftlError):
+ anno.encode(stream)
+
+
+class SignedVBMetaAnnotationLeafTest(unittest.TestCase):
+
+ def test_encode(self):
+ leaf = aftltool.SignedVBMetaPrimaryAnnotationLeaf()
+ self.assertEqual(leaf.encode(),
+ b'\x01' # Version
+ b'\x00\x00\x00\x00\x00\x00\x00\x00' # Timestamp
+ b'\x01' + # Leaf Type
+ b'\x00' * 4 + # Empty Signature
+ b'\x00' * 5) # Empty Annotation
+
+ def test_encode_invalid_type(self):
+ # The version field must be a 1-byte integer.
+ leaf = aftltool.SignedVBMetaPrimaryAnnotationLeaf()
+ leaf.version = 'x'
+ with self.assertRaises(aftltool.AftlError):
+ leaf.encode()
+
+ def test_encode_invalid_size(self):
+ leaf = aftltool.SignedVBMetaPrimaryAnnotationLeaf()
+ leaf.version = 256
+ with self.assertRaises(aftltool.AftlError):
+ leaf.encode()
+
class AftltoolTestCase(unittest.TestCase):
@@ -99,6 +199,28 @@
b'' # metadata (empty)
)
+ # Test Annotation #1
+ anno_1 = aftltool.VBMetaPrimaryAnnotation(vbmeta_hash=b'w'*32,
+ version_incremental='x'*5,
+ manufacturer_key_hash=b'y'*32,
+ description='z'*51)
+ signed_anno_1 = aftltool.SignedVBMetaPrimaryAnnotation(annotation=anno_1)
+
+ self.test_anno_1 = aftltool.SignedVBMetaPrimaryAnnotationLeaf(
+ signed_vbmeta_primary_annotation=signed_anno_1)
+ self.test_anno_1_bytes = (
+ b'\x01' # version
+ b'\x00\x00\x00\x00\x00\x00\x00\x00' # timestamp
+ b'\x01' # leaf_type
+ b'\x00' # hash_algorithm
+ b'\x00' # signature_algorithm
+ + b'\x00\x00' # signature
+ + b'\x20' + b'w' * 32 # vbmeta_hash
+ + b'\x05' + b'x' * 5 # version_incremental
+ + b'\x20' + b'y' * 32 # manufacturer_key_hash
+ + b'\x00\x33' + b'z' * 51 # description
+ )
+
# Fill each structure with an easily observable pattern for easy validation.
self.test_proof_hashes_1 = []
self.test_proof_hashes_1.append(b'b' * 32)
@@ -110,6 +232,7 @@
self.test_entry_1 = aftltool.AftlIcpEntry()
self.test_entry_1.log_url = self.test_tl_url_1
self.test_entry_1.leaf_index = 1
+ self.test_entry_1.annotation_leaf = self.test_anno_1
self.test_entry_1.log_root_descriptor = self.test_sth_1
self.test_entry_1.proofs = self.test_proof_hashes_1
self.test_entry_1.log_root_signature = b'g' * 512
@@ -118,12 +241,13 @@
b'\x00\x00\x00\x1b' # Transparency log url size.
b'\x00\x00\x00\x00\x00\x00\x00\x01' # Leaf index.
b'\x00\x00\x00\x3d' # Log root descriptor size.
- b'\x00\x00\x00\x00' # Firmware info leaf size.
+ b'\x00\x00\x00\x8b' # Annotation leaf size.
b'\x02\x00' # Log root signature size.
b'\x04' # Number of hashes in ICP.
b'\x00\x00\x00\x80' # Size of ICP in bytes.
+ self.test_tl_url_1.encode('ascii') # Transparency log url.
+ self.test_sth_1_bytes
+ + self.test_anno_1_bytes
+ b'g' * 512 # Log root signature.
+ b'b' * 32 # Hashes...
+ b'c' * 32
@@ -161,6 +285,7 @@
self.test_entry_2 = aftltool.AftlIcpEntry()
self.test_entry_2.log_url = self.test_tl_url_2
self.test_entry_2.leaf_index = 2
+ self.test_entry_2.annotation_leaf = self.test_anno_1
self.test_entry_2.log_root_descriptor = self.test_sth_2
self.test_entry_2.log_root_signature = b'd' * 512
self.test_entry_2.proofs = self.test_proof_hashes_2
@@ -169,12 +294,13 @@
b'\x00\x00\x00\x1a' # Transparency log url size.
b'\x00\x00\x00\x00\x00\x00\x00\x02' # Leaf index.
b'\x00\x00\x00\x3f' # Log root descriptor size.
- b'\x00\x00\x00\x00' # Firmware info leaf size.
+ b'\x00\x00\x00\x8b' # Annotation leaf size.
b'\x02\x00' # Log root signature size.
b'\x02' # Number of hashes in ICP.
b'\x00\x00\x00\x40' # Size of ICP in bytes.
+ self.test_tl_url_2.encode('ascii') # Transparency log url.
+ self.test_sth_2_bytes # Log root
+ + self.test_anno_1_bytes
+ b'd' * 512 # Log root signature.
+ b'g' * 32 # Hashes...
+ b'h' * 32)
@@ -188,61 +314,88 @@
b'AFTL' # Magic.
+ struct.pack('!L', avbtool.AVB_VERSION_MAJOR) # Major version.
+ struct.pack('!L', avbtool.AVB_VERSION_MINOR) # Minor version.
- + b'\x00\x00\x05\xb9' # Image size.
+ + b'\x00\x00\x06\xcf' # Image size.
b'\x00\x02' # Number of ICP entries.
+ self.test_entry_1_bytes
+ self.test_entry_2_bytes)
- # pylint: disable=no-member
- self.test_afi_resp = api_pb2.AddFirmwareInfoResponse()
- self.test_afi_resp.fw_info_proof.proof.leaf_index = 6263
+ self.test_avbm_resp = api_pb2.AddVBMetaResponse()
+ self.test_avbm_resp.annotation_proof.proof.leaf_index = 9127
hashes = [
- '3ad99869646980c0a51d637a9791f892d12e0bc83f6bac5d305a9e289e7f7e8b',
- '2e5c664d2aee64f71cb4d292e787d0eae7ca9ed80d1e08abb41d26baca386c05',
- 'a671dd99f8d97e9155cc2f0a9dc776a112a5ec5b821ec71571bb258ac790717a',
- '78046b839595e4e49ad4b0c73f92bf4803aacd4a3351181086509d057ef0d7a9',
- 'c0a7e013f03e7c69e9402070e113dadb345868cf144ccb174fabc384b5605abf',
- 'dc36e5dbe36abe9f4ad10f14170aa0148b6fe3fcaba9df43deaf4dede01b02e8',
- 'b063e7fb665370a361718208756c363dc5206e2e9af9b4d847d81289cdae30de',
- 'a69ea5ba88a221103636d3f4245c800570eb86ad9276121481521f97d0a04a81']
+ '61076ca285b4982669e67757f55682ddc43ab5c11ba671260f82a8efa8831f94',
+ '89c2fbcc58da25a65ce5e9b4fb22aaf208b20601f0bc023f73f05d35bc1f3bac',
+ '75d26b5f754b4bed332a3ce2a2bfea0334706a974b7e00ee663f0279fa8b446e',
+ 'e1cd9c96feb893b5ef7771e424ac1c6c47509c2b98bc578d22ad07369c9641aa',
+ 'e83e0e4dd352b1670a55f93f88781a73bb41efcadb9927399f59459dfa14bc40',
+ '8d5d25996117c88655d66f685baa3c94390867a040507b10587b17fbe92b496a',
+ '5de4c627e9ca712f207d6056f56f0d3286ed4a5381ed7f3cc1aa470217734138',
+ '19acfdb424d7fe28d1f850c76302f78f9a50146a5b9c65f9fdfbbc0173fd6993']
for h in hashes:
- self.test_afi_resp.fw_info_proof.proof.hashes.append(
+ self.test_avbm_resp.annotation_proof.proof.hashes.append(
binascii.unhexlify(h))
- self.test_afi_resp.fw_info_proof.sth.key_hint = binascii.unhexlify(
+ self.test_avbm_resp.annotation_proof.sth.key_hint = binascii.unhexlify(
'5af859abce8fe1ea')
- self.test_afi_resp.fw_info_proof.sth.log_root = binascii.unhexlify(
- '000100000000000018782053b182b55dc1377197c938637f50093131daea4'
- 'd0696b1eae5b8a014bfde884a15edb28f1fc7954400000000000013a50000'
+ self.test_avbm_resp.annotation_proof.sth.log_root = binascii.unhexlify(
+ '0001'
+ '00000000000023a8'
+ '20'
+ '9a5f71340f8dc98bdc6320f976dda5f34db8554cb273ba5ab60f1697c519d6f6'
+ '1609ae15024774b1'
+ '0000000000001e5a'
+ '0000'
)
- self.test_afi_resp.fw_info_proof.sth.log_root_signature = (
+ self.test_avbm_resp.annotation_proof.sth.log_root_signature = (
binascii.unhexlify(
- 'c264bc7986a1cf56364ca4dd04989f45515cb8764d05b4fb2b880172585ea404'
- '2105f95a0e0471fb6e0f8c762b14b2e526fb78eaddcc61484917795a12f6ab3b'
- '557b5571d492d07d7950595f9ad8647a606c7c633f4697c5eb59c272aeca0419'
- '397c70a3b9b51537537c4ea6b49d356110e70a9286902f814cc6afbeafe612e4'
- '9e180146140e902bdd9e9dae66b37b4943150a9571949027a648db88a4eea3ad'
- 'f930b4fa6a183e97b762ab0e55a3a26aa6b0fd44d30531e2541ecb94bf645e62'
- '59e8e3151e7c3b51a09fe24557ce2fd2c0ecdada7ce99c390d2ef10e5d075801'
- '7c10d49c55cdee930959cc35f0104e04f296591eeb5defbc9ebb237da7b204ca'
- 'a4608cb98d6bc3a01f18585a04441caf8ec7a35aa2d35f7483b92b14fd0f4a41'
- '3a91133545579309adc593222ca5032a103b00d8fcaea911936dbec11349e4dd'
- '419b091ea7d1130570d70e2589dd9445fd77fd7492507e1c87736847b9741cc6'
- '236868af42558ff6e833e12010c8ede786e43ada40ff488f5f1870d1619887d7'
- '66a24ad0a06a47cc14e2f7db07361be191172adf3155f49713807c7c265f5a84'
- '040fc84246ccf7913e44721f0043cea05ee774e457e13206775eee992620c3f9'
- 'd2b2584f58aac19e4afe35f0a17df699c45729f94101083f9fc4302659a7e6e0'
- 'e7eb36f8d1ca0be2c9010160d329bd2d17bb707b010fdd63c30b667a0b886cf9'
+ '7c37903cc76e8689a6b31da9ad56c3daeb6194029510297cc7d147278390da33'
+ '09c4d9eb1f6be0cdcd1de5315b0b3b573cc9fcd8620d3fab956abbe3c597a572'
+ '46e5a5d277c4cc4b590872d0292fa64e1d3285626b1dedeb00b6aa0a7a0717c0'
+ '7d4c89b68fda9091be06180be1369675a7c4ce7f42cca133ef0daf8dcc5ba1ee'
+ '930cef6dcb71b0a7690446e19661c8e18c089a5d6f6fc9299a0592efb33a4db5'
+ '4c640027fa4f0ad0009f8bf75ec5fc17e0fa1091fabe74fe52738443745066ab'
+ '48f99b297809b863c01016abda17a2479fce91f9929c60bc2ce15e474204fc5a'
+ '8e79b2190aadb7c149671e8c76a4da506860f8d6020fb2eaabfee025cc267bad'
+ '3c8257186c8aaf1da9eefe50cae4b3e8deb66033ebc4bfcda2b317f9e7d2dd78'
+ 'b47f2d86795815d82058ad4cba8fc7983a3bbf843e9b8c7ec7f1ae137be6848d'
+ '03c76eefdac40ce5e66cc23d9f3e79ad87acbe7ec0c0bb419a7d368ae1e73c85'
+ '742871f847bde69c871e8797638e0e270282fb058ef1cbcba52aded9dcc8249b'
+ '38fbed8424c33b8cfcde4f49797c64dda8d089d73b84062602fd41c66091543c'
+ 'e13c18cfa7f8300530ad4b7adb8924bbb86d17bcc5f1d3d74c522a7dcc8c3c1f'
+ '28a999f2fe1bfe5520c66f93f7c90996dc7f52e62dd95ace9ceace90324c3040'
+ '669b7f5aeb5c5a53f217f1de46e32f80d0aaaf7d9cc9d0e8f8fd7026c612103a'
)
)
- self.test_afi_resp.fw_info_leaf = (
- b'{\"timestamp\":{\"seconds\":1580115370,\"nanos\":621454825},\"Va'
- b'lue\":{\"FwInfo\":{\"info\":{\"info\":{\"vbmeta_hash\":\"ViNzEQS'
- b'/oc/bJ13yl40fk/cvXw90bxHQbzCRxgHDIGc=\",\"version_incremental\":'
- b'\"1\",\"manufacturer_key_hash\":\"yBCrUOdjvaAh4git5EgqWa5neegUao'
- b'XeLlB67+N8ObY=\"}}}}}')
- self.test_fw_info_leaf = aftltool.FirmwareInfoLeaf(
- self.test_afi_resp.fw_info_leaf)
+ anno = aftltool.VBMetaPrimaryAnnotation(
+ vbmeta_hash=bytes.fromhex(
+ '5623731104bfa1cfdb275df2978d1f93f72f5f0f746f11d06f3091c601c32067'),
+ version_incremental='only_for_testing',
+ manufacturer_key_hash=bytes.fromhex(
+ '83ab3b109b73a1d32dce4153a2de57a1a0485052db8364f3180d98614749d7f7'))
+ raw_signature = bytes.fromhex(
+ '6a523021bc5b933bb58c38c8238be3a5fe1166002f5df8b77dee9dd22d353595'
+ 'be7996656d3824ebf4e1411a05ee3652d64669d3d62b167d3290dbdf4f2741ba'
+ '4b6472e1bd71fc1860465fdcdca1ff08c4ab0420d7dcbf4ad144f64e211d8f92'
+ '081ba51192358e2478195e573d000282423b23e6dd945069907dcf11520ff11a'
+ '250e26643b820f8a5d80ccfe7d5d84f58e549cd05630f2254ade8edc88d9aa8a'
+ 'ec2089f84643854e1f265a4f746598ce4cae529c4eaa637f6e35fa1d1da9254e'
+ 'ec8dfede7a4313f7b151547dcdde98782ce6fb3149326ee5b8e750813d3fd37a'
+ '738fe92f6111bf0dff4091769e216b842980e05716f2e50268a7dcca430e175e'
+ '711f80e41a1a28f20635741ac11a56f97492d30db6d1955a827daf8e83faebe5'
+ 'a96e18a13c558ae561a02c90982514c853db0296c2e791e68b77c30e6232a3b7'
+ 'ed355441d4706277f33a01735f56cb8279336491731939691683f96f1c3e3183'
+ 'a0b77510d6ff0199b7688902044829793106546fd6fd4a5294d63c31c91256ad'
+ 'f7be6d053e77875698ad32ffaaeaac5d54b432e537f72549d2543072ae35578f'
+ '138d82afcadd668511ba276ce02b6f9c18ef3b6f2f6ae0d123e9f8cb930f21a9'
+ 'c49a6d9e95de741c7860593a956735e1b77e9851ecb1f6572abf6e2c8ba15085'
+ 'e37e0f7bab0a30d108b997ed5edd74cf7f89cf082590a6f0af7a3a1f68c0077a')
+ signature = aftltool.Signature(signature=raw_signature)
+ signed_anno = aftltool.SignedVBMetaPrimaryAnnotation(annotation=anno,
+ signature=signature)
+ leaf = aftltool.SignedVBMetaPrimaryAnnotationLeaf(
+ timestamp=1587991742919072870,
+ signed_vbmeta_primary_annotation=signed_anno).encode()
+ self.test_avbm_resp.annotation_leaf = leaf
+
def tearDown(self):
"""Tears down the test bed for the unit tests."""
@@ -394,17 +547,17 @@
# Valid vbmeta image without footer with 1 ICP.
tool = aftltool.Aftl()
image_path = self.get_testdata_path(
- 'aftltool/aftl_output_vbmeta_with_1_icp.img')
+ 'aftl_output_vbmeta_with_1_icp.img')
vbmeta_image, _ = tool.get_vbmeta_image(image_path)
desc = tool.get_aftl_image(image_path)
# Valid image checked against correct log key.
self.assertTrue(desc.verify_vbmeta_image(
- vbmeta_image, [self.get_testdata_path('aftltool/aftl_pubkey_1.pub')]))
+ vbmeta_image, [self.get_testdata_path('aftl_pubkey_1.pem')]))
# Valid image checked with a key from another log.
self.assertFalse(desc.verify_vbmeta_image(
- vbmeta_image, [self.get_testdata_path('aftltool/aftl_pubkey_2.pub')]))
+ vbmeta_image, [self.get_testdata_path('testkey_rsa4096_pub.pem')]))
# Valid image checked with non existed key file path.
self.assertFalse(desc.verify_vbmeta_image(
@@ -425,17 +578,17 @@
# Valid vbmeta image without footer with 2 ICPs from same log.
tool = aftltool.Aftl()
image_path = self.get_testdata_path(
- 'aftltool/aftl_output_vbmeta_with_2_icp_same_log.img')
+ 'aftl_output_vbmeta_with_2_icp_same_log.img')
vbmeta_image, _ = tool.get_vbmeta_image(image_path)
desc = tool.get_aftl_image(image_path)
# Valid image checked against correct log key.
self.assertTrue(desc.verify_vbmeta_image(
- vbmeta_image, [self.get_testdata_path('aftltool/aftl_pubkey_1.pub')]))
+ vbmeta_image, [self.get_testdata_path('aftl_pubkey_1.pem')]))
# Valid vbmeta image checked with key from another log.
self.assertFalse(desc.verify_vbmeta_image(
- vbmeta_image, [self.get_testdata_path('aftltool/aftl_pubkey_2.pub')]))
+ vbmeta_image, [self.get_testdata_path('testkey_rsa4096_pub.pem')]))
# Valid image checked with non existed key file path.
self.assertFalse(desc.verify_vbmeta_image(
@@ -448,56 +601,6 @@
# Valid image but checked with empty list of keys.
self.assertFalse(desc.verify_vbmeta_image(vbmeta_image, []))
- def test_verify_vbmeta_image_with_2_icp_from_different_logs(self):
- """Tests the verify_vbmeta_image method."""
- # Valid vbmeta image without footer with 2 ICPs from different logs.
- tool = aftltool.Aftl()
- image_path = self.get_testdata_path(
- 'aftltool/aftl_output_vbmeta_with_2_icp_different_logs.img')
- vbmeta_image, _ = tool.get_vbmeta_image(image_path)
- desc = tool.get_aftl_image(image_path)
-
- # Valid image checked against log keys from both logs.
- self.assertTrue(desc.verify_vbmeta_image(
- vbmeta_image, [
- self.get_testdata_path('aftltool/aftl_pubkey_1.pub'),
- self.get_testdata_path('aftltool/aftl_pubkey_2.pub')
- ]))
-
- # Valid image checked with one of the keys with an invalid file path.
- self.assertFalse(desc.verify_vbmeta_image(
- vbmeta_image, [
- self.get_testdata_path('aftltool/aftl_pubkey_1.pub'),
- self.get_testdata_path('non_existent_blabli')
- ]))
-
- # Valid image checked with one of the keys being a invalid key.
- self.assertFalse(desc.verify_vbmeta_image(
- vbmeta_image, [
- self.get_testdata_path('aftltool/aftl_pubkey_1.pub'),
- self.get_testdata_path('large_blob.bin')
- ]))
-
- # Valid image checked with one of the keys being None.
- self.assertFalse(desc.verify_vbmeta_image(
- vbmeta_image, [
- self.get_testdata_path('aftltool/aftl_pubkey_1.pub'),
- None
- ]))
-
- # Valid vbmeta image checked against only one of the log keys.
- self.assertFalse(desc.verify_vbmeta_image(
- vbmeta_image, [self.get_testdata_path('aftltool/aftl_pubkey_1.pub')]))
- self.assertFalse(desc.verify_vbmeta_image(
- vbmeta_image, [self.get_testdata_path('aftltool/aftl_pubkey_2.pub')]))
-
- # Valid image checked with invalid key.
- self.assertFalse(desc.verify_vbmeta_image(
- vbmeta_image, [self.get_testdata_path('large_blob.bin')]))
-
- # Valid image but checked with empty list of keys.
- self.assertFalse(desc.verify_vbmeta_image(vbmeta_image, []))
-
def test_encode(self):
"""Tests encode method."""
desc_bytes = self.test_aftl_desc.encode()
@@ -649,7 +752,7 @@
self.assertEqual(entry.log_url_size, 0)
self.assertEqual(entry.leaf_index, 0)
self.assertEqual(entry.log_root_descriptor_size, 29)
- self.assertEqual(entry.fw_info_leaf_size, 0)
+ self.assertEqual(entry.annotation_leaf_size, 19)
self.assertEqual(entry.log_root_sig_size, 0)
self.assertEqual(entry.proof_hash_count, 0)
self.assertEqual(entry.inc_proof_size, 0)
@@ -663,7 +766,7 @@
entry = aftltool.AftlIcpEntry(self.test_entry_1_bytes)
self.assertEqual(entry.log_url_size, len(self.test_tl_url_1))
self.assertEqual(entry.leaf_index, 1)
- self.assertEqual(entry.fw_info_leaf_size, 0)
+ self.assertEqual(entry.annotation_leaf_size, 139)
self.assertEqual(entry.log_root_sig_size, 512)
self.assertEqual(entry.proof_hash_count, len(self.test_proof_hashes_1))
self.assertEqual(entry.inc_proof_size, 128)
@@ -680,11 +783,11 @@
"""Tests get_expected_size method."""
# Default record.
entry = aftltool.AftlIcpEntry()
- self.assertEqual(entry.get_expected_size(), 56)
+ self.assertEqual(entry.get_expected_size(), 75)
self.assertEqual(entry.get_expected_size(), len(entry.encode()))
# Test record.
- self.assertEqual(self.test_entry_1.get_expected_size(), 755)
+ self.assertEqual(self.test_entry_1.get_expected_size(), 894)
self.assertEqual(self.test_entry_1.get_expected_size(),
len(self.test_entry_1.encode()))
@@ -717,15 +820,17 @@
def test_translate_response(self):
"""Tests translate_response method."""
entry = aftltool.AftlIcpEntry()
- entry.translate_response('aftl-test.foo.bar:80', self.test_afi_resp)
+ entry.translate_response('aftl-test.foo.bar:80', self.test_avbm_resp)
self.assertEqual(entry.log_url, 'aftl-test.foo.bar:80')
- self.assertEqual(entry.leaf_index, 6263)
+ self.assertEqual(entry.leaf_index, 9127)
self.assertEqual(entry.log_root_descriptor.encode(),
- self.test_afi_resp.fw_info_proof.sth.log_root)
- self.assertEqual(entry.log_root_signature,
- self.test_afi_resp.fw_info_proof.sth.log_root_signature)
- self.assertEqual(entry.proofs,
- self.test_afi_resp.fw_info_proof.proof.hashes)
+ self.test_avbm_resp.annotation_proof.sth.log_root)
+ self.assertEqual(
+ entry.log_root_signature,
+ self.test_avbm_resp.annotation_proof.sth.log_root_signature)
+ self.assertEqual(
+ entry.proofs,
+ self.test_avbm_resp.annotation_proof.proof.hashes)
def test_verify_icp(self):
"""Tests verify_icp method."""
@@ -735,24 +840,25 @@
# Valid ICP.
entry = aftltool.AftlIcpEntry()
- entry.translate_response(self.test_tl_url_1, self.test_afi_resp)
+ entry.translate_response(self.test_tl_url_1, self.test_avbm_resp)
self.assertTrue(entry.verify_icp(key_file.name))
- # Invalid ICP where fw_info_leaf is not matching up with proofs.
+ # Invalid ICP where annotation_leaf is not matching up with proofs.
# pylint: disable=protected-access
entry = aftltool.AftlIcpEntry()
- entry.translate_response(self.test_tl_url_1, self.test_afi_resp)
- fw_info_leaf_bytes = entry.fw_info_leaf._fw_info_leaf_bytes.replace(
- b'ViNzEQS', b'1234567')
- entry.fw_info_leaf._fw_info_leaf_bytes = fw_info_leaf_bytes
- self.assertFalse(entry.verify_icp(key_file.name))
+ entry.translate_response(self.test_tl_url_1, self.test_avbm_resp)
+ vbmeta_hash = entry.annotation_leaf.annotation.vbmeta_hash
+ vbmeta_hash = vbmeta_hash.replace(b"\x56\x23\x73\x11",
+ b"\x00\x00\x00\x00")
+ entry.annotation_leaf.annotation.vbmeta_hash = vbmeta_hash
+ self.assertFalse(entry.verify_icp(key_file))
def test_verify_vbmeta_image(self):
"""Tests the verify_vbmeta_image method."""
# Valid vbmeta image without footer with 1 ICP.
tool = aftltool.Aftl()
image_path = self.get_testdata_path(
- 'aftltool/aftl_output_vbmeta_with_1_icp.img')
+ 'aftl_output_vbmeta_with_1_icp.img')
vbmeta_image, _ = tool.get_vbmeta_image(image_path)
desc = tool.get_aftl_image(image_path)
@@ -762,11 +868,11 @@
# Valid vbmeta image checked with correct log key.
self.assertTrue(entry.verify_vbmeta_image(
- vbmeta_image, self.get_testdata_path('aftltool/aftl_pubkey_1.pub')))
+ vbmeta_image, self.get_testdata_path('aftl_pubkey_1.pem')))
# Valid vbmeta image checked with public key of another log.
self.assertFalse(entry.verify_vbmeta_image(
- vbmeta_image, self.get_testdata_path('aftltool/aftl_pubkey_2.pub')))
+ vbmeta_image, self.get_testdata_path('testkey_rsa4096_pub.pem')))
# Valid vbmeta image checked with invalid key.
self.assertFalse(entry.verify_vbmeta_image(
@@ -780,7 +886,7 @@
# Valid vbmeta image without footer with 1 ICP.
tool = aftltool.Aftl()
image_path = self.get_testdata_path(
- 'aftltool/aftl_output_vbmeta_with_1_icp.img')
+ 'aftl_output_vbmeta_with_1_icp.img')
vbmeta_image, _ = tool.get_vbmeta_image(image_path)
desc = tool.get_aftl_image(image_path)
@@ -792,7 +898,7 @@
# Invalid vbmeta image checked with correct log key.
self.assertFalse(entry.verify_vbmeta_image(
- vbmeta_image, self.get_testdata_path('aftltool/aftl_pubkey_1.pub')))
+ vbmeta_image, self.get_testdata_path('aftl_pubkey_1.pem')))
# Invalid vbmeta image checked with invalid key.
self.assertFalse(entry.verify_vbmeta_image(
@@ -803,7 +909,7 @@
# None image checked with a key.
self.assertFalse(entry.verify_vbmeta_image(
- None, self.get_testdata_path('aftltool/aftl_pubkey_1.pub')))
+ None, self.get_testdata_path('aftl_pubkey_1.pem')))
def test_print_desc(self):
"""Tests print_desc method."""
@@ -995,94 +1101,54 @@
self.assertIn('Metadata:', desc)
-class FirmwareInfoLeafTest(AftltoolTestCase):
- """Test suite for testing the FirmwareInfoLeaf."""
+class SignedVBMetaPrimaryAnnotationLeafTest(AftltoolTestCase):
+ """Test suite for testing the Leaf."""
def test__init__(self):
"""Tests constructor and properties methods."""
# Calls constructor without data.
- leaf = aftltool.FirmwareInfoLeaf()
- self.assertTrue(leaf.is_valid())
- self.assertEqual(leaf.vbmeta_hash, None)
- self.assertEqual(leaf.version_incremental, None)
- self.assertEqual(leaf.platform_key, None)
- self.assertEqual(leaf.manufacturer_key_hash, None)
- self.assertEqual(leaf.description, None)
+ leaf = aftltool.SignedVBMetaPrimaryAnnotationLeaf()
+ self.assertEqual(leaf.version, 1)
+ self.assertEqual(leaf.timestamp, 0)
+ self.assertEqual(leaf.signature.signature, b'')
+ self.assertEqual(leaf.annotation.vbmeta_hash, b'')
+ self.assertEqual(leaf.annotation.description, '')
- # Calls constructor with data.
- leaf = aftltool.FirmwareInfoLeaf(self.test_afi_resp.fw_info_leaf)
- self.assertTrue(leaf.is_valid())
- self.assertEqual(
- leaf.vbmeta_hash,
- base64.b64decode('ViNzEQS/oc/bJ13yl40fk/cvXw90bxHQbzCRxgHDIGc='))
- self.assertEqual(leaf.version_incremental, '1')
- self.assertEqual(leaf.platform_key, None)
- self.assertEqual(
- leaf.manufacturer_key_hash,
- base64.b64decode('yBCrUOdjvaAh4git5EgqWa5neegUaoXeLlB67+N8ObY='))
- self.assertEqual(leaf.description, None)
+ def test_parse(self):
+ # Calls parse with valid data.
+ leaf = aftltool.SignedVBMetaPrimaryAnnotationLeaf.parse(
+ self.test_anno_1_bytes)
+ self.assertEqual(leaf.annotation.vbmeta_hash, b'w'*32)
+ self.assertEqual(leaf.annotation.version_incremental, 'x'*5)
+ self.assertEqual(leaf.annotation.manufacturer_key_hash, b'y'*32)
+ self.assertEqual(leaf.annotation.description, 'z'*51)
- # Calls constructor with invalid JSON data.
+ # Calls parse with invalid data.
with self.assertRaises(aftltool.AftlError):
- leaf = aftltool.FirmwareInfoLeaf('Invalid JSON.')
+ leaf = aftltool.SignedVBMetaPrimaryAnnotationLeaf.parse(b'Invalid data')
def test_get_expected_size(self):
"""Tests get_expected_size method."""
# Calls constructor without data.
- leaf = aftltool.FirmwareInfoLeaf()
- self.assertEqual(leaf.get_expected_size(), 0)
+ leaf = aftltool.SignedVBMetaPrimaryAnnotationLeaf()
+ self.assertEqual(leaf.get_expected_size(), 19)
# Calls constructor with data.
- leaf = aftltool.FirmwareInfoLeaf(self.test_afi_resp.fw_info_leaf)
+ leaf = aftltool.SignedVBMetaPrimaryAnnotationLeaf.parse(
+ self.test_anno_1_bytes)
self.assertEqual(leaf.get_expected_size(),
- len(self.test_afi_resp.fw_info_leaf))
+ len(self.test_anno_1_bytes))
def test_encode(self):
"""Tests encode method."""
- # Calls constructor without data.
- leaf = aftltool.FirmwareInfoLeaf()
- self.assertEqual(leaf.encode(), b'')
-
# Calls constructor with data.
- self.assertEqual(self.test_fw_info_leaf.encode(),
- self.test_afi_resp.fw_info_leaf)
-
- def test_is_valid(self):
- """Tests is_valid method."""
- # Calls constructor without data.
- leaf = aftltool.FirmwareInfoLeaf()
- self.assertTrue(leaf.is_valid())
-
- # Calls constructor with data.
- self.assertTrue(self.test_fw_info_leaf.is_valid())
-
- # Incorrect name for Value key.
- invalid_value_key_name = (
- b'{\"timestamp\":{\"seconds\":1580115370,\"nanos\":621454825},\"In'
- b'val\":{\"FwInfo\":{\"info\":{\"info\":{\"vbmeta_hash\":\"ViNzEQS'
- b'/oc/bJ13yl40fk/cvXw90bxHQbzCRxgHDIGc=\",\"version_incremental\":'
- b'\"1\",\"manufacturer_key_hash\":\"yBCrUOdjvaAh4git5EgqWa5neegUao'
- b'XeLlB67+N8ObY=\"}}}}}')
-
- with self.assertRaises(aftltool.AftlError):
- aftltool.FirmwareInfoLeaf(invalid_value_key_name)
-
- # Within Firmware Info having a field which does not exist in
- # proto.aftl_pb2.FirmwareInfo.
- invalid_fields = (
- b'{\"timestamp\":{\"seconds\":1580115370,\"nanos\":621454825},\"Va'
- b'lue\":{\"FwInfo\":{\"info\":{\"info\":{\"invalid_field\":\"ViNzEQS'
- b'/oc/bJ13yl40fk/cvXw90bxHQbzCRxgHDIGc=\",\"version_incremental\":'
- b'\"1\",\"manufacturer_key_hash\":\"yBCrUOdjvaAh4git5EgqWa5neegUao'
- b'XeLlB67+N8ObY=\"}}}}}')
-
- with self.assertRaises(aftltool.AftlError):
- aftltool.FirmwareInfoLeaf(invalid_fields)
+ self.assertEqual(self.test_anno_1.encode(),
+ self.test_anno_1_bytes)
def test_print_desc(self):
"""Tests print_desc method."""
buf = io.StringIO()
- self.test_fw_info_leaf.print_desc(buf)
+ self.test_anno_1.print_desc(buf)
desc = buf.getvalue()
# Cursory check whether the printed description contains something useful.
@@ -1098,7 +1164,7 @@
Arguments:
transparency_log_config: An aftltool.TransparencyLogConfig instance.
- canned_response: AddFirmwareInfoResponse to return or the Exception to
+ canned_response: AddVBMetaResponse to return or the Exception to
raise.
"""
super(AftlMockCommunication, self).__init__(transparency_log_config,
@@ -1106,7 +1172,7 @@
self.request = None
self.canned_response = canned_response
- def add_firmware_info(self, request):
+ def add_vbmeta(self, request):
"""Records the request and returns the canned response."""
self.request = request
@@ -1122,7 +1188,7 @@
"""Initializes the object.
Arguments:
- canned_response: AddFirmwareInfoResponse to return or the Exception to
+ canned_response: AddVBMetaResponse to return or the Exception to
raise.
"""
self.mock_canned_response = canned_response
@@ -1224,8 +1290,8 @@
def set_up_environment(self):
"""Sets up the environment for unit testing without networking."""
self.aftl_host = 'test.foo.bar:9000'
- self.aftl_pubkey = self.get_testdata_path('aftltool/aftl_pubkey_1.pub')
- self.vbmeta_image = self.get_testdata_path('aftltool/aftl_input_vbmeta.img')
+ self.aftl_pubkey = self.get_testdata_path('aftl_pubkey_1.pem')
+ self.vbmeta_image = self.get_testdata_path('aftl_input_vbmeta.img')
self.manufacturer_key = self.get_testdata_path('testkey_rsa4096.pem')
def get_aftl_implementation(self, canned_response):
@@ -1238,14 +1304,14 @@
# Valid vbmeta image without footer and AftlImage.
image, footer = tool.get_vbmeta_image(
- self.get_testdata_path('aftltool/aftl_input_vbmeta.img'))
+ self.get_testdata_path('aftl_input_vbmeta.img'))
self.assertIsNotNone(image)
self.assertEqual(len(image), 4352)
self.assertIsNone(footer)
# Valid vbmeta image without footer but with AftlImage.
image, footer = tool.get_vbmeta_image(
- self.get_testdata_path('aftltool/aftl_output_vbmeta_with_1_icp.img'))
+ self.get_testdata_path('aftl_output_vbmeta_with_1_icp.img'))
self.assertIsNotNone(image)
self.assertEqual(len(image), 4352)
self.assertIsNone(footer)
@@ -1268,12 +1334,12 @@
# Valid vbmeta image without footer with AftlImage.
desc = tool.get_aftl_image(
- self.get_testdata_path('aftltool/aftl_output_vbmeta_with_1_icp.img'))
+ self.get_testdata_path('aftl_output_vbmeta_with_1_icp.img'))
self.assertIsInstance(desc, aftltool.AftlImage)
# Valid vbmeta image without footer and AftlImage.
desc = tool.get_aftl_image(
- self.get_testdata_path('aftltool/aftl_input_vbmeta.img'))
+ self.get_testdata_path('aftl_input_vbmeta.img'))
self.assertIsNone(desc)
# Invalid vbmeta image.
@@ -1284,30 +1350,36 @@
def test_request_inclusion_proof(self):
"""Tests the request_inclusion_proof method."""
# Always work with a mock independent if run as unit or integration tests.
- aftl = AftlMock(self.test_afi_resp)
+ aftl = AftlMock(self.test_avbm_resp)
icp = aftl.request_inclusion_proof(
self.transparency_log_config, b'a' * 1024, '1',
self.get_testdata_path('testkey_rsa4096.pem'), None, None, None)
self.assertEqual(icp.leaf_index,
- self.test_afi_resp.fw_info_proof.proof.leaf_index)
+ self.test_avbm_resp.annotation_proof.proof.leaf_index)
self.assertEqual(icp.proof_hash_count,
- len(self.test_afi_resp.fw_info_proof.proof.hashes))
+ len(self.test_avbm_resp.annotation_proof.proof.hashes))
self.assertEqual(icp.log_url, self.aftl_host)
self.assertEqual(
icp.log_root_descriptor.root_hash, binascii.unhexlify(
- '53b182b55dc1377197c938637f50093131daea4d0696b1eae5b8a014bfde884a'))
+ '9a5f71340f8dc98bdc6320f976dda5f34db8554cb273ba5ab60f1697c519d6f6'))
- self.assertEqual(icp.fw_info_leaf.version_incremental, '1')
+ self.assertEqual(icp.annotation_leaf.annotation.version_incremental,
+ 'only_for_testing')
# To calculate the hash of the a RSA key use the following command:
# openssl rsa -in test/data/testkey_rsa4096.pem -pubout \
# -outform DER | sha256sum
- self.assertEqual(icp.fw_info_leaf.manufacturer_key_hash, base64.b64decode(
- 'yBCrUOdjvaAh4git5EgqWa5neegUaoXeLlB67+N8ObY='))
+ self.assertEqual(
+ icp.annotation_leaf.annotation.manufacturer_key_hash,
+ bytes.fromhex(
+ "83ab3b109b73a1d32dce4153a2de57a1a0485052db8364f3180d98614749d7f7"))
- self.assertEqual(icp.log_root_signature,
- self.test_afi_resp.fw_info_proof.sth.log_root_signature)
- self.assertEqual(icp.proofs, self.test_afi_resp.fw_info_proof.proof.hashes)
+ self.assertEqual(
+ icp.log_root_signature,
+ self.test_avbm_resp.annotation_proof.sth.log_root_signature)
+ self.assertEqual(
+ icp.proofs,
+ self.test_avbm_resp.annotation_proof.proof.hashes)
# pylint: disable=no-member
def test_request_inclusion_proof_failure(self):
@@ -1323,7 +1395,7 @@
def test_request_inclusion_proof_manuf_key_not_4096(self):
"""Tests request_inclusion_proof with manufacturing key not of size 4096."""
# Always work with a mock independent if run as unit or integration tests.
- aftl = AftlMock(self.test_afi_resp)
+ aftl = AftlMock(self.test_avbm_resp)
with self.assertRaises(aftltool.AftlError) as e:
aftl.request_inclusion_proof(
self.transparency_log_config, b'a' * 1024, 'version_inc',
@@ -1332,7 +1404,7 @@
def test_make_and_verify_icp_with_1_log(self):
"""Tests make_icp_from_vbmeta, verify_image_icp & info_image_icp."""
- aftl = self.get_aftl_implementation(self.test_afi_resp)
+ aftl = self.get_aftl_implementation(self.test_avbm_resp)
# Make a VBmeta image with ICP.
with tempfile.NamedTemporaryFile('wb+') as output_file:
@@ -1357,7 +1429,7 @@
def test_make_and_verify_icp_with_2_logs(self):
"""Tests make_icp_from_vbmeta, verify_image_icp & info_image_icp."""
- aftl = self.get_aftl_implementation(self.test_afi_resp)
+ aftl = self.get_aftl_implementation(self.test_avbm_resp)
# Reconfigures default parameters with two transparency logs.
self.make_icp_default_params['transparency_log_configs'] = [
@@ -1388,10 +1460,10 @@
def test_info_image_icp(self):
"""Tests info_image_icp with vbmeta image with 2 ICP."""
# Always work with a mock independent if run as unit or integration tests.
- aftl = AftlMock(self.test_afi_resp)
+ aftl = AftlMock(self.test_avbm_resp)
image_path = self.get_testdata_path(
- 'aftltool/aftl_output_vbmeta_with_2_icp_different_logs.img')
+ 'aftl_output_vbmeta_with_2_icp_same_log.img')
self.info_icp_default_params['vbmeta_image_path'] = image_path
# Verifies the generated image.
@@ -1401,7 +1473,7 @@
def test_info_image_icp_fail(self):
"""Tests info_image_icp with invalid vbmeta image."""
# Always work with a mock independent if run as unit or integration tests.
- aftl = AftlMock(self.test_afi_resp)
+ aftl = AftlMock(self.test_avbm_resp)
image_path = self.get_testdata_path('large_blob.bin')
self.info_icp_default_params['vbmeta_image_path'] = image_path
@@ -1413,34 +1485,18 @@
def test_verify_image_icp(self):
"""Tets verify_image_icp with 2 ICP with all matching log keys."""
# Always work with a mock independent if run as unit or integration tests.
- aftl = AftlMock(self.test_afi_resp)
+ aftl = AftlMock(self.test_avbm_resp)
image_path = self.get_testdata_path(
- 'aftltool/aftl_output_vbmeta_with_2_icp_different_logs.img')
+ 'aftl_output_vbmeta_with_2_icp_same_log.img')
self.verify_icp_default_params['vbmeta_image_path'] = image_path
self.verify_icp_default_params['transparency_log_pub_keys'] = [
- self.get_testdata_path('aftltool/aftl_pubkey_1.pub'),
- self.get_testdata_path('aftltool/aftl_pubkey_2.pub')
+ self.get_testdata_path('aftl_pubkey_1.pem'),
]
result = aftl.verify_image_icp(**self.verify_icp_default_params)
self.assertTrue(result)
- def test_verify_image_icp_failure(self):
- """Tests verify_image_icp with 2 ICP but only one matching log key."""
- # Always work with a mock independent if run as unit or integration tests.
- aftl = AftlMock(self.test_afi_resp)
-
- image_path = self.get_testdata_path(
- 'aftltool/aftl_output_vbmeta_with_2_icp_different_logs.img')
- self.verify_icp_default_params['vbmeta_image_path'] = image_path
- self.verify_icp_default_params['transparency_log_pub_keys'] = [
- self.get_testdata_path('aftltool/aftl_pubkey_1.pub')
- ]
-
- result = aftl.verify_image_icp(**self.verify_icp_default_params)
- self.assertFalse(result)
-
def test_make_icp_with_invalid_grpc_service(self):
"""Tests make_icp_from_vbmeta command with a host not supporting GRPC."""
aftl = self.get_aftl_implementation(aftltool.AftlError('Comms error'))
@@ -1468,7 +1524,7 @@
def test_load_test_single_process_single_submission(self):
"""Tests load_test_aftl command with 1 process which does 1 submission."""
- aftl = self.get_aftl_implementation(self.test_afi_resp)
+ aftl = self.get_aftl_implementation(self.test_avbm_resp)
with tempfile.TemporaryDirectory() as tmp_dir:
self.load_test_aftl_default_params[
@@ -1485,7 +1541,7 @@
def test_load_test_multi_process_multi_submission(self):
"""Tests load_test_aftl command with 2 processes and 2 submissions each."""
- aftl = self.get_aftl_implementation(self.test_afi_resp)
+ aftl = self.get_aftl_implementation(self.test_avbm_resp)
self.load_test_aftl_default_params['process_count'] = 2
self.load_test_aftl_default_params['submission_count'] = 2
diff --git a/avbtool.py b/avbtool.py
index 4b9c594..7dfbbc0 100755
--- a/avbtool.py
+++ b/avbtool.py
@@ -732,11 +732,12 @@
NUM_CHUNKS_AND_BLOCKS_FORMAT = '<II'
NUM_CHUNKS_AND_BLOCKS_OFFSET = 16
- def __init__(self, image_filename):
+ def __init__(self, image_filename, read_only=False):
"""Initializes an image handler.
Arguments:
image_filename: The name of the file to operate on.
+ read_only: True if file is only opened for read-only operations.
Raises:
ValueError: If data in the file is invalid.
@@ -745,6 +746,7 @@
self._num_total_blocks = 0
self._num_total_chunks = 0
self._file_pos = 0
+ self._read_only = read_only
self._read_header()
def _read_header(self):
@@ -759,7 +761,10 @@
self.is_sparse = False
self.block_size = 4096
self._file_pos = 0
- self._image = open(self.filename, 'r+b')
+ if self._read_only:
+ self._image = open(self.filename, 'rb')
+ else:
+ self._image = open(self.filename, 'r+b')
self._image.seek(0, os.SEEK_END)
self.image_size = self._image.tell()
@@ -885,9 +890,15 @@
Arguments:
num_bytes: Size in number of bytes of the DONT_CARE chunk.
+
+ Raises
+ OSError: If ImageHandler was initialized in read-only mode.
"""
assert num_bytes % self.block_size == 0
+ if self._read_only:
+ raise OSError('ImageHandler is in read-only mode.')
+
if not self.is_sparse:
self._image.seek(0, os.SEEK_END)
# This is more efficient that writing NUL bytes since it'll add
@@ -916,9 +927,15 @@
Arguments:
data: Data to append as bytes.
+
+ Raises
+ OSError: If ImageHandler was initialized in read-only mode.
"""
assert len(data) % self.block_size == 0
+ if self._read_only:
+ raise OSError('ImageHandler is in read-only mode.')
+
if not self.is_sparse:
self._image.seek(0, os.SEEK_END)
self._image.write(data)
@@ -947,11 +964,17 @@
Arguments:
fill_data: Fill data to append - must be four bytes.
size: Number of chunk - must be a multiple of four and the block size.
+
+ Raises
+ OSError: If ImageHandler was initialized in read-only mode.
"""
assert len(fill_data) == 4
assert size % 4 == 0
assert size % self.block_size == 0
+ if self._read_only:
+ raise OSError('ImageHandler is in read-only mode.')
+
if not self.is_sparse:
self._image.seek(0, os.SEEK_END)
self._image.write(fill_data * (size//4))
@@ -1051,7 +1074,11 @@
Raises:
ValueError: If desired size isn't a multiple of the block size.
+ OSError: If ImageHandler was initialized in read-only mode.
"""
+ if self._read_only:
+ raise OSError('ImageHandler is in read-only mode.')
+
if not self.is_sparse:
self._image.truncate(size)
self._read_header()
@@ -1467,7 +1494,7 @@
image = image_containing_descriptor
else:
image_filename = os.path.join(image_dir, self.partition_name + image_ext)
- image = ImageHandler(image_filename)
+ image = ImageHandler(image_filename, read_only=True)
# Generate the hashtree and checks that it matches what's in the file.
digest_size = len(hashlib.new(self.hash_algorithm).digest())
digest_padding = round_to_pow2(digest_size) - digest_size
@@ -1635,7 +1662,7 @@
image = image_containing_descriptor
else:
image_filename = os.path.join(image_dir, self.partition_name + image_ext)
- image = ImageHandler(image_filename)
+ image = ImageHandler(image_filename, read_only=True)
data = image.read(self.image_size)
ha = hashlib.new(self.hash_algorithm)
ha.update(self.salt)
@@ -2169,7 +2196,7 @@
Raises:
AvbError: If there's no footer in the image.
"""
- image = ImageHandler(image_filename)
+ image = ImageHandler(image_filename, read_only=True)
(footer, _, _, _) = self._parse_image(image)
if not footer:
raise AvbError('Given image does not have a footer.')
@@ -2365,7 +2392,7 @@
image_filename: Image file to get information from (file object).
output: Output file to write human-readable information to (file object).
"""
- image = ImageHandler(image_filename)
+ image = ImageHandler(image_filename, read_only=True)
o = output
(footer, header, descriptors, image_size) = self._parse_image(image)
@@ -2460,7 +2487,7 @@
print('Verifying image {} using embedded public key'.format(
image_filename))
- image = ImageHandler(image_filename)
+ image = ImageHandler(image_filename, read_only=True)
(footer, header, descriptors, _) = self._parse_image(image)
offset = 0
if footer:
@@ -2553,7 +2580,7 @@
Raises:
AvbError: If getting the partition digests from the image fails.
"""
- image = ImageHandler(image_filename)
+ image = ImageHandler(image_filename, read_only=True)
(_, _, descriptors, _) = self._parse_image(image)
for desc in descriptors:
@@ -2590,7 +2617,7 @@
image_dir = os.path.dirname(image_filename)
image_ext = os.path.splitext(image_filename)[1]
- image = ImageHandler(image_filename)
+ image = ImageHandler(image_filename, read_only=True)
(footer, header, descriptors, _) = self._parse_image(image)
offset = 0
if footer:
@@ -2607,7 +2634,7 @@
if isinstance(desc, AvbChainPartitionDescriptor):
ch_image_filename = os.path.join(image_dir,
desc.partition_name + image_ext)
- ch_image = ImageHandler(ch_image_filename)
+ ch_image = ImageHandler(ch_image_filename, read_only=True)
(ch_footer, ch_header, _, _) = self._parse_image(ch_image)
ch_offset = 0
ch_size = (ch_header.SIZE + ch_header.authentication_data_block_size +
@@ -2630,7 +2657,7 @@
output: Output file to write human-readable information to (file object).
"""
- image = ImageHandler(image_filename)
+ image = ImageHandler(image_filename, read_only=True)
_, _, descriptors, _ = self._parse_image(image)
image_dir = os.path.dirname(image_filename)
@@ -2641,7 +2668,7 @@
if isinstance(desc, AvbChainPartitionDescriptor):
ch_image_filename = os.path.join(image_dir,
desc.partition_name + image_ext)
- ch_image = ImageHandler(ch_image_filename)
+ ch_image = ImageHandler(ch_image_filename, read_only=True)
_, _, ch_descriptors, _ = self._parse_image(ch_image)
for ch_desc in ch_descriptors:
if isinstance(ch_desc, AvbKernelCmdlineDescriptor):
@@ -2871,7 +2898,8 @@
# Use the bump logic in AvbVBMetaHeader to calculate the max required
# version of all included descriptors.
for image in include_descriptors_from_image:
- (_, image_header, _, _) = self._parse_image(ImageHandler(image.name))
+ (_, image_header, _, _) = self._parse_image(ImageHandler(
+ image.name, read_only=True))
tmp_header.bump_required_libavb_version_minor(
image_header.required_libavb_version_minor)
@@ -3047,7 +3075,7 @@
if include_descriptors_from_image:
descriptors_dict = dict()
for image in include_descriptors_from_image:
- image_handler = ImageHandler(image.name)
+ image_handler = ImageHandler(image.name, read_only=True)
(_, image_vbmeta_header, image_descriptors, _) = self._parse_image(
image_handler)
# Bump the required libavb version to support all included descriptors.
diff --git a/libavb/avb_slot_verify.c b/libavb/avb_slot_verify.c
index f107cf0..fc4c564 100644
--- a/libavb/avb_slot_verify.c
+++ b/libavb/avb_slot_verify.c
@@ -105,11 +105,11 @@
}
if (*out_image_buf != NULL) {
+ *out_image_preloaded = true;
if (part_num_read != image_size) {
avb_errorv(part_name, ": Read incorrect number of bytes.\n", NULL);
return AVB_SLOT_VERIFY_RESULT_ERROR_IO;
}
- *out_image_preloaded = true;
}
}
diff --git a/libavb_aftl/avb_aftl_types.h b/libavb_aftl/avb_aftl_types.h
index 09610f3..028ffda 100644
--- a/libavb_aftl/avb_aftl_types.h
+++ b/libavb_aftl/avb_aftl_types.h
@@ -52,9 +52,8 @@
#define AVB_AFTL_MAX_PROOF_SIZE 64 * AVB_AFTL_HASH_SIZE
/* Max URL limit. */
#define AVB_AFTL_MAX_URL_SIZE 2048ul
-/* Minimum valid size for a FirmwareInfo leaf. Derived from a minimal json
- response that contains only the vbmeta_hash. */
-#define AVB_AFTL_MIN_FW_INFO_SIZE 103ul
+/* Minimum valid size for an Annotation leaf. */
+#define AVB_AFTL_MIN_ANNOTATION_SIZE 18ul
/* Minimum valid size for a TrillianLogRootDescriptor. See the
TrillianLogRootDescriptor struct for details. The values here cover:
version: sizeof(uint16_t)
@@ -74,27 +73,27 @@
log_url_size: sizeof(uint32_t)
leaf_index: sizeof(uint64_t)
log_root_descriptor_size: sizeof(uint32_t)
- fw_info_leaf_size: sizeof(uint32_t)
+ annotation_leaf_size: sizeof(uint32_t)
log_root_sig_size: sizeof(uint32_t)
proof_hash_count: sizeof(uint8_t)
inc_proof_size: sizeof(uint32_t)
log_url: 4 (shortest practical URL)
log_root_descriptor: AVB_AFTL_MIN_TLRD_SIZE
- fw_info_leaf: AVB_AFTL_MIN_FW_INFO_SIZE
+ annotation_leaf: AVB_AFTL_MIN_ANNOTATION_SIZE
log_root_signature: AVB_AFTL_SIGNATURE_SIZE
proofs: AVB_AFTL_HASH_SIZE as there must be at least one hash. */
#define AVB_AFTL_MIN_AFTL_ICP_ENTRY_SIZE \
(sizeof(uint32_t) + sizeof(uint64_t) + sizeof(uint32_t) + sizeof(uint32_t) + \
sizeof(uint32_t) + sizeof(uint8_t) + sizeof(uint32_t) + 4 + \
- AVB_AFTL_MIN_TLRD_SIZE + AVB_AFTL_MIN_FW_INFO_SIZE + \
+ AVB_AFTL_MIN_TLRD_SIZE + AVB_AFTL_MIN_ANNOTATION_SIZE + \
AVB_AFTL_SIGNATURE_SIZE + AVB_AFTL_HASH_SIZE)
/* The maximum AftlIcpEntrySize is the max AftlImage size minus the size
of the AftlImageHeader. */
#define AVB_AFTL_MAX_AFTL_ICP_ENTRY_SIZE \
(AVB_AFTL_MAX_AFTL_IMAGE_SIZE - sizeof(AftlImageHeader))
-/* The maximum FirmwareInfo is the max AftlImage size minus the
+/* The maximum Annotation size is the max AftlImage size minus the
size of the smallest valid AftlIcpEntry. */
-#define AVB_AFTL_MAX_FW_INFO_SIZE \
+#define AVB_AFTL_MAX_ANNOTATION_SIZE \
(AVB_AFTL_MAX_AFTL_IMAGE_SIZE - AVB_AFTL_MIN_AFTL_ICP_ENTRY_SIZE)
/* The maximum metadata size in a TrillianLogRootDescriptor for AFTL is the
max AftlImage size minus the smallest valid AftlIcpEntry size. */
@@ -105,15 +104,6 @@
#define AVB_AFTL_MAX_TLRD_SIZE \
(AVB_AFTL_MIN_TLRD_SIZE + AVB_AFTL_MAX_METADATA_SIZE)
-/* Data structure containing AFTL header information. */
-typedef struct AftlImageHeader {
- uint32_t magic;
- uint32_t required_icp_version_major;
- uint32_t required_icp_version_minor;
- uint32_t image_size; /* Total size of the AftlImage, including this header */
- uint16_t icp_count;
-} AVB_ATTR_PACKED AftlImageHeader;
-
/* Data structure containing a Trillian LogRootDescriptor, from
https://github.com/google/trillian/blob/master/trillian.proto#L255
The log_root_signature is calculated over this structure. */
@@ -128,15 +118,52 @@
uint8_t* metadata;
} TrillianLogRootDescriptor;
-/* Data structure containing the firmware image info stored in the
- transparency log. This is defined in
- https://android.googlesource.com/platform/external/avb/+/master/proto/aftl.proto
- */
-typedef struct FirmwareInfo {
- uint32_t vbmeta_hash_size;
+typedef enum {
+ AVB_AFTL_HASH_SHA256,
+ _AVB_AFTL_HASH_ALGORITHM_NUM
+} HashAlgorithm;
+
+typedef enum {
+ AVB_AFTL_SIGNATURE_RSA, // RSA with PKCS1v15
+ AVB_AFTL_SIGNATURE_ECDSA, // ECDSA with P256 curve
+ _AVB_AFTL_SIGNATURE_ALGORITHM_NUM
+} SignatureAlgorithm;
+
+/* Data structure containing the signature within a leaf of the VBMeta
+ * annotation. This signature is made using the manufacturer key which is
+ * generally not available at boot time. Therefore, this structure is not
+ * verified by the bootloader. */
+typedef struct {
+ uint8_t hash_algorithm;
+ uint8_t signature_algorithm;
+ uint16_t signature_size;
+ uint8_t* signature;
+} Signature;
+
+/* Data structure containing the VBMeta annotation. */
+typedef struct {
+ uint8_t vbmeta_hash_size;
uint8_t* vbmeta_hash;
- uint8_t* json_data;
-} FirmwareInfo;
+ uint8_t version_incremental_size;
+ uint8_t* version_incremental;
+ uint8_t manufacturer_key_hash_size;
+ uint8_t* manufacturer_key_hash;
+ uint16_t description_size;
+ uint8_t* description;
+} VBMetaPrimaryAnnotation;
+
+#define AVB_AFTL_VBMETA_LEAF 0
+#define AVB_AFTL_SIGNED_VBMETA_PRIMARY_ANNOTATION_LEAF 1
+
+/* Data structure containing the leaf that is stored in the
+ transparency log. */
+typedef struct {
+ uint8_t version;
+ uint64_t timestamp;
+ uint8_t leaf_type;
+ Signature* signature;
+ VBMetaPrimaryAnnotation* annotation;
+} SignedVBMetaPrimaryAnnotationLeaf;
/* Data structure containing AFTL inclusion proof data from a single
transparency log. */
@@ -144,22 +171,33 @@
uint32_t log_url_size;
uint64_t leaf_index;
uint32_t log_root_descriptor_size;
- uint32_t fw_info_leaf_size;
+ uint32_t annotation_leaf_size;
uint16_t log_root_sig_size;
uint8_t proof_hash_count;
uint32_t inc_proof_size;
uint8_t* log_url;
TrillianLogRootDescriptor log_root_descriptor;
- FirmwareInfo fw_info_leaf;
+ uint8_t* log_root_descriptor_raw;
+ SignedVBMetaPrimaryAnnotationLeaf* annotation_leaf;
+ uint8_t* annotation_leaf_raw;
uint8_t* log_root_signature;
- uint8_t proofs[/*proof_hash_count*/][AVB_AFTL_HASH_SIZE];
-} AVB_ATTR_PACKED AftlIcpEntry;
+ uint8_t (*proofs)[AVB_AFTL_HASH_SIZE];
+} AftlIcpEntry;
+
+/* Data structure containing AFTL header information. */
+typedef struct AftlImageHeader {
+ uint32_t magic;
+ uint32_t required_icp_version_major;
+ uint32_t required_icp_version_minor;
+ uint32_t image_size; /* Total size of the AftlImage, including this header */
+ uint16_t icp_count;
+} AVB_ATTR_PACKED AftlImageHeader;
/* Main data structure for an AFTL image. */
typedef struct AftlImage {
AftlImageHeader header;
AftlIcpEntry** entries;
-} AVB_ATTR_PACKED AftlImage;
+} AftlImage;
#ifdef __cplusplus
}
diff --git a/libavb_aftl/avb_aftl_util.c b/libavb_aftl/avb_aftl_util.c
index e3747e1..f780e82 100644
--- a/libavb_aftl/avb_aftl_util.c
+++ b/libavb_aftl/avb_aftl_util.c
@@ -47,105 +47,6 @@
return true;
}
-/* Calculates a SHA256 hash of the TrillianLogRootDescriptor in icp_entry.
-
- The hash is calculated over the entire TrillianLogRootDescriptor
- structure. Some of the fields in this implementation are dynamically
- allocated, and so the data needs to be reconstructed so that the hash
- can be properly calculated. The TrillianLogRootDescriptor is defined
- here: https://github.com/google/trillian/blob/master/trillian.proto#L255 */
-bool avb_aftl_hash_log_root_descriptor(AftlIcpEntry* icp_entry, uint8_t* hash) {
- uint8_t* buffer;
- uint8_t* lrd_offset; /* Byte offset into the descriptor. */
- uint32_t tlrd_size;
- uint16_t version;
- uint64_t tree_size;
- uint64_t timestamp;
- uint64_t revision;
- uint16_t metadata_size;
- bool retval;
-
- avb_assert(icp_entry != NULL && hash != NULL);
-
- /* Size of the non-pointer elements of the TrillianLogRootDescriptor. */
- tlrd_size = sizeof(uint16_t) * 2 + sizeof(uint64_t) * 3 + sizeof(uint8_t);
- /* Ensure the log_root_descriptor size is correct. */
- if (icp_entry->log_root_descriptor_size > AVB_AFTL_MAX_TLRD_SIZE) {
- avb_error("Invalid log root descriptor size.\n");
- return false;
- }
- if (icp_entry->log_root_descriptor_size !=
- (tlrd_size + icp_entry->log_root_descriptor.root_hash_size +
- icp_entry->log_root_descriptor.metadata_size)) {
- avb_error("Log root descriptor size doesn't match fields.\n");
- return false;
- }
- /* Check that the root_hash exists, and if not, it's size is sane. */
- if (!icp_entry->log_root_descriptor.root_hash &&
- (icp_entry->log_root_descriptor.root_hash_size != 0)) {
- avb_error("Invalid tree root hash values.\n");
- return false;
- }
-
- /* Check that the metadata exists, and if not, it's size is sane. */
- if (!icp_entry->log_root_descriptor.metadata &&
- (icp_entry->log_root_descriptor.metadata_size != 0)) {
- avb_error("Invalid log root descriptor metadata values.\n");
- return false;
- }
- buffer = (uint8_t*)avb_malloc(icp_entry->log_root_descriptor_size);
- if (buffer == NULL) {
- avb_error("Allocation failure in avb_aftl_hash_log_root_descriptor.\n");
- return false;
- }
- lrd_offset = buffer;
- /* Copy in the version, tree_size and root hash length. */
- /* Ensure endianness is correct. */
- version = avb_be16toh(icp_entry->log_root_descriptor.version);
- avb_memcpy(lrd_offset, &version, sizeof(uint16_t));
- lrd_offset += sizeof(uint16_t);
- /* Ensure endianness is correct. */
- tree_size = avb_be64toh(icp_entry->log_root_descriptor.tree_size);
- avb_memcpy(lrd_offset, &tree_size, sizeof(uint64_t));
- lrd_offset += sizeof(uint64_t);
- avb_memcpy(lrd_offset,
- &(icp_entry->log_root_descriptor.root_hash_size),
- sizeof(uint8_t));
- lrd_offset += sizeof(uint8_t);
- /* Copy the root hash. */
- if (icp_entry->log_root_descriptor.root_hash_size > 0) {
- avb_memcpy(lrd_offset,
- icp_entry->log_root_descriptor.root_hash,
- icp_entry->log_root_descriptor.root_hash_size);
- }
- lrd_offset += icp_entry->log_root_descriptor.root_hash_size;
- /* Copy in the timestamp, revision, and the metadata length. */
- /* Ensure endianness is correct. */
- timestamp = avb_be64toh(icp_entry->log_root_descriptor.timestamp);
- avb_memcpy(lrd_offset, ×tamp, sizeof(uint64_t));
- lrd_offset += sizeof(uint64_t);
- /* Ensure endianness is correct. */
- revision = avb_be64toh(icp_entry->log_root_descriptor.revision);
- avb_memcpy(lrd_offset, &revision, sizeof(uint64_t));
- lrd_offset += sizeof(uint64_t);
- /* Ensure endianness is correct. */
- metadata_size = avb_be16toh(icp_entry->log_root_descriptor.metadata_size);
- avb_memcpy(lrd_offset, &metadata_size, sizeof(uint16_t));
- lrd_offset += sizeof(uint16_t);
-
- /* Copy the metadata if it exists. */
- if (icp_entry->log_root_descriptor.metadata_size > 0) {
- avb_memcpy(lrd_offset,
- icp_entry->log_root_descriptor.metadata,
- icp_entry->log_root_descriptor.metadata_size);
- }
- /* Hash the result & clean up. */
-
- retval = avb_aftl_sha256(buffer, icp_entry->log_root_descriptor_size, hash);
- avb_free(buffer);
- return retval;
-}
-
/* Computes a leaf hash as detailed by https://tools.ietf.org/html/rfc6962. */
bool avb_aftl_rfc6962_hash_leaf(uint8_t* leaf,
uint64_t leaf_size,
@@ -393,6 +294,61 @@
return retval;
}
+/* Defines helper functions read_u8, read_u16, read_u32 and read_u64. These
+ * functions can be used to read from a |data| stream a |value| of a specific
+ * size. The value endianness is converted from big-endian to host. We ensure
+ * that the read do not overflow beyond |data_end|. If successful, |data| is
+ * brought forward by the size of the value read.
+ */
+#define _read_u(fct) \
+ { \
+ size_t value_size = sizeof(*value); \
+ if ((*data + value_size) < *data) return false; \
+ if ((*data + value_size) > data_end) return false; \
+ avb_memcpy(value, *data, value_size); \
+ *value = fct(*value); \
+ *data += value_size; \
+ return true; \
+ }
+static bool read_u8(uint8_t* value, uint8_t** data, uint8_t* data_end) {
+ _read_u();
+}
+AVB_ATTR_WARN_UNUSED_RESULT
+static bool read_u16(uint16_t* value, uint8_t** data, uint8_t* data_end) {
+ _read_u(avb_be16toh);
+}
+AVB_ATTR_WARN_UNUSED_RESULT
+static bool read_u32(uint32_t* value, uint8_t** data, uint8_t* data_end) {
+ _read_u(avb_be32toh);
+}
+AVB_ATTR_WARN_UNUSED_RESULT
+static bool read_u64(uint64_t* value, uint8_t** data, uint8_t* data_end) {
+ _read_u(avb_be64toh);
+}
+AVB_ATTR_WARN_UNUSED_RESULT
+
+/* Allocates |value_size| bytes into |value| and copy |value_size| bytes from
+ * |data|. Ensure that we don't overflow beyond |data_end|. It is the caller
+ * responsibility to avb_free |value|. Advances the |data| pointer pass the
+ * value that has been read. Returns false if an overflow would have occurred or
+ * if the allocation failed.
+ */
+static bool read_mem(uint8_t** value,
+ size_t value_size,
+ uint8_t** data,
+ uint8_t* data_end) {
+ if (*data + value_size < *data || *data + value_size > data_end) {
+ return false;
+ }
+ *value = (uint8_t*)avb_calloc(value_size);
+ if (!value) {
+ return false;
+ }
+ avb_memcpy(*value, *data, value_size);
+ *data += value_size;
+ return true;
+}
+
/* Allocates and populates a TrillianLogRootDescriptor element in an
AftlIcpEntry from a binary blob.
The blob is expected to be pointing to the beginning of a
@@ -403,220 +359,252 @@
static bool parse_trillian_log_root_descriptor(AftlIcpEntry* icp_entry,
uint8_t** aftl_blob,
size_t aftl_blob_remaining) {
- size_t parsed_size;
-
avb_assert(icp_entry);
avb_assert(aftl_blob);
- avb_assert(aftl_blob_remaining >= AVB_AFTL_MIN_TLRD_SIZE);
- /* Copy in the version field from the blob. */
- avb_memcpy(&(icp_entry->log_root_descriptor.version),
- *aftl_blob,
- avb_aftl_member_size(TrillianLogRootDescriptor, version));
- icp_entry->log_root_descriptor.version =
- avb_be16toh(icp_entry->log_root_descriptor.version);
- *aftl_blob += avb_aftl_member_size(TrillianLogRootDescriptor, version);
- parsed_size = avb_aftl_member_size(TrillianLogRootDescriptor, version);
- /* Copy in the tree size field from the blob. */
- avb_memcpy(&(icp_entry->log_root_descriptor.tree_size),
- *aftl_blob,
- avb_aftl_member_size(TrillianLogRootDescriptor, tree_size));
- icp_entry->log_root_descriptor.tree_size =
- avb_be64toh(icp_entry->log_root_descriptor.tree_size);
- *aftl_blob += avb_aftl_member_size(TrillianLogRootDescriptor, tree_size);
- parsed_size += avb_aftl_member_size(TrillianLogRootDescriptor, tree_size);
- /* Copy in the root hash size field from the blob. */
- avb_memcpy(&(icp_entry->log_root_descriptor.root_hash_size),
- *aftl_blob,
- avb_aftl_member_size(TrillianLogRootDescriptor, root_hash_size));
- if (icp_entry->log_root_descriptor.root_hash_size != AVB_AFTL_HASH_SIZE) {
- avb_error("Invalid root hash size.\n");
- free_aftl_icp_entry(icp_entry);
- return false;
- }
- *aftl_blob += avb_aftl_member_size(TrillianLogRootDescriptor, root_hash_size);
- parsed_size +=
- avb_aftl_member_size(TrillianLogRootDescriptor, root_hash_size);
- /* Copy in the root hash from the blob. */
- icp_entry->log_root_descriptor.root_hash =
- (uint8_t*)avb_calloc(icp_entry->log_root_descriptor.root_hash_size);
- if (!icp_entry->log_root_descriptor.root_hash) {
- avb_error("Failure to allocate root hash.\n");
- free_aftl_icp_entry(icp_entry);
+ uint8_t* blob_end = *aftl_blob + aftl_blob_remaining;
+ if (*aftl_blob > blob_end) {
return false;
}
- avb_memcpy(icp_entry->log_root_descriptor.root_hash,
- *aftl_blob,
- icp_entry->log_root_descriptor.root_hash_size);
- *aftl_blob += icp_entry->log_root_descriptor.root_hash_size;
- parsed_size += icp_entry->log_root_descriptor.root_hash_size;
+ /* Copy in the version field from the blob. */
+ if (!read_u16(
+ &(icp_entry->log_root_descriptor.version), aftl_blob, blob_end)) {
+ avb_error("Unable to parse version.\n");
+ return false;
+ }
+
+ /* Copy in the tree size field from the blob. */
+ if (!read_u64(
+ &(icp_entry->log_root_descriptor.tree_size), aftl_blob, blob_end)) {
+ avb_error("Unable to parse tree size.\n");
+ return false;
+ }
+
+ /* Copy in the root hash size field from the blob. */
+ if (!read_u8(&(icp_entry->log_root_descriptor.root_hash_size),
+ aftl_blob,
+ blob_end)) {
+ avb_error("Unable to parse root hash size.\n");
+ return false;
+ }
+ if (icp_entry->log_root_descriptor.root_hash_size != AVB_AFTL_HASH_SIZE) {
+ avb_error("Invalid root hash size.\n");
+ return false;
+ }
+
+ /* Copy in the root hash from the blob. */
+ if (!read_mem(&(icp_entry->log_root_descriptor.root_hash),
+ icp_entry->log_root_descriptor.root_hash_size,
+ aftl_blob,
+ blob_end)) {
+ avb_error("Unable to parse root hash.\n");
+ return false;
+ }
+
/* Copy in the timestamp field from the blob. */
- avb_memcpy(&(icp_entry->log_root_descriptor.timestamp),
- *aftl_blob,
- avb_aftl_member_size(TrillianLogRootDescriptor, timestamp));
- icp_entry->log_root_descriptor.timestamp =
- avb_be64toh(icp_entry->log_root_descriptor.timestamp);
- *aftl_blob += avb_aftl_member_size(TrillianLogRootDescriptor, timestamp);
- parsed_size += avb_aftl_member_size(TrillianLogRootDescriptor, timestamp);
+ if (!read_u64(
+ &(icp_entry->log_root_descriptor.timestamp), aftl_blob, blob_end)) {
+ avb_error("Unable to parse timestamp.\n");
+ return false;
+ }
+
/* Copy in the revision field from the blob. */
- avb_memcpy(&(icp_entry->log_root_descriptor.revision),
- *aftl_blob,
- avb_aftl_member_size(TrillianLogRootDescriptor, revision));
- icp_entry->log_root_descriptor.revision =
- avb_be64toh(icp_entry->log_root_descriptor.revision);
- *aftl_blob += avb_aftl_member_size(TrillianLogRootDescriptor, revision);
- parsed_size += avb_aftl_member_size(TrillianLogRootDescriptor, revision);
+ if (!read_u64(
+ &(icp_entry->log_root_descriptor.revision), aftl_blob, blob_end)) {
+ avb_error("Unable to parse revision.\n");
+ return false;
+ }
+
/* Copy in the metadata size field from the blob. */
- avb_memcpy(&(icp_entry->log_root_descriptor.metadata_size),
- *aftl_blob,
- avb_aftl_member_size(TrillianLogRootDescriptor, metadata_size));
- icp_entry->log_root_descriptor.metadata_size =
- avb_be16toh(icp_entry->log_root_descriptor.metadata_size);
- *aftl_blob += avb_aftl_member_size(TrillianLogRootDescriptor, metadata_size);
- parsed_size += avb_aftl_member_size(TrillianLogRootDescriptor, metadata_size);
+ if (!read_u16(&(icp_entry->log_root_descriptor.metadata_size),
+ aftl_blob,
+ blob_end)) {
+ avb_error("Unable to parse metadata size.\n");
+ return false;
+ }
+
if (icp_entry->log_root_descriptor.metadata_size >
AVB_AFTL_MAX_METADATA_SIZE) {
avb_error("Invalid metadata size.\n");
- free_aftl_icp_entry(icp_entry);
return false;
}
- if (icp_entry->log_root_descriptor.metadata_size + parsed_size >
- aftl_blob_remaining) {
- avb_error("Invalid AftlImage.\n");
- free_aftl_icp_entry(icp_entry);
- return false;
- }
+
/* If it exists, copy in the metadata field from the blob. */
if (icp_entry->log_root_descriptor.metadata_size > 0) {
- icp_entry->log_root_descriptor.metadata =
- (uint8_t*)avb_calloc(icp_entry->log_root_descriptor.metadata_size);
- if (!icp_entry->log_root_descriptor.metadata) {
- avb_error("Failure to allocate metadata.\n");
- free_aftl_icp_entry(icp_entry);
+ if (!read_mem(&(icp_entry->log_root_descriptor.metadata),
+ icp_entry->log_root_descriptor.metadata_size,
+ aftl_blob,
+ blob_end)) {
+ avb_error("Unable to parse metadata.\n");
return false;
}
- avb_memcpy(icp_entry->log_root_descriptor.metadata,
- *aftl_blob,
- icp_entry->log_root_descriptor.metadata_size);
- *aftl_blob += icp_entry->log_root_descriptor.metadata_size;
} else {
icp_entry->log_root_descriptor.metadata = NULL;
}
return true;
}
-static void base64_decode(uint8_t* input,
- size_t input_size,
- uint8_t* output,
- size_t output_size) {
- size_t i, j;
- uint32_t tmp_val;
- uint8_t decode_table[] = {
- 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1,
- -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
- 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
- -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
- 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51};
- avb_assert(input != NULL);
- avb_assert(output != NULL);
-
- for (i = 0, j = 0; i < input_size; i += 4, j += 3) {
- tmp_val = decode_table[input[i] - '+'];
- tmp_val = (tmp_val << 6) | decode_table[input[i + 1] - '+'];
- tmp_val <<= 6;
- if (input[i + 2] != '=') tmp_val |= decode_table[input[i + 2] - '+'];
- tmp_val <<= 6;
- if (input[i + 3] != '=') tmp_val |= decode_table[input[i + 3] - '+'];
-
- output[j] = (tmp_val >> 16) & 0xff;
- if (input[i + 2] != '=') output[j + 1] = (tmp_val >> 8) & 0xff;
- if (input[i + 3] != '=') output[j + 2] = tmp_val & 0xff;
- }
-}
-
-static bool find_and_decode_vbmeta_hash(uint8_t* vbmeta_hash,
- size_t vbmeta_size,
- uint8_t* json_data,
- size_t json_data_size) {
- const char vbmeta_id[] = "\"vbmeta_hash\":";
- size_t vbmeta_id_size = sizeof(vbmeta_id) - 1;
- size_t vbmeta_base64_size;
- uint8_t* vbmeta_ptr;
- uint8_t* vbmeta_base64;
-
- avb_assert(vbmeta_hash != NULL);
- avb_assert(vbmeta_size == AVB_AFTL_HASH_SIZE);
- avb_assert(json_data != NULL);
- avb_assert(json_data_size > vbmeta_size);
-
- vbmeta_ptr = (uint8_t*)avb_strstr((const char*)json_data, vbmeta_id);
- if (vbmeta_ptr == NULL) {
- vbmeta_hash = NULL;
+/* Parses a Signature from |aftl_blob| into leaf->signature.
+ * Returns false if an error occurred during the parsing */
+static bool parse_signature(SignedVBMetaPrimaryAnnotationLeaf* leaf,
+ uint8_t** aftl_blob,
+ uint8_t* blob_end) {
+ Signature* signature = (Signature*)avb_calloc(sizeof(Signature));
+ if (!signature) {
+ avb_error("Failed to allocate signature.\n");
return false;
}
- /* Jump past the vbmeta_hash identifier */
- vbmeta_ptr += vbmeta_id_size;
- if (vbmeta_ptr[0] == '"') {
- vbmeta_base64_size = 1;
- while (vbmeta_ptr[vbmeta_base64_size] != '"' &&
- vbmeta_base64_size <= AVB_AFTL_HASH_SIZE * 4 / 3 + 1) {
- vbmeta_base64_size++;
- }
- vbmeta_base64 = (uint8_t*)avb_calloc(vbmeta_base64_size + 1);
- if (vbmeta_base64 == NULL) {
- vbmeta_hash = NULL;
- return false;
- }
- avb_memcpy(vbmeta_base64, vbmeta_ptr + 1, vbmeta_base64_size);
- base64_decode(vbmeta_base64, vbmeta_base64_size, vbmeta_hash, vbmeta_size);
- avb_free(vbmeta_base64);
- } else {
- vbmeta_hash = NULL;
+ leaf->signature = signature;
+
+ if (!read_u8(&(signature->hash_algorithm), aftl_blob, blob_end)) {
+ avb_error("Unable to parse the hash algorithm.\n");
+ return false;
+ }
+ if (signature->hash_algorithm >= _AVB_AFTL_HASH_ALGORITHM_NUM) {
+ avb_error("Unexpect hash algorithm in leaf signature.\n");
return false;
}
+ if (!read_u8(&(signature->signature_algorithm), aftl_blob, blob_end)) {
+ avb_error("Unable to parse the signature algorithm.\n");
+ return false;
+ }
+ if (signature->signature_algorithm >= _AVB_AFTL_SIGNATURE_ALGORITHM_NUM) {
+ avb_error("Unexpect signature algorithm in leaf signature.\n");
+ return false;
+ }
+
+ if (!read_u16(&(signature->signature_size), aftl_blob, blob_end)) {
+ avb_error("Unable to parse the signature size.\n");
+ return false;
+ }
+ if (!read_mem(&(signature->signature),
+ signature->signature_size,
+ aftl_blob,
+ blob_end)) {
+ avb_error("Unable to parse signature.\n");
+ return false;
+ }
return true;
}
-/* Allocates and populates a FirmwareInfo element in an
+/* Parses an VBMetaPrimaryAnnotation from |aftl_blob| into leaf->annotation.
+ * Returns false if an error occurred during the parsing */
+static bool parse_annotation(SignedVBMetaPrimaryAnnotationLeaf* leaf,
+ uint8_t** aftl_blob,
+ uint8_t* blob_end) {
+ VBMetaPrimaryAnnotation* annotation =
+ (VBMetaPrimaryAnnotation*)avb_calloc(sizeof(VBMetaPrimaryAnnotation));
+ if (!annotation) {
+ avb_error("Failed to allocate annotation.\n");
+ return false;
+ }
+ leaf->annotation = annotation;
+
+ if (!read_u8(&(annotation->vbmeta_hash_size), aftl_blob, blob_end)) {
+ avb_error("Unable to parse VBMeta hash size.\n");
+ return false;
+ }
+ if (annotation->vbmeta_hash_size != AVB_AFTL_HASH_SIZE) {
+ avb_error("Unexpected VBMeta hash size.\n");
+ return false;
+ }
+ if (!read_mem(&(annotation->vbmeta_hash),
+ annotation->vbmeta_hash_size,
+ aftl_blob,
+ blob_end)) {
+ avb_error("Unable to parse VBMeta hash.\n");
+ return false;
+ }
+
+ if (!read_u8(&(annotation->version_incremental_size), aftl_blob, blob_end)) {
+ avb_error("Unable to parse version incremental size.\n");
+ return false;
+ }
+ if (!read_mem(&(annotation->version_incremental),
+ annotation->version_incremental_size,
+ aftl_blob,
+ blob_end)) {
+ avb_error("Unable to parse version incremental.\n");
+ return false;
+ }
+
+ if (!read_u8(
+ &(annotation->manufacturer_key_hash_size), aftl_blob, blob_end)) {
+ avb_error("Unable to parse manufacturer key hash size.\n");
+ return false;
+ }
+ if (!read_mem(&(annotation->manufacturer_key_hash),
+ annotation->manufacturer_key_hash_size,
+ aftl_blob,
+ blob_end)) {
+ avb_error("Unable to parse manufacturer key hash.\n");
+ return false;
+ }
+
+ if (!read_u16(&(annotation->description_size), aftl_blob, blob_end)) {
+ avb_error("Unable to parse description size.\n");
+ return false;
+ }
+ if (!read_mem(&(annotation->description),
+ annotation->description_size,
+ aftl_blob,
+ blob_end)) {
+ avb_error("Unable to parse description.\n");
+ return false;
+ }
+ return true;
+}
+
+/* Allocates and populates a SignedVBMetaPrimaryAnnotationLeaf element in an
AftlIcpEntry from a binary blob.
The blob is expected to be pointing to the beginning of a
- serialized FirmwareInfo element of an AftlIcpEntry.
- The aftl_blob argument is updated to point to the area after the
- FirmwareInfo leaf. */
-static bool parse_firmware_info(AftlIcpEntry* icp_entry, uint8_t** aftl_blob) {
- /* Copy in the fw_info leaf bytes from the blob. */
- /* Parse out and decode in the vbmeta_hash value from the fw_info
- leaf bytes. */
- icp_entry->fw_info_leaf.json_data =
- (uint8_t*)avb_calloc(icp_entry->fw_info_leaf_size);
- if (icp_entry->fw_info_leaf.json_data == NULL) {
- avb_error("Failed to allocate for FirmwareInfo leaf.\n");
- free_aftl_icp_entry(icp_entry);
- return false;
- }
- avb_memcpy(icp_entry->fw_info_leaf.json_data,
- *aftl_blob,
- icp_entry->fw_info_leaf_size);
- *aftl_blob += icp_entry->fw_info_leaf_size;
-
- icp_entry->fw_info_leaf.vbmeta_hash_size = AVB_AFTL_HASH_SIZE;
- icp_entry->fw_info_leaf.vbmeta_hash =
- (uint8_t*)avb_calloc(icp_entry->fw_info_leaf.vbmeta_hash_size);
- if (icp_entry->fw_info_leaf.vbmeta_hash == NULL) {
- avb_error("Failed to allocate vbmeta hash.\n");
- free_aftl_icp_entry(icp_entry);
- return false;
- }
- if (!find_and_decode_vbmeta_hash(icp_entry->fw_info_leaf.vbmeta_hash,
- icp_entry->fw_info_leaf.vbmeta_hash_size,
- icp_entry->fw_info_leaf.json_data,
- icp_entry->fw_info_leaf_size)) {
- avb_error("Could not parse vbmeta_hash out of FirmwareInfo leaf.\n");
- free_aftl_icp_entry(icp_entry);
+ serialized SignedVBMetaPrimaryAnnotationLeaf element of an AftlIcpEntry.
+ The aftl_blob argument is updated to point to the area after the leaf. */
+static bool parse_annotation_leaf(AftlIcpEntry* icp_entry,
+ uint8_t** aftl_blob) {
+ SignedVBMetaPrimaryAnnotationLeaf* leaf;
+ uint8_t* blob_end = *aftl_blob + icp_entry->annotation_leaf_size;
+ if (*aftl_blob > blob_end) {
return false;
}
+ leaf = (SignedVBMetaPrimaryAnnotationLeaf*)avb_calloc(
+ sizeof(SignedVBMetaPrimaryAnnotationLeaf));
+ if (!leaf) {
+ avb_error("Failed to allocate for annotation leaf.\n");
+ return false;
+ }
+ /* The leaf will be free'd within the free_aftl_icp_entry() */
+ icp_entry->annotation_leaf = leaf;
+ if (!read_u8(&(leaf->version), aftl_blob, blob_end)) {
+ avb_error("Unable to parse version.\n");
+ return false;
+ }
+ if (leaf->version != 1) {
+ avb_error("Unexpected leaf version.\n");
+ return false;
+ }
+ if (!read_u64(&(leaf->timestamp), aftl_blob, blob_end)) {
+ avb_error("Unable to parse timestamp.\n");
+ return false;
+ }
+ if (!read_u8(&(leaf->leaf_type), aftl_blob, blob_end)) {
+ avb_error("Unable to parse version.\n");
+ return false;
+ }
+ if (leaf->leaf_type != AVB_AFTL_SIGNED_VBMETA_PRIMARY_ANNOTATION_LEAF) {
+ avb_error("Unexpected leaf type.\n");
+ return false;
+ }
+ if (!parse_signature(leaf, aftl_blob, blob_end)) {
+ avb_error("Unable to parse signature.\n");
+ return false;
+ }
+ if (!parse_annotation(leaf, aftl_blob, blob_end)) {
+ avb_error("Unable to parse annotation.\n");
+ return false;
+ }
return true;
}
@@ -624,115 +612,100 @@
The blob is expected to be pointing to the beginning of a
serialized AftlIcpEntry structure. */
AftlIcpEntry* parse_icp_entry(uint8_t** aftl_blob, size_t* remaining_size) {
- AftlIcpEntry *icp_entry, *tmp_icp_entry;
- uint32_t proof_size;
- uint64_t parsed_size;
-
- /* Make a temp AftlIcpEntry to get the inclusion proof size
- for memory allocation purposes.*/
- tmp_icp_entry = (AftlIcpEntry*)*aftl_blob;
- proof_size = avb_be32toh(tmp_icp_entry->inc_proof_size);
-
- /* Ensure the calculated size is sane. */
- if (proof_size > AVB_AFTL_MAX_PROOF_SIZE) {
- avb_error("Invalid inclusion proof size.\n");
+ AftlIcpEntry* icp_entry;
+ uint8_t* blob_start = *aftl_blob;
+ uint8_t* blob_end = *aftl_blob + *remaining_size;
+ if (*aftl_blob > blob_end) {
return NULL;
}
- if (*remaining_size < proof_size + AVB_AFTL_MIN_AFTL_ICP_ENTRY_SIZE) {
+ if (*remaining_size < AVB_AFTL_MIN_AFTL_ICP_ENTRY_SIZE) {
avb_error("Invalid AftlImage\n");
return NULL;
}
- icp_entry = (AftlIcpEntry*)avb_calloc(proof_size + sizeof(AftlIcpEntry));
+ icp_entry = (AftlIcpEntry*)avb_calloc(sizeof(AftlIcpEntry));
if (!icp_entry) {
avb_error("Failure allocating AftlIcpEntry\n");
return NULL;
}
+
/* Copy in the log server URL size field. */
- avb_memcpy(&(icp_entry->log_url_size),
- *aftl_blob,
- avb_aftl_member_size(AftlIcpEntry, log_url_size));
- icp_entry->log_url_size = avb_be32toh(icp_entry->log_url_size);
+ if (!read_u32(&(icp_entry->log_url_size), aftl_blob, blob_end)) {
+ avb_error("Unable to parse log url size.\n");
+ avb_free(icp_entry);
+ return NULL;
+ }
if (icp_entry->log_url_size > AVB_AFTL_MAX_URL_SIZE) {
avb_error("Invalid log URL size.\n");
avb_free(icp_entry);
return NULL;
}
- *aftl_blob += avb_aftl_member_size(AftlIcpEntry, log_url_size);
- parsed_size = avb_aftl_member_size(AftlIcpEntry, log_url_size);
/* Copy in the leaf index field. */
- avb_memcpy(&(icp_entry->leaf_index),
- *aftl_blob,
- avb_aftl_member_size(AftlIcpEntry, leaf_index));
- icp_entry->leaf_index = avb_be64toh(icp_entry->leaf_index);
- *aftl_blob += avb_aftl_member_size(AftlIcpEntry, leaf_index);
- parsed_size += avb_aftl_member_size(AftlIcpEntry, leaf_index);
+ if (!read_u64(&(icp_entry->leaf_index), aftl_blob, blob_end)) {
+ avb_error("Unable to parse leaf_index.\n");
+ avb_free(icp_entry);
+ return NULL;
+ }
/* Copy in the TrillianLogRootDescriptor size field. */
- avb_memcpy(&(icp_entry->log_root_descriptor_size),
- *aftl_blob,
- avb_aftl_member_size(AftlIcpEntry, log_root_descriptor_size));
- icp_entry->log_root_descriptor_size =
- avb_be32toh(icp_entry->log_root_descriptor_size);
+ if (!read_u32(&(icp_entry->log_root_descriptor_size), aftl_blob, blob_end)) {
+ avb_error("Unable to parse log root descriptor size.\n");
+ avb_free(icp_entry);
+ return NULL;
+ }
if (icp_entry->log_root_descriptor_size < AVB_AFTL_MIN_TLRD_SIZE ||
icp_entry->log_root_descriptor_size > AVB_AFTL_MAX_TLRD_SIZE) {
avb_error("Invalid TrillianLogRootDescriptor size.\n");
avb_free(icp_entry);
return NULL;
}
- *aftl_blob += avb_aftl_member_size(AftlIcpEntry, log_root_descriptor_size);
- parsed_size += avb_aftl_member_size(AftlIcpEntry, log_root_descriptor_size);
- /* Copy in the FirmwareInfo leaf size field. */
- avb_memcpy(&(icp_entry->fw_info_leaf_size),
- *aftl_blob,
- avb_aftl_member_size(AftlIcpEntry, fw_info_leaf_size));
- icp_entry->fw_info_leaf_size = avb_be32toh(icp_entry->fw_info_leaf_size);
- if (icp_entry->fw_info_leaf_size == 0 ||
- icp_entry->fw_info_leaf_size > AVB_AFTL_MAX_FW_INFO_SIZE) {
- avb_error("Invalid FirmwareInfo leaf size.\n");
+
+ /* Copy in the annotation leaf size field. */
+ if (!read_u32(&(icp_entry->annotation_leaf_size), aftl_blob, blob_end)) {
+ avb_error("Unable to parse annotation leaf size.\n");
avb_free(icp_entry);
return NULL;
}
- *aftl_blob += avb_aftl_member_size(AftlIcpEntry, fw_info_leaf_size);
- parsed_size += avb_aftl_member_size(AftlIcpEntry, fw_info_leaf_size);
+ if (icp_entry->annotation_leaf_size == 0 ||
+ icp_entry->annotation_leaf_size > AVB_AFTL_MAX_ANNOTATION_SIZE) {
+ avb_error("Invalid annotation leaf size.\n");
+ avb_free(icp_entry);
+ return NULL;
+ }
+
/* Copy the log root signature size field. */
- avb_memcpy(&(icp_entry->log_root_sig_size),
- *aftl_blob,
- avb_aftl_member_size(AftlIcpEntry, log_root_sig_size));
- icp_entry->log_root_sig_size = avb_be16toh(icp_entry->log_root_sig_size);
+ if (!read_u16(&(icp_entry->log_root_sig_size), aftl_blob, blob_end)) {
+ avb_error("Unable to parse log root signature size.\n");
+ avb_free(icp_entry);
+ return NULL;
+ }
if (icp_entry->log_root_sig_size != AVB_AFTL_SIGNATURE_SIZE) {
avb_error("Invalid log root signature size.\n");
avb_free(icp_entry);
return NULL;
}
- *aftl_blob += avb_aftl_member_size(AftlIcpEntry, log_root_sig_size);
- parsed_size += avb_aftl_member_size(AftlIcpEntry, log_root_sig_size);
/* Copy the inclusion proof hash count field. */
- avb_memcpy(&(icp_entry->proof_hash_count),
- *aftl_blob,
- avb_aftl_member_size(AftlIcpEntry, proof_hash_count));
- *aftl_blob += avb_aftl_member_size(AftlIcpEntry, proof_hash_count);
- parsed_size += avb_aftl_member_size(AftlIcpEntry, proof_hash_count);
+ if (!read_u8(&(icp_entry->proof_hash_count), aftl_blob, blob_end)) {
+ avb_error("Unable to parse proof hash count.\n");
+ avb_free(icp_entry);
+ return NULL;
+ }
/* Copy the inclusion proof size field. */
- avb_memcpy(&(icp_entry->inc_proof_size),
- *aftl_blob,
- avb_aftl_member_size(AftlIcpEntry, inc_proof_size));
- icp_entry->inc_proof_size = avb_be32toh(icp_entry->inc_proof_size);
- if (icp_entry->inc_proof_size !=
- icp_entry->proof_hash_count * AVB_AFTL_HASH_SIZE) {
+ if (!read_u32(&(icp_entry->inc_proof_size), aftl_blob, blob_end)) {
+ avb_error("Unable to parse inclusion proof size.\n");
+ avb_free(icp_entry);
+ return NULL;
+ }
+ if ((icp_entry->inc_proof_size !=
+ icp_entry->proof_hash_count * AVB_AFTL_HASH_SIZE) ||
+ (icp_entry->inc_proof_size > AVB_AFTL_MAX_PROOF_SIZE)) {
avb_error("Invalid inclusion proof size.\n");
avb_free(icp_entry);
return NULL;
}
- *aftl_blob += avb_aftl_member_size(AftlIcpEntry, inc_proof_size);
- parsed_size += avb_aftl_member_size(AftlIcpEntry, inc_proof_size);
/* Copy in the log server URL from the blob. */
- if (!avb_safe_add_to(&parsed_size, icp_entry->log_url_size)) {
- avb_error("Invalid URL size.\n");
- free_aftl_icp_entry(icp_entry);
- return NULL;
- }
- if (parsed_size > *remaining_size) {
+ if (*aftl_blob + icp_entry->log_url_size < *aftl_blob ||
+ *aftl_blob + icp_entry->log_url_size > blob_end) {
avb_error("Invalid AftlImage.\n");
avb_free(icp_entry);
return NULL;
@@ -747,49 +720,61 @@
*aftl_blob += icp_entry->log_url_size;
/* Populate the TrillianLogRootDescriptor elements. */
- if (!avb_safe_add_to(&parsed_size, icp_entry->log_root_descriptor_size)) {
- avb_error("Invalid TrillianLogRootDescriptor size.\n");
- free_aftl_icp_entry(icp_entry);
- return NULL;
- }
- if (parsed_size > *remaining_size) {
+ if (*aftl_blob + icp_entry->log_root_descriptor_size < *aftl_blob ||
+ *aftl_blob + icp_entry->log_root_descriptor_size > blob_end) {
avb_error("Invalid AftlImage.\n");
free_aftl_icp_entry(icp_entry);
return NULL;
}
+ icp_entry->log_root_descriptor_raw =
+ (uint8_t*)avb_calloc(icp_entry->log_root_descriptor_size);
+ if (!icp_entry->log_root_descriptor_raw) {
+ avb_error("Failure to allocate log root descriptor.\n");
+ free_aftl_icp_entry(icp_entry);
+ return NULL;
+ }
+ avb_memcpy(icp_entry->log_root_descriptor_raw,
+ *aftl_blob,
+ icp_entry->log_root_descriptor_size);
if (!parse_trillian_log_root_descriptor(
icp_entry, aftl_blob, icp_entry->log_root_descriptor_size)) {
- return NULL;
- }
-
- /* Populate the FirmwareInfo elements. */
- if (!avb_safe_add_to(&parsed_size, icp_entry->fw_info_leaf_size)) {
- avb_error("Invalid FirmwareInfo leaf size.\n");
free_aftl_icp_entry(icp_entry);
return NULL;
}
- if (parsed_size > *remaining_size) {
+
+ /* Populate the annotation leaf. */
+ if (*aftl_blob + icp_entry->annotation_leaf_size < *aftl_blob ||
+ *aftl_blob + icp_entry->annotation_leaf_size > blob_end) {
avb_error("Invalid AftlImage.\n");
free_aftl_icp_entry(icp_entry);
return NULL;
}
- if (!parse_firmware_info(icp_entry, aftl_blob)) return NULL;
+ icp_entry->annotation_leaf_raw =
+ (uint8_t*)avb_calloc(icp_entry->annotation_leaf_size);
+ if (!icp_entry->annotation_leaf_raw) {
+ avb_error("Failure to allocate annotation leaf.\n");
+ free_aftl_icp_entry(icp_entry);
+ return NULL;
+ }
+ avb_memcpy(icp_entry->annotation_leaf_raw,
+ *aftl_blob,
+ icp_entry->annotation_leaf_size);
+ if (!parse_annotation_leaf(icp_entry, aftl_blob)) {
+ free_aftl_icp_entry(icp_entry);
+ return NULL;
+ }
/* Allocate and copy the log root signature from the blob. */
- if (!avb_safe_add_to(&parsed_size, icp_entry->log_root_sig_size)) {
- avb_error("Invalid log root signature size.\n");
- free_aftl_icp_entry(icp_entry);
- return NULL;
- }
- if (parsed_size > *remaining_size) {
+ if (*aftl_blob + icp_entry->log_root_sig_size < *aftl_blob ||
+ *aftl_blob + icp_entry->log_root_sig_size > blob_end) {
avb_error("Invalid AftlImage.\n");
free_aftl_icp_entry(icp_entry);
return NULL;
}
-
icp_entry->log_root_signature =
(uint8_t*)avb_calloc(icp_entry->log_root_sig_size);
if (!icp_entry->log_root_signature) {
+ avb_error("Failure to allocate log root signature.\n");
free_aftl_icp_entry(icp_entry);
return NULL;
}
@@ -797,22 +782,22 @@
icp_entry->log_root_signature, *aftl_blob, icp_entry->log_root_sig_size);
*aftl_blob += icp_entry->log_root_sig_size;
- if (!avb_safe_add_to(&parsed_size, icp_entry->inc_proof_size)) {
- avb_error("Invalid inclusion proof size.\n");
- free_aftl_icp_entry(icp_entry);
- return NULL;
- }
- if (parsed_size > *remaining_size) {
+ /* Finally, copy the proof hash data from the blob to the AftlImage. */
+ if (*aftl_blob + icp_entry->inc_proof_size < *aftl_blob ||
+ *aftl_blob + icp_entry->inc_proof_size > blob_end) {
avb_error("Invalid AftlImage.\n");
free_aftl_icp_entry(icp_entry);
return NULL;
}
-
- /* Finally, copy the proof hash data from the blob to the AftlImage. */
+ icp_entry->proofs = avb_calloc(icp_entry->inc_proof_size);
+ if (!icp_entry->proofs) {
+ free_aftl_icp_entry(icp_entry);
+ return NULL;
+ }
avb_memcpy(icp_entry->proofs, *aftl_blob, icp_entry->inc_proof_size);
*aftl_blob += icp_entry->inc_proof_size;
- *remaining_size -= parsed_size;
+ *remaining_size -= *aftl_blob - blob_start;
return icp_entry;
}
@@ -820,12 +805,16 @@
AftlImage* parse_aftl_image(uint8_t* aftl_blob, size_t aftl_blob_size) {
AftlImage* image;
AftlImageHeader* image_header;
+ AftlIcpEntry* entry;
size_t image_size;
size_t i;
size_t remaining_size;
/* Ensure the blob is at least large enough for an AftlImageHeader */
- avb_assert(aftl_blob_size >= sizeof(AftlImageHeader));
+ if (aftl_blob_size < sizeof(AftlImageHeader)) {
+ avb_error("Invalid image header.\n");
+ return NULL;
+ }
image_header = (AftlImageHeader*)aftl_blob;
/* Check for the magic value for an AftlImageHeader. */
if (image_header->magic != AVB_AFTL_MAGIC) {
@@ -834,9 +823,11 @@
}
/* Extract the size out of the header. */
image_size = avb_be32toh(image_header->image_size);
- if (image_size > AVB_AFTL_MAX_AFTL_IMAGE_SIZE) return NULL;
- avb_assert(image_size >= sizeof(AftlImageHeader) &&
- image_size < AVB_AFTL_MAX_AFTL_IMAGE_SIZE);
+ if (image_size < sizeof(AftlImageHeader) ||
+ image_size > AVB_AFTL_MAX_AFTL_IMAGE_SIZE) {
+ avb_error("Invalid image size.\n");
+ return NULL;
+ }
image = (AftlImage*)avb_calloc(sizeof(AftlImage));
if (!image) {
avb_error("Failed allocation for AftlImage.\n");
@@ -864,7 +855,12 @@
aftl_blob += sizeof(AftlImageHeader);
remaining_size = aftl_blob_size - sizeof(AftlImageHeader);
for (i = 0; i < image->header.icp_count && remaining_size > 0; i++) {
- image->entries[i] = parse_icp_entry(&aftl_blob, &remaining_size);
+ entry = parse_icp_entry(&aftl_blob, &remaining_size);
+ if (!entry) {
+ free_aftl_image(image);
+ return NULL;
+ }
+ image->entries[i] = entry;
}
return image;
@@ -877,16 +873,38 @@
/* Free the log_url and log_root_signature elements if they exist. */
if (icp_entry->log_url) avb_free(icp_entry->log_url);
if (icp_entry->log_root_signature) avb_free(icp_entry->log_root_signature);
- /* Free the FirmwareInfo elements if they exist. */
- if (icp_entry->fw_info_leaf.json_data)
- avb_free(icp_entry->fw_info_leaf.json_data);
- if (icp_entry->fw_info_leaf.vbmeta_hash)
- avb_free(icp_entry->fw_info_leaf.vbmeta_hash);
+ /* Free the annotation elements if they exist. */
+ if (icp_entry->annotation_leaf) {
+ if (icp_entry->annotation_leaf->signature) {
+ if (icp_entry->annotation_leaf->signature->signature) {
+ avb_free(icp_entry->annotation_leaf->signature->signature);
+ }
+ avb_free(icp_entry->annotation_leaf->signature);
+ }
+ if (icp_entry->annotation_leaf->annotation) {
+ if (icp_entry->annotation_leaf->annotation->vbmeta_hash)
+ avb_free(icp_entry->annotation_leaf->annotation->vbmeta_hash);
+ if (icp_entry->annotation_leaf->annotation->version_incremental)
+ avb_free(icp_entry->annotation_leaf->annotation->version_incremental);
+ if (icp_entry->annotation_leaf->annotation->manufacturer_key_hash)
+ avb_free(
+ icp_entry->annotation_leaf->annotation->manufacturer_key_hash);
+ if (icp_entry->annotation_leaf->annotation->description)
+ avb_free(icp_entry->annotation_leaf->annotation->description);
+ avb_free(icp_entry->annotation_leaf->annotation);
+ }
+ avb_free(icp_entry->annotation_leaf);
+ }
+ if (icp_entry->annotation_leaf_raw)
+ avb_free(icp_entry->annotation_leaf_raw);
/* Free the TrillianLogRoot elements if they exist. */
if (icp_entry->log_root_descriptor.metadata)
avb_free(icp_entry->log_root_descriptor.metadata);
if (icp_entry->log_root_descriptor.root_hash)
avb_free(icp_entry->log_root_descriptor.root_hash);
+ if (icp_entry->log_root_descriptor_raw)
+ avb_free(icp_entry->log_root_descriptor_raw);
+ if (icp_entry->proofs) avb_free(icp_entry->proofs);
/* Finally, free the AftlIcpEntry. */
avb_free(icp_entry);
}
diff --git a/libavb_aftl/avb_aftl_validate.c b/libavb_aftl/avb_aftl_validate.c
index 4121792..2d76b2f 100644
--- a/libavb_aftl/avb_aftl_validate.c
+++ b/libavb_aftl/avb_aftl_validate.c
@@ -42,14 +42,15 @@
/* Only SHA256 hashes are currently supported. If the vbmeta hash
size is not AVB_AFTL_HASH_SIZE, return false. */
- if (icp_entry->fw_info_leaf.vbmeta_hash_size != AVB_AFTL_HASH_SIZE) {
+ if (icp_entry->annotation_leaf->annotation->vbmeta_hash_size !=
+ AVB_AFTL_HASH_SIZE) {
avb_error("Invalid VBMeta hash size.\n");
return false;
}
/* Return whether the calculated VBMeta hash matches the stored one. */
return avb_safe_memcmp(vbmeta_hash,
- icp_entry->fw_info_leaf.vbmeta_hash,
+ icp_entry->annotation_leaf->annotation->vbmeta_hash,
AVB_AFTL_HASH_SIZE) == 0;
}
@@ -57,25 +58,14 @@
bool avb_aftl_verify_icp_root_hash(AftlIcpEntry* icp_entry) {
uint8_t leaf_hash[AVB_AFTL_HASH_SIZE];
uint8_t result_hash[AVB_AFTL_HASH_SIZE];
- uint8_t* buffer;
avb_assert(icp_entry != NULL);
- if (icp_entry->fw_info_leaf_size > AVB_AFTL_MAX_FW_INFO_SIZE) {
- avb_error("Invalid FirmwareInfo leaf size\n");
- return false;
- }
- buffer = (uint8_t*)avb_malloc(icp_entry->fw_info_leaf_size);
- if (buffer == NULL) {
- avb_error("Allocation failure in avb_aftl_verify_icp_root_hash\n");
- return false;
- }
/* Calculate the RFC 6962 hash of the seed entry. */
- if (!avb_aftl_rfc6962_hash_leaf(icp_entry->fw_info_leaf.json_data,
- icp_entry->fw_info_leaf_size,
+ if (!avb_aftl_rfc6962_hash_leaf(icp_entry->annotation_leaf_raw,
+ icp_entry->annotation_leaf_size,
leaf_hash)) {
return false;
}
- avb_free(buffer);
/* Calculate the Merkle tree's root hash. */
if (!avb_aftl_root_from_icp(icp_entry->leaf_index,
icp_entry->log_root_descriptor.tree_size,
@@ -114,7 +104,9 @@
log_root_hash_num_bytes = AVB_AFTL_HASH_SIZE;
/* Calculate the SHA256 of the TrillianLogRootDescriptor. */
- if (!avb_aftl_hash_log_root_descriptor(icp_entry, log_root_hash))
+ if (!avb_aftl_sha256(icp_entry->log_root_descriptor_raw,
+ icp_entry->log_root_descriptor_size,
+ log_root_hash))
return false;
/* algorithm_data is used to calculate the padding for signature verification.
diff --git a/proto/README.md b/proto/README.md
index eb3966c..ee64b01 100644
--- a/proto/README.md
+++ b/proto/README.md
@@ -2,27 +2,20 @@
---
This directory contains the proto definitions required to communicate with an
-AFTL server. Two (api.proto and aftl.proto) contain the definitions of the
-protos needed to communicate with the AFTL Trillian personality. The remainder
-are dependencies. The original repos and purpose for each proto file are as
+AFTL server. The original repos and purpose for each proto file are as
follows:
-* aftl.proto
- <!-- TODO(danielaustin): Add detailed message descriptions. -->
- Contains messages used by the AFTL frontend and the Trillian log.
* api.proto
- <!-- TODO(danielaustin): Add detailed message descriptions. -->
- Contains the messages to communicate through the AFTL personality.
+ Contains the messages to communicate with the AFTL personality.
* crypto/keyspb/keyspb.proto
From https://github.com/google/trillian
Dependency of trillian.proto
Contains the PublicKey message definition used by Tree.
* crypto/sigpb/sigpb.proto
From https://github.com/google/trillian
- Dependency of trillian.proto and aftl.proto
+ Dependency of trillian.proto
For trillian.proto, contains the DigitallySigned message used by Tree and
- SignedEntryTimestamp. For aftl.proto, contains the DigitallySigned message
- used by SignedFirmwareInfo.
+ SignedEntryTimestamp.
* trillian.proto
From https://github.com/google/trillian
Dependency of aftl.proto
diff --git a/proto/aftl.proto b/proto/aftl.proto
deleted file mode 100644
index 41f1148..0000000
--- a/proto/aftl.proto
+++ /dev/null
@@ -1,112 +0,0 @@
-// Copyright 2019 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-syntax = "proto3";
-
-package aftl;
-option go_package = "proto";
-
-import "trillian.proto";
-import "crypto/sigpb/sigpb.proto";
-import "google/protobuf/timestamp.proto";
-
-// These messages are used both by the frontend API and the Trillian log.
-message FirmwareInfo {
- // This is the SHA256 hash of vbmeta.
- bytes vbmeta_hash = 1;
-
- // Subcomponent of the build fingerprint as defined at
- // https://source.android.com/compatibility/android-cdd#3_2_2_build_parameters.
- // For example, a Pixel device with the following build fingerprint
- // google/crosshatch/crosshatch:9/PQ3A.190605.003/5524043:user/release-keys,
- // would have 5524043 for the version incremental.
- string version_incremental = 2;
-
- // Public key of the platform. This is the same key used to sign the vbmeta.
- bytes platform_key = 3;
-
- // SHA256 of the manufacturer public key (DER-encoded, x509
- // subjectPublicKeyInfo format). The public key MUST already be in the list
- // of root keys known and trusted by the AFTL.
- // Internal: This field is required to be able to identify which manufacturer
- // this request is coming from.
- bytes manufacturer_key_hash = 4;
-
- // Free form description field. It can be used to annotate this message with
- // further context on the build (e.g., carrier specific build).
- string description = 5;
-}
-
-message SignedFirmwareInfo {
- FirmwareInfo info = 1;
-
- // Signature of the info field, using manufacturer_pub_key.
- // For the signature, info is first serialized to JSON. It is not
- // expected to be able to reconstruct the info field from scratch.
- // When verifying the inclusion proof associated with the info, it is
- // expected that the leaf is provided.
- sigpb.DigitallySigned info_signature = 2;
-}
-
-message FirmwareImageInfo {
- // This is the SHA256 hash of vbmeta.
- bytes vbmeta_hash = 1;
-
- // SHA256 hash of the complete binary image. In case of Pixel, this would be
- // the hash of the ZIP file that is offered for download at:
- // https://developers.google.com/android/images
- bytes hash = 2;
-
- // Build fingerprint, e.g. in case of Pixel
- // google/crosshatch/crosshatch:9/PQ3A.190605.003/5524043:user/release-keys
- // See https://source.android.com/compatibility/android-cdd.html#3_2_2_build_parameters
- // for the expected format of this field.
- string build_fingerprint = 3;
-}
-
-message SignedFirmwareImageInfo {
- FirmwareImageInfo image_info = 1;
- sigpb.DigitallySigned image_info_signature = 2;
-}
-
-
-message InclusionProof {
- trillian.Proof proof = 1;
- trillian.SignedLogRoot sth = 2;
-}
-
-// Trillian-specific data types
-message Leaf {
- int32 version = 1;
-
- // Timestamp when the entry was added to the log.
- google.protobuf.Timestamp timestamp = 2;
-
- oneof value {
- bytes vbmeta = 3;
- FirmwareInfoAnnotation fw_info = 4;
- FirmwareImageInfoAnnotation fw_image_info = 5;
- }
-}
-
-message FirmwareInfoAnnotation {
- SignedFirmwareInfo info = 1;
-}
-
-message FirmwareImageInfoAnnotation {
- SignedFirmwareImageInfo info = 1;
-
- // URL of the firmware image in the Cloud Storage bucket populated by AFTL.
- string url = 2;
-}
diff --git a/proto/aftl_pb2.py b/proto/aftl_pb2.py
deleted file mode 100644
index ed811ae..0000000
--- a/proto/aftl_pb2.py
+++ /dev/null
@@ -1,469 +0,0 @@
-# -*- coding: utf-8 -*-
-# Generated by the protocol buffer compiler. DO NOT EDIT!
-# source: aftl.proto
-
-import sys
-_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
-from google.protobuf import descriptor as _descriptor
-from google.protobuf import message as _message
-from google.protobuf import reflection as _reflection
-from google.protobuf import symbol_database as _symbol_database
-# @@protoc_insertion_point(imports)
-
-_sym_db = _symbol_database.Default()
-
-
-import trillian_pb2 as trillian__pb2
-from crypto.sigpb import sigpb_pb2 as crypto_dot_sigpb_dot_sigpb__pb2
-from google.protobuf import timestamp_pb2 as google_dot_protobuf_dot_timestamp__pb2
-
-
-DESCRIPTOR = _descriptor.FileDescriptor(
- name='aftl.proto',
- package='aftl',
- syntax='proto3',
- serialized_options=_b('Z\005proto'),
- serialized_pb=_b('\n\naftl.proto\x12\x04\x61\x66tl\x1a\x0etrillian.proto\x1a\x18\x63rypto/sigpb/sigpb.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"\x8a\x01\n\x0c\x46irmwareInfo\x12\x13\n\x0bvbmeta_hash\x18\x01 \x01(\x0c\x12\x1b\n\x13version_incremental\x18\x02 \x01(\t\x12\x14\n\x0cplatform_key\x18\x03 \x01(\x0c\x12\x1d\n\x15manufacturer_key_hash\x18\x04 \x01(\x0c\x12\x13\n\x0b\x64\x65scription\x18\x05 \x01(\t\"f\n\x12SignedFirmwareInfo\x12 \n\x04info\x18\x01 \x01(\x0b\x32\x12.aftl.FirmwareInfo\x12.\n\x0einfo_signature\x18\x02 \x01(\x0b\x32\x16.sigpb.DigitallySigned\"Q\n\x11\x46irmwareImageInfo\x12\x13\n\x0bvbmeta_hash\x18\x01 \x01(\x0c\x12\x0c\n\x04hash\x18\x02 \x01(\x0c\x12\x19\n\x11\x62uild_fingerprint\x18\x03 \x01(\t\"|\n\x17SignedFirmwareImageInfo\x12+\n\nimage_info\x18\x01 \x01(\x0b\x32\x17.aftl.FirmwareImageInfo\x12\x34\n\x14image_info_signature\x18\x02 \x01(\x0b\x32\x16.sigpb.DigitallySigned\"V\n\x0eInclusionProof\x12\x1e\n\x05proof\x18\x01 \x01(\x0b\x32\x0f.trillian.Proof\x12$\n\x03sth\x18\x02 \x01(\x0b\x32\x17.trillian.SignedLogRoot\"\xce\x01\n\x04Leaf\x12\x0f\n\x07version\x18\x01 \x01(\x05\x12-\n\ttimestamp\x18\x02 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x10\n\x06vbmeta\x18\x03 \x01(\x0cH\x00\x12/\n\x07\x66w_info\x18\x04 \x01(\x0b\x32\x1c.aftl.FirmwareInfoAnnotationH\x00\x12:\n\rfw_image_info\x18\x05 \x01(\x0b\x32!.aftl.FirmwareImageInfoAnnotationH\x00\x42\x07\n\x05value\"@\n\x16\x46irmwareInfoAnnotation\x12&\n\x04info\x18\x01 \x01(\x0b\x32\x18.aftl.SignedFirmwareInfo\"W\n\x1b\x46irmwareImageInfoAnnotation\x12+\n\x04info\x18\x01 \x01(\x0b\x32\x1d.aftl.SignedFirmwareImageInfo\x12\x0b\n\x03url\x18\x02 \x01(\tB\x07Z\x05protob\x06proto3')
- ,
- dependencies=[trillian__pb2.DESCRIPTOR,crypto_dot_sigpb_dot_sigpb__pb2.DESCRIPTOR,google_dot_protobuf_dot_timestamp__pb2.DESCRIPTOR,])
-
-
-
-
-_FIRMWAREINFO = _descriptor.Descriptor(
- name='FirmwareInfo',
- full_name='aftl.FirmwareInfo',
- filename=None,
- file=DESCRIPTOR,
- containing_type=None,
- fields=[
- _descriptor.FieldDescriptor(
- name='vbmeta_hash', full_name='aftl.FirmwareInfo.vbmeta_hash', index=0,
- number=1, type=12, cpp_type=9, label=1,
- has_default_value=False, default_value=_b(""),
- message_type=None, enum_type=None, containing_type=None,
- is_extension=False, extension_scope=None,
- serialized_options=None, file=DESCRIPTOR),
- _descriptor.FieldDescriptor(
- name='version_incremental', full_name='aftl.FirmwareInfo.version_incremental', index=1,
- number=2, type=9, cpp_type=9, label=1,
- has_default_value=False, default_value=_b("").decode('utf-8'),
- message_type=None, enum_type=None, containing_type=None,
- is_extension=False, extension_scope=None,
- serialized_options=None, file=DESCRIPTOR),
- _descriptor.FieldDescriptor(
- name='platform_key', full_name='aftl.FirmwareInfo.platform_key', index=2,
- number=3, type=12, cpp_type=9, label=1,
- has_default_value=False, default_value=_b(""),
- message_type=None, enum_type=None, containing_type=None,
- is_extension=False, extension_scope=None,
- serialized_options=None, file=DESCRIPTOR),
- _descriptor.FieldDescriptor(
- name='manufacturer_key_hash', full_name='aftl.FirmwareInfo.manufacturer_key_hash', index=3,
- number=4, type=12, cpp_type=9, label=1,
- has_default_value=False, default_value=_b(""),
- message_type=None, enum_type=None, containing_type=None,
- is_extension=False, extension_scope=None,
- serialized_options=None, file=DESCRIPTOR),
- _descriptor.FieldDescriptor(
- name='description', full_name='aftl.FirmwareInfo.description', index=4,
- number=5, type=9, cpp_type=9, label=1,
- has_default_value=False, default_value=_b("").decode('utf-8'),
- message_type=None, enum_type=None, containing_type=None,
- is_extension=False, extension_scope=None,
- serialized_options=None, file=DESCRIPTOR),
- ],
- extensions=[
- ],
- nested_types=[],
- enum_types=[
- ],
- serialized_options=None,
- is_extendable=False,
- syntax='proto3',
- extension_ranges=[],
- oneofs=[
- ],
- serialized_start=96,
- serialized_end=234,
-)
-
-
-_SIGNEDFIRMWAREINFO = _descriptor.Descriptor(
- name='SignedFirmwareInfo',
- full_name='aftl.SignedFirmwareInfo',
- filename=None,
- file=DESCRIPTOR,
- containing_type=None,
- fields=[
- _descriptor.FieldDescriptor(
- name='info', full_name='aftl.SignedFirmwareInfo.info', index=0,
- number=1, type=11, cpp_type=10, label=1,
- has_default_value=False, default_value=None,
- message_type=None, enum_type=None, containing_type=None,
- is_extension=False, extension_scope=None,
- serialized_options=None, file=DESCRIPTOR),
- _descriptor.FieldDescriptor(
- name='info_signature', full_name='aftl.SignedFirmwareInfo.info_signature', index=1,
- number=2, type=11, cpp_type=10, label=1,
- has_default_value=False, default_value=None,
- message_type=None, enum_type=None, containing_type=None,
- is_extension=False, extension_scope=None,
- serialized_options=None, file=DESCRIPTOR),
- ],
- extensions=[
- ],
- nested_types=[],
- enum_types=[
- ],
- serialized_options=None,
- is_extendable=False,
- syntax='proto3',
- extension_ranges=[],
- oneofs=[
- ],
- serialized_start=236,
- serialized_end=338,
-)
-
-
-_FIRMWAREIMAGEINFO = _descriptor.Descriptor(
- name='FirmwareImageInfo',
- full_name='aftl.FirmwareImageInfo',
- filename=None,
- file=DESCRIPTOR,
- containing_type=None,
- fields=[
- _descriptor.FieldDescriptor(
- name='vbmeta_hash', full_name='aftl.FirmwareImageInfo.vbmeta_hash', index=0,
- number=1, type=12, cpp_type=9, label=1,
- has_default_value=False, default_value=_b(""),
- message_type=None, enum_type=None, containing_type=None,
- is_extension=False, extension_scope=None,
- serialized_options=None, file=DESCRIPTOR),
- _descriptor.FieldDescriptor(
- name='hash', full_name='aftl.FirmwareImageInfo.hash', index=1,
- number=2, type=12, cpp_type=9, label=1,
- has_default_value=False, default_value=_b(""),
- message_type=None, enum_type=None, containing_type=None,
- is_extension=False, extension_scope=None,
- serialized_options=None, file=DESCRIPTOR),
- _descriptor.FieldDescriptor(
- name='build_fingerprint', full_name='aftl.FirmwareImageInfo.build_fingerprint', index=2,
- number=3, type=9, cpp_type=9, label=1,
- has_default_value=False, default_value=_b("").decode('utf-8'),
- message_type=None, enum_type=None, containing_type=None,
- is_extension=False, extension_scope=None,
- serialized_options=None, file=DESCRIPTOR),
- ],
- extensions=[
- ],
- nested_types=[],
- enum_types=[
- ],
- serialized_options=None,
- is_extendable=False,
- syntax='proto3',
- extension_ranges=[],
- oneofs=[
- ],
- serialized_start=340,
- serialized_end=421,
-)
-
-
-_SIGNEDFIRMWAREIMAGEINFO = _descriptor.Descriptor(
- name='SignedFirmwareImageInfo',
- full_name='aftl.SignedFirmwareImageInfo',
- filename=None,
- file=DESCRIPTOR,
- containing_type=None,
- fields=[
- _descriptor.FieldDescriptor(
- name='image_info', full_name='aftl.SignedFirmwareImageInfo.image_info', index=0,
- number=1, type=11, cpp_type=10, label=1,
- has_default_value=False, default_value=None,
- message_type=None, enum_type=None, containing_type=None,
- is_extension=False, extension_scope=None,
- serialized_options=None, file=DESCRIPTOR),
- _descriptor.FieldDescriptor(
- name='image_info_signature', full_name='aftl.SignedFirmwareImageInfo.image_info_signature', index=1,
- number=2, type=11, cpp_type=10, label=1,
- has_default_value=False, default_value=None,
- message_type=None, enum_type=None, containing_type=None,
- is_extension=False, extension_scope=None,
- serialized_options=None, file=DESCRIPTOR),
- ],
- extensions=[
- ],
- nested_types=[],
- enum_types=[
- ],
- serialized_options=None,
- is_extendable=False,
- syntax='proto3',
- extension_ranges=[],
- oneofs=[
- ],
- serialized_start=423,
- serialized_end=547,
-)
-
-
-_INCLUSIONPROOF = _descriptor.Descriptor(
- name='InclusionProof',
- full_name='aftl.InclusionProof',
- filename=None,
- file=DESCRIPTOR,
- containing_type=None,
- fields=[
- _descriptor.FieldDescriptor(
- name='proof', full_name='aftl.InclusionProof.proof', index=0,
- number=1, type=11, cpp_type=10, label=1,
- has_default_value=False, default_value=None,
- message_type=None, enum_type=None, containing_type=None,
- is_extension=False, extension_scope=None,
- serialized_options=None, file=DESCRIPTOR),
- _descriptor.FieldDescriptor(
- name='sth', full_name='aftl.InclusionProof.sth', index=1,
- number=2, type=11, cpp_type=10, label=1,
- has_default_value=False, default_value=None,
- message_type=None, enum_type=None, containing_type=None,
- is_extension=False, extension_scope=None,
- serialized_options=None, file=DESCRIPTOR),
- ],
- extensions=[
- ],
- nested_types=[],
- enum_types=[
- ],
- serialized_options=None,
- is_extendable=False,
- syntax='proto3',
- extension_ranges=[],
- oneofs=[
- ],
- serialized_start=549,
- serialized_end=635,
-)
-
-
-_LEAF = _descriptor.Descriptor(
- name='Leaf',
- full_name='aftl.Leaf',
- filename=None,
- file=DESCRIPTOR,
- containing_type=None,
- fields=[
- _descriptor.FieldDescriptor(
- name='version', full_name='aftl.Leaf.version', index=0,
- number=1, type=5, cpp_type=1, label=1,
- has_default_value=False, default_value=0,
- message_type=None, enum_type=None, containing_type=None,
- is_extension=False, extension_scope=None,
- serialized_options=None, file=DESCRIPTOR),
- _descriptor.FieldDescriptor(
- name='timestamp', full_name='aftl.Leaf.timestamp', index=1,
- number=2, type=11, cpp_type=10, label=1,
- has_default_value=False, default_value=None,
- message_type=None, enum_type=None, containing_type=None,
- is_extension=False, extension_scope=None,
- serialized_options=None, file=DESCRIPTOR),
- _descriptor.FieldDescriptor(
- name='vbmeta', full_name='aftl.Leaf.vbmeta', index=2,
- number=3, type=12, cpp_type=9, label=1,
- has_default_value=False, default_value=_b(""),
- message_type=None, enum_type=None, containing_type=None,
- is_extension=False, extension_scope=None,
- serialized_options=None, file=DESCRIPTOR),
- _descriptor.FieldDescriptor(
- name='fw_info', full_name='aftl.Leaf.fw_info', index=3,
- number=4, type=11, cpp_type=10, label=1,
- has_default_value=False, default_value=None,
- message_type=None, enum_type=None, containing_type=None,
- is_extension=False, extension_scope=None,
- serialized_options=None, file=DESCRIPTOR),
- _descriptor.FieldDescriptor(
- name='fw_image_info', full_name='aftl.Leaf.fw_image_info', index=4,
- number=5, type=11, cpp_type=10, label=1,
- has_default_value=False, default_value=None,
- message_type=None, enum_type=None, containing_type=None,
- is_extension=False, extension_scope=None,
- serialized_options=None, file=DESCRIPTOR),
- ],
- extensions=[
- ],
- nested_types=[],
- enum_types=[
- ],
- serialized_options=None,
- is_extendable=False,
- syntax='proto3',
- extension_ranges=[],
- oneofs=[
- _descriptor.OneofDescriptor(
- name='value', full_name='aftl.Leaf.value',
- index=0, containing_type=None, fields=[]),
- ],
- serialized_start=638,
- serialized_end=844,
-)
-
-
-_FIRMWAREINFOANNOTATION = _descriptor.Descriptor(
- name='FirmwareInfoAnnotation',
- full_name='aftl.FirmwareInfoAnnotation',
- filename=None,
- file=DESCRIPTOR,
- containing_type=None,
- fields=[
- _descriptor.FieldDescriptor(
- name='info', full_name='aftl.FirmwareInfoAnnotation.info', index=0,
- number=1, type=11, cpp_type=10, label=1,
- has_default_value=False, default_value=None,
- message_type=None, enum_type=None, containing_type=None,
- is_extension=False, extension_scope=None,
- serialized_options=None, file=DESCRIPTOR),
- ],
- extensions=[
- ],
- nested_types=[],
- enum_types=[
- ],
- serialized_options=None,
- is_extendable=False,
- syntax='proto3',
- extension_ranges=[],
- oneofs=[
- ],
- serialized_start=846,
- serialized_end=910,
-)
-
-
-_FIRMWAREIMAGEINFOANNOTATION = _descriptor.Descriptor(
- name='FirmwareImageInfoAnnotation',
- full_name='aftl.FirmwareImageInfoAnnotation',
- filename=None,
- file=DESCRIPTOR,
- containing_type=None,
- fields=[
- _descriptor.FieldDescriptor(
- name='info', full_name='aftl.FirmwareImageInfoAnnotation.info', index=0,
- number=1, type=11, cpp_type=10, label=1,
- has_default_value=False, default_value=None,
- message_type=None, enum_type=None, containing_type=None,
- is_extension=False, extension_scope=None,
- serialized_options=None, file=DESCRIPTOR),
- _descriptor.FieldDescriptor(
- name='url', full_name='aftl.FirmwareImageInfoAnnotation.url', index=1,
- number=2, type=9, cpp_type=9, label=1,
- has_default_value=False, default_value=_b("").decode('utf-8'),
- message_type=None, enum_type=None, containing_type=None,
- is_extension=False, extension_scope=None,
- serialized_options=None, file=DESCRIPTOR),
- ],
- extensions=[
- ],
- nested_types=[],
- enum_types=[
- ],
- serialized_options=None,
- is_extendable=False,
- syntax='proto3',
- extension_ranges=[],
- oneofs=[
- ],
- serialized_start=912,
- serialized_end=999,
-)
-
-_SIGNEDFIRMWAREINFO.fields_by_name['info'].message_type = _FIRMWAREINFO
-_SIGNEDFIRMWAREINFO.fields_by_name['info_signature'].message_type = crypto_dot_sigpb_dot_sigpb__pb2._DIGITALLYSIGNED
-_SIGNEDFIRMWAREIMAGEINFO.fields_by_name['image_info'].message_type = _FIRMWAREIMAGEINFO
-_SIGNEDFIRMWAREIMAGEINFO.fields_by_name['image_info_signature'].message_type = crypto_dot_sigpb_dot_sigpb__pb2._DIGITALLYSIGNED
-_INCLUSIONPROOF.fields_by_name['proof'].message_type = trillian__pb2._PROOF
-_INCLUSIONPROOF.fields_by_name['sth'].message_type = trillian__pb2._SIGNEDLOGROOT
-_LEAF.fields_by_name['timestamp'].message_type = google_dot_protobuf_dot_timestamp__pb2._TIMESTAMP
-_LEAF.fields_by_name['fw_info'].message_type = _FIRMWAREINFOANNOTATION
-_LEAF.fields_by_name['fw_image_info'].message_type = _FIRMWAREIMAGEINFOANNOTATION
-_LEAF.oneofs_by_name['value'].fields.append(
- _LEAF.fields_by_name['vbmeta'])
-_LEAF.fields_by_name['vbmeta'].containing_oneof = _LEAF.oneofs_by_name['value']
-_LEAF.oneofs_by_name['value'].fields.append(
- _LEAF.fields_by_name['fw_info'])
-_LEAF.fields_by_name['fw_info'].containing_oneof = _LEAF.oneofs_by_name['value']
-_LEAF.oneofs_by_name['value'].fields.append(
- _LEAF.fields_by_name['fw_image_info'])
-_LEAF.fields_by_name['fw_image_info'].containing_oneof = _LEAF.oneofs_by_name['value']
-_FIRMWAREINFOANNOTATION.fields_by_name['info'].message_type = _SIGNEDFIRMWAREINFO
-_FIRMWAREIMAGEINFOANNOTATION.fields_by_name['info'].message_type = _SIGNEDFIRMWAREIMAGEINFO
-DESCRIPTOR.message_types_by_name['FirmwareInfo'] = _FIRMWAREINFO
-DESCRIPTOR.message_types_by_name['SignedFirmwareInfo'] = _SIGNEDFIRMWAREINFO
-DESCRIPTOR.message_types_by_name['FirmwareImageInfo'] = _FIRMWAREIMAGEINFO
-DESCRIPTOR.message_types_by_name['SignedFirmwareImageInfo'] = _SIGNEDFIRMWAREIMAGEINFO
-DESCRIPTOR.message_types_by_name['InclusionProof'] = _INCLUSIONPROOF
-DESCRIPTOR.message_types_by_name['Leaf'] = _LEAF
-DESCRIPTOR.message_types_by_name['FirmwareInfoAnnotation'] = _FIRMWAREINFOANNOTATION
-DESCRIPTOR.message_types_by_name['FirmwareImageInfoAnnotation'] = _FIRMWAREIMAGEINFOANNOTATION
-_sym_db.RegisterFileDescriptor(DESCRIPTOR)
-
-FirmwareInfo = _reflection.GeneratedProtocolMessageType('FirmwareInfo', (_message.Message,), {
- 'DESCRIPTOR' : _FIRMWAREINFO,
- '__module__' : 'aftl_pb2'
- # @@protoc_insertion_point(class_scope:aftl.FirmwareInfo)
- })
-_sym_db.RegisterMessage(FirmwareInfo)
-
-SignedFirmwareInfo = _reflection.GeneratedProtocolMessageType('SignedFirmwareInfo', (_message.Message,), {
- 'DESCRIPTOR' : _SIGNEDFIRMWAREINFO,
- '__module__' : 'aftl_pb2'
- # @@protoc_insertion_point(class_scope:aftl.SignedFirmwareInfo)
- })
-_sym_db.RegisterMessage(SignedFirmwareInfo)
-
-FirmwareImageInfo = _reflection.GeneratedProtocolMessageType('FirmwareImageInfo', (_message.Message,), {
- 'DESCRIPTOR' : _FIRMWAREIMAGEINFO,
- '__module__' : 'aftl_pb2'
- # @@protoc_insertion_point(class_scope:aftl.FirmwareImageInfo)
- })
-_sym_db.RegisterMessage(FirmwareImageInfo)
-
-SignedFirmwareImageInfo = _reflection.GeneratedProtocolMessageType('SignedFirmwareImageInfo', (_message.Message,), {
- 'DESCRIPTOR' : _SIGNEDFIRMWAREIMAGEINFO,
- '__module__' : 'aftl_pb2'
- # @@protoc_insertion_point(class_scope:aftl.SignedFirmwareImageInfo)
- })
-_sym_db.RegisterMessage(SignedFirmwareImageInfo)
-
-InclusionProof = _reflection.GeneratedProtocolMessageType('InclusionProof', (_message.Message,), {
- 'DESCRIPTOR' : _INCLUSIONPROOF,
- '__module__' : 'aftl_pb2'
- # @@protoc_insertion_point(class_scope:aftl.InclusionProof)
- })
-_sym_db.RegisterMessage(InclusionProof)
-
-Leaf = _reflection.GeneratedProtocolMessageType('Leaf', (_message.Message,), {
- 'DESCRIPTOR' : _LEAF,
- '__module__' : 'aftl_pb2'
- # @@protoc_insertion_point(class_scope:aftl.Leaf)
- })
-_sym_db.RegisterMessage(Leaf)
-
-FirmwareInfoAnnotation = _reflection.GeneratedProtocolMessageType('FirmwareInfoAnnotation', (_message.Message,), {
- 'DESCRIPTOR' : _FIRMWAREINFOANNOTATION,
- '__module__' : 'aftl_pb2'
- # @@protoc_insertion_point(class_scope:aftl.FirmwareInfoAnnotation)
- })
-_sym_db.RegisterMessage(FirmwareInfoAnnotation)
-
-FirmwareImageInfoAnnotation = _reflection.GeneratedProtocolMessageType('FirmwareImageInfoAnnotation', (_message.Message,), {
- 'DESCRIPTOR' : _FIRMWAREIMAGEINFOANNOTATION,
- '__module__' : 'aftl_pb2'
- # @@protoc_insertion_point(class_scope:aftl.FirmwareImageInfoAnnotation)
- })
-_sym_db.RegisterMessage(FirmwareImageInfoAnnotation)
-
-
-DESCRIPTOR._options = None
-# @@protoc_insertion_point(module_scope)
diff --git a/proto/aftl_pb2_grpc.py b/proto/aftl_pb2_grpc.py
deleted file mode 100644
index a894352..0000000
--- a/proto/aftl_pb2_grpc.py
+++ /dev/null
@@ -1,3 +0,0 @@
-# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
-import grpc
-
diff --git a/proto/api.proto b/proto/api.proto
index 4c66333..e22ae47 100644
--- a/proto/api.proto
+++ b/proto/api.proto
@@ -1,4 +1,4 @@
-// Copyright 2019 Google LLC
+// Copyright 2019-2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -17,27 +17,35 @@
package aftl;
option go_package = "proto";
-import "aftl.proto";
+import "trillian.proto";
-message AddFirmwareInfoRequest {
+message InclusionProof {
+ trillian.Proof proof = 1;
+ trillian.SignedLogRoot sth = 2;
+}
+
+message AddVBMetaRequest {
// VBMeta structure as described in
// https://android.googlesource.com/platform/external/avb/+/master/README.md.
// In case of chained partitions, each VBMeta is added via a separate call.
// The default size for gRPC payload is about 4MB. We expect vbmeta to be
- // in the order of 1kB.
+ // in the order of 64kB.
bytes vbmeta = 1;
- SignedFirmwareInfo fw_info = 2;
+ // Serialized SignedVBMetaPrimaryAnnotation. This annotation contains the hash
+ // of the vbmeta structure. It is signed using the manufacturer key.
+ // See types/types.go.
+ bytes signed_vbmeta_primary_annotation = 2;
}
-message AddFirmwareInfoResponse {
+message AddVBMetaResponse {
// Inclusion proof and the leaf that was added to the log, which contains
- // information on the firmware.
+ // the annotation on VBMeta.
// It is required to have the complete leaf to validate the inclusion proof.
// For on-device verification, only these first 2 fields are required to
// validate the inclusion.
- InclusionProof fw_info_proof = 1;
- bytes fw_info_leaf = 2;
+ InclusionProof annotation_proof = 1;
+ bytes annotation_leaf = 2;
// Inclusion proof and leaf that was added to the log, which contains the full
// vbmeta partition.
@@ -47,12 +55,13 @@
bytes vbmeta_leaf = 4;
}
-message AddFirmwareImageRequest {
+message AnnotateVBMetaWithBuildRequest {
+ // Serialized SignedVBMetaBuildAnnotation. This annotation contains the hash
+ // of the full build image. See types/types.go.
+ bytes signed_vbmeta_build_annotation = 1;
- SignedFirmwareImageInfo fw_image_info = 1;
-
- // Bytes of the binary images. These are not signed as their final
- // hash value is already signed in fw_image_info.hash
+ // Bytes of the binary images. The hash value of the concatenation of these
+ // chunk is contained in SignedVBMetaBuildAnnotation.
// This is ignored if any of the requests origin_url is set.
bytes image_chunk = 2;
@@ -61,14 +70,13 @@
string origin_url = 3;
}
-message AddFirmwareImageResponse {
-
+message AnnotateVBMetaWithBuildResponse {
// Inclusion proof and leaf for the firmware image. The leaf contains the URL
// where the image was stored.
// It is not required for vendors to keep this information. However, this can
// be used for their records to ensure the correctness of the log.
- InclusionProof fw_image_info_proof = 1;
- Leaf fw_image_info_leaf = 2;
+ InclusionProof annotation_proof = 1;
+ bytes annotation_leaf = 2;
}
service AFTLog {
@@ -76,12 +84,11 @@
// Insert a new VBMeta structure into the log.
// This request will effectively create 2 log entries:
// - VBMeta itself
- // - Vendor annotations, including a reference to the VBMeta leaf.
- rpc AddFirmwareInfo(AddFirmwareInfoRequest) returns (AddFirmwareInfoResponse) {}
+ // - Vendor annotations, which includes a reference to the VBMeta.
+ rpc AddVBMeta(AddVBMetaRequest) returns (AddVBMetaResponse) {}
// Upload (or copy) the complete firmware image.
- rpc AddFirmwareImage(stream AddFirmwareImageRequest) returns (AddFirmwareImageResponse) {}
+ rpc AnnotateVBMetaWithBuild(stream AnnotateVBMetaWithBuildResponse) returns (AnnotateVBMetaWithBuildResponse) {}
- // TODO GetProofByHash, GetSthConsistency, GetEntries, GetRootKeys
+ // TODO(tweek): GetProofByHash, GetSthConsistency, GetEntries, GetRootKeys
}
-
diff --git a/proto/api_pb2.py b/proto/api_pb2.py
index f8f9a01..fbe3bab 100644
--- a/proto/api_pb2.py
+++ b/proto/api_pb2.py
@@ -1,4 +1,3 @@
-# pylint: skip-file
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: api.proto
@@ -14,7 +13,7 @@
_sym_db = _symbol_database.Default()
-import aftl_pb2 as aftl__pb2
+import trillian_pb2 as trillian__pb2
DESCRIPTOR = _descriptor.FileDescriptor(
@@ -22,29 +21,29 @@
package='aftl',
syntax='proto3',
serialized_options=_b('Z\005proto'),
- serialized_pb=_b('\n\tapi.proto\x12\x04\x61\x66tl\x1a\naftl.proto\"S\n\x16\x41\x64\x64\x46irmwareInfoRequest\x12\x0e\n\x06vbmeta\x18\x01 \x01(\x0c\x12)\n\x07\x66w_info\x18\x02 \x01(\x0b\x32\x18.aftl.SignedFirmwareInfo\"\x9d\x01\n\x17\x41\x64\x64\x46irmwareInfoResponse\x12+\n\rfw_info_proof\x18\x01 \x01(\x0b\x32\x14.aftl.InclusionProof\x12\x14\n\x0c\x66w_info_leaf\x18\x02 \x01(\x0c\x12*\n\x0cvbmeta_proof\x18\x03 \x01(\x0b\x32\x14.aftl.InclusionProof\x12\x13\n\x0bvbmeta_leaf\x18\x04 \x01(\x0c\"x\n\x17\x41\x64\x64\x46irmwareImageRequest\x12\x34\n\rfw_image_info\x18\x01 \x01(\x0b\x32\x1d.aftl.SignedFirmwareImageInfo\x12\x13\n\x0bimage_chunk\x18\x02 \x01(\x0c\x12\x12\n\norigin_url\x18\x03 \x01(\t\"u\n\x18\x41\x64\x64\x46irmwareImageResponse\x12\x31\n\x13\x66w_image_info_proof\x18\x01 \x01(\x0b\x32\x14.aftl.InclusionProof\x12&\n\x12\x66w_image_info_leaf\x18\x02 \x01(\x0b\x32\n.aftl.Leaf2\xb1\x01\n\x06\x41\x46TLog\x12P\n\x0f\x41\x64\x64\x46irmwareInfo\x12\x1c.aftl.AddFirmwareInfoRequest\x1a\x1d.aftl.AddFirmwareInfoResponse\"\x00\x12U\n\x10\x41\x64\x64\x46irmwareImage\x12\x1d.aftl.AddFirmwareImageRequest\x1a\x1e.aftl.AddFirmwareImageResponse\"\x00(\x01\x42\x07Z\x05protob\x06proto3')
+ serialized_pb=_b('\n\tapi.proto\x12\x04\x61\x66tl\x1a\x0etrillian.proto\"V\n\x0eInclusionProof\x12\x1e\n\x05proof\x18\x01 \x01(\x0b\x32\x0f.trillian.Proof\x12$\n\x03sth\x18\x02 \x01(\x0b\x32\x17.trillian.SignedLogRoot\"L\n\x10\x41\x64\x64VBMetaRequest\x12\x0e\n\x06vbmeta\x18\x01 \x01(\x0c\x12(\n signed_vbmeta_primary_annotation\x18\x02 \x01(\x0c\"\x9d\x01\n\x11\x41\x64\x64VBMetaResponse\x12.\n\x10\x61nnotation_proof\x18\x01 \x01(\x0b\x32\x14.aftl.InclusionProof\x12\x17\n\x0f\x61nnotation_leaf\x18\x02 \x01(\x0c\x12*\n\x0cvbmeta_proof\x18\x03 \x01(\x0b\x32\x14.aftl.InclusionProof\x12\x13\n\x0bvbmeta_leaf\x18\x04 \x01(\x0c\"q\n\x1e\x41nnotateVBMetaWithBuildRequest\x12&\n\x1esigned_vbmeta_build_annotation\x18\x01 \x01(\x0c\x12\x13\n\x0bimage_chunk\x18\x02 \x01(\x0c\x12\x12\n\norigin_url\x18\x03 \x01(\t\"j\n\x1f\x41nnotateVBMetaWithBuildResponse\x12.\n\x10\x61nnotation_proof\x18\x01 \x01(\x0b\x32\x14.aftl.InclusionProof\x12\x17\n\x0f\x61nnotation_leaf\x18\x02 \x01(\x0c\x32\xb5\x01\n\x06\x41\x46TLog\x12>\n\tAddVBMeta\x12\x16.aftl.AddVBMetaRequest\x1a\x17.aftl.AddVBMetaResponse\"\x00\x12k\n\x17\x41nnotateVBMetaWithBuild\x12%.aftl.AnnotateVBMetaWithBuildResponse\x1a%.aftl.AnnotateVBMetaWithBuildResponse\"\x00(\x01\x42\x07Z\x05protob\x06proto3')
,
- dependencies=[aftl__pb2.DESCRIPTOR,])
+ dependencies=[trillian__pb2.DESCRIPTOR,])
-_ADDFIRMWAREINFOREQUEST = _descriptor.Descriptor(
- name='AddFirmwareInfoRequest',
- full_name='aftl.AddFirmwareInfoRequest',
+_INCLUSIONPROOF = _descriptor.Descriptor(
+ name='InclusionProof',
+ full_name='aftl.InclusionProof',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
- name='vbmeta', full_name='aftl.AddFirmwareInfoRequest.vbmeta', index=0,
- number=1, type=12, cpp_type=9, label=1,
- has_default_value=False, default_value=_b(""),
+ name='proof', full_name='aftl.InclusionProof.proof', index=0,
+ number=1, type=11, cpp_type=10, label=1,
+ has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
- name='fw_info', full_name='aftl.AddFirmwareInfoRequest.fw_info', index=1,
+ name='sth', full_name='aftl.InclusionProof.sth', index=1,
number=2, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
@@ -62,41 +61,79 @@
extension_ranges=[],
oneofs=[
],
- serialized_start=31,
- serialized_end=114,
+ serialized_start=35,
+ serialized_end=121,
)
-_ADDFIRMWAREINFORESPONSE = _descriptor.Descriptor(
- name='AddFirmwareInfoResponse',
- full_name='aftl.AddFirmwareInfoResponse',
+_ADDVBMETAREQUEST = _descriptor.Descriptor(
+ name='AddVBMetaRequest',
+ full_name='aftl.AddVBMetaRequest',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
- name='fw_info_proof', full_name='aftl.AddFirmwareInfoResponse.fw_info_proof', index=0,
+ name='vbmeta', full_name='aftl.AddVBMetaRequest.vbmeta', index=0,
+ number=1, type=12, cpp_type=9, label=1,
+ has_default_value=False, default_value=_b(""),
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ serialized_options=None, file=DESCRIPTOR),
+ _descriptor.FieldDescriptor(
+ name='signed_vbmeta_primary_annotation', full_name='aftl.AddVBMetaRequest.signed_vbmeta_primary_annotation', index=1,
+ number=2, type=12, cpp_type=9, label=1,
+ has_default_value=False, default_value=_b(""),
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ serialized_options=None, file=DESCRIPTOR),
+ ],
+ extensions=[
+ ],
+ nested_types=[],
+ enum_types=[
+ ],
+ serialized_options=None,
+ is_extendable=False,
+ syntax='proto3',
+ extension_ranges=[],
+ oneofs=[
+ ],
+ serialized_start=123,
+ serialized_end=199,
+)
+
+
+_ADDVBMETARESPONSE = _descriptor.Descriptor(
+ name='AddVBMetaResponse',
+ full_name='aftl.AddVBMetaResponse',
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ fields=[
+ _descriptor.FieldDescriptor(
+ name='annotation_proof', full_name='aftl.AddVBMetaResponse.annotation_proof', index=0,
number=1, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
- name='fw_info_leaf', full_name='aftl.AddFirmwareInfoResponse.fw_info_leaf', index=1,
+ name='annotation_leaf', full_name='aftl.AddVBMetaResponse.annotation_leaf', index=1,
number=2, type=12, cpp_type=9, label=1,
has_default_value=False, default_value=_b(""),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
- name='vbmeta_proof', full_name='aftl.AddFirmwareInfoResponse.vbmeta_proof', index=2,
+ name='vbmeta_proof', full_name='aftl.AddVBMetaResponse.vbmeta_proof', index=2,
number=3, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
- name='vbmeta_leaf', full_name='aftl.AddFirmwareInfoResponse.vbmeta_leaf', index=3,
+ name='vbmeta_leaf', full_name='aftl.AddVBMetaResponse.vbmeta_leaf', index=3,
number=4, type=12, cpp_type=9, label=1,
has_default_value=False, default_value=_b(""),
message_type=None, enum_type=None, containing_type=None,
@@ -114,34 +151,34 @@
extension_ranges=[],
oneofs=[
],
- serialized_start=117,
- serialized_end=274,
+ serialized_start=202,
+ serialized_end=359,
)
-_ADDFIRMWAREIMAGEREQUEST = _descriptor.Descriptor(
- name='AddFirmwareImageRequest',
- full_name='aftl.AddFirmwareImageRequest',
+_ANNOTATEVBMETAWITHBUILDREQUEST = _descriptor.Descriptor(
+ name='AnnotateVBMetaWithBuildRequest',
+ full_name='aftl.AnnotateVBMetaWithBuildRequest',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
- name='fw_image_info', full_name='aftl.AddFirmwareImageRequest.fw_image_info', index=0,
- number=1, type=11, cpp_type=10, label=1,
- has_default_value=False, default_value=None,
+ name='signed_vbmeta_build_annotation', full_name='aftl.AnnotateVBMetaWithBuildRequest.signed_vbmeta_build_annotation', index=0,
+ number=1, type=12, cpp_type=9, label=1,
+ has_default_value=False, default_value=_b(""),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
- name='image_chunk', full_name='aftl.AddFirmwareImageRequest.image_chunk', index=1,
+ name='image_chunk', full_name='aftl.AnnotateVBMetaWithBuildRequest.image_chunk', index=1,
number=2, type=12, cpp_type=9, label=1,
has_default_value=False, default_value=_b(""),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
- name='origin_url', full_name='aftl.AddFirmwareImageRequest.origin_url', index=2,
+ name='origin_url', full_name='aftl.AnnotateVBMetaWithBuildRequest.origin_url', index=2,
number=3, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
@@ -159,29 +196,29 @@
extension_ranges=[],
oneofs=[
],
- serialized_start=276,
- serialized_end=396,
+ serialized_start=361,
+ serialized_end=474,
)
-_ADDFIRMWAREIMAGERESPONSE = _descriptor.Descriptor(
- name='AddFirmwareImageResponse',
- full_name='aftl.AddFirmwareImageResponse',
+_ANNOTATEVBMETAWITHBUILDRESPONSE = _descriptor.Descriptor(
+ name='AnnotateVBMetaWithBuildResponse',
+ full_name='aftl.AnnotateVBMetaWithBuildResponse',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
- name='fw_image_info_proof', full_name='aftl.AddFirmwareImageResponse.fw_image_info_proof', index=0,
+ name='annotation_proof', full_name='aftl.AnnotateVBMetaWithBuildResponse.annotation_proof', index=0,
number=1, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
- name='fw_image_info_leaf', full_name='aftl.AddFirmwareImageResponse.fw_image_info_leaf', index=1,
- number=2, type=11, cpp_type=10, label=1,
- has_default_value=False, default_value=None,
+ name='annotation_leaf', full_name='aftl.AnnotateVBMetaWithBuildResponse.annotation_leaf', index=1,
+ number=2, type=12, cpp_type=9, label=1,
+ has_default_value=False, default_value=_b(""),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
@@ -197,49 +234,56 @@
extension_ranges=[],
oneofs=[
],
- serialized_start=398,
- serialized_end=515,
+ serialized_start=476,
+ serialized_end=582,
)
-_ADDFIRMWAREINFOREQUEST.fields_by_name['fw_info'].message_type = aftl__pb2._SIGNEDFIRMWAREINFO
-_ADDFIRMWAREINFORESPONSE.fields_by_name['fw_info_proof'].message_type = aftl__pb2._INCLUSIONPROOF
-_ADDFIRMWAREINFORESPONSE.fields_by_name['vbmeta_proof'].message_type = aftl__pb2._INCLUSIONPROOF
-_ADDFIRMWAREIMAGEREQUEST.fields_by_name['fw_image_info'].message_type = aftl__pb2._SIGNEDFIRMWAREIMAGEINFO
-_ADDFIRMWAREIMAGERESPONSE.fields_by_name['fw_image_info_proof'].message_type = aftl__pb2._INCLUSIONPROOF
-_ADDFIRMWAREIMAGERESPONSE.fields_by_name['fw_image_info_leaf'].message_type = aftl__pb2._LEAF
-DESCRIPTOR.message_types_by_name['AddFirmwareInfoRequest'] = _ADDFIRMWAREINFOREQUEST
-DESCRIPTOR.message_types_by_name['AddFirmwareInfoResponse'] = _ADDFIRMWAREINFORESPONSE
-DESCRIPTOR.message_types_by_name['AddFirmwareImageRequest'] = _ADDFIRMWAREIMAGEREQUEST
-DESCRIPTOR.message_types_by_name['AddFirmwareImageResponse'] = _ADDFIRMWAREIMAGERESPONSE
+_INCLUSIONPROOF.fields_by_name['proof'].message_type = trillian__pb2._PROOF
+_INCLUSIONPROOF.fields_by_name['sth'].message_type = trillian__pb2._SIGNEDLOGROOT
+_ADDVBMETARESPONSE.fields_by_name['annotation_proof'].message_type = _INCLUSIONPROOF
+_ADDVBMETARESPONSE.fields_by_name['vbmeta_proof'].message_type = _INCLUSIONPROOF
+_ANNOTATEVBMETAWITHBUILDRESPONSE.fields_by_name['annotation_proof'].message_type = _INCLUSIONPROOF
+DESCRIPTOR.message_types_by_name['InclusionProof'] = _INCLUSIONPROOF
+DESCRIPTOR.message_types_by_name['AddVBMetaRequest'] = _ADDVBMETAREQUEST
+DESCRIPTOR.message_types_by_name['AddVBMetaResponse'] = _ADDVBMETARESPONSE
+DESCRIPTOR.message_types_by_name['AnnotateVBMetaWithBuildRequest'] = _ANNOTATEVBMETAWITHBUILDREQUEST
+DESCRIPTOR.message_types_by_name['AnnotateVBMetaWithBuildResponse'] = _ANNOTATEVBMETAWITHBUILDRESPONSE
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
-AddFirmwareInfoRequest = _reflection.GeneratedProtocolMessageType('AddFirmwareInfoRequest', (_message.Message,), {
- 'DESCRIPTOR' : _ADDFIRMWAREINFOREQUEST,
+InclusionProof = _reflection.GeneratedProtocolMessageType('InclusionProof', (_message.Message,), {
+ 'DESCRIPTOR' : _INCLUSIONPROOF,
'__module__' : 'api_pb2'
- # @@protoc_insertion_point(class_scope:aftl.AddFirmwareInfoRequest)
+ # @@protoc_insertion_point(class_scope:aftl.InclusionProof)
})
-_sym_db.RegisterMessage(AddFirmwareInfoRequest)
+_sym_db.RegisterMessage(InclusionProof)
-AddFirmwareInfoResponse = _reflection.GeneratedProtocolMessageType('AddFirmwareInfoResponse', (_message.Message,), {
- 'DESCRIPTOR' : _ADDFIRMWAREINFORESPONSE,
+AddVBMetaRequest = _reflection.GeneratedProtocolMessageType('AddVBMetaRequest', (_message.Message,), {
+ 'DESCRIPTOR' : _ADDVBMETAREQUEST,
'__module__' : 'api_pb2'
- # @@protoc_insertion_point(class_scope:aftl.AddFirmwareInfoResponse)
+ # @@protoc_insertion_point(class_scope:aftl.AddVBMetaRequest)
})
-_sym_db.RegisterMessage(AddFirmwareInfoResponse)
+_sym_db.RegisterMessage(AddVBMetaRequest)
-AddFirmwareImageRequest = _reflection.GeneratedProtocolMessageType('AddFirmwareImageRequest', (_message.Message,), {
- 'DESCRIPTOR' : _ADDFIRMWAREIMAGEREQUEST,
+AddVBMetaResponse = _reflection.GeneratedProtocolMessageType('AddVBMetaResponse', (_message.Message,), {
+ 'DESCRIPTOR' : _ADDVBMETARESPONSE,
'__module__' : 'api_pb2'
- # @@protoc_insertion_point(class_scope:aftl.AddFirmwareImageRequest)
+ # @@protoc_insertion_point(class_scope:aftl.AddVBMetaResponse)
})
-_sym_db.RegisterMessage(AddFirmwareImageRequest)
+_sym_db.RegisterMessage(AddVBMetaResponse)
-AddFirmwareImageResponse = _reflection.GeneratedProtocolMessageType('AddFirmwareImageResponse', (_message.Message,), {
- 'DESCRIPTOR' : _ADDFIRMWAREIMAGERESPONSE,
+AnnotateVBMetaWithBuildRequest = _reflection.GeneratedProtocolMessageType('AnnotateVBMetaWithBuildRequest', (_message.Message,), {
+ 'DESCRIPTOR' : _ANNOTATEVBMETAWITHBUILDREQUEST,
'__module__' : 'api_pb2'
- # @@protoc_insertion_point(class_scope:aftl.AddFirmwareImageResponse)
+ # @@protoc_insertion_point(class_scope:aftl.AnnotateVBMetaWithBuildRequest)
})
-_sym_db.RegisterMessage(AddFirmwareImageResponse)
+_sym_db.RegisterMessage(AnnotateVBMetaWithBuildRequest)
+
+AnnotateVBMetaWithBuildResponse = _reflection.GeneratedProtocolMessageType('AnnotateVBMetaWithBuildResponse', (_message.Message,), {
+ 'DESCRIPTOR' : _ANNOTATEVBMETAWITHBUILDRESPONSE,
+ '__module__' : 'api_pb2'
+ # @@protoc_insertion_point(class_scope:aftl.AnnotateVBMetaWithBuildResponse)
+ })
+_sym_db.RegisterMessage(AnnotateVBMetaWithBuildResponse)
DESCRIPTOR._options = None
@@ -250,25 +294,25 @@
file=DESCRIPTOR,
index=0,
serialized_options=None,
- serialized_start=518,
- serialized_end=695,
+ serialized_start=585,
+ serialized_end=766,
methods=[
_descriptor.MethodDescriptor(
- name='AddFirmwareInfo',
- full_name='aftl.AFTLog.AddFirmwareInfo',
+ name='AddVBMeta',
+ full_name='aftl.AFTLog.AddVBMeta',
index=0,
containing_service=None,
- input_type=_ADDFIRMWAREINFOREQUEST,
- output_type=_ADDFIRMWAREINFORESPONSE,
+ input_type=_ADDVBMETAREQUEST,
+ output_type=_ADDVBMETARESPONSE,
serialized_options=None,
),
_descriptor.MethodDescriptor(
- name='AddFirmwareImage',
- full_name='aftl.AFTLog.AddFirmwareImage',
+ name='AnnotateVBMetaWithBuild',
+ full_name='aftl.AFTLog.AnnotateVBMetaWithBuild',
index=1,
containing_service=None,
- input_type=_ADDFIRMWAREIMAGEREQUEST,
- output_type=_ADDFIRMWAREIMAGERESPONSE,
+ input_type=_ANNOTATEVBMETAWITHBUILDRESPONSE,
+ output_type=_ANNOTATEVBMETAWITHBUILDRESPONSE,
serialized_options=None,
),
])
diff --git a/proto/api_pb2_grpc.py b/proto/api_pb2_grpc.py
index b1834c7..d487856 100644
--- a/proto/api_pb2_grpc.py
+++ b/proto/api_pb2_grpc.py
@@ -1,4 +1,3 @@
-# pylint: skip-file
# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
import grpc
@@ -15,15 +14,15 @@
Args:
channel: A grpc.Channel.
"""
- self.AddFirmwareInfo = channel.unary_unary(
- '/aftl.AFTLog/AddFirmwareInfo',
- request_serializer=api__pb2.AddFirmwareInfoRequest.SerializeToString,
- response_deserializer=api__pb2.AddFirmwareInfoResponse.FromString,
+ self.AddVBMeta = channel.unary_unary(
+ '/aftl.AFTLog/AddVBMeta',
+ request_serializer=api__pb2.AddVBMetaRequest.SerializeToString,
+ response_deserializer=api__pb2.AddVBMetaResponse.FromString,
)
- self.AddFirmwareImage = channel.stream_unary(
- '/aftl.AFTLog/AddFirmwareImage',
- request_serializer=api__pb2.AddFirmwareImageRequest.SerializeToString,
- response_deserializer=api__pb2.AddFirmwareImageResponse.FromString,
+ self.AnnotateVBMetaWithBuild = channel.stream_unary(
+ '/aftl.AFTLog/AnnotateVBMetaWithBuild',
+ request_serializer=api__pb2.AnnotateVBMetaWithBuildResponse.SerializeToString,
+ response_deserializer=api__pb2.AnnotateVBMetaWithBuildResponse.FromString,
)
@@ -31,17 +30,17 @@
# missing associated documentation comment in .proto file
pass
- def AddFirmwareInfo(self, request, context):
+ def AddVBMeta(self, request, context):
"""Insert a new VBMeta structure into the log.
This request will effectively create 2 log entries:
- VBMeta itself
- - Vendor annotations, including a reference to the VBMeta leaf.
+ - Vendor annotations, which includes a reference to the VBMeta.
"""
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
- def AddFirmwareImage(self, request_iterator, context):
+ def AnnotateVBMetaWithBuild(self, request_iterator, context):
"""Upload (or copy) the complete firmware image.
"""
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
@@ -51,15 +50,15 @@
def add_AFTLogServicer_to_server(servicer, server):
rpc_method_handlers = {
- 'AddFirmwareInfo': grpc.unary_unary_rpc_method_handler(
- servicer.AddFirmwareInfo,
- request_deserializer=api__pb2.AddFirmwareInfoRequest.FromString,
- response_serializer=api__pb2.AddFirmwareInfoResponse.SerializeToString,
+ 'AddVBMeta': grpc.unary_unary_rpc_method_handler(
+ servicer.AddVBMeta,
+ request_deserializer=api__pb2.AddVBMetaRequest.FromString,
+ response_serializer=api__pb2.AddVBMetaResponse.SerializeToString,
),
- 'AddFirmwareImage': grpc.stream_unary_rpc_method_handler(
- servicer.AddFirmwareImage,
- request_deserializer=api__pb2.AddFirmwareImageRequest.FromString,
- response_serializer=api__pb2.AddFirmwareImageResponse.SerializeToString,
+ 'AnnotateVBMetaWithBuild': grpc.stream_unary_rpc_method_handler(
+ servicer.AnnotateVBMetaWithBuild,
+ request_deserializer=api__pb2.AnnotateVBMetaWithBuildResponse.FromString,
+ response_serializer=api__pb2.AnnotateVBMetaWithBuildResponse.SerializeToString,
),
}
generic_handler = grpc.method_handlers_generic_handler(
diff --git a/test/avb_aftl_fuzz.cc b/test/avb_aftl_fuzz.cc
new file mode 100644
index 0000000..89b59d8
--- /dev/null
+++ b/test/avb_aftl_fuzz.cc
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "libavb_aftl/avb_aftl_types.h"
+#include "libavb_aftl/avb_aftl_util.h"
+
+extern "C" int LLVMFuzzerTestOneInput(const char* data, size_t size) {
+ AftlImage* image = parse_aftl_image((uint8_t*)data, size);
+ free_aftl_image(image);
+ return 0;
+}
diff --git a/test/avb_aftl_util_unittest.cc b/test/avb_aftl_util_unittest.cc
index a813976..33a598c 100644
--- a/test/avb_aftl_util_unittest.cc
+++ b/test/avb_aftl_util_unittest.cc
@@ -29,8 +29,13 @@
namespace {
-const char kAftlImagePath[] = "test/data/aftl_image.bin";
-const char kAftlImageMultiPath[] = "test/data/aftl_image_multi.bin";
+/* TODO(b/154115873): These VBMetas are manually generated. We need to implement
+ * a mock in aftltool that generates an inclusion proof and call that mock from
+ * the unit tests, similarly to what is done with GenerateVBMetaImage. */
+const char kAftlImagePath[] = "test/data/aftl_output_vbmeta_with_1_icp.img";
+const uint64_t kAftlImageOffset = 0x1100;
+const char kAftlImageMultiPath[] =
+ "test/data/aftl_output_vbmeta_with_2_icp_same_log.img";
} // namespace
@@ -41,31 +46,23 @@
AvbAftlUtilTest() {}
~AvbAftlUtilTest() {}
void SetUp() override {
- uint8_t* aftl_blob;
- int64_t aftl_image_size;
+ std::string content;
BaseAvbToolTest::SetUp();
/* Read in test data from the aftl_image binaries. */
- base::GetFileSize(base::FilePath(kAftlImagePath), &aftl_image_size);
- ASSERT_GT(aftl_image_size, 0);
- aftl_blob = (uint8_t*)avb_malloc(aftl_image_size);
- ASSERT_TRUE(aftl_blob != NULL);
- base::ReadFile(
- base::FilePath(kAftlImagePath), (char*)aftl_blob, aftl_image_size);
+ ASSERT_TRUE(
+ base::ReadFileToString(base::FilePath(kAftlImagePath), &content));
+ content = content.substr(kAftlImageOffset);
/* Allocate and populate an AftlImage for testing. */
- aftl_image_ = parse_aftl_image(aftl_blob, aftl_image_size);
- avb_free(aftl_blob);
+ aftl_image_ = parse_aftl_image((uint8_t*)content.data(), content.size());
/* Read in test data from the aftl_image file with multiple ICPs. */
- base::GetFileSize(base::FilePath(kAftlImageMultiPath), &aftl_image_size);
- ASSERT_GT(aftl_image_size, 0);
- aftl_blob = (uint8_t*)avb_malloc(aftl_image_size);
- ASSERT_TRUE(aftl_blob != NULL);
- base::ReadFile(
- base::FilePath(kAftlImageMultiPath), (char*)aftl_blob, aftl_image_size);
+ ASSERT_TRUE(
+ base::ReadFileToString(base::FilePath(kAftlImageMultiPath), &content));
+ content = content.substr(kAftlImageOffset);
/* Allocate and populate an AftlImage for testing. */
- aftl_image_multi_ = parse_aftl_image(aftl_blob, aftl_image_size);
- avb_free(aftl_blob);
+ aftl_image_multi_ =
+ parse_aftl_image((uint8_t*)content.data(), content.size());
}
void TearDown() override {
@@ -77,7 +74,7 @@
void TestAftlImageHeader(AftlImageHeader* aftl_header, uint16_t icp_count) {
EXPECT_EQ(aftl_header->magic, 0x4c544641ul);
EXPECT_EQ(aftl_header->required_icp_version_major, 1ul);
- EXPECT_EQ(aftl_header->required_icp_version_minor, 1ul);
+ EXPECT_EQ(aftl_header->required_icp_version_minor, 2ul);
EXPECT_EQ(aftl_header->icp_count, icp_count);
}
@@ -86,7 +83,7 @@
EXPECT_GT(icp_entry->log_url_size, 0ul);
EXPECT_GT(icp_entry->leaf_index, 1ul);
EXPECT_GT(icp_entry->log_root_descriptor_size, 0ul);
- EXPECT_GT(icp_entry->fw_info_leaf_size, 0ul);
+ EXPECT_GT(icp_entry->annotation_leaf_size, 0ul);
EXPECT_EQ(icp_entry->log_root_sig_size, AVB_AFTL_SIGNATURE_SIZE);
EXPECT_GT(icp_entry->proof_hash_count, 0ul);
EXPECT_LT(icp_entry->proof_hash_count, 64ul);
@@ -101,7 +98,8 @@
EXPECT_GT(icp_entry->log_root_descriptor.revision, 0ull);
EXPECT_EQ(icp_entry->log_root_descriptor.metadata_size, 0);
/* Test the FirmwareInfo fields. */
- EXPECT_EQ(icp_entry->fw_info_leaf.vbmeta_hash_size, AVB_AFTL_HASH_SIZE);
+ EXPECT_EQ(icp_entry->annotation_leaf->annotation->vbmeta_hash_size,
+ AVB_AFTL_HASH_SIZE);
EXPECT_EQ(icp_entry->proof_hash_count * 32ul, icp_entry->inc_proof_size);
}
diff --git a/test/avb_aftl_validate_unittest.cc b/test/avb_aftl_validate_unittest.cc
index 84a723d..2a78e6a 100644
--- a/test/avb_aftl_validate_unittest.cc
+++ b/test/avb_aftl_validate_unittest.cc
@@ -33,8 +33,15 @@
namespace {
-const char kAftlKeyBytesPath[] = "test/data/aftl_key_bytes.bin";
-const char kAftlLogSigPath[] = "test/data/aftl_log_sig.bin";
+/* Public part of testkey_rsa4096.pem, in the AvbRsaPublicKey format. Generated
+ * using:
+ * $ openssl rsa -in testkey_rsa4096.pem -pubout -out testkey_rsa4096_pub.pem
+ * $ avbtool extract_public_key --key testkey_rsa4096_pub.pem --output \
+ * testkey_rsa4096_pub.bin.
+ */
+const char kKeyBytesPath[] = "test/data/testkey_rsa4096_pub.bin";
+/* Example VBMeta. Its hash should match the value kVBMetaHash defined below. */
+const char kVBMetaPath[] = "test/data/aftl_input_vbmeta.img";
} /* namespace */
@@ -46,44 +53,108 @@
AvbAftlValidateTest() {}
~AvbAftlValidateTest() {}
void SetUp() override {
- uint8_t kAftlJsonData[] =
- "{\"timestamp\":{\"seconds\":1581533076,\"nanos\":884246745},\"Value\":"
- "{\"FwInfo\":{\"info\":{\"info\":{\"vbmeta_hash\":"
- "\"mS461dkWuKtPENmqaVQpg/"
- "xoHUPNsqRvnrh1uLUkKCQ=\",\"version_incremental\":\"1\",\"manufacturer_"
- "key_hash\":\"JkjCeRzSiHsHxxiVVieHNEvd9bsehav59qmB4BRvYGs=\"},\"info_"
- "signature\":{\"hash_algorithm\":4,\"signature_algorithm\":1,"
- "\"signature\":\"YqMyK9rOly4dG+"
- "QX3qXwkCedZK8w8iXHX90i0OXV4reCNS8xP51scQoh/"
- "SINWjJQ3hDjIfveQ0SRtY748GeNfrajCDslRAce8f48M3B9Jf5RezbY/MA4ZE/"
- "IfgTQp6sFLPp2xM+RoPd/GMHtEP0zc98+0/7hsDC7wZeGip7HoxGGiaWqpy+zkp/"
- "NpD4aSEIz5gtvBisPI/blQbyPoH6cfNT9rJLvzfHIa6Cp/xpZoY7e2EUH/"
- "XoG6cJGDC3ddPxuLISITQ6ddZkpyhTcA5+xSN8zJxjei1EQOk02Oo9Bqs4srIuO1o/"
- "b91bTteykCK6ScCMt/rSsfxW6N9o/KvNSOr/"
- "csXyIBkeHQZ952MaD8vGNX3NkE+FdOEXBr6AWdAwIuHsjVK1uSp+nR/"
- "kQ2NuXnALXTsM1nB70rnUYdD0cC8OIHvJs9JvV4ATJ/"
- "SQAoGIDdk1up7w6y7+QOtXC+Dd2Y6aul96xiqDRrdza0ZyEzOBPIssNq34dVR+k7+"
- "jofkMsDD/"
- "VT3Ngec17SeZUFfKj1Uv1z6bt6fusfv6Veb84ch0Yx5elLXNfnvvguF0z5qZp+"
- "AjlkUEbhI5sRKrE9v1wV/IFiwYuHNMX3NBuKpx+8e7SXwZodXRBeocpSlA/"
- "Qf8dtomxAALZrB30HSOzYavMs/4=\"}}}}}";
+ /* Generate an artificial inclusion proof with its own annotation. The
+ * annotation matches the kVBMetaPath file. It is signed using the
+ * testkey_rsa4096.pem key. */
+ /* We define the constants below as string literals (to be able to annotate
+ * the bytes). We keep their sizes in a separate variable as sizeof will
+ * include the final null byte that is automatically appended. */
+ const uint8_t kAnnotationLeafHeader[] =
+ "\x01" // Version
+ "\x00\x00\x00\x00\x00\x00\x00\x00" // Timestamp
+ "\x01"; // Leaf Type
+ const size_t kAnnotationLeafHeaderSize = sizeof(kAnnotationLeafHeader) - 1;
+ const uint8_t kSignature[] =
+ "\x00" // Hash Type
+ "\x00" // Signature Type
+ "\x00"; // Signature size
+ const size_t kSignatureSize = sizeof(kSignature) - 1;
+ const uint8_t kAnnotationHeader[] = "\x20"; // VBMeta hash size
+ const size_t kAnnotationHeaderSize = sizeof(kAnnotationHeader) - 1;
+ /* This is the SHA256 hash of the image at kVBMetaPath */
+ const uint8_t kVBMetaHash[] =
+ "\x34\x1c\x6c\xf2\x4b\xc1\xe6\x4a\xb1\x03\xa0\xee\xe1\x9d\xee\x9c"
+ "\x35\x34\xdb\x07\x17\x29\xb4\xad\xd0\xce\xa0\xbd\x52\x92\x54\xec";
+ const uint8_t kAnnotationFooter[] =
+ "\x03" // Version incremental size
+ "123" // Version incremental
+ "\x00" // Manufacturer key hash size
+ "\x00\x05" // Description size
+ "abcde"; // Description
+ const size_t kAnnotationFooterSize = sizeof(kAnnotationFooter) - 1;
+ const uint8_t kLogRootDescriptorHeader[] =
+ "\x00\x01" // Version
+ "\x00\x00\x00\x00\x00\x00\x00\x03" // Tree size
+ "\x20"; // Root hash size
+ const size_t kLogRootDescriptorHeaderSize =
+ sizeof(kLogRootDescriptorHeader) - 1;
+ const uint8_t kLogRootDescriptorRootHash[] =
+ "\x40\x79\x2f\xf1\xcb\xfc\xd1\x8a\x13\x70\x90\xaf\x6a\x16\x4d\xa9"
+ "\x36\x80\x99\xb3\xf9\x7f\x99\x13\x3e\x07\xff\xbc\x73\x42\xfc\xc7";
+ const uint8_t kLogRootDescriptorFooter[] =
+ "\x00\x00\x00\x00\x13\x36\x4b\xff" // Timestamp
+ "\x00\x00\x00\x00\x00\x00\x00\x00" // Revision
+ "\x00\x00"; // Metadata size
+ const size_t kLogRootDescriptorFooterSize =
+ sizeof(kLogRootDescriptorFooter) - 1;
+ /* Signature of the log root descriptor.
+ * $ openssl dgst -sha256 -sign testkey_rsa4096.pem \
+ * -out kLogRootHashSignature log_root_descriptor_raw
+ * log_root_descriptor_raw is defined as the concatenation:
+ * kLogRootDescriptorHeader || kLogRootDescriptorRootHash ||
+ * kLogRootDescriptorFooter */
+ const uint8_t kLogRootHashSignature[] = {
+ 0x55, 0x1d, 0xd3, 0x13, 0x3c, 0x41, 0xde, 0x67, 0x79, 0xf1, 0xc6, 0xad,
+ 0x72, 0x10, 0xff, 0xfb, 0x6d, 0xac, 0xc1, 0x1c, 0x06, 0x2a, 0x3e, 0xa8,
+ 0xd9, 0xf3, 0x8c, 0x9c, 0x67, 0xbe, 0x1e, 0x8e, 0xe1, 0x02, 0xf6, 0xdb,
+ 0xd2, 0x5c, 0x31, 0x4b, 0x26, 0xad, 0x9a, 0xd1, 0xf5, 0x7d, 0xb9, 0x6b,
+ 0x4b, 0xf1, 0x7a, 0x89, 0x9d, 0xf0, 0x17, 0xb4, 0xee, 0xb2, 0x08, 0x0d,
+ 0xd8, 0x99, 0xac, 0x7b, 0x34, 0x1f, 0xd1, 0x9c, 0x2e, 0x0c, 0xd1, 0xb1,
+ 0x42, 0x34, 0xf2, 0x65, 0xbb, 0x79, 0x7a, 0xac, 0x23, 0x37, 0xec, 0xfc,
+ 0xff, 0xbf, 0x66, 0x51, 0xed, 0x3e, 0xa7, 0x45, 0x3a, 0xf9, 0x72, 0xaa,
+ 0x01, 0x3c, 0xfd, 0x59, 0x01, 0x67, 0x67, 0xb4, 0x57, 0x23, 0xb6, 0x7e,
+ 0x59, 0x82, 0xb3, 0x98, 0xa2, 0x57, 0xd4, 0x64, 0x83, 0xaa, 0x02, 0x17,
+ 0x87, 0xfd, 0xa2, 0xe2, 0x3b, 0xa8, 0xf5, 0xc2, 0xfb, 0xce, 0x7f, 0x59,
+ 0x72, 0x10, 0xc5, 0x11, 0x81, 0x80, 0x20, 0x4a, 0x3e, 0xf9, 0x85, 0x2e,
+ 0x44, 0x94, 0x87, 0xec, 0xfa, 0x2e, 0x8f, 0x75, 0x00, 0x6f, 0x52, 0x1b,
+ 0x4d, 0x5c, 0xfc, 0xe4, 0x1f, 0xe2, 0x94, 0xbc, 0x8c, 0xe8, 0x7f, 0x74,
+ 0x14, 0x2f, 0x66, 0x8e, 0xfb, 0x11, 0x34, 0xde, 0x80, 0x21, 0x92, 0xc3,
+ 0x52, 0xa7, 0xf7, 0x5e, 0x49, 0x53, 0x21, 0x7d, 0x8b, 0xa2, 0xcb, 0x84,
+ 0x80, 0x64, 0x0d, 0xd7, 0xd0, 0x6d, 0x6f, 0x2a, 0x98, 0x57, 0x3b, 0x95,
+ 0xa1, 0x63, 0x39, 0x00, 0x22, 0x9e, 0x5a, 0x75, 0x07, 0x10, 0x1f, 0x7e,
+ 0xdb, 0x05, 0x5d, 0x3d, 0x76, 0x75, 0x3c, 0x1a, 0xd4, 0x1e, 0x8d, 0x6e,
+ 0xce, 0x57, 0xd6, 0xce, 0x23, 0xc0, 0x23, 0x4c, 0xcb, 0x10, 0xec, 0x59,
+ 0x22, 0x64, 0x57, 0x33, 0x1c, 0x3f, 0xa9, 0x43, 0x97, 0xc1, 0xc0, 0x93,
+ 0x5a, 0x16, 0x80, 0x51, 0x56, 0x28, 0x98, 0x33, 0xee, 0x1a, 0xf8, 0x38,
+ 0x7a, 0xaa, 0xdb, 0x43, 0x39, 0x90, 0x9e, 0x74, 0xb7, 0x9f, 0xfe, 0xa5,
+ 0x84, 0x69, 0xf5, 0x77, 0x80, 0x92, 0xec, 0x06, 0x06, 0xe0, 0xd2, 0x98,
+ 0x34, 0x66, 0x25, 0xc3, 0x7c, 0x89, 0x78, 0x3a, 0x0b, 0x48, 0x49, 0x37,
+ 0x46, 0x07, 0xc4, 0xc8, 0x04, 0x72, 0x45, 0x60, 0x36, 0x98, 0x2d, 0x47,
+ 0xfe, 0xba, 0x74, 0xb9, 0xb0, 0xe4, 0xf5, 0x45, 0xa0, 0xfb, 0x4a, 0x53,
+ 0xe0, 0x16, 0x6a, 0x6b, 0x82, 0xcc, 0x33, 0x1c, 0x3c, 0x64, 0xe0, 0x90,
+ 0x3c, 0x59, 0xfa, 0x04, 0x51, 0xe0, 0xe8, 0xaa, 0xe9, 0x92, 0x43, 0x04,
+ 0x2a, 0x49, 0xd4, 0xdf, 0xac, 0x1d, 0x46, 0x44, 0xad, 0x65, 0x62, 0xaf,
+ 0x44, 0x16, 0xb0, 0x05, 0x56, 0x2b, 0xa4, 0xad, 0x4c, 0x7e, 0xbd, 0x04,
+ 0x95, 0xcb, 0xce, 0x0e, 0xf6, 0xd5, 0x4b, 0x3a, 0xc0, 0xde, 0x1e, 0xf8,
+ 0xfa, 0xf5, 0x73, 0x4a, 0x6d, 0xc2, 0x4a, 0xe1, 0xaf, 0xae, 0xd8, 0x31,
+ 0x23, 0x16, 0x5d, 0x15, 0x41, 0xe6, 0xbf, 0x4a, 0xe0, 0xf3, 0xdd, 0x74,
+ 0x32, 0x96, 0x64, 0x4c, 0x16, 0x7d, 0xd3, 0xad, 0x21, 0x47, 0x2b, 0x17,
+ 0xb9, 0xf3, 0x84, 0x38, 0x80, 0x60, 0xb6, 0xcb, 0x24, 0x45, 0x24, 0x90,
+ 0x74, 0xe9, 0x50, 0xea, 0x2e, 0x1f, 0xc2, 0x74, 0x36, 0xa2, 0xf5, 0xd7,
+ 0x24, 0xb3, 0xa1, 0x1f, 0xd3, 0x39, 0x61, 0x67, 0x37, 0xe4, 0x2a, 0x20,
+ 0x67, 0x95, 0x53, 0x9d, 0xd4, 0xdb, 0x4f, 0xa6, 0xb8, 0x7f, 0x91, 0xb2,
+ 0xc5, 0x6f, 0x71, 0x3c, 0x86, 0xc8, 0x36, 0x8d, 0xa4, 0x4d, 0x53, 0x6b,
+ 0x3f, 0xe6, 0xce, 0xf1, 0x7a, 0xa2, 0x2e, 0x53, 0x80, 0x4c, 0x52, 0x9d,
+ 0x3e, 0xd7, 0xec, 0x47, 0x4a, 0xfa, 0x84, 0xa5, 0x9a, 0x2f, 0x7b, 0xfc,
+ 0xfc, 0xe8, 0xa4, 0x09, 0xfb, 0xb5, 0xb7, 0xf2};
BaseAvbToolTest::SetUp();
/* Read in test data from the key and log_sig binaries. */
- base::GetFileSize(base::FilePath(kAftlKeyBytesPath), &key_size_);
- if (key_size_ != AVB_AFTL_PUB_KEY_SIZE) return;
- key_bytes_ = (uint8_t*)avb_malloc(key_size_);
- if (!key_bytes_) return;
- base::ReadFile(
- base::FilePath(kAftlKeyBytesPath), (char*)key_bytes_, key_size_);
- base::GetFileSize(base::FilePath(kAftlLogSigPath), &log_sig_size_);
- if (log_sig_size_ != AVB_AFTL_SIGNATURE_SIZE) return;
- log_sig_bytes_ = (uint8_t*)avb_malloc(log_sig_size_);
- if (!log_sig_bytes_) return;
- base::ReadFile(
- base::FilePath(kAftlLogSigPath), (char*)log_sig_bytes_, log_sig_size_);
- icp_entry_ =
- (AftlIcpEntry*)avb_malloc(sizeof(AftlIcpEntry) + AVB_AFTL_HASH_SIZE);
+ ASSERT_TRUE(
+ base::ReadFileToString(base::FilePath(kKeyBytesPath), &key_bytes_));
+
+ /* Allocate and populate the inclusion proof */
+ icp_entry_ = (AftlIcpEntry*)avb_malloc(sizeof(AftlIcpEntry));
if (!icp_entry_) return;
icp_entry_->log_root_descriptor.version = 1;
icp_entry_->log_root_descriptor.tree_size = 3;
@@ -92,108 +163,141 @@
icp_entry_->log_root_descriptor.revision = 0;
icp_entry_->log_root_descriptor.metadata_size = 0;
icp_entry_->log_root_descriptor.metadata = NULL;
- icp_entry_->log_root_descriptor_size =
- icp_entry_->log_root_descriptor.root_hash_size +
- icp_entry_->log_root_descriptor.metadata_size + 29;
-
- icp_entry_->fw_info_leaf_size = sizeof(kAftlJsonData);
- icp_entry_->fw_info_leaf.vbmeta_hash_size = AVB_AFTL_HASH_SIZE;
- icp_entry_->fw_info_leaf.vbmeta_hash =
- (uint8_t*)avb_malloc(AVB_AFTL_HASH_SIZE);
- if (!icp_entry_->fw_info_leaf.vbmeta_hash) {
+ icp_entry_->log_root_descriptor_size = kLogRootDescriptorHeaderSize +
+ AVB_AFTL_HASH_SIZE +
+ kLogRootDescriptorFooterSize;
+ icp_entry_->log_root_descriptor_raw =
+ (uint8_t*)avb_malloc(icp_entry_->log_root_descriptor_size);
+ if (!icp_entry_->log_root_descriptor_raw) {
return;
}
- memcpy(icp_entry_->fw_info_leaf.vbmeta_hash,
- "\x65\xec\x58\x83\x43\x62\x8e\x81\x4d\xc7\x75\xa8\xcb\x77\x1f\x46"
- "\x81\xcc\x79\x6f\xba\x32\xf0\x68\xc7\x17\xce\x2e\xe2\x14\x4d\x39",
+ memcpy(icp_entry_->log_root_descriptor_raw,
+ kLogRootDescriptorHeader,
+ kLogRootDescriptorHeaderSize);
+ memcpy(icp_entry_->log_root_descriptor_raw + kLogRootDescriptorHeaderSize,
+ kLogRootDescriptorRootHash,
AVB_AFTL_HASH_SIZE);
- icp_entry_->fw_info_leaf.json_data =
- (uint8_t*)avb_calloc(icp_entry_->fw_info_leaf_size);
- if (icp_entry_->fw_info_leaf.json_data == NULL) {
- avb_free(icp_entry_->fw_info_leaf.vbmeta_hash);
- return;
- }
- memcpy(icp_entry_->fw_info_leaf.json_data,
- kAftlJsonData,
- icp_entry_->fw_info_leaf_size);
- icp_entry_->leaf_index = 2;
+ memcpy(icp_entry_->log_root_descriptor_raw + kLogRootDescriptorHeaderSize +
+ AVB_AFTL_HASH_SIZE,
+ kLogRootDescriptorFooter,
+ kLogRootDescriptorFooterSize);
+ icp_entry_->log_root_descriptor.root_hash =
+ (uint8_t*)avb_malloc(AVB_AFTL_HASH_SIZE);
+ if (!icp_entry_->log_root_descriptor.root_hash) return;
+ /* Copy the hash from within the raw version */
+ memcpy(icp_entry_->log_root_descriptor.root_hash,
+ kLogRootDescriptorRootHash,
+ AVB_AFTL_HASH_SIZE);
+ icp_entry_->log_root_sig_size = AVB_AFTL_SIGNATURE_SIZE;
+ icp_entry_->log_root_signature =
+ (uint8_t*)avb_malloc(AVB_AFTL_SIGNATURE_SIZE);
+ memcpy(icp_entry_->log_root_signature,
+ kLogRootHashSignature,
+ AVB_AFTL_SIGNATURE_SIZE);
+ /* Allocate the annotation leaf */
+ icp_entry_->annotation_leaf_size =
+ kAnnotationLeafHeaderSize + kSignatureSize + kAnnotationHeaderSize +
+ AVB_AFTL_HASH_SIZE + kAnnotationFooterSize;
+ icp_entry_->annotation_leaf =
+ (SignedVBMetaPrimaryAnnotationLeaf*)avb_calloc(
+ sizeof(SignedVBMetaPrimaryAnnotationLeaf));
+ if (!icp_entry_->annotation_leaf) return;
+ icp_entry_->annotation_leaf->version = 1;
+ icp_entry_->annotation_leaf->timestamp = 0;
+ icp_entry_->annotation_leaf->leaf_type =
+ AVB_AFTL_SIGNED_VBMETA_PRIMARY_ANNOTATION_LEAF;
+ icp_entry_->annotation_leaf->annotation =
+ (VBMetaPrimaryAnnotation*)avb_calloc(sizeof(VBMetaPrimaryAnnotation));
+ if (!icp_entry_->annotation_leaf->annotation) return;
+ icp_entry_->annotation_leaf->annotation->vbmeta_hash_size =
+ AVB_AFTL_HASH_SIZE;
+ icp_entry_->annotation_leaf->annotation->vbmeta_hash =
+ (uint8_t*)avb_calloc(AVB_AFTL_HASH_SIZE);
+ if (!icp_entry_->annotation_leaf->annotation->vbmeta_hash) return;
+ memcpy(icp_entry_->annotation_leaf->annotation->vbmeta_hash,
+ kVBMetaHash,
+ AVB_AFTL_HASH_SIZE);
+ icp_entry_->annotation_leaf_raw =
+ (uint8_t*)avb_calloc(icp_entry_->annotation_leaf_size);
+ if (!icp_entry_->annotation_leaf_raw) return;
+ memcpy(icp_entry_->annotation_leaf_raw,
+ kAnnotationLeafHeader,
+ kAnnotationLeafHeaderSize);
+ memcpy(icp_entry_->annotation_leaf_raw + kAnnotationLeafHeaderSize,
+ kSignature,
+ kSignatureSize);
+ memcpy(icp_entry_->annotation_leaf_raw + kAnnotationLeafHeaderSize +
+ kSignatureSize,
+ kAnnotationHeader,
+ kAnnotationHeaderSize);
+ memcpy(icp_entry_->annotation_leaf_raw + kAnnotationLeafHeaderSize +
+ kSignatureSize + kAnnotationHeaderSize,
+ kVBMetaHash,
+ AVB_AFTL_HASH_SIZE);
+ memcpy(icp_entry_->annotation_leaf_raw + kAnnotationLeafHeaderSize +
+ kSignatureSize + kAnnotationHeaderSize + AVB_AFTL_HASH_SIZE,
+ kAnnotationFooter,
+ kAnnotationFooterSize);
+
+ icp_entry_->leaf_index = 2;
+ icp_entry_->proofs =
+ (uint8_t(*)[AVB_AFTL_HASH_SIZE])avb_calloc(AVB_AFTL_HASH_SIZE);
memcpy(icp_entry_->proofs[0],
"\xfa\xc5\x42\x03\xe7\xcc\x69\x6c\xf0\xdf\xcb\x42\xc9\x2a\x1d\x9d"
"\xba\xf7\x0a\xd9\xe6\x21\xf4\xbd\x8d\x98\x66\x2f\x00\xe3\xc1\x25",
AVB_AFTL_HASH_SIZE);
icp_entry_->proof_hash_count = 1;
- icp_entry_->log_root_descriptor.root_hash =
- (uint8_t*)avb_malloc(AVB_AFTL_HASH_SIZE);
- if (!icp_entry_->log_root_descriptor.root_hash) return;
- memcpy(icp_entry_->log_root_descriptor.root_hash,
- "\x5a\xb3\x43\x21\x8f\x54\x4d\x05\x46\x34\x62\x86\x2f\xa8\xf8\x6e"
- "\x3b\xa3\x19\x2d\xe9\x9c\xb2\xab\x8e\x09\xd8\x55\xc3\xde\x34\xd6",
- AVB_AFTL_HASH_SIZE);
}
void TearDown() override {
- if (icp_entry_ != NULL) {
- if (icp_entry_->fw_info_leaf.json_data != NULL)
- avb_free(icp_entry_->fw_info_leaf.json_data);
- if (icp_entry_->fw_info_leaf.vbmeta_hash != NULL)
- avb_free(icp_entry_->fw_info_leaf.vbmeta_hash);
- if (icp_entry_->log_root_descriptor.root_hash != NULL)
+ if (icp_entry_) {
+ if (icp_entry_->annotation_leaf_raw)
+ avb_free(icp_entry_->annotation_leaf_raw);
+ if (icp_entry_->annotation_leaf) {
+ if (icp_entry_->annotation_leaf->annotation) {
+ if (icp_entry_->annotation_leaf->annotation->vbmeta_hash)
+ avb_free(icp_entry_->annotation_leaf->annotation->vbmeta_hash);
+ avb_free(icp_entry_->annotation_leaf->annotation);
+ }
+ avb_free(icp_entry_->annotation_leaf);
+ }
+ if (icp_entry_->log_root_descriptor.root_hash)
avb_free(icp_entry_->log_root_descriptor.root_hash);
+ if (icp_entry_->log_root_descriptor_raw)
+ avb_free(icp_entry_->log_root_descriptor_raw);
+ if (icp_entry_->log_root_signature)
+ avb_free(icp_entry_->log_root_signature);
+ if (icp_entry_->proofs) avb_free(icp_entry_->proofs);
avb_free(icp_entry_);
}
- avb_free(key_bytes_);
- avb_free(log_sig_bytes_);
BaseAvbToolTest::TearDown();
}
protected:
AftlIcpEntry* icp_entry_;
- uint8_t* key_bytes_;
- uint8_t* log_sig_bytes_;
- int64_t key_size_;
- int64_t log_sig_size_;
+ std::string key_bytes_;
};
-TEST_F(AvbAftlValidateTest, AvbAftlVerifySignature) {
- icp_entry_->log_root_sig_size = AVB_AFTL_SIGNATURE_SIZE;
- icp_entry_->log_root_signature =
- (uint8_t*)avb_malloc(AVB_AFTL_SIGNATURE_SIZE);
- memcpy(
- icp_entry_->log_root_signature, log_sig_bytes_, AVB_AFTL_SIGNATURE_SIZE);
+TEST_F(AvbAftlValidateTest, VerifyEntrySignature) {
EXPECT_EQ(true,
- avb_aftl_verify_entry_signature(key_bytes_, key_size_, icp_entry_));
- avb_free(icp_entry_->log_root_signature);
+ avb_aftl_verify_entry_signature(
+ (uint8_t*)key_bytes_.data(), key_bytes_.size(), icp_entry_));
}
-TEST_F(AvbAftlValidateTest, AvbAftlHashLogRootDescriptor) {
- uint8_t hash[AVB_AFTL_HASH_SIZE];
-
- /* Initialize the icp_entry components used with the test. */
-
- avb_aftl_hash_log_root_descriptor(icp_entry_, hash);
- EXPECT_EQ("4f932f328f4b1c9b16500d6d09005c46abebf5c4dc761bbd1e8602378789edac",
- mem_to_hexstring(hash, AVB_AFTL_HASH_SIZE));
-}
-
-TEST_F(AvbAftlValidateTest, AvbAftlVerifyIcpRootHash) {
- /* Initialize the icp_entry components used with the test. */
+TEST_F(AvbAftlValidateTest, VerifyIcpRootHash) {
EXPECT_EQ(true, avb_aftl_verify_icp_root_hash(icp_entry_));
}
-// TODO(b/154115873): reenable this test
-TEST_F(AvbAftlValidateTest, DISABLED_AftlVerifyVbmetaHash) {
- GenerateVBMetaImage("vbmeta.img",
- "SHA256_RSA4096",
- 0,
- base::FilePath("test/data/testkey_rsa4096.pem"));
-
+TEST_F(AvbAftlValidateTest, VerifyVbmetaHash) {
+ std::string vbmeta;
+ ASSERT_TRUE(base::ReadFileToString(base::FilePath(kVBMetaPath), &vbmeta));
EXPECT_EQ(true,
avb_aftl_verify_vbmeta_hash(
- vbmeta_image_.data(), vbmeta_image_.size(), icp_entry_));
+ (uint8_t*)vbmeta.data(), vbmeta.size(), icp_entry_));
}
-TEST_F(AvbAftlValidateTest, AvbAftlRootFromIcp) {
+TEST_F(AvbAftlValidateTest, RootFromIcp) {
/* Tests from trillian root_from_icp functionality:
https://github.com/google/trillian/blob/master/merkle/log_verifier_test.go
*/
@@ -280,7 +384,7 @@
<< "Failed on test #4";
}
-TEST_F(AvbAftlValidateTest, AvbAftlChainInner) {
+TEST_F(AvbAftlValidateTest, ChainInner) {
uint8_t hash[AVB_AFTL_HASH_SIZE];
uint8_t seed[AVB_AFTL_HASH_SIZE];
uint8_t proof[4][AVB_AFTL_HASH_SIZE];
@@ -339,7 +443,7 @@
<< " and leaf_index 3";
}
-TEST_F(AvbAftlValidateTest, AvbAftlChainBorderRight) {
+TEST_F(AvbAftlValidateTest, ChainBorderRight) {
uint8_t hash[AVB_AFTL_HASH_SIZE];
uint8_t seed[AVB_AFTL_HASH_SIZE];
uint8_t proof[2][AVB_AFTL_HASH_SIZE];
@@ -369,7 +473,7 @@
"\"7890abcdefghijklmnopqrstuvwxyz12\"]";
}
-TEST_F(AvbAftlValidateTest, AvbAftlRFC6962HashChildren) {
+TEST_F(AvbAftlValidateTest, RFC6962HashChildren) {
uint8_t hash[AVB_AFTL_HASH_SIZE];
avb_aftl_rfc6962_hash_children((uint8_t*)"", 0, (uint8_t*)"", 0, hash);
@@ -394,7 +498,7 @@
<< "Failed on inputs \"abcd\" and \"efgh\"";
}
-TEST_F(AvbAftlValidateTest, AvbAftlRFC6962HashLeaf) {
+TEST_F(AvbAftlValidateTest, RFC6962HashLeaf) {
uint8_t hash[AVB_AFTL_HASH_SIZE];
avb_aftl_rfc6962_hash_leaf((uint8_t*)"", 0, hash);
EXPECT_EQ("6e340b9cffb37a989ca544e6bb780a2c78901d3fb33738768511a30617afa01d",
@@ -406,7 +510,7 @@
<< "Failed on input \"abcdefg\"";
}
-TEST_F(AvbAftlValidateTest, AvbAftlSha256) {
+TEST_F(AvbAftlValidateTest, Sha256) {
/* Computed with:
*
* $ echo -n foobar |sha256sum
diff --git a/test/avb_aftl_verify_unittest.cc b/test/avb_aftl_verify_unittest.cc
index 9f64294..1e44a4a 100644
--- a/test/avb_aftl_verify_unittest.cc
+++ b/test/avb_aftl_verify_unittest.cc
@@ -36,12 +36,15 @@
namespace {
/* Log transparency key */
-const char kAftlTestKey[] = "test/data/aftl_log_key_bytes.bin";
-/* Regular VBMeta structure without AFTL-specific data */
-const char kVbmetaBin[] = "test/data/aftl_verify_vbmeta.bin";
-/* Full vbmeta partition which contains the VBMeta above followed by its
- * associated AftlDescriptor */
-const char kVbmetaWithAftlDescBin[] = "test/data/aftl_verify_full.img";
+const char kAftlTestKey[] = "test/data/aftl_pubkey_1.bin";
+/* Full VBMeta partition which contains an AftlImage */
+/* TODO(b/154115873): These VBMetas are manually generated. We need to implement
+ * a mock in aftltool that generates an inclusion proof and call that mock from
+ * the unit tests, similarly to what is done with GenerateVBMetaImage. */
+const char kVbmetaWithAftlDescBin[] =
+ "test/data/aftl_output_vbmeta_with_1_icp.img";
+/* Size of the VBMetaImage in the partition */
+const uint64_t kVbmetaSize = 0x1100;
} /* namespace */
@@ -60,24 +63,11 @@
asv_test_data_ = NULL;
/* Read in the test data. */
- base::GetFileSize(base::FilePath(kAftlTestKey), &key_size_);
- key_bytes_ = (uint8_t*)avb_malloc(key_size_);
- ASSERT_TRUE(key_bytes_ != NULL);
- base::ReadFile(base::FilePath(kAftlTestKey), (char*)key_bytes_, key_size_);
-
- base::GetFileSize(base::FilePath(kVbmetaBin), &vbmeta_blob_size_);
- vbmeta_blob_ = (uint8_t*)avb_malloc(vbmeta_blob_size_);
- ASSERT_TRUE(vbmeta_blob_ != NULL);
- base::ReadFile(
- base::FilePath(kVbmetaBin), (char*)vbmeta_blob_, vbmeta_blob_size_);
-
- base::GetFileSize(base::FilePath(kVbmetaWithAftlDescBin),
- &vbmeta_full_blob_size_);
- vbmeta_full_blob_ = (uint8_t*)avb_malloc(vbmeta_full_blob_size_);
- ASSERT_TRUE(vbmeta_full_blob_ != NULL);
- base::ReadFile(base::FilePath(kVbmetaWithAftlDescBin),
- (char*)vbmeta_full_blob_,
- vbmeta_full_blob_size_);
+ ASSERT_TRUE(base::ReadFileToString(base::FilePath(kAftlTestKey), &key_));
+ ASSERT_TRUE(base::ReadFileToString(base::FilePath(kVbmetaWithAftlDescBin),
+ &vbmeta_icp_));
+ /* Keep a truncated version of the image without the ICP */
+ vbmeta_ = vbmeta_icp_.substr(0, kVbmetaSize);
/* Set up required parts of asv_test_data */
asv_test_data_ = (AvbSlotVerifyData*)avb_calloc(sizeof(AvbSlotVerifyData));
@@ -87,20 +77,18 @@
asv_test_data_->vbmeta_images =
(AvbVBMetaData*)avb_calloc(sizeof(AvbVBMetaData));
ASSERT_TRUE(asv_test_data_->vbmeta_images != NULL);
- asv_test_data_->vbmeta_images[0].vbmeta_size = vbmeta_blob_size_;
+ asv_test_data_->vbmeta_images[0].vbmeta_size = vbmeta_.size();
asv_test_data_->vbmeta_images[0].vbmeta_data =
- (uint8_t*)avb_calloc(vbmeta_blob_size_);
+ (uint8_t*)avb_calloc(vbmeta_.size());
ASSERT_TRUE(asv_test_data_->vbmeta_images[0].vbmeta_data != NULL);
memcpy(asv_test_data_->vbmeta_images[0].vbmeta_data,
- vbmeta_blob_,
- vbmeta_blob_size_);
- asv_test_data_->vbmeta_images[0].partition_name = (char*)"aftl_verify_full";
+ vbmeta_.data(),
+ vbmeta_.size());
+ asv_test_data_->vbmeta_images[0].partition_name =
+ (char*)"aftl_output_vbmeta_with_1_icp";
}
void TearDown() override {
- if (key_bytes_ != NULL) avb_free(key_bytes_);
- if (vbmeta_blob_ != NULL) avb_free(vbmeta_blob_);
- if (vbmeta_full_blob_ != NULL) avb_free(vbmeta_full_blob_);
if (asv_test_data_ != NULL) {
if (asv_test_data_->vbmeta_images != NULL) {
if (asv_test_data_->vbmeta_images[0].vbmeta_data != NULL) {
@@ -115,41 +103,37 @@
protected:
AvbSlotVerifyData* asv_test_data_;
- uint8_t* key_bytes_;
- int64_t key_size_;
-
- uint8_t* vbmeta_blob_;
- int64_t vbmeta_blob_size_;
- uint8_t* vbmeta_full_blob_;
- int64_t vbmeta_full_blob_size_;
+ std::string key_;
+ std::string vbmeta_;
+ std::string vbmeta_icp_;
};
TEST_F(AvbAftlVerifyTest, Basic) {
- AftlSlotVerifyResult result =
- aftl_slot_verify(ops_.avb_ops(), asv_test_data_, key_bytes_, key_size_);
+ AftlSlotVerifyResult result = aftl_slot_verify(
+ ops_.avb_ops(), asv_test_data_, (uint8_t*)key_.data(), key_.size());
EXPECT_EQ(result, AFTL_SLOT_VERIFY_RESULT_OK);
}
TEST_F(AvbAftlVerifyTest, PartitionError) {
asv_test_data_->vbmeta_images[0].partition_name = (char*)"do-no-exist";
- AftlSlotVerifyResult result =
- aftl_slot_verify(ops_.avb_ops(), asv_test_data_, key_bytes_, key_size_);
+ AftlSlotVerifyResult result = aftl_slot_verify(
+ ops_.avb_ops(), asv_test_data_, (uint8_t*)key_.data(), key_.size());
EXPECT_EQ(result, AFTL_SLOT_VERIFY_RESULT_ERROR_IMAGE_NOT_FOUND);
}
TEST_F(AvbAftlVerifyTest, MismatchingVBMeta) {
asv_test_data_->vbmeta_images[0].vbmeta_data[0] = 'X';
- AftlSlotVerifyResult result =
- aftl_slot_verify(ops_.avb_ops(), asv_test_data_, key_bytes_, key_size_);
+ AftlSlotVerifyResult result = aftl_slot_verify(
+ ops_.avb_ops(), asv_test_data_, (uint8_t*)key_.data(), key_.size());
EXPECT_EQ(result, AFTL_SLOT_VERIFY_RESULT_ERROR_VBMETA_HASH_MISMATCH);
}
TEST_F(AvbAftlVerifyTest, InvalidKey) {
// Corrupt the key in order to fail the verification: complement the last
// byte, we keep the key header valid.
- key_bytes_[key_size_ - 1] = ~key_bytes_[key_size_ - 1];
- AftlSlotVerifyResult result =
- aftl_slot_verify(ops_.avb_ops(), asv_test_data_, key_bytes_, key_size_);
+ key_[key_.size() - 1] = ~key_[key_.size() - 1];
+ AftlSlotVerifyResult result = aftl_slot_verify(
+ ops_.avb_ops(), asv_test_data_, (uint8_t*)key_.data(), key_.size());
EXPECT_EQ(result, AFTL_SLOT_VERIFY_RESULT_ERROR_INVALID_PROOF_SIGNATURE);
}
diff --git a/test/avb_slot_verify_unittest.cc b/test/avb_slot_verify_unittest.cc
index c516d24..680ea27 100644
--- a/test/avb_slot_verify_unittest.cc
+++ b/test/avb_slot_verify_unittest.cc
@@ -831,6 +831,64 @@
avb_slot_verify_data_free(slot_data);
}
+TEST_F(AvbSlotVerifyTest, SmallPreallocatedPreloadedPartitionFailGracefully) {
+ const size_t boot_partition_size = 16 * 1024 * 1024;
+ const size_t boot_image_size = 5 * 1024 * 1024;
+ // Generate vbmeta based on this boot image.
+ base::FilePath boot_path = GenerateImage("boot_a.img", boot_image_size);
+
+ // Preload smaller image than expected on the stack
+ // libavb should not attempt to free this buffer.
+ const size_t fake_preload_image_size = 1024;
+ uint8_t fake_preload_buf[fake_preload_image_size];
+
+ EXPECT_COMMAND(
+ 0,
+ "./avbtool add_hash_footer"
+ " --image %s"
+ " --rollback_index 0"
+ " --partition_name boot"
+ " --partition_size %zd"
+ " --kernel_cmdline 'cmdline in hash footer $(ANDROID_SYSTEM_PARTUUID)'"
+ " --salt deadbeef"
+ " --internal_release_string \"\"",
+ boot_path.value().c_str(),
+ boot_partition_size);
+
+ GenerateVBMetaImage(
+ "vbmeta_a.img",
+ "SHA256_RSA2048",
+ 4,
+ base::FilePath("test/data/testkey_rsa2048.pem"),
+ base::StringPrintf(
+ "--include_descriptors_from_image %s"
+ " --kernel_cmdline 'cmdline in vbmeta $(ANDROID_BOOT_PARTUUID)'"
+ " --internal_release_string \"\"",
+ boot_path.value().c_str()));
+
+ EXPECT_COMMAND(0,
+ "./avbtool erase_footer"
+ " --image %s",
+ boot_path.value().c_str());
+
+ ops_.set_expected_public_key(
+ PublicKeyAVB(base::FilePath("test/data/testkey_rsa2048.pem")));
+ ops_.enable_get_preloaded_partition();
+ EXPECT_TRUE(ops_.preload_preallocated_partition(
+ "boot_a", fake_preload_buf, fake_preload_image_size));
+
+ AvbSlotVerifyData* slot_data = NULL;
+ const char* requested_partitions[] = {"boot", NULL};
+ EXPECT_EQ(AVB_SLOT_VERIFY_RESULT_ERROR_IO,
+ avb_slot_verify(ops_.avb_ops(),
+ requested_partitions,
+ "_a",
+ AVB_SLOT_VERIFY_FLAGS_NONE,
+ AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE,
+ &slot_data));
+ EXPECT_EQ(nullptr, slot_data);
+}
+
TEST_F(AvbSlotVerifyTest, HashDescriptorInVBMetaCorruptBoot) {
size_t boot_partition_size = 16 * 1024 * 1024;
base::FilePath boot_path = GenerateImage("boot_a.img", 5 * 1024 * 1024);
diff --git a/test/avbtool_signing_helper_test.py b/test/avbtool_signing_helper_test.py
index c9bb660..aa03fcc 100755
--- a/test/avbtool_signing_helper_test.py
+++ b/test/avbtool_signing_helper_test.py
@@ -1,7 +1,7 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
#
-# Copyright (C) 2016 The Android Open Source Project
+# Copyright (C) 2016-2020 The Android Open Source Project
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation
@@ -29,35 +29,38 @@
# to catch mistakes where the standard C library is inadvertently
# used.
-import subprocess
-import sys
import errno
import os
+import subprocess
+import sys
+
def rsa_signer(argv):
if len(argv) != 3:
- sys.stderr.write("Wrong number of arguments: {} <alg> <pub key>\n".format(argv[0]))
+ sys.stderr.write('Wrong number of arguments: {} <alg> <pub key>\n'
+ .format(argv[0]))
return errno.EINVAL
- data = sys.stdin.read()
- if len(data) == 0:
- sys.stderr.write("There is not input data\n")
+ data = sys.stdin.buffer.read()
+ if not data:
+ sys.stderr.write('There is not input data\n')
return errno.EINVAL
if os.environ.get('SIGNING_HELPER_GENERATE_WRONG_SIGNATURE'):
# We're only called with this algorithm which signature size is 256.
assert sys.argv[1] == 'SHA256_RSA2048'
- sys.stdout.write('X'*256)
+ sys.stdout.buffer.write(b'X' * 256)
return 0
- if 'SIGNING_HELPER_TEST' not in os.environ or os.environ['SIGNING_HELPER_TEST'] == "":
- sys.stderr.write("env SIGNING_HELPER_TEST is not set or empty\n")
+ if not os.getenv('SIGNING_HELPER_TEST'):
+ sys.stderr.write('env SIGNING_HELPER_TEST is not set or empty\n')
return errno.EINVAL
test_file_name = os.environ['SIGNING_HELPER_TEST']
if os.path.isfile(test_file_name) and not os.access(test_file_name, os.W_OK):
- sys.stderr.write("no permission to write into {} file\n".format(test_file_name))
- return errno.EACCESS
+ sys.stderr.write('no permission to write into {} file\n'
+ .format(test_file_name))
+ return errno.EACCES
p = subprocess.Popen(
['openssl', 'rsautl', '-sign', '-inkey', argv[2], '-raw'],
@@ -68,10 +71,10 @@
if retcode != 0:
return retcode
- with open(test_file_name, "w") as f:
- f.write("DONE")
+ with open(test_file_name, 'w') as f:
+ f.write('DONE')
return 0
if __name__ == '__main__':
- sys.exit(rsa_signer(sys.argv))
+ sys.exit(rsa_signer(sys.argv))
diff --git a/test/avbtool_signing_helper_with_files_test.py b/test/avbtool_signing_helper_with_files_test.py
index 9811225..2be3e97 100755
--- a/test/avbtool_signing_helper_with_files_test.py
+++ b/test/avbtool_signing_helper_with_files_test.py
@@ -1,7 +1,7 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
#
-# Copyright (C) 2017 The Android Open Source Project
+# Copyright (C) 2017-2020 The Android Open Source Project
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation
@@ -24,37 +24,40 @@
# SOFTWARE.
#
-import subprocess
-import sys
import errno
import os
+import subprocess
+import sys
+
def rsa_signer_with_files(argv):
if len(argv) != 4:
- sys.stderr.write("Wrong number of arguments: {} <alg> <pub key> <file>\n".format(argv[0]))
+ sys.stderr.write('Wrong number of arguments: {} <alg> <pub key> <file>\n'
+ .format(argv[0]))
return errno.EINVAL
- signing_file = open(argv[3], mode='rw+')
+ signing_file = open(argv[3], mode='rb+')
data = signing_file.read()
- if len(data) == 0:
- sys.stderr.write("There is no input data\n")
+ if not data:
+ sys.stderr.write('There is no input data\n')
return errno.EINVAL
if os.environ.get('SIGNING_HELPER_GENERATE_WRONG_SIGNATURE'):
# We're only called with this algorithm which signature size is 256.
assert argv[1] == 'SHA256_RSA2048'
signing_file.seek(0)
- signing_file.write('X'*256)
+ signing_file.write(b'X' * 256)
return 0
- if 'SIGNING_HELPER_TEST' not in os.environ or os.environ['SIGNING_HELPER_TEST'] == "":
- sys.stderr.write("env SIGNING_HELPER_TEST is not set or empty\n")
+ if not os.getenv('SIGNING_HELPER_TEST'):
+ sys.stderr.write('env SIGNING_HELPER_TEST is not set or empty\n')
return errno.EINVAL
test_file_name = os.environ['SIGNING_HELPER_TEST']
if os.path.isfile(test_file_name) and not os.access(test_file_name, os.W_OK):
- sys.stderr.write("no permission to write into {} file\n".format(test_file_name))
- return errno.EACCESS
+ sys.stderr.write('no permission to write into {} file\n'
+ .format(test_file_name))
+ return errno.EACCES
p = subprocess.Popen(
['openssl', 'rsautl', '-sign', '-inkey', argv[2], '-raw'],
@@ -68,8 +71,8 @@
signing_file.seek(0)
signing_file.write(pout)
- with open(test_file_name, "w") as f:
- f.write("DONE")
+ with open(test_file_name, 'w') as f:
+ f.write('DONE')
return 0
diff --git a/test/corpus/icp.bin b/test/corpus/icp.bin
new file mode 100644
index 0000000..19125fe
--- /dev/null
+++ b/test/corpus/icp.bin
Binary files differ
diff --git a/test/data/aftl_image.bin b/test/data/aftl_image.bin
deleted file mode 100644
index 1e6e65a..0000000
--- a/test/data/aftl_image.bin
+++ /dev/null
Binary files differ
diff --git a/test/data/aftl_image_multi.bin b/test/data/aftl_image_multi.bin
deleted file mode 100644
index 9a16421..0000000
--- a/test/data/aftl_image_multi.bin
+++ /dev/null
Binary files differ
diff --git a/test/data/aftltool/aftl_input_vbmeta.img b/test/data/aftl_input_vbmeta.img
similarity index 100%
rename from test/data/aftltool/aftl_input_vbmeta.img
rename to test/data/aftl_input_vbmeta.img
Binary files differ
diff --git a/test/data/aftl_log_key_bytes.bin b/test/data/aftl_log_key_bytes.bin
deleted file mode 100644
index a4748d4..0000000
--- a/test/data/aftl_log_key_bytes.bin
+++ /dev/null
Binary files differ
diff --git a/test/data/aftl_log_sig.bin b/test/data/aftl_log_sig.bin
deleted file mode 100644
index 892040e..0000000
--- a/test/data/aftl_log_sig.bin
+++ /dev/null
Binary files differ
diff --git a/test/data/aftltool/aftl_output_vbmeta_with_1_icp.img b/test/data/aftl_output_vbmeta_with_1_icp.img
similarity index 67%
rename from test/data/aftltool/aftl_output_vbmeta_with_1_icp.img
rename to test/data/aftl_output_vbmeta_with_1_icp.img
index 25e0869..74b67bb 100644
--- a/test/data/aftltool/aftl_output_vbmeta_with_1_icp.img
+++ b/test/data/aftl_output_vbmeta_with_1_icp.img
Binary files differ
diff --git a/test/data/aftl_output_vbmeta_with_2_icp_same_log.img b/test/data/aftl_output_vbmeta_with_2_icp_same_log.img
new file mode 100644
index 0000000..2a6368e
--- /dev/null
+++ b/test/data/aftl_output_vbmeta_with_2_icp_same_log.img
Binary files differ
diff --git a/test/data/aftl_pubkey_1.bin b/test/data/aftl_pubkey_1.bin
new file mode 100644
index 0000000..5bad4be
--- /dev/null
+++ b/test/data/aftl_pubkey_1.bin
Binary files differ
diff --git a/test/data/aftltool/aftl_pubkey_1.pub b/test/data/aftl_pubkey_1.pem
similarity index 100%
rename from test/data/aftltool/aftl_pubkey_1.pub
rename to test/data/aftl_pubkey_1.pem
diff --git a/test/data/aftl_verify_full.img b/test/data/aftl_verify_full.img
deleted file mode 100644
index 6c2212e..0000000
--- a/test/data/aftl_verify_full.img
+++ /dev/null
Binary files differ
diff --git a/test/data/aftl_verify_vbmeta.bin b/test/data/aftl_verify_vbmeta.bin
deleted file mode 100644
index bde01e3..0000000
--- a/test/data/aftl_verify_vbmeta.bin
+++ /dev/null
Binary files differ
diff --git a/test/data/aftltool/aftl_output_vbmeta_with_2_icp_different_logs.img b/test/data/aftltool/aftl_output_vbmeta_with_2_icp_different_logs.img
deleted file mode 100644
index ad36580..0000000
--- a/test/data/aftltool/aftl_output_vbmeta_with_2_icp_different_logs.img
+++ /dev/null
Binary files differ
diff --git a/test/data/aftltool/aftl_output_vbmeta_with_2_icp_same_log.img b/test/data/aftltool/aftl_output_vbmeta_with_2_icp_same_log.img
deleted file mode 100644
index e53178c..0000000
--- a/test/data/aftltool/aftl_output_vbmeta_with_2_icp_same_log.img
+++ /dev/null
Binary files differ
diff --git a/test/data/aftltool/aftl_pubkey_2.pub b/test/data/aftltool/aftl_pubkey_2.pub
deleted file mode 100644
index 470fefa..0000000
--- a/test/data/aftltool/aftl_pubkey_2.pub
+++ /dev/null
@@ -1,14 +0,0 @@
------BEGIN PUBLIC KEY-----
-MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAylNLlTCf4FzlYDZIOWGf
-YQw3CusPo4bbcExfXP+0A5G94LXz02haTzlxHi3rIfiCqcUiJH1YrPWUFsD4dju+
-MKmb0lAPYSMjA5VMO3XINn5z0C+CUMq0/6rIw+n4iH/bfC3wqh0C/qqxDWM+pm5f
-duC0sk30jQ9+SMQqo/kxNY6Tzv3C1rLxDZ5lxsZ4+8IbAj7gtQFoibgwa9w2hbkZ
-dmXbyF/G8wjFPvQREC5VQik4RVPKnAB9r8ZDR9D3Myjfs/84KgMnpK7YVvsDqEcO
-4jB79t3AAVU/d6vl3hCGjTCXDZxaBzbB0PGJzDYX9cWn0tclu1WlpC7YY2YLZ8ai
-EWkMp7dXJxFGtQ7gn/RuULE+Li/H8jJkwQzVu2tb9geGDodXwNJYba4xs0CgLDjr
-L5LuiFsKhh+GBTAE/6JbQkgb97tI3ClmqhBNjvPki9sKMVL6hcUTzPHj4zxKTY8V
-yB+/1WEETcVyq1SDy0VrWPDgxXbvqkeMcMxr/8JfL6alsTCClPSlisLlhkXGrp+t
-FlkthdsD4M8BtccQHRuru3fAL8Kk5XOE7qeOcs0cDgzzmkZY1Pg4g4TpL3yiBvfi
-a3wHB2u7gF1XdLeMPNJa3v5pMwxHZzokQ8q01pC+gf/wNldY7oGWnTi5JHu/EyFV
-vWW/HX+Hd7cWppyAQFRqWwsCAwEAAQ==
------END PUBLIC KEY-----
diff --git a/test/data/aftl_key_bytes.bin b/test/data/testkey_rsa4096_pub.bin
similarity index 100%
rename from test/data/aftl_key_bytes.bin
rename to test/data/testkey_rsa4096_pub.bin
Binary files differ
diff --git a/test/data/testkey_rsa4096_pub.pem b/test/data/testkey_rsa4096_pub.pem
new file mode 100644
index 0000000..efd7144
--- /dev/null
+++ b/test/data/testkey_rsa4096_pub.pem
@@ -0,0 +1,14 @@
+-----BEGIN PUBLIC KEY-----
+MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA2ASv49OEbH4NiT3CjNMS
+VeliyfEPXswWcqtEfCxlSpS1FisAuwbvEwdTTPlkuSh6G4SYiNhnpCP5p0vcSg/3
+OhiuVKgV/rCtrDXaO60nvK/o0y83NNZRK2xaJ9eWBq9ruIDK+jC0sYWzTaqqwxY0
+Grjnx/r5CXerl5PrRK7PILzwgBHbIwxHcblt1ntgR4cWVpO3wiqasEwBDDDYk4fw
+7W6LvjBb9qav3YB8RV6PkZNeRP64ggfuecq/MXNiWOPNxLzCER2hSr/+J32h9jWj
+XsrcVy8+8Mldhmr4r2an7c247aFfupuFGtUJrpROO8/LXMl5gPfMpkqoatjTMRH5
+9gJjKhot0RpmGxZBvb33TcBK5SdJX39Y4yct5clmDlI4Fjj7FutTP+b96aJeJVnY
+eUX/A0wmogBajsJRoRX5e/RcgZsYRzXYLQXprQ81dBWjjovMJ9p8XeT6BNMFC7o6
+sklFL0fHDUE/l4BNP8G1u3BfpzevSCISRS71D4eS4oQB+RIPFBUkzomZ7rnEF3Bw
+Feq+xmwfYrP0LRaH+1YeRauuMuReke1TZl697a3mEjkNg8noa2wtpe7EWmaujJfX
+DWxJx/XEkjGLCe4z2qk3tkkY+A5gRcgzke8gVxC+eC2DJtbKYfkv4L8FMFJaEhwA
+p13MfC7FlYujO/BDLl7dANsCAwEAAQ==
+-----END PUBLIC KEY-----
diff --git a/test/fake_avb_ops.cc b/test/fake_avb_ops.cc
index 6e8ab8c..0f4db5a 100644
--- a/test/fake_avb_ops.cc
+++ b/test/fake_avb_ops.cc
@@ -87,6 +87,18 @@
return true;
}
+bool FakeAvbOps::preload_preallocated_partition(const std::string& partition,
+ uint8_t* buffer,
+ size_t size) {
+ if (preallocated_preloaded_partitions_.count(partition) > 0) {
+ fprintf(stderr, "Partition '%s' already preloaded\n", partition.c_str());
+ return false;
+ }
+
+ preallocated_preloaded_partitions_[partition] = std::make_pair(buffer, size);
+ return true;
+}
+
AvbIOResult FakeAvbOps::read_from_partition(const char* partition,
int64_t offset,
size_t num_bytes,
@@ -160,6 +172,15 @@
if (hidden_partitions_.find(partition) != hidden_partitions_.end()) {
return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
}
+
+ std::map<std::string, std::pair<uint8_t*, size_t>>::iterator prealloc_it =
+ preallocated_preloaded_partitions_.find(std::string(partition));
+ if (prealloc_it != preallocated_preloaded_partitions_.end()) {
+ *out_pointer = prealloc_it->second.first;
+ *out_num_bytes_preloaded = std::min(prealloc_it->second.second, num_bytes);
+ return AVB_IO_RESULT_OK;
+ }
+
std::map<std::string, uint8_t*>::iterator it =
preloaded_partitions_.find(std::string(partition));
if (it == preloaded_partitions_.end()) {
@@ -173,11 +194,8 @@
if (result != AVB_IO_RESULT_OK) {
return result;
}
- if (size != num_bytes) {
- return AVB_IO_RESULT_ERROR_IO;
- }
- *out_num_bytes_preloaded = num_bytes;
+ *out_num_bytes_preloaded = std::min(static_cast<size_t>(size), num_bytes);
*out_pointer = it->second;
return AVB_IO_RESULT_OK;
}
diff --git a/test/fake_avb_ops.h b/test/fake_avb_ops.h
index 2cc12d8..5dea5bd 100644
--- a/test/fake_avb_ops.h
+++ b/test/fake_avb_ops.h
@@ -211,6 +211,10 @@
bool preload_partition(const std::string& partition,
const base::FilePath& path);
+ bool preload_preallocated_partition(const std::string& partition,
+ uint8_t* buffer,
+ size_t size);
+
// Gets the partition names that were passed to the
// read_from_partition() operation.
std::set<std::string> get_partition_names_read_from();
@@ -315,6 +319,8 @@
std::set<std::string> partition_names_read_from_;
std::map<std::string, uint8_t*> preloaded_partitions_;
+ std::map<std::string, std::pair<uint8_t*, size_t>>
+ preallocated_preloaded_partitions_;
std::set<std::string> hidden_partitions_;
std::map<std::string, std::string> stored_values_;