1*288bf522SAndroid Build Coastguard Worker /*
2*288bf522SAndroid Build Coastguard Worker * Copyright (C) 2020 The Android Open Source Project
3*288bf522SAndroid Build Coastguard Worker *
4*288bf522SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*288bf522SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*288bf522SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*288bf522SAndroid Build Coastguard Worker *
8*288bf522SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*288bf522SAndroid Build Coastguard Worker *
10*288bf522SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*288bf522SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*288bf522SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*288bf522SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*288bf522SAndroid Build Coastguard Worker * limitations under the License.
15*288bf522SAndroid Build Coastguard Worker */
16*288bf522SAndroid Build Coastguard Worker
17*288bf522SAndroid Build Coastguard Worker #include "avb_utils.h"
18*288bf522SAndroid Build Coastguard Worker
19*288bf522SAndroid Build Coastguard Worker #include <android-base/strings.h>
20*288bf522SAndroid Build Coastguard Worker #include <libavb/libavb.h>
21*288bf522SAndroid Build Coastguard Worker
22*288bf522SAndroid Build Coastguard Worker #include "fec_private.h"
23*288bf522SAndroid Build Coastguard Worker
parse_vbmeta_from_footer(fec_handle * f,std::vector<uint8_t> * vbmeta)24*288bf522SAndroid Build Coastguard Worker int parse_vbmeta_from_footer(fec_handle *f, std::vector<uint8_t> *vbmeta) {
25*288bf522SAndroid Build Coastguard Worker if (f->size <= AVB_FOOTER_SIZE) {
26*288bf522SAndroid Build Coastguard Worker debug("file size not large enough to be avb images:" PRIu64, f->size);
27*288bf522SAndroid Build Coastguard Worker return -1;
28*288bf522SAndroid Build Coastguard Worker }
29*288bf522SAndroid Build Coastguard Worker
30*288bf522SAndroid Build Coastguard Worker AvbFooter footer_read;
31*288bf522SAndroid Build Coastguard Worker if (!raw_pread(f->fd, &footer_read, AVB_FOOTER_SIZE,
32*288bf522SAndroid Build Coastguard Worker f->size - AVB_FOOTER_SIZE)) {
33*288bf522SAndroid Build Coastguard Worker error("failed to read footer: %s", strerror(errno));
34*288bf522SAndroid Build Coastguard Worker return -1;
35*288bf522SAndroid Build Coastguard Worker }
36*288bf522SAndroid Build Coastguard Worker
37*288bf522SAndroid Build Coastguard Worker AvbFooter footer;
38*288bf522SAndroid Build Coastguard Worker if (!avb_footer_validate_and_byteswap(&footer_read, &footer)) {
39*288bf522SAndroid Build Coastguard Worker debug("invalid avb footer");
40*288bf522SAndroid Build Coastguard Worker return -1;
41*288bf522SAndroid Build Coastguard Worker }
42*288bf522SAndroid Build Coastguard Worker uint64_t vbmeta_offset = footer.vbmeta_offset;
43*288bf522SAndroid Build Coastguard Worker uint64_t vbmeta_size = footer.vbmeta_size;
44*288bf522SAndroid Build Coastguard Worker check(vbmeta_offset <= f->size - sizeof(footer) - vbmeta_size);
45*288bf522SAndroid Build Coastguard Worker
46*288bf522SAndroid Build Coastguard Worker std::vector<uint8_t> vbmeta_data(vbmeta_size, 0);
47*288bf522SAndroid Build Coastguard Worker // TODO(xunchang) handle the sparse image with libsparse.
48*288bf522SAndroid Build Coastguard Worker if (!raw_pread(f->fd, vbmeta_data.data(), vbmeta_data.size(),
49*288bf522SAndroid Build Coastguard Worker vbmeta_offset)) {
50*288bf522SAndroid Build Coastguard Worker error("failed to read avb vbmeta: %s", strerror(errno));
51*288bf522SAndroid Build Coastguard Worker return -1;
52*288bf522SAndroid Build Coastguard Worker }
53*288bf522SAndroid Build Coastguard Worker
54*288bf522SAndroid Build Coastguard Worker if (auto status = avb_vbmeta_image_verify(
55*288bf522SAndroid Build Coastguard Worker vbmeta_data.data(), vbmeta_data.size(), nullptr, nullptr);
56*288bf522SAndroid Build Coastguard Worker status != AVB_VBMETA_VERIFY_RESULT_OK &&
57*288bf522SAndroid Build Coastguard Worker status != AVB_VBMETA_VERIFY_RESULT_OK_NOT_SIGNED) {
58*288bf522SAndroid Build Coastguard Worker error("failed to verify avb vbmeta, status: %d", status);
59*288bf522SAndroid Build Coastguard Worker return -1;
60*288bf522SAndroid Build Coastguard Worker }
61*288bf522SAndroid Build Coastguard Worker *vbmeta = std::move(vbmeta_data);
62*288bf522SAndroid Build Coastguard Worker return 0;
63*288bf522SAndroid Build Coastguard Worker }
64*288bf522SAndroid Build Coastguard Worker
parse_avb_image(fec_handle * f,const std::vector<uint8_t> & vbmeta)65*288bf522SAndroid Build Coastguard Worker int parse_avb_image(fec_handle *f, const std::vector<uint8_t> &vbmeta) {
66*288bf522SAndroid Build Coastguard Worker // TODO(xunchang) check if avb verification or hashtree is disabled.
67*288bf522SAndroid Build Coastguard Worker
68*288bf522SAndroid Build Coastguard Worker // Look for the hashtree descriptor, we expect exactly one descriptor in
69*288bf522SAndroid Build Coastguard Worker // vbmeta.
70*288bf522SAndroid Build Coastguard Worker // TODO(xunchang) handle the image with AvbHashDescriptor.
71*288bf522SAndroid Build Coastguard Worker auto parse_descriptor = [](const AvbDescriptor *descriptor,
72*288bf522SAndroid Build Coastguard Worker void *user_data) {
73*288bf522SAndroid Build Coastguard Worker if (descriptor &&
74*288bf522SAndroid Build Coastguard Worker avb_be64toh(descriptor->tag) == AVB_DESCRIPTOR_TAG_HASHTREE) {
75*288bf522SAndroid Build Coastguard Worker auto desp = static_cast<const AvbDescriptor **>(user_data);
76*288bf522SAndroid Build Coastguard Worker *desp = descriptor;
77*288bf522SAndroid Build Coastguard Worker return false;
78*288bf522SAndroid Build Coastguard Worker }
79*288bf522SAndroid Build Coastguard Worker return true;
80*288bf522SAndroid Build Coastguard Worker };
81*288bf522SAndroid Build Coastguard Worker
82*288bf522SAndroid Build Coastguard Worker const AvbHashtreeDescriptor *hashtree_descriptor_ptr = nullptr;
83*288bf522SAndroid Build Coastguard Worker avb_descriptor_foreach(vbmeta.data(), vbmeta.size(), parse_descriptor,
84*288bf522SAndroid Build Coastguard Worker &hashtree_descriptor_ptr);
85*288bf522SAndroid Build Coastguard Worker if (!hashtree_descriptor_ptr) {
86*288bf522SAndroid Build Coastguard Worker error("failed to find avb hashtree descriptor");
87*288bf522SAndroid Build Coastguard Worker return -1;
88*288bf522SAndroid Build Coastguard Worker }
89*288bf522SAndroid Build Coastguard Worker
90*288bf522SAndroid Build Coastguard Worker AvbHashtreeDescriptor hashtree_descriptor;
91*288bf522SAndroid Build Coastguard Worker if (!avb_hashtree_descriptor_validate_and_byteswap(hashtree_descriptor_ptr,
92*288bf522SAndroid Build Coastguard Worker &hashtree_descriptor)) {
93*288bf522SAndroid Build Coastguard Worker error("failed to verify avb hashtree descriptor");
94*288bf522SAndroid Build Coastguard Worker return -1;
95*288bf522SAndroid Build Coastguard Worker }
96*288bf522SAndroid Build Coastguard Worker
97*288bf522SAndroid Build Coastguard Worker // The partition name, salt, root append right after the hashtree
98*288bf522SAndroid Build Coastguard Worker // descriptor.
99*288bf522SAndroid Build Coastguard Worker auto read_ptr = reinterpret_cast<const uint8_t *>(hashtree_descriptor_ptr);
100*288bf522SAndroid Build Coastguard Worker // Calculate the offset with respect to the vbmeta; and check both the
101*288bf522SAndroid Build Coastguard Worker // salt & root are within the range.
102*288bf522SAndroid Build Coastguard Worker uint32_t salt_offset =
103*288bf522SAndroid Build Coastguard Worker sizeof(AvbHashtreeDescriptor) + hashtree_descriptor.partition_name_len;
104*288bf522SAndroid Build Coastguard Worker uint32_t root_offset = salt_offset + hashtree_descriptor.salt_len;
105*288bf522SAndroid Build Coastguard Worker check(hashtree_descriptor.salt_len < vbmeta.size());
106*288bf522SAndroid Build Coastguard Worker check(salt_offset < vbmeta.size() - hashtree_descriptor.salt_len);
107*288bf522SAndroid Build Coastguard Worker check(hashtree_descriptor.root_digest_len < vbmeta.size());
108*288bf522SAndroid Build Coastguard Worker check(root_offset < vbmeta.size() - hashtree_descriptor.root_digest_len);
109*288bf522SAndroid Build Coastguard Worker std::vector<uint8_t> salt(
110*288bf522SAndroid Build Coastguard Worker read_ptr + salt_offset,
111*288bf522SAndroid Build Coastguard Worker read_ptr + salt_offset + hashtree_descriptor.salt_len);
112*288bf522SAndroid Build Coastguard Worker std::vector<uint8_t> root_hash(
113*288bf522SAndroid Build Coastguard Worker read_ptr + root_offset,
114*288bf522SAndroid Build Coastguard Worker read_ptr + root_offset + hashtree_descriptor.root_digest_len);
115*288bf522SAndroid Build Coastguard Worker
116*288bf522SAndroid Build Coastguard Worker // Expect the AVB image has the format:
117*288bf522SAndroid Build Coastguard Worker // 1. hashtree
118*288bf522SAndroid Build Coastguard Worker // 2. ecc data
119*288bf522SAndroid Build Coastguard Worker // 3. vbmeta
120*288bf522SAndroid Build Coastguard Worker // 4. avb footer
121*288bf522SAndroid Build Coastguard Worker check(hashtree_descriptor.fec_offset ==
122*288bf522SAndroid Build Coastguard Worker hashtree_descriptor.tree_offset + hashtree_descriptor.tree_size);
123*288bf522SAndroid Build Coastguard Worker check(hashtree_descriptor.fec_offset <=
124*288bf522SAndroid Build Coastguard Worker f->size - hashtree_descriptor.fec_size);
125*288bf522SAndroid Build Coastguard Worker
126*288bf522SAndroid Build Coastguard Worker f->data_size = hashtree_descriptor.fec_offset;
127*288bf522SAndroid Build Coastguard Worker
128*288bf522SAndroid Build Coastguard Worker f->ecc.blocks = fec_div_round_up(f->data_size, FEC_BLOCKSIZE);
129*288bf522SAndroid Build Coastguard Worker f->ecc.rounds = fec_div_round_up(f->ecc.blocks, f->ecc.rsn);
130*288bf522SAndroid Build Coastguard Worker f->ecc.size = hashtree_descriptor.fec_size;
131*288bf522SAndroid Build Coastguard Worker f->ecc.start = hashtree_descriptor.fec_offset;
132*288bf522SAndroid Build Coastguard Worker // TODO(xunchang) verify the integrity of the ecc data.
133*288bf522SAndroid Build Coastguard Worker f->ecc.valid = true;
134*288bf522SAndroid Build Coastguard Worker
135*288bf522SAndroid Build Coastguard Worker std::string hash_algorithm =
136*288bf522SAndroid Build Coastguard Worker reinterpret_cast<char *>(hashtree_descriptor.hash_algorithm);
137*288bf522SAndroid Build Coastguard Worker int nid = -1;
138*288bf522SAndroid Build Coastguard Worker if (android::base::EqualsIgnoreCase(hash_algorithm, "sha1")) {
139*288bf522SAndroid Build Coastguard Worker nid = NID_sha1;
140*288bf522SAndroid Build Coastguard Worker } else if (android::base::EqualsIgnoreCase(hash_algorithm, "sha256")) {
141*288bf522SAndroid Build Coastguard Worker nid = NID_sha256;
142*288bf522SAndroid Build Coastguard Worker } else {
143*288bf522SAndroid Build Coastguard Worker error("unsupported hash algorithm %s", hash_algorithm.c_str());
144*288bf522SAndroid Build Coastguard Worker }
145*288bf522SAndroid Build Coastguard Worker
146*288bf522SAndroid Build Coastguard Worker hashtree_info hashtree;
147*288bf522SAndroid Build Coastguard Worker hashtree.initialize(hashtree_descriptor.tree_offset,
148*288bf522SAndroid Build Coastguard Worker hashtree_descriptor.tree_offset / FEC_BLOCKSIZE, salt,
149*288bf522SAndroid Build Coastguard Worker nid);
150*288bf522SAndroid Build Coastguard Worker if (hashtree.verify_tree(f, root_hash.data()) != 0) {
151*288bf522SAndroid Build Coastguard Worker error("failed to verify hashtree");
152*288bf522SAndroid Build Coastguard Worker return -1;
153*288bf522SAndroid Build Coastguard Worker }
154*288bf522SAndroid Build Coastguard Worker
155*288bf522SAndroid Build Coastguard Worker // We have validate the hashtree,
156*288bf522SAndroid Build Coastguard Worker f->data_size = hashtree.hash_start;
157*288bf522SAndroid Build Coastguard Worker f->avb = {
158*288bf522SAndroid Build Coastguard Worker .valid = true,
159*288bf522SAndroid Build Coastguard Worker .vbmeta = vbmeta,
160*288bf522SAndroid Build Coastguard Worker .hashtree = std::move(hashtree),
161*288bf522SAndroid Build Coastguard Worker };
162*288bf522SAndroid Build Coastguard Worker
163*288bf522SAndroid Build Coastguard Worker return 0;
164*288bf522SAndroid Build Coastguard Worker }
165