/* 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 #include #include #include #include #include #include #include #include #include #include #include "2sysincludes.h" #include "2common.h" #include "2sha.h" #include "futility.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 struct vb2_gbb_header *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 struct vb2_gbb_header *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 struct vb2_gbb_header *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; } }