]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sd-journal: introduce JournalAuthContext
authorYu Watanabe <watanabe.yu+github@gmail.com>
Thu, 25 Jun 2026 16:26:21 +0000 (01:26 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Sat, 27 Jun 2026 15:00:09 +0000 (00:00 +0900)
Then, move several components for journal tagging in JournalFile
to JournalAuthContext.
This also introduces wrapper functions that checks gcrypt support.

14 files changed:
src/journal/journald-manager.c
src/journal/journald.c
src/libsystemd/meson.build
src/libsystemd/sd-journal/journal-authenticate-internal.c [new file with mode: 0644]
src/libsystemd/sd-journal/journal-authenticate-internal.h [new file with mode: 0644]
src/libsystemd/sd-journal/journal-authenticate.c
src/libsystemd/sd-journal/journal-authenticate.h
src/libsystemd/sd-journal/journal-def.h
src/libsystemd/sd-journal/journal-file.c
src/libsystemd/sd-journal/journal-file.h
src/libsystemd/sd-journal/journal-verify.c
src/libsystemd/sd-journal/test-journal.c
src/shared/journal-file-util.c
src/shared/journal-file-util.h

index 764e5091ab3fdc8b7d7314c91d89f296f56655d2..68f95ea96782ea1160de7ddf78dfac0f3c84ca97 100644 (file)
@@ -697,7 +697,10 @@ static int manager_archive_offline_user_journals(Manager *m) {
 
                 TAKE_FD(fd); /* Donated to journal_file_open() */
 
-                journal_file_write_final_tag(f);
+                r = journal_file_auth_append_tag(f);
+                if (r < 0)
+                        log_debug_errno(r, "Failed to append tag when closing journal, ignoring: %m");
+
                 r = journal_file_archive(f, NULL);
                 if (r < 0)
                         log_debug_errno(r, "Failed to archive journal file '%s', ignoring: %m", full);
@@ -2539,18 +2542,16 @@ int manager_init(Manager *m) {
 }
 
 void manager_maybe_append_tags(Manager *m) {
-#if HAVE_GCRYPT
-        JournalFile *f;
-        usec_t n;
+        assert(m);
 
-        n = now(CLOCK_REALTIME);
+        usec_t n = now(CLOCK_REALTIME);
 
         if (m->system_journal)
-                journal_file_maybe_append_tag(m->system_journal, n);
+                journal_file_auth_append_tag_maybe(m->system_journal, n);
 
+        JournalFile *f;
         ORDERED_HASHMAP_FOREACH(f, m->user_journals)
-                journal_file_maybe_append_tag(f, n);
-#endif
+                journal_file_auth_append_tag_maybe(f, n);
 }
 
 Manager* manager_free(Manager *m) {
index 9ab5fdfdedb43cf0dd1e62edb577533b013b5254..f72ba2cc9070b6e7707a27553a1f42dd02d056c7 100644 (file)
@@ -110,14 +110,12 @@ static int run(int argc, char *argv[]) {
                 } else
                         t = USEC_INFINITY;
 
-#if HAVE_GCRYPT
                 if (m->system_journal) {
                         usec_t u;
 
-                        if (journal_file_next_evolve_usec(m->system_journal, &u) >= 0)
+                        if (journal_file_auth_next_evolve_usec(m->system_journal, &u) >= 0)
                                 t = MIN(t, usec_sub_unsigned(u, n));
                 }
-#endif
 
                 r = sd_event_run(m->event, t);
                 if (r < 0)
index 24979e8882e6f7456a2afe99a5e4366d8efb8d0c..e27f3ce376417049aa3ac01f11a30bfcbe429413 100644 (file)
@@ -5,6 +5,7 @@ sd_journal_sources = files(
         'sd-journal/catalog.c',
         'sd-journal/fsprg.c',
         'sd-journal/journal-authenticate.c',
+        'sd-journal/journal-authenticate-internal.c',
         'sd-journal/journal-file.c',
         'sd-journal/journal-send.c',
         'sd-journal/journal-vacuum.c',
diff --git a/src/libsystemd/sd-journal/journal-authenticate-internal.c b/src/libsystemd/sd-journal/journal-authenticate-internal.c
new file mode 100644 (file)
index 0000000..2210bd1
--- /dev/null
@@ -0,0 +1,172 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "journal-authenticate.h"
+#include "journal-authenticate-internal.h"
+#include "journal-file.h"
+
+void journal_file_auth_done(JournalFile *f) {
+        assert(f);
+
+#if HAVE_GCRYPT
+        f->auth_context = journal_auth_free(f->auth_context);
+#endif
+}
+
+int journal_file_auth_load(JournalFile *f) {
+        assert(f);
+
+#if HAVE_GCRYPT
+        return journal_auth_load(&f->auth_context);
+#else
+        return -EOPNOTSUPP;
+#endif
+}
+
+int journal_file_auth_load_key(JournalFile *f, const char *key) {
+        assert(f);
+
+#if HAVE_GCRYPT
+        return journal_auth_load_key(&f->auth_context, key);
+#else
+        return -EOPNOTSUPP;
+#endif
+}
+
+int journal_file_auth_epoch_to_realtime_usec(JournalFile *f, uint64_t epoch, usec_t *ret_start, usec_t *ret_end) {
+        assert(f);
+
+        if (!JOURNAL_HEADER_SEALED(f->header))
+                return -EOPNOTSUPP;
+
+#if HAVE_GCRYPT
+        return journal_auth_epoch_to_realtime_usec(f->auth_context, epoch, ret_start, ret_end);
+#else
+        assert_not_reached();
+#endif
+}
+
+int journal_file_auth_next_evolve_usec(JournalFile *f, usec_t *ret) {
+        assert(f);
+
+        if (!JOURNAL_HEADER_SEALED(f->header))
+                return -EOPNOTSUPP;
+
+#if HAVE_GCRYPT
+        return journal_auth_next_evolve_usec(f->auth_context, ret);
+#else
+        assert_not_reached();
+#endif
+}
+
+int journal_file_auth_seek(JournalFile *f, uint64_t goal) {
+        assert(f);
+
+        if (!JOURNAL_HEADER_SEALED(f->header))
+                return 0;
+
+#if HAVE_GCRYPT
+        return journal_auth_seek(f->auth_context, goal);
+#else
+        assert_not_reached();
+#endif
+}
+
+int journal_file_auth_start(JournalFile *f) {
+        assert(f);
+
+        if (!JOURNAL_HEADER_SEALED(f->header))
+                return 0;
+
+#if HAVE_GCRYPT
+        return journal_auth_start(f->auth_context);
+#else
+        assert_not_reached();
+#endif
+}
+
+int journal_file_auth_end(JournalFile *f, uint8_t ret[static TAG_LENGTH]) {
+        assert(f);
+
+        if (!JOURNAL_HEADER_SEALED(f->header))
+                return -EOPNOTSUPP;
+
+#if HAVE_GCRYPT
+        return journal_auth_end(f->auth_context, ret);
+#else
+        assert_not_reached();
+#endif
+}
+
+int journal_file_auth_put_header(JournalFile *f) {
+        assert(f);
+
+        if (!JOURNAL_HEADER_SEALED(f->header))
+                return 0;
+
+#if HAVE_GCRYPT
+        return journal_auth_put_header(f->auth_context, f);
+#else
+        assert_not_reached();
+#endif
+}
+
+int journal_file_auth_put_object(JournalFile *f, ObjectType type, Object *o, uint64_t p) {
+        assert(f);
+
+        if (!JOURNAL_HEADER_SEALED(f->header))
+                return 0;
+
+#if HAVE_GCRYPT
+        return journal_auth_put_object(f->auth_context, f, type, o, p);
+#else
+        assert_not_reached();
+#endif
+}
+
+int journal_file_auth_append_tag(JournalFile *f) {
+        assert(f);
+
+        if (!JOURNAL_HEADER_SEALED(f->header))
+                return 0;
+
+        if (!journal_file_writable(f))
+                return 0;
+
+#if HAVE_GCRYPT
+        return journal_auth_append_tag(f->auth_context, f);
+#else
+        assert_not_reached();
+#endif
+}
+
+int journal_file_auth_append_tag_first(JournalFile *f) {
+        assert(f);
+
+        if (!JOURNAL_HEADER_SEALED(f->header))
+                return 0;
+
+        if (!journal_file_writable(f))
+                return 0;
+
+#if HAVE_GCRYPT
+        return journal_auth_append_tag_first(f->auth_context, f);
+#else
+        assert_not_reached();
+#endif
+}
+
+int journal_file_auth_append_tag_maybe(JournalFile *f, usec_t realtime) {
+        assert(f);
+
+        if (!JOURNAL_HEADER_SEALED(f->header))
+                return 0;
+
+        if (!journal_file_writable(f))
+                return 0;
+
+#if HAVE_GCRYPT
+        return journal_auth_append_tag_maybe(f->auth_context, f, realtime);
+#else
+        assert_not_reached();
+#endif
+}
diff --git a/src/libsystemd/sd-journal/journal-authenticate-internal.h b/src/libsystemd/sd-journal/journal-authenticate-internal.h
new file mode 100644 (file)
index 0000000..ee7ea67
--- /dev/null
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#include "journal-def.h"
+#include "sd-forward.h"
+
+void journal_file_auth_done(JournalFile *f);
+int journal_file_auth_load(JournalFile *f);
+int journal_file_auth_load_key(JournalFile *f, const char *key);
+int journal_file_auth_epoch_to_realtime_usec(JournalFile *f, uint64_t epoch, usec_t *ret_start, usec_t *ret_end);
+int journal_file_auth_next_evolve_usec(JournalFile *f, usec_t *ret);
+int journal_file_auth_seek(JournalFile *f, uint64_t goal);
+int journal_file_auth_start(JournalFile *f);
+int journal_file_auth_end(JournalFile *f, uint8_t ret[static TAG_LENGTH]);
+int journal_file_auth_put_header(JournalFile *f);
+int journal_file_auth_put_object(JournalFile *f, ObjectType type, Object *o, uint64_t p);
+int journal_file_auth_append_tag(JournalFile *f);
+int journal_file_auth_append_tag_first(JournalFile *f);
+int journal_file_auth_append_tag_maybe(JournalFile *f, usec_t realtime);
index f2c42ce0ffb2129fe44069d8ede9db342821ea8d..fff7f221ab972248d8495670775763ba24a8c26b 100644 (file)
 #include "string-util.h"
 #include "time-util.h"
 
+#if HAVE_GCRYPT
+
+struct JournalAuthContext {
+        gcry_md_hd_t hmac;
+        bool hmac_running;
+
+        FSSHeader *fss_file;
+        size_t fss_file_size;
+
+        uint64_t fss_start_usec;
+        uint64_t fss_interval_usec;
+
+        struct iovec fsprg_state;
+        struct iovec fsprg_seed;
+};
+
+JournalAuthContext* journal_auth_free(JournalAuthContext *c) {
+        if (!c)
+                return NULL;
+
+        if (c->fss_file) {
+                size_t sz = PAGE_ALIGN(c->fss_file_size);
+                assert(sz < SIZE_MAX);
+                munmap(c->fss_file, sz);
+        } else
+                iovec_done_erase(&c->fsprg_state);
+
+        iovec_done_erase(&c->fsprg_seed);
+
+        if (c->hmac)
+                sym_gcry_md_close(c->hmac);
+
+        return mfree(c);
+}
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(JournalAuthContext*, journal_auth_free);
+
 static void* fssheader_free(FSSHeader *p) {
         /* mmap() returns MAP_FAILED on error and sets the errno */
         if (!p || p == MAP_FAILED)
@@ -29,10 +66,10 @@ static void* fssheader_free(FSSHeader *p) {
 
 DEFINE_TRIVIAL_CLEANUP_FUNC(FSSHeader*, fssheader_free);
 
-int journal_file_fss_load(JournalFile *f) {
+int journal_auth_load(JournalAuthContext **ret) {
         int r;
 
-        assert(f);
+        assert(ret);
 
         /* This function is used to determine whether sealing should be enabled in the journal header so we
          * can't check the header to check if sealing is enabled here. */
@@ -95,6 +132,10 @@ int journal_file_fss_load(JournalFile *f) {
         if (le64toh(header->start_usec) <= 0 || le64toh(header->interval_usec) <= 0)
                 return -EBADMSG;
 
+        _cleanup_(journal_auth_freep) JournalAuthContext *c = new0(JournalAuthContext, 1);
+        if (!c)
+                return -ENOMEM;
+
         size_t sz = PAGE_ALIGN(fss_file_size);
         if (sz >= SIZE_MAX)
                 return -EBADMSG;
@@ -103,23 +144,26 @@ int journal_file_fss_load(JournalFile *f) {
         if (p == MAP_FAILED)
                 return -errno;
 
-        f->fss_file_size = fss_file_size;
-        f->fss_file = p;
+        *c = (JournalAuthContext) {
+                .fss_file_size = fss_file_size,
+                .fss_file = p,
 
-        f->fss_start_usec = le64toh(p->start_usec);
-        f->fss_interval_usec = le64toh(p->interval_usec);
+                .fss_start_usec = le64toh(p->start_usec),
+                .fss_interval_usec = le64toh(p->interval_usec),
 
-        f->fsprg_state = IOVEC_MAKE(
-                        (uint8_t*) p + le64toh(p->header_size),
-                        le64toh(p->fsprg_state_size));
+                .fsprg_state = IOVEC_MAKE(
+                                (uint8_t*) p + le64toh(p->header_size),
+                                le64toh(p->fsprg_state_size)),
+        };
 
+        *ret = TAKE_PTR(c);
         return 0;
 }
 
-int journal_file_parse_verification_key(JournalFile *f, const char *key) {
+int journal_auth_load_key(JournalAuthContext **ret, const char *key) {
         int r;
 
-        assert(f);
+        assert(ret);
         assert(key);
 
         size_t seed_size = FSPRG_RECOMMENDED_SEEDLEN;
@@ -162,22 +206,30 @@ int journal_file_parse_verification_key(JournalFile *f, const char *key) {
         if (!MUL_SAFE(&start_usec, start, interval))
                 return -EKEYREJECTED;
 
-        f->fsprg_seed = IOVEC_MAKE(TAKE_PTR(seed), seed_size);
-        f->fss_start_usec = start_usec;
-        f->fss_interval_usec = interval;
+        _cleanup_(journal_auth_freep) JournalAuthContext *c = new(JournalAuthContext, 1);
+        if (!c)
+                return -ENOMEM;
 
+        *c = (JournalAuthContext) {
+                .fss_start_usec = start_usec,
+                .fss_interval_usec = interval,
+
+                .fsprg_seed = IOVEC_MAKE(TAKE_PTR(seed), seed_size),
+        };
+
+        *ret = TAKE_PTR(c);
         return 0;
 }
 
-static int journal_auth_epoch_to_realtime_usec(JournalFile *f, uint64_t epoch, usec_t *ret_start, usec_t *ret_end) {
-        assert(f);
-        assert(f->fss_start_usec > 0);
-        assert(f->fss_interval_usec > 0);
+int journal_auth_epoch_to_realtime_usec(const JournalAuthContext *c, uint64_t epoch, usec_t *ret_start, usec_t *ret_end) {
+        assert(c);
+        assert(c->fss_start_usec > 0);
+        assert(c->fss_interval_usec > 0);
 
         uint64_t start, end;
-        if (!MUL_SAFE(&start, epoch, f->fss_interval_usec) ||
-            !INC_SAFE(&start, f->fss_start_usec) ||
-            !ADD_SAFE(&end, start, f->fss_interval_usec))
+        if (!MUL_SAFE(&start, epoch, c->fss_interval_usec) ||
+            !INC_SAFE(&start, c->fss_start_usec) ||
+            !ADD_SAFE(&end, start, c->fss_interval_usec))
                 return -ERANGE;
 
         if (ret_start)
@@ -188,38 +240,29 @@ static int journal_auth_epoch_to_realtime_usec(JournalFile *f, uint64_t epoch, u
         return 0;
 }
 
-int journal_file_next_evolve_usec(JournalFile *f, usec_t *ret) {
-        assert(f);
-
-        if (!JOURNAL_HEADER_SEALED(f->header))
-                return -EOPNOTSUPP;
+int journal_auth_next_evolve_usec(const JournalAuthContext *c, usec_t *ret) {
+        assert(c);
 
-        uint64_t epoch = FSPRG_GetEpoch(f->fsprg_state.iov_base);
+        uint64_t epoch = FSPRG_GetEpoch(c->fsprg_state.iov_base);
 
-        return journal_auth_epoch_to_realtime_usec(f, epoch, /* ret_start= */ NULL, ret);
+        return journal_auth_epoch_to_realtime_usec(c, epoch, /* ret_start= */ NULL, ret);
 }
 
-int journal_file_fsprg_seek(JournalFile *f, uint64_t goal) {
+int journal_auth_seek(JournalAuthContext *c, uint64_t goal) {
         int r;
 
-        assert(f);
-
-        if (!JOURNAL_HEADER_SEALED(f->header))
-                return 0;
-
-        assert(iovec_is_set(&f->fsprg_seed));
+        assert(c);
+        assert(iovec_is_set(&c->fsprg_seed));
 
-        if (iovec_is_set(&f->fsprg_state)) {
-                /* Cheaper... */
-
-                uint64_t epoch = FSPRG_GetEpoch(f->fsprg_state.iov_base);
+        if (iovec_is_set(&c->fsprg_state)) {
+                uint64_t epoch = FSPRG_GetEpoch(c->fsprg_state.iov_base);
                 if (goal == epoch)
                         return 0;
 
                 if (goal == epoch + 1)
-                        return FSPRG_Evolve(f->fsprg_state.iov_base);
+                        return FSPRG_Evolve(c->fsprg_state.iov_base);
         } else {
-                r = iovec_alloc(FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR), &f->fsprg_state);
+                r = iovec_alloc(FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR), &c->fsprg_state);
                 if (r < 0)
                         return r;
         }
@@ -227,82 +270,81 @@ int journal_file_fsprg_seek(JournalFile *f, uint64_t goal) {
         log_debug("Seeking FSPRG key to %"PRIu64".", goal);
 
         _cleanup_(iovec_erase) struct iovec msk = IOVEC_ALLOCA(FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR));
-        r = FSPRG_GenMK(msk.iov_base, NULL, f->fsprg_seed.iov_base, f->fsprg_seed.iov_len, FSPRG_RECOMMENDED_SECPAR);
+        r = FSPRG_GenMK(msk.iov_base, NULL, c->fsprg_seed.iov_base, c->fsprg_seed.iov_len, FSPRG_RECOMMENDED_SECPAR);
         if (r < 0)
                 return r;
 
-        return FSPRG_Seek(f->fsprg_state.iov_base, goal, msk.iov_base, f->fsprg_seed.iov_base, f->fsprg_seed.iov_len);
+        return FSPRG_Seek(c->fsprg_state.iov_base, goal, msk.iov_base, c->fsprg_seed.iov_base, c->fsprg_seed.iov_len);
 }
 
-#if HAVE_GCRYPT
-static int journal_file_hmac_setup(JournalFile *f) {
+static int journal_auth_setup(JournalAuthContext *c) {
         int r;
 
-        assert(f);
+        assert(c);
 
-        if (f->hmac)
+        if (c->hmac)
                 return 0;
 
         r = initialize_libgcrypt(true);
         if (r < 0)
                 return r;
 
-        if (sym_gcry_md_open(&f->hmac, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC) != 0)
+        if (sym_gcry_md_open(&c->hmac, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC) != 0)
                 return -EOPNOTSUPP;
 
         return 0;
 }
-#endif
 
-int journal_file_hmac_start(JournalFile *f) {
-#if HAVE_GCRYPT
+int journal_auth_start(JournalAuthContext *c) {
         int r;
 
-        assert(f);
-
-        if (!JOURNAL_HEADER_SEALED(f->header))
-                return 0;
+        assert(c);
 
-        if (f->hmac_running)
+        if (c->hmac_running)
                 return 0;
 
-        r = journal_file_hmac_setup(f);
+        r = journal_auth_setup(c);
         if (r < 0)
                 return r;
 
         /* Prepare HMAC for next cycle */
-        sym_gcry_md_reset(f->hmac);
+        sym_gcry_md_reset(c->hmac);
 
         uint8_t key[256 / 8]; /* Let's pass 256 bit from FSPRG to HMAC */
         CLEANUP_ERASE(key);
-        r = FSPRG_GetKey(f->fsprg_state.iov_base, key, sizeof(key), 0);
+        r = FSPRG_GetKey(c->fsprg_state.iov_base, key, sizeof(key), 0);
         if (r < 0)
                 return r;
 
-        gcry_error_t err = sym_gcry_md_setkey(f->hmac, key, sizeof(key));
+        gcry_error_t err = sym_gcry_md_setkey(c->hmac, key, sizeof(key));
         if (gcry_err_code(err) != GPG_ERR_NO_ERROR)
                 return log_debug_errno(SYNTHETIC_ERRNO(EIO),
                                        "sym_gcry_md_setkey() failed with error code: %s",
                                        sym_gcry_strerror(err));
 
-        f->hmac_running = true;
+        c->hmac_running = true;
+        return 0;
+}
+
+int journal_auth_end(JournalAuthContext *c, uint8_t ret[static TAG_LENGTH]) {
+        assert(c);
+        assert(ret);
+
+        if (!c->hmac_running)
+                return -EINVAL;
 
+        memcpy(ret, sym_gcry_md_read(c->hmac, 0), TAG_LENGTH);
+        c->hmac_running = false;
         return 0;
-#else
-        return -EOPNOTSUPP;
-#endif
 }
 
-int journal_file_hmac_put_header(JournalFile *f) {
-#if HAVE_GCRYPT
+int journal_auth_put_header(JournalAuthContext *c, JournalFile *f) {
         int r;
 
+        assert(c);
         assert(f);
 
-        if (!JOURNAL_HEADER_SEALED(f->header))
-                return 0;
-
-        r = journal_file_hmac_start(f);
+        r = journal_auth_start(c);
         if (r < 0)
                 return r;
 
@@ -313,27 +355,21 @@ int journal_file_hmac_put_header(JournalFile *f) {
          * tail_entry_monotonic, n_data, n_fields, n_tags,
          * n_entry_arrays. */
 
-        sym_gcry_md_write(f->hmac, f->header->signature, offsetof(Header, state) - offsetof(Header, signature));
-        sym_gcry_md_write(f->hmac, &f->header->file_id, offsetof(Header, tail_entry_boot_id) - offsetof(Header, file_id));
-        sym_gcry_md_write(f->hmac, &f->header->seqnum_id, offsetof(Header, arena_size) - offsetof(Header, seqnum_id));
-        sym_gcry_md_write(f->hmac, &f->header->data_hash_table_offset, offsetof(Header, tail_object_offset) - offsetof(Header, data_hash_table_offset));
+        sym_gcry_md_write(c->hmac, f->header->signature, offsetof(Header, state) - offsetof(Header, signature));
+        sym_gcry_md_write(c->hmac, &f->header->file_id, offsetof(Header, tail_entry_boot_id) - offsetof(Header, file_id));
+        sym_gcry_md_write(c->hmac, &f->header->seqnum_id, offsetof(Header, arena_size) - offsetof(Header, seqnum_id));
+        sym_gcry_md_write(c->hmac, &f->header->data_hash_table_offset, offsetof(Header, tail_object_offset) - offsetof(Header, data_hash_table_offset));
 
         return 0;
-#else
-        return -EOPNOTSUPP;
-#endif
 }
 
-int journal_file_hmac_put_object(JournalFile *f, ObjectType type, Object *o, uint64_t p) {
-#if HAVE_GCRYPT
+int journal_auth_put_object(JournalAuthContext *c, JournalFile *f, ObjectType type, Object *o, uint64_t p) {
         int r;
 
+        assert(c);
         assert(f);
 
-        if (!JOURNAL_HEADER_SEALED(f->header))
-                return 0;
-
-        r = journal_file_hmac_start(f);
+        r = journal_auth_start(c);
         if (r < 0)
                 return r;
 
@@ -344,25 +380,25 @@ int journal_file_hmac_put_object(JournalFile *f, ObjectType type, Object *o, uin
         } else if (type > OBJECT_UNUSED && o->object.type != type)
                 return -EBADMSG;
 
-        sym_gcry_md_write(f->hmac, o, offsetof(ObjectHeader, payload));
+        sym_gcry_md_write(c->hmac, o, offsetof(ObjectHeader, payload));
 
         switch (o->object.type) {
 
         case OBJECT_DATA:
                 /* All but hash and payload are mutable */
-                sym_gcry_md_write(f->hmac, &o->data.hash, sizeof(o->data.hash));
-                sym_gcry_md_write(f->hmac, journal_file_data_payload_field(f, o), le64toh(o->object.size) - journal_file_data_payload_offset(f));
+                sym_gcry_md_write(c->hmac, &o->data.hash, sizeof(o->data.hash));
+                sym_gcry_md_write(c->hmac, journal_file_data_payload_field(f, o), le64toh(o->object.size) - journal_file_data_payload_offset(f));
                 break;
 
         case OBJECT_FIELD:
                 /* Same here */
-                sym_gcry_md_write(f->hmac, &o->field.hash, sizeof(o->field.hash));
-                sym_gcry_md_write(f->hmac, o->field.payload, le64toh(o->object.size) - offsetof(Object, field.payload));
+                sym_gcry_md_write(c->hmac, &o->field.hash, sizeof(o->field.hash));
+                sym_gcry_md_write(c->hmac, o->field.payload, le64toh(o->object.size) - offsetof(Object, field.payload));
                 break;
 
         case OBJECT_ENTRY:
                 /* All */
-                sym_gcry_md_write(f->hmac, &o->entry.seqnum, le64toh(o->object.size) - offsetof(Object, entry.seqnum));
+                sym_gcry_md_write(c->hmac, &o->entry.seqnum, le64toh(o->object.size) - offsetof(Object, entry.seqnum));
                 break;
 
         case OBJECT_FIELD_HASH_TABLE:
@@ -373,29 +409,23 @@ int journal_file_hmac_put_object(JournalFile *f, ObjectType type, Object *o, uin
 
         case OBJECT_TAG:
                 /* All but the tag itself */
-                sym_gcry_md_write(f->hmac, &o->tag.seqnum, sizeof(o->tag.seqnum));
-                sym_gcry_md_write(f->hmac, &o->tag.epoch, sizeof(o->tag.epoch));
+                sym_gcry_md_write(c->hmac, &o->tag.seqnum, sizeof(o->tag.seqnum));
+                sym_gcry_md_write(c->hmac, &o->tag.epoch, sizeof(o->tag.epoch));
                 break;
         default:
                 return -EINVAL;
         }
 
         return 0;
-#else
-        return -EOPNOTSUPP;
-#endif
 }
 
-int journal_file_append_tag(JournalFile *f) {
-#if HAVE_GCRYPT
+int journal_auth_append_tag(JournalAuthContext *c, JournalFile *f) {
         int r;
 
+        assert(c);
         assert(f);
 
-        if (!JOURNAL_HEADER_SEALED(f->header))
-                return 0;
-
-        r = journal_file_hmac_start(f);
+        r = journal_auth_start(c);
         if (r < 0)
                 return r;
 
@@ -409,39 +439,31 @@ int journal_file_append_tag(JournalFile *f) {
         f->header->n_tags = htole64(seqnum);
 
         o->tag.seqnum = htole64(seqnum);
-        o->tag.epoch = htole64(FSPRG_GetEpoch(f->fsprg_state.iov_base));
+        o->tag.epoch = htole64(FSPRG_GetEpoch(c->fsprg_state.iov_base));
 
         log_debug("Writing tag %"PRIu64" for epoch %"PRIu64"",
                   le64toh(o->tag.seqnum), le64toh(o->tag.epoch));
 
         /* Add the tag object itself, so that we can protect its
          * header. This will exclude the actual hash value in it */
-        r = journal_file_hmac_put_object(f, OBJECT_TAG, o, p);
+        r = journal_auth_put_object(c, f, OBJECT_TAG, o, p);
         if (r < 0)
                 return r;
 
         /* Get the HMAC tag and store it in the object */
-        memcpy(o->tag.tag, sym_gcry_md_read(f->hmac, 0), TAG_LENGTH);
-        f->hmac_running = false;
-
-        return 0;
-#else
-        return -EOPNOTSUPP;
-#endif
+        return journal_auth_end(c, o->tag.tag);
 }
 
-int journal_file_append_first_tag(JournalFile *f) {
+int journal_auth_append_tag_first(JournalAuthContext *c, JournalFile *f) {
         uint64_t p;
         int r;
 
+        assert(c);
         assert(f);
 
-        if (!JOURNAL_HEADER_SEALED(f->header))
-                return 0;
-
         log_debug("Calculating first tag...");
 
-        r = journal_file_hmac_put_header(f);
+        r = journal_auth_put_header(c, f);
         if (r < 0)
                 return r;
 
@@ -450,7 +472,7 @@ int journal_file_append_first_tag(JournalFile *f) {
                 return -EINVAL;
         p -= offsetof(Object, hash_table.items);
 
-        r = journal_file_hmac_put_object(f, OBJECT_FIELD_HASH_TABLE, NULL, p);
+        r = journal_auth_put_object(c, f, OBJECT_FIELD_HASH_TABLE, NULL, p);
         if (r < 0)
                 return r;
 
@@ -459,40 +481,39 @@ int journal_file_append_first_tag(JournalFile *f) {
                 return -EINVAL;
         p -= offsetof(Object, hash_table.items);
 
-        r = journal_file_hmac_put_object(f, OBJECT_DATA_HASH_TABLE, NULL, p);
+        r = journal_auth_put_object(c, f, OBJECT_DATA_HASH_TABLE, NULL, p);
         if (r < 0)
                 return r;
 
-        return journal_file_append_tag(f);
+        return journal_auth_append_tag(c, f);
 }
 
-int journal_file_maybe_append_tag(JournalFile *f, uint64_t realtime) {
+int journal_auth_append_tag_maybe(JournalAuthContext *c, JournalFile *f, usec_t realtime) {
         int r;
 
+        assert(c);
+        assert(c->fss_start_usec > 0);
+        assert(c->fss_interval_usec > 0);
         assert(f);
 
-        if (!JOURNAL_HEADER_SEALED(f->header))
-                return 0;
-
-        assert(f->fss_start_usec > 0);
-        assert(f->fss_interval_usec > 0);
-
         if (realtime <= 0)
                 realtime = now(CLOCK_REALTIME);
 
-        uint64_t goal = usec_sub_unsigned(realtime, f->fss_start_usec) / f->fss_interval_usec;
+        uint64_t goal = usec_sub_unsigned(realtime, c->fss_start_usec) / c->fss_interval_usec;
 
         for (;;) {
-                uint64_t epoch = FSPRG_GetEpoch(f->fsprg_state.iov_base);
+                uint64_t epoch = FSPRG_GetEpoch(c->fsprg_state.iov_base);
                 if (epoch >= goal)
                         return 0;
 
-                r = journal_file_append_tag(f);
+                r = journal_auth_append_tag(c, f);
                 if (r < 0)
                         return r;
 
-                r = FSPRG_Evolve(f->fsprg_state.iov_base);
+                r = FSPRG_Evolve(c->fsprg_state.iov_base);
                 if (r < 0)
                         return r;
         }
 }
+
+#endif /* HAVE_GCRYPT */
index f4164b32ad68e56493ddc6cf275c40b6b8f39d3c..c50c83a7a2d555fcdc52f15475f2a586917743ad 100644 (file)
@@ -1,20 +1,24 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
+#include "journal-authenticate-internal.h"       /* IWYU pragma: export */
+#include "journal-def.h"
 #include "sd-forward.h"
-#include "journal-file.h"
 
-int journal_file_append_tag(JournalFile *f);
-int journal_file_maybe_append_tag(JournalFile *f, uint64_t realtime);
-int journal_file_append_first_tag(JournalFile *f);
+#if HAVE_GCRYPT
 
-int journal_file_hmac_start(JournalFile *f);
-int journal_file_hmac_put_header(JournalFile *f);
-int journal_file_hmac_put_object(JournalFile *f, ObjectType type, Object *o, uint64_t p);
+JournalAuthContext* journal_auth_free(JournalAuthContext *c);
+int journal_auth_load(JournalAuthContext **ret);
+int journal_auth_load_key(JournalAuthContext **ret, const char *key);
+int journal_auth_epoch_to_realtime_usec(const JournalAuthContext *c, uint64_t epoch, usec_t *ret_start, usec_t *ret_end);
+int journal_auth_next_evolve_usec(const JournalAuthContext *c, usec_t *ret);
+int journal_auth_seek(JournalAuthContext *c, uint64_t goal);
+int journal_auth_start(JournalAuthContext *c);
+int journal_auth_end(JournalAuthContext *c, uint8_t ret[static TAG_LENGTH]);
+int journal_auth_put_header(JournalAuthContext *c, JournalFile *f);
+int journal_auth_put_object(JournalAuthContext *c, JournalFile *f, ObjectType type, Object *o, uint64_t p);
+int journal_auth_append_tag(JournalAuthContext *c, JournalFile *f);
+int journal_auth_append_tag_first(JournalAuthContext *c, JournalFile *f);
+int journal_auth_append_tag_maybe(JournalAuthContext *c, JournalFile *f, usec_t realtime);
 
-int journal_file_fss_load(JournalFile *f);
-int journal_file_parse_verification_key(JournalFile *f, const char *key);
-
-int journal_file_fsprg_seek(JournalFile *f, uint64_t goal);
-
-int journal_file_next_evolve_usec(JournalFile *f, usec_t *ret);
+#endif
index 026aa4c941444c37e4ff11e2e14c443d8146051c..9dd3d25dc453d0bae992657a8000310bc083aa08 100644 (file)
@@ -43,6 +43,9 @@ typedef struct HashItem HashItem;
 
 typedef struct FSSHeader FSSHeader;
 
+typedef struct JournalFile JournalFile;
+typedef struct JournalAuthContext JournalAuthContext;
+
 /* Object types */
 typedef enum ObjectType {
         OBJECT_UNUSED, /* also serves as "any type" or "additional category" */
index 4dfcb9343f24461059ae8642597f196f9ec0ce5c..2a4e71b776485e02020dd174abd2751c1d16d721 100644 (file)
 #include "fd-util.h"
 #include "format-util.h"
 #include "fs-util.h"
-#include "gcrypt-util.h"
 #include "hashmap.h"
 #include "id128-util.h"
-#include "iovec-util.h"
-#include "journal-authenticate.h"
+#include "journal-authenticate-internal.h"
 #include "journal-def.h"
 #include "journal-file.h"
 #include "journal-internal.h"
@@ -308,17 +306,7 @@ JournalFile* journal_file_close(JournalFile *f) {
         free(f->compress_buffer);
 #endif
 
-        if (f->fss_file) {
-                size_t sz = PAGE_ALIGN(f->fss_file_size);
-                assert(sz < SIZE_MAX);
-                munmap(f->fss_file, sz);
-        } else
-                iovec_done_erase(&f->fsprg_state);
-
-        iovec_done_erase(&f->fsprg_seed);
-
-        if (f->hmac)
-                sym_gcry_md_close(f->hmac);
+        journal_file_auth_done(f);
 
         return mfree(f);
 }
@@ -404,16 +392,13 @@ static int journal_file_init_header(
                 JournalFileFlags file_flags,
                 JournalFile *template) {
 
-        bool seal = false;
         ssize_t k;
         int r;
 
         assert(f);
 
-#if HAVE_GCRYPT
         /* Try to load the FSPRG state, and if we can't, then just don't do sealing */
-        seal = FLAGS_SET(file_flags, JOURNAL_SEAL) && journal_file_fss_load(f) >= 0;
-#endif
+        bool seal = FLAGS_SET(file_flags, JOURNAL_SEAL) && journal_file_auth_load(f) >= 0;
 
         Header h = {
                 .header_size = htole64(ALIGN64(sizeof(h))),
@@ -1833,11 +1818,9 @@ static int journal_file_append_field(
         /* The linking might have altered the window, so let's only pass the offset to hmac which will
          * move to the object again if needed. */
 
-#if HAVE_GCRYPT
-        r = journal_file_hmac_put_object(f, OBJECT_FIELD, NULL, p);
+        r = journal_file_auth_put_object(f, OBJECT_FIELD, NULL, p);
         if (r < 0)
                 return r;
-#endif
 
         if (ret_object) {
                 r = journal_file_move_to_object(f, OBJECT_FIELD, p, ret_object);
@@ -1948,11 +1931,9 @@ static int journal_file_append_data(
         if (r < 0)
                 return r;
 
-#if HAVE_GCRYPT
-        r = journal_file_hmac_put_object(f, OBJECT_DATA, o, p);
+        r = journal_file_auth_put_object(f, OBJECT_DATA, o, p);
         if (r < 0)
                 return r;
-#endif
 
         /* Create field object ... */
         r = journal_file_append_field(f, data, (uint8_t*) eq - (uint8_t*) data, &fo, NULL);
@@ -2198,11 +2179,9 @@ static int link_entry_into_array(
         if (r < 0)
                 return r;
 
-#if HAVE_GCRYPT
-        r = journal_file_hmac_put_object(f, OBJECT_ENTRY_ARRAY, o, q);
+        r = journal_file_auth_put_object(f, OBJECT_ENTRY_ARRAY, o, q);
         if (r < 0)
                 return r;
-#endif
 
         write_entry_array_item(f, o, i, p);
 
@@ -2444,11 +2423,9 @@ static int journal_file_append_entry_internal(
         for (size_t i = 0; i < n_items; i++)
                 write_entry_item(f, o, i, &items[i]);
 
-#if HAVE_GCRYPT
-        r = journal_file_hmac_put_object(f, OBJECT_ENTRY, o, np);
+        r = journal_file_auth_put_object(f, OBJECT_ENTRY, o, np);
         if (r < 0)
                 return r;
-#endif
 
         r = journal_file_link_entry(f, o, np, items, n_items);
         if (r < 0)
@@ -2633,11 +2610,9 @@ int journal_file_append_entry(
         else
                 machine_id = &_machine_id;
 
-#if HAVE_GCRYPT
-        r = journal_file_maybe_append_tag(f, ts->realtime);
+        r = journal_file_auth_append_tag_maybe(f, ts->realtime);
         if (r < 0)
                 return r;
-#endif
 
         if (n_iovec < ALLOCA_MAX / sizeof(EntryItem) / 2)
                 items = newa(EntryItem, n_iovec);
@@ -4284,13 +4259,11 @@ int journal_file_open(
                         goto fail;
         }
 
-#if HAVE_GCRYPT
         if (!newly_created && journal_file_writable(f) && JOURNAL_HEADER_SEALED(f->header)) {
-                r = journal_file_fss_load(f);
+                r = journal_file_auth_load(f);
                 if (r < 0)
                         goto fail;
         }
-#endif
 
         if (journal_file_writable(f)) {
                 if (metrics) {
@@ -4313,11 +4286,9 @@ int journal_file_open(
                 if (r < 0)
                         goto fail;
 
-#if HAVE_GCRYPT
-                r = journal_file_append_first_tag(f);
+                r = journal_file_auth_append_tag_first(f);
                 if (r < 0)
                         goto fail;
-#endif
         }
 
         if (mmap_cache_fd_got_sigbus(f->cache_fd)) {
index fea181cafdc9bdee07f1b56608f6c78947e626a5..8499fa2b662f937f2ba5085e055cfaec51650e6c 100644 (file)
@@ -6,7 +6,6 @@
 
 #include "compress.h"
 #include "sd-forward.h"
-#include "gcrypt-util.h"
 #include "journal-def.h"
 #include "mmap-cache.h"
 #include "sparse-endian.h"
@@ -98,17 +97,7 @@ typedef struct JournalFile {
         void *compress_buffer;
 #endif
 
-        gcry_md_hd_t hmac;
-        bool hmac_running;
-
-        FSSHeader *fss_file;
-        size_t fss_file_size;
-
-        uint64_t fss_start_usec;
-        uint64_t fss_interval_usec;
-
-        struct iovec fsprg_state;
-        struct iovec fsprg_seed;
+        JournalAuthContext *auth_context;
 
         /* When we insert this file into the per-boot priority queue 'newest_by_boot_id' in sd_journal, then by these keys */
         sd_id128_t newest_boot_id;
index 02420840dfc1d1ca0801aabd4dd9d783282eba1f..b8cc3555f6b1238715442882bd888ceed9a130bb 100644 (file)
@@ -9,8 +9,7 @@
 #include "fd-util.h"
 #include "fileio.h"
 #include "fs-util.h"
-#include "gcrypt-util.h"
-#include "journal-authenticate.h"
+#include "journal-authenticate-internal.h"
 #include "journal-def.h"
 #include "journal-file.h"
 #include "journal-verify.h"
@@ -821,7 +820,7 @@ int journal_file_verify(
 
         int r;
         Object *o;
-        uint64_t p = 0, last_epoch = 0, last_tag_realtime = 0, last_tag_realtime_end = 0;
+        uint64_t p = 0, last_tag = 0, last_epoch = 0, last_tag_realtime = 0, last_tag_realtime_end = 0;
         uint64_t entry_seqnum = 0, entry_monotonic = 0, entry_realtime = 0;
         usec_t min_entry_realtime = USEC_INFINITY, max_entry_realtime = 0;
         sd_id128_t entry_boot_id = {};  /* Unnecessary initialization to appease gcc */
@@ -836,19 +835,12 @@ int journal_file_verify(
         const char *tmp_dir = NULL;
         MMapCache *m;
 
-#if HAVE_GCRYPT
-        uint64_t last_tag = 0;
-#endif
         assert(f);
 
         if (key) {
-#if HAVE_GCRYPT
-                r = journal_file_parse_verification_key(f, key);
+                r = journal_file_auth_load_key(f, key);
                 if (r < 0)
                         return log_error_errno(r, "Failed to load verification key: %m");
-#else
-                return -EOPNOTSUPP;
-#endif
         } else if (JOURNAL_HEADER_SEALED(f->header))
                 return -ENOKEY;
 
@@ -1155,14 +1147,15 @@ int journal_file_verify(
                                 }
                         }
 
-#if HAVE_GCRYPT
                         if (JOURNAL_HEADER_SEALED(f->header)) {
                                 uint64_t q, rt, rt_end;
 
                                 debug(p, "Checking tag %"PRIu64"...", le64toh(o->tag.seqnum));
 
-                                rt = f->fss_start_usec + le64toh(o->tag.epoch) * f->fss_interval_usec;
-                                rt_end = usec_add(rt, f->fss_interval_usec);
+                                r = journal_file_auth_epoch_to_realtime_usec(f, le64toh(o->tag.epoch), &rt, &rt_end);
+                                if (r < 0)
+                                        goto fail;
+
                                 if (entry_realtime_set && entry_realtime >= rt_end) {
                                         error(p,
                                               "tag/entry realtime timestamp out of synchronization (%"PRIu64" >= %"PRIu64")",
@@ -1192,16 +1185,16 @@ int journal_file_verify(
                                 /* OK, now we know the epoch. So let's now set
                                  * it, and calculate the HMAC for everything
                                  * since the last tag. */
-                                r = journal_file_fsprg_seek(f, le64toh(o->tag.epoch));
+                                r = journal_file_auth_seek(f, le64toh(o->tag.epoch));
                                 if (r < 0)
                                         goto fail;
 
-                                r = journal_file_hmac_start(f);
+                                r = journal_file_auth_start(f);
                                 if (r < 0)
                                         goto fail;
 
                                 if (last_tag == 0) {
-                                        r = journal_file_hmac_put_header(f);
+                                        r = journal_file_auth_put_header(f);
                                         if (r < 0)
                                                 goto fail;
 
@@ -1214,7 +1207,7 @@ int journal_file_verify(
                                         if (r < 0)
                                                 goto fail;
 
-                                        r = journal_file_hmac_put_object(f, OBJECT_UNUSED, o, q);
+                                        r = journal_file_auth_put_object(f, OBJECT_UNUSED, o, q);
                                         if (r < 0)
                                                 goto fail;
 
@@ -1226,20 +1219,24 @@ int journal_file_verify(
                                 if (r < 0)
                                         goto fail;
 
-                                if (memcmp(o->tag.tag, sym_gcry_md_read(f->hmac, 0), TAG_LENGTH) != 0) {
+                                uint8_t tag[TAG_LENGTH];
+                                CLEANUP_ERASE(tag);
+
+                                r = journal_file_auth_end(f, tag);
+                                if (r < 0)
+                                        goto fail;
+
+                                if (memcmp(o->tag.tag, tag, TAG_LENGTH) != 0) {
                                         error(p, "Tag failed verification");
                                         r = -EBADMSG;
                                         goto fail;
                                 }
 
-                                f->hmac_running = false;
                                 last_tag_realtime = rt;
                                 last_tag_realtime_end = rt_end;
                         }
 
                         last_tag = p + ALIGN64(le64toh(o->object.size));
-#endif
-
                         last_epoch = le64toh(o->tag.epoch);
 
                         n_tags++;
index bcd7293dba00848d445f19958272bd1b57e13a7b..d638192dc39165b70cd2f6ff6883679354c7b78b 100644 (file)
@@ -55,9 +55,8 @@ static void test_non_empty_one(void) {
         iovec = IOVEC_MAKE_STRING(test);
         ASSERT_OK_ZERO(journal_file_append_entry(f, &ts, &fake_boot_id, &iovec, 1, NULL, NULL, NULL, NULL));
 
-#if HAVE_GCRYPT
-        journal_file_append_tag(f);
-#endif
+        journal_file_auth_append_tag(f);
+
         journal_file_dump(f);
 
         ASSERT_EQ(journal_file_next_entry(f, 0, DIRECTION_DOWN, &o, &p), 1);
@@ -200,9 +199,8 @@ static bool check_compressed(uint64_t compress_threshold, uint64_t data_size) {
         iovec = IOVEC_MAKE(data, data_size);
         ASSERT_OK_ZERO(journal_file_append_entry(f, &ts, NULL, &iovec, 1, NULL, NULL, NULL, NULL));
 
-#if HAVE_GCRYPT
-        journal_file_append_tag(f);
-#endif
+        journal_file_auth_append_tag(f);
+
         journal_file_dump(f);
 
         /* We have to partially reimplement some of the dump logic, because the normal next_entry does the
index 8aecda96105b2bdfdeddb91c1377b2b7653c1128..1567defac5f998b9c074e4648d003e1df12f2167 100644 (file)
@@ -405,23 +405,15 @@ bool journal_file_is_offlining(JournalFile *f) {
         return true;
 }
 
-void journal_file_write_final_tag(JournalFile *f) {
-        assert(f);
-#if HAVE_GCRYPT
-        if (!JOURNAL_HEADER_SEALED(f->header) || !journal_file_writable(f))
-                return;
-
-        int r = journal_file_append_tag(f);
-        if (r < 0)
-                log_debug_errno(r, "Failed to append tag when closing journal: %m");
-#endif
-}
-
 JournalFile* journal_file_offline_close(JournalFile *f) {
+        int r;
+
         if (!f)
                 return NULL;
 
-        journal_file_write_final_tag(f);
+        r = journal_file_auth_append_tag(f);
+        if (r < 0)
+                log_debug_errno(r, "Failed to append tag when closing journal, ignoring: %m");
 
         if (sd_event_source_get_enabled(f->post_change_timer, NULL) > 0)
                 journal_file_post_change(f);
@@ -464,7 +456,10 @@ int journal_file_rotate(
         assert(f);
         assert(*f);
 
-        journal_file_write_final_tag(*f);
+        r = journal_file_auth_append_tag(*f);
+        if (r < 0)
+                log_debug_errno(r, "Failed to append tag when closing journal, ignoring: %m");
+
         r = journal_file_archive(*f, &path);
         if (r < 0)
                 return r;
index d3ffe4e7a6dfa6ba5071f4d3113f10a9d031ac8f..a3a87812187d5b637033bab15cbfcf1a9b80dfda 100644 (file)
@@ -6,7 +6,6 @@
 
 int journal_file_set_offline(JournalFile *f, bool wait);
 bool journal_file_is_offlining(JournalFile *f);
-void journal_file_write_final_tag(JournalFile *f);
 JournalFile* journal_file_offline_close(JournalFile *f);
 DEFINE_TRIVIAL_CLEANUP_FUNC(JournalFile*, journal_file_offline_close);