From bb4dafb1e78890074552daa51db86f18d2c8be87 Mon Sep 17 00:00:00 2001 From: Stefan Berger Date: Sat, 13 Jan 2024 16:19:39 -0500 Subject: [PATCH] tpm2: NVMarshal: Introduce MAX_MARSHALLED_OBJECT_SIZE Introduce the #define MAX_MARSHALLED_OBJECT_SIZE to be used for a size of a byte buffer that is supposed to hold a marshalled OBJECT. The number is not exact but provides for a 'safe' size of a buffer. Add a test case to check that MAX_MARSHALLED_OBJECT_SIZE is sufficient. The test case needs access to ANY_OBJECT_Marshal, which is only available when -static can be used for linking since otherwise the function is private to the library. Static linking the test case does not work when test-coverage is enabled, therefore disable statically linked test cases in when test-coverage is enabled and give control to the user to disable statically linked test cases in other cases as well. Signed-off-by: Stefan Berger --- .gitignore | 1 + configure.ac | 14 +++++++ src/tpm2/NVMarshal.h | 5 +++ tests/Makefile.am | 23 ++++++++++++ tests/object_size.c | 87 ++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 130 insertions(+) create mode 100644 tests/object_size.c diff --git a/.gitignore b/.gitignore index 1864a1cc..98e50221 100644 --- a/.gitignore +++ b/.gitignore @@ -53,6 +53,7 @@ Makefile /tests/fuzz /tests/freebl_sha1flattensize /tests/nvram_offsets +/tests/object_size /tests/tpm2_createprimary /tests/tpm2_cve-2023-1017 /tests/tpm2_cve-2023-1018 diff --git a/configure.ac b/configure.ac index eedcdf58..5910e416 100644 --- a/configure.ac +++ b/configure.ac @@ -267,11 +267,24 @@ AC_ARG_ENABLE([test-coverage], [if test "$enableval" = "yes"; then COVERAGE_CFLAGS="-fprofile-arcs -ftest-coverage" COVERAGE_LDFLAGS="-fprofile-arcs" + enable_static_tests=no # some tests will not link fi], [ enable_test_coverage=no ] ) +AC_ARG_ENABLE([static-tests], + AS_HELP_STRING([--disable-static-tests], [Disable statically linked tests]), + [if test "$enableval" = "yes"; then + AM_CONDITIONAL(ENABLE_STATIC_TESTS, true) + else + AM_CONDITIONAL(ENABLE_STATIC_TESTS, false) + fi], [ + AM_CONDITIONAL(ENABLE_STATIC_TESTS, true) + enable_static_tests=yes + ] +) + LT_INIT AC_PROG_CC AC_PROG_CXX @@ -372,5 +385,6 @@ echo "With TPM2 support : $with_tpm2" echo "HAVE_VERSION_SCRIPT : $have_version_script" echo "Use openssl crypto for : $use_openssl_functions_for" echo "Test coverage : $enable_test_coverage" +echo "Statically linked tests : $enable_static_tests" echo echo diff --git a/src/tpm2/NVMarshal.h b/src/tpm2/NVMarshal.h index 92a74fb6..a6e2931a 100644 --- a/src/tpm2/NVMarshal.h +++ b/src/tpm2/NVMarshal.h @@ -46,6 +46,11 @@ #define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0])) +// Maximum size of buffer ANY_OBJECT_Marshal() will require to marshal an OBJECT +// This is not an exact number but gives a 'safe' buffer size +#define MAX_MARSHALLED_OBJECT_SIZE \ + (sizeof(OBJECT) + 32 /* marshalling headers */) + UINT16 VolatileState_Marshal(BYTE **buffer, INT32 *size); TPM_RC VolatileState_Unmarshal(BYTE **buffer, INT32 *size); diff --git a/tests/Makefile.am b/tests/Makefile.am index 482d3133..bc61239c 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -48,6 +48,29 @@ nvram_offsets_CFLAGS = $(AM_CFLAGS) \ -DTPM_POSIX nvram_offsets_LDFLAGS = $(AM_LDFLAGS) + +if WITH_TPM2 +if ENABLE_STATIC_TESTS + +# object_size needs ANY_OBJECT_Marshal which only is accessible with '-static' +check_PROGRAMS += \ + object_size +TESTS += \ + object_size + +object_size_SOURCES = object_size.c +object_size_CFLAGS = $(AM_CFLAGS) \ + -static \ + -I$(top_srcdir)/include/libtpms \ + -I$(top_srcdir)/src \ + -I$(top_srcdir)/src/tpm2 \ + -I$(top_srcdir)/src/tpm2/crypto \ + -I$(top_srcdir)/src/tpm2/crypto/openssl \ + -DTPM_POSIX +object_size_LDFLAGS = $(AM_LDFLAGS) +endif # ENABLE_STATIC_TESTS +endif # WITH_TPM2 + if WITH_TPM2 check_PROGRAMS += fuzz endif diff --git a/tests/object_size.c b/tests/object_size.c new file mode 100644 index 00000000..9ecb2107 --- /dev/null +++ b/tests/object_size.c @@ -0,0 +1,87 @@ +#include +#include + +#include "Tpm.h" + +int main(void) +{ + /* This is supposed to be the OBJECT that requires the most bytes + * when it is marshalled: currently an RSA key + */ + OBJECT object = { + .attributes = { + .occupied = SET, + }, + .publicArea = { + .type = TPM_ALG_RSA, + .nameAlg = TPM_ALG_SHA512, + .objectAttributes = 0, + .authPolicy.t = { + .size = sizeof(object.publicArea.authPolicy.t.buffer), + }, + .parameters.rsaDetail = { + .symmetric = { + .algorithm = TPM_ALG_AES, + .keyBits = 256, + .mode = TPM_ALG_ECB, + }, + .scheme = TPM_ALG_RSAPSS, + .keyBits = MAX_RSA_KEY_BITS, + .exponent = 0x10001, + }, + .unique.rsa.t = { + .size = sizeof(object.publicArea.unique.rsa.t.buffer), + }, + }, + .sensitive = { + .sensitiveType = TPM_ALG_RSA, + .authValue.t = { + .size = sizeof(object.sensitive.authValue.t.buffer), + }, + .seedValue.t = { + .size = sizeof(object.sensitive.seedValue.t.buffer), + }, + .sensitive.rsa.t = { + .size = sizeof(object.sensitive.sensitive.rsa.t.buffer), + }, + }, + .privateExponent = { + .Q = { + .size = CRYPT_WORDS(BITS_TO_BYTES(MAX_RSA_KEY_BITS / 2)), + }, + .dP = { + .size = CRYPT_WORDS(BITS_TO_BYTES(MAX_RSA_KEY_BITS / 2)), + }, + .dQ = { + .size = CRYPT_WORDS(BITS_TO_BYTES(MAX_RSA_KEY_BITS / 2)), + }, + .qInv = { + .size = CRYPT_WORDS(BITS_TO_BYTES(MAX_RSA_KEY_BITS / 2)), + }, + }, + .qualifiedName.t = { + .size = sizeof(object.qualifiedName.t.name), + }, + .evictHandle = 0x12345678, + .name.t = { + .size = sizeof(object.name.t.name), + }, + .seedCompatLevel = 1, + }; + /* this buffer must only be filled to <= MAX_MARSHALLED_OBJECT_SIZE bytes */ + BYTE buffer[2 * MAX_MARSHALLED_OBJECT_SIZE]; + BYTE *buf = buffer; + INT32 size = sizeof(buffer); + UINT32 written; + + written = ANY_OBJECT_Marshal(&object, &buf, &size); + if (written > MAX_MARSHALLED_OBJECT_SIZE) { + fprintf(stderr, + "Expected flattened OBJECT to have %zu bytes, but it has %u.\n", + MAX_MARSHALLED_OBJECT_SIZE, written); + return EXIT_FAILURE; + } + fprintf(stdout, " written = %d < MAX_MARSHALLED_OBJECT_SIZE = %zu\n", + written, MAX_MARSHALLED_OBJECT_SIZE); + return EXIT_SUCCESS; +} \ No newline at end of file