| /* Copyright (c) 2014 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. |
| * |
| * Common functions between firmware and kernel verified boot. |
| */ |
| |
| #ifndef VBOOT_REFERENCE_2COMMON_H_ |
| #define VBOOT_REFERENCE_2COMMON_H_ |
| |
| #include "2api.h" |
| #include "2gbb.h" |
| #include "2return_codes.h" |
| #include "2sha.h" |
| #include "2struct.h" |
| #include "2sysincludes.h" |
| |
| struct vb2_public_key; |
| |
| /* Time conversion constants. */ |
| #define VB2_USEC_PER_MSEC 1000ULL |
| #define VB2_MSEC_PER_SEC 1000ULL |
| |
| /* |
| * Return the min/max of A and B. This is used in macros which calculate the |
| * required buffer size, so can't be turned into a static inline function. |
| */ |
| #define VB2_MIN(a, b) ({ \ |
| typeof(a) __vb2_min_a = (a); \ |
| typeof(b) __vb2_min_b = (b); \ |
| __vb2_min_a < __vb2_min_b ? __vb2_min_a : __vb2_min_b; \ |
| }) |
| #define VB2_MAX(a, b) ({ \ |
| typeof(a) __vb2_max_a = (a); \ |
| typeof(b) __vb2_max_b = (b); \ |
| __vb2_max_a > __vb2_max_b ? __vb2_max_a : __vb2_max_b; \ |
| }) |
| |
| /* Return the number of elements in an array */ |
| #ifndef ARRAY_SIZE |
| #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) |
| #endif |
| |
| /* Platform-dependent debug/assert output macros. */ |
| #define VB2_DEBUG(format, args...) \ |
| vb2ex_printf(__func__, format, ## args) |
| |
| #define VB2_DEBUG_RAW(format, args...) \ |
| vb2ex_printf(NULL, format, ## args) |
| |
| #define VB2_ASSERT(expr) do { \ |
| if (!(expr)) { \ |
| VB2_DEBUG("assertion failed: %s at %s:%d\n", \ |
| #expr, __FILE__, __LINE__); \ |
| vb2ex_abort(); \ |
| for (;;); \ |
| } \ |
| } while (0) |
| |
| #define VB2_DIE(format, args...) do { \ |
| VB2_DEBUG(format, ## args); \ |
| vb2ex_abort(); \ |
| for (;;); \ |
| } while (0) |
| |
| #define VB2_REC_OR_DIE(ctx, format, args...) do { \ |
| VB2_DEBUG(format, ## args); \ |
| if (!(ctx->flags & VB2_CONTEXT_RECOVERY_MODE)) { \ |
| vb2ex_abort(); \ |
| for (;;); \ |
| } \ |
| VB2_DEBUG("IGNORING ABORT IN RECOVERY MODE!!!\n"); \ |
| } while (0) |
| |
| /* |
| * Define test_mockable and for mocking functions when compiled for Chrome OS |
| * environment (that is, not for firmware). |
| */ |
| #ifndef test_mockable |
| #ifdef CHROMEOS_ENVIRONMENT |
| #define test_mockable __attribute__((weak)) |
| #else |
| #define test_mockable |
| #endif |
| #endif |
| |
| #if (defined(__GNUC__) && __GNUC__ >= 7) |
| #define VBOOT_FALLTHROUGH __attribute__((fallthrough)) |
| #elif defined(__clang__) |
| #if __has_attribute(fallthrough) |
| #define VBOOT_FALLTHROUGH __attribute__((fallthrough)) |
| #endif |
| #else |
| #define VBOOT_FALLTHROUGH ((void)0) |
| #endif |
| |
| /** |
| * Round up a number to a multiple of VB2_WORKBUF_ALIGN |
| * |
| * @param v Number to round up |
| * @return The number, rounded up. |
| */ |
| static inline uint32_t vb2_wb_round_up(uint32_t v) |
| { |
| return (v + VB2_WORKBUF_ALIGN - 1) & ~(VB2_WORKBUF_ALIGN - 1); |
| } |
| |
| /* Work buffer */ |
| struct vb2_workbuf { |
| uint8_t *buf; |
| uint32_t size; |
| }; |
| |
| /** |
| * Initialize a work buffer. |
| * |
| * @param wb Work buffer to init |
| * @param buf Pointer to work buffer data |
| * @param size Size of work buffer data in bytes |
| */ |
| void vb2_workbuf_init(struct vb2_workbuf *wb, uint8_t *buf, uint32_t size); |
| |
| /** |
| * Allocate space in a work buffer. |
| * |
| * Note that the returned buffer will always be aligned to VB2_WORKBUF_ALIGN. |
| * |
| * The work buffer acts like a stack, and detailed tracking of allocs and frees |
| * is not done. The caller must track the size of each allocation and free via |
| * vb2_workbuf_free() in the reverse order they were allocated. |
| * |
| * An acceptable alternate workflow inside a function is to pass in a const |
| * work buffer, then make a local copy. Allocations done to the local copy |
| * then don't change the passed-in work buffer, and will effectively be freed |
| * when the local copy goes out of scope. |
| * |
| * @param wb Work buffer |
| * @param size Requested size in bytes |
| * @return A pointer to the allocated space, or NULL if error. |
| */ |
| void *vb2_workbuf_alloc(struct vb2_workbuf *wb, uint32_t size); |
| |
| /** |
| * Reallocate space in a work buffer. |
| * |
| * Note that the returned buffer will always be aligned to VB2_WORKBUF_ALIGN. |
| * The work buffer acts like a stack, so this must only be done to the most |
| * recently allocated buffer. |
| * |
| * @param wb Work buffer |
| * @param oldsize Old allocation size in bytes |
| * @param newsize Requested size in bytes |
| * @return A pointer to the allocated space, or NULL if error. |
| */ |
| void *vb2_workbuf_realloc(struct vb2_workbuf *wb, uint32_t oldsize, |
| uint32_t newsize); |
| |
| /** |
| * Free the preceding allocation. |
| * |
| * Note that the work buffer acts like a stack, and detailed tracking of |
| * allocs and frees is not done. The caller must track the size of each |
| * allocation and free them in reverse order. |
| * |
| * @param wb Work buffer |
| * @param size Size of data to free |
| */ |
| void vb2_workbuf_free(struct vb2_workbuf *wb, uint32_t size); |
| |
| /* Check if a pointer is aligned on an align-byte boundary */ |
| #define vb2_aligned(ptr, align) (!(((uintptr_t)(ptr)) & ((align) - 1))) |
| |
| /** |
| * Safer memcmp() for use in crypto. |
| * |
| * Compares the buffers to see if they are equal. Time taken to perform |
| * the comparison is dependent only on the size, not the relationship of |
| * the match between the buffers. Note that unlike memcmp(), this only |
| * indicates inequality, not which buffer is lesser. |
| * |
| * @param s1 First buffer |
| * @param s2 Second buffer |
| * @param size Number of bytes to compare |
| * @return 0 if match or size=0, non-zero if at least one byte mismatched. |
| */ |
| vb2_error_t vb2_safe_memcmp(const void *s1, const void *s2, size_t size); |
| |
| /** |
| * Align a buffer and check its size. |
| * |
| * @param **ptr Pointer to pointer to align |
| * @param *size Points to size of buffer pointed to by *ptr |
| * @param align Required alignment (must be power of 2) |
| * @param want_size Required size |
| * @return VB2_SUCCESS, or non-zero if error. |
| */ |
| vb2_error_t vb2_align(uint8_t **ptr, uint32_t *size, uint32_t align, |
| uint32_t want_size); |
| |
| /** |
| * Return offset of ptr from base. |
| * |
| * @param base Base pointer |
| * @param ptr Pointer at some offset from base |
| * @return The offset of ptr from base. |
| */ |
| ptrdiff_t vb2_offset_of(const void *base, const void *ptr); |
| |
| /** |
| * Return member of given object. |
| * |
| * @param parent Pointer to parent object |
| * @param offset Offset from base |
| * @return Pointer to child object. |
| */ |
| void *vb2_member_of(void *parent, ptrdiff_t offset); |
| |
| /** |
| * Return expected signature size for a signature/hash algorithm pair |
| * |
| * @param sig_alg Signature algorithm |
| * @param hash_alg Hash algorithm |
| * @return The signature size, or zero if error / unsupported algorithm. |
| */ |
| uint32_t vb2_sig_size(enum vb2_signature_algorithm sig_alg, |
| enum vb2_hash_algorithm hash_alg); |
| |
| /** |
| * Return a key ID for an unsigned hash algorithm. |
| * |
| * @param hash_alg Hash algorithm to return key for |
| * @return A pointer to the key ID for that hash algorithm with |
| * sig_alg=VB2_SIG_NONE, or NULL if error. |
| */ |
| const struct vb2_id *vb2_hash_id(enum vb2_hash_algorithm hash_alg); |
| |
| /* Size of work buffer sufficient for vb2_verify_digest() worst case. */ |
| #define VB2_VERIFY_DIGEST_WORKBUF_BYTES VB2_VERIFY_RSA_DIGEST_WORKBUF_BYTES |
| |
| /* Size of work buffer sufficient for vb2_verify_data() worst case. */ |
| #define VB2_VERIFY_DATA_WORKBUF_BYTES \ |
| (VB2_SHA512_DIGEST_SIZE + \ |
| VB2_MAX(VB2_VERIFY_DIGEST_WORKBUF_BYTES, \ |
| sizeof(struct vb2_digest_context))) |
| |
| /* Size of work buffer sufficient for vb2_verify_keyblock() worst case. */ |
| #define VB2_KEYBLOCK_VERIFY_WORKBUF_BYTES VB2_VERIFY_DATA_WORKBUF_BYTES |
| |
| /* Size of work buffer sufficient for vb2_verify_fw_preamble() worst case. */ |
| #define VB2_VERIFY_FIRMWARE_PREAMBLE_WORKBUF_BYTES VB2_VERIFY_DATA_WORKBUF_BYTES |
| |
| /* |
| * Size of work buffer sufficient for vb2_verify_kernel_preamble() worst |
| * case. |
| */ |
| #define VB2_VERIFY_KERNEL_PREAMBLE_WORKBUF_BYTES VB2_VERIFY_DATA_WORKBUF_BYTES |
| |
| /** |
| * Verify the data pointed to by a subfield is inside the parent data. |
| * |
| * The subfield has a header pointed to by member, and a separate data |
| * field at an offset relative to the header. That is: |
| * |
| * struct parent { |
| * (possibly other parent fields) |
| * struct member { |
| * (member header fields) |
| * }; |
| * (possibly other parent fields) |
| * }; |
| * (possibly some other parent data) |
| * (member data) |
| * (possibly some other parent data) |
| * |
| * @param parent Parent data |
| * @param parent_size Parent size in bytes |
| * @param member Subfield header |
| * @param member_size Size of subfield header in bytes |
| * @param member_data_offset Offset of member data from start of member |
| * @param member_data_size Size of member data in bytes |
| * @return VB2_SUCCESS, or non-zero if error. |
| */ |
| vb2_error_t vb2_verify_member_inside(const void *parent, size_t parent_size, |
| const void *member, size_t member_size, |
| ptrdiff_t member_data_offset, |
| size_t member_data_size); |
| |
| /* |
| * Helper function to get data pointed to by a public key. |
| */ |
| static inline uint8_t *vb2_packed_key_data_mutable( |
| struct vb2_packed_key *key) |
| { |
| return (uint8_t *)key + key->key_offset; |
| } |
| |
| static inline const uint8_t *vb2_packed_key_data( |
| const struct vb2_packed_key *key) |
| { |
| return (const uint8_t *)key + key->key_offset; |
| } |
| |
| /** |
| * Verify a packed key is fully contained in its parent data |
| * |
| * @param parent Parent data |
| * @param parent_size Parent size in bytes |
| * @param key Packed key pointer |
| * @return VB2_SUCCESS, or non-zero if error. |
| */ |
| static inline vb2_error_t vb2_verify_packed_key_inside( |
| const void *parent, |
| uint32_t parent_size, |
| const struct vb2_packed_key *key) |
| { |
| return vb2_verify_member_inside(parent, parent_size, |
| key, sizeof(*key), |
| key->key_offset, key->key_size); |
| } |
| |
| /* |
| * Helper functions to get data pointed to by a public key or signature. |
| */ |
| static inline uint8_t *vb2_signature_data_mutable( |
| struct vb2_signature *sig) |
| { |
| return (uint8_t *)sig + sig->sig_offset; |
| } |
| |
| static inline const uint8_t *vb2_signature_data( |
| const struct vb2_signature *sig) |
| { |
| return (const uint8_t *)sig + sig->sig_offset; |
| } |
| |
| /** |
| * Verify a signature is fully contained in its parent data |
| * |
| * @param parent Parent data |
| * @param parent_size Parent size in bytes |
| * @param sig Signature pointer |
| * @return VB2_SUCCESS, or non-zero if error. |
| */ |
| static inline vb2_error_t vb2_verify_signature_inside( |
| const void *parent, |
| uint32_t parent_size, |
| const struct vb2_signature *sig) |
| { |
| return vb2_verify_member_inside(parent, parent_size, |
| sig, sizeof(*sig), |
| sig->sig_offset, sig->sig_size); |
| } |
| |
| /** |
| * Verify a signature against an expected hash digest. |
| * |
| * @param key Key to use in signature verification |
| * @param sig Signature to verify (may be destroyed in process) |
| * @param digest Digest of signed data |
| * @param wb Work buffer |
| * @return VB2_SUCCESS, or non-zero if error. |
| */ |
| vb2_error_t vb2_verify_digest(const struct vb2_public_key *key, |
| struct vb2_signature *sig, const uint8_t *digest, |
| const struct vb2_workbuf *wb); |
| |
| /** |
| * Verify data matches signature. |
| * |
| * @param data Data to verify |
| * @param size Size of data buffer. Note that amount of data to |
| * actually validate is contained in sig->data_size. |
| * @param sig Signature of data (destroyed in process) |
| * @param key Key to use to validate signature |
| * @param wb Work buffer |
| * @return VB2_SUCCESS, or non-zero error code if error. |
| */ |
| vb2_error_t vb2_verify_data(const uint8_t *data, uint32_t size, |
| struct vb2_signature *sig, |
| const struct vb2_public_key *key, |
| const struct vb2_workbuf *wb); |
| |
| /** |
| * Check the validity of a keyblock structure. |
| * |
| * Verifies all the header fields. Does not verify key index or keyblock |
| * flags. Should be called before verifying the keyblock data itself using |
| * the key. (This function does not itself verify the signature - just that |
| * the right amount of data is claimed to be signed.) |
| * |
| * @param block Keyblock to verify |
| * @param size Size of keyblock buffer |
| * @param sig Which signature inside the keyblock to use |
| */ |
| vb2_error_t vb2_check_keyblock(const struct vb2_keyblock *block, uint32_t size, |
| const struct vb2_signature *sig); |
| |
| /** |
| * Verify a keyblock using a public key. |
| * |
| * Header fields are also checked for validity. Does not verify key index or key |
| * block flags. Signature inside block is destroyed during check. |
| * |
| * @param block Keyblock to verify |
| * @param size Size of keyblock buffer |
| * @param key Key to use to verify block |
| * @param wb Work buffer |
| * @return VB2_SUCCESS, or non-zero error code if error. |
| */ |
| vb2_error_t vb2_verify_keyblock(struct vb2_keyblock *block, uint32_t size, |
| const struct vb2_public_key *key, |
| const struct vb2_workbuf *wb); |
| |
| /** |
| * Check the validity of a firmware preamble using a public key. |
| * |
| * The signature in the preamble is destroyed during the check. |
| * |
| * @param preamble Preamble to verify |
| * @param size Size of preamble buffer |
| * @param key Key to use to verify preamble |
| * @param wb Work buffer |
| * @return VB2_SUCCESS, or non-zero error code if error. |
| */ |
| vb2_error_t vb2_verify_fw_preamble(struct vb2_fw_preamble *preamble, |
| uint32_t size, |
| const struct vb2_public_key *key, |
| const struct vb2_workbuf *wb); |
| |
| #endif /* VBOOT_REFERENCE_2COMMON_H_ */ |