mirror of
https://github.com/systemd/systemd.git
synced 2026-11-06 05:17:24 +00:00
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.
152 lines
9.7 KiB
XML
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>
|