Files
systemd/man/systemd-report-sign-tpm2@.service.xml
Adrian Reber 0cb06c715a report-sign-tpm2: certify the SRK and report its public area
Secrets sealed to the SRK, e.g. via the --tpm2-device-key= switch of
systemd-cryptenroll and systemd-repart, can only be unsealed by the TPM
the SRK lives in, and sealing needs no access to that TPM. With the SRK
certified by the attestation key, a verifier of the report hence has a
public key it can trust to encrypt data for the reporting system
specifically. Since TPM2_Clear replaces the SRK, a certification of the
same SRK in a later report also shows that the TPM has not been cleared
in between.

Certify the SRK with each signing key, and provide its public area as
TSS2 JSON, like the signing key's. Marshalled into a TPM2B_PUBLIC this
is what --tpm2-device-key= consumes. If there is no SRK one is created,
like systemd-cryptenroll does.

Whatever sits at the SRK handle is certified. Judging its attributes is
up to the verifier, and whether it can be authorized with a password
session is left to TPM2_Certify. The one exception is noDA: an object
without it with an auth value we don't know would count every failed
attempt towards the TPM's dictionary attack lockout, and reports are
requested repeatedly, so such an object is not certified at all. Apart
from that we only make sure up front that we can calculate the name and
encode the public area, so that a pre-existing SRK we cannot handle
doesn't fail the whole report, and hand the vetted public area to the
report generator, so that an object swapped in at the handle afterwards
fails the name check rather than being certified. Failing to acquire the
SRK is not fatal either, the report is still useful without the
certification.
2026-10-19 17:33:12 +00:00

152 lines
9.7 KiB
XML

