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);
}
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) {
} 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)
'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',
--- /dev/null
+/* 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
+}
--- /dev/null
+/* 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);
#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)
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. */
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;
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;
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)
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;
}
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;
* 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;
} 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:
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;
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;
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;
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 */
/* 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
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" */
#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"
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);
}
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))),
/* 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);
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);
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);
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)
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);
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) {
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)) {
#include "compress.h"
#include "sd-forward.h"
-#include "gcrypt-util.h"
#include "journal-def.h"
#include "mmap-cache.h"
#include "sparse-endian.h"
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;
#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"
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 */
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;
}
}
-#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")",
/* 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;
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;
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++;
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);
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
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);
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;
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);