| /* |
| * Copyright 2015 The Chromium OS Authors. All rights reserved. |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| #include <errno.h> |
| #include <getopt.h> |
| #include <inttypes.h> |
| #include <stddef.h> |
| #include <stdint.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <sys/stat.h> |
| #include <sys/types.h> |
| #include <unistd.h> |
| |
| #include "2sysincludes.h" |
| #include "2common.h" |
| #include "2sha.h" |
| #include "futility.h" |
| #include "gbb_header.h" |
| |
| #define SEARCH_STRIDE 4 |
| |
| /** |
| * Check if the pointer contains the magic string. We need to use a |
| * case-swapped version, so that the actual magic string doesn't appear in the |
| * code, to avoid falsely finding it when searching for the struct. |
| */ |
| static int is_magic(const void *ptr) |
| { |
| const char magic_inv[RYU_ROOT_KEY_HASH_MAGIC_SIZE] = |
| RYU_ROOT_KEY_HASH_MAGIC_INVCASE; |
| const char *magic = ptr; |
| int i; |
| |
| for (i = 0; i < RYU_ROOT_KEY_HASH_MAGIC_SIZE; i++) { |
| if (magic[i] != (magic_inv[i] ^ 0x20)) |
| return 0; |
| } |
| |
| return 1; |
| } |
| |
| static int valid_ryu_root_header(struct vb2_ryu_root_key_hash *hash, |
| size_t size) |
| { |
| if (!is_magic(hash->magic)) |
| return 0; /* Wrong magic */ |
| |
| if (hash->header_version_major != RYU_ROOT_KEY_HASH_VERSION_MAJOR) |
| return 0; /* Version we can't parse */ |
| |
| if (hash->struct_size < EXPECTED_VB2_RYU_ROOT_KEY_HASH_SIZE) |
| return 0; /* Header too small */ |
| |
| if (hash->struct_size > size) |
| return 0; /* Claimed size doesn't fit in buffer */ |
| |
| return 1; |
| } |
| |
| /** |
| * Find the root key hash struct and return it or NULL if error. |
| */ |
| static struct vb2_ryu_root_key_hash *find_ryu_root_header(uint8_t *ptr, |
| size_t size) |
| { |
| size_t i; |
| struct vb2_ryu_root_key_hash *tmp, *hash = NULL; |
| int count = 0; |
| |
| /* Look for the ryu root key hash header */ |
| for (i = 0; i <= size - SEARCH_STRIDE; i += SEARCH_STRIDE) { |
| if (!is_magic(ptr + i)) |
| continue; |
| |
| /* Found something. See if it's any good. */ |
| tmp = (struct vb2_ryu_root_key_hash *) (ptr + i); |
| if (valid_ryu_root_header(tmp, size - i)) |
| if (!count++) |
| hash = tmp; |
| } |
| |
| switch (count) { |
| case 0: |
| return NULL; |
| case 1: |
| return hash; |
| default: |
| fprintf(stderr, |
| "WARNING: multiple ryu root hash headers found\n"); |
| /* But hey, it's only a warning. Use the first one. */ |
| return hash; |
| } |
| } |
| |
| static void calculate_root_key_hash(uint8_t *digest, size_t digest_size, |
| const GoogleBinaryBlockHeader *gbb) |
| { |
| const uint8_t *gbb_base = (const uint8_t *)gbb; |
| |
| vb2_digest_buffer(gbb_base + gbb->rootkey_offset, |
| gbb->rootkey_size, |
| VB2_HASH_SHA256, |
| digest, |
| digest_size); |
| } |
| |
| int fill_ryu_root_header(uint8_t *ptr, size_t size, |
| const GoogleBinaryBlockHeader *gbb) |
| { |
| struct vb2_ryu_root_key_hash *hash; |
| |
| /* |
| * Find the ryu root header. If not found, nothing we can do, but |
| * that's ok because most images don't have the header. |
| */ |
| hash = find_ryu_root_header(ptr, size); |
| if (!hash) |
| return 0; |
| |
| /* Update the hash stored in the header based on the root key */ |
| calculate_root_key_hash(hash->root_key_hash_digest, |
| sizeof(hash->root_key_hash_digest), |
| gbb); |
| |
| printf(" - calculate ryu root hash: success\n"); |
| return 0; |
| } |
| |
| int verify_ryu_root_header(uint8_t *ptr, size_t size, |
| const GoogleBinaryBlockHeader *gbb) |
| { |
| uint8_t digest[VB2_SHA256_DIGEST_SIZE] = {0}; |
| |
| struct vb2_ryu_root_key_hash *hash; |
| |
| /* |
| * Find the ryu root header. If not found, nothing we can do, but |
| * that's ok because most images don't have the header. |
| */ |
| hash = find_ryu_root_header(ptr, size); |
| if (!hash) { |
| printf(" - ryu root hash not found\n"); |
| return 0; |
| } |
| |
| /* Check for all 0's, which means hash hasn't been set */ |
| if (0 == memcmp(digest, hash->root_key_hash_digest, sizeof(digest))) { |
| printf(" - ryu root hash is unset\n"); |
| return 0; |
| } |
| |
| /* Update the hash stored in the header based on the root key */ |
| calculate_root_key_hash(digest, sizeof(digest), gbb); |
| |
| if (0 == memcmp(digest, hash->root_key_hash_digest, sizeof(digest))) { |
| printf(" - ryu root hash verified\n"); |
| return 0; |
| } else { |
| printf(" - ryu root hash does not verify\n"); |
| return -1; |
| } |
| } |