diff options
-rw-r--r-- | Makefile | 8 | ||||
-rw-r--r-- | firmware/2lib/2hmac.c | 60 | ||||
-rw-r--r-- | firmware/2lib/2sha_utility.c | 40 | ||||
-rw-r--r-- | firmware/2lib/include/2crypto.h | 3 | ||||
-rw-r--r-- | firmware/2lib/include/2hmac.h | 29 | ||||
-rw-r--r-- | firmware/2lib/include/2sha.h | 26 | ||||
-rw-r--r-- | tests/hmac_test.c | 98 | ||||
-rw-r--r-- | tests/vb2_sha_tests.c | 28 |
8 files changed, 290 insertions, 2 deletions
@@ -356,7 +356,8 @@ FWLIB2X_SRCS = \ firmware/2lib/2sha256.c \ firmware/2lib/2sha512.c \ firmware/2lib/2sha_utility.c \ - firmware/2lib/2tpm_bootmode.c + firmware/2lib/2tpm_bootmode.c \ + firmware/2lib/2hmac.c FWLIB20_SRCS = \ firmware/lib20/api.c \ @@ -757,7 +758,8 @@ TEST2X_NAMES = \ tests/vb2_rsa_utility_tests \ tests/vb2_secdata_tests \ tests/vb2_secdatak_tests \ - tests/vb2_sha_tests + tests/vb2_sha_tests \ + tests/hmac_test TEST20_NAMES = \ tests/vb20_api_tests \ @@ -1263,6 +1265,7 @@ ${BUILD}/tests/vb20_common3_tests: LDLIBS += ${CRYPTO_LIBS} ${BUILD}/tests/verify_kernel: LDLIBS += ${CRYPTO_LIBS} ${BUILD}/tests/bdb_test: LDLIBS += ${CRYPTO_LIBS} ${BUILD}/tests/bdb_sprw_test: LDLIBS += ${CRYPTO_LIBS} +${BUILD}/tests/hmac_test: LDLIBS += ${CRYPTO_LIBS} ${TEST21_BINS}: LDLIBS += ${CRYPTO_LIBS} @@ -1464,6 +1467,7 @@ run2tests: test_setup ${RUNTEST} ${BUILD_RUN}/tests/vb21_host_keyblock_tests ${TEST_KEYS} ${RUNTEST} ${BUILD_RUN}/tests/vb21_host_misc_tests ${BUILD} ${RUNTEST} ${BUILD_RUN}/tests/vb21_host_sig_tests ${TEST_KEYS} + ${RUNTEST} ${BUILD_RUN}/tests/hmac_test .PHONY: runbdbtests runbdbtests: test_setup diff --git a/firmware/2lib/2hmac.c b/firmware/2lib/2hmac.c new file mode 100644 index 00000000..651ae57f --- /dev/null +++ b/firmware/2lib/2hmac.c @@ -0,0 +1,60 @@ +/* Copyright 2016 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 "2sysincludes.h" +#include "2sha.h" +#include "2hmac.h" + +int hmac(enum vb2_hash_algorithm alg, + const void *key, uint32_t key_size, + const void *msg, uint32_t msg_size, + uint8_t *mac, uint32_t mac_size) +{ + uint32_t block_size; + uint32_t digest_size; + uint8_t k[VB2_MAX_BLOCK_SIZE]; + uint8_t o_pad[VB2_MAX_BLOCK_SIZE]; + uint8_t i_pad[VB2_MAX_BLOCK_SIZE]; + uint8_t b[VB2_MAX_DIGEST_SIZE]; + struct vb2_digest_context dc; + int i; + + if (!key | !msg | !mac) + return -1; + + digest_size = vb2_digest_size(alg); + block_size = vb2_hash_block_size(alg); + if (!digest_size || !block_size) + return -1; + + if (mac_size < digest_size) + return -1; + + if (key_size > block_size) { + vb2_digest_buffer((uint8_t *)key, key_size, alg, k, block_size); + key_size = digest_size; + } else { + memcpy(k, key, key_size); + } + if (key_size < block_size) + memset(k + key_size, 0, block_size - key_size); + + for (i = 0; i < block_size; i++) { + o_pad[i] = 0x5c ^ k[i]; + i_pad[i] = 0x36 ^ k[i]; + } + + vb2_digest_init(&dc, alg); + vb2_digest_extend(&dc, i_pad, block_size); + vb2_digest_extend(&dc, msg, msg_size); + vb2_digest_finalize(&dc, b, digest_size); + + vb2_digest_init(&dc, alg); + vb2_digest_extend(&dc, o_pad, block_size); + vb2_digest_extend(&dc, b, digest_size); + vb2_digest_finalize(&dc, mac, mac_size); + + return 0; +} diff --git a/firmware/2lib/2sha_utility.c b/firmware/2lib/2sha_utility.c index b75f0e58..dd74f290 100644 --- a/firmware/2lib/2sha_utility.c +++ b/firmware/2lib/2sha_utility.c @@ -70,6 +70,46 @@ int vb2_digest_size(enum vb2_hash_algorithm hash_alg) } } +int vb2_hash_block_size(enum vb2_hash_algorithm alg) +{ + switch (alg) { +#if VB2_SUPPORT_SHA1 + case VB2_HASH_SHA1: + return VB2_SHA1_BLOCK_SIZE; +#endif +#if VB2_SUPPORT_SHA256 + case VB2_HASH_SHA256: + return VB2_SHA256_BLOCK_SIZE; +#endif +#if VB2_SUPPORT_SHA512 + case VB2_HASH_SHA512: + return VB2_SHA512_BLOCK_SIZE; +#endif + default: + return 0; + } +} + +const char *vb2_get_hash_algorithm_name(enum vb2_hash_algorithm alg) +{ + switch (alg) { +#if VB2_SUPPORT_SHA1 + case VB2_HASH_SHA1: + return VB2_SHA1_ALG_NAME; +#endif +#if VB2_SUPPORT_SHA256 + case VB2_HASH_SHA256: + return VB2_SHA256_ALG_NAME; +#endif +#if VB2_SUPPORT_SHA512 + case VB2_HASH_SHA512: + return VB2_SHA512_ALG_NAME; +#endif + default: + return VB2_INVALID_ALG_NAME; + } +} + int vb2_digest_init(struct vb2_digest_context *dc, enum vb2_hash_algorithm hash_alg) { diff --git a/firmware/2lib/include/2crypto.h b/firmware/2lib/include/2crypto.h index 9cc877c7..c1f225d7 100644 --- a/firmware/2lib/include/2crypto.h +++ b/firmware/2lib/include/2crypto.h @@ -57,6 +57,9 @@ enum vb2_hash_algorithm { /* SHA-256 and SHA-512 */ VB2_HASH_SHA256 = 2, VB2_HASH_SHA512 = 3, + + /* Last index. Don't add anything below. */ + VB2_HASH_ALG_COUNT, }; #endif /* VBOOT_REFERENCE_VBOOT_2CRYPTO_H_ */ diff --git a/firmware/2lib/include/2hmac.h b/firmware/2lib/include/2hmac.h new file mode 100644 index 00000000..1df19397 --- /dev/null +++ b/firmware/2lib/include/2hmac.h @@ -0,0 +1,29 @@ +/* Copyright 2016 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. + */ + +#ifndef VBOOT_REFERENCE_VBOOT_2HMAC_H_ +#define VBOOT_REFERENCE_VBOOT_2HMAC_H_ + +#include <stdint.h> +#include "2crypto.h" + +/** + * Compute HMAC + * + * @param alg Hash algorithm ID + * @param key HMAC key + * @param key_size HMAC key size + * @param msg Message to compute HMAC for + * @param msg_size Message size + * @param mac Computed message authentication code + * @param mac_size Size of the buffer pointed by <mac> + * @return + */ +int hmac(enum vb2_hash_algorithm alg, + const void *key, uint32_t key_size, + const void *msg, uint32_t msg_size, + uint8_t *mac, uint32_t mac_size); + +#endif diff --git a/firmware/2lib/include/2sha.h b/firmware/2lib/include/2sha.h index 24590244..0077f379 100644 --- a/firmware/2lib/include/2sha.h +++ b/firmware/2lib/include/2sha.h @@ -27,8 +27,15 @@ #define VB2_SUPPORT_SHA512 1 #endif +/* These are set to the biggest values among the supported hash algorithms. + * They have to be updated as we add new hash algorithms */ +#define VB2_MAX_DIGEST_SIZE VB2_SHA512_DIGEST_SIZE +#define VB2_MAX_BLOCK_SIZE VB2_SHA512_BLOCK_SIZE +#define VB2_INVALID_ALG_NAME "INVALID" + #define VB2_SHA1_DIGEST_SIZE 20 #define VB2_SHA1_BLOCK_SIZE 64 +#define VB2_SHA1_ALG_NAME "SHA1" /* Context structs for hash algorithms */ @@ -47,6 +54,7 @@ struct vb2_sha1_context { #define VB2_SHA256_DIGEST_SIZE 32 #define VB2_SHA256_BLOCK_SIZE 64 +#define VB2_SHA256_ALG_NAME "SHA256" struct vb2_sha256_context { uint32_t h[8]; @@ -57,6 +65,7 @@ struct vb2_sha256_context { #define VB2_SHA512_DIGEST_SIZE 64 #define VB2_SHA512_BLOCK_SIZE 128 +#define VB2_SHA512_ALG_NAME "SHA512" struct vb2_sha512_context { uint64_t h[8]; @@ -143,6 +152,23 @@ enum vb2_hash_algorithm vb2_crypto_to_hash(uint32_t algorithm); int vb2_digest_size(enum vb2_hash_algorithm hash_alg); /** + * Return the block size of a hash algorithm. + * + * @param hash_alg Hash algorithm + * @return The block size of the algorithm, or 0 if error. + */ +int vb2_hash_block_size(enum vb2_hash_algorithm alg); + +/** + * Return the name of a hash algorithm + * + * @param alg Hash algorithm ID + * @return String containing a hash name or VB2_INVALID_ALG_NAME + * if <alg> is invalid. + */ +const char *vb2_get_hash_algorithm_name(enum vb2_hash_algorithm alg); + +/** * Initialize a digest context for doing block-style digesting. * * @param dc Digest context diff --git a/tests/hmac_test.c b/tests/hmac_test.c new file mode 100644 index 00000000..92c52fc3 --- /dev/null +++ b/tests/hmac_test.c @@ -0,0 +1,98 @@ +/* Copyright 2016 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 <stdint.h> +#include <string.h> +#include <stdio.h> +#include <openssl/hmac.h> + +#include "2sha.h" +#include "2hmac.h" +#include "test_common.h" + +const char short_key[] = "key"; +const char message[] = "The quick brown fox jumps over the lazy dog"; +/* This is supposed to be longer than the supported block sizes */ +const char long_key[] = + "loooooooooooooooooooooooooooooooooooooooooooonooooooooooooooooooo" + "ooooooooooooooooooooooooooooooooooooooooooooonooooooooooooog key"; + +static void test_hmac_by_openssl(enum vb2_hash_algorithm alg, + const void *key, uint32_t key_size, + const void *msg, uint32_t msg_size) +{ + uint8_t mac[VB2_MAX_DIGEST_SIZE]; + uint32_t mac_size = sizeof(mac); + uint8_t md[VB2_MAX_DIGEST_SIZE]; + uint32_t md_size = sizeof(md); + char test_name[256]; + + switch (alg) { + case VB2_HASH_SHA1: + HMAC(EVP_sha1(), key, key_size, msg, msg_size, md, &md_size); + break; + case VB2_HASH_SHA256: + HMAC(EVP_sha256(), key, key_size, msg, msg_size, md, &md_size); + break; + case VB2_HASH_SHA512: + HMAC(EVP_sha512(), key, key_size, msg, msg_size, md, &md_size); + break; + default: + TEST_SUCC(-1, "Unsupported hash algorithm"); + } + sprintf(test_name, "%s: HMAC-%s (key_size=%d)", + __func__, vb2_get_hash_algorithm_name(alg), key_size); + TEST_SUCC(hmac(alg, key, key_size, msg, msg_size, mac, mac_size), + test_name); + TEST_SUCC(memcmp(mac, md, md_size), "HMAC digests match"); +} + +static void test_hmac_error(void) +{ + uint8_t mac[VB2_MAX_DIGEST_SIZE]; + enum vb2_hash_algorithm alg; + + alg = VB2_HASH_SHA1; + TEST_TRUE(hmac(alg, NULL, 0, + message, strlen(message), mac, sizeof(mac)), + "key = NULL"); + TEST_TRUE(hmac(alg, short_key, strlen(short_key), + NULL, 0, mac, sizeof(mac)), + "msg = NULL"); + TEST_TRUE(hmac(alg, short_key, strlen(short_key), + message, strlen(message), NULL, 0), + "mac = NULL"); + TEST_TRUE(hmac(alg, short_key, strlen(short_key), + message, strlen(message), mac, 0), + "Buffer too small"); + alg = -1; + TEST_TRUE(hmac(alg, short_key, strlen(short_key), + message, strlen(message), mac, sizeof(mac)), + "Invalid algorithm"); +} + +static void test_hmac(void) +{ + int alg; + + for (alg = 1; alg < VB2_HASH_ALG_COUNT; alg++) { + /* Try short key */ + test_hmac_by_openssl(alg, short_key, strlen(short_key), + message, strlen(message)); + /* Try key longer than a block size */ + test_hmac_by_openssl(alg, long_key, strlen(long_key), + message, strlen(message)); + /* Try empty key and message */ + test_hmac_by_openssl(alg, "", 0, "", 0); + } +} + +int main(void) +{ + test_hmac(); + test_hmac_error(); + + return gTestSuccess ? 0 : 255; +} diff --git a/tests/vb2_sha_tests.c b/tests/vb2_sha_tests.c index 0a85096f..c3185cac 100644 --- a/tests/vb2_sha_tests.c +++ b/tests/vb2_sha_tests.c @@ -5,6 +5,8 @@ /* FIPS 180-2 Tests for message digest functions. */ +#include <stdio.h> + #include "2sysincludes.h" #include "2rsa.h" #include "2sha.h" @@ -38,6 +40,9 @@ void sha1_tests(void) VB2_HASH_SHA1, digest, sizeof(digest) - 1), VB2_ERROR_SHA_FINALIZE_DIGEST_SIZE, "vb2_digest_buffer() too small"); + + TEST_EQ(vb2_hash_block_size(VB2_HASH_SHA1), VB2_SHA1_BLOCK_SIZE, + "vb2_hash_block_size(VB2_HASH_SHA1)"); } void sha256_tests(void) @@ -82,6 +87,9 @@ void sha256_tests(void) vb2_sha256_finalize(&ctx, digest); TEST_EQ(memcmp(digest, expect_multiple, sizeof(digest)), 0, "SHA-256 multiple extends"); + + TEST_EQ(vb2_hash_block_size(VB2_HASH_SHA256), VB2_SHA256_BLOCK_SIZE, + "vb2_hash_block_size(VB2_HASH_SHA256)"); } void sha512_tests(void) @@ -109,6 +117,9 @@ void sha512_tests(void) VB2_HASH_SHA512, digest, sizeof(digest) - 1), VB2_ERROR_SHA_FINALIZE_DIGEST_SIZE, "vb2_digest_buffer() too small"); + + TEST_EQ(vb2_hash_block_size(VB2_HASH_SHA512), VB2_SHA512_BLOCK_SIZE, + "vb2_hash_block_size(VB2_HASH_SHA512)"); } void misc_tests(void) @@ -131,6 +142,9 @@ void misc_tests(void) TEST_EQ(vb2_digest_size(VB2_HASH_INVALID), 0, "digest size invalid alg"); + TEST_EQ(vb2_hash_block_size(VB2_HASH_INVALID), 0, + "vb2_hash_block_size(VB2_HASH_INVALID)"); + TEST_EQ(vb2_digest_buffer((uint8_t *)oneblock_msg, strlen(oneblock_msg), VB2_HASH_INVALID, digest, sizeof(digest)), VB2_ERROR_SHA_INIT_ALGORITHM, @@ -147,6 +161,19 @@ void misc_tests(void) "vb2_digest_finalize() invalid alg"); } +static void hash_algorithm_name_tests(void) +{ + enum vb2_hash_algorithm alg; + char test_name[256]; + + for (alg = 1; alg < VB2_HASH_ALG_COUNT; alg++) { + sprintf(test_name, "%s: %s (alg=%d)", + __func__, vb2_get_hash_algorithm_name(alg), alg); + TEST_STR_NEQ(vb2_get_hash_algorithm_name(alg), + VB2_INVALID_ALG_NAME, test_name); + } +} + int main(int argc, char *argv[]) { /* Initialize long_msg with 'a' x 1,000,000 */ @@ -158,6 +185,7 @@ int main(int argc, char *argv[]) sha256_tests(); sha512_tests(); misc_tests(); + hash_algorithm_name_tests(); free(long_msg); |