mirror of https://github.com/wolfSSL/wolfBoot.git
294 lines
6.5 KiB
C
294 lines
6.5 KiB
C
/* unit-tpm-rsa-exp.c
|
|
*
|
|
* Unit tests for TPM RSA public-key loading.
|
|
*/
|
|
|
|
#include <check.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#ifndef SPI_CS_TPM
|
|
#define SPI_CS_TPM 1
|
|
#endif
|
|
#ifndef WOLFBOOT_SHA_DIGEST_SIZE
|
|
#define WOLFBOOT_SHA_DIGEST_SIZE 32
|
|
#endif
|
|
#ifndef WOLFBOOT_TPM_HASH_ALG
|
|
#define WOLFBOOT_TPM_HASH_ALG TPM_ALG_SHA256
|
|
#endif
|
|
#define WOLFBOOT_TPM_KEYSTORE
|
|
|
|
#include "wolfboot/wolfboot.h"
|
|
#include "keystore.h"
|
|
#include "tpm.h"
|
|
|
|
static uint8_t test_hdr[16];
|
|
static uint8_t test_modulus[256];
|
|
static uint8_t test_exponent_der[] = { 0xAA, 0x01, 0x00, 0x01, 0x7B };
|
|
static uint8_t test_nv_digest[WOLFBOOT_SHA_DIGEST_SIZE];
|
|
static uint32_t captured_exponent;
|
|
static int forbidden_memcmp_calls;
|
|
static uint32_t mock_nv_digest_sz;
|
|
static int mock_keystore_size;
|
|
static int decode_calls;
|
|
|
|
int keyslot_id_by_sha(const uint8_t* pubkey_hint)
|
|
{
|
|
(void)pubkey_hint;
|
|
return 0;
|
|
}
|
|
|
|
uint32_t keystore_get_key_type(int id)
|
|
{
|
|
ck_assert_int_eq(id, 0);
|
|
return AUTH_KEY_RSA2048;
|
|
}
|
|
|
|
uint8_t *keystore_get_buffer(int id)
|
|
{
|
|
ck_assert_int_eq(id, 0);
|
|
return test_hdr;
|
|
}
|
|
|
|
int keystore_get_size(int id)
|
|
{
|
|
ck_assert_int_eq(id, 0);
|
|
return mock_keystore_size;
|
|
}
|
|
|
|
int wc_RsaPublicKeyDecode_ex(const byte* input, word32* inOutIdx, word32 inSz,
|
|
const byte** n, word32* nSz, const byte** e, word32* eSz)
|
|
{
|
|
(void)input;
|
|
(void)inSz;
|
|
|
|
decode_calls++;
|
|
*inOutIdx = 0;
|
|
*n = test_modulus;
|
|
*nSz = sizeof(test_modulus);
|
|
*e = &test_exponent_der[1];
|
|
*eSz = 3;
|
|
return 0;
|
|
}
|
|
|
|
int wolfTPM2_LoadRsaPublicKey_ex(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
|
|
const byte* rsaPub, word32 rsaPubSz, word32 exponent,
|
|
TPM_ALG_ID scheme, TPMI_ALG_HASH hashAlg)
|
|
{
|
|
(void)dev;
|
|
(void)key;
|
|
(void)rsaPub;
|
|
(void)rsaPubSz;
|
|
(void)scheme;
|
|
(void)hashAlg;
|
|
|
|
captured_exponent = exponent;
|
|
return 0;
|
|
}
|
|
|
|
int wolfTPM2_SetAuthHandle(WOLFTPM2_DEV* dev, int index,
|
|
const WOLFTPM2_HANDLE* handle)
|
|
{
|
|
(void)dev;
|
|
(void)index;
|
|
(void)handle;
|
|
return 0;
|
|
}
|
|
|
|
int wolfTPM2_SetAuthSession(WOLFTPM2_DEV* dev, int index,
|
|
WOLFTPM2_SESSION* tpmSession, TPMA_SESSION sessionAttributes)
|
|
{
|
|
(void)dev;
|
|
(void)index;
|
|
(void)tpmSession;
|
|
(void)sessionAttributes;
|
|
return 0;
|
|
}
|
|
|
|
int wolfTPM2_UnsetAuth(WOLFTPM2_DEV* dev, int index)
|
|
{
|
|
(void)dev;
|
|
(void)index;
|
|
return 0;
|
|
}
|
|
|
|
int wolfTPM2_UnsetAuthSession(WOLFTPM2_DEV* dev, int index,
|
|
WOLFTPM2_SESSION* tpmSession)
|
|
{
|
|
(void)dev;
|
|
(void)index;
|
|
(void)tpmSession;
|
|
return 0;
|
|
}
|
|
|
|
int wolfTPM2_NVReadAuth(WOLFTPM2_DEV* dev, WOLFTPM2_NV* nv,
|
|
word32 nvIndex, byte* dataBuf, word32* pDataSz, word32 offset)
|
|
{
|
|
(void)dev;
|
|
(void)nv;
|
|
(void)nvIndex;
|
|
(void)offset;
|
|
ck_assert_uint_eq(*pDataSz, WOLFBOOT_SHA_DIGEST_SIZE);
|
|
memcpy(dataBuf, test_nv_digest, WOLFBOOT_SHA_DIGEST_SIZE);
|
|
*pDataSz = mock_nv_digest_sz;
|
|
return 0;
|
|
}
|
|
|
|
const char* wolfTPM2_GetRCString(int rc)
|
|
{
|
|
(void)rc;
|
|
return "mock";
|
|
}
|
|
|
|
int ConstantCompare(const byte* a, const byte* b, int length)
|
|
{
|
|
int diff = 0;
|
|
int i;
|
|
|
|
for (i = 0; i < length; i++) {
|
|
diff |= a[i] ^ b[i];
|
|
}
|
|
return diff;
|
|
}
|
|
|
|
static int forbidden_memcmp(const void *a, const void *b, size_t n)
|
|
{
|
|
const uint8_t *lhs = (const uint8_t *)a;
|
|
const uint8_t *rhs = (const uint8_t *)b;
|
|
size_t i;
|
|
|
|
forbidden_memcmp_calls++;
|
|
for (i = 0; i < n; i++) {
|
|
if (lhs[i] != rhs[i])
|
|
return (int)lhs[i] - (int)rhs[i];
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#define memcmp forbidden_memcmp
|
|
#include "../../src/tpm.c"
|
|
#undef memcmp
|
|
|
|
static void setup(void)
|
|
{
|
|
memset(test_hdr, 0x42, sizeof(test_hdr));
|
|
memset(test_modulus, 0x5A, sizeof(test_modulus));
|
|
memset(test_nv_digest, 0x7C, sizeof(test_nv_digest));
|
|
captured_exponent = 0;
|
|
forbidden_memcmp_calls = 0;
|
|
mock_nv_digest_sz = WOLFBOOT_SHA_DIGEST_SIZE;
|
|
mock_keystore_size = (int)sizeof(test_hdr);
|
|
decode_calls = 0;
|
|
}
|
|
|
|
START_TEST(test_wolfBoot_load_pubkey_decodes_der_exponent_bytes)
|
|
{
|
|
uint8_t hint[WOLFBOOT_SHA_DIGEST_SIZE] = { 0 };
|
|
WOLFTPM2_KEY key;
|
|
TPM_ALG_ID alg = TPM_ALG_NULL;
|
|
int rc;
|
|
|
|
memset(&key, 0, sizeof(key));
|
|
|
|
rc = wolfBoot_load_pubkey(hint, &key, &alg);
|
|
|
|
ck_assert_int_eq(rc, 0);
|
|
ck_assert_int_eq(alg, TPM_ALG_RSA);
|
|
ck_assert_uint_eq(captured_exponent, 65537U);
|
|
}
|
|
END_TEST
|
|
|
|
/* A failed keystore_get_size() (-1: invalid or oversized OTP slot) must be
|
|
* rejected, not narrowed to uint16_t (65535) and fed to the key parser. */
|
|
START_TEST(test_wolfBoot_load_pubkey_rejects_failed_keystore_size)
|
|
{
|
|
uint8_t hint[WOLFBOOT_SHA_DIGEST_SIZE] = { 0 };
|
|
WOLFTPM2_KEY key;
|
|
TPM_ALG_ID alg = TPM_ALG_NULL;
|
|
int rc;
|
|
|
|
memset(&key, 0, sizeof(key));
|
|
mock_keystore_size = -1;
|
|
|
|
rc = wolfBoot_load_pubkey(hint, &key, &alg);
|
|
|
|
ck_assert_int_eq(rc, -1);
|
|
ck_assert_uint_eq(decode_calls, 0);
|
|
ck_assert_int_eq(alg, TPM_ALG_NULL);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(test_wolfBoot_check_rot_avoids_memcmp_on_digest_compare)
|
|
{
|
|
uint8_t hint[WOLFBOOT_SHA_DIGEST_SIZE];
|
|
int rc;
|
|
|
|
memcpy(hint, test_nv_digest, sizeof(hint));
|
|
|
|
rc = wolfBoot_check_rot(0, hint);
|
|
|
|
ck_assert_int_eq(rc, 0);
|
|
ck_assert_int_eq(forbidden_memcmp_calls, 0);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(test_wolfBoot_check_rot_rejects_mismatched_digest)
|
|
{
|
|
uint8_t hint[WOLFBOOT_SHA_DIGEST_SIZE];
|
|
int rc;
|
|
|
|
memcpy(hint, test_nv_digest, sizeof(hint));
|
|
hint[0] ^= 0x01;
|
|
|
|
rc = wolfBoot_check_rot(0, hint);
|
|
|
|
ck_assert_int_ne(rc, 0);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(test_wolfBoot_check_rot_rejects_wrong_digest_size)
|
|
{
|
|
uint8_t hint[WOLFBOOT_SHA_DIGEST_SIZE];
|
|
int rc;
|
|
|
|
memcpy(hint, test_nv_digest, sizeof(hint));
|
|
mock_nv_digest_sz = WOLFBOOT_SHA_DIGEST_SIZE - 1;
|
|
|
|
rc = wolfBoot_check_rot(0, hint);
|
|
|
|
ck_assert_int_ne(rc, 0);
|
|
}
|
|
END_TEST
|
|
|
|
static Suite *tpm_suite(void)
|
|
{
|
|
Suite *s;
|
|
TCase *tc;
|
|
|
|
s = suite_create("TPM RSA");
|
|
tc = tcase_create("wolfBoot_load_pubkey");
|
|
tcase_add_checked_fixture(tc, setup, NULL);
|
|
tcase_add_test(tc, test_wolfBoot_load_pubkey_decodes_der_exponent_bytes);
|
|
tcase_add_test(tc, test_wolfBoot_load_pubkey_rejects_failed_keystore_size);
|
|
tcase_add_test(tc, test_wolfBoot_check_rot_avoids_memcmp_on_digest_compare);
|
|
tcase_add_test(tc, test_wolfBoot_check_rot_rejects_mismatched_digest);
|
|
tcase_add_test(tc, test_wolfBoot_check_rot_rejects_wrong_digest_size);
|
|
suite_add_tcase(s, tc);
|
|
return s;
|
|
}
|
|
|
|
int main(void)
|
|
{
|
|
Suite *s;
|
|
SRunner *sr;
|
|
int failed;
|
|
|
|
s = tpm_suite();
|
|
sr = srunner_create(s);
|
|
srunner_run_all(sr, CK_NORMAL);
|
|
failed = srunner_ntests_failed(sr);
|
|
srunner_free(sr);
|
|
return failed == 0 ? 0 : 1;
|
|
}
|