blob: dec65a40bc71a63a1c49f9e49b1a76557d0d7726 [file] [log] [blame]
David Zeuthen21e95262016-07-27 17:58:40 -04001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
David Zeuthenc612e2e2016-09-16 16:44:08 -04004 * Permission is hereby granted, free of charge, to any person
5 * obtaining a copy of this software and associated documentation
6 * files (the "Software"), to deal in the Software without
7 * restriction, including without limitation the rights to use, copy,
8 * modify, merge, publish, distribute, sublicense, and/or sell copies
9 * of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
David Zeuthen21e95262016-07-27 17:58:40 -040011 *
David Zeuthenc612e2e2016-09-16 16:44:08 -040012 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
David Zeuthen21e95262016-07-27 17:58:40 -040014 *
David Zeuthenc612e2e2016-09-16 16:44:08 -040015 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
David Zeuthen21e95262016-07-27 17:58:40 -040023 */
24
25#include "avb_slot_verify.h"
26#include "avb_chain_partition_descriptor.h"
27#include "avb_footer.h"
28#include "avb_hash_descriptor.h"
29#include "avb_kernel_cmdline_descriptor.h"
30#include "avb_sha.h"
31#include "avb_util.h"
32#include "avb_vbmeta_image.h"
33
34/* Maximum allow length (in bytes) of a partition name, including
35 * ab_suffix.
36 */
37#define PART_NAME_MAX_SIZE 32
38
39/* Maximum size of a vbmeta image - 64 KiB. */
40#define VBMETA_MAX_SIZE (64 * 1024)
41
42static AvbSlotVerifyResult load_and_verify_hash_partition(
43 AvbOps* ops, const char* ab_suffix, const AvbDescriptor* descriptor,
44 AvbSlotVerifyData* slot_data) {
45 AvbHashDescriptor hash_desc;
46 const uint8_t* desc_partition_name;
47 const uint8_t* desc_salt;
48 const uint8_t* desc_digest;
49 char part_name[PART_NAME_MAX_SIZE];
50 AvbSlotVerifyResult ret;
51 AvbIOResult io_ret;
52 uint8_t* image_buf = NULL;
53 size_t part_num_read;
54 uint8_t* digest;
55 size_t digest_len;
56
57 if (!avb_hash_descriptor_validate_and_byteswap(
58 (const AvbHashDescriptor*)descriptor, &hash_desc)) {
59 ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
60 goto out;
61 }
62
63 desc_partition_name =
64 ((const uint8_t*)descriptor) + sizeof(AvbHashDescriptor);
65 desc_salt = desc_partition_name + hash_desc.partition_name_len;
66 desc_digest = desc_salt + hash_desc.salt_len;
67
68 if (!avb_validate_utf8(desc_partition_name, hash_desc.partition_name_len)) {
69 avb_error("Partition name is not valid UTF-8.\n");
70 ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
71 goto out;
72 }
73
74 if (!avb_str_concat(
75 part_name, sizeof part_name, (const char*)desc_partition_name,
76 hash_desc.partition_name_len, ab_suffix, avb_strlen(ab_suffix))) {
77 avb_error("Partition name and suffix does not fit.\n");
78 ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
79 goto out;
80 }
81
82 image_buf = avb_malloc(hash_desc.image_size);
83 if (image_buf == NULL) {
84 ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
85 goto out;
86 }
87
88 io_ret =
89 ops->read_from_partition(ops, part_name, 0 /* offset */,
90 hash_desc.image_size, image_buf, &part_num_read);
David Zeuthen507752b2016-09-29 16:31:18 -040091 if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
92 ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
93 goto out;
94 } else if (io_ret != AVB_IO_RESULT_OK) {
David Zeuthen21e95262016-07-27 17:58:40 -040095 avb_errorv(part_name, ": Error loading data from partition.\n", NULL);
96 ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
97 goto out;
98 }
99 if (part_num_read != hash_desc.image_size) {
100 avb_errorv(part_name, ": Read fewer than requested bytes.\n", NULL);
101 ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
102 goto out;
103 }
104
105 if (avb_strcmp((const char*)hash_desc.hash_algorithm, "sha256") == 0) {
106 AvbSHA256Ctx sha256_ctx;
107 avb_sha256_init(&sha256_ctx);
108 avb_sha256_update(&sha256_ctx, desc_salt, hash_desc.salt_len);
109 avb_sha256_update(&sha256_ctx, image_buf, hash_desc.image_size);
110 digest = avb_sha256_final(&sha256_ctx);
111 digest_len = AVB_SHA256_DIGEST_SIZE;
112 } else if (avb_strcmp((const char*)hash_desc.hash_algorithm, "sha512") == 0) {
113 AvbSHA512Ctx sha512_ctx;
114 avb_sha512_init(&sha512_ctx);
115 avb_sha512_update(&sha512_ctx, desc_salt, hash_desc.salt_len);
116 avb_sha512_update(&sha512_ctx, image_buf, hash_desc.image_size);
117 digest = avb_sha512_final(&sha512_ctx);
118 digest_len = AVB_SHA512_DIGEST_SIZE;
119 } else {
120 avb_errorv(part_name, ": Unsupported hash algorithm.\n", NULL);
121 ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
122 goto out;
123 }
124
125 if (digest_len != hash_desc.digest_len) {
126 avb_errorv(part_name, ": Digest in descriptor not of expected size.\n",
127 NULL);
128 ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
129 goto out;
130 }
131
132 if (avb_safe_memcmp(digest, desc_digest, digest_len) != 0) {
133 avb_errorv(part_name,
134 ": Hash of data does not match digest in descriptor.\n", NULL);
135 ret = AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION;
136 goto out;
137 }
138
139 ret = AVB_SLOT_VERIFY_RESULT_OK;
140
141 /* If this is the boot partition, copy to slot_data. */
142 if (hash_desc.partition_name_len == 4 &&
143 avb_memcmp(desc_partition_name, "boot", 4) == 0) {
144 if (slot_data->boot_data != NULL) {
145 avb_free(slot_data->boot_data);
146 }
147 slot_data->boot_size = hash_desc.image_size;
148 slot_data->boot_data = image_buf;
149 image_buf = NULL;
150 }
151
152out:
153 if (image_buf != NULL) {
154 avb_free(image_buf);
155 }
156 return ret;
157}
158
159static AvbSlotVerifyResult load_and_verify_vbmeta(
160 AvbOps* ops, const char* ab_suffix, int rollback_index_slot,
161 const char* partition_name, size_t partition_name_len,
162 const uint8_t* expected_public_key, size_t expected_public_key_length,
163 AvbSlotVerifyData* slot_data, AvbAlgorithmType* out_algorithm_type) {
164 char full_partition_name[PART_NAME_MAX_SIZE];
165 AvbSlotVerifyResult ret;
166 AvbIOResult io_ret;
167 size_t vbmeta_offset;
168 size_t vbmeta_size;
169 uint8_t* vbmeta_buf = NULL;
170 size_t vbmeta_num_read;
171 AvbVBMetaVerifyResult vbmeta_ret;
172 const uint8_t* pk_data;
173 size_t pk_len;
174 AvbVBMetaImageHeader vbmeta_header;
175 uint64_t stored_rollback_index;
176 const AvbDescriptor** descriptors = NULL;
177 size_t num_descriptors;
178 size_t n;
179 int is_main_vbmeta;
180
181 avb_assert(slot_data != NULL);
182
183 is_main_vbmeta = (avb_strcmp(partition_name, "vbmeta") == 0);
184
185 if (!avb_validate_utf8((const uint8_t*)partition_name, partition_name_len)) {
186 avb_error("Partition name is not valid UTF-8.\n");
187 ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
188 goto out;
189 }
190
191 /* Construct full partition name. */
192 if (!avb_str_concat(full_partition_name, sizeof full_partition_name,
193 partition_name, partition_name_len, ab_suffix,
194 avb_strlen(ab_suffix))) {
195 avb_error("Partition name and suffix does not fit.\n");
196 ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
197 goto out;
198 }
199
200 avb_debugv("Loading vbmeta struct from partition '", full_partition_name,
201 "'.\n", NULL);
202
203 /* If we're loading from the main vbmeta partition, the vbmeta
204 * struct is in the beginning. Otherwise we have to locate it via a
205 * footer.
206 */
207 if (is_main_vbmeta) {
208 vbmeta_offset = 0;
209 vbmeta_size = VBMETA_MAX_SIZE;
210 } else {
211 uint8_t footer_buf[AVB_FOOTER_SIZE];
212 size_t footer_num_read;
213 AvbFooter footer;
214
215 io_ret =
216 ops->read_from_partition(ops, full_partition_name, -AVB_FOOTER_SIZE,
217 AVB_FOOTER_SIZE, footer_buf, &footer_num_read);
David Zeuthen507752b2016-09-29 16:31:18 -0400218 if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
219 ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
220 goto out;
221 } else if (io_ret != AVB_IO_RESULT_OK) {
David Zeuthen21e95262016-07-27 17:58:40 -0400222 avb_errorv(full_partition_name, ": Error loading footer.\n", NULL);
223 ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
224 goto out;
225 }
226 avb_assert(footer_num_read == AVB_FOOTER_SIZE);
227
228 if (!avb_footer_validate_and_byteswap((const AvbFooter*)footer_buf,
229 &footer)) {
230 avb_errorv(full_partition_name, ": Error validating footer.\n", NULL);
231 ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
232 goto out;
233 }
234
235 /* Basic footer sanity check since the data is untrusted. */
236 if (footer.vbmeta_size > VBMETA_MAX_SIZE) {
237 avb_errorv(full_partition_name, ": Invalid vbmeta size in footer.\n",
238 NULL);
239 ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
240 goto out;
241 }
242
243 vbmeta_offset = footer.vbmeta_offset;
244 vbmeta_size = footer.vbmeta_size;
245 }
246
247 vbmeta_buf = avb_malloc(vbmeta_size);
248 if (vbmeta_buf == NULL) {
249 ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
250 goto out;
251 }
252
253 io_ret = ops->read_from_partition(ops, full_partition_name, vbmeta_offset,
254 vbmeta_size, vbmeta_buf, &vbmeta_num_read);
David Zeuthen507752b2016-09-29 16:31:18 -0400255 if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
256 ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
257 goto out;
258 } else if (io_ret != AVB_IO_RESULT_OK) {
David Zeuthen21e95262016-07-27 17:58:40 -0400259 avb_errorv(full_partition_name, ": Error loading vbmeta data.\n", NULL);
260 ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
261 goto out;
262 }
263 avb_assert(vbmeta_num_read <= vbmeta_size);
264
265 /* Check if the image is properly signed and get the public key used
266 * to sign the image.
267 */
268 vbmeta_ret =
269 avb_vbmeta_image_verify(vbmeta_buf, vbmeta_num_read, &pk_data, &pk_len);
270 if (vbmeta_ret != AVB_VBMETA_VERIFY_RESULT_OK) {
271 avb_errorv(full_partition_name, ": Error verifying vbmeta image.\n", NULL);
272 ret = AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION;
273 goto out;
274 }
275
276 /* Check if key used to make signature matches what is expected. */
277 if (expected_public_key != NULL) {
278 avb_assert(!is_main_vbmeta);
279 if (expected_public_key_length != pk_len ||
280 avb_safe_memcmp(expected_public_key, pk_data, pk_len) != 0) {
281 avb_errorv(full_partition_name,
282 ": Public key used to sign data does not match key in chain "
283 "partition descriptor.\n",
284 NULL);
285 ret = AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED;
286 goto out;
287 }
288 } else {
David Zeuthen507752b2016-09-29 16:31:18 -0400289 bool key_is_trusted = false;
290
David Zeuthen21e95262016-07-27 17:58:40 -0400291 avb_assert(is_main_vbmeta);
David Zeuthen507752b2016-09-29 16:31:18 -0400292 io_ret =
293 ops->validate_vbmeta_public_key(ops, pk_data, pk_len, &key_is_trusted);
294 if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
295 ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
296 goto out;
297 } else if (io_ret != AVB_IO_RESULT_OK) {
298 avb_errorv(full_partition_name,
299 ": Error while checking public key used to sign data.\n",
300 NULL);
301 ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
302 goto out;
303 }
304 if (!key_is_trusted) {
David Zeuthen21e95262016-07-27 17:58:40 -0400305 avb_errorv(full_partition_name,
306 ": Public key used to sign data rejected.\n", NULL);
307 ret = AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED;
308 goto out;
309 }
310 }
311
312 avb_vbmeta_image_header_to_host_byte_order((AvbVBMetaImageHeader*)vbmeta_buf,
313 &vbmeta_header);
314
315 /* Check rollback index. */
David Zeuthen507752b2016-09-29 16:31:18 -0400316 io_ret = ops->read_rollback_index(ops, rollback_index_slot,
317 &stored_rollback_index);
318 if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
319 ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
320 goto out;
321 } else if (io_ret != AVB_IO_RESULT_OK) {
David Zeuthen21e95262016-07-27 17:58:40 -0400322 avb_errorv(full_partition_name,
323 ": Error getting rollback index for slot.\n", NULL);
324 ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
325 goto out;
326 }
327 if (vbmeta_header.rollback_index < stored_rollback_index) {
328 avb_errorv(
329 full_partition_name,
330 ": Image rollback index is less than the stored rollback index.\n",
331 NULL);
332 ret = AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX;
333 goto out;
334 }
335
336 /* Now go through all descriptors and take the appropriate action:
337 *
338 * - hash descriptor: Load data from partition, calculate hash, and
339 * checks that it matches what's in the hash descriptor.
340 *
341 * - hashtree descriptor: Do nothing since verification happens
342 * on-the-fly from within the OS.
343 *
344 * - chained partition descriptor: Load the footer, load the vbmeta
345 * image, verify vbmeta image (includes rollback checks, hash
346 * checks, bail on chained partitions).
347 */
348 descriptors =
349 avb_descriptor_get_all(vbmeta_buf, vbmeta_num_read, &num_descriptors);
350 for (n = 0; n < num_descriptors; n++) {
351 AvbDescriptor desc;
352
353 if (!avb_descriptor_validate_and_byteswap(descriptors[n], &desc)) {
354 avb_errorv(full_partition_name, ": Descriptor is invalid.\n", NULL);
355 ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
356 goto out;
357 }
358
359 switch (desc.tag) {
360 case AVB_DESCRIPTOR_TAG_HASH: {
361 AvbSlotVerifyResult sub_ret;
362 sub_ret = load_and_verify_hash_partition(ops, ab_suffix, descriptors[n],
363 slot_data);
364 if (sub_ret != AVB_SLOT_VERIFY_RESULT_OK) {
365 ret = sub_ret;
366 goto out;
367 }
368 } break;
369
370 case AVB_DESCRIPTOR_TAG_CHAIN_PARTITION: {
371 AvbSlotVerifyResult sub_ret;
372 AvbChainPartitionDescriptor chain_desc;
373 const uint8_t* chain_partition_name;
374 const uint8_t* chain_public_key;
375
376 /* Only allow CHAIN_PARTITION descriptors in the main vbmeta image. */
377 if (!is_main_vbmeta) {
378 avb_errorv(full_partition_name,
379 ": Encountered chain descriptor not in main image.\n",
380 NULL);
381 ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
382 goto out;
383 }
384
385 if (!avb_chain_partition_descriptor_validate_and_byteswap(
386 (AvbChainPartitionDescriptor*)descriptors[n], &chain_desc)) {
387 avb_errorv(full_partition_name,
388 ": Chain partition descriptor is invalid.\n", NULL);
389 ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
390 goto out;
391 }
392
393 chain_partition_name = ((const uint8_t*)descriptors[n]) +
394 sizeof(AvbChainPartitionDescriptor);
395 chain_public_key = chain_partition_name + chain_desc.partition_name_len;
396
397 sub_ret = load_and_verify_vbmeta(
398 ops, ab_suffix, chain_desc.rollback_index_slot,
399 (const char*)chain_partition_name, chain_desc.partition_name_len,
400 chain_public_key, chain_desc.public_key_len, slot_data,
401 NULL /* out_algorithm_type */);
402 if (sub_ret != AVB_SLOT_VERIFY_RESULT_OK) {
403 ret = sub_ret;
404 goto out;
405 }
406 } break;
407
408 case AVB_DESCRIPTOR_TAG_KERNEL_CMDLINE: {
409 const uint8_t* kernel_cmdline;
410 AvbKernelCmdlineDescriptor kernel_cmdline_desc;
411
412 if (!avb_kernel_cmdline_descriptor_validate_and_byteswap(
413 (AvbKernelCmdlineDescriptor*)descriptors[n],
414 &kernel_cmdline_desc)) {
415 avb_errorv(full_partition_name,
416 ": Kernel cmdline descriptor is invalid.\n", NULL);
417 ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
418 goto out;
419 }
420
421 kernel_cmdline = ((const uint8_t*)descriptors[n]) +
422 sizeof(AvbKernelCmdlineDescriptor);
423
424 if (!avb_validate_utf8(kernel_cmdline,
425 kernel_cmdline_desc.kernel_cmdline_length)) {
426 avb_errorv(full_partition_name,
427 ": Kernel cmdline is not valid UTF-8.\n", NULL);
428 ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
429 goto out;
430 }
431
432 if (slot_data->cmdline == NULL) {
433 slot_data->cmdline =
434 avb_calloc(kernel_cmdline_desc.kernel_cmdline_length + 1);
435 if (slot_data->cmdline == NULL) {
436 ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
437 goto out;
438 }
439 avb_memcpy(slot_data->cmdline, kernel_cmdline,
440 kernel_cmdline_desc.kernel_cmdline_length);
441 } else {
442 /* new cmdline is: <existing_cmdline> + ' ' + <newcmdline> + '\0' */
443 size_t orig_size = avb_strlen(slot_data->cmdline);
444 size_t new_size =
445 orig_size + 1 + kernel_cmdline_desc.kernel_cmdline_length + 1;
446 char* new_cmdline = avb_calloc(new_size);
447 if (new_cmdline == NULL) {
448 ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
449 goto out;
450 }
451 avb_memcpy(new_cmdline, slot_data->cmdline, orig_size);
452 new_cmdline[orig_size] = ' ';
453 avb_memcpy(new_cmdline + orig_size + 1, kernel_cmdline,
454 kernel_cmdline_desc.kernel_cmdline_length);
455 avb_free(slot_data->cmdline);
456 slot_data->cmdline = new_cmdline;
457 }
458 } break;
459
460 /* Explicit fall-through */
461 case AVB_DESCRIPTOR_TAG_PROPERTY:
462 case AVB_DESCRIPTOR_TAG_HASHTREE:
463 /* Do nothing. */
464 break;
465 }
466 }
467
468 ret = AVB_SLOT_VERIFY_RESULT_OK;
469
470 /* So far, so good. Copy needed data to user, if requested. */
471 if (is_main_vbmeta) {
472 if (slot_data->vbmeta_data != NULL) {
473 avb_free(slot_data->vbmeta_data);
474 }
475 /* Note that |vbmeta_buf| is actually |vbmeta_num_read| bytes long
476 * and this includes data past the end of the image. Pass the
477 * actual size of the vbmeta image. Also, no need to use
478 * avb_safe_add() since the header has already been verified.
479 */
480 slot_data->vbmeta_size = sizeof(AvbVBMetaImageHeader) +
481 vbmeta_header.authentication_data_block_size +
482 vbmeta_header.auxiliary_data_block_size;
483 slot_data->vbmeta_data = vbmeta_buf;
484 vbmeta_buf = NULL;
485 }
486
487 if (rollback_index_slot >= AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_SLOTS) {
488 avb_errorv(full_partition_name, ": Invalid rollback_index_slot.\n", NULL);
489 ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
490 goto out;
491 }
492
493 slot_data->rollback_indexes[rollback_index_slot] =
494 vbmeta_header.rollback_index;
495
496 if (out_algorithm_type != NULL) {
497 *out_algorithm_type = (AvbAlgorithmType)vbmeta_header.algorithm_type;
498 }
499
500out:
501 if (vbmeta_buf != NULL) {
502 avb_free(vbmeta_buf);
503 }
504 if (descriptors != NULL) {
505 avb_free(descriptors);
506 }
507 return ret;
508}
509
David Zeuthen507752b2016-09-29 16:31:18 -0400510#define NUM_GUIDS 2
511
David Zeuthen21e95262016-07-27 17:58:40 -0400512/* Substitutes all variables (e.g. $(ANDROID_SYSTEM_PARTUUID)) with
513 * values. Returns NULL on OOM, otherwise the cmdline with values
514 * replaced.
515 */
516static char* sub_cmdline(AvbOps* ops, const char* cmdline,
517 const char* ab_suffix) {
David Zeuthen21e95262016-07-27 17:58:40 -0400518 const char* part_name_str[NUM_GUIDS] = {"system", "boot"};
519 const char* replace_str[NUM_GUIDS] = {"$(ANDROID_SYSTEM_PARTUUID)",
520 "$(ANDROID_BOOT_PARTUUID)"};
521 char* ret = NULL;
David Zeuthen507752b2016-09-29 16:31:18 -0400522 AvbIOResult io_ret;
David Zeuthen21e95262016-07-27 17:58:40 -0400523
524 /* Replace unique partition GUIDs */
525 for (size_t n = 0; n < NUM_GUIDS; n++) {
526 char part_name[PART_NAME_MAX_SIZE];
527 char guid_buf[37];
528 char* new_ret;
529
530 if (!avb_str_concat(part_name, sizeof part_name, part_name_str[n],
531 avb_strlen(part_name_str[n]), ab_suffix,
532 avb_strlen(ab_suffix))) {
533 avb_error("Partition name and suffix does not fit.\n");
534 goto fail;
535 }
536
David Zeuthen507752b2016-09-29 16:31:18 -0400537 io_ret = ops->get_unique_guid_for_partition(ops, part_name, guid_buf,
538 sizeof guid_buf);
539 if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
540 return NULL;
541 } else if (io_ret != AVB_IO_RESULT_OK) {
David Zeuthen21e95262016-07-27 17:58:40 -0400542 avb_error("Error getting unique GUID for partition.\n");
543 goto fail;
544 }
545
546 if (ret == NULL) {
547 new_ret = avb_replace(cmdline, replace_str[n], guid_buf);
548 } else {
549 new_ret = avb_replace(ret, replace_str[n], guid_buf);
550 }
551 if (new_ret == NULL) {
552 goto fail;
553 }
554 ret = new_ret;
555 }
556
557 return ret;
558
559fail:
560 if (ret != NULL) {
561 avb_free(ret);
562 }
563 return NULL;
564}
565
566static int cmdline_append_option(AvbSlotVerifyData* slot_data, const char* key,
567 const char* value) {
568 size_t offset, key_len, value_len;
569 char* new_cmdline;
570
571 key_len = avb_strlen(key);
572 value_len = avb_strlen(value);
573
574 offset = 0;
575 if (slot_data->cmdline != NULL) {
576 offset = avb_strlen(slot_data->cmdline);
577 if (offset > 0) {
578 offset += 1;
579 }
580 }
581
582 new_cmdline = avb_calloc(offset + key_len + value_len + 2);
583 if (new_cmdline == NULL) {
584 return 0;
585 }
586 if (offset > 0) {
587 avb_memcpy(new_cmdline, slot_data->cmdline, offset - 1);
588 new_cmdline[offset - 1] = ' ';
589 }
590 avb_memcpy(new_cmdline + offset, key, key_len);
591 new_cmdline[offset + key_len] = '=';
592 avb_memcpy(new_cmdline + offset + key_len + 1, value, value_len);
593 if (slot_data->cmdline != NULL) {
594 avb_free(slot_data->cmdline);
595 }
596 slot_data->cmdline = new_cmdline;
597
598 return 1;
599}
600
601static int cmdline_append_uint64_base10(AvbSlotVerifyData* slot_data,
602 const char* key, uint64_t value) {
603 const int MAX_DIGITS = 32;
604 char rev_digits[MAX_DIGITS];
605 char digits[MAX_DIGITS];
606 size_t n, num_digits;
607
608 for (num_digits = 0; num_digits < MAX_DIGITS - 1;) {
609 rev_digits[num_digits++] = (value % 10) + '0';
610 value /= 10;
611 if (value == 0) {
612 break;
613 }
614 }
615
616 for (n = 0; n < num_digits; n++) {
617 digits[n] = rev_digits[num_digits - 1 - n];
618 }
619 digits[n] = '\0';
620
621 return cmdline_append_option(slot_data, key, digits);
622}
623
624static int cmdline_append_hex(AvbSlotVerifyData* slot_data, const char* key,
625 const uint8_t* data, size_t data_len) {
626 char hex_digits[17] = "0123456789abcdef";
627 char* hex_data;
628 int ret;
629 size_t n;
630
631 hex_data = avb_malloc(data_len * 2 + 1);
632 if (hex_data == NULL) return 0;
633
634 for (n = 0; n < data_len; n++) {
635 hex_data[n * 2] = hex_digits[data[n] >> 4];
636 hex_data[n * 2 + 1] = hex_digits[data[n] & 0x0f];
637 }
638 hex_data[n] = '\0';
639
640 ret = cmdline_append_option(slot_data, key, hex_data);
641 avb_free(hex_data);
642 return ret;
643}
644
645AvbSlotVerifyResult avb_slot_verify(AvbOps* ops, const char* ab_suffix,
646 AvbSlotVerifyData** out_data) {
647 AvbSlotVerifyResult ret;
648 AvbSlotVerifyData* slot_data = NULL;
649 AvbAlgorithmType algorithm_type = AVB_ALGORITHM_TYPE_NONE;
David Zeuthen507752b2016-09-29 16:31:18 -0400650 AvbIOResult io_ret;
David Zeuthen21e95262016-07-27 17:58:40 -0400651
652 if (out_data != NULL) {
653 *out_data = NULL;
654 }
655
656 slot_data = avb_calloc(sizeof(AvbSlotVerifyData));
657 if (slot_data == NULL) {
658 ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
659 goto fail;
660 }
661
662 ret = load_and_verify_vbmeta(
663 ops, ab_suffix, 0 /* rollback_index_slot */, "vbmeta",
664 avb_strlen("vbmeta"), NULL /* expected_public_key */,
665 0 /* expected_public_key_length */, slot_data, &algorithm_type);
666
667 /* If things check out, mangle the kernel command-line as needed. */
668 if (ret == AVB_SLOT_VERIFY_RESULT_OK) {
David Zeuthen8b6973b2016-09-20 12:39:49 -0400669 /* Fill in |ab_suffix| field. */
670 slot_data->ab_suffix = avb_strdup(ab_suffix);
671 if (slot_data->ab_suffix == NULL) {
672 ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
673 goto fail;
674 }
675
David Zeuthen21e95262016-07-27 17:58:40 -0400676 /* Substitute $(ANDROID_SYSTEM_PARTUUID) and friends. */
677 if (slot_data->cmdline != NULL) {
678 char* new_cmdline = sub_cmdline(ops, slot_data->cmdline, ab_suffix);
679 if (new_cmdline == NULL) {
680 ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
681 goto fail;
682 }
683 avb_free(slot_data->cmdline);
684 slot_data->cmdline = new_cmdline;
685 }
686
687 /* Add androidboot.slot_suffix, if applicable. */
688 if (avb_strlen(ab_suffix) > 0) {
689 if (!cmdline_append_option(slot_data, "androidboot.slot_suffix",
690 ab_suffix)) {
691 ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
692 goto fail;
693 }
694 }
695
696 /* Set androidboot.avb.device_state to "locked" or "unlocked". */
697 bool is_device_unlocked;
David Zeuthen507752b2016-09-29 16:31:18 -0400698 io_ret = ops->read_is_device_unlocked(ops, &is_device_unlocked);
699 if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
700 ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
701 goto fail;
702 } else if (io_ret != AVB_IO_RESULT_OK) {
David Zeuthen21e95262016-07-27 17:58:40 -0400703 avb_error("Error getting device state.\n");
704 ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
705 goto fail;
706 }
707 if (!cmdline_append_option(slot_data, "androidboot.vbmeta.device_state",
708 is_device_unlocked ? "unlocked" : "locked")) {
709 ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
710 goto fail;
711 }
712
713 /* Set androidboot.vbmeta.{hash_alg, size, digest} - use same hash
714 * function as is used to sign vbmeta.
715 */
716 switch (algorithm_type) {
717 /* Explicit fallthrough. */
718 case AVB_ALGORITHM_TYPE_NONE:
719 case AVB_ALGORITHM_TYPE_SHA256_RSA2048:
720 case AVB_ALGORITHM_TYPE_SHA256_RSA4096:
721 case AVB_ALGORITHM_TYPE_SHA256_RSA8192: {
722 AvbSHA256Ctx ctx;
723 avb_sha256_init(&ctx);
724 avb_sha256_update(&ctx, slot_data->vbmeta_data, slot_data->vbmeta_size);
725 if (!cmdline_append_option(slot_data, "androidboot.vbmeta.hash_alg",
726 "sha256") ||
727 !cmdline_append_uint64_base10(slot_data, "androidboot.vbmeta.size",
728 slot_data->vbmeta_size) ||
729 !cmdline_append_hex(slot_data, "androidboot.vbmeta.digest",
730 avb_sha256_final(&ctx),
731 AVB_SHA256_DIGEST_SIZE)) {
732 ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
733 goto fail;
734 }
735 } break;
736 /* Explicit fallthrough. */
737 case AVB_ALGORITHM_TYPE_SHA512_RSA2048:
738 case AVB_ALGORITHM_TYPE_SHA512_RSA4096:
739 case AVB_ALGORITHM_TYPE_SHA512_RSA8192: {
740 AvbSHA512Ctx ctx;
741 avb_sha512_init(&ctx);
742 avb_sha512_update(&ctx, slot_data->vbmeta_data, slot_data->vbmeta_size);
743 if (!cmdline_append_option(slot_data, "androidboot.vbmeta.hash_alg",
744 "sha512") ||
745 !cmdline_append_uint64_base10(slot_data, "androidboot.vbmeta.size",
746 slot_data->vbmeta_size) ||
747 !cmdline_append_hex(slot_data, "androidboot.vbmeta.digest",
748 avb_sha512_final(&ctx),
749 AVB_SHA512_DIGEST_SIZE)) {
750 ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
751 goto fail;
752 }
753 } break;
754 case _AVB_ALGORITHM_NUM_TYPES:
755 avb_assert_not_reached();
756 break;
757 }
758
759 if (out_data != NULL) {
760 *out_data = slot_data;
761 } else {
762 avb_slot_verify_data_free(slot_data);
763 }
764 }
765
766 return ret;
767
768fail:
769 if (slot_data != NULL) {
770 avb_slot_verify_data_free(slot_data);
771 }
772 return ret;
773}
774
775void avb_slot_verify_data_free(AvbSlotVerifyData* data) {
David Zeuthen8b6973b2016-09-20 12:39:49 -0400776 if (data->ab_suffix != NULL) {
777 avb_free(data->ab_suffix);
778 }
David Zeuthen21e95262016-07-27 17:58:40 -0400779 if (data->boot_data != NULL) {
780 avb_free(data->boot_data);
781 }
782 if (data->cmdline != NULL) {
783 avb_free(data->cmdline);
784 }
785 avb_free(data);
786}
David Zeuthen8b6973b2016-09-20 12:39:49 -0400787
788const char* avb_slot_verify_result_to_string(AvbSlotVerifyResult result) {
789 const char* ret = NULL;
790
791 switch (result) {
792 case AVB_SLOT_VERIFY_RESULT_OK:
793 ret = "OK";
794 break;
795 case AVB_SLOT_VERIFY_RESULT_ERROR_OOM:
796 ret = "ERROR_OOM";
797 break;
798 case AVB_SLOT_VERIFY_RESULT_ERROR_IO:
799 ret = "ERROR_IO";
800 break;
801 case AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION:
802 ret = "ERROR_VERIFICATION";
803 break;
804 case AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX:
805 ret = "ERROR_ROLLBACK_INDEX";
806 break;
807 case AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED:
808 ret = "ERROR_PUBLIC_KEY_REJECTED";
809 break;
810 case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA:
811 ret = "ERROR_INVALID_METADATA";
812 break;
813 /* Do not add a 'default:' case here because of -Wswitch. */
814 }
815
816 if (ret == NULL) {
817 avb_error("Unknown AvbSlotVerifyResult value.\n");
818 ret = "(unknown)";
819 }
820
821 return ret;
822}