Skip to content

Commit

Permalink
Fix for wrong endian determination when signature is same for both
Browse files Browse the repository at this point in the history
endians.

Signed-off-by: Kong, Richard <[email protected]>
  • Loading branch information
richkong88 authored and jyao1 committed Oct 12, 2023
1 parent b8d92d4 commit 2b625ea
Show file tree
Hide file tree
Showing 2 changed files with 226 additions and 17 deletions.
98 changes: 82 additions & 16 deletions library/spdm_crypt_lib/libspdm_crypt_asym.c
Original file line number Diff line number Diff line change
Expand Up @@ -689,6 +689,64 @@ void libspdm_copy_signature_swap_endian(
}
}

/**
* libspdm_is_palindrome
* Checks to see if a buffer is a palindrome.
* If the buffer is a palindrone, it is the same for both endians,
* and therefore endianness cannot be determined.
**/
bool libspdm_is_palindrome(const uint8_t* buf, size_t buf_size)
{
size_t head;
size_t tail;

head = 0;
tail = buf_size - 1;

while (head < tail) {
if (buf[head] != buf[tail]) {
return false;
}
head++;
tail--;
}

return true;
}

bool libspdm_is_signature_buffer_palindrome(
uint32_t base_asym_algo, const uint8_t *buf, size_t buf_size)
{
const uint32_t spdm_10_11_rsa_algos =
SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_2048 |
SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_2048 |
SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_3072 |
SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_3072 |
SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_4096 |
SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_4096;

const uint32_t spdm_10_11_ecdsa_algos =
SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P256 |
SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P384 |
SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P521;

if (base_asym_algo & spdm_10_11_rsa_algos) {
return libspdm_is_palindrome(buf, buf_size);
} else if (base_asym_algo & spdm_10_11_ecdsa_algos) {
const size_t x_size = buf_size / 2;
const size_t y_size = x_size;

const uint8_t *x = buf;
const uint8_t *y = buf + x_size;

return libspdm_is_palindrome(x, x_size) && libspdm_is_palindrome(y, y_size);
} else {
/* Currently do not expect asymmetric algorithms other than RSA and ECDSA */
LIBSPDM_ASSERT(0);
return false;
}
}

