Merge pull request #17524 from poettering/fileio-offset
cryptsetup: if keyfile is specified as AF_UNIX socket in the fs, connect to it, and read key data from it
This commit is contained in:
commit
946f3d868c
3
TODO
3
TODO
|
@ -76,9 +76,6 @@ Features:
|
|||
|
||||
* make use of new glibc 2.32 APIs sigabbrev_np() and strerrorname_np().
|
||||
|
||||
* cryptsetup: if keyfile specified in crypttab is AF_UNIX socket, connect to it
|
||||
and read from it (like we do elsewhere with READ_FULL_FILE_CONNECT_SOCKET)
|
||||
|
||||
* when main nspawn supervisor process gets suspended due to SIGSTOP/SIGTTOU or
|
||||
so, freeze the payload too.
|
||||
|
||||
|
|
|
@ -53,25 +53,36 @@
|
|||
it is opened as a LUKS device; otherwise, it is assumed to be in
|
||||
raw dm-crypt (plain mode) format.</para>
|
||||
|
||||
<para>The first field contains the name of the resulting encrypted volume; its block device is set up
|
||||
below <filename>/dev/mapper/</filename>.</para>
|
||||
<para>The four fields of <filename>/etc/crypttab</filename> are defined as follows:</para>
|
||||
|
||||
<para>The second field contains a path to the underlying block
|
||||
<orderedlist>
|
||||
|
||||
<listitem><para>The first field contains the name of the resulting volume with decrypted data; its
|
||||
block device is set up below <filename>/dev/mapper/</filename>.</para></listitem>
|
||||
|
||||
<listitem><para>The second field contains a path to the underlying block
|
||||
device or file, or a specification of a block device via
|
||||
<literal>UUID=</literal> followed by the UUID.</para>
|
||||
<literal>UUID=</literal> followed by the UUID.</para></listitem>
|
||||
|
||||
<para>The third field specifies an absolute path to a file with the encryption key. Optionally,
|
||||
the path may be followed by <literal>:</literal> and an fstab device specification (e.g. starting with
|
||||
<literal>LABEL=</literal> or similar); in which case the path is taken relative to the device file system
|
||||
root. If the field is not present or is <literal>none</literal> or <literal>-</literal>, a key file
|
||||
named after the volume to unlock (i.e. the first column of the line), suffixed with
|
||||
<filename>.key</filename> is automatically loaded from the <filename>/etc/cryptsetup-keys.d/</filename>
|
||||
and <filename>/run/cryptsetup-keys.d/</filename> directories, if present. Otherwise, the password has to
|
||||
be manually entered during system boot. For swap encryption, <filename>/dev/urandom</filename> may be
|
||||
used as key file.</para>
|
||||
<listitem><para>The third field specifies an absolute path to a file with the encryption
|
||||
key. Optionally, the path may be followed by <literal>:</literal> and an fstab device specification
|
||||
(e.g. starting with <literal>LABEL=</literal> or similar); in which case the path is taken relative to
|
||||
the device file system root. If the field is not present or is <literal>none</literal> or
|
||||
<literal>-</literal>, a key file named after the volume to unlock (i.e. the first column of the line),
|
||||
suffixed with <filename>.key</filename> is automatically loaded from the
|
||||
<filename>/etc/cryptsetup-keys.d/</filename> and <filename>/run/cryptsetup-keys.d/</filename>
|
||||
directories, if present. Otherwise, the password has to be manually entered during system boot. For
|
||||
swap encryption, <filename>/dev/urandom</filename> may be used as key file, resulting in a randomized
|
||||
key.</para>
|
||||
|
||||
<para>The fourth field, if present, is a comma-delimited list of
|
||||
options. The following options are recognized:</para>
|
||||
<para>If the specified key file path refers to an <constant>AF_UNIX</constant> stream socket in the
|
||||
file system, the key is acquired by connecting to the socket and reading it from the connection. This
|
||||
allows the implementation of a service to provide key information dynamically, at the moment when it is
|
||||
needed. For details see below.</para></listitem>
|
||||
|
||||
<listitem><para>The fourth field, if present, is a comma-delimited list of options. The suppported
|
||||
options are listed below.</para></listitem>
|
||||
</orderedlist>
|
||||
|
||||
<variablelist class='fstab-options'>
|
||||
|
||||
|
@ -499,6 +510,34 @@
|
|||
<citerefentry><refentrytitle>systemd-cryptsetup-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title><constant>AF_UNIX</constant> Key Files</title>
|
||||
|
||||
<para>If the key file path (as specified in the third column of <filename>/etc/crypttab</filename>
|
||||
entries, see above) refers to an <constant>AF_UNIX</constant> stream socket in the file system, the key
|
||||
is acquired by connecting to the socket and reading the key from the connection. The connection is made
|
||||
from an <constant>AF_UNIX</constant> socket name in the abstract namespace, see <citerefentry
|
||||
project='man-pages'><refentrytitle>unix</refentrytitle><manvolnum>7</manvolnum></citerefentry> for
|
||||
details. The source socket name is chosen according the following format:</para>
|
||||
|
||||
<programlisting><constant>NUL</constant> <replaceable>RANDOM</replaceable> <literal>/cryptsetup/</literal> <replaceable>VOLUME</replaceable></programlisting>
|
||||
|
||||
<para>In other words: a <constant>NUL</constant> byte (as required for abstract namespace sockets),
|
||||
followed by a random string (consisting of alphabenumeric characters only), followed by the literal
|
||||
string <literal>/cryptsetup/</literal>, followed by the name of the volume to acquire they key
|
||||
for. Example (for a volume <literal>myvol</literal>):</para>
|
||||
|
||||
<example><programlisting>\0d7067f78d9827418/cryptsetup/myvol</programlisting></example>
|
||||
|
||||
<para>Services listening on the <constant>AF_UNIX</constant> stream socket may query the source socket
|
||||
name with <citerefentry
|
||||
project='man-pages'><refentrytitle>getpeername</refentrytitle><manvolnum>2</manvolnum></citerefentry>,
|
||||
and use it to determine which key to send, allowing a single listening socket to serve keys for a
|
||||
multitude of volumes. If the PKCS#11 logic is used (see below) the socket source name is picked in
|
||||
identical fashion, except that the literal string <literal>/cryptsetup-pkcs11/</literal> is used. This is
|
||||
done so that services providing key material know that not a secret key is requested but an encrypted key
|
||||
that will be decrypted via the PKCS#11 logic to acquire the final secret key.</para>
|
||||
</refsect1>
|
||||
<refsect1>
|
||||
<title>Examples</title>
|
||||
<example>
|
||||
|
@ -529,7 +568,6 @@ external /dev/sda3 keyfile:LABEL=keydev keyfile-timeout=10s,cipher=xchac
|
|||
<para>A few notes on the above:</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem><para>We use RSA (and not ECC), since Yubikeys support PKCS#11 Decrypt() only for RSA keys</para></listitem>
|
||||
<listitem><para>We use RSA2048, which is the longest key size current Yubikeys support</para></listitem>
|
||||
<listitem><para>LUKS key size must be shorter than 2048bit due to RSA padding, hence we use 128 bytes</para></listitem>
|
||||
<listitem><para>We use Yubikey key slot 9d, since that's apparently the keyslot to use for decryption purposes,
|
||||
|
|
|
@ -68,8 +68,8 @@
|
|||
<term><option>--key=</option></term>
|
||||
|
||||
<listitem><para>Specify the path to a file or <constant>AF_UNIX</constant> stream socket to read the
|
||||
server key corresponding to the certificate specified with <option>--cert=</option> from. The key
|
||||
must be in PEM format.</para></listitem>
|
||||
secret server key corresponding to the certificate specified with <option>--cert=</option> from. The
|
||||
key must be in PEM format.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
|
|
|
@ -180,7 +180,7 @@
|
|||
<varlistentry>
|
||||
<term><option>--key=</option></term>
|
||||
|
||||
<listitem><para> Takes a path to a SSL key file in PEM format. Defaults to
|
||||
<listitem><para>Takes a path to a SSL secret key file in PEM format. Defaults to
|
||||
<filename>&CERTIFICATE_ROOT;/private/journal-remote.pem</filename>. This option can be used with
|
||||
<option>--listen-https=</option>. If the path refers to an <constant>AF_UNIX</constant> stream socket
|
||||
in the file system a connection is made to it and the key read from it.</para></listitem>
|
||||
|
|
|
@ -472,12 +472,13 @@ int read_full_virtual_file(const char *filename, char **ret_contents, size_t *re
|
|||
int read_full_stream_full(
|
||||
FILE *f,
|
||||
const char *filename,
|
||||
uint64_t offset,
|
||||
size_t size,
|
||||
ReadFullFileFlags flags,
|
||||
char **ret_contents,
|
||||
size_t *ret_size) {
|
||||
|
||||
_cleanup_free_ char *buf = NULL;
|
||||
struct stat st;
|
||||
size_t n, n_next, l;
|
||||
int fd, r;
|
||||
|
||||
|
@ -485,32 +486,45 @@ int read_full_stream_full(
|
|||
assert(ret_contents);
|
||||
assert(!FLAGS_SET(flags, READ_FULL_FILE_UNBASE64 | READ_FULL_FILE_UNHEX));
|
||||
|
||||
n_next = LINE_MAX; /* Start size */
|
||||
if (offset != UINT64_MAX && offset > LONG_MAX)
|
||||
return -ERANGE;
|
||||
|
||||
n_next = size != SIZE_MAX ? size : LINE_MAX; /* Start size */
|
||||
|
||||
fd = fileno(f);
|
||||
if (fd >= 0) { /* If the FILE* object is backed by an fd (as opposed to memory or such, see fmemopen()), let's
|
||||
* optimize our buffering */
|
||||
if (fd >= 0) { /* If the FILE* object is backed by an fd (as opposed to memory or such, see
|
||||
* fmemopen()), let's optimize our buffering */
|
||||
struct stat st;
|
||||
|
||||
if (fstat(fd, &st) < 0)
|
||||
return -errno;
|
||||
|
||||
if (S_ISREG(st.st_mode)) {
|
||||
if (size == SIZE_MAX) {
|
||||
uint64_t rsize =
|
||||
LESS_BY((uint64_t) st.st_size, offset == UINT64_MAX ? 0 : offset);
|
||||
|
||||
/* Safety check */
|
||||
if (st.st_size > READ_FULL_BYTES_MAX)
|
||||
if (rsize > READ_FULL_BYTES_MAX)
|
||||
return -E2BIG;
|
||||
|
||||
/* Start with the right file size. Note that we increase the size
|
||||
* to read here by one, so that the first read attempt already
|
||||
* makes us notice the EOF. */
|
||||
/* Start with the right file size. Note that we increase the size to read
|
||||
* here by one, so that the first read attempt already makes us notice the
|
||||
* EOF. If the reported size of the file is zero, we avoid this logic
|
||||
* however, since quite likely it might be a virtual file in procfs that all
|
||||
* report a zero file size. */
|
||||
if (st.st_size > 0)
|
||||
n_next = st.st_size + 1;
|
||||
n_next = rsize + 1;
|
||||
}
|
||||
|
||||
if (flags & READ_FULL_FILE_WARN_WORLD_READABLE)
|
||||
(void) warn_file_is_world_accessible(filename, &st, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (offset != UINT64_MAX && fseek(f, offset, SEEK_SET) < 0)
|
||||
return -errno;
|
||||
|
||||
n = l = 0;
|
||||
for (;;) {
|
||||
char *t;
|
||||
|
@ -547,6 +561,11 @@ int read_full_stream_full(
|
|||
if (feof(f))
|
||||
break;
|
||||
|
||||
if (size != SIZE_MAX) { /* If we got asked to read some specific size, we already sized the buffer right, hence leave */
|
||||
assert(l == size);
|
||||
break;
|
||||
}
|
||||
|
||||
assert(k > 0); /* we can't have read zero bytes because that would have been EOF */
|
||||
|
||||
/* Safety check */
|
||||
|
@ -605,15 +624,18 @@ finalize:
|
|||
int read_full_file_full(
|
||||
int dir_fd,
|
||||
const char *filename,
|
||||
uint64_t offset,
|
||||
size_t size,
|
||||
ReadFullFileFlags flags,
|
||||
const char *bind_name,
|
||||
char **contents, size_t *size) {
|
||||
char **ret_contents,
|
||||
size_t *ret_size) {
|
||||
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(contents);
|
||||
assert(ret_contents);
|
||||
|
||||
r = xfopenat(dir_fd, filename, "re", 0, &f);
|
||||
if (r < 0) {
|
||||
|
@ -628,6 +650,10 @@ int read_full_file_full(
|
|||
if (!FLAGS_SET(flags, READ_FULL_FILE_CONNECT_SOCKET))
|
||||
return -ENXIO;
|
||||
|
||||
/* Seeking is not supported on AF_UNIX sockets */
|
||||
if (offset != UINT64_MAX)
|
||||
return -ESPIPE;
|
||||
|
||||
if (dir_fd == AT_FDCWD)
|
||||
r = sockaddr_un_set_path(&sa.un, filename);
|
||||
else {
|
||||
|
@ -681,7 +707,7 @@ int read_full_file_full(
|
|||
|
||||
(void) __fsetlocking(f, FSETLOCKING_BYCALLER);
|
||||
|
||||
return read_full_stream_full(f, filename, flags, contents, size);
|
||||
return read_full_stream_full(f, filename, offset, size, flags, ret_contents, ret_size);
|
||||
}
|
||||
|
||||
int executable_is_script(const char *path, char **interpreter) {
|
||||
|
|
|
@ -60,14 +60,14 @@ static inline int write_string_file(const char *fn, const char *line, WriteStrin
|
|||
int write_string_filef(const char *fn, WriteStringFileFlags flags, const char *format, ...) _printf_(3, 4);
|
||||
|
||||
int read_one_line_file(const char *filename, char **line);
|
||||
int read_full_file_full(int dir_fd, const char *filename, ReadFullFileFlags flags, const char *bind_name, char **contents, size_t *size);
|
||||
static inline int read_full_file(const char *filename, char **contents, size_t *size) {
|
||||
return read_full_file_full(AT_FDCWD, filename, 0, NULL, contents, size);
|
||||
int read_full_file_full(int dir_fd, const char *filename, uint64_t offset, size_t size, ReadFullFileFlags flags, const char *bind_name, char **ret_contents, size_t *ret_size);
|
||||
static inline int read_full_file(const char *filename, char **ret_contents, size_t *ret_size) {
|
||||
return read_full_file_full(AT_FDCWD, filename, UINT64_MAX, SIZE_MAX, 0, NULL, ret_contents, ret_size);
|
||||
}
|
||||
int read_full_virtual_file(const char *filename, char **ret_contents, size_t *ret_size);
|
||||
int read_full_stream_full(FILE *f, const char *filename, ReadFullFileFlags flags, char **contents, size_t *size);
|
||||
static inline int read_full_stream(FILE *f, char **contents, size_t *size) {
|
||||
return read_full_stream_full(f, NULL, 0, contents, size);
|
||||
int read_full_stream_full(FILE *f, const char *filename, uint64_t offset, size_t size, ReadFullFileFlags flags, char **ret_contents, size_t *ret_size);
|
||||
static inline int read_full_stream(FILE *f, char **ret_contents, size_t *ret_size) {
|
||||
return read_full_stream_full(f, NULL, UINT64_MAX, SIZE_MAX, 0, ret_contents, ret_size);
|
||||
}
|
||||
|
||||
int verify_file(const char *fn, const char *blob, bool accept_extra_nl);
|
||||
|
|
|
@ -2576,7 +2576,7 @@ static int acquire_credentials(
|
|||
|
||||
|
||||
if (source)
|
||||
r = read_full_file_full(AT_FDCWD, source, flags, bindname, &data, &size);
|
||||
r = read_full_file_full(AT_FDCWD, source, UINT64_MAX, SIZE_MAX, flags, bindname, &data, &size);
|
||||
else
|
||||
r = -ENOENT;
|
||||
if (r == -ENOENT &&
|
||||
|
|
|
@ -1,29 +1,18 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include "cryptsetup-keyfile.h"
|
||||
#include "fd-util.h"
|
||||
#include "format-util.h"
|
||||
#include "memory-util.h"
|
||||
#include "fileio.h"
|
||||
#include "path-util.h"
|
||||
#include "stat-util.h"
|
||||
#include "strv.h"
|
||||
|
||||
#define KEY_FILE_SIZE_MAX (16U*1024U*1024U) /* 16 MiB */
|
||||
|
||||
int load_key_file(
|
||||
int find_key_file(
|
||||
const char *key_file,
|
||||
char **search_path,
|
||||
size_t key_file_size,
|
||||
uint64_t key_file_offset,
|
||||
const char *bindname,
|
||||
void **ret_key,
|
||||
size_t *ret_key_size) {
|
||||
|
||||
_cleanup_(erase_and_freep) char *buffer = NULL;
|
||||
_cleanup_free_ char *discovered_path = NULL;
|
||||
_cleanup_close_ int fd = -1;
|
||||
ssize_t n;
|
||||
char **i;
|
||||
int r;
|
||||
|
||||
assert(key_file);
|
||||
|
@ -31,11 +20,17 @@ int load_key_file(
|
|||
assert(ret_key_size);
|
||||
|
||||
if (strv_isempty(search_path) || path_is_absolute(key_file)) {
|
||||
fd = open(key_file, O_RDONLY|O_CLOEXEC);
|
||||
if (fd < 0)
|
||||
return log_error_errno(errno, "Failed to load key file '%s': %m", key_file);
|
||||
} else {
|
||||
char **i;
|
||||
|
||||
r = read_full_file_full(
|
||||
AT_FDCWD, key_file, UINT64_MAX, SIZE_MAX,
|
||||
READ_FULL_FILE_SECURE|READ_FULL_FILE_WARN_WORLD_READABLE|READ_FULL_FILE_CONNECT_SOCKET,
|
||||
bindname,
|
||||
(char**) ret_key, ret_key_size);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to load key file '%s': %m", key_file);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
STRV_FOREACH(i, search_path) {
|
||||
_cleanup_free_ char *joined;
|
||||
|
@ -44,67 +39,19 @@ int load_key_file(
|
|||
if (!joined)
|
||||
return log_oom();
|
||||
|
||||
fd = open(joined, O_RDONLY|O_CLOEXEC);
|
||||
if (fd >= 0) {
|
||||
discovered_path = TAKE_PTR(joined);
|
||||
break;
|
||||
}
|
||||
if (errno != ENOENT)
|
||||
return log_error_errno(errno, "Failed to load key file '%s': %m", joined);
|
||||
r = read_full_file_full(
|
||||
AT_FDCWD, joined, UINT64_MAX, SIZE_MAX,
|
||||
READ_FULL_FILE_SECURE|READ_FULL_FILE_WARN_WORLD_READABLE|READ_FULL_FILE_CONNECT_SOCKET,
|
||||
bindname,
|
||||
(char**) ret_key, ret_key_size);
|
||||
if (r >= 0)
|
||||
return 1;
|
||||
if (r != -ENOENT)
|
||||
return log_error_errno(r, "Failed to load key file '%s': %m", key_file);
|
||||
}
|
||||
|
||||
if (!discovered_path) {
|
||||
/* Search path supplied, but file not found, report by returning NULL, but not failing */
|
||||
*ret_key = NULL;
|
||||
*ret_key_size = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert(fd >= 0);
|
||||
key_file = discovered_path;
|
||||
}
|
||||
|
||||
if (key_file_size == 0) {
|
||||
struct stat st;
|
||||
|
||||
if (fstat(fd, &st) < 0)
|
||||
return log_error_errno(errno, "Failed to stat key file '%s': %m", key_file);
|
||||
|
||||
r = stat_verify_regular(&st);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Key file is not a regular file: %m");
|
||||
|
||||
if (st.st_size == 0)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Key file is empty, refusing.");
|
||||
if ((uint64_t) st.st_size > KEY_FILE_SIZE_MAX) {
|
||||
char buf1[FORMAT_BYTES_MAX], buf2[FORMAT_BYTES_MAX];
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ERANGE),
|
||||
"Key file larger (%s) than allowed maximum size (%s), refusing.",
|
||||
format_bytes(buf1, sizeof(buf1), st.st_size),
|
||||
format_bytes(buf2, sizeof(buf2), KEY_FILE_SIZE_MAX));
|
||||
}
|
||||
|
||||
if (key_file_offset >= (uint64_t) st.st_size)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Key file offset too large for file, refusing.");
|
||||
|
||||
key_file_size = st.st_size - key_file_offset;
|
||||
}
|
||||
|
||||
buffer = malloc(key_file_size);
|
||||
if (!buffer)
|
||||
return log_oom();
|
||||
|
||||
if (key_file_offset > 0)
|
||||
n = pread(fd, buffer, key_file_size, key_file_offset);
|
||||
else
|
||||
n = read(fd, buffer, key_file_size);
|
||||
if (n < 0)
|
||||
return log_error_errno(errno, "Failed to read key file '%s': %m", key_file);
|
||||
if (n == 0)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Empty encrypted key found, refusing.");
|
||||
|
||||
*ret_key = TAKE_PTR(buffer);
|
||||
*ret_key_size = (size_t) n;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -4,10 +4,9 @@
|
|||
#include <inttypes.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
int load_key_file(
|
||||
int find_key_file(
|
||||
const char *key_file,
|
||||
char **search_path,
|
||||
size_t key_file_size,
|
||||
uint64_t key_file_offset,
|
||||
const char *bindname,
|
||||
void **ret_key,
|
||||
size_t *ret_key_size);
|
||||
|
|
|
@ -10,13 +10,14 @@
|
|||
#include "alloc-util.h"
|
||||
#include "ask-password-api.h"
|
||||
#include "cryptsetup-pkcs11.h"
|
||||
#include "cryptsetup-keyfile.h"
|
||||
#include "escape.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
#include "format-util.h"
|
||||
#include "macro.h"
|
||||
#include "memory-util.h"
|
||||
#include "pkcs11-util.h"
|
||||
#include "random-util.h"
|
||||
#include "stat-util.h"
|
||||
#include "strv.h"
|
||||
|
||||
|
@ -95,6 +96,7 @@ static int pkcs11_callback(
|
|||
}
|
||||
|
||||
int decrypt_pkcs11_key(
|
||||
const char *volume_name,
|
||||
const char *friendly_name,
|
||||
const char *pkcs11_uri,
|
||||
const char *key_file, /* We either expect key_file and associated parameters to be set (for file keys) … */
|
||||
|
@ -126,7 +128,19 @@ int decrypt_pkcs11_key(
|
|||
|
||||
data.free_encrypted_key = false;
|
||||
} else {
|
||||
r = load_key_file(key_file, NULL, key_file_size, key_file_offset, &data.encrypted_key, &data.encrypted_key_size);
|
||||
_cleanup_free_ char *bindname = NULL;
|
||||
|
||||
/* If we read the key via AF_UNIX, make this client recognizable */
|
||||
if (asprintf(&bindname, "@%" PRIx64"/cryptsetup-pkcs11/%s", random_u64(), volume_name) < 0)
|
||||
return log_oom();
|
||||
|
||||
r = read_full_file_full(
|
||||
AT_FDCWD, key_file,
|
||||
key_file_offset == 0 ? UINT64_MAX : key_file_offset,
|
||||
key_file_size == 0 ? SIZE_MAX : key_file_size,
|
||||
READ_FULL_FILE_CONNECT_SOCKET,
|
||||
bindname,
|
||||
(char**) &data.encrypted_key, &data.encrypted_key_size);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#if HAVE_P11KIT
|
||||
|
||||
int decrypt_pkcs11_key(
|
||||
const char *volume_name,
|
||||
const char *friendly_name,
|
||||
const char *pkcs11_uri,
|
||||
const char *key_file,
|
||||
|
@ -23,6 +24,7 @@ int decrypt_pkcs11_key(
|
|||
#else
|
||||
|
||||
static inline int decrypt_pkcs11_key(
|
||||
const char *volume_name,
|
||||
const char *friendly_name,
|
||||
const char *pkcs11_uri,
|
||||
const char *key_file,
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "path-util.h"
|
||||
#include "pkcs11-util.h"
|
||||
#include "pretty-print.h"
|
||||
#include "random-util.h"
|
||||
#include "string-util.h"
|
||||
#include "strv.h"
|
||||
|
||||
|
@ -550,6 +551,15 @@ static int attach_tcrypt(
|
|||
return 0;
|
||||
}
|
||||
|
||||
static char *make_bindname(const char *volume) {
|
||||
char *s;
|
||||
|
||||
if (asprintf(&s, "@%" PRIx64"/cryptsetup/%s", random_u64(), volume) < 0)
|
||||
return NULL;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
static int attach_luks_or_plain_or_bitlk(
|
||||
struct crypt_device *cd,
|
||||
const char *name,
|
||||
|
@ -636,6 +646,7 @@ static int attach_luks_or_plain_or_bitlk(
|
|||
bool processed = false;
|
||||
|
||||
r = decrypt_pkcs11_key(
|
||||
name,
|
||||
friendly,
|
||||
arg_pkcs11_uri,
|
||||
key_file, arg_keyfile_size, arg_keyfile_offset,
|
||||
|
@ -735,13 +746,30 @@ static int attach_luks_or_plain_or_bitlk(
|
|||
return log_error_errno(r, "Failed to activate: %m");
|
||||
|
||||
} else if (key_file) {
|
||||
r = crypt_activate_by_keyfile_device_offset(cd, name, arg_key_slot, key_file, arg_keyfile_size, arg_keyfile_offset, flags);
|
||||
if (r == -EPERM) {
|
||||
log_error_errno(r, "Failed to activate with key file '%s'. (Key data incorrect?)", key_file);
|
||||
_cleanup_(erase_and_freep) char *kfdata = NULL;
|
||||
_cleanup_free_ char *bindname = NULL;
|
||||
size_t kfsize;
|
||||
|
||||
/* If we read the key via AF_UNIX, make this client recognizable */
|
||||
bindname = make_bindname(name);
|
||||
if (!bindname)
|
||||
return log_oom();
|
||||
|
||||
r = read_full_file_full(
|
||||
AT_FDCWD, key_file,
|
||||
arg_keyfile_offset == 0 ? UINT64_MAX : arg_keyfile_offset,
|
||||
arg_keyfile_size == 0 ? SIZE_MAX : arg_keyfile_size,
|
||||
READ_FULL_FILE_SECURE|READ_FULL_FILE_WARN_WORLD_READABLE|READ_FULL_FILE_CONNECT_SOCKET,
|
||||
bindname,
|
||||
&kfdata, &kfsize);
|
||||
if (r == -ENOENT) {
|
||||
log_error_errno(r, "Failed to activate, key file '%s' missing.", key_file);
|
||||
return -EAGAIN; /* Log actual error, but return EAGAIN */
|
||||
}
|
||||
if (r == -EINVAL) {
|
||||
log_error_errno(r, "Failed to activate with key file '%s'. (Key file missing?)", key_file);
|
||||
|
||||
r = crypt_activate_by_passphrase(cd, name, arg_key_slot, kfdata, kfsize, flags);
|
||||
if (r == -EPERM) {
|
||||
log_error_errno(r, "Failed to activate with key file '%s'. (Key data incorrect?)", key_file);
|
||||
return -EAGAIN; /* Log actual error, but return EAGAIN */
|
||||
}
|
||||
if (r < 0)
|
||||
|
@ -880,15 +908,21 @@ static int run(int argc, char *argv[]) {
|
|||
(void) mlockall(MCL_FUTURE);
|
||||
|
||||
if (!key_file) {
|
||||
_cleanup_free_ char *bindname = NULL;
|
||||
const char *fn;
|
||||
|
||||
bindname = make_bindname(argv[2]);
|
||||
if (!bindname)
|
||||
return log_oom();
|
||||
|
||||
/* If a key file is not explicitly specified, search for a key in a well defined
|
||||
* search path, and load it. */
|
||||
|
||||
fn = strjoina(argv[2], ".key");
|
||||
r = load_key_file(fn,
|
||||
r = find_key_file(
|
||||
fn,
|
||||
STRV_MAKE("/etc/cryptsetup-keys.d", "/run/cryptsetup-keys.d"),
|
||||
0, 0, /* Note we leave arg_keyfile_offset/arg_keyfile_size as something that only applies to arg_keyfile! */
|
||||
bindname,
|
||||
&key_data, &key_data_size);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "log.h"
|
||||
#include "logs-show.h"
|
||||
#include "main-func.h"
|
||||
#include "memory-util.h"
|
||||
#include "microhttpd-util.h"
|
||||
#include "os-util.h"
|
||||
#include "parse-util.h"
|
||||
|
@ -37,7 +38,7 @@ static char *arg_cert_pem = NULL;
|
|||
static char *arg_trust_pem = NULL;
|
||||
static const char *arg_directory = NULL;
|
||||
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_key_pem, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_key_pem, erase_and_freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_cert_pem, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_trust_pem, freep);
|
||||
|
||||
|
@ -896,7 +897,11 @@ static int parse_argv(int argc, char *argv[]) {
|
|||
if (arg_key_pem)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Key file specified twice");
|
||||
r = read_full_file_full(AT_FDCWD, optarg, READ_FULL_FILE_CONNECT_SOCKET, NULL, &arg_key_pem, NULL);
|
||||
r = read_full_file_full(
|
||||
AT_FDCWD, optarg, UINT64_MAX, SIZE_MAX,
|
||||
READ_FULL_FILE_SECURE|READ_FULL_FILE_WARN_WORLD_READABLE|READ_FULL_FILE_CONNECT_SOCKET,
|
||||
NULL,
|
||||
&arg_key_pem, NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to read key file: %m");
|
||||
assert(arg_key_pem);
|
||||
|
@ -906,7 +911,11 @@ static int parse_argv(int argc, char *argv[]) {
|
|||
if (arg_cert_pem)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Certificate file specified twice");
|
||||
r = read_full_file_full(AT_FDCWD, optarg, READ_FULL_FILE_CONNECT_SOCKET, NULL, &arg_cert_pem, NULL);
|
||||
r = read_full_file_full(
|
||||
AT_FDCWD, optarg, UINT64_MAX, SIZE_MAX,
|
||||
READ_FULL_FILE_CONNECT_SOCKET,
|
||||
NULL,
|
||||
&arg_cert_pem, NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to read certificate file: %m");
|
||||
assert(arg_cert_pem);
|
||||
|
@ -917,14 +926,18 @@ static int parse_argv(int argc, char *argv[]) {
|
|||
if (arg_trust_pem)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"CA certificate file specified twice");
|
||||
r = read_full_file_full(AT_FDCWD, optarg, READ_FULL_FILE_CONNECT_SOCKET, NULL, &arg_trust_pem, NULL);
|
||||
r = read_full_file_full(
|
||||
AT_FDCWD, optarg, UINT64_MAX, SIZE_MAX,
|
||||
READ_FULL_FILE_CONNECT_SOCKET,
|
||||
NULL,
|
||||
&arg_trust_pem, NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to read CA certificate file: %m");
|
||||
assert(arg_trust_pem);
|
||||
break;
|
||||
#else
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Option --trust is not available.");
|
||||
"Option --trust= is not available.");
|
||||
#endif
|
||||
case 'D':
|
||||
arg_directory = optarg;
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "journal-remote-write.h"
|
||||
#include "journal-remote.h"
|
||||
#include "main-func.h"
|
||||
#include "memory-util.h"
|
||||
#include "pretty-print.h"
|
||||
#include "process-util.h"
|
||||
#include "rlimit-util.h"
|
||||
|
@ -1077,12 +1078,20 @@ static int parse_argv(int argc, char *argv[]) {
|
|||
static int load_certificates(char **key, char **cert, char **trust) {
|
||||
int r;
|
||||
|
||||
r = read_full_file_full(AT_FDCWD, arg_key ?: PRIV_KEY_FILE, READ_FULL_FILE_CONNECT_SOCKET, NULL, key, NULL);
|
||||
r = read_full_file_full(
|
||||
AT_FDCWD, arg_key ?: PRIV_KEY_FILE, UINT64_MAX, SIZE_MAX,
|
||||
READ_FULL_FILE_SECURE|READ_FULL_FILE_WARN_WORLD_READABLE|READ_FULL_FILE_CONNECT_SOCKET,
|
||||
NULL,
|
||||
key, NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to read key from file '%s': %m",
|
||||
arg_key ?: PRIV_KEY_FILE);
|
||||
|
||||
r = read_full_file_full(AT_FDCWD, arg_cert ?: CERT_FILE, READ_FULL_FILE_CONNECT_SOCKET, NULL, cert, NULL);
|
||||
r = read_full_file_full(
|
||||
AT_FDCWD, arg_cert ?: CERT_FILE, UINT64_MAX, SIZE_MAX,
|
||||
READ_FULL_FILE_CONNECT_SOCKET,
|
||||
NULL,
|
||||
cert, NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to read certificate from file '%s': %m",
|
||||
arg_cert ?: CERT_FILE);
|
||||
|
@ -1090,7 +1099,11 @@ static int load_certificates(char **key, char **cert, char **trust) {
|
|||
if (arg_trust_all)
|
||||
log_info("Certificate checking disabled.");
|
||||
else {
|
||||
r = read_full_file_full(AT_FDCWD, arg_trust ?: TRUST_FILE, READ_FULL_FILE_CONNECT_SOCKET, NULL, trust, NULL);
|
||||
r = read_full_file_full(
|
||||
AT_FDCWD, arg_trust ?: TRUST_FILE, UINT64_MAX, SIZE_MAX,
|
||||
READ_FULL_FILE_CONNECT_SOCKET,
|
||||
NULL,
|
||||
trust, NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to read CA certificate file '%s': %m",
|
||||
arg_trust ?: TRUST_FILE);
|
||||
|
@ -1106,7 +1119,8 @@ static int load_certificates(char **key, char **cert, char **trust) {
|
|||
static int run(int argc, char **argv) {
|
||||
_cleanup_(journal_remote_server_destroy) RemoteServer s = {};
|
||||
_cleanup_(notify_on_cleanup) const char *notify_message = NULL;
|
||||
_cleanup_free_ char *key = NULL, *cert = NULL, *trust = NULL;
|
||||
_cleanup_(erase_and_freep) char *key = NULL;
|
||||
_cleanup_free_ char *cert = NULL, *trust = NULL;
|
||||
int r;
|
||||
|
||||
log_show_color(true);
|
||||
|
|
|
@ -986,7 +986,7 @@ static int macsec_read_key_file(NetDev *netdev, SecurityAssociation *sa) {
|
|||
(void) warn_file_is_world_accessible(sa->key_file, NULL, NULL, 0);
|
||||
|
||||
r = read_full_file_full(
|
||||
AT_FDCWD, sa->key_file,
|
||||
AT_FDCWD, sa->key_file, UINT64_MAX, SIZE_MAX,
|
||||
READ_FULL_FILE_SECURE | READ_FULL_FILE_UNHEX | READ_FULL_FILE_WARN_WORLD_READABLE | READ_FULL_FILE_CONNECT_SOCKET,
|
||||
NULL, (char **) &key, &key_len);
|
||||
if (r < 0)
|
||||
|
|
|
@ -869,7 +869,7 @@ static int wireguard_read_key_file(const char *filename, uint8_t dest[static WG_
|
|||
(void) warn_file_is_world_accessible(filename, NULL, NULL, 0);
|
||||
|
||||
r = read_full_file_full(
|
||||
AT_FDCWD, filename,
|
||||
AT_FDCWD, filename, UINT64_MAX, SIZE_MAX,
|
||||
READ_FULL_FILE_SECURE | READ_FULL_FILE_UNBASE64 | READ_FULL_FILE_WARN_WORLD_READABLE | READ_FULL_FILE_CONNECT_SOCKET,
|
||||
NULL, &key, &key_len);
|
||||
if (r < 0)
|
||||
|
|
|
@ -1589,7 +1589,10 @@ static int parse_argv(int argc, char *argv[]) {
|
|||
return log_oom();
|
||||
}
|
||||
|
||||
r = read_full_file_full(AT_FDCWD, j ?: p, flags, NULL, &data, &size);
|
||||
r = read_full_file_full(AT_FDCWD, j ?: p, UINT64_MAX, SIZE_MAX,
|
||||
flags,
|
||||
NULL,
|
||||
&data, &size);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to read credential '%s': %m", j ?: p);
|
||||
|
||||
|
|
|
@ -3621,7 +3621,11 @@ static int parse_argv(int argc, char *argv[]) {
|
|||
_cleanup_(erase_and_freep) char *k = NULL;
|
||||
size_t n = 0;
|
||||
|
||||
r = read_full_file_full(AT_FDCWD, optarg, READ_FULL_FILE_SECURE|READ_FULL_FILE_CONNECT_SOCKET, NULL, &k, &n);
|
||||
r = read_full_file_full(
|
||||
AT_FDCWD, optarg, UINT64_MAX, SIZE_MAX,
|
||||
READ_FULL_FILE_SECURE|READ_FULL_FILE_WARN_WORLD_READABLE|READ_FULL_FILE_CONNECT_SOCKET,
|
||||
NULL,
|
||||
&k, &n);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to read key file '%s': %m", optarg);
|
||||
|
||||
|
|
|
@ -2115,7 +2115,7 @@ int verity_settings_load(
|
|||
|
||||
if (verity->root_hash && !verity->root_hash_sig) {
|
||||
if (root_hash_sig_path) {
|
||||
r = read_full_file_full(AT_FDCWD, root_hash_sig_path, 0, NULL, (char**) &root_hash_sig, &root_hash_sig_size);
|
||||
r = read_full_file(root_hash_sig_path, (char**) &root_hash_sig, &root_hash_sig_size);
|
||||
if (r < 0 && r != -ENOENT)
|
||||
return r;
|
||||
|
||||
|
@ -2131,7 +2131,7 @@ int verity_settings_load(
|
|||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
r = read_full_file_full(AT_FDCWD, p, 0, NULL, (char**) &root_hash_sig, &root_hash_sig_size);
|
||||
r = read_full_file(p, (char**) &root_hash_sig, &root_hash_sig_size);
|
||||
if (r < 0 && r != -ENOENT)
|
||||
return r;
|
||||
if (r >= 0)
|
||||
|
@ -2145,7 +2145,7 @@ int verity_settings_load(
|
|||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
r = read_full_file_full(AT_FDCWD, p, 0, NULL, (char**) &root_hash_sig, &root_hash_sig_size);
|
||||
r = read_full_file(p, (char**) &root_hash_sig, &root_hash_sig_size);
|
||||
if (r < 0 && r != -ENOENT)
|
||||
return r;
|
||||
if (r >= 0)
|
||||
|
|
|
@ -3195,7 +3195,7 @@ int json_parse_file_at(FILE *f, int dir_fd, const char *path, JsonParseFlags fla
|
|||
if (f)
|
||||
r = read_full_stream(f, &text, NULL);
|
||||
else if (path)
|
||||
r = read_full_file_full(dir_fd, path, 0, NULL, &text, NULL);
|
||||
r = read_full_file_full(dir_fd, path, UINT64_MAX, SIZE_MAX, 0, NULL, &text, NULL);
|
||||
else
|
||||
return -EINVAL;
|
||||
if (r < 0)
|
||||
|
|
|
@ -911,8 +911,8 @@ static void test_read_full_file_socket(void) {
|
|||
_exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
assert_se(read_full_file_full(AT_FDCWD, j, 0, NULL, &data, &size) == -ENXIO);
|
||||
assert_se(read_full_file_full(AT_FDCWD, j, READ_FULL_FILE_CONNECT_SOCKET, clientname, &data, &size) >= 0);
|
||||
assert_se(read_full_file_full(AT_FDCWD, j, UINT64_MAX, SIZE_MAX, 0, NULL, &data, &size) == -ENXIO);
|
||||
assert_se(read_full_file_full(AT_FDCWD, j, UINT64_MAX, SIZE_MAX, READ_FULL_FILE_CONNECT_SOCKET, clientname, &data, &size) >= 0);
|
||||
assert_se(size == strlen(TEST_STR));
|
||||
assert_se(streq(data, TEST_STR));
|
||||
|
||||
|
@ -920,6 +920,50 @@ static void test_read_full_file_socket(void) {
|
|||
#undef TEST_STR
|
||||
}
|
||||
|
||||
static void test_read_full_file_offset_size(void) {
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
_cleanup_(unlink_and_freep) char *fn = NULL;
|
||||
_cleanup_free_ char *rbuf = NULL;
|
||||
size_t rbuf_size;
|
||||
uint8_t buf[4711];
|
||||
|
||||
random_bytes(buf, sizeof(buf));
|
||||
|
||||
assert_se(tempfn_random_child(NULL, NULL, &fn) >= 0);
|
||||
assert_se(f = fopen(fn, "we"));
|
||||
assert_se(fwrite(buf, 1, sizeof(buf), f) == sizeof(buf));
|
||||
assert_se(fflush_and_check(f) >= 0);
|
||||
|
||||
assert_se(read_full_file_full(AT_FDCWD, fn, UINT64_MAX, SIZE_MAX, 0, NULL, &rbuf, &rbuf_size) >= 0);
|
||||
assert_se(rbuf_size == sizeof(buf));
|
||||
assert_se(memcmp(buf, rbuf, rbuf_size) == 0);
|
||||
rbuf = mfree(rbuf);
|
||||
|
||||
assert_se(read_full_file_full(AT_FDCWD, fn, UINT64_MAX, 128, 0, NULL, &rbuf, &rbuf_size) >= 0);
|
||||
assert_se(rbuf_size == 128);
|
||||
assert_se(memcmp(buf, rbuf, rbuf_size) == 0);
|
||||
rbuf = mfree(rbuf);
|
||||
|
||||
assert_se(read_full_file_full(AT_FDCWD, fn, 1234, SIZE_MAX, 0, NULL, &rbuf, &rbuf_size) >= 0);
|
||||
assert_se(rbuf_size == sizeof(buf) - 1234);
|
||||
assert_se(memcmp(buf + 1234, rbuf, rbuf_size) == 0);
|
||||
rbuf = mfree(rbuf);
|
||||
|
||||
assert_se(read_full_file_full(AT_FDCWD, fn, 2345, 777, 0, NULL, &rbuf, &rbuf_size) >= 0);
|
||||
assert_se(rbuf_size == 777);
|
||||
assert_se(memcmp(buf + 2345, rbuf, rbuf_size) == 0);
|
||||
rbuf = mfree(rbuf);
|
||||
|
||||
assert_se(read_full_file_full(AT_FDCWD, fn, 4700, 20, 0, NULL, &rbuf, &rbuf_size) >= 0);
|
||||
assert_se(rbuf_size == 11);
|
||||
assert_se(memcmp(buf + 4700, rbuf, rbuf_size) == 0);
|
||||
rbuf = mfree(rbuf);
|
||||
|
||||
assert_se(read_full_file_full(AT_FDCWD, fn, 10000, 99, 0, NULL, &rbuf, &rbuf_size) >= 0);
|
||||
assert_se(rbuf_size == 0);
|
||||
rbuf = mfree(rbuf);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
test_setup_logging(LOG_DEBUG);
|
||||
|
||||
|
@ -946,6 +990,7 @@ int main(int argc, char *argv[]) {
|
|||
test_read_line4();
|
||||
test_read_nul_string();
|
||||
test_read_full_file_socket();
|
||||
test_read_full_file_offset_size();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -100,7 +100,11 @@ static int run(int argc, char *argv[]) {
|
|||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse root hash signature '%s': %m", argv[6]);
|
||||
} else {
|
||||
r = read_full_file_full(AT_FDCWD, argv[6], READ_FULL_FILE_CONNECT_SOCKET, NULL, &hash_sig, &hash_sig_size);
|
||||
r = read_full_file_full(
|
||||
AT_FDCWD, argv[6], UINT64_MAX, SIZE_MAX,
|
||||
READ_FULL_FILE_CONNECT_SOCKET,
|
||||
NULL,
|
||||
&hash_sig, &hash_sig_size);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to read root hash signature: %m");
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue