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