#if LIBSPDM_RSA_SSA_SUPPORT
static bool libspdm_rsa_pkcs1_verify_with_nid_wrap (void *context, size_t hash_nid,
const uint8_t *param, size_t param_size,
Expand Down Expand Up @@ -979,10 +1037,12 @@ bool libspdm_asym_verify_ex(
}
}
if (try_big_endian && try_little_endian && result) {
if (little_endian_succeeded) {
*endian = LIBSPDM_SPDM_10_11_VERIFY_SIGNATURE_ENDIAN_LITTLE_ONLY;
} else {
*endian = LIBSPDM_SPDM_10_11_VERIFY_SIGNATURE_ENDIAN_BIG_ONLY;
if (!libspdm_is_signature_buffer_palindrome(base_asym_algo, signature, sig_size)) {
if (little_endian_succeeded) {
*endian = LIBSPDM_SPDM_10_11_VERIFY_SIGNATURE_ENDIAN_LITTLE_ONLY;
} else {
*endian = LIBSPDM_SPDM_10_11_VERIFY_SIGNATURE_ENDIAN_BIG_ONLY;
}
}
}
return result;
Expand Down Expand Up @@ -1102,10 +1162,12 @@ bool libspdm_asym_verify_hash_ex(
little_endian_succeeded = result;
}
if (try_big_endian && try_little_endian && result) {
if (little_endian_succeeded) {
*endian = LIBSPDM_SPDM_10_11_VERIFY_SIGNATURE_ENDIAN_LITTLE_ONLY;
} else {
*endian = LIBSPDM_SPDM_10_11_VERIFY_SIGNATURE_ENDIAN_BIG_ONLY;
if (!libspdm_is_signature_buffer_palindrome(base_asym_algo, signature, sig_size)) {
if (little_endian_succeeded) {
*endian = LIBSPDM_SPDM_10_11_VERIFY_SIGNATURE_ENDIAN_LITTLE_ONLY;
} else {
*endian = LIBSPDM_SPDM_10_11_VERIFY_SIGNATURE_ENDIAN_BIG_ONLY;
}
}
}
return result;
Expand Down Expand Up @@ -1454,10 +1516,12 @@ bool libspdm_req_asym_verify_ex(
}
}
if (try_big_endian && try_little_endian && result) {
if (little_endian_succeeded) {
*endian = LIBSPDM_SPDM_10_11_VERIFY_SIGNATURE_ENDIAN_LITTLE_ONLY;
} else {
*endian = LIBSPDM_SPDM_10_11_VERIFY_SIGNATURE_ENDIAN_BIG_ONLY;
if (!libspdm_is_signature_buffer_palindrome(req_base_asym_alg, signature, sig_size)) {
if (little_endian_succeeded) {
*endian = LIBSPDM_SPDM_10_11_VERIFY_SIGNATURE_ENDIAN_LITTLE_ONLY;
} else {
*endian = LIBSPDM_SPDM_10_11_VERIFY_SIGNATURE_ENDIAN_BIG_ONLY;
}
}
}
return result;
Expand Down Expand Up @@ -1574,10 +1638,12 @@ bool libspdm_req_asym_verify_hash_ex(
little_endian_succeeded = result;
}
if (try_big_endian && try_little_endian && result) {
if (little_endian_succeeded) {
*endian = LIBSPDM_SPDM_10_11_VERIFY_SIGNATURE_ENDIAN_LITTLE_ONLY;
} else {
*endian = LIBSPDM_SPDM_10_11_VERIFY_SIGNATURE_ENDIAN_BIG_ONLY;
if (!libspdm_is_signature_buffer_palindrome(req_base_asym_alg, signature, sig_size)) {
if (little_endian_succeeded) {
*endian = LIBSPDM_SPDM_10_11_VERIFY_SIGNATURE_ENDIAN_LITTLE_ONLY;
} else {
*endian = LIBSPDM_SPDM_10_11_VERIFY_SIGNATURE_ENDIAN_BIG_ONLY;
}
}
}
return result;
Expand Down
145 changes: 144 additions & 1 deletion unit_test/test_spdm_crypt/test_spdm_crypt.c
Original file line number Diff line number Diff line change
Expand Up @@ -861,6 +861,143 @@ void libspdm_test_crypt_req_asym_verify(void **state)
#endif
}

bool libspdm_is_palindrome(const uint8_t *buf, size_t buf_size);

bool libspdm_is_signature_buffer_palindrome(
uint32_t base_asym_algo, const uint8_t *buf, size_t buf_size);

void libspdm_test_crypt_palindrome(void **state)
{
bool status;

/* Test valid palindrome with even number of elements */
uint8_t buf1[] = {0, 1, 2, 3, 4, 5, 6, 7, 7, 6, 5, 4, 3, 2, 1, 0};
status = libspdm_is_palindrome(buf1, sizeof(buf1));
assert_true(status);

/* Test valid palindrome with odd number of elements */
uint8_t buf2[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 7, 6, 5, 4, 3, 2, 1, 0 };
status = libspdm_is_palindrome(buf2, sizeof(buf2));
assert_true(status);

/* Test invalid palindrome where inner corner-case element is not matching */
uint8_t buf3[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 6, 5, 4, 3, 2, 1, 0 };
status = libspdm_is_palindrome(buf3, sizeof(buf3));
assert_false(status);

/* Test invalid palindrome where outer corner-case element is not matching */
uint8_t buf4[] = { 0, 1, 2, 3, 4, 5, 6, 7, 7, 6, 5, 4, 3, 2, 1, 8 };
status = libspdm_is_palindrome(buf4, sizeof(buf4));
assert_false(status);

/* Test invalid palindrome where middle element is not matching */
uint8_t buf5[] = { 0, 1, 2, 3, 4, 5, 6, 7, 7, 6, 5, 4, 4, 2, 1, 0 };
status = libspdm_is_palindrome(buf5, sizeof(buf5));
assert_false(status);
}

void libspdm_test_crypt_rsa_palindrome(void **state)
{
/* Test RSA Buffers as palindrone */
int i;
bool status;

const uint32_t rsa_algos[] = {
SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_2048,
SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_2048,
SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_3072,
SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_3072,
SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_4096,
SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_4096
};

/* Palindrome for RSA */
uint8_t buf0[] = { 0, 1, 2, 3, 4, 5, 6, 7, 7, 6, 5, 4, 3, 2, 1, 0 };

/* Not Palindrome cases for RSA */

/* Test invalid palindrome where inner corner-case element is not matching */
uint8_t buf1[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 6, 5, 4, 3, 2, 1, 0 };

/* Test invalid palindrome where outer corner-case element is not matching */
uint8_t buf2[] = { 0, 1, 2, 3, 4, 5, 6, 7, 7, 6, 5, 4, 3, 2, 1, 8 };

/* Test invalid palindrome where middle element is not matching */
uint8_t buf3[] = { 0, 1, 2, 3, 4, 5, 6, 7, 7, 6, 5, 4, 4, 2, 1, 0 };

/* Test each of these buffers against each RSA algo type */
for (i = 0; i < (sizeof(rsa_algos) / sizeof(rsa_algos[0])); i++) {
/* Test case where buffer is palindrone */
status = libspdm_is_signature_buffer_palindrome(rsa_algos[i], buf0, sizeof(buf0));
assert_true(status);

/* Test cases where buffer is NOT palindrone */
status = libspdm_is_signature_buffer_palindrome(rsa_algos[i], buf1, sizeof(buf1));
assert_false(status);
status = libspdm_is_signature_buffer_palindrome(rsa_algos[i], buf2, sizeof(buf2));
assert_false(status);
status = libspdm_is_signature_buffer_palindrome(rsa_algos[i], buf3, sizeof(buf3));
assert_false(status);
}
}

void libspdm_test_crypt_ecdsa_palindrome(void **state)
{
int i;
bool status;

/* Test ECDSA Buffers as palindrome */
const uint32_t ecdsa_algos[] = {
SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P256,
SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P384,
SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P521
};

/* Test for valid ECDSA buffer palindrome */
uint8_t buf0[] = { 0, 1, 2, 3, 3, 2, 1, 0, 0, 1, 2, 3, 3, 2, 1, 0 };

/* Tests for ECDSA buffer not palidrome */

/* Test for invalid palindrome where outer element of 1st buffer does not match */
uint8_t buf1[] = { 0, 1, 2, 3, 3, 2, 1, 1, 0, 1, 2, 3, 3, 2, 1, 0 };

/* Test for invalid palindrome where outer element of 2nd buffer does not match */
uint8_t buf2[] = { 0, 1, 2, 3, 3, 2, 1, 0, 0, 1, 2, 3, 3, 2, 1, 1 };

/* Test for invalid palindrome where inner element of 1st buffer does not match */
uint8_t buf3[] = { 0, 1, 2, 3, 4, 2, 1, 0, 0, 1, 2, 3, 3, 2, 1, 0 };

/* Test for invalid palindrome where inner element of 2nd buffer does not match */
uint8_t buf4[] = { 0, 1, 2, 3, 3, 2, 1, 0, 0, 1, 2, 3, 4, 2, 1, 0 };

/* Test for invalid palindrome where middle element of 1st buffer does not match */
uint8_t buf5[] = { 0, 1, 2, 3, 3, 2, 0, 0, 0, 1, 2, 3, 3, 2, 1, 0 };

/* Test for invalid palindrome where middle element of 2nd buffer does not match */
uint8_t buf6[] = { 0, 1, 2, 3, 3, 2, 1, 0, 0, 1, 2, 3, 3, 0, 1, 0 };

/* Test each of the buffers against each ECDSA algo type */
for (i = 0; i < (sizeof(ecdsa_algos) / sizeof(ecdsa_algos[0])); i++) {
/* Test case where buffer is palindrone */
status = libspdm_is_signature_buffer_palindrome(ecdsa_algos[i], buf0, sizeof(buf0));
assert_true(status);

/* Test cases where buffer is NOT palindrone */
status = libspdm_is_signature_buffer_palindrome(ecdsa_algos[i], buf1, sizeof(buf1));
assert_false(status);
status = libspdm_is_signature_buffer_palindrome(ecdsa_algos[i], buf2, sizeof(buf2));
assert_false(status);
status = libspdm_is_signature_buffer_palindrome(ecdsa_algos[i], buf3, sizeof(buf3));
assert_false(status);
status = libspdm_is_signature_buffer_palindrome(ecdsa_algos[i], buf4, sizeof(buf4));
assert_false(status);
status = libspdm_is_signature_buffer_palindrome(ecdsa_algos[i], buf5, sizeof(buf5));
assert_false(status);
status = libspdm_is_signature_buffer_palindrome(ecdsa_algos[i], buf6, sizeof(buf6));
assert_false(status);
}
}

int libspdm_crypt_lib_setup(void **state)
{
return 0;
Expand All @@ -883,7 +1020,13 @@ int libspdm_crypt_lib_test_main(void)

cmocka_unit_test(libspdm_test_crypt_asym_verify),

cmocka_unit_test(libspdm_test_crypt_req_asym_verify)
cmocka_unit_test(libspdm_test_crypt_req_asym_verify),

cmocka_unit_test(libspdm_test_crypt_palindrome),

cmocka_unit_test(libspdm_test_crypt_rsa_palindrome),

cmocka_unit_test(libspdm_test_crypt_ecdsa_palindrome),
};

return cmocka_run_group_tests(spdm_crypt_lib_tests,
Expand Down

0 comments on commit 2b625ea

Please sign in to comment.