mirror of
https://github.com/systemd/systemd
synced 2026-04-25 16:34:50 +02:00
Compare commits
26 Commits
7d40544643
...
ebf3ee4105
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ebf3ee4105 | ||
|
|
f4bdbae725 | ||
|
|
947914cb44 | ||
|
|
fe43a638c5 | ||
|
|
b6553329c0 | ||
|
|
571d829ee4 | ||
|
|
7cac4a2e2d | ||
|
|
b9b156ea3c | ||
|
|
47a9f91760 | ||
|
|
8b82513375 | ||
|
|
5a560d4cc3 | ||
|
|
2a86ed67ed | ||
|
|
9dbfcaf229 | ||
|
|
146f4482b2 | ||
|
|
072f5f9b18 | ||
|
|
e4e1353c25 | ||
|
|
bb60956b39 | ||
|
|
056a18e465 | ||
|
|
63ec7a8490 | ||
|
|
c399ed923d | ||
|
|
55bfacc6c3 | ||
|
|
6a7ca27740 | ||
|
|
c2d7dd35d2 | ||
|
|
b21f237d99 | ||
|
|
c8431e9e35 | ||
|
|
6dd18b34cf |
30
TODO
30
TODO
@ -78,6 +78,14 @@ Janitorial Clean-ups:
|
||||
|
||||
Features:
|
||||
|
||||
* sd-event: compat wd reuse in inotify code: keep a set of removed watch
|
||||
descriptors, and clear this set piecemeal when we see the IN_IGNORED event
|
||||
for it, or when read() returns EAGAIN or on IN_Q_OVERFLOW. Then, whenever we
|
||||
see an inotify wd event check against this set, and if it is contained ignore
|
||||
the event. (to be fully correct this would have to count the occurances, in
|
||||
case the same wd is reused multiple times before we start processing
|
||||
IN_IGNORED again)
|
||||
|
||||
* sd-stub: set efi var indicating stub features, i.e. whether they pick up
|
||||
creds, sysexts and so on. similar to existing variable of sd-boot
|
||||
|
||||
@ -106,12 +114,6 @@ Features:
|
||||
- sd-stub: automatically pick up microcode from ESP (/loader/microcode/*)
|
||||
and synthesize initrd from it, and measure it. Signing is not necessary, as
|
||||
microcode does that on its own. Pass as first initrd to kernel.
|
||||
- systemd-creds should have a fallback logic that uses neither TPM nor the
|
||||
system key in /var for encryption and instead some fixed key. This should
|
||||
be opt in (since it provides no security properties) but be used by
|
||||
kernel-install when encrypting the creds it generates on systems that lack
|
||||
a TPM, so that we can have very similar codepaths on TPM and TPM-less
|
||||
systems. i.e. --with-key=tpm-graceful or so.
|
||||
- sd-stub should measure the kernel/initrd/… into a separate PCR, so that we
|
||||
have one PCR we can bind the encrypted creds to that is not effected by
|
||||
anything else but what we drop in via kernel-install, i.e. by earlier EFI
|
||||
@ -194,6 +196,22 @@ Features:
|
||||
as directory manifest. The file would be a standard directory listing as
|
||||
generated by GNU sha256sums.
|
||||
|
||||
* sd-boot: maybe add support for embedding the various auxiliary resources we
|
||||
look for right in the sd-boot binary. i.e. take inspiration from sd-stub
|
||||
logic: allow combining sd-boot via objcopy with kernels to enumerate, .conf
|
||||
files, drivers, keys to enroll and so on. Then, add whatever we find that way
|
||||
to the menu. Usecase: allow building a single PE image you can boot into via
|
||||
UEFI HTTP boot.
|
||||
|
||||
* maybe add a new UEFI stub binary "sd-http". It works similar to sd-stub, but
|
||||
all it does is download a file from a http server, and execute it, after
|
||||
optionally checking its hash sum. idea would be: combine this "sd-http" stub
|
||||
binary with some minimal info about an URL + hash sum, plus .osrel data, and
|
||||
drop it into the unified kernel dir in the ESP. And bam you have something
|
||||
that is tiny, feels a lot like a unified kernel, but all it does is chainload
|
||||
the real kernel. benefit: downloading these stubs would be tiny and quick,
|
||||
hence cheap for enumeration.
|
||||
|
||||
* initialize machine ID from systemd credential picked up from the ESP via
|
||||
sd-stub, so that machine ID is stable even on systems where unified kernels
|
||||
are used, and hence kernel cmdline cannot be modified locally
|
||||
|
||||
@ -263,23 +263,32 @@
|
||||
<term><option>-H</option></term>
|
||||
<term><option>-T</option></term>
|
||||
|
||||
<listitem><para>When specified with the <command>encrypt</command> command controls the encryption
|
||||
key to use. Takes one of <literal>host</literal>, <literal>tpm2</literal>,
|
||||
<literal>host+tpm2</literal> or <literal>auto</literal>. See above for details on the three key
|
||||
types. If set to <literal>auto</literal> (which is the default) the TPM2 key is used if a TPM2 device
|
||||
is found and not running in a container. The host key is used if
|
||||
<filename>/var/lib/systemd/</filename> is on persistent media. This means on typical systems the
|
||||
encryption is by default bound to both the TPM2 chip and the OS installation, and both need to be
|
||||
available to decrypt the credential again. If <literal>auto</literal> is selected but neither TPM2 is
|
||||
available (or running in container) nor <filename>/var/lib/systemd/</filename> is on persistent
|
||||
media, encryption will fail.</para>
|
||||
<listitem><para>When specified with the <command>encrypt</command> command controls the
|
||||
encryption/signature key to use. Takes one of <literal>host</literal>, <literal>tpm2</literal>,
|
||||
<literal>host+tpm2</literal>, <literal>tpm2-absent</literal>, <literal>auto</literal>,
|
||||
<literal>auto-initrd</literal>. See above for details on the three key types. If set to
|
||||
<literal>auto</literal> (which is the default) the TPM2 key is used if a TPM2 device is found and not
|
||||
running in a container. The host key is used if <filename>/var/lib/systemd/</filename> is on
|
||||
persistent media. This means on typical systems the encryption is by default bound to both the TPM2
|
||||
chip and the OS installation, and both need to be available to decrypt the credential again. If
|
||||
<literal>auto</literal> is selected but neither TPM2 is available (or running in container) nor
|
||||
<filename>/var/lib/systemd/</filename> is on persistent media, encryption will fail. If set to
|
||||
<literal>tpm2-absent</literal> a fixed zero length key is used (thus, in this mode no confidentiality
|
||||
nor authenticity are provided!). This logic is useful to cover for systems that lack a TPM2 chip but
|
||||
where credentials shall be generated. Note that decryption of such credentials is refused on systems
|
||||
that have a TPM2 chip and where UEFI SecureBoot is enabled (this is done so that such a locked down
|
||||
system cannot be tricked into loading a credential generated this way that lacks authentication
|
||||
information). If set to <literal>auto-initrd</literal> a TPM2 key is used if a TPM2 is found. If not
|
||||
a fixed zero length key is used, equivalent to <literal>tpm2-absent</literal> mode. This option is
|
||||
particularly useful to generate credentials files that are encrypted/authenticated against TPM2 where
|
||||
available but still work on systems lacking support for this.</para>
|
||||
|
||||
<para>The <option>-H</option> switch is a shortcut for <option>--with-key=host</option>. Similar,
|
||||
<option>-T</option> is a shortcut for <option>--with-key=tpm2</option>.</para>
|
||||
|
||||
<para>When encrypting credentials that shall be used in the initial RAM disk (initrd) where
|
||||
<filename>/var/lib/systemd/</filename> is typically not available make sure to use
|
||||
<option>--with-key=tpm2</option> mode, to disable binding against the host secret.</para>
|
||||
<option>--with-key=auto-initrd</option> mode, to disable binding against the host secret.</para>
|
||||
|
||||
<para>This switch has no effect on the <command>decrypt</command> command, as information on which
|
||||
key to use for decryption is included in the encrypted credential already.</para></listitem>
|
||||
|
||||
@ -251,7 +251,7 @@
|
||||
|
||||
<row>
|
||||
<entry>4</entry>
|
||||
<entry>Boot loader; changes on boot loader updates. The shim project will measure the PE binary it chain loads into this PCR.</entry>
|
||||
<entry>Boot loader and additional drivers; changes on boot loader updates. The shim project will measure the PE binary it chain loads into this PCR. If the Linux kernel is invoked as UEFI PE binary, it is measured here, too. <citerefentry><refentrytitle>sd-stub</refentrytitle><manvolnum>7</manvolnum></citerefentry> measures system extension images read from the ESP here too (see <citerefentry><refentrytitle>systemd-sysext</refentrytitle><manvolnum>8</manvolnum></citerefentry>).</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
@ -273,8 +273,9 @@
|
||||
<!-- Grub measures all files it reads (including kernel image, initrd, …) into PCR 9… -->
|
||||
|
||||
<row>
|
||||
<entry>12</entry>
|
||||
<entry><citerefentry><refentrytitle>sd-boot</refentrytitle><manvolnum>7</manvolnum></citerefentry> measures the kernel command line into this PCR.</entry>
|
||||
<entry>9</entry>
|
||||
<entry>The Linux kernel measures all initial RAM file systems it receives into this PCR.</entry>
|
||||
<!-- Strictly speaking only Linux >= 5.17 using the LOAD_FILE2 protocol, see https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=f046fff8bc4c4d8f8a478022e76e40b818f692df -->
|
||||
</row>
|
||||
|
||||
<row>
|
||||
@ -282,6 +283,11 @@
|
||||
<entry>The IMA project measures its runtime state into this PCR.</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>12</entry>
|
||||
<entry><citerefentry><refentrytitle>systemd-boot</refentrytitle><manvolnum>7</manvolnum></citerefentry> measures any specified kernel command line into this PCR. <citerefentry><refentrytitle>systemd-stub</refentrytitle><manvolnum>7</manvolnum></citerefentry> measures any manually specified kernel command line (i.e. a kernel command line that overrides the one embedded in the unified PE image) and loaded credentials into this PCR. (Note that if <command>sytemd-boot</command> and <command>systemd-stub</command> are used in combination the command line might be measured twice!)</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>14</entry>
|
||||
<entry>The shim project measures its "MOK" certificates and hashes into this PCR.</entry>
|
||||
|
||||
@ -70,7 +70,7 @@
|
||||
image, any attempts to override the kernel command line by passing one as invocation parameters to the
|
||||
EFI binary are ignored. Thus, in order to allow overriding the kernel command line, either disable UEFI
|
||||
SecureBoot, or don't include a kernel command line PE section in the kernel image file. If a command line
|
||||
is accepted via EFI invocation parameters to the EFI binary it is measured into TPM PCR 8 (if a TPM is
|
||||
is accepted via EFI invocation parameters to the EFI binary it is measured into TPM PCR 12 (if a TPM is
|
||||
present).</para>
|
||||
|
||||
<para>If a DeviceTree is embedded in the <literal>.dtb</literal> section, it replaces an existing
|
||||
@ -100,7 +100,7 @@
|
||||
<citerefentry><refentrytitle>systemd-creds</refentrytitle><manvolnum>1</manvolnum></citerefentry>
|
||||
for
|
||||
details on encrypted credentials. The generated <command>cpio</command> archive is measured into TPM
|
||||
PCR 4 (if a TPM is present).</para></listitem>
|
||||
PCR 12 (if a TPM is present).</para></listitem>
|
||||
|
||||
<listitem><para>Similarly, files <filename><replaceable>foo</replaceable>.efi.extra.d/*.raw</filename>
|
||||
are packed up in a <command>cpio</command> archive and placed in the <filename>/.extra/sysext/</filename>
|
||||
@ -108,13 +108,13 @@
|
||||
images to the initrd. See
|
||||
<citerefentry><refentrytitle>systemd-sysext</refentrytitle><manvolnum>8</manvolnum></citerefentry> for
|
||||
details on system extension images. The generated <command>cpio</command> archive containing these
|
||||
system extension images is measured into TPM PCR 8 (if a TPM is present).</para></listitem>
|
||||
system extension images is measured into TPM PCR 4 (if a TPM is present).</para></listitem>
|
||||
|
||||
<listitem><para>Files <filename>/loader/credentials/*.cred</filename> are packed up in a
|
||||
<command>cpio</command> archive and placed in the <filename>/.extra/global_credentials/</filename>
|
||||
directory of the initrd file hierarchy. This is supposed to be used to pass additional credentials to
|
||||
the initrd, regardless of the kernel being booted. The generated <command>cpio</command> archive is
|
||||
measured into TPM PCR 4 (if a TPM is present)</para></listitem>
|
||||
measured into TPM PCR 12 (if a TPM is present)</para></listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>These mechanisms may be used to parameterize and extend trusted (i.e. signed), immutable initrd
|
||||
@ -125,6 +125,78 @@
|
||||
details); in case of the system extension images by using signed Verity images.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>TPM2 PCR Notes</title>
|
||||
|
||||
<para>Note that when a unified kernel using <command>systemd-stub</command> is invoked the firmware will
|
||||
measure it as a whole to TPM PCR 4, covering all embedded resources, such as the stub code itself, the
|
||||
core kernel, the embedded initrd and kernel command line (see above for a full list).</para>
|
||||
|
||||
<para>Also note that the Linux kernel will measure all initrds it receives into TPM PCR 9. This means
|
||||
every type of initrd will be measured twice: the initrd embedded in the kernel image will be measured to
|
||||
both PCR 4 and PCR 9; the initrd synthesized from credentials will be measured to both PCR 12 and PCR 9;
|
||||
the initrd synthesized from system extensions will be measured to both PCR 4 and PCR 9. Let's summarize
|
||||
the OS resources and the PCRs they are measured to:</para>
|
||||
|
||||
<table>
|
||||
<title>OS Resource PCR Summary</title>
|
||||
|
||||
<tgroup cols='2' align='left' colsep='1' rowsep='1'>
|
||||
<colspec colname="pcr" />
|
||||
<colspec colname="definition" />
|
||||
|
||||
<thead>
|
||||
<row>
|
||||
<entry>OS Resource</entry>
|
||||
<entry>Measurement PCR</entry>
|
||||
</row>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<row>
|
||||
<entry><command>systemd-stub</command> code (the entry point of the unified PE binary)</entry>
|
||||
<entry>4</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>Boot splash (embedded in the unified PE binary)</entry>
|
||||
<entry>4</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>Core kernel code (embedded in unified PE binary)</entry>
|
||||
<entry>4</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>Main initrd (embedded in unified PE binary)</entry>
|
||||
<entry>4 + 9</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>Default kernel command line (embedded in unified PE binary)</entry>
|
||||
<entry>4</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>Overriden kernel command line</entry>
|
||||
<entry>12</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>Credentials (synthesized initrd from companion files)</entry>
|
||||
<entry>12 + 9</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>System Extensions (synthesized initrd from companion files)</entry>
|
||||
<entry>4 + 9</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>EFI Variables</title>
|
||||
|
||||
|
||||
@ -155,7 +155,7 @@ int readlink_malloc(const char *p, char **ret) {
|
||||
}
|
||||
|
||||
int readlink_value(const char *p, char **ret) {
|
||||
_cleanup_free_ char *link = NULL;
|
||||
_cleanup_free_ char *link = NULL, *name = NULL;
|
||||
int r;
|
||||
|
||||
assert(p);
|
||||
@ -165,7 +165,14 @@ int readlink_value(const char *p, char **ret) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return path_extract_filename(link, ret);
|
||||
r = path_extract_filename(link, &name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == O_DIRECTORY)
|
||||
return -EINVAL;
|
||||
|
||||
*ret = TAKE_PTR(name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int readlink_and_make_absolute(const char *p, char **r) {
|
||||
|
||||
@ -396,8 +396,12 @@ static inline int __coverity_check_and_return__(int condition) {
|
||||
if (!p) \
|
||||
return NULL; \
|
||||
\
|
||||
assert(p->n_ref > 0); \
|
||||
p->n_ref++; \
|
||||
/* For type check. */ \
|
||||
unsigned *q = &p->n_ref; \
|
||||
assert(*q > 0); \
|
||||
assert(*q < UINT_MAX); \
|
||||
\
|
||||
(*q)++; \
|
||||
return p; \
|
||||
}
|
||||
|
||||
|
||||
@ -1162,3 +1162,30 @@ bool streq_skip_trailing_chars(const char *s1, const char *s2, const char *ok) {
|
||||
|
||||
return in_charset(s1, ok) && in_charset(s2, ok);
|
||||
}
|
||||
|
||||
char *string_replace_char(char *str, char old_char, char new_char) {
|
||||
assert(str);
|
||||
assert(old_char != '\0');
|
||||
assert(new_char != '\0');
|
||||
assert(old_char != new_char);
|
||||
|
||||
for (char *p = strchr(str, old_char); p; p = strchr(p + 1, old_char))
|
||||
*p = new_char;
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
size_t strspn_from_end(const char *str, const char *accept) {
|
||||
size_t n = 0;
|
||||
|
||||
if (isempty(str))
|
||||
return 0;
|
||||
|
||||
if (isempty(accept))
|
||||
return 0;
|
||||
|
||||
for (const char *p = str + strlen(str); p > str && strchr(accept, p[-1]); p--)
|
||||
n++;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
@ -233,3 +233,7 @@ static inline int string_contains_word(const char *string, const char *separator
|
||||
}
|
||||
|
||||
bool streq_skip_trailing_chars(const char *s1, const char *s2, const char *ok);
|
||||
|
||||
char *string_replace_char(char *str, char old_char, char new_char);
|
||||
|
||||
size_t strspn_from_end(const char *str, const char *accept);
|
||||
|
||||
@ -40,7 +40,7 @@ static bool arg_legend = true;
|
||||
static bool arg_system = false;
|
||||
static TranscodeMode arg_transcode = TRANSCODE_OFF;
|
||||
static int arg_newline = -1;
|
||||
static sd_id128_t arg_with_key = SD_ID128_NULL;
|
||||
static sd_id128_t arg_with_key = _CRED_AUTO;
|
||||
static const char *arg_tpm2_device = NULL;
|
||||
static uint32_t arg_tpm2_pcr_mask = UINT32_MAX;
|
||||
static const char *arg_name = NULL;
|
||||
@ -560,7 +560,7 @@ static int verb_help(int argc, char **argv, void *userdata) {
|
||||
" --timestamp=TIME Include specified timestamp in encrypted credential\n"
|
||||
" --not-after=TIME Include specified invalidation time in encrypted\n"
|
||||
" credential\n"
|
||||
" --with-key=host|tpm2|host+tpm2|auto\n"
|
||||
" --with-key=host|tpm2|host+tpm2|tpm2-absent|auto|auto-initrd\n"
|
||||
" Which keys to encrypt with\n"
|
||||
" -H Shortcut for --with-key=host\n"
|
||||
" -T Shortcut for --with-key=tpm2\n"
|
||||
@ -684,13 +684,17 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
|
||||
case ARG_WITH_KEY:
|
||||
if (isempty(optarg) || streq(optarg, "auto"))
|
||||
arg_with_key = SD_ID128_NULL;
|
||||
arg_with_key = _CRED_AUTO;
|
||||
else if (streq(optarg, "auto-initrd"))
|
||||
arg_with_key = _CRED_AUTO_INITRD;
|
||||
else if (streq(optarg, "host"))
|
||||
arg_with_key = CRED_AES256_GCM_BY_HOST;
|
||||
else if (streq(optarg, "tpm2"))
|
||||
arg_with_key = CRED_AES256_GCM_BY_TPM2_HMAC;
|
||||
else if (STR_IN_SET(optarg, "host+tpm2", "tpm2+host"))
|
||||
arg_with_key = CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC;
|
||||
else if (streq(optarg, "tpm2-absent"))
|
||||
arg_with_key = CRED_AES256_GCM_BY_TPM2_ABSENT;
|
||||
else
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown key type: %s", optarg);
|
||||
|
||||
|
||||
@ -40,7 +40,6 @@ struct sd_bus_track {
|
||||
"arg0='", name, "'")
|
||||
|
||||
static struct track_item* track_item_free(struct track_item *i) {
|
||||
|
||||
if (!i)
|
||||
return NULL;
|
||||
|
||||
@ -49,7 +48,8 @@ static struct track_item* track_item_free(struct track_item *i) {
|
||||
return mfree(i);
|
||||
}
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(struct track_item*, track_item_free);
|
||||
DEFINE_PRIVATE_TRIVIAL_REF_UNREF_FUNC(struct track_item, track_item, track_item_free);
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(struct track_item*, track_item_unref);
|
||||
DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(track_item_hash_ops, char, string_hash_func, string_compare_func,
|
||||
struct track_item, track_item_free);
|
||||
|
||||
@ -165,13 +165,13 @@ DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_bus_track, sd_bus_track, track_free);
|
||||
|
||||
static int on_name_owner_changed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||
sd_bus_track *track = userdata;
|
||||
const char *name, *old, *new;
|
||||
const char *name;
|
||||
int r;
|
||||
|
||||
assert(message);
|
||||
assert(track);
|
||||
|
||||
r = sd_bus_message_read(message, "sss", &name, &old, &new);
|
||||
r = sd_bus_message_read(message, "sss", &name, NULL, NULL);
|
||||
if (r < 0)
|
||||
return 0;
|
||||
|
||||
@ -180,7 +180,7 @@ static int on_name_owner_changed(sd_bus_message *message, void *userdata, sd_bus
|
||||
}
|
||||
|
||||
_public_ int sd_bus_track_add_name(sd_bus_track *track, const char *name) {
|
||||
_cleanup_(track_item_freep) struct track_item *n = NULL;
|
||||
_cleanup_(track_item_unrefp) struct track_item *n = NULL;
|
||||
struct track_item *i;
|
||||
const char *match;
|
||||
int r;
|
||||
@ -190,14 +190,8 @@ _public_ int sd_bus_track_add_name(sd_bus_track *track, const char *name) {
|
||||
|
||||
i = hashmap_get(track->names, name);
|
||||
if (i) {
|
||||
if (track->recursive) {
|
||||
unsigned k = track->n_ref + 1;
|
||||
|
||||
if (k < track->n_ref) /* Check for overflow */
|
||||
return -EOVERFLOW;
|
||||
|
||||
track->n_ref = k;
|
||||
}
|
||||
if (track->recursive)
|
||||
track_item_ref(i);
|
||||
|
||||
bus_track_remove_from_queue(track);
|
||||
return 0;
|
||||
@ -207,9 +201,14 @@ _public_ int sd_bus_track_add_name(sd_bus_track *track, const char *name) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
n = new0(struct track_item, 1);
|
||||
n = new(struct track_item, 1);
|
||||
if (!n)
|
||||
return -ENOMEM;
|
||||
|
||||
*n = (struct track_item) {
|
||||
.n_ref = 1,
|
||||
};
|
||||
|
||||
n->name = strdup(name);
|
||||
if (!n->name)
|
||||
return -ENOMEM;
|
||||
@ -241,8 +240,7 @@ _public_ int sd_bus_track_add_name(sd_bus_track *track, const char *name) {
|
||||
return r;
|
||||
}
|
||||
|
||||
n->n_ref = 1;
|
||||
n = NULL;
|
||||
TAKE_PTR(n);
|
||||
|
||||
bus_track_remove_from_queue(track);
|
||||
track->modified = true;
|
||||
@ -258,20 +256,16 @@ _public_ int sd_bus_track_remove_name(sd_bus_track *track, const char *name) {
|
||||
if (!track) /* Treat a NULL track object as an empty track object */
|
||||
return 0;
|
||||
|
||||
if (!track->recursive)
|
||||
return bus_track_remove_name_fully(track, name);
|
||||
|
||||
i = hashmap_get(track->names, name);
|
||||
if (!i)
|
||||
return -EUNATCH;
|
||||
if (i->n_ref <= 0)
|
||||
return -EUNATCH;
|
||||
return 0;
|
||||
|
||||
i->n_ref--;
|
||||
|
||||
if (i->n_ref <= 0)
|
||||
assert(i->n_ref >= 1);
|
||||
if (i->n_ref <= 1)
|
||||
return bus_track_remove_name_fully(track, name);
|
||||
|
||||
track_item_unref(i);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -293,7 +287,7 @@ _public_ const char* sd_bus_track_contains(sd_bus_track *track, const char *name
|
||||
if (!track) /* Let's consider a NULL object equivalent to an empty object */
|
||||
return NULL;
|
||||
|
||||
return hashmap_get(track->names, (void*) name) ? name : NULL;
|
||||
return hashmap_contains(track->names, name) ? name : NULL;
|
||||
}
|
||||
|
||||
_public_ const char* sd_bus_track_first(sd_bus_track *track) {
|
||||
|
||||
@ -10,6 +10,7 @@
|
||||
|
||||
static bool track_cb_called_x = false;
|
||||
static bool track_cb_called_y = false;
|
||||
static bool track_destroy_called_z = false;
|
||||
|
||||
static int track_cb_x(sd_bus_track *t, void *userdata) {
|
||||
|
||||
@ -26,7 +27,6 @@ static int track_cb_x(sd_bus_track *t, void *userdata) {
|
||||
}
|
||||
|
||||
static int track_cb_y(sd_bus_track *t, void *userdata) {
|
||||
int r;
|
||||
|
||||
log_error("TRACK CB Y");
|
||||
|
||||
@ -35,15 +35,22 @@ static int track_cb_y(sd_bus_track *t, void *userdata) {
|
||||
|
||||
/* We got disconnected, let's close everything */
|
||||
|
||||
r = sd_event_exit(sd_bus_get_event(sd_bus_track_get_bus(t)), EXIT_SUCCESS);
|
||||
assert_se(r >= 0);
|
||||
assert_se(sd_event_exit(sd_bus_get_event(sd_bus_track_get_bus(t)), EXIT_SUCCESS) >= 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int track_cb_z(sd_bus_track *t, void *userdata) {
|
||||
assert_not_reached();
|
||||
}
|
||||
|
||||
static void track_destroy_z(void *userdata) {
|
||||
track_destroy_called_z = true;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
_cleanup_(sd_event_unrefp) sd_event *event = NULL;
|
||||
_cleanup_(sd_bus_track_unrefp) sd_bus_track *x = NULL, *y = NULL;
|
||||
_cleanup_(sd_bus_track_unrefp) sd_bus_track *x = NULL, *y = NULL, *z = NULL;
|
||||
_cleanup_(sd_bus_unrefp) sd_bus *a = NULL, *b = NULL;
|
||||
bool use_system_bus = false;
|
||||
const char *unique;
|
||||
@ -51,8 +58,7 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
test_setup_logging(LOG_INFO);
|
||||
|
||||
r = sd_event_default(&event);
|
||||
assert_se(r >= 0);
|
||||
assert_se(sd_event_default(&event) >= 0);
|
||||
|
||||
r = sd_bus_open_user(&a);
|
||||
if (IN_SET(r, -ECONNREFUSED, -ENOENT, -ENOMEDIUM)) {
|
||||
@ -63,43 +69,80 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
assert_se(r >= 0);
|
||||
|
||||
r = sd_bus_attach_event(a, event, SD_EVENT_PRIORITY_NORMAL);
|
||||
assert_se(r >= 0);
|
||||
assert_se(sd_bus_attach_event(a, event, SD_EVENT_PRIORITY_NORMAL) >= 0);
|
||||
|
||||
if (use_system_bus)
|
||||
r = sd_bus_open_system(&b);
|
||||
assert_se(sd_bus_open_system(&b) >= 0);
|
||||
else
|
||||
r = sd_bus_open_user(&b);
|
||||
assert_se(r >= 0);
|
||||
assert_se(sd_bus_open_user(&b) >= 0);
|
||||
|
||||
r = sd_bus_attach_event(b, event, SD_EVENT_PRIORITY_NORMAL);
|
||||
assert_se(r >= 0);
|
||||
assert_se(sd_bus_attach_event(b, event, SD_EVENT_PRIORITY_NORMAL) >= 0);
|
||||
|
||||
/* Watch b's name from a */
|
||||
r = sd_bus_track_new(a, &x, track_cb_x, NULL);
|
||||
assert_se(r >= 0);
|
||||
assert_se(sd_bus_track_new(a, &x, track_cb_x, NULL) >= 0);
|
||||
|
||||
r = sd_bus_get_unique_name(b, &unique);
|
||||
assert_se(r >= 0);
|
||||
assert_se(sd_bus_get_unique_name(b, &unique) >= 0);
|
||||
|
||||
r = sd_bus_track_add_name(x, unique);
|
||||
assert_se(r >= 0);
|
||||
assert_se(sd_bus_track_add_name(x, unique) >= 0);
|
||||
|
||||
/* Watch's a's own name from a */
|
||||
r = sd_bus_track_new(a, &y, track_cb_y, NULL);
|
||||
assert_se(r >= 0);
|
||||
assert_se(sd_bus_track_new(a, &y, track_cb_y, NULL) >= 0);
|
||||
|
||||
r = sd_bus_get_unique_name(a, &unique);
|
||||
assert_se(r >= 0);
|
||||
assert_se(sd_bus_get_unique_name(a, &unique) >= 0);
|
||||
|
||||
r = sd_bus_track_add_name(y, unique);
|
||||
assert_se(r >= 0);
|
||||
assert_se(sd_bus_track_add_name(y, unique) >= 0);
|
||||
|
||||
/* Basic tests. */
|
||||
assert_se(sd_bus_track_new(a, &z, track_cb_z, NULL) >= 0);
|
||||
|
||||
/* non-recursive case */
|
||||
assert_se(sd_bus_track_set_recursive(z, false) >= 0);
|
||||
assert_se(sd_bus_track_get_recursive(z) == 0);
|
||||
assert_se(!sd_bus_track_contains(z, unique));
|
||||
assert_se(sd_bus_track_count_name(z, unique) == 0);
|
||||
assert_se(sd_bus_track_remove_name(z, unique) == 0);
|
||||
assert_se(sd_bus_track_add_name(z, unique) >= 0);
|
||||
assert_se(sd_bus_track_add_name(z, unique) >= 0);
|
||||
assert_se(sd_bus_track_add_name(z, unique) >= 0);
|
||||
assert_se(sd_bus_track_set_recursive(z, true) == -EBUSY);
|
||||
assert_se(sd_bus_track_contains(z, unique));
|
||||
assert_se(sd_bus_track_count_name(z, unique) == 1);
|
||||
assert_se(sd_bus_track_remove_name(z, unique) == 1);
|
||||
assert_se(!sd_bus_track_contains(z, unique));
|
||||
assert_se(sd_bus_track_count_name(z, unique) == 0);
|
||||
assert_se(sd_bus_track_remove_name(z, unique) == 0);
|
||||
|
||||
/* recursive case */
|
||||
assert_se(sd_bus_track_set_recursive(z, true) >= 0);
|
||||
assert_se(sd_bus_track_get_recursive(z) == 1);
|
||||
assert_se(!sd_bus_track_contains(z, unique));
|
||||
assert_se(sd_bus_track_count_name(z, unique) == 0);
|
||||
assert_se(sd_bus_track_remove_name(z, unique) == 0);
|
||||
assert_se(sd_bus_track_add_name(z, unique) >= 0);
|
||||
assert_se(sd_bus_track_add_name(z, unique) >= 0);
|
||||
assert_se(sd_bus_track_add_name(z, unique) >= 0);
|
||||
assert_se(sd_bus_track_set_recursive(z, false) == -EBUSY);
|
||||
assert_se(sd_bus_track_contains(z, unique));
|
||||
assert_se(sd_bus_track_count_name(z, unique) == 3);
|
||||
assert_se(sd_bus_track_remove_name(z, unique) == 1);
|
||||
assert_se(sd_bus_track_contains(z, unique));
|
||||
assert_se(sd_bus_track_count_name(z, unique) == 2);
|
||||
assert_se(sd_bus_track_remove_name(z, unique) == 1);
|
||||
assert_se(sd_bus_track_contains(z, unique));
|
||||
assert_se(sd_bus_track_count_name(z, unique) == 1);
|
||||
assert_se(sd_bus_track_remove_name(z, unique) == 1);
|
||||
assert_se(!sd_bus_track_contains(z, unique));
|
||||
assert_se(sd_bus_track_count_name(z, unique) == 0);
|
||||
assert_se(sd_bus_track_remove_name(z, unique) == 0);
|
||||
|
||||
assert_se(sd_bus_track_set_destroy_callback(z, track_destroy_z) >= 0);
|
||||
z = sd_bus_track_unref(z);
|
||||
assert_se(track_destroy_called_z);
|
||||
|
||||
/* Now make b's name disappear */
|
||||
sd_bus_close(b);
|
||||
|
||||
r = sd_event_loop(event);
|
||||
assert_se(r >= 0);
|
||||
assert_se(sd_event_loop(event) >= 0);
|
||||
|
||||
assert_se(track_cb_called_x);
|
||||
assert_se(track_cb_called_y);
|
||||
|
||||
@ -1173,7 +1173,7 @@ _public_ int sd_device_get_devname(sd_device *device, const char **devname) {
|
||||
|
||||
static int device_set_sysname_and_sysnum(sd_device *device) {
|
||||
_cleanup_free_ char *sysname = NULL;
|
||||
char *p;
|
||||
size_t len, n;
|
||||
int r;
|
||||
|
||||
assert(device);
|
||||
@ -1181,16 +1181,19 @@ static int device_set_sysname_and_sysnum(sd_device *device) {
|
||||
r = path_extract_filename(device->devpath, &sysname);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == O_DIRECTORY)
|
||||
return -EINVAL;
|
||||
|
||||
/* some devices have '!' in their name, change that to '/' */
|
||||
for (p = strchrnul(sysname, '!'); *p != '\0'; p = strchrnul(p, '!'))
|
||||
*p = '/';
|
||||
string_replace_char(sysname, '!', '/');
|
||||
|
||||
/* trailing number (refuse number only sysname)*/
|
||||
for (; p > sysname && isdigit(p[-1]); p--)
|
||||
;
|
||||
n = strspn_from_end(sysname, DIGITS);
|
||||
len = strlen(sysname);
|
||||
assert(n <= len);
|
||||
if (n == len)
|
||||
n = 0; /* Do not set sysnum for number only sysname. */
|
||||
|
||||
device->sysnum = p > sysname && *p != '\0' ? p : NULL;
|
||||
device->sysnum = n > 0 ? sysname + len - n : NULL;
|
||||
return free_and_replace(device->sysname, sysname);
|
||||
}
|
||||
|
||||
@ -1457,6 +1460,8 @@ int device_get_device_id(sd_device *device, const char **ret) {
|
||||
r = path_extract_filename(device->devpath, &sysname);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == O_DIRECTORY)
|
||||
return -EINVAL;
|
||||
|
||||
if (streq(subsystem, "drivers")) {
|
||||
/* the 'drivers' pseudo-subsystem is special, and needs the real
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
#include "blockdev-util.h"
|
||||
#include "chattr-util.h"
|
||||
#include "creds-util.h"
|
||||
#include "efi-api.h"
|
||||
#include "env-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
@ -366,6 +367,11 @@ int get_credential_host_secret(CredentialSecretFlags flags, void **ret, size_t *
|
||||
*
|
||||
* 3. The concatenation of the above.
|
||||
*
|
||||
* 4. Or a fixed "empty" key. This will not provide confidentiality or authenticity, of course, but is
|
||||
* useful to encode credentials for the initrd on TPM-less systems, where we simply have no better
|
||||
* concept to bind things to. Note that decryption of a key set up like this will be refused on
|
||||
* systems that have a TPM and have SecureBoot enabled.
|
||||
*
|
||||
* The above is hashed with SHA256 which is then used as encryption key for AES256-GCM. The encrypted
|
||||
* credential is a short (unencrypted) header describing which of the three keys to use, the IV to use for
|
||||
* AES256-GCM and some more meta information (sizes of certain objects) that is strictly speaking redundant,
|
||||
@ -474,15 +480,21 @@ int encrypt_credential_and_warn(
|
||||
int ksz, bsz, ivsz, tsz, added, r;
|
||||
uint8_t md[SHA256_DIGEST_LENGTH];
|
||||
const EVP_CIPHER *cc;
|
||||
#if HAVE_TPM2
|
||||
bool try_tpm2 = false;
|
||||
#endif
|
||||
sd_id128_t id;
|
||||
|
||||
assert(input || input_size == 0);
|
||||
assert(ret);
|
||||
assert(ret_size);
|
||||
|
||||
if (!sd_id128_in_set(with_key,
|
||||
_CRED_AUTO,
|
||||
_CRED_AUTO_INITRD,
|
||||
CRED_AES256_GCM_BY_HOST,
|
||||
CRED_AES256_GCM_BY_TPM2_HMAC,
|
||||
CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC,
|
||||
CRED_AES256_GCM_BY_TPM2_ABSENT))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid key type: " SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(with_key));
|
||||
|
||||
if (name && !credential_name_valid(name))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid credential name: %s", name);
|
||||
|
||||
@ -500,23 +512,26 @@ int encrypt_credential_and_warn(
|
||||
log_debug("Including not-after timestamp '%s' in encrypted credential.", format_timestamp(buf, sizeof(buf), not_after));
|
||||
}
|
||||
|
||||
if (sd_id128_is_null(with_key) ||
|
||||
sd_id128_in_set(with_key, CRED_AES256_GCM_BY_HOST, CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC)) {
|
||||
if (sd_id128_in_set(with_key,
|
||||
_CRED_AUTO,
|
||||
CRED_AES256_GCM_BY_HOST,
|
||||
CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC)) {
|
||||
|
||||
r = get_credential_host_secret(
|
||||
CREDENTIAL_SECRET_GENERATE|
|
||||
CREDENTIAL_SECRET_WARN_NOT_ENCRYPTED|
|
||||
(sd_id128_is_null(with_key) ? CREDENTIAL_SECRET_FAIL_ON_TEMPORARY_FS : 0),
|
||||
(sd_id128_equal(with_key, _CRED_AUTO) ? CREDENTIAL_SECRET_FAIL_ON_TEMPORARY_FS : 0),
|
||||
&host_key,
|
||||
&host_key_size);
|
||||
if (r == -ENOMEDIUM && sd_id128_is_null(with_key))
|
||||
if (r == -ENOMEDIUM && sd_id128_equal(with_key, _CRED_AUTO))
|
||||
log_debug_errno(r, "Credential host secret location on temporary file system, not using.");
|
||||
else if (r < 0)
|
||||
return log_error_errno(r, "Failed to determine local credential host secret: %m");
|
||||
}
|
||||
|
||||
#if HAVE_TPM2
|
||||
if (sd_id128_is_null(with_key)) {
|
||||
bool try_tpm2;
|
||||
if (sd_id128_equal(with_key, _CRED_AUTO)) {
|
||||
/* If automatic mode is selected and we are running in a container, let's not try TPM2. OTOH
|
||||
* if user picks TPM2 explicitly, let's always honour the request and try. */
|
||||
|
||||
@ -527,11 +542,17 @@ int encrypt_credential_and_warn(
|
||||
log_debug("Running in container, not attempting to use TPM2.");
|
||||
|
||||
try_tpm2 = r <= 0;
|
||||
}
|
||||
} else if (sd_id128_equal(with_key, _CRED_AUTO_INITRD)) {
|
||||
/* If automatic mode for initrds is selected, we'll use the TPM2 key if the firmware does it,
|
||||
* otherwise we'll use a fixed key */
|
||||
|
||||
if (try_tpm2 ||
|
||||
sd_id128_in_set(with_key, CRED_AES256_GCM_BY_TPM2_HMAC, CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC)) {
|
||||
try_tpm2 = efi_has_tpm2();
|
||||
if (!try_tpm2)
|
||||
log_debug("Firmware lacks TPM2 support, not attempting to use TPM2.");
|
||||
} else
|
||||
try_tpm2 = sd_id128_in_set(with_key, CRED_AES256_GCM_BY_TPM2_HMAC, CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC);
|
||||
|
||||
if (try_tpm2) {
|
||||
r = tpm2_seal(tpm2_device,
|
||||
tpm2_pcr_mask,
|
||||
NULL,
|
||||
@ -544,7 +565,9 @@ int encrypt_credential_and_warn(
|
||||
&tpm2_pcr_bank,
|
||||
&tpm2_primary_alg);
|
||||
if (r < 0) {
|
||||
if (!sd_id128_is_null(with_key))
|
||||
if (sd_id128_equal(with_key, _CRED_AUTO_INITRD))
|
||||
log_warning("Firmware reported a TPM2 being present and used, but we didn't manage to talk to it. Credential will be refused if SecureBoot is enabled.");
|
||||
else if (!sd_id128_equal(with_key, _CRED_AUTO))
|
||||
return r;
|
||||
|
||||
log_debug_errno(r, "TPM2 sealing didn't work, not using: %m");
|
||||
@ -555,7 +578,7 @@ int encrypt_credential_and_warn(
|
||||
}
|
||||
#endif
|
||||
|
||||
if (sd_id128_is_null(with_key)) {
|
||||
if (sd_id128_in_set(with_key, _CRED_AUTO, _CRED_AUTO_INITRD)) {
|
||||
/* Let's settle the key type in auto mode now. */
|
||||
|
||||
if (host_key && tpm2_key)
|
||||
@ -564,12 +587,17 @@ int encrypt_credential_and_warn(
|
||||
id = CRED_AES256_GCM_BY_TPM2_HMAC;
|
||||
else if (host_key)
|
||||
id = CRED_AES256_GCM_BY_HOST;
|
||||
else if (sd_id128_equal(with_key, _CRED_AUTO_INITRD))
|
||||
id = CRED_AES256_GCM_BY_TPM2_ABSENT;
|
||||
else
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
|
||||
"TPM2 not available and host key located on temporary file system, no encryption key available.");
|
||||
} else
|
||||
id = with_key;
|
||||
|
||||
if (sd_id128_equal(id, CRED_AES256_GCM_BY_TPM2_ABSENT))
|
||||
log_warning("Using a null key for encryption and signing. Confidentiality or authenticity will not be provided.");
|
||||
|
||||
/* Let's now take the host key and the TPM2 key and hash it together, to use as encryption key for the data */
|
||||
r = sha256_hash_host_and_tpm2_key(host_key, host_key_size, tpm2_key, tpm2_key_size, md);
|
||||
if (r < 0)
|
||||
@ -727,7 +755,7 @@ int decrypt_credential_and_warn(
|
||||
struct encrypted_credential_header *h;
|
||||
struct metadata_credential_header *m;
|
||||
uint8_t md[SHA256_DIGEST_LENGTH];
|
||||
bool with_tpm2, with_host_key;
|
||||
bool with_tpm2, with_host_key, is_tpm2_absent;
|
||||
const EVP_CIPHER *cc;
|
||||
int r, added;
|
||||
|
||||
@ -743,10 +771,31 @@ int decrypt_credential_and_warn(
|
||||
|
||||
with_host_key = sd_id128_in_set(h->id, CRED_AES256_GCM_BY_HOST, CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC);
|
||||
with_tpm2 = sd_id128_in_set(h->id, CRED_AES256_GCM_BY_TPM2_HMAC, CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC);
|
||||
is_tpm2_absent = sd_id128_equal(h->id, CRED_AES256_GCM_BY_TPM2_ABSENT);
|
||||
|
||||
if (!with_host_key && !with_tpm2)
|
||||
if (!with_host_key && !with_tpm2 && !is_tpm2_absent)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Unknown encryption format, or corrupted data: %m");
|
||||
|
||||
if (is_tpm2_absent) {
|
||||
/* So this is a credential encrypted with a zero length key. We support this to cover for the
|
||||
* case where neither a host key not a TPM2 are available (specifically: initrd environments
|
||||
* where the host key is not yet accessible and no TPM2 chip exists at all), to minimize
|
||||
* different codeflow for TPM2 and non-TPM2 codepaths. Of course, credentials encoded this
|
||||
* way offer no confidentiality nor authenticity. Because of that it's important we refuse to
|
||||
* use them on systems that actually *do* have a TPM2 chip – if we are in SecureBoot
|
||||
* mode. Otherwise an attacker could hand us credentials like this and we'd use them thinking
|
||||
* they are trusted, even though they are not. */
|
||||
|
||||
if (efi_has_tpm2()) {
|
||||
if (is_efi_secure_boot())
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EBADMSG),
|
||||
"Credential uses fixed key for fallback use when TPM2 is absent — but TPM2 is present, and SecureBoot is enabled, refusing.");
|
||||
|
||||
log_warning("Credential uses fixed key for use when TPM2 is absent, but TPM2 is present! Accepting anyway, since SecureBoot is disabled.");
|
||||
} else
|
||||
log_debug("Credential uses fixed key for use when TPM2 is absent, and TPM2 indeed is absent. Accepting.");
|
||||
}
|
||||
|
||||
/* Now we know the minimum header size */
|
||||
if (input_size < offsetof(struct encrypted_credential_header, iv))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Encrypted file too short.");
|
||||
@ -827,6 +876,9 @@ int decrypt_credential_and_warn(
|
||||
return log_error_errno(r, "Failed to determine local credential key: %m");
|
||||
}
|
||||
|
||||
if (is_tpm2_absent)
|
||||
log_warning("Warning: using a null key for decryption and authentication. Confidentiality or authenticity are not provided.");
|
||||
|
||||
sha256_hash_host_and_tpm2_key(host_key, host_key_size, tpm2_key, tpm2_key_size, md);
|
||||
|
||||
assert_se(cc = EVP_aes_256_gcm());
|
||||
|
||||
@ -38,10 +38,22 @@ typedef enum CredentialSecretFlags {
|
||||
|
||||
int get_credential_host_secret(CredentialSecretFlags flags, void **ret, size_t *ret_size);
|
||||
|
||||
/* The three modes we support: keyed only by on-disk key, only by TPM2 HMAC key, and by the combination of both */
|
||||
/* The four modes we support: keyed only by on-disk key, only by TPM2 HMAC key, and by the combination of
|
||||
* both, as well as one with a fixed zero length key if TPM2 is missing (the latter of course provides no
|
||||
* authenticity or confidentiality, but is still useful for integrity protection, and makes things simpler
|
||||
* for us to handle). */
|
||||
#define CRED_AES256_GCM_BY_HOST SD_ID128_MAKE(5a,1c,6a,86,df,9d,40,96,b1,d5,a6,5e,08,62,f1,9a)
|
||||
#define CRED_AES256_GCM_BY_TPM2_HMAC SD_ID128_MAKE(0c,7c,c0,7b,11,76,45,91,9c,4b,0b,ea,08,bc,20,fe)
|
||||
#define CRED_AES256_GCM_BY_HOST_AND_TPM2_HMAC SD_ID128_MAKE(93,a8,94,09,48,74,44,90,90,ca,f2,fc,93,ca,b5,53)
|
||||
#define CRED_AES256_GCM_BY_TPM2_ABSENT SD_ID128_MAKE(05,84,69,da,f6,f5,43,24,80,05,49,da,0f,8e,a2,fb)
|
||||
|
||||
/* Two special IDs to pick a general automatic mode (i.e. tpm2+host if TPM2 exists, only host otherwise) or
|
||||
* an initrd-specific automatic mode (i.e. tpm2 if firmware can do it, otherwise fixed zero-length key, and
|
||||
* never involve host keys). These IDs will never be stored on disk, but are useful only internally while
|
||||
* figuring out what precisely to write to disk. To mark that these aren't a "real" type, we'll prefix them
|
||||
* with an underscore. */
|
||||
#define _CRED_AUTO SD_ID128_MAKE(a2,19,cb,07,85,b2,4c,04,b1,6d,18,ca,b9,d2,ee,01)
|
||||
#define _CRED_AUTO_INITRD SD_ID128_MAKE(02,dc,8e,de,3a,02,43,ab,a9,ec,54,9c,05,e6,a0,71)
|
||||
|
||||
int encrypt_credential_and_warn(sd_id128_t with_key, const char *name, usec_t timestamp, usec_t not_after, const char *tpm2_device, uint32_t tpm2_pcr_mask, const void *input, size_t input_size, void **ret, size_t *ret_size);
|
||||
int decrypt_credential_and_warn(const char *validate_name, usec_t validate_timestamp, const char *tpm2_device, const void *input, size_t input_size, void **ret, size_t *ret_size);
|
||||
|
||||
@ -546,11 +546,3 @@ bool efi_has_tpm2(void) {
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
char *efi_tilt_backslashes(char *s) {
|
||||
for (char *p = s; *p; p++)
|
||||
if (*p == '\\')
|
||||
*p = '/';
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
|
||||
#include "efivars-fundamental.h"
|
||||
#include "efivars.h"
|
||||
#include "string-util.h"
|
||||
|
||||
/* Various calls for interfacing with EFI variables from the official UEFI specs. */
|
||||
|
||||
@ -65,4 +66,6 @@ static inline bool efi_has_tpm2(void) {
|
||||
|
||||
#endif
|
||||
|
||||
char *efi_tilt_backslashes(char *s);
|
||||
static inline char *efi_tilt_backslashes(char *s) {
|
||||
return string_replace_char(s, '\\', '/');
|
||||
}
|
||||
|
||||
@ -31,7 +31,7 @@
|
||||
|
||||
static int nfnl_netlink_sendv(
|
||||
sd_netlink *nfnl,
|
||||
sd_netlink_message **messages,
|
||||
sd_netlink_message *messages[static 1],
|
||||
size_t msgcount) {
|
||||
|
||||
_cleanup_free_ uint32_t *serial = NULL;
|
||||
|
||||
@ -41,7 +41,7 @@ assert_cc(DEPTH_MAX <= UINT16_MAX);
|
||||
|
||||
typedef struct JsonSource {
|
||||
/* When we parse from a file or similar, encodes the filename, to indicate the source of a json variant */
|
||||
size_t n_ref;
|
||||
unsigned n_ref;
|
||||
unsigned max_line;
|
||||
unsigned max_column;
|
||||
char name[];
|
||||
@ -53,7 +53,7 @@ struct JsonVariant {
|
||||
/* We either maintain a reference counter for this variant itself, or we are embedded into an
|
||||
* array/object, in which case only that surrounding object is ref-counted. (If 'embedded' is false,
|
||||
* see below.) */
|
||||
size_t n_ref;
|
||||
unsigned n_ref;
|
||||
|
||||
/* If this JsonVariant is part of an array/object, then this field points to the surrounding
|
||||
* JSON_VARIANT_ARRAY/JSON_VARIANT_OBJECT object. (If 'embedded' is true, see below.) */
|
||||
|
||||
@ -935,6 +935,26 @@ TEST(strextendf) {
|
||||
assert_se(streq(p, "<77>,<99>,< 88>,<00001234>"));
|
||||
}
|
||||
|
||||
TEST(string_replace_char) {
|
||||
assert_se(streq(string_replace_char(strdupa(""), 'a', 'b'), ""));
|
||||
assert_se(streq(string_replace_char(strdupa("abc"), 'a', 'b'), "bbc"));
|
||||
assert_se(streq(string_replace_char(strdupa("hoge"), 'a', 'b'), "hoge"));
|
||||
assert_se(streq(string_replace_char(strdupa("aaaa"), 'a', 'b'), "bbbb"));
|
||||
assert_se(streq(string_replace_char(strdupa("aaaa"), 'a', '\t'), "\t\t\t\t"));
|
||||
}
|
||||
|
||||
TEST(strspn_from_end) {
|
||||
assert_se(strspn_from_end(NULL, NULL) == 0);
|
||||
assert_se(strspn_from_end("hoge", NULL) == 0);
|
||||
assert_se(strspn_from_end(NULL, DIGITS) == 0);
|
||||
assert_se(strspn_from_end("", DIGITS) == 0);
|
||||
assert_se(strspn_from_end("hoge", DIGITS) == 0);
|
||||
assert_se(strspn_from_end("1234", DIGITS) == 4);
|
||||
assert_se(strspn_from_end("aaa1234", DIGITS) == 4);
|
||||
assert_se(strspn_from_end("aaa1234aaa", DIGITS) == 0);
|
||||
assert_se(strspn_from_end("aaa12aa34", DIGITS) == 2);
|
||||
}
|
||||
|
||||
TEST(streq_skip_trailing_chars) {
|
||||
/* NULL is WHITESPACE by default*/
|
||||
assert_se(streq_skip_trailing_chars("foo bar", "foo bar", NULL));
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user