summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--firmware/2lib/2sha_utility.c19
-rw-r--r--firmware/2lib/include/2return_codes.h3
-rw-r--r--firmware/2lib/include/2sha.h64
-rw-r--r--tests/vb2_sha_api_tests.c115
5 files changed, 199 insertions, 4 deletions
diff --git a/Makefile b/Makefile
index 28b6460b..c71f5e32 100644
--- a/Makefile
+++ b/Makefile
@@ -756,6 +756,7 @@ TEST2X_NAMES = \
tests/vb2_secdata_firmware_tests \
tests/vb2_secdata_fwmp_tests \
tests/vb2_secdata_kernel_tests \
+ tests/vb2_sha_api_tests \
tests/vb2_sha_tests \
tests/hmac_test
@@ -1317,6 +1318,7 @@ run2tests: test_setup
${RUNTEST} ${BUILD_RUN}/tests/vb2_secdata_firmware_tests
${RUNTEST} ${BUILD_RUN}/tests/vb2_secdata_fwmp_tests
${RUNTEST} ${BUILD_RUN}/tests/vb2_secdata_kernel_tests
+ ${RUNTEST} ${BUILD_RUN}/tests/vb2_sha_api_tests
${RUNTEST} ${BUILD_RUN}/tests/vb2_sha_tests
${RUNTEST} ${BUILD_RUN}/tests/vb20_api_kernel_tests
${RUNTEST} ${BUILD_RUN}/tests/vb20_kernel_tests
diff --git a/firmware/2lib/2sha_utility.c b/firmware/2lib/2sha_utility.c
index a267edde..8c6f4b80 100644
--- a/firmware/2lib/2sha_utility.c
+++ b/firmware/2lib/2sha_utility.c
@@ -56,7 +56,7 @@ enum vb2_hash_algorithm vb2_crypto_to_hash(uint32_t algorithm)
return VB2_HASH_INVALID;
}
-vb2_error_t vb2_digest_size(enum vb2_hash_algorithm hash_alg)
+size_t vb2_digest_size(enum vb2_hash_algorithm hash_alg)
{
switch (hash_alg) {
#if VB2_SUPPORT_SHA1
@@ -76,7 +76,7 @@ vb2_error_t vb2_digest_size(enum vb2_hash_algorithm hash_alg)
}
}
-vb2_error_t vb2_hash_block_size(enum vb2_hash_algorithm alg)
+size_t vb2_hash_block_size(enum vb2_hash_algorithm alg)
{
switch (alg) {
#if VB2_SUPPORT_SHA1
@@ -211,3 +211,18 @@ vb2_error_t vb2_digest_buffer(const uint8_t *buf, uint32_t size,
return vb2_digest_finalize(&dc, digest, digest_size);
}
+
+vb2_error_t vb2_hash_verify(const void *buf, uint32_t size,
+ const struct vb2_hash *hash)
+{
+ uint8_t hash_buf[VB2_MAX_DIGEST_SIZE];
+ size_t hash_size = vb2_digest_size(hash->algo);
+ vb2_error_t rv = vb2_digest_buffer(buf, size, hash->algo,
+ hash_buf, hash_size);
+ if (rv)
+ return rv;
+ if (memcmp(hash_buf, hash->bytes.raw, hash_size))
+ return VB2_ERROR_SHA_MISMATCH;
+ else
+ return VB2_SUCCESS;
+}
diff --git a/firmware/2lib/include/2return_codes.h b/firmware/2lib/include/2return_codes.h
index b504a087..fa6bf68a 100644
--- a/firmware/2lib/include/2return_codes.h
+++ b/firmware/2lib/include/2return_codes.h
@@ -110,6 +110,9 @@ enum vb2_return_code {
/* Digest size buffer too small in vb2_digest_finalize() */
VB2_ERROR_SHA_FINALIZE_DIGEST_SIZE,
+ /* Hash mismatch in vb2_hash_verify() */
+ VB2_ERROR_SHA_MISMATCH,
+
/**********************************************************************
* RSA errors
*/
diff --git a/firmware/2lib/include/2sha.h b/firmware/2lib/include/2sha.h
index 646c7c17..32af9f74 100644
--- a/firmware/2lib/include/2sha.h
+++ b/firmware/2lib/include/2sha.h
@@ -97,6 +97,36 @@ struct vb2_digest_context {
int using_hwcrypto;
};
+/*
+ * Serializable data structure that can store any vboot hash. Layout used in
+ * CBFS attributes that need to be backwards-compatible -- do not change!
+ * When serializing/deserizaling this, you should store/load (offsetof(bytes) +
+ * vb2_digest_size(algo)), not the full size of this structure.
+ */
+struct vb2_hash {
+ /* enum vb2_hash_algorithm. Fixed width for serialization.
+ Single byte to avoid endianness issues. */
+ uint8_t algo;
+ /* Padding to align and to match existing CBFS attribute. */
+ uint8_t reserved[3];
+ /* The actual digest. Can add new types here as required. */
+ union {
+ uint8_t raw[0];
+#if VB2_SUPPORT_SHA1
+ uint8_t sha1[VB2_SHA1_DIGEST_SIZE];
+#endif
+#if VB2_SUPPORT_SHA256
+ uint8_t sha256[VB2_SHA256_DIGEST_SIZE];
+#endif
+#if VB2_SUPPORT_SHA512
+ uint8_t sha512[VB2_SHA512_DIGEST_SIZE];
+#endif
+ } bytes; /* This has a name so that it's easy to sizeof(). */
+};
+_Static_assert(sizeof(((struct vb2_hash *)0)->bytes) <= VB2_MAX_DIGEST_SIZE,
+ "Must update VB2_MAX_DIGEST_SIZE for new digests!");
+_Static_assert(VB2_HASH_ALG_COUNT <= UINT8_MAX, "vb2_hash.algo overflow!");
+
/**
* Initialize a hash context.
*
@@ -159,7 +189,7 @@ enum vb2_hash_algorithm vb2_crypto_to_hash(uint32_t algorithm);
* @param hash_alg Hash algorithm
* @return The size of the digest, or 0 if error.
*/
-vb2_error_t vb2_digest_size(enum vb2_hash_algorithm hash_alg);
+size_t vb2_digest_size(enum vb2_hash_algorithm hash_alg);
/**
* Return the block size of a hash algorithm.
@@ -167,7 +197,7 @@ vb2_error_t vb2_digest_size(enum vb2_hash_algorithm hash_alg);
* @param hash_alg Hash algorithm
* @return The block size of the algorithm, or 0 if error.
*/
-vb2_error_t vb2_hash_block_size(enum vb2_hash_algorithm alg);
+size_t vb2_hash_block_size(enum vb2_hash_algorithm alg);
/**
* Return the name of a hash algorithm
@@ -226,4 +256,34 @@ vb2_error_t vb2_digest_buffer(const uint8_t *buf, uint32_t size,
enum vb2_hash_algorithm hash_alg, uint8_t *digest,
uint32_t digest_size);
+/**
+ * Fill a vb2_hash structure with the hash of a buffer.
+ *
+ * @param buf Buffer to hash
+ * @param size Size of |buf| in bytes
+ * @param algo The hash algorithm to use (and store in |hash|)
+ * @param hash vb2_hash structure to fill with the hash of |buf|
+ * @return VB2_SUCCESS, or non-zero on error.
+ */
+static inline vb2_error_t vb2_hash_calculate(const void *buf, uint32_t size,
+ enum vb2_hash_algorithm algo,
+ struct vb2_hash *hash)
+{
+ hash->algo = algo;
+ return vb2_digest_buffer(buf, size, algo, hash->bytes.raw,
+ vb2_digest_size(algo));
+}
+
+/**
+ * Verify that a vb2_hash matches a buffer.
+ *
+ * @param buf Buffer to hash and match to |hash|
+ * @param size Size of |buf| in bytes
+ * @param hash Hash to compare to the buffer
+ * @return VB2_SUCCESS if hash matches, VB2_ERROR_SHA_MISMATCH if hash doesn't
+ * match, or non-zero on other error.
+ */
+vb2_error_t vb2_hash_verify(const void *buf, uint32_t size,
+ const struct vb2_hash *hash);
+
#endif /* VBOOT_REFERENCE_2SHA_H_ */
diff --git a/tests/vb2_sha_api_tests.c b/tests/vb2_sha_api_tests.c
new file mode 100644
index 00000000..21e32684
--- /dev/null
+++ b/tests/vb2_sha_api_tests.c
@@ -0,0 +1,115 @@
+/* Copyright 2019 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.
+ *
+ * Tests for vb2_hash_(calculate|verify) functions.
+ */
+
+#include "2return_codes.h"
+#include "2sha.h"
+#include "2sysincludes.h"
+#include "test_common.h"
+
+uint8_t mock_sha1[] = {0x1, 0x3, 0x5, 0x2, 0x4, 0x6, 0xa, 0xb, 0xc, 0xd,
+ 0xd, 0xe, 0xa, 0xd, 0xb, 0xe, 0xe, 0xf, 0x0, 0xf0};
+_Static_assert(sizeof(mock_sha1) == VB2_SHA1_DIGEST_SIZE, "");
+
+struct vb2_hash mock_hash;
+uint8_t mock_buffer[] = "Mock Buffer";
+
+vb2_error_t mock_init_rv;
+vb2_error_t mock_extend_rv;
+vb2_error_t mock_finalize_rv;
+
+static void reset_common_data(void)
+{
+ memset(&mock_hash, 0xaa, sizeof(mock_hash));
+
+ mock_init_rv = VB2_SUCCESS;
+ mock_extend_rv = VB2_SUCCESS;
+ mock_finalize_rv = VB2_SUCCESS;
+}
+
+vb2_error_t vb2_digest_init(struct vb2_digest_context *dc,
+ enum vb2_hash_algorithm hash_alg)
+{
+ if (hash_alg != VB2_HASH_SHA1)
+ return VB2_ERROR_MOCK;
+ return mock_init_rv;
+}
+
+vb2_error_t vb2_digest_extend(struct vb2_digest_context *dc, const uint8_t *buf,
+ uint32_t size)
+{
+ TEST_PTR_EQ(buf, mock_buffer, "digest_extend unexpected buf");
+ TEST_EQ(size, sizeof(mock_buffer), "digest_extend unexpected size");
+ return mock_extend_rv;
+}
+
+vb2_error_t vb2_digest_finalize(struct vb2_digest_context *dc, uint8_t *digest,
+ uint32_t size)
+{
+ TEST_EQ(size, VB2_SHA1_DIGEST_SIZE, "digest_finalize unexpected size");
+ memcpy(digest, mock_sha1, size);
+ return mock_finalize_rv;
+}
+
+static void vb2_hash_calculate_tests(void)
+{
+ reset_common_data();
+ TEST_SUCC(vb2_hash_calculate(&mock_buffer, sizeof(mock_buffer),
+ VB2_HASH_SHA1, &mock_hash),
+ "hash_calculate success");
+ TEST_SUCC(memcmp(mock_hash.bytes.sha1, mock_sha1, sizeof(mock_sha1)),
+ " got the right hash");
+ TEST_EQ(mock_hash.algo, VB2_HASH_SHA1, " set algo correctly");
+
+ reset_common_data();
+ mock_init_rv = VB2_ERROR_MOCK;
+ TEST_EQ(vb2_hash_calculate(mock_buffer, sizeof(mock_buffer),
+ VB2_HASH_SHA1, &mock_hash),
+ VB2_ERROR_MOCK, "hash_calculate init error");
+
+ reset_common_data();
+ mock_extend_rv = VB2_ERROR_MOCK;
+ TEST_EQ(vb2_hash_calculate(mock_buffer, sizeof(mock_buffer),
+ VB2_HASH_SHA1, &mock_hash),
+ VB2_ERROR_MOCK, "hash_calculate extend error");
+
+ reset_common_data();
+ mock_finalize_rv = VB2_ERROR_MOCK;
+ TEST_EQ(vb2_hash_calculate(mock_buffer, sizeof(mock_buffer),
+ VB2_HASH_SHA1, &mock_hash),
+ VB2_ERROR_MOCK, "hash_calculate finalize error");
+}
+
+static void vb2_hash_verify_tests(void)
+{
+ reset_common_data();
+
+ memcpy(mock_hash.bytes.sha1, mock_sha1, sizeof(mock_sha1));
+ mock_hash.algo = VB2_HASH_SHA1;
+ TEST_SUCC(vb2_hash_verify(mock_buffer, sizeof(mock_buffer),
+ &mock_hash), "hash_verify success");
+
+ memcpy(mock_hash.bytes.sha1, mock_sha1, sizeof(mock_sha1));
+ mock_hash.algo = VB2_HASH_SHA256;
+ TEST_EQ(vb2_hash_verify(mock_buffer, sizeof(mock_buffer),
+ &mock_hash), VB2_ERROR_MOCK,
+ "hash_verify wrong algo");
+
+ memcpy(mock_hash.bytes.sha1, mock_sha1, sizeof(mock_sha1));
+ mock_hash.bytes.raw[5] = 0xfe;
+ mock_hash.algo = VB2_HASH_SHA1;
+ TEST_EQ(vb2_hash_verify(mock_buffer, sizeof(mock_buffer),
+ &mock_hash), VB2_ERROR_SHA_MISMATCH,
+ "hash_verify mismatch");
+}
+
+int main(int argc, char *argv[])
+{
+ vb2_hash_calculate_tests();
+ vb2_hash_verify_tests();
+
+ return gTestSuccess ? 0 : 255;
+}