diff --git a/man/systemd-analyze.xml b/man/systemd-analyze.xml
index 1aaf03ac52..2f2873452a 100644
--- a/man/systemd-analyze.xml
+++ b/man/systemd-analyze.xml
@@ -174,6 +174,11 @@
pcrs
PCR
+
+ systemd-analyze
+ OPTIONS
+ srk >FILE
+
@@ -926,6 +931,16 @@ NR NAME SHA256
23 application-support 0000000000000000000000000000000000000000000000000000000000000000
+
+
+ systemd-analyze srk > FILE
+
+ This command reads the Storage Root Key (SRK) from the TPM2 device, and writes it in marshalled
+ TPM2B_PUBLIC format to stdout. Example:
+
+ systemd-analyze srk > srk.tpm2b_public
+
+
diff --git a/src/analyze/analyze-srk.c b/src/analyze/analyze-srk.c
new file mode 100644
index 0000000000..3138246225
--- /dev/null
+++ b/src/analyze/analyze-srk.c
@@ -0,0 +1,47 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "analyze.h"
+#include "analyze-srk.h"
+#include "tpm2-util.h"
+
+int verb_srk(int argc, char *argv[], void *userdata) {
+#if HAVE_TPM2
+ _cleanup_(tpm2_context_unrefp) Tpm2Context *c = NULL;
+ _cleanup_(Esys_Freep) TPM2B_PUBLIC *public = NULL;
+ int r;
+
+ r = tpm2_context_new(/* device= */ NULL, &c);
+ if (r < 0)
+ return log_error_errno(r, "Failed to create TPM2 context: %m");
+
+ r = tpm2_get_srk(
+ c,
+ /* session= */ NULL,
+ &public,
+ /* ret_name= */ NULL,
+ /* ret_qname= */ NULL,
+ /* ret_handle= */ NULL);
+ if (r < 0)
+ return log_error_errno(r, "Failed to get SRK: %m");
+ if (r == 0)
+ return log_error_errno(SYNTHETIC_ERRNO(ENOENT), "No SRK stored so far.");
+
+ _cleanup_free_ void *marshalled = NULL;
+ size_t marshalled_size = 0;
+ r = tpm2_marshal_public(public, &marshalled, &marshalled_size);
+ if (r < 0)
+ return log_error_errno(r, "Failed to marshal SRK: %m");
+
+ if (isatty(STDOUT_FILENO))
+ return log_error_errno(SYNTHETIC_ERRNO(EIO), "Refusing to write binary data to TTY, please redirect output to file.");
+
+ if (fwrite(marshalled, 1, marshalled_size, stdout) != marshalled_size)
+ return log_error_errno(errno, "Failed to write SRK to stdout: %m");
+
+ fflush(stdout);
+
+ return EXIT_SUCCESS;
+#else
+ return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "TPM2 support not available.");
+#endif
+}
diff --git a/src/analyze/analyze-srk.h b/src/analyze/analyze-srk.h
new file mode 100644
index 0000000000..26028354f8
--- /dev/null
+++ b/src/analyze/analyze-srk.h
@@ -0,0 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+int verb_srk(int argc, char *argv[], void *userdata);
diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c
index 1b96e8b69a..d2be144f4f 100644
--- a/src/analyze/analyze.c
+++ b/src/analyze/analyze.c
@@ -32,6 +32,7 @@
#include "analyze-plot.h"
#include "analyze-security.h"
#include "analyze-service-watchdogs.h"
+#include "analyze-srk.h"
#include "analyze-syscall-filter.h"
#include "analyze-time.h"
#include "analyze-time-data.h"
@@ -236,6 +237,7 @@ static int help(int argc, char *argv[], void *userdata) {
" malloc [D-BUS SERVICE...] Dump malloc stats of a D-Bus service\n"
" fdstore SERVICE... Show file descriptor store contents of service\n"
" pcrs [PCR...] Show TPM2 PCRs and their names\n"
+ " srk > FILE Write TPM2 SRK to stdout\n"
"\nOptions:\n"
" --recursive-errors=MODE Control which units are verified\n"
" --offline=BOOL Perform a security review on unit file(s)\n"
@@ -646,6 +648,7 @@ static int run(int argc, char *argv[]) {
{ "fdstore", 2, VERB_ANY, 0, verb_fdstore },
{ "image-policy", 2, 2, 0, verb_image_policy },
{ "pcrs", VERB_ANY, VERB_ANY, 0, verb_pcrs },
+ { "srk", VERB_ANY, 1, 0, verb_srk },
{}
};
diff --git a/src/analyze/meson.build b/src/analyze/meson.build
index 1a9b68f6d2..a50544730b 100644
--- a/src/analyze/meson.build
+++ b/src/analyze/meson.build
@@ -21,6 +21,7 @@ systemd_analyze_sources = files(
'analyze-plot.c',
'analyze-security.c',
'analyze-service-watchdogs.c',
+ 'analyze-srk.c',
'analyze-syscall-filter.c',
'analyze-time.c',
'analyze-time-data.c',