1
0
mirror of https://github.com/systemd/systemd synced 2026-03-08 06:04:45 +01:00

Compare commits

..

No commits in common. "cad60201fc2621a0e327d83a9bf5259c196e4b14" and "450e0dce02d754d7af599dd99ab40b9363072760" have entirely different histories.

31 changed files with 120 additions and 584 deletions

2
README
View File

@ -204,8 +204,6 @@ REQUIREMENTS:
CONFIG_MEMCG
glibc >= 2.34
musl >= 1.2.5 with fde29c04adbab9d5b081bf6717b5458188647f1c
(required when building systemd with -Dlibc=musl)
libxcrypt >= 4.4.0 (optional)
libmount >= 2.30 (from util-linux)
(util-linux *must* be built without --enable-libmount-support-mtab)

22
TODO
View File

@ -720,6 +720,10 @@ Features:
deleting entries for rotation, place an event that declares how many items
have been dropped, and what the hash before and after that.
* measure information about all DDIs as we activate them to an NvPCR. We
probably should measure the dm-verity root hash from the kernel side, but
DDI meta info from userspace.
* use name_to_handle_at() with AT_HANDLE_FID instead of .st_ino (inode
number) for identifying inodes, for example in copy.c when finding hard
links, or loop-util.c for tracking backing files, and other places.
@ -1295,9 +1299,9 @@ Features:
- If run on every boot, should it use the sysupdate config from the host on
subsequent boots?
* To mimic the new tpm2-measure-pcr= crypttab option and tpm2-measure-nvpcr=
veritytab option, add the same to integritytab (measuring the HMAC key if one
is used)
* To mimic the new tpm2-measure-pcr= crypttab option add the same to veritytab
(measuring the root hash) and integritytab (measuring the HMAC key if one is
used)
* We should start measuring all services, containers, and system extensions we
activate. probably into PCR 13. i.e. add --tpm2-measure-pcr= or so to
@ -1716,6 +1720,18 @@ Features:
keys of /etc/crypttab. That way people can store/provide the roothash
externally and provide to us on demand only.
* we probably should extend the root verity hash of the root fs into some PCR
on boot. (i.e. maybe add a veritytab option tpm2-measure=12 or so to measure
it into PCR 12); Similar: we probably should extend the LUKS volume key of
the root fs into some PCR on boot. (i.e. maybe add a crypttab option
tpm2-measure=15 or so to measure it into PCR 15); once both are in place
update gpt-auto-discovery to generate these by default for the partitions it
discovers. Static vendor stuff should probably end up in PCR 12 (i.e. the
verity hash), with local keys in PCR 15 (i.e. the encryption volume
key). That way, we nicely distinguish resources supplied by the OS vendor
(i.e. sysext, root verity) from those inherently local (i.e. encryption key),
which is useful if they shall be signed separately.
* rework recursive read-only remount to use new mount API
* when mounting disk images: if IMAGE_ID/IMAGE_VERSION is set in os-release

View File

@ -945,12 +945,12 @@
<term><option>tpm2-measure-keyslot-nvpcr=</option></term>
<listitem><para>Controls whether to measure information about the used LUKS unlock keyslot to a TPM2
non-volatile index (nvindex in PCR mode). Takes a boolean argument, or an NvPCR name. If set to false
or an empty string (which is the default) no TPM2 nvindex extension is done, otherwise keyslot
information is measured to an nvindex of the specified name, which is allocated if needed. If set to
true the recommended default of <literal>cryptsetup</literal> is selected as NvPCR. The slot index
and the used unlock mechanism (i.e. <literal>tpm2</literal>, <literal>fido2</literal>,
<literal>pkcs11</literal>) are measured along with the activated volume name and its UUID.</para>
non-volatile index (nvindex in PCR mode). If set to to an empty string (which is the default) no TPM2
nvindex extension is done, otherwise keyslot information is measured to an nvindex of the specified
name, which is allocated if needed. It is recommended to set this to <literal>cryptsetup</literal> to
enable this logic. The slot index and the used unlock mechanism (i.e. <literal>tpm2</literal>,
<literal>fido2</literal>, <literal>pkcs11</literal>) is measured along with the activated volume name
and its UUID.</para>
<xi:include href="version-info.xml" xpointer="v259"/></listitem>
</varlistentry>

View File

@ -272,13 +272,9 @@
<para>If the system was booted via
<citerefentry><refentrytitle>systemd-stub</refentrytitle><manvolnum>7</manvolnum></citerefentry> and the
stub reported to userspace that the kernel image was measured to a TPM2 PCR, then any discovered root and
<filename>/var/</filename> volume identifiers (and volume encryption keys, in case they are encrypted)
will be automatically measured into PCR 15 on activation, via
<citerefentry><refentrytitle>systemd-pcrfs@.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>. Moreover,
information about the LUKS key slot used to unlock the volume is measured into NvPCR
<literal>cryptsetup</literal>. Finally, if the root or <filename>/usr/</filename> partition is protected
via Verity its root hash and the serial/issuer of the key used for the provided root hash signature (if
any) are measured into the NvPCR <literal>verity</literal>.</para>
<filename>/var/</filename> volume identifiers (and volume encryption key in case it is encrypted) will be
automatically measured into PCR 15 on activation, via
<citerefentry><refentrytitle>systemd-pcrfs@.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
<para>Mount constraint metadata contained in the file systems is validated by pulling in
<citerefentry><refentrytitle>systemd-validatefs@.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>

View File

@ -298,18 +298,6 @@ This is based on crypttab(5).
</listitem>
</varlistentry>
<varlistentry>
<term><option>tpm2-measure-nvpcr=</option></term>
<listitem><para>Takes a boolean argument, or an NvPCR name as argument. May be used to enable
automatic measurement of the volume name and Verity root hash, as well as the serials and issuers of
the certificates used to generate the provided signatures (if any) will be measured. Passing false
disables the mechanism. Passing true enables measurement into the <literal>verity</literal> NvPCR. If
any other string is specified this selects the NvPCR to measure into by name.</para>
<xi:include href="version-info.xml" xpointer="v260"/></listitem>
</varlistentry>
</variablelist>
<para>At early boot and when the system manager configuration is

View File

@ -6,11 +6,7 @@ KERNEL!="event*", GOTO="joystick_end"
# joystick:<bustype>:v<vid>p<pid>:name:<name>:*
KERNELS=="input*", ENV{ID_BUS}!="", \
IMPORT{builtin}="hwdb 'joystick:$env{ID_BUS}:v$attr{id/vendor}p$attr{id/product}:name:$attr{name}:'"
# Spread the hwdb override to ID_INTEGRATION, in the future we could remove the
# joystick hwdb entirely or retain it using the generic ID_INTEGRATION instead
# specific ID_INPUT_JOYSTICK_INTEGRATION.
ENV{ID_INPUT_JOYSTICK_INTEGRATION}!="", ENV{ID_INTEGRATION}="$env{ID_INPUT_JOYSTICK_INTEGRATION}"
IMPORT{builtin}="hwdb 'joystick:$env{ID_BUS}:v$attr{id/vendor}p$attr{id/product}:name:$attr{name}:'", \
GOTO="joystick_end"
LABEL="joystick_end"

