From f362fe731bc7d78ce915b4cdb69ad3ad46536bf5 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 4 Nov 2020 16:13:09 +0100 Subject: [PATCH 01/13] journal-remote: erase secret PEM key from memory after use --- src/journal-remote/journal-gatewayd.c | 3 ++- src/journal-remote/journal-remote-main.c | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/journal-remote/journal-gatewayd.c b/src/journal-remote/journal-gatewayd.c index 0723f7d8bb..09c7ca4573 100644 --- a/src/journal-remote/journal-gatewayd.c +++ b/src/journal-remote/journal-gatewayd.c @@ -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); diff --git a/src/journal-remote/journal-remote-main.c b/src/journal-remote/journal-remote-main.c index d2aa1815c2..16759aa6b5 100644 --- a/src/journal-remote/journal-remote-main.c +++ b/src/journal-remote/journal-remote-main.c @@ -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" @@ -1106,7 +1107,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); From ae9cf30b2f22500a250d3132e1a9a49380c4c5eb Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 4 Nov 2020 16:17:26 +0100 Subject: [PATCH 02/13] dissect-image: use simple version of read_full_file() where we can --- src/shared/dissect-image.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/shared/dissect-image.c b/src/shared/dissect-image.c index b32a8bc4e4..c2c46e1816 100644 --- a/src/shared/dissect-image.c +++ b/src/shared/dissect-image.c @@ -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) From 8b3c3a49739d6fc10b8d0805b7ede9a330cf7d95 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 4 Nov 2020 16:19:49 +0100 Subject: [PATCH 03/13] repart: warn about world writable key files We have easy support for this, hence use it for privileged key data. --- src/partition/repart.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/partition/repart.c b/src/partition/repart.c index 6db413ed5e..58cacab244 100644 --- a/src/partition/repart.c +++ b/src/partition/repart.c @@ -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, + 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); From e5de42e6f26a0323bd4ac027140c1dc075b664fb Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 4 Nov 2020 16:21:26 +0100 Subject: [PATCH 04/13] journal-remote: use READ_FULL_FILE_SECURE|READ_FULL_FILE_WARN_WORLD_READABLE when reading PEM secret key It's secret data, hence use the appropriate flags. --- src/journal-remote/journal-gatewayd.c | 6 +++++- src/journal-remote/journal-remote-main.c | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/journal-remote/journal-gatewayd.c b/src/journal-remote/journal-gatewayd.c index 09c7ca4573..15d5b15eaa 100644 --- a/src/journal-remote/journal-gatewayd.c +++ b/src/journal-remote/journal-gatewayd.c @@ -897,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, + 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); diff --git a/src/journal-remote/journal-remote-main.c b/src/journal-remote/journal-remote-main.c index 16759aa6b5..a78896c14f 100644 --- a/src/journal-remote/journal-remote-main.c +++ b/src/journal-remote/journal-remote-main.c @@ -1078,7 +1078,11 @@ 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, + 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); From ce82de671f63105e9839978b432e2b015783ffc0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 4 Nov 2020 16:23:11 +0100 Subject: [PATCH 05/13] man: mention that --key= is about *secret* keys --- man/systemd-journal-gatewayd.service.xml | 4 ++-- man/systemd-journal-remote.service.xml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/man/systemd-journal-gatewayd.service.xml b/man/systemd-journal-gatewayd.service.xml index 61a4037669..43ceb97032 100644 --- a/man/systemd-journal-gatewayd.service.xml +++ b/man/systemd-journal-gatewayd.service.xml @@ -68,8 +68,8 @@ Specify the path to a file or AF_UNIX stream socket to read the - server key corresponding to the certificate specified with from. The key - must be in PEM format. + secret server key corresponding to the certificate specified with from. The + key must be in PEM format. diff --git a/man/systemd-journal-remote.service.xml b/man/systemd-journal-remote.service.xml index 6e068a617a..bea0936d66 100644 --- a/man/systemd-journal-remote.service.xml +++ b/man/systemd-journal-remote.service.xml @@ -180,7 +180,7 @@ - Takes a path to a SSL key file in PEM format. Defaults to + Takes a path to a SSL secret key file in PEM format. Defaults to &CERTIFICATE_ROOT;/private/journal-remote.pem. This option can be used with . If the path refers to an AF_UNIX stream socket in the file system a connection is made to it and the key read from it. From c61f46fe3142e8b2fee48c845339bd82e29df085 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 4 Nov 2020 20:24:57 +0100 Subject: [PATCH 06/13] journal-remote: suffix cmdline option that expects arg with = --- src/journal-remote/journal-gatewayd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/journal-remote/journal-gatewayd.c b/src/journal-remote/journal-gatewayd.c index 15d5b15eaa..362c61203a 100644 --- a/src/journal-remote/journal-gatewayd.c +++ b/src/journal-remote/journal-gatewayd.c @@ -929,7 +929,7 @@ static int parse_argv(int argc, char *argv[]) { 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; From 986311c2da873ea24ee05e59e97c60f5584e4226 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 4 Nov 2020 20:25:06 +0100 Subject: [PATCH 07/13] fileio: teach read_full_file_full() to read from offset/with maximum size --- src/basic/fileio.c | 56 +++++++++++++++++------- src/basic/fileio.h | 12 ++--- src/core/execute.c | 2 +- src/journal-remote/journal-gatewayd.c | 14 ++++-- src/journal-remote/journal-remote-main.c | 14 ++++-- src/network/netdev/macsec.c | 2 +- src/network/netdev/wireguard.c | 2 +- src/nspawn/nspawn.c | 5 ++- src/partition/repart.c | 2 +- src/shared/json.c | 2 +- src/test/test-fileio.c | 49 ++++++++++++++++++++- src/veritysetup/veritysetup.c | 6 ++- 12 files changed, 130 insertions(+), 36 deletions(-) diff --git a/src/basic/fileio.c b/src/basic/fileio.c index 973756c891..f4708bc05f 100644 --- a/src/basic/fileio.c +++ b/src/basic/fileio.c @@ -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) - return -E2BIG; + /* Safety check */ + 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. */ - if (st.st_size > 0) - n_next = st.st_size + 1; + /* 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 = 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) { diff --git a/src/basic/fileio.h b/src/basic/fileio.h index 0886354cbc..498e880354 100644 --- a/src/basic/fileio.h +++ b/src/basic/fileio.h @@ -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); diff --git a/src/core/execute.c b/src/core/execute.c index f1f3744191..56793c5a43 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -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 && diff --git a/src/journal-remote/journal-gatewayd.c b/src/journal-remote/journal-gatewayd.c index 362c61203a..534de51b0f 100644 --- a/src/journal-remote/journal-gatewayd.c +++ b/src/journal-remote/journal-gatewayd.c @@ -898,7 +898,7 @@ static int parse_argv(int argc, char *argv[]) { return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Key file specified twice"); r = read_full_file_full( - AT_FDCWD, optarg, + 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); @@ -911,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); @@ -922,7 +926,11 @@ 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); diff --git a/src/journal-remote/journal-remote-main.c b/src/journal-remote/journal-remote-main.c index a78896c14f..af8cde7eef 100644 --- a/src/journal-remote/journal-remote-main.c +++ b/src/journal-remote/journal-remote-main.c @@ -1079,7 +1079,7 @@ static int load_certificates(char **key, char **cert, char **trust) { int r; r = read_full_file_full( - AT_FDCWD, arg_key ?: PRIV_KEY_FILE, + 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); @@ -1087,7 +1087,11 @@ static int load_certificates(char **key, char **cert, char **trust) { 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); @@ -1095,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); diff --git a/src/network/netdev/macsec.c b/src/network/netdev/macsec.c index 313277ca16..27fc2fd5e5 100644 --- a/src/network/netdev/macsec.c +++ b/src/network/netdev/macsec.c @@ -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) diff --git a/src/network/netdev/wireguard.c b/src/network/netdev/wireguard.c index 416e9b92d1..76444bdd7c 100644 --- a/src/network/netdev/wireguard.c +++ b/src/network/netdev/wireguard.c @@ -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) diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 0842731c18..ad2f572869 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -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); diff --git a/src/partition/repart.c b/src/partition/repart.c index 58cacab244..ddb9476cec 100644 --- a/src/partition/repart.c +++ b/src/partition/repart.c @@ -3622,7 +3622,7 @@ static int parse_argv(int argc, char *argv[]) { size_t n = 0; r = read_full_file_full( - AT_FDCWD, optarg, + 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); diff --git a/src/shared/json.c b/src/shared/json.c index ddf6dcb663..28fe482749 100644 --- a/src/shared/json.c +++ b/src/shared/json.c @@ -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) diff --git a/src/test/test-fileio.c b/src/test/test-fileio.c index 431aea07ef..a5834eba36 100644 --- a/src/test/test-fileio.c +++ b/src/test/test-fileio.c @@ -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; } diff --git a/src/veritysetup/veritysetup.c b/src/veritysetup/veritysetup.c index 558e9510ff..9b8bca11f2 100644 --- a/src/veritysetup/veritysetup.c +++ b/src/veritysetup/veritysetup.c @@ -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"); } From 4d1bb8f39702630c52d6b3599e4fc96ee31b84aa Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 4 Nov 2020 17:22:39 +0100 Subject: [PATCH 08/13] cryptsetup: port PKCS#11 code to read key file with read_full_file() Now that we can read from offsets/with size, let's port the cryptsetup PKCS#11 key file logic over to read_full_file_full(). --- src/cryptsetup/cryptsetup-pkcs11.c | 18 ++++++++++++++++-- src/cryptsetup/cryptsetup-pkcs11.h | 2 ++ src/cryptsetup/cryptsetup.c | 1 + 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/cryptsetup/cryptsetup-pkcs11.c b/src/cryptsetup/cryptsetup-pkcs11.c index 50db46f8d1..b645ff28e0 100644 --- a/src/cryptsetup/cryptsetup-pkcs11.c +++ b/src/cryptsetup/cryptsetup-pkcs11.c @@ -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; diff --git a/src/cryptsetup/cryptsetup-pkcs11.h b/src/cryptsetup/cryptsetup-pkcs11.h index 266c8e1b3e..522ed28bd3 100644 --- a/src/cryptsetup/cryptsetup-pkcs11.h +++ b/src/cryptsetup/cryptsetup-pkcs11.h @@ -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, diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c index 5f9d7bb3bb..7f95749f2f 100644 --- a/src/cryptsetup/cryptsetup.c +++ b/src/cryptsetup/cryptsetup.c @@ -636,6 +636,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, From e2c2f868b28f1445e061bf7eb475b0c49efe3ac2 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 4 Nov 2020 17:24:53 +0100 Subject: [PATCH 09/13] cryptsetup: port cryptsetup's main key file logic over to read_full_file_full() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously, we'd load the file with libcryptsetup's calls. Let's do that in our own, so that we can make use of READ_FULL_FILE_CONNECT_SOCKET, i.e. read in keys via AF_UNIX sockets, so that people can plug key providers into our logic. This provides functionality similar to Debian's keyscript= crypttab option (see → #3007), as it allows key scripts to be run as socket activated services, that have stdout connected to the activated socket. In contrast to traditional keyscript= support this logic runs stuff out of process however, which is beneficial, since it allows sandboxing and similar. --- src/cryptsetup/cryptsetup.c | 37 ++++++++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c index 7f95749f2f..e32cc9207c 100644 --- a/src/cryptsetup/cryptsetup.c +++ b/src/cryptsetup/cryptsetup.c @@ -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, @@ -736,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) From e060ed32e46bdd7583dcad87ff462ff4c006115f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 4 Nov 2020 18:15:42 +0100 Subject: [PATCH 10/13] cryptsetup: modify keyfile search logic to use read_file_full() too Let's move the 3rd way how cryptsetup acquires key files to read_file_full() too. Since load_key_file()'s raison d'etre now is just the search path logic, let's rename the function to find_key_file(). --- src/cryptsetup/cryptsetup-keyfile.c | 113 ++++++++-------------------- src/cryptsetup/cryptsetup-keyfile.h | 5 +- src/cryptsetup/cryptsetup.c | 14 +++- 3 files changed, 42 insertions(+), 90 deletions(-) diff --git a/src/cryptsetup/cryptsetup-keyfile.c b/src/cryptsetup/cryptsetup-keyfile.c index f849123563..a6281fbdee 100644 --- a/src/cryptsetup/cryptsetup-keyfile.c +++ b/src/cryptsetup/cryptsetup-keyfile.c @@ -1,29 +1,18 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ -#include - #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,80 +20,38 @@ 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; - STRV_FOREACH(i, search_path) { - _cleanup_free_ char *joined; - - joined = path_join(*i, 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); - } - - 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); + 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, "Key file is not a regular file: %m"); + return log_error_errno(r, "Failed to load key file '%s': %m", key_file); - 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; + return 1; } - buffer = malloc(key_file_size); - if (!buffer) - return log_oom(); + STRV_FOREACH(i, search_path) { + _cleanup_free_ char *joined; - 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."); + joined = path_join(*i, key_file); + if (!joined) + return log_oom(); - *ret_key = TAKE_PTR(buffer); - *ret_key_size = (size_t) n; + 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); + } - return 1; + /* Search path supplied, but file not found, report by returning NULL, but not failing */ + *ret_key = NULL; + *ret_key_size = 0; + return 0; } diff --git a/src/cryptsetup/cryptsetup-keyfile.h b/src/cryptsetup/cryptsetup-keyfile.h index 308f5ebd68..83bd1fbed2 100644 --- a/src/cryptsetup/cryptsetup-keyfile.h +++ b/src/cryptsetup/cryptsetup-keyfile.h @@ -4,10 +4,9 @@ #include #include -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); diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c index e32cc9207c..78d8eec1d7 100644 --- a/src/cryptsetup/cryptsetup.c +++ b/src/cryptsetup/cryptsetup.c @@ -908,16 +908,22 @@ 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, - 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! */ - &key_data, &key_data_size); + r = find_key_file( + fn, + STRV_MAKE("/etc/cryptsetup-keys.d", "/run/cryptsetup-keys.d"), + bindname, + &key_data, &key_data_size); if (r < 0) return r; if (r > 0) From 96e9a9a4e6438704518fea394c128477b5249ed4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 4 Nov 2020 20:20:41 +0100 Subject: [PATCH 11/13] man: document how cryptsetup keys may be acquired via AF_UNIX sockets --- man/crypttab.xml | 71 +++++++++++++++++++++++++++++++++++++----------- 1 file changed, 55 insertions(+), 16 deletions(-) diff --git a/man/crypttab.xml b/man/crypttab.xml index 14bf93a0f7..04695f626f 100644 --- a/man/crypttab.xml +++ b/man/crypttab.xml @@ -53,25 +53,36 @@ it is opened as a LUKS device; otherwise, it is assumed to be in raw dm-crypt (plain mode) format. - The first field contains the name of the resulting encrypted volume; its block device is set up - below /dev/mapper/. + The four fields of /etc/crypttab are defined as follows: - The second field contains a path to the underlying block - device or file, or a specification of a block device via - UUID= followed by the UUID. + - The third field specifies an absolute path to a file with the encryption key. Optionally, - the path may be followed by : and an fstab device specification (e.g. starting with - LABEL= or similar); in which case the path is taken relative to the device file system - root. If the field is not present or is none or -, a key file - named after the volume to unlock (i.e. the first column of the line), suffixed with - .key is automatically loaded from the /etc/cryptsetup-keys.d/ - and /run/cryptsetup-keys.d/ directories, if present. Otherwise, the password has to - be manually entered during system boot. For swap encryption, /dev/urandom may be - used as key file. + The first field contains the name of the resulting volume with decrypted data; its + block device is set up below /dev/mapper/. - The fourth field, if present, is a comma-delimited list of - options. The following options are recognized: + The second field contains a path to the underlying block + device or file, or a specification of a block device via + UUID= followed by the UUID. + + The third field specifies an absolute path to a file with the encryption + key. Optionally, the path may be followed by : and an fstab device specification + (e.g. starting with LABEL= or similar); in which case the path is taken relative to + the device file system root. If the field is not present or is none or + -, a key file named after the volume to unlock (i.e. the first column of the line), + suffixed with .key is automatically loaded from the + /etc/cryptsetup-keys.d/ and /run/cryptsetup-keys.d/ + directories, if present. Otherwise, the password has to be manually entered during system boot. For + swap encryption, /dev/urandom may be used as key file, resulting in a randomized + key. + + If the specified key file path refers to an AF_UNIX 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. + + The fourth field, if present, is a comma-delimited list of options. The suppported + options are listed below. + @@ -499,6 +510,34 @@ systemd-cryptsetup-generator8. + + <constant>AF_UNIX</constant> Key Files + + If the key file path (as specified in the third column of /etc/crypttab + entries, see above) refers to an AF_UNIX 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 AF_UNIX socket name in the abstract namespace, see unix7 for + details. The source socket name is chosen according the following format: + + NUL RANDOM /cryptsetup/ VOLUME + + In other words: a NUL byte (as required for abstract namespace sockets), + followed by a random string (consisting of alphabenumeric characters only), followed by the literal + string /cryptsetup/, followed by the name of the volume to acquire they key + for. Example (for a volume myvol): + + \0d7067f78d9827418/cryptsetup/myvol + + Services listening on the AF_UNIX stream socket may query the source socket + name with getpeername2, + 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 /cryptsetup-pkcs11/ 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. + Examples From 59d6f7b097ab67b8353db96dfcb1907fce7f5bc6 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 1 Dec 2020 14:23:38 +0100 Subject: [PATCH 12/13] man: drop comment about ECC vs. RSA and Yubikey The comment is pointless, ECC systematically doesn't allow encryption/decryption directly, only RSA does that. If you want to use ECC for asymmetric encryption/decryption you have to combine it with key exchange scheme and symmetric scheme. This all is not a limitation of the Yubikey, hence don't claim so. It's just how ECC is. --- man/crypttab.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/man/crypttab.xml b/man/crypttab.xml index 04695f626f..93c0ec01e4 100644 --- a/man/crypttab.xml +++ b/man/crypttab.xml @@ -568,7 +568,6 @@ external /dev/sda3 keyfile:LABEL=keydev keyfile-timeout=10s,cipher=xchac A few notes on the above: - We use RSA (and not ECC), since Yubikeys support PKCS#11 Decrypt() only for RSA keys We use RSA2048, which is the longest key size current Yubikeys support LUKS key size must be shorter than 2048bit due to RSA padding, hence we use 128 bytes We use Yubikey key slot 9d, since that's apparently the keyslot to use for decryption purposes, From 8c437318b85655f43e325929df10708b09123708 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 4 Nov 2020 18:43:12 +0100 Subject: [PATCH 13/13] update TODO --- TODO | 3 --- 1 file changed, 3 deletions(-) diff --git a/TODO b/TODO index 89f7455e5b..bd5bdda744 100644 --- a/TODO +++ b/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.