From: Stefan Berger <stefanb@linux.ibm.com>
To test large data transfers (receiving and sending) that make us of a CRB
chunked transfer, create an ML-DSA-87 key and sign some data with it and
receive the 4627 bytes signature. After this send the signature back to the
TPM to have the TPM verify the signature.
Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
Signed-off-by: Arun Menon <armenon@redhat.com>
---
tests/qtest/tpm-crb-swtpm-test.c | 5 +-
tests/qtest/tpm-tests.c | 96 ++++++++++++++++++++++++++++++++
tests/qtest/tpm-tests.h | 4 ++
tests/qtest/tpm-util.c | 37 ++++++++++++
tests/qtest/tpm-util.h | 2 +
5 files changed, 142 insertions(+), 2 deletions(-)
diff --git a/tests/qtest/tpm-crb-swtpm-test.c b/tests/qtest/tpm-crb-swtpm-test.c
index 050c7b0c1f..541fd58133 100644
--- a/tests/qtest/tpm-crb-swtpm-test.c
+++ b/tests/qtest/tpm-crb-swtpm-test.c
@@ -37,8 +37,9 @@ static void tpm_crb_chunk_swtpm_test(const void *data)
{
const TestState *ts = data;
- tpm_test_swtpm_test(ts->src_tpm_path, tpm_util_crb_chunk_transfer,
- "tpm-crb", NULL);
+ tpm_test_swtpm_large_tx_test(ts->src_tpm_path,
+ tpm_util_crb_chunk_transfer,
+ "tpm-crb", NULL);
}
static void tpm_crb_swtpm_migration_test(const void *data)
diff --git a/tests/qtest/tpm-tests.c b/tests/qtest/tpm-tests.c
index f71d882990..21811f3a2e 100644
--- a/tests/qtest/tpm-tests.c
+++ b/tests/qtest/tpm-tests.c
@@ -13,6 +13,7 @@
*/
#include "qemu/osdep.h"
+#include "system/tpm_util.h"
#include <glib/gstdio.h>
#include "libqtest-single.h"
@@ -130,3 +131,98 @@ void tpm_test_swtpm_migration_test(const char *src_tpm_path,
g_unlink(src_tpm_addr->u.q_unix.path);
qapi_free_SocketAddress(src_tpm_addr);
}
+
+void tpm_test_swtpm_large_tx_test(const char *src_tpm_path, tx_func *tx,
+ const char *ifmodel,
+ const char *machine_options)
+{
+ unsigned char signature[2 + 2 + 4627]; /* TPMT_SIGNATURE */
+ unsigned char response[8192];
+ unsigned char request[8192];
+ SocketAddress *addr = NULL;
+ GError *error = NULL;
+ char *args = NULL;
+ GPid swtpm_pid;
+ QTestState *s;
+ gboolean succ;
+
+ if (tpm_test_swtpm_skip()) {
+ return;
+ }
+
+ /* Large transfers based on ML-DSA operations required default-v2 profile */
+ if (!tpm_util_swtpm_has_profile("default-v2", "ml-dsa")) {
+ return;
+ }
+
+ succ = tpm_util_swtpm_start(src_tpm_path, &swtpm_pid, &addr, "default-v2",
+ &error);
+ g_assert_true(succ);
+
+ args = g_strdup_printf(
+ "%s "
+ "-chardev socket,id=chr,path=%s "
+ "-tpmdev emulator,id=dev,chardev=chr "
+ "-device %s,tpmdev=dev",
+ machine_options ? : "", addr->u.q_unix.path, ifmodel);
+
+ s = qtest_start(args);
+ g_free(args);
+
+ tpm_util_startup(s, tx);
+
+ static const unsigned char tpm_createprimary_mldsa[] =
+ "\x80\x02\x00\x00\x00\x38\x00\x00\x01\x31\x40\x00\x00\x07\x00\x00"
+ "\x00\x09\x40\x00\x00\x09\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00"
+ "\x00\x00\x0f\x00\xa1\x00\x0b\x00\x04\x04\x72\x00\x00\x00\x03\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00";
+ tx(s, tpm_createprimary_mldsa, sizeof(tpm_createprimary_mldsa),
+ response, sizeof(response));
+ g_assert_cmpint(tpm_cmd_get_errcode(response), ==, 0);
+ g_assert_cmpint(tpm_cmd_get_size(response), ==, 2831);
+
+ static const unsigned char tpm_signsequencestart[] =
+ "\x80\x01\x00\x00\x00\x12\x00\x00\x01\xaa\x80\x00\x00\x00\x00\x00"
+ "\x00\x00";
+ tx(s, tpm_signsequencestart, sizeof(tpm_signsequencestart),
+ response, sizeof(response));
+ g_assert_cmpint(tpm_cmd_get_errcode(response), ==, 0);
+ g_assert_cmpint(tpm_cmd_get_size(response), ==, 14);
+
+ /* Complete sequence and get signature */
+ static const unsigned char tpm_signsequencecomplete[] =
+ "\x80\x02\x00\x00\x00\x2a\x00\x00\x01\xa4\x80\x00\x00\x01\x80\x00"
+ "\x00\x00\x00\x00\x00\x12\x40\x00\x00\x09\x00\x00\x00\x00\x00\x40"
+ "\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00";
+ tx(s, tpm_signsequencecomplete, sizeof(tpm_signsequencecomplete),
+ response, sizeof(response));
+ g_assert_cmpint(tpm_cmd_get_errcode(response), ==, 0);
+ g_assert_cmpint(tpm_cmd_get_size(response), ==, 4655);
+
+ /* TPMT_SIGNATURE found at offset 14 */
+ memcpy(signature, &response[14], sizeof(signature));
+
+ static const unsigned char tpm_verifysequencestart[] =
+ "\x80\x01\x00\x00\x00\x14\x00\x00\x01\xa9\x80\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00";
+ tx(s, tpm_verifysequencestart, sizeof(tpm_verifysequencestart),
+ response, sizeof(response));
+ g_assert_cmpint(tpm_cmd_get_errcode(response), ==, 0);
+ g_assert_cmpint(tpm_cmd_get_size(response), ==, 14);
+
+ /* TPM2_VerifySequenceComplete */
+ memcpy(request,
+ "\x80\x02\x00\x00\x12\x36\x00\x00\x01\xa3\x80\x00\x00\x01\x80\x00"
+ "\x00\x00\x00\x00\x00\x09\x40\x00\x00\x09\x00\x00\x00\x00\x00",
+ 31);
+ memcpy(&request[31], signature, sizeof(signature));
+ tx(s, request, 31 + sizeof(signature), response, sizeof(response));
+ g_assert_cmpint(tpm_cmd_get_errcode(response), ==, 0);
+ g_assert_cmpint(tpm_cmd_get_size(response), ==, 27);
+
+ qtest_end();
+ tpm_util_swtpm_kill(swtpm_pid);
+
+ g_unlink(addr->u.q_unix.path);
+ qapi_free_SocketAddress(addr);
+}
diff --git a/tests/qtest/tpm-tests.h b/tests/qtest/tpm-tests.h
index 07ba60d26e..6993ce40dc 100644
--- a/tests/qtest/tpm-tests.h
+++ b/tests/qtest/tpm-tests.h
@@ -24,4 +24,8 @@ void tpm_test_swtpm_migration_test(const char *src_tpm_path,
const char *ifmodel,
const char *machine_options);
+void tpm_test_swtpm_large_tx_test(const char *src_tpm_path, tx_func *tx,
+ const char *ifmodel,
+ const char *machine_options);
+
#endif /* TESTS_TPM_TESTS_H */
diff --git a/tests/qtest/tpm-util.c b/tests/qtest/tpm-util.c
index 24243065c1..6163f5a533 100644
--- a/tests/qtest/tpm-util.c
+++ b/tests/qtest/tpm-util.c
@@ -209,6 +209,43 @@ bool tpm_util_swtpm_has_tpm2(void)
return has_tpm2;
}
+bool tpm_util_swtpm_has_profile(const char *profilename,
+ const char *content)
+{
+ bool has_profile = false;
+ char *out = NULL;
+ static const char *argv[] = {
+ "swtpm", "socket", "--tpm2", "--print-profiles", NULL
+ };
+
+ if (!tpm_util_swtpm_has_tpm2()) {
+ return false;
+ }
+
+ if (!g_spawn_sync(NULL /* working_dir */,
+ (char **)argv,
+ NULL /* envp */,
+ G_SPAWN_SEARCH_PATH,
+ NULL /* child_setup */,
+ NULL /* user_data */,
+ &out,
+ NULL /* err */,
+ NULL /* exit_status */,
+ NULL)) {
+ return false;
+ }
+
+ if (strstr(out, profilename)) {
+ has_profile = true;
+ }
+ if (has_profile && content && strstr(out, content) == NULL) {
+ has_profile = false;
+ }
+
+ g_free(out);
+ return has_profile;
+}
+
gboolean tpm_util_swtpm_start(const char *path, GPid *pid,
SocketAddress **addr, const char *profilename,
GError **error)
diff --git a/tests/qtest/tpm-util.h b/tests/qtest/tpm-util.h
index ca2d7d173f..90790f30db 100644
--- a/tests/qtest/tpm-util.h
+++ b/tests/qtest/tpm-util.h
@@ -39,6 +39,8 @@ void tpm_util_pcrread(QTestState *s, tx_func *tx,
const unsigned char *exp_resp, size_t exp_resp_size);
bool tpm_util_swtpm_has_tpm2(void);
+bool tpm_util_swtpm_has_profile(const char *profilename,
+ const char *content);
gboolean tpm_util_swtpm_start(const char *path, GPid *pid,
SocketAddress **addr, const char *profilename,
--
2.53.0