View File

@ -1,16 +1,13 @@
# do not edit this file, it will be overwritten on update
ACTION=="remove", GOTO="touchpad_end"
ENV{ID_INPUT}=="", GOTO="touchpad_end"
ENV{ID_INPUT_TOUCHPAD}=="", GOTO="touchpad_end"
KERNEL!="event*", GOTO="touchpad_end"
# touchpad:<subsystem>:v<vid>p<pid>:name:<name>:*
KERNELS=="input*", ENV{ID_BUS}!="", \
IMPORT{builtin}="hwdb 'touchpad:$env{ID_BUS}:v$attr{id/vendor}p$attr{id/product}:name:$attr{name}:'"
# Spread the hwdb override to ID_INTEGRATION, in the future we could remove the
# touchpad hwdb entirely or retain it using the generic ID_INTEGRATION instead
# specific ID_INPUT_TOUCHPAD_INTEGRATION.
ENV{ID_INPUT_TOUCHPAD_INTEGRATION}!="", ENV{ID_INTEGRATION}="$env{ID_INPUT_TOUCHPAD_INTEGRATION}"
IMPORT{builtin}="hwdb 'touchpad:$env{ID_BUS}:v$attr{id/vendor}p$attr{id/product}:name:$attr{name}:'", \
GOTO="touchpad_end"
LABEL="touchpad_end"

View File

