1*d8f9d2afSIgor Opaniuk /*
2*d8f9d2afSIgor Opaniuk  * Copyright (C) 2016 The Android Open Source Project
3*d8f9d2afSIgor Opaniuk  *
4*d8f9d2afSIgor Opaniuk  * SPDX-License-Identifier:	MIT
5*d8f9d2afSIgor Opaniuk  */
6*d8f9d2afSIgor Opaniuk 
7*d8f9d2afSIgor Opaniuk #include "avb_vbmeta_image.h"
8*d8f9d2afSIgor Opaniuk #include "avb_crypto.h"
9*d8f9d2afSIgor Opaniuk #include "avb_rsa.h"
10*d8f9d2afSIgor Opaniuk #include "avb_sha.h"
11*d8f9d2afSIgor Opaniuk #include "avb_util.h"
12*d8f9d2afSIgor Opaniuk #include "avb_version.h"
13*d8f9d2afSIgor Opaniuk 
14*d8f9d2afSIgor Opaniuk AvbVBMetaVerifyResult avb_vbmeta_image_verify(
15*d8f9d2afSIgor Opaniuk     const uint8_t* data,
16*d8f9d2afSIgor Opaniuk     size_t length,
17*d8f9d2afSIgor Opaniuk     const uint8_t** out_public_key_data,
18*d8f9d2afSIgor Opaniuk     size_t* out_public_key_length) {
19*d8f9d2afSIgor Opaniuk   AvbVBMetaVerifyResult ret;
20*d8f9d2afSIgor Opaniuk   AvbVBMetaImageHeader h;
21*d8f9d2afSIgor Opaniuk   uint8_t* computed_hash;
22*d8f9d2afSIgor Opaniuk   const AvbAlgorithmData* algorithm;
23*d8f9d2afSIgor Opaniuk   AvbSHA256Ctx sha256_ctx;
24*d8f9d2afSIgor Opaniuk   AvbSHA512Ctx sha512_ctx;
25*d8f9d2afSIgor Opaniuk   const uint8_t* header_block;
26*d8f9d2afSIgor Opaniuk   const uint8_t* authentication_block;
27*d8f9d2afSIgor Opaniuk   const uint8_t* auxiliary_block;
28*d8f9d2afSIgor Opaniuk   int verification_result;
29*d8f9d2afSIgor Opaniuk 
30*d8f9d2afSIgor Opaniuk   ret = AVB_VBMETA_VERIFY_RESULT_INVALID_VBMETA_HEADER;
31*d8f9d2afSIgor Opaniuk 
32*d8f9d2afSIgor Opaniuk   if (out_public_key_data != NULL) {
33*d8f9d2afSIgor Opaniuk     *out_public_key_data = NULL;
34*d8f9d2afSIgor Opaniuk   }
35*d8f9d2afSIgor Opaniuk   if (out_public_key_length != NULL) {
36*d8f9d2afSIgor Opaniuk     *out_public_key_length = 0;
37*d8f9d2afSIgor Opaniuk   }
38*d8f9d2afSIgor Opaniuk 
39*d8f9d2afSIgor Opaniuk   /* Ensure magic is correct. */
40*d8f9d2afSIgor Opaniuk   if (avb_safe_memcmp(data, AVB_MAGIC, AVB_MAGIC_LEN) != 0) {
41*d8f9d2afSIgor Opaniuk     avb_error("Magic is incorrect.\n");
42*d8f9d2afSIgor Opaniuk     goto out;
43*d8f9d2afSIgor Opaniuk   }
44*d8f9d2afSIgor Opaniuk 
45*d8f9d2afSIgor Opaniuk   /* Before we byteswap, ensure length is long enough. */
46*d8f9d2afSIgor Opaniuk   if (length < sizeof(AvbVBMetaImageHeader)) {
47*d8f9d2afSIgor Opaniuk     avb_error("Length is smaller than header.\n");
48*d8f9d2afSIgor Opaniuk     goto out;
49*d8f9d2afSIgor Opaniuk   }
50*d8f9d2afSIgor Opaniuk   avb_vbmeta_image_header_to_host_byte_order((const AvbVBMetaImageHeader*)data,
51*d8f9d2afSIgor Opaniuk                                              &h);
52*d8f9d2afSIgor Opaniuk 
53*d8f9d2afSIgor Opaniuk   /* Ensure we don't attempt to access any fields if we do not meet
54*d8f9d2afSIgor Opaniuk    * the specified minimum version of libavb.
55*d8f9d2afSIgor Opaniuk    */
56*d8f9d2afSIgor Opaniuk   if ((h.required_libavb_version_major != AVB_VERSION_MAJOR) ||
57*d8f9d2afSIgor Opaniuk       (h.required_libavb_version_minor > AVB_VERSION_MINOR)) {
58*d8f9d2afSIgor Opaniuk     avb_error("Mismatch between image version and libavb version.\n");
59*d8f9d2afSIgor Opaniuk     ret = AVB_VBMETA_VERIFY_RESULT_UNSUPPORTED_VERSION;
60*d8f9d2afSIgor Opaniuk     goto out;
61*d8f9d2afSIgor Opaniuk   }
62*d8f9d2afSIgor Opaniuk 
63*d8f9d2afSIgor Opaniuk   /* Ensure |release_string| ends with a NUL byte. */
64*d8f9d2afSIgor Opaniuk   if (h.release_string[AVB_RELEASE_STRING_SIZE - 1] != '\0') {
65*d8f9d2afSIgor Opaniuk     avb_error("Release string does not end with a NUL byte.\n");
66*d8f9d2afSIgor Opaniuk     goto out;
67*d8f9d2afSIgor Opaniuk   }
68*d8f9d2afSIgor Opaniuk 
69*d8f9d2afSIgor Opaniuk   /* Ensure inner block sizes are multiple of 64. */
70*d8f9d2afSIgor Opaniuk   if ((h.authentication_data_block_size & 0x3f) != 0 ||
71*d8f9d2afSIgor Opaniuk       (h.auxiliary_data_block_size & 0x3f) != 0) {
72*d8f9d2afSIgor Opaniuk     avb_error("Block size is not a multiple of 64.\n");
73*d8f9d2afSIgor Opaniuk     goto out;
74*d8f9d2afSIgor Opaniuk   }
75*d8f9d2afSIgor Opaniuk 
76*d8f9d2afSIgor Opaniuk   /* Ensure block sizes all add up to at most |length|. */
77*d8f9d2afSIgor Opaniuk   uint64_t block_total = sizeof(AvbVBMetaImageHeader);
78*d8f9d2afSIgor Opaniuk   if (!avb_safe_add_to(&block_total, h.authentication_data_block_size) ||
79*d8f9d2afSIgor Opaniuk       !avb_safe_add_to(&block_total, h.auxiliary_data_block_size)) {
80*d8f9d2afSIgor Opaniuk     avb_error("Overflow while computing size of boot image.\n");
81*d8f9d2afSIgor Opaniuk     goto out;
82*d8f9d2afSIgor Opaniuk   }
83*d8f9d2afSIgor Opaniuk   if (block_total > length) {
84*d8f9d2afSIgor Opaniuk     avb_error("Block sizes add up to more than given length.\n");
85*d8f9d2afSIgor Opaniuk     goto out;
86*d8f9d2afSIgor Opaniuk   }
87*d8f9d2afSIgor Opaniuk 
88*d8f9d2afSIgor Opaniuk   uintptr_t data_ptr = (uintptr_t)data;
89*d8f9d2afSIgor Opaniuk   /* Ensure passed in memory doesn't wrap. */
90*d8f9d2afSIgor Opaniuk   if (!avb_safe_add(NULL, (uint64_t)data_ptr, length)) {
91*d8f9d2afSIgor Opaniuk     avb_error("Boot image location and length mismatch.\n");
92*d8f9d2afSIgor Opaniuk     goto out;
93*d8f9d2afSIgor Opaniuk   }
94*d8f9d2afSIgor Opaniuk 
95*d8f9d2afSIgor Opaniuk   /* Ensure hash and signature are entirely in the Authentication data block. */
96*d8f9d2afSIgor Opaniuk   uint64_t hash_end;
97*d8f9d2afSIgor Opaniuk   if (!avb_safe_add(&hash_end, h.hash_offset, h.hash_size) ||
98*d8f9d2afSIgor Opaniuk       hash_end > h.authentication_data_block_size) {
99*d8f9d2afSIgor Opaniuk     avb_error("Hash is not entirely in its block.\n");
100*d8f9d2afSIgor Opaniuk     goto out;
101*d8f9d2afSIgor Opaniuk   }
102*d8f9d2afSIgor Opaniuk   uint64_t signature_end;
103*d8f9d2afSIgor Opaniuk   if (!avb_safe_add(&signature_end, h.signature_offset, h.signature_size) ||
104*d8f9d2afSIgor Opaniuk       signature_end > h.authentication_data_block_size) {
105*d8f9d2afSIgor Opaniuk     avb_error("Signature is not entirely in its block.\n");
106*d8f9d2afSIgor Opaniuk     goto out;
107*d8f9d2afSIgor Opaniuk   }
108*d8f9d2afSIgor Opaniuk 
109*d8f9d2afSIgor Opaniuk   /* Ensure public key is entirely in the Auxiliary data block. */
110*d8f9d2afSIgor Opaniuk   uint64_t pubkey_end;
111*d8f9d2afSIgor Opaniuk   if (!avb_safe_add(&pubkey_end, h.public_key_offset, h.public_key_size) ||
112*d8f9d2afSIgor Opaniuk       pubkey_end > h.auxiliary_data_block_size) {
113*d8f9d2afSIgor Opaniuk     avb_error("Public key is not entirely in its block.\n");
114*d8f9d2afSIgor Opaniuk     goto out;
115*d8f9d2afSIgor Opaniuk   }
116*d8f9d2afSIgor Opaniuk 
117*d8f9d2afSIgor Opaniuk   /* Ensure public key metadata (if set) is entirely in the Auxiliary
118*d8f9d2afSIgor Opaniuk    * data block. */
119*d8f9d2afSIgor Opaniuk   if (h.public_key_metadata_size > 0) {
120*d8f9d2afSIgor Opaniuk     uint64_t pubkey_md_end;
121*d8f9d2afSIgor Opaniuk     if (!avb_safe_add(&pubkey_md_end,
122*d8f9d2afSIgor Opaniuk                       h.public_key_metadata_offset,
123*d8f9d2afSIgor Opaniuk                       h.public_key_metadata_size) ||
124*d8f9d2afSIgor Opaniuk         pubkey_md_end > h.auxiliary_data_block_size) {
125*d8f9d2afSIgor Opaniuk       avb_error("Public key metadata is not entirely in its block.\n");
126*d8f9d2afSIgor Opaniuk       goto out;
127*d8f9d2afSIgor Opaniuk     }
128*d8f9d2afSIgor Opaniuk   }
129*d8f9d2afSIgor Opaniuk 
130*d8f9d2afSIgor Opaniuk   /* Bail early if there's no hash or signature. */
131*d8f9d2afSIgor Opaniuk   if (h.algorithm_type == AVB_ALGORITHM_TYPE_NONE) {
132*d8f9d2afSIgor Opaniuk     ret = AVB_VBMETA_VERIFY_RESULT_OK_NOT_SIGNED;
133*d8f9d2afSIgor Opaniuk     goto out;
134*d8f9d2afSIgor Opaniuk   }
135*d8f9d2afSIgor Opaniuk 
136*d8f9d2afSIgor Opaniuk   /* Ensure algorithm field is supported. */
137*d8f9d2afSIgor Opaniuk   algorithm = avb_get_algorithm_data(h.algorithm_type);
138*d8f9d2afSIgor Opaniuk   if (!algorithm) {
139*d8f9d2afSIgor Opaniuk     avb_error("Invalid or unknown algorithm.\n");
140*d8f9d2afSIgor Opaniuk     goto out;
141*d8f9d2afSIgor Opaniuk   }
142*d8f9d2afSIgor Opaniuk 
143*d8f9d2afSIgor Opaniuk   /* Bail if the embedded hash size doesn't match the chosen algorithm. */
144*d8f9d2afSIgor Opaniuk   if (h.hash_size != algorithm->hash_len) {
145*d8f9d2afSIgor Opaniuk     avb_error("Embedded hash has wrong size.\n");
146*d8f9d2afSIgor Opaniuk     goto out;
147*d8f9d2afSIgor Opaniuk   }
148*d8f9d2afSIgor Opaniuk 
149*d8f9d2afSIgor Opaniuk   /* No overflow checks needed from here-on after since all block
150*d8f9d2afSIgor Opaniuk    * sizes and offsets have been verified above.
151*d8f9d2afSIgor Opaniuk    */
152*d8f9d2afSIgor Opaniuk 
153*d8f9d2afSIgor Opaniuk   header_block = data;
154*d8f9d2afSIgor Opaniuk   authentication_block = header_block + sizeof(AvbVBMetaImageHeader);
155*d8f9d2afSIgor Opaniuk   auxiliary_block = authentication_block + h.authentication_data_block_size;
156*d8f9d2afSIgor Opaniuk 
157*d8f9d2afSIgor Opaniuk   switch (h.algorithm_type) {
158*d8f9d2afSIgor Opaniuk     /* Explicit fall-through: */
159*d8f9d2afSIgor Opaniuk     case AVB_ALGORITHM_TYPE_SHA256_RSA2048:
160*d8f9d2afSIgor Opaniuk     case AVB_ALGORITHM_TYPE_SHA256_RSA4096:
161*d8f9d2afSIgor Opaniuk     case AVB_ALGORITHM_TYPE_SHA256_RSA8192:
162*d8f9d2afSIgor Opaniuk       avb_sha256_init(&sha256_ctx);
163*d8f9d2afSIgor Opaniuk       avb_sha256_update(
164*d8f9d2afSIgor Opaniuk           &sha256_ctx, header_block, sizeof(AvbVBMetaImageHeader));
165*d8f9d2afSIgor Opaniuk       avb_sha256_update(
166*d8f9d2afSIgor Opaniuk           &sha256_ctx, auxiliary_block, h.auxiliary_data_block_size);
167*d8f9d2afSIgor Opaniuk       computed_hash = avb_sha256_final(&sha256_ctx);
168*d8f9d2afSIgor Opaniuk       break;
169*d8f9d2afSIgor Opaniuk     /* Explicit fall-through: */
170*d8f9d2afSIgor Opaniuk     case AVB_ALGORITHM_TYPE_SHA512_RSA2048:
171*d8f9d2afSIgor Opaniuk     case AVB_ALGORITHM_TYPE_SHA512_RSA4096:
172*d8f9d2afSIgor Opaniuk     case AVB_ALGORITHM_TYPE_SHA512_RSA8192:
173*d8f9d2afSIgor Opaniuk       avb_sha512_init(&sha512_ctx);
174*d8f9d2afSIgor Opaniuk       avb_sha512_update(
175*d8f9d2afSIgor Opaniuk           &sha512_ctx, header_block, sizeof(AvbVBMetaImageHeader));
176*d8f9d2afSIgor Opaniuk       avb_sha512_update(
177*d8f9d2afSIgor Opaniuk           &sha512_ctx, auxiliary_block, h.auxiliary_data_block_size);
178*d8f9d2afSIgor Opaniuk       computed_hash = avb_sha512_final(&sha512_ctx);
179*d8f9d2afSIgor Opaniuk       break;
180*d8f9d2afSIgor Opaniuk     default:
181*d8f9d2afSIgor Opaniuk       avb_error("Unknown algorithm.\n");
182*d8f9d2afSIgor Opaniuk       goto out;
183*d8f9d2afSIgor Opaniuk   }
184*d8f9d2afSIgor Opaniuk 
185*d8f9d2afSIgor Opaniuk   if (avb_safe_memcmp(authentication_block + h.hash_offset,
186*d8f9d2afSIgor Opaniuk                       computed_hash,
187*d8f9d2afSIgor Opaniuk                       h.hash_size) != 0) {
188*d8f9d2afSIgor Opaniuk     avb_error("Hash does not match!\n");
189*d8f9d2afSIgor Opaniuk     ret = AVB_VBMETA_VERIFY_RESULT_HASH_MISMATCH;
190*d8f9d2afSIgor Opaniuk     goto out;
191*d8f9d2afSIgor Opaniuk   }
192*d8f9d2afSIgor Opaniuk 
193*d8f9d2afSIgor Opaniuk   verification_result =
194*d8f9d2afSIgor Opaniuk       avb_rsa_verify(auxiliary_block + h.public_key_offset,
195*d8f9d2afSIgor Opaniuk                      h.public_key_size,
196*d8f9d2afSIgor Opaniuk                      authentication_block + h.signature_offset,
197*d8f9d2afSIgor Opaniuk                      h.signature_size,
198*d8f9d2afSIgor Opaniuk                      authentication_block + h.hash_offset,
199*d8f9d2afSIgor Opaniuk                      h.hash_size,
200*d8f9d2afSIgor Opaniuk                      algorithm->padding,
201*d8f9d2afSIgor Opaniuk                      algorithm->padding_len);
202*d8f9d2afSIgor Opaniuk 
203*d8f9d2afSIgor Opaniuk   if (verification_result == 0) {
204*d8f9d2afSIgor Opaniuk     ret = AVB_VBMETA_VERIFY_RESULT_SIGNATURE_MISMATCH;
205*d8f9d2afSIgor Opaniuk     goto out;
206*d8f9d2afSIgor Opaniuk   }
207*d8f9d2afSIgor Opaniuk 
208*d8f9d2afSIgor Opaniuk   if (h.public_key_size > 0) {
209*d8f9d2afSIgor Opaniuk     if (out_public_key_data != NULL) {
210*d8f9d2afSIgor Opaniuk       *out_public_key_data = auxiliary_block + h.public_key_offset;
211*d8f9d2afSIgor Opaniuk     }
212*d8f9d2afSIgor Opaniuk     if (out_public_key_length != NULL) {
213*d8f9d2afSIgor Opaniuk       *out_public_key_length = h.public_key_size;
214*d8f9d2afSIgor Opaniuk     }
215*d8f9d2afSIgor Opaniuk   }
216*d8f9d2afSIgor Opaniuk 
217*d8f9d2afSIgor Opaniuk   ret = AVB_VBMETA_VERIFY_RESULT_OK;
218*d8f9d2afSIgor Opaniuk 
219*d8f9d2afSIgor Opaniuk out:
220*d8f9d2afSIgor Opaniuk   return ret;
221*d8f9d2afSIgor Opaniuk }
222*d8f9d2afSIgor Opaniuk 
223*d8f9d2afSIgor Opaniuk void avb_vbmeta_image_header_to_host_byte_order(const AvbVBMetaImageHeader* src,
224*d8f9d2afSIgor Opaniuk                                                 AvbVBMetaImageHeader* dest) {
225*d8f9d2afSIgor Opaniuk   avb_memcpy(dest, src, sizeof(AvbVBMetaImageHeader));
226*d8f9d2afSIgor Opaniuk 
227*d8f9d2afSIgor Opaniuk   dest->required_libavb_version_major =
228*d8f9d2afSIgor Opaniuk       avb_be32toh(dest->required_libavb_version_major);
229*d8f9d2afSIgor Opaniuk   dest->required_libavb_version_minor =
230*d8f9d2afSIgor Opaniuk       avb_be32toh(dest->required_libavb_version_minor);
231*d8f9d2afSIgor Opaniuk 
232*d8f9d2afSIgor Opaniuk   dest->authentication_data_block_size =
233*d8f9d2afSIgor Opaniuk       avb_be64toh(dest->authentication_data_block_size);
234*d8f9d2afSIgor Opaniuk   dest->auxiliary_data_block_size =
235*d8f9d2afSIgor Opaniuk       avb_be64toh(dest->auxiliary_data_block_size);
236*d8f9d2afSIgor Opaniuk 
237*d8f9d2afSIgor Opaniuk   dest->algorithm_type = avb_be32toh(dest->algorithm_type);
238*d8f9d2afSIgor Opaniuk 
239*d8f9d2afSIgor Opaniuk   dest->hash_offset = avb_be64toh(dest->hash_offset);
240*d8f9d2afSIgor Opaniuk   dest->hash_size = avb_be64toh(dest->hash_size);
241*d8f9d2afSIgor Opaniuk 
242*d8f9d2afSIgor Opaniuk   dest->signature_offset = avb_be64toh(dest->signature_offset);
243*d8f9d2afSIgor Opaniuk   dest->signature_size = avb_be64toh(dest->signature_size);
244*d8f9d2afSIgor Opaniuk 
245*d8f9d2afSIgor Opaniuk   dest->public_key_offset = avb_be64toh(dest->public_key_offset);
246*d8f9d2afSIgor Opaniuk   dest->public_key_size = avb_be64toh(dest->public_key_size);
247*d8f9d2afSIgor Opaniuk 
248*d8f9d2afSIgor Opaniuk   dest->public_key_metadata_offset =
249*d8f9d2afSIgor Opaniuk       avb_be64toh(dest->public_key_metadata_offset);
250*d8f9d2afSIgor Opaniuk   dest->public_key_metadata_size = avb_be64toh(dest->public_key_metadata_size);
251*d8f9d2afSIgor Opaniuk 
252*d8f9d2afSIgor Opaniuk   dest->descriptors_offset = avb_be64toh(dest->descriptors_offset);
253*d8f9d2afSIgor Opaniuk   dest->descriptors_size = avb_be64toh(dest->descriptors_size);
254*d8f9d2afSIgor Opaniuk 
255*d8f9d2afSIgor Opaniuk   dest->rollback_index = avb_be64toh(dest->rollback_index);
256*d8f9d2afSIgor Opaniuk   dest->flags = avb_be32toh(dest->flags);
257*d8f9d2afSIgor Opaniuk }
258*d8f9d2afSIgor Opaniuk 
259*d8f9d2afSIgor Opaniuk const char* avb_vbmeta_verify_result_to_string(AvbVBMetaVerifyResult result) {
260*d8f9d2afSIgor Opaniuk   const char* ret = NULL;
261*d8f9d2afSIgor Opaniuk 
262*d8f9d2afSIgor Opaniuk   switch (result) {
263*d8f9d2afSIgor Opaniuk     case AVB_VBMETA_VERIFY_RESULT_OK:
264*d8f9d2afSIgor Opaniuk       ret = "OK";
265*d8f9d2afSIgor Opaniuk       break;
266*d8f9d2afSIgor Opaniuk     case AVB_VBMETA_VERIFY_RESULT_OK_NOT_SIGNED:
267*d8f9d2afSIgor Opaniuk       ret = "OK_NOT_SIGNED";
268*d8f9d2afSIgor Opaniuk       break;
269*d8f9d2afSIgor Opaniuk     case AVB_VBMETA_VERIFY_RESULT_INVALID_VBMETA_HEADER:
270*d8f9d2afSIgor Opaniuk       ret = "INVALID_VBMETA_HEADER";
271*d8f9d2afSIgor Opaniuk       break;
272*d8f9d2afSIgor Opaniuk     case AVB_VBMETA_VERIFY_RESULT_UNSUPPORTED_VERSION:
273*d8f9d2afSIgor Opaniuk       ret = "UNSUPPORTED_VERSION";
274*d8f9d2afSIgor Opaniuk       break;
275*d8f9d2afSIgor Opaniuk     case AVB_VBMETA_VERIFY_RESULT_HASH_MISMATCH:
276*d8f9d2afSIgor Opaniuk       ret = "HASH_MISMATCH";
277*d8f9d2afSIgor Opaniuk       break;
278*d8f9d2afSIgor Opaniuk     case AVB_VBMETA_VERIFY_RESULT_SIGNATURE_MISMATCH:
279*d8f9d2afSIgor Opaniuk       ret = "SIGNATURE_MISMATCH";
280*d8f9d2afSIgor Opaniuk       break;
281*d8f9d2afSIgor Opaniuk       /* Do not add a 'default:' case here because of -Wswitch. */
282*d8f9d2afSIgor Opaniuk   }
283*d8f9d2afSIgor Opaniuk 
284*d8f9d2afSIgor Opaniuk   if (ret == NULL) {
285*d8f9d2afSIgor Opaniuk     avb_error("Unknown AvbVBMetaVerifyResult value.\n");
286*d8f9d2afSIgor Opaniuk     ret = "(unknown)";
287*d8f9d2afSIgor Opaniuk   }
288*d8f9d2afSIgor Opaniuk 
289*d8f9d2afSIgor Opaniuk   return ret;
290*d8f9d2afSIgor Opaniuk }
291