<?xml version="1.0"?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
<!-- SPDX-License-Identifier: LGPL-2.1-or-later -->
<refentry id="systemd-report-sign-tpm2_.service"
xmlns:xi="http://www.w3.org/2001/XInclude"
conditional='ENABLE_REPORT HAVE_OPENSSL HAVE_TPM2'>
<refentryinfo>
<title>systemd-report-sign-tpm2@.service</title>
<productname>systemd</productname>
</refentryinfo>
<refmeta>
<refentrytitle>systemd-report-sign-tpm2@.service</refentrytitle>
<manvolnum>8</manvolnum>
</refmeta>
<refnamediv>
<refname>systemd-report-sign-tpm2@.service</refname>
<refname>systemd-report-sign-tpm2.socket</refname>
<refname>systemd-report-sign-tpm2</refname>
<refpurpose>Sign system reports with a set of signed TPM2 attestations</refpurpose>
</refnamediv>
<refsynopsisdiv>
<para><filename>systemd-report-sign-tpm2@.service</filename></para>
<para><filename>systemd-report-sign-tpm2.socket</filename></para>
<para><filename>/usr/lib/systemd/systemd-report-sign-tpm2</filename></para>
</refsynopsisdiv>
<refsect1>
<title>Description</title>
<para><command>systemd-report-sign-tpm2@.service</command> is a system service that signs system reports
generated by
<citerefentry><refentrytitle>systemd-report</refentrytitle><manvolnum>1</manvolnum></citerefentry>. It is
a signing backend for the <option>--sign=</option> logic of that tool: it implements the
<function>io.systemd.Report.Signer.Sign()</function> Varlink method and is reached via a socket linked into
the <filename>/run/systemd/report.sign/</filename> directory, named <filename>tpm2</filename>.</para>
<para>The service is socket-activated (one instance per connection) via
<filename>systemd-report-sign-tpm2.socket</filename>. Rather than returning a single signature, it uses a
TPM2 device to generate a set of signed attestations that also bind the report digest passed to it,
together providing a verifier with evidence about the state of the system that produced the report.</para>
<para>The returned report consists of several components. Some of these carry a JSON encoded attestation
structure (<constant>TPMS_ATTEST</constant>) and its corresponding signature. The signature is provided as
a JSON encoded <constant>TPMT_SIGNATURE</constant> structure and in PEM encoded form. The components are:</para>
<itemizedlist>
<listitem><para>A PCR quote, generated with <constant>TPM2_Quote</constant>. This contains the JSON
encoded attestation and the corresponding signature.</para></listitem>
<listitem><para>One attestation per NvPCR, generated with <constant>TPM2_NV_Certify</constant>. Each
of these contain the JSON encoded attestation structure and its signature. In addition to this, each
one also includes the readable name of the NvPCR, the NV index public area (as a JSON encoded
<constant>TPMS_NV_PUBLIC</constant> structure), and a JSON blob of authenticated data (the NvPCR name
and priority) that is digested and supplied as the qualifying data to the certify command.</para></listitem>
<listitem><para>A certification of the TPM's storage root key (SRK), generated with
<constant>TPM2_Certify</constant>. This contains the JSON encoded attestation and the corresponding
signature. The component also includes the public area of the SRK, as a JSON encoded
<constant>TPMT_PUBLIC</constant> structure. Marshalled into a <constant>TPM2B_PUBLIC</constant>
structure, this is the format accepted by the <option>--tpm2-device-key=</option> switch of
<citerefentry><refentrytitle>systemd-cryptenroll</refentrytitle><manvolnum>1</manvolnum></citerefentry>
and <citerefentry><refentrytitle>systemd-repart</refentrytitle><manvolnum>8</manvolnum></citerefentry>.
The certification proves to a verifier that the SRK resides in the same TPM as the attestation key,
so that secrets sealed to it, sealing to which requires no access to the TPM, can only be unsealed by
the reporting system. As <constant>TPM2_Clear</constant> replaces the SRK, a certification of the same
SRK in a later report is also evidence that the TPM has not been cleared in between. If no SRK exists
yet, one is created and persisted at the usual handle, which requires the authorization value of the
TPM's owner hierarchy to be empty. If the SRK cannot be acquired, or the object at its handle cannot
be authorized with an empty password, the report is generated without this component. The same applies
if the object lacks the <constant>noDA</constant> attribute, as a failed authorization attempt would
then count towards the TPM's dictionary attack protection. Checking that the attributes of the
certified key are those of a storage key that cannot leave the TPM is up to the verifier.</para></listitem>
<listitem><para>One component per reported TPM property, generated with <constant>TPM2_GetCapability</constant>.
Each of these contain the property and its value as a JSON encoded <constant>TPMS_TAGGED_PROPERTY</constant>
structure, as well as a boolean indicating the value of the <constant>moreData</constant> parameter returned
from the TPM. These components contain no signature of their own, but the response is included in the
audit session digest.</para></listitem>
<listitem><para>One component per reported TPM permanent handle authorization policy, generated with
<constant>TPM2_GetCapability</constant>. Each of these contain the handle, the policy digest algorithm,
and the policy digest (if the algorithm is not NULL) as a JSON encoded <constant>TPMS_TAGGED_POLICY</constant>
structure, as well as a boolean indicating the value of the <constant>moreData</constant> parameter
returned from the TPM. These components contain no signature of their own, but the response is included
in the audit session digest. Note that these components are omitted on TPMs that don't support
<constant>TPM_CAP_AUTH_POLICIES</constant>.</para></listitem>
<listitem><para>An audit session attestation, generated with
<constant>TPM2_GetSessionAuditDigest</constant>. This is always the last component. The report digest
passed in via Varlink is supplied as its qualifying data. All other components are generated using this
audit session.</para></listitem>
</itemizedlist>
<para>The report additionally includes the measurement event log, and the public area of the signing key.
The public area is provided as a JSON encoded <constant>TPMT_PUBLIC</constant> structure, and in PEM
encoded form.</para>
<para>The preceding components are all executed under the audit session, and the report is only generated
if that session remains exclusive throughout. Because the audit session attestation records whether the
session was still exclusive when it was signed, this provides evidence to a verifier that the report is a
single, consistent snapshot of the system, with no other TPM commands interleaved while it was
generated.</para>
<para>The set of attested PCRs, NvPCRs, TPM properties and permanent handle authorization policies is
currently fixed. It covers all firmware PCRs except PCR 6, all other S-RTM PCRs except the IMA PCR (which is
not useful without the IMA log), all defined NvPCRs, the TPM_PT_PERMANENT, TPM_PT_MAX_AUTH_FAIL,
TPM_PT_LOCKOUT_INTERVAL and TPM_PT_LOCKOUT_RECOVERY TPM properties, and the authorization policies for the
storage, endorsement and lockout hierarchies. Note that authorization policies are omitted on TPMs that
don't support <constant>TPM_CAP_AUTH_POLICIES</constant></para>
</refsect1>
<refsect1>
<title>Signing key</title>
<para>The attestation signing key is stored as a JSON file named <filename>default.key</filename> in
<filename>/var/lib/systemd/report.sign.tpm2/</filename>. Three kinds of key are supported: an ordinary
object protected by an existing persistent object such as the SRK or EK, a persistent object, and a
primary object that is recreated from a template on each use. In all cases the key must be a restricted
signing key. If no key exists, an ordinary key is generated automatically on first use.</para>
<para>For ordinary and primary keys, the loaded object context is cached in the service's runtime
directory as <filename>/run/systemd/report.sign.tpm2/default.context</filename> and reused on subsequent
invocations, avoiding a repeated <constant>TPM2_Load</constant> (which requires authorization with the
parent key) or primary key recreation.</para>
<para>The key may optionally have an associated <emphasis>voucher</emphasis>, stored alongside it as
<filename>default.voucher</filename>. This is an opaque credential — for example one issued by a CA during
onboarding — that is attached to the signed report and presented to a verifier as proof that the
attestation key is authentic. It is deliberately not required to be any particular format (such as an
X.509 certificate).</para>
</refsect1>
<!-- Note: we do not document the command line switches here. The systemd-report-sign-tpm2 binary itself
should not be invoked by users, but only as a service. Use systemd-report(1) to generate signed
reports. -->
<refsect1>
<title>See Also</title>
<para><simplelist type="inline">
<member><citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
<member><citerefentry><refentrytitle>systemd-report</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
</simplelist></para>
</refsect1>
</refentry>