@ -557,14 +557,12 @@ static int parse_one_option(const char *option) {
} else if ((val = startswith(option, "tpm2-measure-keyslot-nvpcr="))) {
r = isempty(val) ? false : parse_boolean(val);
if (r == 0) {
if (isempty(val)) {
arg_tpm2_measure_keyslot_nvpcr = mfree(arg_tpm2_measure_keyslot_nvpcr);
return 0;
}
if (r > 0)
val = "cryptsetup";
else if (!tpm2_nvpcr_name_is_valid(val)) {
if (!tpm2_nvpcr_name_is_valid(val)) {
log_warning("Invalid NvPCR name, ignoring: %s", option);
return 0;
}
@ -1097,9 +1095,8 @@ static int measure_keyslot(
const char *mechanism,
int keyslot) {
#if HAVE_TPM2
int r;
#endif
assert(cd);
assert(name);
@ -1108,7 +1105,6 @@ static int measure_keyslot(
return 0;
}
#if HAVE_TPM2
r = efi_measured_uki(LOG_WARNING);
if (r < 0)
return r;
@ -1117,6 +1113,7 @@ static int measure_keyslot(
return 0;
}
#if HAVE_TPM2
_cleanup_(tpm2_context_unrefp) Tpm2Context *c = NULL;
r = tpm2_context_new_or_warn(arg_tpm2_device, &c);
if (r < 0)

View File

@ -127,7 +127,7 @@ static int add_cryptsetup(
* assignment, under the assumption that people who are fine to use sd-stub with its PCR
* assignments are also OK with our PCR 15 use here. */
if (r > 0)
if (!strextend_with_separator(&options, ",", "tpm2-measure-pcr=yes,tpm2-measure-keyslot-nvpcr=yes"))
if (!strextend_with_separator(&options, ",", "tpm2-measure-pcr=yes,tpm2-measure-keyslot-nvpcr=cryptsetup"))
return log_oom();
if (r == 0)
log_debug("Will not measure volume key of volume '%s', not booted via systemd-stub with measurements enabled.", id);
@ -190,8 +190,7 @@ static int add_veritysetup(
const char *id,
const char *data_what,
const char *hash_what,
const char *mount_opts,
MountPointFlags flags) {
const char *mount_opts) {
#if HAVE_LIBCRYPTSETUP
int r;
@ -234,26 +233,13 @@ static int add_veritysetup(
"After=%1$s %2$s\n",
dd, dh);
_cleanup_free_ char *options =
strdup("root-hash-signature=auto"); /* auto means: derive signature from udev property ID_DISSECT_PART_ROOTHASH_SIG */
if (!options)
return log_oom();
if (FLAGS_SET(flags, MOUNT_MEASURE)) {
r = efi_measured_uki(LOG_WARNING);
if (r > 0 && !strextend_with_separator(&options, ",", "tpm2-measure-nvpcr=yes"))
return log_oom();
if (r == 0)
log_debug("Will not measure root hash/signature of volume '%s', not booted via systemd-stub with measurements enabled.", id);
}
r = generator_write_veritysetup_service_section(
f,
id,
data_what,
hash_what,
/* roothash= */ NULL, /* NULL means: derive root hash from udev property ID_DISSECT_PART_ROOTHASH */
options);
"root-hash-signature=auto"); /* auto means: derive signature from udev property ID_DISSECT_PART_ROOTHASH_SIG */
if (r < 0)
return r;
@ -885,8 +871,7 @@ static int add_root_mount(void) {
"root",
"/dev/disk/by-designator/root-verity-data",
"/dev/disk/by-designator/root-verity",
arg_root_options,
MOUNT_MEASURE);
arg_root_options);
if (r < 0)
return r;
}
@ -967,8 +952,7 @@ static int add_usr_mount(void) {
"usr",
"/dev/disk/by-designator/usr-verity-data",
"/dev/disk/by-designator/usr-verity",
arg_usr_options,
MOUNT_MEASURE);
arg_usr_options);
if (r < 0)
return r;
}

View File

@ -369,7 +369,6 @@ typedef struct MethodExtendParameters {
const char *nvpcr;
const char *text;
struct iovec data;
Tpm2UserspaceEventType event_type;
} MethodExtendParameters;
static void method_extend_parameters_done(MethodExtendParameters *p) {
@ -378,21 +377,17 @@ static void method_extend_parameters_done(MethodExtendParameters *p) {
iovec_done(&p->data);
}
static JSON_DISPATCH_ENUM_DEFINE(json_dispatch_tpm2_userspace_event_type, Tpm2UserspaceEventType, tpm2_userspace_event_type_from_string);
static int vl_method_extend(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
static const sd_json_dispatch_field dispatch_table[] = {
{ "pcr", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint, offsetof(MethodExtendParameters, pcr), 0 },
{ "nvpcr", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(MethodExtendParameters, nvpcr), 0 },
{ "text", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(MethodExtendParameters, text), 0 },
{ "data", SD_JSON_VARIANT_STRING, json_dispatch_unbase64_iovec, offsetof(MethodExtendParameters, data), 0 },
{ "eventType", SD_JSON_VARIANT_STRING, json_dispatch_tpm2_userspace_event_type, offsetof(MethodExtendParameters, event_type), 0 },
{ "pcr", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint, offsetof(MethodExtendParameters, pcr), 0 },
{ "nvpcr", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(MethodExtendParameters, nvpcr), 0 },
{ "text", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(MethodExtendParameters, text), 0 },
{ "data", SD_JSON_VARIANT_STRING, json_dispatch_unbase64_iovec, offsetof(MethodExtendParameters, data), 0 },
{}
};
_cleanup_(method_extend_parameters_done) MethodExtendParameters p = {
.pcr = UINT_MAX,
.event_type = _TPM2_USERSPACE_EVENT_TYPE_INVALID,
};
int r;
@ -429,11 +424,11 @@ static int vl_method_extend(sd_varlink *link, sd_json_variant *parameters, sd_va
return sd_varlink_error_invalid_parameter_name(link, "text");
if (p.nvpcr) {
r = extend_nvpcr_now(p.nvpcr, extend_iovec->iov_base, extend_iovec->iov_len, p.event_type);
r = extend_nvpcr_now(p.nvpcr, extend_iovec->iov_base, extend_iovec->iov_len, _TPM2_USERSPACE_EVENT_TYPE_INVALID);
if (r == -ENOENT)
return sd_varlink_error(link, "io.systemd.PCRExtend.NoSuchNvPCR", NULL);
} else
r = extend_pcr_now(p.pcr, extend_iovec->iov_base, extend_iovec->iov_len, p.event_type);
r = extend_pcr_now(p.pcr, extend_iovec->iov_base, extend_iovec->iov_len, _TPM2_USERSPACE_EVENT_TYPE_INVALID);
if (r < 0)
return r;

View File

@ -60,7 +60,6 @@
#include "openssl-util.h"
#include "os-util.h"
#include "path-util.h"
#include "pcrextend-util.h"
#include "pidref.h"
#include "proc-cmdline.h"
#include "process-util.h"
@ -3220,13 +3219,13 @@ static int do_crypt_activate_verity(
DissectImageFlags flags,
PartitionPolicyFlags policy_flags) {
int r;
bool check_signature;
int r, k;
assert(cd);
assert(name);
assert(verity);
bool check_signature;
if (iovec_is_set(&verity->root_hash_sig) && FLAGS_SET(policy_flags, PARTITION_POLICY_SIGNED)) {
r = secure_getenv_bool("SYSTEMD_DISSECT_VERITY_SIGNATURE");
if (r < 0 && r != -ENXIO)
@ -3236,10 +3235,7 @@ static int do_crypt_activate_verity(
} else
check_signature = false;
bool measure_signature;
if (check_signature) {
int k;
/* First, if we have support for signed keys in the kernel, then try that first. */
r = sym_crypt_activate_by_signed_key(
cd,
@ -3251,8 +3247,7 @@ static int do_crypt_activate_verity(
CRYPT_ACTIVATE_READONLY);
if (r >= 0) {
log_debug("Verity activation via kernel signature logic worked.");
measure_signature = true;
goto done;
return 0;
}
log_debug_errno(r, "Validation of dm-verity signature failed via the kernel, trying userspace validation instead: %m");
@ -3285,13 +3280,9 @@ static int do_crypt_activate_verity(
/* Otherwise let's see what signature-less activation results in. */
measure_signature = true;
} else if (!FLAGS_SET(policy_flags, PARTITION_POLICY_VERITY))
return log_debug_errno(SYNTHETIC_ERRNO(ERFKILL),
"No-signature activation of Verity volume not allowed by policy, refusing.");
else
measure_signature = false;
r = sym_crypt_activate_by_volume_key(
cd,
@ -3303,12 +3294,6 @@ static int do_crypt_activate_verity(
return log_debug_errno(r, "Activation of Verity via root hash failed: %m");
log_debug("Activation of Verity via root hash succeeded.");
done:
(void) pcrextend_verity_now(
name,
&verity->root_hash,
measure_signature ? &verity->root_hash_sig : NULL);
return 0;
}

View File

@ -152,7 +152,6 @@ shared_sources = files(
'pcre2-util.c',
'pcrextend-util.c',
'pe-binary.c',
'pkcs7-util.c',
'pkcs11-util.c',
'plymouth-util.c',
'polkit-agent.c',

View File

@ -2,7 +2,6 @@
#include "sd-device.h"
#include "sd-id128.h"
#include "sd-varlink.h"
#include "alloc-util.h"
#include "blkid-util.h"
@ -11,13 +10,10 @@
#include "errno-util.h"
#include "escape.h"
#include "fd-util.h"
#include "hexdecoct.h"
#include "id128-util.h"
#include "iovec-util.h"
#include "log.h"
#include "mountpoint-util.h"
#include "pcrextend-util.h"
#include "pkcs7-util.h"
#include "string-util.h"
#include "strv.h"
@ -184,110 +180,3 @@ int pcrextend_product_id_word(char **ret) {
*ret = TAKE_PTR(word);
return 0;
}
int pcrextend_verity_word(
const char *name,
const struct iovec *root_hash,
const struct iovec *root_hash_sig,
char **ret) {
int r;
assert(name);
assert(iovec_is_set(root_hash));
_cleanup_free_ char *name_escaped = xescape(name, ":"); /* Avoid ambiguity around ":" */
if (!name_escaped)
return log_oom();
_cleanup_free_ char *h = hexmem(root_hash->iov_base, root_hash->iov_len);
if (!h)
return log_oom();
_cleanup_free_ char *sigs = NULL;
if (iovec_is_set(root_hash_sig)) {
size_t n_signers = 0;
Signer *signers = NULL;
/* Let's extract the X.509 issuer + serial number from the PKCS#7 signature and include that
* in the measurement record. This is useful since it allows us to have different signing
* keys for confext + sysext + other types of DDIs, and by means of this information we can
* discern which kind it was. Ideally, we'd measure the fingerprint of the X.509 certificate,
* but typically that's not available in a PKCS#7 signature. */
CLEANUP_ARRAY(signers, n_signers, signer_free_many);
r = pkcs7_extract_signers(root_hash_sig, &signers, &n_signers);
if (r < 0)
return r;
FOREACH_ARRAY(i, signers, n_signers) {
_cleanup_free_ char *serial = hexmem(i->serial.iov_base, i->serial.iov_len);
if (!serial)
return log_oom();
_cleanup_free_ char *issuer = NULL;
if (base64mem(i->issuer.iov_base, i->issuer.iov_len, &issuer) < 0)
return log_oom();
if (strextendf_with_separator(&sigs, ",", "%s/%s", serial, issuer) < 0)
return log_oom();
}
}
_cleanup_free_ char *word = strjoin("verity:", name_escaped, ":", h, ":", strempty(sigs));
if (!word)
return log_oom();
*ret = TAKE_PTR(word);
return 0;
}
int pcrextend_verity_now(
const char *name,
const struct iovec *root_hash,
const struct iovec *root_hash_sig) {
#if HAVE_TPM2
int r;
_cleanup_free_ char *word = NULL;
r = pcrextend_verity_word(
name,
root_hash,
root_hash_sig,
&word);
if (r < 0)
return r;
_cleanup_free_ sd_varlink *vl = NULL;
r = sd_varlink_connect_address(&vl, "/run/systemd/io.systemd.PCRExtend");
if (r < 0)
return r;
_cleanup_(sd_json_variant_unrefp) sd_json_variant *reply = NULL;
const char *error_id = NULL;
r = sd_varlink_callbo(
vl,
"io.systemd.PCRExtend.Extend",
/* ret_reply= */ NULL,
&error_id,
SD_JSON_BUILD_PAIR_STRING("nvpcr", "verity"),
SD_JSON_BUILD_PAIR_STRING("text", word),
SD_JSON_BUILD_PAIR_STRING("eventType", "dm_verity"));
if (r < 0)
return log_debug_errno(r, "Failed to issue io.systemd.PCRExtend.Extend() varlink call: %m");
if (error_id) {
r = sd_varlink_error_to_errno(error_id, reply);
if (r != -EBADR)
return log_debug_errno(r, "Failed to issue io.systemd.PCRExtend.Extend() varlink call: %m");
return log_debug_errno(r, "Failed to issue io.systemd.PCRExtend.Extend() varlink call: %s", error_id);
}
log_debug("Measurement of '%s' into 'images' NvPCR completed.", word);
return 1;
#else
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "TPM2 support disabled, not measuring Verity root hashes and signatures.");
#endif
}

View File

@ -4,6 +4,3 @@
int pcrextend_file_system_word(const char *path, char **ret, char **ret_normalized_path);
int pcrextend_machine_id_word(char **ret);
int pcrextend_product_id_word(char **ret);
int pcrextend_verity_word(const char *name, const struct iovec *root_hash, const struct iovec *root_hash_sig, char **ret);
int pcrextend_verity_now(const char *name, const struct iovec *root_hash,const struct iovec *root_hash_sig);

View File

@ -243,7 +243,7 @@ int pe_read_section_data_by_name(
assert(fd >= 0);
assert(pe_header);
assert(sections || le16toh(pe_header->pe.NumberOfSections) == 0);
assert(sections || pe_header->pe.NumberOfSections == 0);
assert(name);
section = pe_header_find_section(pe_header, sections, name);
@ -408,9 +408,9 @@ int pe_hash(int fd,
return r;
/* Sort by location in file */
typesafe_qsort(sections, le16toh(pe_header->pe.NumberOfSections), section_offset_cmp);
typesafe_qsort(sections, pe_header->pe.NumberOfSections, section_offset_cmp);
FOREACH_ARRAY(section, sections, le16toh(pe_header->pe.NumberOfSections)) {
FOREACH_ARRAY(section, sections, pe_header->pe.NumberOfSections) {
r = hash_file(fd, mdctx, section->PointerToRawData, section->SizeOfRawData);
if (r < 0)
return r;
@ -537,7 +537,7 @@ int uki_hash(int fd,
if (hsz < 0)
return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to get hash size.");
FOREACH_ARRAY(section, sections, le16toh(pe_header->pe.NumberOfSections)) {
FOREACH_ARRAY(section, sections, pe_header->pe.NumberOfSections) {
_cleanup_(EVP_MD_CTX_freep) EVP_MD_CTX *mdctx = NULL;
_cleanup_free_ char *n = NULL;
ssize_t i;

View File

@ -1,84 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "alloc-util.h"
#include "openssl-util.h"
#include "pkcs7-util.h"
#include "log.h"
#define SIGNERS_MAX 32
static void signer_done(Signer *signer) {
assert(signer);
iovec_done(&signer->issuer);
iovec_done(&signer->serial);
}
void signer_free_many(Signer *signers, size_t n) {
assert(signers || n == 0);
FOREACH_ARRAY(i, signers, n)
signer_done(i);
free(signers);
}
int pkcs7_extract_signers(
const struct iovec *sig,
Signer **ret_signers,
size_t *ret_n_signers) {
assert(ret_signers);
assert(ret_n_signers);
if (!iovec_is_set(sig))
return -EBADMSG;
#if HAVE_OPENSSL
const unsigned char *d = sig->iov_base;
_cleanup_(PKCS7_freep) PKCS7 *p7 = NULL;
p7 = d2i_PKCS7(/* a= */ NULL, &d, (long) sig->iov_len);
if (!p7)
return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG), "Failed to parse PKCS7 DER signature data.");
STACK_OF(PKCS7_SIGNER_INFO) *sinfos = PKCS7_get_signer_info(p7);
if (!sinfos)
return log_debug_errno(SYNTHETIC_ERRNO(ENODATA), "No signature information in PKCS7 signature?");
int n = sk_PKCS7_SIGNER_INFO_num(sinfos);
if (n == 0)
return log_debug_errno(SYNTHETIC_ERRNO(ENODATA), "No signatures in PKCS7 signature, refusing.");
if (n > SIGNERS_MAX) /* safety net, in case people send us weirdly complex signatures */
return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG), "Too many signatures, refusing.");
assert(n > 0);
size_t n_signers = 0;
Signer *signers = new(Signer, n);
if (!signers)
return log_oom_debug();
CLEANUP_ARRAY(signers, n_signers, signer_free_many);
for (int i = 0; i < n; i++) {
PKCS7_SIGNER_INFO *si = sk_PKCS7_SIGNER_INFO_value(PKCS7_get_signer_info(p7), i);
if (!si)
return log_debug_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to get signer information.");
_cleanup_(signer_done) Signer signer = {};
_cleanup_free_ unsigned char *p = NULL;
int len = i2d_X509_NAME(si->issuer_and_serial->issuer, &p);
signer.issuer = IOVEC_MAKE(TAKE_PTR(p), len);
len = i2d_ASN1_INTEGER(si->issuer_and_serial->serial, &p);
signer.serial = IOVEC_MAKE(TAKE_PTR(p), len);
signers[n_signers++] = TAKE_STRUCT(signer);
}
*ret_signers = TAKE_PTR(signers);
*ret_n_signers = n_signers;
return n;
#else
return -EOPNOTSUPP;
#endif
}

View File

@ -1,16 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <sys/uio.h>
typedef struct Signer {
struct iovec issuer;
struct iovec serial;
} Signer;
void signer_free_many(Signer *signers, size_t n);
int pkcs7_extract_signers(
const struct iovec *sig,
Signer **ret_signers,
size_t *ret_n_signers);

View File

@ -6478,7 +6478,6 @@ static const char* tpm2_userspace_event_type_table[_TPM2_USERSPACE_EVENT_TYPE_MA
[TPM2_EVENT_KEYSLOT] = "keyslot",
[TPM2_EVENT_NVPCR_INIT] = "nvpcr-init",
[TPM2_EVENT_NVPCR_SEPARATOR] = "nvpcr-separator",
[TPM2_EVENT_DM_VERITY] = "dm-verity",
};
DEFINE_STRING_TABLE_LOOKUP(tpm2_userspace_event_type, Tpm2UserspaceEventType);

View File

@ -145,7 +145,6 @@ typedef enum Tpm2UserspaceEventType {
TPM2_EVENT_KEYSLOT,
TPM2_EVENT_NVPCR_INIT,
TPM2_EVENT_NVPCR_SEPARATOR,
TPM2_EVENT_DM_VERITY,
_TPM2_USERSPACE_EVENT_TYPE_MAX,
_TPM2_USERSPACE_EVENT_TYPE_INVALID = -EINVAL,
} Tpm2UserspaceEventType;

View File

@ -2,18 +2,6 @@
#include "varlink-io.systemd.PCRExtend.h"
static SD_VARLINK_DEFINE_ENUM_TYPE(
EventType,
SD_VARLINK_DEFINE_ENUM_VALUE(phase),
SD_VARLINK_DEFINE_ENUM_VALUE(filesystem),
SD_VARLINK_DEFINE_ENUM_VALUE(volume_key),
SD_VARLINK_DEFINE_ENUM_VALUE(machine_id),
SD_VARLINK_DEFINE_ENUM_VALUE(product_id),
SD_VARLINK_DEFINE_ENUM_VALUE(keyslot),
SD_VARLINK_DEFINE_ENUM_VALUE(nvpcr_init),
SD_VARLINK_DEFINE_ENUM_VALUE(nvpcr_separator),
SD_VARLINK_DEFINE_ENUM_VALUE(dm_verity));
static SD_VARLINK_DEFINE_METHOD(
Extend,
SD_VARLINK_FIELD_COMMENT("PCR number to extend, in range of 0…23. Either this or 'nvpcr' must be specified, not both, not neither."),
@ -23,9 +11,7 @@ static SD_VARLINK_DEFINE_METHOD(
SD_VARLINK_FIELD_COMMENT("Text string to measure. (Specify either this, or the 'data' field below, not both)"),
SD_VARLINK_DEFINE_INPUT(text, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Binary data to measure, encoded in Base64. (Specify either this, or the 'text' field above, not both)"),
SD_VARLINK_DEFINE_INPUT(data, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Event type to include in the (userspace) event log). This is optional, and mostly for debugging."),
SD_VARLINK_DEFINE_INPUT_BY_TYPE(eventType, EventType, SD_VARLINK_NULLABLE));
SD_VARLINK_DEFINE_INPUT(data, SD_VARLINK_STRING, SD_VARLINK_NULLABLE));
static SD_VARLINK_DEFINE_ERROR(NoSuchNvPCR);
@ -35,6 +21,4 @@ SD_VARLINK_DEFINE_INTERFACE(
SD_VARLINK_INTERFACE_COMMENT("TPM PCR Extension APIs"),
SD_VARLINK_SYMBOL_COMMENT("Measure some text or binary data into a PCR"),
&vl_method_Extend,
SD_VARLINK_SYMBOL_COMMENT("Event type to store in event log"),
&vl_type_EventType,
&vl_error_NoSuchNvPCR);

View File

@ -9,20 +9,6 @@
#include "string-util.h"
#include "sysupdate-partition.h"
/* App-specific IDs used as HMAC keys to derive "partial" and "pending" partition type UUIDs from the
* original partition type UUID. This way we can indicate sysupdate transfer state via a separate GPT
* partition type UUID instead of using a label prefix, saving precious label space. */
#define GPT_SYSUPDATE_PARTIAL_APP_ID SD_ID128_MAKE(ac,cf,a0,c2,da,24,46,0a,9f,c9,0b,b8,fc,78,52,19)
#define GPT_SYSUPDATE_PENDING_APP_ID SD_ID128_MAKE(80,f3,d6,1e,23,83,43,b9,81,f5,ce,37,93,f4,7d,4c)
int gpt_partition_type_uuid_for_sysupdate_partial(sd_id128_t type, sd_id128_t *ret) {
return sd_id128_get_app_specific(type, GPT_SYSUPDATE_PARTIAL_APP_ID, ret);
}
int gpt_partition_type_uuid_for_sysupdate_pending(sd_id128_t type, sd_id128_t *ret) {
return sd_id128_get_app_specific(type, GPT_SYSUPDATE_PENDING_APP_ID, ret);
}
void partition_info_destroy(PartitionInfo *p) {
assert(p);
@ -256,22 +242,6 @@ int patch_partition(
return log_error_errno(r, "Failed to update partition UUID: %m");
}
if (change & PARTITION_TYPE) {
_cleanup_(fdisk_unref_parttypep) struct fdisk_parttype *pt = NULL;
pt = fdisk_new_parttype();
if (!pt)
return log_oom();
r = fdisk_parttype_set_typestr(pt, SD_ID128_TO_UUID_STRING(info->type));
if (r < 0)
return log_error_errno(r, "Failed to initialize partition type: %m");
r = fdisk_partition_set_type(pa, pt);
if (r < 0)
return log_error_errno(r, "Failed to update partition type: %m");
}
type = gpt_partition_type_from_uuid(info->type);
/* Tweak the read-only flag, but only if supported by the partition type */

View File

@ -12,8 +12,7 @@ typedef enum PartitionChange {
PARTITION_GROWFS = 1 << 3,
PARTITION_UUID = 1 << 4,
PARTITION_LABEL = 1 << 5,
PARTITION_TYPE = 1 << 6,
_PARTITION_CHANGE_MAX = (1 << 7) - 1, /* all of the above */
_PARTITION_CHANGE_MAX = (1 << 6) - 1, /* all of the above */
_PARTITION_CHANGE_INVALID = -EINVAL,
} PartitionChange;
@ -41,8 +40,5 @@ int partition_info_copy(PartitionInfo *dest, const PartitionInfo *src);
int read_partition_info(struct fdisk_context *c, struct fdisk_table *t, size_t i, PartitionInfo *ret);
int gpt_partition_type_uuid_for_sysupdate_partial(sd_id128_t type, sd_id128_t *ret);
int gpt_partition_type_uuid_for_sysupdate_pending(sd_id128_t type, sd_id128_t *ret);
int find_suitable_partition(const char *device, uint64_t space, sd_id128_t *partition_type, PartitionInfo *ret);
int patch_partition(const char *device, const PartitionInfo *info, PartitionChange change);

View File

@ -31,7 +31,6 @@
#include "strv.h"
#include "sysupdate-cache.h"
#include "sysupdate-instance.h"
#include "sysupdate-partition.h"
#include "sysupdate-pattern.h"
#include "sysupdate-resource.h"
#include "time-util.h"
@ -245,7 +244,9 @@ static int resource_load_from_blockdev(Resource *rr) {
_cleanup_(instance_metadata_destroy) InstanceMetadata extracted_fields = INSTANCE_METADATA_NULL;
_cleanup_(partition_info_destroy) PartitionInfo pinfo = PARTITION_INFO_NULL;
Instance *instance;
const char *pinfo_label_stripped;
bool is_partial = false, is_pending = false;
const char *stripped;
r = read_partition_info(c, t, i, &pinfo);
if (r < 0)
@ -253,28 +254,9 @@ static int resource_load_from_blockdev(Resource *rr) {
if (r == 0) /* not assigned */
continue;
/* Check if partition type matches, either directly or via derived partial/pending type
* UUIDs. The derived UUIDs are computed from the configured partition type by hashing it
* with a fixed app-specific ID, so we can detect the state without relying on label
* prefixes. */
if (rr->partition_type_set) {
sd_id128_t partial_type, pending_type;
r = gpt_partition_type_uuid_for_sysupdate_partial(rr->partition_type.uuid, &partial_type);
if (r < 0)
return log_error_errno(r, "Failed to derive partial partition type UUID: %m");
r = gpt_partition_type_uuid_for_sysupdate_pending(rr->partition_type.uuid, &pending_type);
if (r < 0)
return log_error_errno(r, "Failed to derive pending partition type UUID: %m");
if (sd_id128_equal(pinfo.type, partial_type))
is_partial = true;
else if (sd_id128_equal(pinfo.type, pending_type))
is_pending = true;
else if (!sd_id128_equal(pinfo.type, rr->partition_type.uuid))
continue;
}
/* Check if partition type matches */
if (rr->partition_type_set && !sd_id128_equal(pinfo.type, rr->partition_type.uuid))
continue;
/* A label of "_empty" means "not used so far" for us */
if (streq_ptr(pinfo.label, "_empty")) {
@ -282,7 +264,18 @@ static int resource_load_from_blockdev(Resource *rr) {
continue;
}
r = pattern_match_many(rr->patterns, pinfo.label, &extracted_fields);
/* Match the label with any partial/pending prefix removed so the users existing patterns
* match regardless of the instances state. */
if ((stripped = startswith(pinfo.label, "PRT#"))) {
pinfo_label_stripped = stripped;
is_partial = true;
} else if ((stripped = startswith(pinfo.label, "PND#"))) {
pinfo_label_stripped = stripped;
is_pending = true;
} else
pinfo_label_stripped = pinfo.label;
r = pattern_match_many(rr->patterns, pinfo_label_stripped, &extracted_fields);
if (r < 0)
return log_error_errno(r, "Failed to match pattern: %m");
if (IN_SET(r, PATTERN_MATCH_NO, PATTERN_MATCH_RETRY))

View File

@ -67,6 +67,8 @@ Transfer* transfer_free(Transfer *t) {
strv_free(t->appstream);
partition_info_destroy(&t->partition_info);
free(t->temporary_partial_partition_label);
free(t->temporary_pending_partition_label);
free(t->final_partition_label);
resource_destroy(&t->source);
@ -764,21 +766,12 @@ static int transfer_instance_vacuum(
case RESOURCE_PARTITION: {
PartitionInfo pinfo = instance->partition_info;
PartitionChange change = PARTITION_LABEL;
/* label "_empty" means "no contents" for our purposes */
pinfo.label = (char*) "_empty";
/* If the partition had a derived partial/pending type UUID, restore the original
* partition type so that the slot is properly recognized as empty in subsequent
* scans. */
if ((instance->is_partial || instance->is_pending) && t->target.partition_type_set) {
pinfo.type = t->target.partition_type.uuid;
change |= PARTITION_TYPE;
}
log_debug("Resetting partition '%s' to empty.", pinfo.device);
r = patch_partition(t->target.path, &pinfo, change);
log_debug("Relabelling partition '%s' to '%s'.", pinfo.device, pinfo.label);
r = patch_partition(t->target.path, &pinfo, PARTITION_LABEL);
if (r < 0)
return r;
@ -1179,7 +1172,7 @@ static int run_callout(
* and pending instances which are about to be installed (in which case, transfer_acquire_instance() is
* skipped). */
int transfer_compute_temporary_paths(Transfer *t, Instance *i, InstanceMetadata *f) {
_cleanup_free_ char *formatted_pattern = NULL;
_cleanup_free_ char *formatted_pattern = NULL, *formatted_partial_pattern = NULL, *formatted_pending_pattern = NULL;
int r;
assert(t);
@ -1189,6 +1182,8 @@ int transfer_compute_temporary_paths(Transfer *t, Instance *i, InstanceMetadata
assert(!t->temporary_partial_path);
assert(!t->temporary_pending_path);
assert(!t->final_partition_label);
assert(!t->temporary_partial_partition_label);
assert(!t->temporary_pending_partition_label);
assert(!strv_isempty(t->target.patterns));
/* Format the target name using the first pattern specified */
@ -1239,18 +1234,25 @@ int transfer_compute_temporary_paths(Transfer *t, Instance *i, InstanceMetadata
if (!r)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Formatted pattern is not suitable as GPT partition label, refusing: %s", formatted_pattern);
if (!t->target.partition_type_set)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Partition type must be set for partition targets.");
/* Derive temporary partition type UUIDs for partial/pending states from the configured
* partition type. This avoids the need for label prefixes. */
r = gpt_partition_type_uuid_for_sysupdate_partial(t->target.partition_type.uuid, &t->partition_type_partial);
if (!strprepend(&formatted_partial_pattern, "PRT#", formatted_pattern))
return log_oom();
r = gpt_partition_label_valid(formatted_partial_pattern);
if (r < 0)
return log_error_errno(r, "Failed to derive partial partition type UUID: %m");
return log_error_errno(r, "Failed to determine if formatted pattern is suitable as GPT partition label: %s", formatted_partial_pattern);
if (!r)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Formatted pattern is not suitable as GPT partition label, refusing: %s", formatted_partial_pattern);
r = gpt_partition_type_uuid_for_sysupdate_pending(t->target.partition_type.uuid, &t->partition_type_pending);
free_and_replace(t->temporary_partial_partition_label, formatted_partial_pattern);
if (!strprepend(&formatted_pending_pattern, "PND#", formatted_pattern))
return log_oom();
r = gpt_partition_label_valid(formatted_pending_pattern);
if (r < 0)
return log_error_errno(r, "Failed to derive pending partition type UUID: %m");
return log_error_errno(r, "Failed to determine if formatted pattern is suitable as GPT partition label: %s", formatted_pending_pattern);
if (!r)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Formatted pattern is not suitable as GPT partition label, refusing: %s", formatted_pending_pattern);
free_and_replace(t->temporary_pending_partition_label, formatted_pending_pattern);
t->final_partition_label = TAKE_PTR(formatted_pattern);
}
@ -1310,18 +1312,13 @@ int transfer_acquire_instance(Transfer *t, Instance *i, InstanceMetadata *f, Tra
where = t->partition_info.device;
/* Set the partition label and change the partition type to the derived "partial" type UUID
* to indicate that a transfer to it is in progress. */
r = free_and_strdup_warn(&t->partition_info.label, t->final_partition_label);
/* Rename the partition to `PRT#<VERSION>` to indicate that a transfer to it is in progress. */
r = free_and_strdup_warn(&t->partition_info.label, t->temporary_partial_partition_label);
if (r < 0)
return r;
t->partition_info.type = t->partition_type_partial;
t->partition_change = PARTITION_LABEL | PARTITION_TYPE;
t->partition_change = PARTITION_LABEL;
log_debug("Marking partition '%s' as partial (label='%s', type=%s).",
t->partition_info.device,
t->partition_info.label,
SD_ID128_TO_UUID_STRING(t->partition_info.type));
log_debug("Relabelling partition '%s' to '%s'.", t->partition_info.device, t->partition_info.label);
r = patch_partition(
t->target.path,
&t->partition_info,
@ -1548,10 +1545,12 @@ int transfer_acquire_instance(Transfer *t, Instance *i, InstanceMetadata *f, Tra
}
if (t->target.type == RESOURCE_PARTITION) {
/* Now change the partition type to the derived "pending" type UUID to indicate that the
* acquire is complete and the partition is ready for install. */
t->partition_info.type = t->partition_type_pending;
t->partition_change = PARTITION_TYPE;
/* Now rename the partition again to `PND#<VERSION>` to indicate that the acquire is complete
* and the partition is ready for install. */
r = free_and_strdup_warn(&t->partition_info.label, t->temporary_pending_partition_label);
if (r < 0)
return r;
t->partition_change = PARTITION_LABEL;
if (f->partition_uuid_set) {
t->partition_info.uuid = f->partition_uuid;
@ -1578,9 +1577,7 @@ int transfer_acquire_instance(Transfer *t, Instance *i, InstanceMetadata *f, Tra
t->partition_change |= PARTITION_GROWFS;
}
log_debug("Marking partition '%s' as pending (type=%s).",
t->partition_info.device,
SD_ID128_TO_UUID_STRING(t->partition_info.type));
log_debug("Relabelling partition '%s' to '%s'.", t->partition_info.device, t->partition_info.label);
r = patch_partition(
t->target.path,
&t->partition_info,
@ -1620,7 +1617,7 @@ int transfer_process_partial_and_pending_instance(Transfer *t, Instance *i) {
/* This is the analogue of find_suitable_partition(), but since finding the suitable partition has
* already happened in the acquire phase, the target should already have that information and it
* should already have been claimed with the pending partition type UUID. */
* should already have been claimed as `PND#`. */
if (t->target.type == RESOURCE_PARTITION) {
assert(i->resource == &t->target);
assert(i->is_pending);
@ -1668,17 +1665,14 @@ int transfer_install_instance(
t->temporary_pending_path = mfree(t->temporary_pending_path);
}
if (t->final_partition_label) {
if (t->temporary_pending_partition_label) {
assert(t->target.type == RESOURCE_PARTITION);
assert(t->target.partition_type_set);
assert(t->final_partition_label);
r = free_and_strdup_warn(&t->partition_info.label, t->final_partition_label);
if (r < 0)
return r;
/* Restore the original partition type UUID now that the partition is fully installed. */
t->partition_info.type = t->target.partition_type.uuid;
t->partition_change = PARTITION_LABEL | PARTITION_TYPE;
t->partition_change = PARTITION_LABEL;
r = patch_partition(
t->target.path,

View File

@ -48,11 +48,8 @@ typedef struct Transfer {
PartitionInfo partition_info;
PartitionChange partition_change;
char *final_partition_label;
/* Derived partition type UUIDs used to indicate partial/pending state on the partition type level,
* instead of polluting the partition label with prefixes */
sd_id128_t partition_type_partial;
sd_id128_t partition_type_pending;
char *temporary_partial_partition_label;
char *temporary_pending_partition_label;
Context *context;
} Transfer;

View File

@ -405,11 +405,6 @@ executables += [
'dependencies' : libopenssl,
'conditions' : ['HAVE_OPENSSL'],
},
test_template + {
'sources' : files('test-pkcs7-util.c'),
'dependencies' : libopenssl,
'conditions' : ['HAVE_OPENSSL'],
},
test_template + {
'sources' : files('test-parse-util.c'),
'dependencies' : libm,

View File

@ -1,55 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "hexdecoct.h"
#include "iovec-util.h"
#include "pkcs7-util.h"
#include "tests.h"
TEST(pkcs7_extract_signers) {
const char tsig[] =
"MIIEgwYJKoZIhvcNAQcCoIIEdDCCBHACAQExDzANBglghkgBZQMEAgEFADALBgkqhkiG9w0BBwGgggLp"
"MIIC5TCCAc2gAwIBAgIURlvlj5ak0ZhvNS8hENNKwVv60x0wDQYJKoZIhvcNAQELBQAwGzEZMBcGA1UE"
"AwwQbWtvc2kgb2YgbGVubmFydDAeFw0yNTAyMDMxMTAwMjNaFw0yNzAyMDMxMTAwMjNaMBsxGTAXBgNV"
"BAMMEG1rb3NpIG9mIGxlbm5hcnQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCldQdmHVgU"
"m4saaSqEpF1EVRf9pcIxpVShROBGAbxpxs4BQ7vV7zCg5bXwEVaqaENlIyzqPAj+YQifQS3Dj6LQfH3i"
"War+ciKAv4PYcESG+pcdBb2kJOS8cVD6abZlO9rInvdhXK6PhYF7VohMwMPj/yJYdO50skwA5OQsCHO6"
"amowh0tVzNzpbaJZg6wWIyTf3+ZzZdnOl5EvBCaUqeUhbaxRV9SrAw51rzAOnndUhW1we/vVKEGAPk3c"
"SCb0LLPBG20XX2C00UXgnCWBkU5rkq6BnWSuInhFKCa48avstIet1ZFBA5T5J83ncU9UOVFksEYBXFoc"
"lzcmcbx/2/oFAgMBAAGjITAfMB0GA1UdDgQWBBQewILFCixwq2rejOvJqmZSug2BBDANBgkqhkiG9w0B"
"AQsFAAOCAQEAIvaeNPaJUoIUN5lQC/kcCiKeys96WNRGL2wbTp5PqdnRw14sbWY5iC2z13ih3dmTI9NF"
"TBa7C/ji+5BaAfiJF17LOV00Y8eP5V94fHz4isb0sv5RzLsE4h8X7QFk4JBdV5GiCDzPXjxQAx9kM2so"
"9RGtL8EhHpNygYDgyZ18YeiwcUPkCXT+xG2rM6s/Xlsji0s/18ycI4G8AC8dj5HycyS9BiZHgKrkgqTb"
"VPo4zHYzhZdh0Qrd0J4YpoaotzQ35bkH9PtIkF6C7mE1Z7uMSGFkGQASgJ0BDTpM8QPAf2HIR2xxEtJR"
"ZXkwxxdC+W9AJAzqJldmCHYGSrSR54J0rDGCAV4wggFaAgEBMDMwGzEZMBcGA1UEAwwQbWtvc2kgb2Yg"
"bGVubmFydAIURlvlj5ak0ZhvNS8hENNKwVv60x0wDQYJYIZIAWUDBAIBBQAwDQYJKoZIhvcNAQEBBQAE"
"ggEAXccqvpiEWsz/xvuLhINVZKIOznVdqjkERbZSqCBK94BYESSd+cijaB4XbYaFUZ45Bb3uUDQ56Ojq"
"WoY1elEfqPyCb4vc887QoHmxI0BtdIaHhIDfCGBxhX8fwMknxqjgFa9YvONmDtv4QG4syTw+U3SEqBaa"
"Avftqaa4v4eLk4uZ0nMIgMkx4qOlaxknpP404/nyZPANkOIwDxviNtRBCN9zSiPSqo1zre1vqzaM57Ww"
"8zJASsPEzNR7OsPoLaIZv2OHXpowsRB78TuXGkQnm74T6xdG6DNs24jTYJuCPfGuYLHbrytdhXpFBS6m"
"Orz9715jK2NU5VvGhNVXX4chcw==";
_cleanup_free_ void *sig = NULL;
size_t siglen;
ASSERT_OK(unbase64mem(tsig, &sig, &siglen));
size_t n_signers = 0;
Signer *signers = NULL;
CLEANUP_ARRAY(signers, n_signers, signer_free_many);
ASSERT_OK_EQ(pkcs7_extract_signers(&IOVEC_MAKE(sig, siglen), &signers, &n_signers), 1);
ASSERT_EQ(n_signers, 1U);
ASSERT_EQ(signers[0].issuer.iov_len, 29U);
ASSERT_EQ(signers[0].serial.iov_len, 22U);
_cleanup_free_ char *issuer = NULL;
ASSERT_OK(base64mem(signers[0].issuer.iov_base, signers[0].issuer.iov_len, &issuer));
_cleanup_free_ char *serial = NULL;
ASSERT_OK(base64mem(signers[0].serial.iov_base, signers[0].serial.iov_len, &serial));
ASSERT_STREQ(issuer, "MBsxGTAXBgNVBAMMEG1rb3NpIG9mIGxlbm5hcnQ=");
ASSERT_STREQ(serial, "AhRGW+WPlqTRmG81LyEQ00rBW/rTHQ==");
}
DEFINE_TEST_MAIN(LOG_INFO);

View File

@ -31,12 +31,12 @@ executables += [
'HAVE_TPM2',
],
},
]
if conf.get('ENABLE_BOOTLOADER') == 1 and conf.get('HAVE_OPENSSL') == 1 and conf.get('HAVE_TPM2') == 1
nvpcrs = [ 'cryptsetup',
'hardware',
'verity']
'hardware' ]
foreach n : nvpcrs
custom_target(
input : 'nvpcr/' + n + '.nvpcr.in',

View File

@ -1,5 +0,0 @@
{
"name" : "verity",
"algorithm" : "sha256",
"nvIndex" : {{TPM2_NVPCR_BASE + 2}}
}

View File

@ -16,11 +16,9 @@
#include "main-func.h"
#include "parse-util.h"
#include "path-util.h"
#include "pcrextend-util.h"
#include "pretty-print.h"
#include "string-util.h"
#include "strv.h"
#include "tpm2-util.h"
#include "verbs.h"
static char *arg_hash = NULL; /* the hash algorithm */
@ -40,14 +38,12 @@ static uint64_t arg_fec_roots = 2;
static void *arg_root_hash_signature = NULL;
static size_t arg_root_hash_signature_size = 0;
static bool arg_root_hash_signature_auto = false;
static char *arg_tpm2_measure_nvpcr = NULL;
STATIC_DESTRUCTOR_REGISTER(arg_hash, freep);
STATIC_DESTRUCTOR_REGISTER(arg_salt, freep);
STATIC_DESTRUCTOR_REGISTER(arg_uuid, freep);
STATIC_DESTRUCTOR_REGISTER(arg_fec_what, freep);
STATIC_DESTRUCTOR_REGISTER(arg_root_hash_signature, freep);
STATIC_DESTRUCTOR_REGISTER(arg_tpm2_measure_nvpcr, freep);
static int help(void) {
_cleanup_free_ char *link = NULL;
@ -146,7 +142,7 @@ static int parse_options(const char *options) {
for (;;) {
_cleanup_free_ char *word = NULL;
const char *val;
char *val;
r = extract_first_word(&options, &word, ",", EXTRACT_DONT_COALESCE_SEPARATORS | EXTRACT_UNESCAPE_SEPARATORS);
if (r < 0)
@ -294,21 +290,6 @@ static int parse_options(const char *options) {
if (r < 0)
return r;
} else if ((val = startswith(word, "tpm2-measure-nvpcr="))) {
r = isempty(val) ? 0 : parse_boolean(val);
if (r == 0) {
arg_tpm2_measure_nvpcr = mfree(arg_tpm2_measure_nvpcr);
return 0;
}
if (r > 0)
val = "verity";
else if (!tpm2_nvpcr_name_is_valid(val)) {
log_warning("Invalid NvPCR name, ignoring: %s", word);
return 0;
}
if (free_and_strdup(&arg_tpm2_measure_nvpcr, val) < 0)
return log_oom();
} else
log_warning("Encountered unknown option '%s', ignoring.", word);
}
@ -442,11 +423,6 @@ static int verb_attach(int argc, char *argv[], void *userdata) {
if (r < 0)
return log_error_errno(r, "Failed to set up verity device '%s': %m", volume);
(void) pcrextend_verity_now(
volume,
&IOVEC_MAKE(rh, rh_size),
&IOVEC_MAKE(arg_root_hash_signature, arg_root_hash_signature_size));
return 0;
}

View File

@ -20,8 +20,7 @@ at_exit() {
jq --seq --slurp </run/log/systemd/tpm2-measure.log
fi
rm -rf /run/nvpcr /tmp/nvpcr
rm -f /var/tmp/nvpcr.raw /run/verity.d/test-79-nvpcr.crt
rm -rf /run/nvpcr
}
trap at_exit EXIT
@ -53,46 +52,3 @@ test "$DIGEST_ACTUAL2" != "$DIGEST_EXPECTED"
DIGEST_MEASURED2="$(echo -n "schnurz" | openssl dgst -sha256 -hex -r | cut -d' ' -f1)"
DIGEST_EXPECTED2="$(echo "$DIGEST_EXPECTED$DIGEST_MEASURED2" | tr '[:lower:]' '[:upper:]' | basenc --base16 -d | openssl dgst -sha256 -hex -r | cut -d' ' -f1)"
test "$DIGEST_ACTUAL2" = "$DIGEST_EXPECTED2"
mkdir /tmp/nvpcr
OPENSSL_CONFIG="/tmp/nvpcr/opensslconfig"
# Unfortunately OpenSSL insists on reading some config file, hence provide one with mostly placeholder contents
cat >"${OPENSSL_CONFIG:?}" <<EOF
[ req ]
prompt = no
distinguished_name = req_distinguished_name
[ req_distinguished_name ]
C = DE
ST = Test State
L = Test Locality
O = Org Name
OU = Org Unit Name
CN = Common Name
emailAddress = test@email.com
EOF
openssl req -config "$OPENSSL_CONFIG" -subj="/CN=waldo" \
-x509 -sha256 -nodes -days 365 -newkey rsa:4096 \
-keyout /tmp/nvpcr/test-70-nvpcr.key -out /tmp/nvpcr/test-70-nvpcr.crt
mkdir /tmp/nvpcr/tree
touch /tmp/nvpcr/tree/file
SYSTEMD_REPART_OVERRIDE_FSTYPE=squashfs \
systemd-repart -P \
-s /tmp/nvpcr/tree \
--certificate=/tmp/nvpcr/test-70-nvpcr.crt \
--private-key=/tmp/nvpcr/test-70-nvpcr.key \
/var/tmp/nvpcr.raw
mkdir -p /run/verity.d
cp /tmp/nvpcr/test-70-nvpcr.crt /run/verity.d/
cp /run/log/systemd/tpm2-measure.log /tmp/nvpcr/log-before
systemd-dissect --image-policy='root=signed:=absent+unused' --mtree /var/tmp/nvpcr.raw
set +o pipefail
diff /tmp/nvpcr/log-before /run/log/systemd/tpm2-measure.log | grep -F '"content":{"nvIndexName":"verity","string":"verity:'