summaryrefslogtreecommitdiffstats
path: root/src/journal/journalctl-authenticate.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/journal/journalctl-authenticate.c207
1 files changed, 207 insertions, 0 deletions
diff --git a/src/journal/journalctl-authenticate.c b/src/journal/journalctl-authenticate.c
new file mode 100644
index 0000000..10630f5
--- /dev/null
+++ b/src/journal/journalctl-authenticate.c
@@ -0,0 +1,207 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "chattr-util.h"
+#include "errno-util.h"
+#include "fd-util.h"
+#include "fs-util.h"
+#include "fsprg.h"
+#include "hostname-util.h"
+#include "io-util.h"
+#include "journal-authenticate.h"
+#include "journalctl.h"
+#include "journalctl-authenticate.h"
+#include "memstream-util.h"
+#include "path-util.h"
+#include "qrcode-util.h"
+#include "random-util.h"
+#include "stat-util.h"
+#include "terminal-util.h"
+#include "tmpfile-util.h"
+
+static int format_key(
+ const void *seed,
+ size_t seed_size,
+ uint64_t start,
+ uint64_t interval,
+ char **ret) {
+
+ _cleanup_(memstream_done) MemStream m = {};
+ FILE *f;
+
+ assert(seed);
+ assert(seed_size > 0);
+ assert(ret);
+
+ f = memstream_init(&m);
+ if (!f)
+ return -ENOMEM;
+
+ for (size_t i = 0; i < seed_size; i++) {
+ if (i > 0 && i % 3 == 0)
+ fputc('-', f);
+ fprintf(f, "%02x", ((uint8_t*) seed)[i]);
+ }
+
+ fprintf(f, "/%"PRIx64"-%"PRIx64, start, interval);
+
+ return memstream_finalize(&m, ret, NULL);
+}
+
+int action_setup_keys(void) {
+ _cleanup_(unlink_and_freep) char *tmpfile = NULL;
+ _cleanup_close_ int fd = -EBADF;
+ _cleanup_free_ char *path = NULL;
+ size_t mpk_size, seed_size, state_size;
+ uint8_t *mpk, *seed, *state;
+ sd_id128_t machine, boot;
+ uint64_t n;
+ int r;
+
+ assert(arg_action == ACTION_SETUP_KEYS);
+
+ r = is_dir("/var/log/journal/", /* follow = */ false);
+ if (r == 0)
+ return log_error_errno(SYNTHETIC_ERRNO(ENOTDIR),
+ "/var/log/journal is not a directory, must be using persistent logging for FSS.");
+ if (r == -ENOENT)
+ return log_error_errno(r, "Directory /var/log/journal/ does not exist, must be using persistent logging for FSS.");
+ if (r < 0)
+ return log_error_errno(r, "Failed to check if /var/log/journal/ is a directory: %m");
+
+ r = sd_id128_get_machine(&machine);
+ if (r < 0)
+ return log_error_errno(r, "Failed to get machine ID: %m");
+
+ r = sd_id128_get_boot(&boot);
+ if (r < 0)
+ return log_error_errno(r, "Failed to get boot ID: %m");
+
+ path = path_join("/var/log/journal/", SD_ID128_TO_STRING(machine), "/fss");
+ if (!path)
+ return log_oom();
+
+ if (arg_force) {
+ if (unlink(path) < 0 && errno != ENOENT)
+ return log_error_errno(errno, "Failed to remove \"%s\": %m", path);
+ } else if (access(path, F_OK) >= 0)
+ return log_error_errno(SYNTHETIC_ERRNO(EEXIST),
+ "Sealing key file %s exists already. Use --force to recreate.", path);
+
+ mpk_size = FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR);
+ mpk = alloca_safe(mpk_size);
+
+ seed_size = FSPRG_RECOMMENDED_SEEDLEN;
+ seed = alloca_safe(seed_size);
+
+ state_size = FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR);
+ state = alloca_safe(state_size);
+
+ log_info("Generating seed...");
+ r = crypto_random_bytes(seed, seed_size);
+ if (r < 0)
+ return log_error_errno(r, "Failed to acquire random seed: %m");
+
+ log_info("Generating key pair...");
+ r = FSPRG_GenMK(NULL, mpk, seed, seed_size, FSPRG_RECOMMENDED_SECPAR);
+ if (r < 0)
+ return log_error_errno(r, "Failed to generate key pair: %m");
+
+ log_info("Generating sealing key...");
+ r = FSPRG_GenState0(state, mpk, seed, seed_size);
+ if (r < 0)
+ return log_error_errno(r, "Failed to generate sealing key: %m");
+
+ assert(arg_interval > 0);
+ n = now(CLOCK_REALTIME);
+ n /= arg_interval;
+
+ fd = open_tmpfile_linkable(path, O_WRONLY|O_CLOEXEC, &tmpfile);
+ if (fd < 0)
+ return log_error_errno(fd, "Failed to open a temporary file for %s: %m", path);
+
+ r = chattr_secret(fd, CHATTR_WARN_UNSUPPORTED_FLAGS);
+ if (r < 0)
+ log_full_errno(ERRNO_IS_NOT_SUPPORTED(r) ? LOG_DEBUG : LOG_WARNING,
+ r, "Failed to set file attributes on a temporary file for '%s', ignoring: %m", path);
+
+ struct FSSHeader h = {
+ .signature = { 'K', 'S', 'H', 'H', 'R', 'H', 'L', 'P' },
+ .machine_id = machine,
+ .boot_id = boot,
+ .header_size = htole64(sizeof(h)),
+ .start_usec = htole64(n * arg_interval),
+ .interval_usec = htole64(arg_interval),
+ .fsprg_secpar = htole16(FSPRG_RECOMMENDED_SECPAR),
+ .fsprg_state_size = htole64(state_size),
+ };
+
+ r = loop_write(fd, &h, sizeof(h));
+ if (r < 0)
+ return log_error_errno(r, "Failed to write header: %m");
+
+ r = loop_write(fd, state, state_size);
+ if (r < 0)
+ return log_error_errno(r, "Failed to write state: %m");
+
+ r = link_tmpfile(fd, tmpfile, path, /* flags = */ 0);
+ if (r < 0)
+ return log_error_errno(r, "Failed to link file: %m");
+
+ tmpfile = mfree(tmpfile);
+
+ _cleanup_free_ char *key = NULL;
+ r = format_key(seed, seed_size, n, arg_interval, &key);
+ if (r < 0)
+ return r;
+
+ if (!on_tty()) {
+ /* If we are not on a TTY, show only the key. */
+ puts(key);
+ return 0;
+ }
+
+ _cleanup_free_ char *hn = NULL;
+ hn = gethostname_malloc();
+ if (hn)
+ hostname_cleanup(hn);
+
+ fprintf(stderr,
+ "\nNew keys have been generated for host %s%s" SD_ID128_FORMAT_STR ".\n"
+ "\n"
+ "The %ssecret sealing key%s has been written to the following local file.\n"
+ "This key file is automatically updated when the sealing key is advanced.\n"
+ "It should not be used on multiple hosts.\n"
+ "\n"
+ "\t%s\n"
+ "\n"
+ "The sealing key is automatically changed every %s.\n"
+ "\n"
+ "Please write down the following %ssecret verification key%s. It should be stored\n"
+ "in a safe location and should not be saved locally on disk.\n"
+ "\n\t%s",
+ strempty(hn), hn ? "/" : "",
+ SD_ID128_FORMAT_VAL(machine),
+ ansi_highlight(), ansi_normal(),
+ path,
+ FORMAT_TIMESPAN(arg_interval, 0),
+ ansi_highlight(), ansi_normal(),
+ ansi_highlight_red());
+ fflush(stderr);
+
+ puts(key);
+
+ fputs(ansi_normal(), stderr);
+
+#if HAVE_QRENCODE
+ _cleanup_free_ char *url = NULL;
+ url = strjoin("fss://", key, "?machine=", SD_ID128_TO_STRING(machine), hn ? ";hostname=" : "", hn);
+ if (!url)
+ return log_oom();
+
+ (void) print_qrcode(stderr,
+ "To transfer the verification key to your phone scan the QR code below",
+ url);
+#endif
+
+ return 0;
+}