From 0284adc6a60ce0af1107cb0b50041a65d731f39e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 16 Aug 2012 01:51:54 +0200 Subject: journal: split up journal-file.c --- src/journal/journal-authenticate.h | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 src/journal/journal-authenticate.h (limited to 'src/journal/journal-authenticate.h') diff --git a/src/journal/journal-authenticate.h b/src/journal/journal-authenticate.h new file mode 100644 index 0000000000..c991b22e4a --- /dev/null +++ b/src/journal/journal-authenticate.h @@ -0,0 +1,35 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#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); + +int journal_file_hmac_put_header(JournalFile *f); +int journal_file_hmac_put_object(JournalFile *f, int type, uint64_t p); + +int journal_file_load_fsprg(JournalFile *f); + +int journal_file_setup_hmac(JournalFile *f); -- cgit v1.2.3-54-g00ecf From 4da416aa20b956571d74720bc91222881443e24b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 16 Aug 2012 02:14:34 +0200 Subject: journalctl: add --verify-seed= switch to specify seed value --- src/journal/journal-authenticate.c | 6 +++ src/journal/journal-authenticate.h | 5 ++ src/journal/journalctl.c | 95 ++++++++++++++++++++++---------------- 3 files changed, 65 insertions(+), 41 deletions(-) (limited to 'src/journal/journal-authenticate.h') diff --git a/src/journal/journal-authenticate.c b/src/journal/journal-authenticate.c index 827e4e4fb9..5a0314b4f6 100644 --- a/src/journal/journal-authenticate.c +++ b/src/journal/journal-authenticate.c @@ -432,3 +432,9 @@ int journal_file_append_first_tag(JournalFile *f) { return 0; } + +bool journal_file_fsprg_enabled(JournalFile *f) { + assert(f); + + return !!(le32toh(f->header->compatible_flags) & HEADER_COMPATIBLE_AUTHENTICATED); +} diff --git a/src/journal/journal-authenticate.h b/src/journal/journal-authenticate.h index c991b22e4a..566d7a81a9 100644 --- a/src/journal/journal-authenticate.h +++ b/src/journal/journal-authenticate.h @@ -21,6 +21,9 @@ along with systemd; If not, see . ***/ +#include +#include + #include "journal-file.h" int journal_file_append_tag(JournalFile *f); @@ -33,3 +36,5 @@ int journal_file_hmac_put_object(JournalFile *f, int type, uint64_t p); int journal_file_load_fsprg(JournalFile *f); int journal_file_setup_hmac(JournalFile *f); + +bool journal_file_fsprg_enabled(JournalFile *f); diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c index a70de0684e..3d274c8eb5 100644 --- a/src/journal/journalctl.c +++ b/src/journal/journalctl.c @@ -41,9 +41,10 @@ #include "logs-show.h" #include "strv.h" #include "journal-internal.h" -#include "fsprg.h" #include "journal-def.h" #include "journal-verify.h" +#include "journal-authenticate.h" +#include "fsprg.h" #define DEFAULT_FSPRG_INTERVAL_USEC (15*USEC_PER_MINUTE) @@ -58,6 +59,7 @@ static bool arg_local = false; static bool arg_this_boot = false; static const char *arg_directory = NULL; static int arg_priorities = 0xFF; +static const char *arg_verify_seed = NULL; static enum { ACTION_SHOW, @@ -71,25 +73,26 @@ static int help(void) { printf("%s [OPTIONS...] [MATCH]\n\n" "Send control commands to or query the journal.\n\n" - " -h --help Show this help\n" - " --version Show package version\n" - " --no-pager Do not pipe output into a pager\n" - " -a --all Show all fields, including long and unprintable\n" - " -f --follow Follow journal\n" - " -n --lines=INTEGER Journal entries to show\n" - " --no-tail Show all lines, even in follow mode\n" - " -o --output=STRING Change journal output mode (short, short-monotonic,\n" - " verbose, export, json, cat)\n" - " -q --quiet Don't show privilege warning\n" - " -l --local Only local entries\n" - " -b --this-boot Show data only from current boot\n" - " -D --directory=PATH Show journal files from directory\n" - " -p --priority=RANGE Show only messages within the specified priority range\n\n" + " -h --help Show this help\n" + " --version Show package version\n" + " --no-pager Do not pipe output into a pager\n" + " -a --all Show all fields, including long and unprintable\n" + " -f --follow Follow journal\n" + " -n --lines=INTEGER Journal entries to show\n" + " --no-tail Show all lines, even in follow mode\n" + " -o --output=STRING Change journal output mode (short, short-monotonic,\n" + " verbose, export, json, cat)\n" + " -q --quiet Don't show privilege warning\n" + " -l --local Only local entries\n" + " -b --this-boot Show data only from current boot\n" + " -D --directory=PATH Show journal files from directory\n" + " -p --priority=RANGE Show only messages within the specified priority range\n\n" "Commands:\n" - " --new-id128 Generate a new 128 Bit ID\n" - " --header Show journal header information\n" - " --setup-keys Generate new FSPRG key pair\n" - " --verify Verify journal file consistency\n", + " --new-id128 Generate a new 128 Bit ID\n" + " --header Show journal header information\n" + " --verify Verify journal file consistency\n" + " --verify-seed=SEED Specify FSPRG seed for verification\n" + " --setup-keys Generate new FSPRG key and seed\n", program_invocation_short_name); return 0; @@ -104,28 +107,30 @@ static int parse_argv(int argc, char *argv[]) { ARG_NEW_ID128, ARG_HEADER, ARG_SETUP_KEYS, - ARG_VERIFY + ARG_VERIFY, + ARG_VERIFY_SEED }; static const struct option options[] = { - { "help", no_argument, NULL, 'h' }, - { "version" , no_argument, NULL, ARG_VERSION }, - { "no-pager", no_argument, NULL, ARG_NO_PAGER }, - { "follow", no_argument, NULL, 'f' }, - { "output", required_argument, NULL, 'o' }, - { "all", no_argument, NULL, 'a' }, - { "lines", required_argument, NULL, 'n' }, - { "no-tail", no_argument, NULL, ARG_NO_TAIL }, - { "new-id128", no_argument, NULL, ARG_NEW_ID128 }, - { "quiet", no_argument, NULL, 'q' }, - { "local", no_argument, NULL, 'l' }, - { "this-boot", no_argument, NULL, 'b' }, - { "directory", required_argument, NULL, 'D' }, - { "header", no_argument, NULL, ARG_HEADER }, - { "priority", no_argument, NULL, 'p' }, - { "setup-keys",no_argument, NULL, ARG_SETUP_KEYS}, - { "verify", no_argument, NULL, ARG_VERIFY }, - { NULL, 0, NULL, 0 } + { "help", no_argument, NULL, 'h' }, + { "version" , no_argument, NULL, ARG_VERSION }, + { "no-pager", no_argument, NULL, ARG_NO_PAGER }, + { "follow", no_argument, NULL, 'f' }, + { "output", required_argument, NULL, 'o' }, + { "all", no_argument, NULL, 'a' }, + { "lines", required_argument, NULL, 'n' }, + { "no-tail", no_argument, NULL, ARG_NO_TAIL }, + { "new-id128", no_argument, NULL, ARG_NEW_ID128 }, + { "quiet", no_argument, NULL, 'q' }, + { "local", no_argument, NULL, 'l' }, + { "this-boot", no_argument, NULL, 'b' }, + { "directory", required_argument, NULL, 'D' }, + { "header", no_argument, NULL, ARG_HEADER }, + { "priority", no_argument, NULL, 'p' }, + { "setup-keys", no_argument, NULL, ARG_SETUP_KEYS }, + { "verify", no_argument, NULL, ARG_VERIFY }, + { "verify-seed", required_argument, NULL, ARG_VERIFY_SEED }, + { NULL, 0, NULL, 0 } }; int c, r; @@ -212,6 +217,11 @@ static int parse_argv(int argc, char *argv[]) { arg_action = ACTION_VERIFY; break; + case ARG_VERIFY_SEED: + arg_action = ACTION_VERIFY; + arg_verify_seed = optarg; + break; + case 'p': { const char *dots; @@ -541,8 +551,8 @@ static int setup_keys(void) { fprintf(stderr, "\n" "The new key pair has been generated. The evolving key has been written to the\n" - "following file. It will be used to protect local journal files. This file does\n" - "not need to be kept secret. It should not be used on multiple hosts.\n" + "following file. It will be used to protect local journal files. This file\n" + "should be kept secret. It should not be used on multiple hosts.\n" "\n" "\t%s\n" "\n" @@ -591,7 +601,10 @@ static int verify(sd_journal *j) { HASHMAP_FOREACH(f, j->files, i) { int k; - k = journal_file_verify(f, NULL); + if (!arg_verify_seed && journal_file_fsprg_enabled(f)) + log_warning("Journal file %s has authentication enabled but verification seed has not been passed using --verify-seed=.", f->path); + + k = journal_file_verify(f, arg_verify_seed); if (k < 0) { log_warning("FAIL: %s (%s)", f->path, strerror(-k)); r = -r; -- cgit v1.2.3-54-g00ecf From 14d10188de1fd58e663d73683a400d8d7dc67dba Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 16 Aug 2012 23:58:14 +0200 Subject: journal: add FSPRG journal authentication --- src/journal/journal-authenticate.c | 52 +++++++++++++++++++++++++---- src/journal/journal-authenticate.h | 3 ++ src/journal/journal-def.h | 1 + src/journal/journal-file.c | 8 ++--- src/journal/journal-verify.c | 68 +++++++++++++++++++++++++++++++++++--- src/journal/journalctl.c | 63 ++++++++++++++++++++--------------- src/journal/test-journal-verify.c | 5 +-- 7 files changed, 157 insertions(+), 43 deletions(-) (limited to 'src/journal/journal-authenticate.h') diff --git a/src/journal/journal-authenticate.c b/src/journal/journal-authenticate.c index 809655e1ac..c087ad4c8b 100644 --- a/src/journal/journal-authenticate.c +++ b/src/journal/journal-authenticate.c @@ -60,6 +60,7 @@ int journal_file_append_tag(JournalFile *f) { return r; o->tag.seqnum = htole64(journal_file_tag_seqnum(f)); + o->tag.epoch = htole64(FSPRG_GetEpoch(f->fsprg_state)); /* Add the tag object itself, so that we can protect its * header. This will exclude the actual hash value in it */ @@ -74,9 +75,8 @@ int journal_file_append_tag(JournalFile *f) { return 0; } -static int journal_file_hmac_start(JournalFile *f) { +int journal_file_hmac_start(JournalFile *f) { uint8_t key[256 / 8]; /* Let's pass 256 bit from FSPRG to HMAC */ - assert(f); if (!f->authenticate) @@ -163,6 +163,44 @@ static int journal_file_evolve(JournalFile *f, uint64_t realtime) { } } +int journal_file_fsprg_seek(JournalFile *f, uint64_t goal) { + void *msk; + uint64_t epoch; + + assert(f); + + if (!f->authenticate) + return 0; + + assert(f->fsprg_seed); + + if (f->fsprg_state) { + /* Cheaper... */ + + epoch = FSPRG_GetEpoch(f->fsprg_state); + if (goal == epoch) + return 0; + + if (goal == epoch+1) { + FSPRG_Evolve(f->fsprg_state); + return 0; + } + } else { + f->fsprg_state_size = FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR); + f->fsprg_state = malloc(f->fsprg_state_size); + + if (!f->fsprg_state) + return -ENOMEM; + } + + log_debug("Seeking FSPRG key to %llu.", (unsigned long long) goal); + + msk = alloca(FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR)); + FSPRG_GenMK(msk, NULL, f->fsprg_seed, f->fsprg_seed_size, FSPRG_RECOMMENDED_SECPAR); + FSPRG_Seek(f->fsprg_state, goal, msk, f->fsprg_seed, f->fsprg_seed_size); + return 0; +} + int journal_file_maybe_append_tag(JournalFile *f, uint64_t realtime) { int r; @@ -212,7 +250,7 @@ int journal_file_hmac_put_object(JournalFile *f, int type, uint64_t p) { switch (o->object.type) { case OBJECT_DATA: - /* All but: hash and payload are mutable */ + /* All but hash and payload are mutable */ gcry_md_write(f->hmac, &o->data.hash, sizeof(o->data.hash)); gcry_md_write(f->hmac, o->data.payload, le64toh(o->object.size) - offsetof(DataObject, payload)); break; @@ -231,6 +269,7 @@ int journal_file_hmac_put_object(JournalFile *f, int type, uint64_t p) { case OBJECT_TAG: /* All but the tag itself */ gcry_md_write(f->hmac, &o->tag.seqnum, sizeof(o->tag.seqnum)); + gcry_md_write(f->hmac, &o->tag.epoch, sizeof(o->tag.epoch)); break; default: return -EINVAL; @@ -252,15 +291,16 @@ int journal_file_hmac_put_header(JournalFile *f) { return r; /* All but state+reserved, boot_id, arena_size, - * tail_object_offset, n_objects, n_entries, tail_seqnum, + * tail_object_offset, n_objects, n_entries, + * tail_entry_seqnum, head_entry_seqnum, entry_array_offset, * head_entry_realtime, tail_entry_realtime, - * tail_entry_monotonic, n_data, n_fields, header_tag */ + * tail_entry_monotonic, n_data, n_fields, n_tags, + * n_entry_arrays. */ gcry_md_write(f->hmac, f->header->signature, offsetof(Header, state) - offsetof(Header, signature)); gcry_md_write(f->hmac, &f->header->file_id, offsetof(Header, boot_id) - offsetof(Header, file_id)); gcry_md_write(f->hmac, &f->header->seqnum_id, offsetof(Header, arena_size) - offsetof(Header, seqnum_id)); gcry_md_write(f->hmac, &f->header->data_hash_table_offset, offsetof(Header, tail_object_offset) - offsetof(Header, data_hash_table_offset)); - gcry_md_write(f->hmac, &f->header->head_entry_seqnum, offsetof(Header, head_entry_realtime) - offsetof(Header, head_entry_seqnum)); return 0; } diff --git a/src/journal/journal-authenticate.h b/src/journal/journal-authenticate.h index 566d7a81a9..282c73f68c 100644 --- a/src/journal/journal-authenticate.h +++ b/src/journal/journal-authenticate.h @@ -30,6 +30,7 @@ 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); +int journal_file_hmac_start(JournalFile *f); int journal_file_hmac_put_header(JournalFile *f); int journal_file_hmac_put_object(JournalFile *f, int type, uint64_t p); @@ -38,3 +39,5 @@ int journal_file_load_fsprg(JournalFile *f); int journal_file_setup_hmac(JournalFile *f); bool journal_file_fsprg_enabled(JournalFile *f); + +int journal_file_fsprg_seek(JournalFile *f, uint64_t epoch); diff --git a/src/journal/journal-def.h b/src/journal/journal-def.h index 660a92c147..ab4988037c 100644 --- a/src/journal/journal-def.h +++ b/src/journal/journal-def.h @@ -125,6 +125,7 @@ _packed_ struct EntryArrayObject { _packed_ struct TagObject { ObjectHeader object; uint64_t seqnum; + uint64_t epoch; uint8_t tag[TAG_LENGTH]; /* SHA-256 HMAC */ }; diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c index 3bb1e90fb3..274f22db17 100644 --- a/src/journal/journal-file.c +++ b/src/journal/journal-file.c @@ -2049,12 +2049,12 @@ int journal_file_open( r = journal_file_refresh_header(f); if (r < 0) goto fail; - - r = journal_file_setup_hmac(f); - if (r < 0) - goto fail; } + r = journal_file_setup_hmac(f); + if (r < 0) + goto fail; + if (newly_created) { r = journal_file_setup_field_hash_table(f); if (r < 0) diff --git a/src/journal/journal-verify.c b/src/journal/journal-verify.c index 94f90b670d..e646e38ddc 100644 --- a/src/journal/journal-verify.c +++ b/src/journal/journal-verify.c @@ -35,7 +35,10 @@ /* FIXME: * - * - verify FSPRG + * - write tag only if non-tag objects have been written + * - change terms + * - write bit mucking test + * * - Allow building without libgcrypt * - check with sparse * - 64bit conversions @@ -650,11 +653,11 @@ static int journal_file_parse_seed(JournalFile *f, const char *s) { int journal_file_verify(JournalFile *f, const char *seed) { int r; Object *o; - uint64_t p = 0, last_tag = 0; - uint64_t n_tags = 0, entry_seqnum = 0, entry_monotonic = 0, entry_realtime = 0; + uint64_t p = 0, last_tag = 0, last_epoch = 0; + uint64_t entry_seqnum = 0, entry_monotonic = 0, entry_realtime = 0; sd_id128_t entry_boot_id; bool entry_seqnum_set = false, entry_monotonic_set = false, entry_realtime_set = false, found_main_entry_array = false; - uint64_t n_weird = 0, n_objects = 0, n_entries = 0, n_data = 0, n_fields = 0, n_data_hash_tables = 0, n_field_hash_tables = 0, n_entry_arrays = 0; + uint64_t n_weird = 0, n_objects = 0, n_entries = 0, n_data = 0, n_fields = 0, n_data_hash_tables = 0, n_field_hash_tables = 0, n_entry_arrays = 0, n_tags = 0; usec_t last_usec = 0; int data_fd = -1, entry_fd = -1, entry_array_fd = -1; char data_path[] = "/var/tmp/journal-data-XXXXXX", @@ -842,7 +845,9 @@ int journal_file_verify(JournalFile *f, const char *seed) { n_entry_arrays++; break; - case OBJECT_TAG: + case OBJECT_TAG: { + uint64_t q; + if (!(le32toh(f->header->compatible_flags) & HEADER_COMPATIBLE_AUTHENTICATED)) { log_error("Tag object without authentication at %llu", (unsigned long long) p); r = -EBADMSG; @@ -855,8 +860,61 @@ int journal_file_verify(JournalFile *f, const char *seed) { goto fail; } + if (le64toh(o->tag.epoch) < last_epoch) { + log_error("Epoch sequence out of synchronization at %llu", (unsigned long long) p); + r = -EBADMSG; + goto fail; + } + + /* 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)); + if (r < 0) + goto fail; + + r = journal_file_hmac_start(f); + if (r < 0) + goto fail; + + if (last_tag == 0) { + r = journal_file_hmac_put_header(f); + if (r < 0) + goto fail; + + q = le64toh(f->header->header_size); + } else + q = last_tag; + + while (q <= p) { + r = journal_file_move_to_object(f, -1, q, &o); + if (r < 0) + goto fail; + + r = journal_file_hmac_put_object(f, -1, q); + if (r < 0) + goto fail; + + q = q + ALIGN64(le64toh(o->object.size)); + } + + /* Position might have changed, let's reposition things */ + r = journal_file_move_to_object(f, -1, p, &o); + if (r < 0) + goto fail; + + if (memcmp(o->tag.tag, gcry_md_read(f->hmac, 0), TAG_LENGTH) != 0) { + log_error("Tag did not authenticate at %llu", (unsigned long long) p); + r = -EBADMSG; + goto fail; + } + + f->hmac_running = false; + + last_tag = p + ALIGN64(le64toh(o->object.size)); n_tags ++; break; + } default: n_weird ++; diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c index 25e441b022..f0654fe4e8 100644 --- a/src/journal/journalctl.c +++ b/src/journal/journalctl.c @@ -60,6 +60,7 @@ static bool arg_this_boot = false; static const char *arg_directory = NULL; static int arg_priorities = 0xFF; static const char *arg_verify_seed = NULL; +static usec_t arg_evolve = DEFAULT_FSPRG_INTERVAL_USEC; static enum { ACTION_SHOW, @@ -73,26 +74,27 @@ static int help(void) { printf("%s [OPTIONS...] [MATCH]\n\n" "Send control commands to or query the journal.\n\n" - " -h --help Show this help\n" - " --version Show package version\n" - " --no-pager Do not pipe output into a pager\n" - " -a --all Show all fields, including long and unprintable\n" - " -f --follow Follow journal\n" - " -n --lines=INTEGER Journal entries to show\n" - " --no-tail Show all lines, even in follow mode\n" - " -o --output=STRING Change journal output mode (short, short-monotonic,\n" - " verbose, export, json, cat)\n" - " -q --quiet Don't show privilege warning\n" - " -l --local Only local entries\n" - " -b --this-boot Show data only from current boot\n" - " -D --directory=PATH Show journal files from directory\n" - " -p --priority=RANGE Show only messages within the specified priority range\n\n" + " -h --help Show this help\n" + " --version Show package version\n" + " --no-pager Do not pipe output into a pager\n" + " -a --all Show all fields, including long and unprintable\n" + " -f --follow Follow journal\n" + " -n --lines=INTEGER Journal entries to show\n" + " --no-tail Show all lines, even in follow mode\n" + " -o --output=STRING Change journal output mode (short, short-monotonic,\n" + " verbose, export, json, cat)\n" + " -q --quiet Don't show privilege warning\n" + " -l --local Only local entries\n" + " -b --this-boot Show data only from current boot\n" + " -D --directory=PATH Show journal files from directory\n" + " -p --priority=RANGE Show only messages within the specified priority range\n\n" "Commands:\n" - " --new-id128 Generate a new 128 Bit ID\n" - " --header Show journal header information\n" - " --verify Verify journal file consistency\n" - " --verify-seed=SEED Specify FSPRG seed for verification\n" - " --setup-keys Generate new FSPRG key and seed\n", + " --new-id128 Generate a new 128 Bit ID\n" + " --header Show journal header information\n" + " --verify Verify journal file consistency\n" + " --verify-seed=SEED Specify FSPRG seed for verification\n" + " --setup-keys Generate new FSPRG key and seed\n" + " --evolve=TIME How of to evolve FSPRG keys\n", program_invocation_short_name); return 0; @@ -108,7 +110,8 @@ static int parse_argv(int argc, char *argv[]) { ARG_HEADER, ARG_SETUP_KEYS, ARG_VERIFY, - ARG_VERIFY_SEED + ARG_VERIFY_SEED, + ARG_EVOLVE }; static const struct option options[] = { @@ -130,6 +133,7 @@ static int parse_argv(int argc, char *argv[]) { { "setup-keys", no_argument, NULL, ARG_SETUP_KEYS }, { "verify", no_argument, NULL, ARG_VERIFY }, { "verify-seed", required_argument, NULL, ARG_VERIFY_SEED }, + { "evolve", required_argument, NULL, ARG_EVOLVE }, { NULL, 0, NULL, 0 } }; @@ -222,6 +226,14 @@ static int parse_argv(int argc, char *argv[]) { arg_verify_seed = optarg; break; + case ARG_EVOLVE: + r = parse_usec(optarg, &arg_evolve); + if (r < 0 || arg_evolve <= 0) { + log_error("Failed to parse evolve interval: %s", optarg); + return -EINVAL; + } + break; + case 'p': { const char *dots; @@ -445,7 +457,7 @@ static int setup_keys(void) { sd_id128_t machine, boot; char *p = NULL, *k = NULL; struct FSPRGHeader h; - uint64_t n, interval; + uint64_t n; r = sd_id128_get_machine(&machine); if (r < 0) { @@ -505,9 +517,8 @@ static int setup_keys(void) { log_info("Generating evolving key..."); FSPRG_GenState0(state, mpk, seed, seed_size); - interval = DEFAULT_FSPRG_INTERVAL_USEC; n = now(CLOCK_REALTIME); - n /= interval; + n /= arg_evolve; close_nointr_nofail(fd); fd = mkostemp(k, O_WRONLY|O_CLOEXEC|O_NOCTTY); @@ -522,8 +533,8 @@ static int setup_keys(void) { h.machine_id = machine; h.boot_id = boot; h.header_size = htole64(sizeof(h)); - h.fsprg_start_usec = htole64(n * interval); - h.fsprg_interval_usec = htole64(interval); + h.fsprg_start_usec = htole64(n * arg_evolve); + h.fsprg_interval_usec = htole64(arg_evolve); h.secpar = htole16(FSPRG_RECOMMENDED_SECPAR); h.state_size = htole64(state_size); @@ -567,7 +578,7 @@ static int setup_keys(void) { printf("%02x", ((uint8_t*) seed)[i]); } - printf("/%llx-%llx\n", (unsigned long long) n, (unsigned long long) interval); + printf("/%llx-%llx\n", (unsigned long long) n, (unsigned long long) arg_evolve); if (isatty(STDOUT_FILENO)) fputs(ANSI_HIGHLIGHT_OFF "\n", stderr); diff --git a/src/journal/test-journal-verify.c b/src/journal/test-journal-verify.c index bada498fab..8a7d998ff9 100644 --- a/src/journal/test-journal-verify.c +++ b/src/journal/test-journal-verify.c @@ -35,6 +35,7 @@ int main(int argc, char *argv[]) { char t[] = "/tmp/journal-XXXXXX"; unsigned n; JournalFile *f; + const char *verification_key = argv[1]; log_set_max_level(LOG_DEBUG); @@ -43,7 +44,7 @@ int main(int argc, char *argv[]) { log_info("Generating..."); - assert_se(journal_file_open("test.journal", O_RDWR|O_CREAT, 0666, true, true, NULL, NULL, NULL, &f) == 0); + assert_se(journal_file_open("test.journal", O_RDWR|O_CREAT, 0666, true, !!verification_key, NULL, NULL, NULL, &f) == 0); for (n = 0; n < N_ENTRIES; n++) { struct iovec iovec; @@ -67,7 +68,7 @@ int main(int argc, char *argv[]) { log_info("Verifying..."); assert_se(journal_file_open("test.journal", O_RDONLY, 0666, false, false, NULL, NULL, NULL, &f) == 0); - assert_se(journal_file_verify(f, NULL) >= 0); + assert_se(journal_file_verify(f, verification_key) >= 0); journal_file_close(f); log_info("Exiting..."); -- cgit v1.2.3-54-g00ecf From baed47c3c20512507e497058d388782400a072f6 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 17 Aug 2012 00:45:18 +0200 Subject: journal: rework terminology Let's clean up our terminology a bit. New terminology: FSS = Forward Secure Sealing FSPRG = Forward Secure Pseudo-Random Generator FSS is the combination of FSPRG and a HMAC. Sealing = process of adding authentication tags to the journal. Verification = process of checking authentication tags to the journal. Sealing Key = The key used for adding authentication tags to the journal. Verification Key = The key used for checking authentication tags of the journal. Key pair = The pair of Sealing Key and Verification Key Internally, the Sealing Key is the combination of the FSPRG State plus change interval/start time. Internally, the Verification Key is the combination of the FSPRG Seed plus change interval/start time. --- src/journal/journal-authenticate.c | 88 ++++++++++----------- src/journal/journal-authenticate.h | 9 +-- src/journal/journal-def.h | 16 ++-- src/journal/journal-file.c | 44 +++++------ src/journal/journal-file.h | 18 ++--- src/journal/journal-verify.c | 22 +++--- src/journal/journalctl.c | 151 +++++++++++++++++++------------------ 7 files changed, 178 insertions(+), 170 deletions(-) (limited to 'src/journal/journal-authenticate.h') diff --git a/src/journal/journal-authenticate.c b/src/journal/journal-authenticate.c index c087ad4c8b..ae64d3c8e0 100644 --- a/src/journal/journal-authenticate.c +++ b/src/journal/journal-authenticate.c @@ -45,7 +45,7 @@ int journal_file_append_tag(JournalFile *f) { assert(f); - if (!f->authenticate) + if (!f->seal) return 0; if (!f->hmac_running) @@ -79,7 +79,7 @@ int journal_file_hmac_start(JournalFile *f) { uint8_t key[256 / 8]; /* Let's pass 256 bit from FSPRG to HMAC */ assert(f); - if (!f->authenticate) + if (!f->seal) return 0; if (f->hmac_running) @@ -100,28 +100,28 @@ static int journal_file_get_epoch(JournalFile *f, uint64_t realtime, uint64_t *e assert(f); assert(epoch); - assert(f->authenticate); + assert(f->seal); - if (f->fsprg_start_usec == 0 || - f->fsprg_interval_usec == 0) + if (f->fss_start_usec == 0 || + f->fss_interval_usec == 0) return -ENOTSUP; - if (realtime < f->fsprg_start_usec) + if (realtime < f->fss_start_usec) return -ESTALE; - t = realtime - f->fsprg_start_usec; - t = t / f->fsprg_interval_usec; + t = realtime - f->fss_start_usec; + t = t / f->fss_interval_usec; *epoch = t; return 0; } -static int journal_file_need_evolve(JournalFile *f, uint64_t realtime) { +static int journal_file_fsprg_need_evolve(JournalFile *f, uint64_t realtime) { uint64_t goal, epoch; int r; assert(f); - if (!f->authenticate) + if (!f->seal) return 0; r = journal_file_get_epoch(f, realtime, &goal); @@ -135,13 +135,13 @@ static int journal_file_need_evolve(JournalFile *f, uint64_t realtime) { return epoch != goal; } -static int journal_file_evolve(JournalFile *f, uint64_t realtime) { +int journal_file_fsprg_evolve(JournalFile *f, uint64_t realtime) { uint64_t goal, epoch; int r; assert(f); - if (!f->authenticate) + if (!f->seal) return 0; r = journal_file_get_epoch(f, realtime, &goal); @@ -169,7 +169,7 @@ int journal_file_fsprg_seek(JournalFile *f, uint64_t goal) { assert(f); - if (!f->authenticate) + if (!f->seal) return 0; assert(f->fsprg_seed); @@ -206,10 +206,10 @@ int journal_file_maybe_append_tag(JournalFile *f, uint64_t realtime) { assert(f); - if (!f->authenticate) + if (!f->seal) return 0; - r = journal_file_need_evolve(f, realtime); + r = journal_file_fsprg_need_evolve(f, realtime); if (r <= 0) return 0; @@ -217,7 +217,7 @@ int journal_file_maybe_append_tag(JournalFile *f, uint64_t realtime) { if (r < 0) return r; - r = journal_file_evolve(f, realtime); + r = journal_file_fsprg_evolve(f, realtime); if (r < 0) return r; @@ -234,7 +234,7 @@ int journal_file_hmac_put_object(JournalFile *f, int type, uint64_t p) { assert(f); - if (!f->authenticate) + if (!f->seal) return 0; r = journal_file_hmac_start(f); @@ -283,7 +283,7 @@ int journal_file_hmac_put_header(JournalFile *f) { assert(f); - if (!f->authenticate) + if (!f->seal) return 0; r = journal_file_hmac_start(f); @@ -305,23 +305,23 @@ int journal_file_hmac_put_header(JournalFile *f) { return 0; } -int journal_file_load_fsprg(JournalFile *f) { +int journal_file_fss_load(JournalFile *f) { int r, fd = -1; char *p = NULL; struct stat st; - FSPRGHeader *m = NULL; + FSSHeader *m = NULL; sd_id128_t machine; assert(f); - if (!f->authenticate) + if (!f->seal) return 0; r = sd_id128_get_machine(&machine); if (r < 0) return r; - if (asprintf(&p, "/var/log/journal/" SD_ID128_FORMAT_STR "/fsprg", + if (asprintf(&p, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss", SD_ID128_FORMAT_VAL(machine)) < 0) return -ENOMEM; @@ -337,19 +337,19 @@ int journal_file_load_fsprg(JournalFile *f) { goto finish; } - if (st.st_size < (off_t) sizeof(FSPRGHeader)) { + if (st.st_size < (off_t) sizeof(FSSHeader)) { r = -ENODATA; goto finish; } - m = mmap(NULL, PAGE_ALIGN(sizeof(FSPRGHeader)), PROT_READ, MAP_SHARED, fd, 0); + m = mmap(NULL, PAGE_ALIGN(sizeof(FSSHeader)), PROT_READ, MAP_SHARED, fd, 0); if (m == MAP_FAILED) { m = NULL; r = -errno; goto finish; } - if (memcmp(m->signature, FSPRG_HEADER_SIGNATURE, 8) != 0) { + if (memcmp(m->signature, FSS_HEADER_SIGNATURE, 8) != 0) { r = -EBADMSG; goto finish; } @@ -359,18 +359,18 @@ int journal_file_load_fsprg(JournalFile *f) { goto finish; } - if (le64toh(m->header_size) < sizeof(FSPRGHeader)) { + if (le64toh(m->header_size) < sizeof(FSSHeader)) { r = -EBADMSG; goto finish; } - if (le64toh(m->state_size) != FSPRG_stateinbytes(m->secpar)) { + if (le64toh(m->fsprg_state_size) != FSPRG_stateinbytes(m->fsprg_secpar)) { r = -EBADMSG; goto finish; } - f->fsprg_file_size = le64toh(m->header_size) + le64toh(m->state_size); - if ((uint64_t) st.st_size < f->fsprg_file_size) { + f->fss_file_size = le64toh(m->header_size) + le64toh(m->fsprg_state_size); + if ((uint64_t) st.st_size < f->fss_file_size) { r = -ENODATA; goto finish; } @@ -380,30 +380,30 @@ int journal_file_load_fsprg(JournalFile *f) { goto finish; } - if (le64toh(m->fsprg_start_usec) <= 0 || - le64toh(m->fsprg_interval_usec) <= 0) { + if (le64toh(m->start_usec) <= 0 || + le64toh(m->interval_usec) <= 0) { r = -EBADMSG; goto finish; } - f->fsprg_file = mmap(NULL, PAGE_ALIGN(f->fsprg_file_size), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); - if (f->fsprg_file == MAP_FAILED) { - f->fsprg_file = NULL; + f->fss_file = mmap(NULL, PAGE_ALIGN(f->fss_file_size), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); + if (f->fss_file == MAP_FAILED) { + f->fss_file = NULL; r = -errno; goto finish; } - f->fsprg_start_usec = le64toh(f->fsprg_file->fsprg_start_usec); - f->fsprg_interval_usec = le64toh(f->fsprg_file->fsprg_interval_usec); + f->fss_start_usec = le64toh(f->fss_file->start_usec); + f->fss_interval_usec = le64toh(f->fss_file->interval_usec); - f->fsprg_state = (uint8_t*) f->fsprg_file + le64toh(f->fsprg_file->header_size); - f->fsprg_state_size = le64toh(f->fsprg_file->state_size); + f->fsprg_state = (uint8_t*) f->fss_file + le64toh(f->fss_file->header_size); + f->fsprg_state_size = le64toh(f->fss_file->fsprg_state_size); r = 0; finish: if (m) - munmap(m, PAGE_ALIGN(sizeof(FSPRGHeader))); + munmap(m, PAGE_ALIGN(sizeof(FSSHeader))); if (fd >= 0) close_nointr_nofail(fd); @@ -412,10 +412,10 @@ finish: return r; } -int journal_file_setup_hmac(JournalFile *f) { +int journal_file_hmac_setup(JournalFile *f) { gcry_error_t e; - if (!f->authenticate) + if (!f->seal) return 0; e = gcry_md_open(&f->hmac, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC); @@ -429,7 +429,7 @@ int journal_file_append_first_tag(JournalFile *f) { int r; uint64_t p; - if (!f->authenticate) + if (!f->seal) return 0; log_debug("Calculating first tag..."); @@ -463,8 +463,8 @@ int journal_file_append_first_tag(JournalFile *f) { return 0; } -bool journal_file_fsprg_enabled(JournalFile *f) { +bool journal_file_fss_enabled(JournalFile *f) { assert(f); - return !!(le32toh(f->header->compatible_flags) & HEADER_COMPATIBLE_AUTHENTICATED); + return !!(le32toh(f->header->compatible_flags) & HEADER_COMPATIBLE_SEALED); } diff --git a/src/journal/journal-authenticate.h b/src/journal/journal-authenticate.h index 282c73f68c..4f4f45b114 100644 --- a/src/journal/journal-authenticate.h +++ b/src/journal/journal-authenticate.h @@ -30,14 +30,13 @@ 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); +int journal_file_hmac_setup(JournalFile *f); int journal_file_hmac_start(JournalFile *f); int journal_file_hmac_put_header(JournalFile *f); int journal_file_hmac_put_object(JournalFile *f, int type, uint64_t p); -int journal_file_load_fsprg(JournalFile *f); - -int journal_file_setup_hmac(JournalFile *f); - -bool journal_file_fsprg_enabled(JournalFile *f); +int journal_file_fss_load(JournalFile *f); +bool journal_file_fss_enabled(JournalFile *f); +int journal_file_fsprg_evolve(JournalFile *f, uint64_t realtime); int journal_file_fsprg_seek(JournalFile *f, uint64_t epoch); diff --git a/src/journal/journal-def.h b/src/journal/journal-def.h index ab4988037c..52c55ab4bb 100644 --- a/src/journal/journal-def.h +++ b/src/journal/journal-def.h @@ -42,7 +42,7 @@ typedef struct TagObject TagObject; typedef struct EntryItem EntryItem; typedef struct HashItem HashItem; -typedef struct FSPRGHeader FSPRGHeader; +typedef struct FSSHeader FSSHeader; /* Object types */ enum { @@ -151,7 +151,7 @@ enum { }; enum { - HEADER_COMPATIBLE_AUTHENTICATED = 1 + HEADER_COMPATIBLE_SEALED = 1 }; #define HEADER_SIGNATURE ((char[]) { 'L', 'P', 'K', 'S', 'H', 'H', 'R', 'H' }) @@ -189,18 +189,18 @@ _packed_ struct Header { le64_t n_entry_arrays; }; -#define FSPRG_HEADER_SIGNATURE ((char[]) { 'K', 'S', 'H', 'H', 'R', 'H', 'L', 'P' }) +#define FSS_HEADER_SIGNATURE ((char[]) { 'K', 'S', 'H', 'H', 'R', 'H', 'L', 'P' }) -_packed_ struct FSPRGHeader { +_packed_ struct FSSHeader { uint8_t signature[8]; /* "KSHHRHLP" */ le32_t compatible_flags; le32_t incompatible_flags; sd_id128_t machine_id; sd_id128_t boot_id; /* last writer */ le64_t header_size; - le64_t fsprg_start_usec; - le64_t fsprg_interval_usec; - le16_t secpar; + le64_t start_usec; + le64_t interval_usec; + le16_t fsprg_secpar; le16_t reserved[3]; - le64_t state_size; + le64_t fsprg_state_size; }; diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c index 274f22db17..76bf0e53ca 100644 --- a/src/journal/journal-file.c +++ b/src/journal/journal-file.c @@ -65,7 +65,7 @@ void journal_file_close(JournalFile *f) { assert(f); /* Write the final tag */ - if (f->authenticate) + if (f->seal) journal_file_append_tag(f); /* Sync everything to disk, before we mark the file offline */ @@ -96,8 +96,8 @@ void journal_file_close(JournalFile *f) { #endif #ifdef HAVE_GCRYPT - if (f->fsprg_file) - munmap(f->fsprg_file, PAGE_ALIGN(f->fsprg_file_size)); + if (f->fss_file) + munmap(f->fss_file, PAGE_ALIGN(f->fss_file_size)); else if (f->fsprg_state) free(f->fsprg_state); @@ -125,7 +125,7 @@ static int journal_file_init_header(JournalFile *f, JournalFile *template) { htole32(f->compress ? HEADER_INCOMPATIBLE_COMPRESSED : 0); h.compatible_flags = - htole32(f->authenticate ? HEADER_COMPATIBLE_AUTHENTICATED : 0); + htole32(f->seal ? HEADER_COMPATIBLE_SEALED : 0); r = sd_id128_randomize(&h.file_id); if (r < 0) @@ -195,7 +195,7 @@ static int journal_file_verify_header(JournalFile *f) { * compatible flags, too */ if (f->writable) { #ifdef HAVE_GCRYPT - if ((le32toh(f->header->compatible_flags) & ~HEADER_COMPATIBLE_AUTHENTICATED) != 0) + if ((le32toh(f->header->compatible_flags) & ~HEADER_COMPATIBLE_SEALED) != 0) return -EPROTONOSUPPORT; #else if (f->header->compatible_flags != 0) @@ -207,8 +207,8 @@ static int journal_file_verify_header(JournalFile *f) { if (le64toh(f->header->header_size) < HEADER_SIZE_MIN) return -EBADMSG; - if ((le32toh(f->header->compatible_flags) & HEADER_COMPATIBLE_AUTHENTICATED) && - !JOURNAL_HEADER_CONTAINS(f->header, n_tags)) + if ((le32toh(f->header->compatible_flags) & HEADER_COMPATIBLE_SEALED) && + !JOURNAL_HEADER_CONTAINS(f->header, n_entry_arrays)) return -EBADMSG; if ((uint64_t) f->last_stat.st_size < (le64toh(f->header->header_size) + le64toh(f->header->arena_size))) @@ -240,7 +240,7 @@ static int journal_file_verify_header(JournalFile *f) { } f->compress = !!(le32toh(f->header->incompatible_flags) & HEADER_INCOMPATIBLE_COMPRESSED); - f->authenticate = !!(le32toh(f->header->compatible_flags) & HEADER_COMPATIBLE_AUTHENTICATED); + f->seal = !!(le32toh(f->header->compatible_flags) & HEADER_COMPATIBLE_SEALED); return 0; } @@ -1900,8 +1900,8 @@ void journal_file_print_header(JournalFile *f) { f->header->state == STATE_OFFLINE ? "offline" : f->header->state == STATE_ONLINE ? "online" : f->header->state == STATE_ARCHIVED ? "archived" : "unknown", - (f->header->compatible_flags & HEADER_COMPATIBLE_AUTHENTICATED) ? " AUTHENTICATED" : "", - (f->header->compatible_flags & ~HEADER_COMPATIBLE_AUTHENTICATED) ? " ???" : "", + (f->header->compatible_flags & HEADER_COMPATIBLE_SEALED) ? " SEALED" : "", + (f->header->compatible_flags & ~HEADER_COMPATIBLE_SEALED) ? " ???" : "", (f->header->incompatible_flags & HEADER_INCOMPATIBLE_COMPRESSED) ? " COMPRESSED" : "", (f->header->incompatible_flags & ~HEADER_INCOMPATIBLE_COMPRESSED) ? " ???" : "", (unsigned long long) le64toh(f->header->header_size), @@ -1934,7 +1934,7 @@ int journal_file_open( int flags, mode_t mode, bool compress, - bool authenticate, + bool seal, JournalMetrics *metrics, MMapCache *mmap_cache, JournalFile *template, @@ -1964,7 +1964,7 @@ int journal_file_open( f->prot = prot_from_flags(flags); f->writable = (flags & O_ACCMODE) != O_RDONLY; f->compress = compress; - f->authenticate = authenticate; + f->seal = seal; if (mmap_cache) f->mmap = mmap_cache_ref(mmap_cache); @@ -2000,10 +2000,10 @@ int journal_file_open( newly_created = true; /* Try to load the FSPRG state, and if we can't, then - * just don't do authentication */ - r = journal_file_load_fsprg(f); + * just don't do sealing */ + r = journal_file_fss_load(f); if (r < 0) - f->authenticate = false; + f->seal = false; r = journal_file_init_header(f, template); if (r < 0) @@ -2034,7 +2034,7 @@ int journal_file_open( } if (!newly_created && f->writable) { - r = journal_file_load_fsprg(f); + r = journal_file_fss_load(f); if (r < 0) goto fail; } @@ -2051,7 +2051,7 @@ int journal_file_open( goto fail; } - r = journal_file_setup_hmac(f); + r = journal_file_hmac_setup(f); if (r < 0) goto fail; @@ -2088,7 +2088,7 @@ fail: return r; } -int journal_file_rotate(JournalFile **f, bool compress, bool authenticate) { +int journal_file_rotate(JournalFile **f, bool compress, bool seal) { char *p; size_t l; JournalFile *old_file, *new_file = NULL; @@ -2127,7 +2127,7 @@ int journal_file_rotate(JournalFile **f, bool compress, bool authenticate) { old_file->header->state = STATE_ARCHIVED; - r = journal_file_open(old_file->path, old_file->flags, old_file->mode, compress, authenticate, NULL, old_file->mmap, old_file, &new_file); + r = journal_file_open(old_file->path, old_file->flags, old_file->mode, compress, seal, NULL, old_file->mmap, old_file, &new_file); journal_file_close(old_file); *f = new_file; @@ -2139,7 +2139,7 @@ int journal_file_open_reliably( int flags, mode_t mode, bool compress, - bool authenticate, + bool seal, JournalMetrics *metrics, MMapCache *mmap_cache, JournalFile *template, @@ -2149,7 +2149,7 @@ int journal_file_open_reliably( size_t l; char *p; - r = journal_file_open(fname, flags, mode, compress, authenticate, + r = journal_file_open(fname, flags, mode, compress, seal, metrics, mmap_cache, template, ret); if (r != -EBADMSG && /* corrupted */ r != -ENODATA && /* truncated */ @@ -2184,7 +2184,7 @@ int journal_file_open_reliably( log_warning("File %s corrupted or uncleanly shut down, renaming and replacing.", fname); - return journal_file_open(fname, flags, mode, compress, authenticate, + return journal_file_open(fname, flags, mode, compress, seal, metrics, mmap_cache, template, ret); } diff --git a/src/journal/journal-file.h b/src/journal/journal-file.h index 9d437ae791..58de214359 100644 --- a/src/journal/journal-file.h +++ b/src/journal/journal-file.h @@ -51,7 +51,7 @@ typedef struct JournalFile { int prot; bool writable; bool compress; - bool authenticate; + bool seal; bool tail_entry_monotonic_valid; @@ -73,17 +73,17 @@ typedef struct JournalFile { gcry_md_hd_t hmac; bool hmac_running; - FSPRGHeader *fsprg_file; - size_t fsprg_file_size; + FSSHeader *fss_file; + size_t fss_file_size; + + uint64_t fss_start_usec; + uint64_t fss_interval_usec; void *fsprg_state; size_t fsprg_state_size; void *fsprg_seed; size_t fsprg_seed_size; - - uint64_t fsprg_start_usec; - uint64_t fsprg_interval_usec; #endif } JournalFile; @@ -97,7 +97,7 @@ int journal_file_open( int flags, mode_t mode, bool compress, - bool authenticate, + bool seal, JournalMetrics *metrics, MMapCache *mmap_cache, JournalFile *template, @@ -110,7 +110,7 @@ int journal_file_open_reliably( int flags, mode_t mode, bool compress, - bool authenticate, + bool seal, JournalMetrics *metrics, MMapCache *mmap_cache, JournalFile *template, @@ -152,7 +152,7 @@ int journal_file_copy_entry(JournalFile *from, JournalFile *to, Object *o, uint6 void journal_file_dump(JournalFile *f); void journal_file_print_header(JournalFile *f); -int journal_file_rotate(JournalFile **f, bool compress, bool authenticate); +int journal_file_rotate(JournalFile **f, bool compress, bool seal); void journal_file_post_change(JournalFile *f); diff --git a/src/journal/journal-verify.c b/src/journal/journal-verify.c index e646e38ddc..b7097e7b01 100644 --- a/src/journal/journal-verify.c +++ b/src/journal/journal-verify.c @@ -38,6 +38,7 @@ * - write tag only if non-tag objects have been written * - change terms * - write bit mucking test + * - tag timestamps should be between entry timestamps * * - Allow building without libgcrypt * - check with sparse @@ -595,7 +596,7 @@ static int verify_entry_array( return 0; } -static int journal_file_parse_seed(JournalFile *f, const char *s) { +static int journal_file_parse_verification_key(JournalFile *f, const char *key) { uint8_t *seed; size_t seed_size, c; const char *k; @@ -607,7 +608,7 @@ static int journal_file_parse_seed(JournalFile *f, const char *s) { if (!seed) return -ENOMEM; - k = s; + k = key; for (c = 0; c < seed_size; c++) { int x, y; @@ -644,13 +645,14 @@ static int journal_file_parse_seed(JournalFile *f, const char *s) { f->fsprg_seed = seed; f->fsprg_seed_size = seed_size; - f->fsprg_start_usec = start; - f->fsprg_interval_usec = interval; + + f->fss_start_usec = start; + f->fss_interval_usec = interval; return 0; } -int journal_file_verify(JournalFile *f, const char *seed) { +int journal_file_verify(JournalFile *f, const char *key) { int r; Object *o; uint64_t p = 0, last_tag = 0, last_epoch = 0; @@ -666,8 +668,8 @@ int journal_file_verify(JournalFile *f, const char *seed) { assert(f); - if (seed) { - r = journal_file_parse_seed(f, seed); + if (key) { + r = journal_file_parse_verification_key(f, key); if (r < 0) { log_error("Failed to parse seed."); return r; @@ -848,8 +850,8 @@ int journal_file_verify(JournalFile *f, const char *seed) { case OBJECT_TAG: { uint64_t q; - if (!(le32toh(f->header->compatible_flags) & HEADER_COMPATIBLE_AUTHENTICATED)) { - log_error("Tag object without authentication at %llu", (unsigned long long) p); + if (!(le32toh(f->header->compatible_flags) & HEADER_COMPATIBLE_SEALED)) { + log_error("Tag object without sealing at %llu", (unsigned long long) p); r = -EBADMSG; goto fail; } @@ -904,7 +906,7 @@ int journal_file_verify(JournalFile *f, const char *seed) { goto fail; if (memcmp(o->tag.tag, gcry_md_read(f->hmac, 0), TAG_LENGTH) != 0) { - log_error("Tag did not authenticate at %llu", (unsigned long long) p); + log_error("Tag failed verification at %llu", (unsigned long long) p); r = -EBADMSG; goto fail; } diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c index f0654fe4e8..0df8ce57fd 100644 --- a/src/journal/journalctl.c +++ b/src/journal/journalctl.c @@ -46,7 +46,7 @@ #include "journal-authenticate.h" #include "fsprg.h" -#define DEFAULT_FSPRG_INTERVAL_USEC (15*USEC_PER_MINUTE) +#define DEFAULT_FSS_INTERVAL_USEC (15*USEC_PER_MINUTE) static OutputMode arg_output = OUTPUT_SHORT; static bool arg_follow = false; @@ -59,8 +59,8 @@ static bool arg_local = false; static bool arg_this_boot = false; static const char *arg_directory = NULL; static int arg_priorities = 0xFF; -static const char *arg_verify_seed = NULL; -static usec_t arg_evolve = DEFAULT_FSPRG_INTERVAL_USEC; +static const char *arg_verify_key = NULL; +static usec_t arg_interval = DEFAULT_FSS_INTERVAL_USEC; static enum { ACTION_SHOW, @@ -74,27 +74,27 @@ static int help(void) { printf("%s [OPTIONS...] [MATCH]\n\n" "Send control commands to or query the journal.\n\n" - " -h --help Show this help\n" - " --version Show package version\n" - " --no-pager Do not pipe output into a pager\n" - " -a --all Show all fields, including long and unprintable\n" - " -f --follow Follow journal\n" - " -n --lines=INTEGER Journal entries to show\n" - " --no-tail Show all lines, even in follow mode\n" - " -o --output=STRING Change journal output mode (short, short-monotonic,\n" - " verbose, export, json, cat)\n" - " -q --quiet Don't show privilege warning\n" - " -l --local Only local entries\n" - " -b --this-boot Show data only from current boot\n" - " -D --directory=PATH Show journal files from directory\n" - " -p --priority=RANGE Show only messages within the specified priority range\n\n" + " -h --help Show this help\n" + " --version Show package version\n" + " --no-pager Do not pipe output into a pager\n" + " -a --all Show all fields, including long and unprintable\n" + " -f --follow Follow journal\n" + " -n --lines=INTEGER Journal entries to show\n" + " --no-tail Show all lines, even in follow mode\n" + " -o --output=STRING Change journal output mode (short, short-monotonic,\n" + " verbose, export, json, cat)\n" + " -q --quiet Don't show privilege warning\n" + " -l --local Only local entries\n" + " -b --this-boot Show data only from current boot\n" + " -D --directory=PATH Show journal files from directory\n" + " -p --priority=RANGE Show only messages within the specified priority range\n\n" "Commands:\n" - " --new-id128 Generate a new 128 Bit ID\n" - " --header Show journal header information\n" - " --verify Verify journal file consistency\n" - " --verify-seed=SEED Specify FSPRG seed for verification\n" - " --setup-keys Generate new FSPRG key and seed\n" - " --evolve=TIME How of to evolve FSPRG keys\n", + " --new-id128 Generate a new 128 Bit ID\n" + " --header Show journal header information\n" + " --setup-keys Generate new FSS key pair\n" + " --interval=TIME Time interval for changing the FSS sealing key\n" + " --verify Verify journal file consistency\n" + " --verify-key=KEY Specify FSS verification key\n", program_invocation_short_name); return 0; @@ -109,32 +109,32 @@ static int parse_argv(int argc, char *argv[]) { ARG_NEW_ID128, ARG_HEADER, ARG_SETUP_KEYS, + ARG_INTERVAL, ARG_VERIFY, - ARG_VERIFY_SEED, - ARG_EVOLVE + ARG_VERIFY_KEY }; static const struct option options[] = { - { "help", no_argument, NULL, 'h' }, - { "version" , no_argument, NULL, ARG_VERSION }, - { "no-pager", no_argument, NULL, ARG_NO_PAGER }, - { "follow", no_argument, NULL, 'f' }, - { "output", required_argument, NULL, 'o' }, - { "all", no_argument, NULL, 'a' }, - { "lines", required_argument, NULL, 'n' }, - { "no-tail", no_argument, NULL, ARG_NO_TAIL }, - { "new-id128", no_argument, NULL, ARG_NEW_ID128 }, - { "quiet", no_argument, NULL, 'q' }, - { "local", no_argument, NULL, 'l' }, - { "this-boot", no_argument, NULL, 'b' }, - { "directory", required_argument, NULL, 'D' }, - { "header", no_argument, NULL, ARG_HEADER }, - { "priority", no_argument, NULL, 'p' }, - { "setup-keys", no_argument, NULL, ARG_SETUP_KEYS }, - { "verify", no_argument, NULL, ARG_VERIFY }, - { "verify-seed", required_argument, NULL, ARG_VERIFY_SEED }, - { "evolve", required_argument, NULL, ARG_EVOLVE }, - { NULL, 0, NULL, 0 } + { "help", no_argument, NULL, 'h' }, + { "version" , no_argument, NULL, ARG_VERSION }, + { "no-pager", no_argument, NULL, ARG_NO_PAGER }, + { "follow", no_argument, NULL, 'f' }, + { "output", required_argument, NULL, 'o' }, + { "all", no_argument, NULL, 'a' }, + { "lines", required_argument, NULL, 'n' }, + { "no-tail", no_argument, NULL, ARG_NO_TAIL }, + { "new-id128", no_argument, NULL, ARG_NEW_ID128 }, + { "quiet", no_argument, NULL, 'q' }, + { "local", no_argument, NULL, 'l' }, + { "this-boot", no_argument, NULL, 'b' }, + { "directory", required_argument, NULL, 'D' }, + { "header", no_argument, NULL, ARG_HEADER }, + { "priority", no_argument, NULL, 'p' }, + { "setup-keys", no_argument, NULL, ARG_SETUP_KEYS }, + { "interval", required_argument, NULL, ARG_INTERVAL }, + { "verify", no_argument, NULL, ARG_VERIFY }, + { "verify-key", required_argument, NULL, ARG_VERIFY_KEY }, + { NULL, 0, NULL, 0 } }; int c, r; @@ -221,15 +221,15 @@ static int parse_argv(int argc, char *argv[]) { arg_action = ACTION_VERIFY; break; - case ARG_VERIFY_SEED: + case ARG_VERIFY_KEY: arg_action = ACTION_VERIFY; - arg_verify_seed = optarg; + arg_verify_key = optarg; break; - case ARG_EVOLVE: - r = parse_usec(optarg, &arg_evolve); - if (r < 0 || arg_evolve <= 0) { - log_error("Failed to parse evolve interval: %s", optarg); + case ARG_INTERVAL: + r = parse_usec(optarg, &arg_interval); + if (r < 0 || arg_interval <= 0) { + log_error("Failed to parse sealing key change interval: %s", optarg); return -EINVAL; } break; @@ -456,7 +456,7 @@ static int setup_keys(void) { int fd = -1, r; sd_id128_t machine, boot; char *p = NULL, *k = NULL; - struct FSPRGHeader h; + struct FSSHeader h; uint64_t n; r = sd_id128_get_machine(&machine); @@ -471,7 +471,7 @@ static int setup_keys(void) { return r; } - if (asprintf(&p, "/var/log/journal/" SD_ID128_FORMAT_STR "/fsprg", + if (asprintf(&p, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss", SD_ID128_FORMAT_VAL(machine)) < 0) return log_oom(); @@ -481,7 +481,7 @@ static int setup_keys(void) { goto finish; } - if (asprintf(&k, "/var/log/journal/" SD_ID128_FORMAT_STR "/fsprg.tmp.XXXXXX", + if (asprintf(&k, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss.tmp.XXXXXX", SD_ID128_FORMAT_VAL(machine)) < 0) { r = log_oom(); goto finish; @@ -514,11 +514,13 @@ static int setup_keys(void) { log_info("Generating key pair..."); FSPRG_GenMK(NULL, mpk, seed, seed_size, FSPRG_RECOMMENDED_SECPAR); - log_info("Generating evolving key..."); + log_info("Generating sealing key..."); FSPRG_GenState0(state, mpk, seed, seed_size); + assert(arg_interval > 0); + n = now(CLOCK_REALTIME); - n /= arg_evolve; + n /= arg_interval; close_nointr_nofail(fd); fd = mkostemp(k, O_WRONLY|O_CLOEXEC|O_NOCTTY); @@ -533,10 +535,10 @@ static int setup_keys(void) { h.machine_id = machine; h.boot_id = boot; h.header_size = htole64(sizeof(h)); - h.fsprg_start_usec = htole64(n * arg_evolve); - h.fsprg_interval_usec = htole64(arg_evolve); - h.secpar = htole16(FSPRG_RECOMMENDED_SECPAR); - h.state_size = htole64(state_size); + h.start_usec = htole64(n * arg_interval); + h.interval_usec = htole64(arg_interval); + h.fsprg_secpar = htole16(FSPRG_RECOMMENDED_SECPAR); + h.fsprg_state_size = htole64(state_size); l = loop_write(fd, &h, sizeof(h), false); if (l < 0 || (size_t) l != sizeof(h)) { @@ -561,14 +563,13 @@ static int setup_keys(void) { if (isatty(STDOUT_FILENO)) { fprintf(stderr, "\n" - "The new key pair has been generated. The evolving key has been written to the\n" - "following file. It will be used to protect local journal files. This file\n" - "should be kept secret. It should not be used on multiple hosts.\n" + "The new key pair has been generated. The " ANSI_HIGHLIGHT_ON "secret sealing key" ANSI_HIGHLIGHT_OFF " has been written to\n" + "the following local file. It should not be used on multiple hosts.\n" "\n" "\t%s\n" "\n" - "Please write down the following " ANSI_HIGHLIGHT_ON "secret" ANSI_HIGHLIGHT_OFF " seed value. It should not be stored\n" - "locally on disk, and may be used to verify journal files from this host.\n" + "Please write down the following " ANSI_HIGHLIGHT_ON "secret verification key" ANSI_HIGHLIGHT_OFF ". It should be stored\n" + "at a safe location and should not be saved locally on disk.\n" "\n\t" ANSI_HIGHLIGHT_RED_ON, p); fflush(stderr); } @@ -578,10 +579,16 @@ static int setup_keys(void) { printf("%02x", ((uint8_t*) seed)[i]); } - printf("/%llx-%llx\n", (unsigned long long) n, (unsigned long long) arg_evolve); + printf("/%llx-%llx\n", (unsigned long long) n, (unsigned long long) arg_interval); + + if (isatty(STDOUT_FILENO)) { + char tsb[FORMAT_TIMESPAN_MAX]; - if (isatty(STDOUT_FILENO)) - fputs(ANSI_HIGHLIGHT_OFF "\n", stderr); + fprintf(stderr, + ANSI_HIGHLIGHT_OFF "\n" + "The sealing key is automatically changed every %s.\n", + format_timespan(tsb, sizeof(tsb), arg_interval)); + } r = 0; @@ -613,13 +620,13 @@ static int verify(sd_journal *j) { int k; #ifdef HAVE_GCRYPT - if (!arg_verify_seed && journal_file_fsprg_enabled(f)) - log_warning("Journal file %s has authentication enabled but verification seed has not been passed using --verify-seed=.", f->path); + if (!arg_verify_key && journal_file_fss_enabled(f)) + log_warning("Journal file %s has sealing enabled but verification key has not been passed using --verify-key=.", f->path); #endif - k = journal_file_verify(f, arg_verify_seed); + k = journal_file_verify(f, arg_verify_key); if (k == -EINVAL) { - /* If the seed was invalid give up right-away. */ + /* If the key was invalid give up right-away. */ return k; } else if (k < 0) { log_warning("FAIL: %s (%s)", f->path, strerror(-k)); -- cgit v1.2.3-54-g00ecf From feb12d3ed2c7f9132c64773c7c41b9e3a608a814 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 20 Aug 2012 16:51:46 +0200 Subject: journal: make libgcrypt dependency optional --- Makefile.am | 4 +-- README | 1 + TODO | 6 ---- configure.ac | 2 +- src/core/build.h | 20 ++++++++++- src/journal/journal-authenticate.c | 57 ++++++++++++++++++++++++++++-- src/journal/journal-authenticate.h | 2 +- src/journal/journal-file.c | 18 ++++++++++ src/journal/journal-verify.c | 71 ++++++-------------------------------- src/journal/journalctl.c | 30 +++++++++++----- src/journal/test-journal-verify.c | 7 ++-- src/journal/test-journal.c | 2 ++ 12 files changed, 134 insertions(+), 86 deletions(-) (limited to 'src/journal/journal-authenticate.h') diff --git a/Makefile.am b/Makefile.am index 3eeb842afe..166c357db2 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2402,8 +2402,6 @@ libsystemd_journal_la_SOURCES = \ src/journal/journal-vacuum.h \ src/journal/journal-verify.c \ src/journal/journal-verify.h \ - src/journal/journal-authenticate.c \ - src/journal/journal-authenticate.h \ src/journal/lookup3.c \ src/journal/lookup3.h \ src/journal/journal-send.c \ @@ -2455,6 +2453,8 @@ endif if HAVE_GCRYPT libsystemd_journal_la_SOURCES += \ + src/journal/journal-authenticate.c \ + src/journal/journal-authenticate.h \ src/journal/fsprg.c \ src/journal/fsprg.h diff --git a/README b/README index a5d569028d..334c597213 100644 --- a/README +++ b/README @@ -42,6 +42,7 @@ REQUIREMENTS: libcap PAM >= 1.1.2 (optional) libcryptsetup (optional) + libgcrypt (optional) libaudit (optional) libacl (optional) libselinux (optional) diff --git a/TODO b/TODO index 875a3db4d6..e16db6fa4d 100644 --- a/TODO +++ b/TODO @@ -254,8 +254,6 @@ Features: * cleanup syslog 'priority' vs. 'level' wording -* journal: if mmap() fails for mapping window try to unmap a a few older maps - * dbus upstream still refers to dbus.target and shouldn't * when a service has the same env var set twice we actually store it twice and return that in systemctl show -p... We should only show the last setting @@ -300,8 +298,6 @@ Features: * journal: message catalog -* journal: forward-secure signatures - * document the exit codes when services fail before they are exec()ed * systemctl journal command @@ -503,6 +499,4 @@ Scheduled for removal (or fixing): * xxxOverridable dependencies -* journald.conf: ImportKernel= - * prefdm.service diff --git a/configure.ac b/configure.ac index c1e88daa3f..3df43b91fd 100644 --- a/configure.ac +++ b/configure.ac @@ -302,7 +302,7 @@ AC_SUBST(ACL_LIBS) AM_CONDITIONAL([HAVE_ACL], [test "x$have_acl" != xno]) # ------------------------------------------------------------------------------ -AC_ARG_ENABLE([], +AC_ARG_ENABLE([gcrypt], AS_HELP_STRING([--disable-gcrypt],[Disable optional GCRYPT support]), [case "${enableval}" in yes) have_gcrypt=yes ;; diff --git a/src/core/build.h b/src/core/build.h index 0b38050bd4..4513a0bad7 100644 --- a/src/core/build.h +++ b/src/core/build.h @@ -63,4 +63,22 @@ #define _LIBCRYPTSETUP_FEATURE_ "-LIBCRYPTSETUP" #endif -#define SYSTEMD_FEATURES _PAM_FEATURE_ " " _LIBWRAP_FEATURE_ " " _AUDIT_FEATURE_ " " _SELINUX_FEATURE_ " " _IMA_FEATURE_ " " _SYSVINIT_FEATURE_ " " _LIBCRYPTSETUP_FEATURE_ +#ifdef HAVE_GCRYPT +#define _GCRYPT_FEATURE_ "+GCRYPT" +#else +#define _GCRYPT_FEATURE_ "-GCRYPT" +#endif + +#ifdef HAVE_ACL +#define _ACL_FEATURE_ "+ACL" +#else +#define _ACL_FEATURE_ "-ACL" +#endif + +#ifdef HAVE_XZ +#define _XZ_FEATURE_ "+XZ" +#else +#define _XZ_FEATURE_ "-XZ" +#endif + +#define SYSTEMD_FEATURES _PAM_FEATURE_ " " _LIBWRAP_FEATURE_ " " _AUDIT_FEATURE_ " " _SELINUX_FEATURE_ " " _IMA_FEATURE_ " " _SYSVINIT_FEATURE_ " " _LIBCRYPTSETUP_FEATURE_ " " _GCRYPT_FEATURE_ " " _ACL_FEATURE_ " " _XZ_FEATURE_ diff --git a/src/journal/journal-authenticate.c b/src/journal/journal-authenticate.c index ddcf856aec..93cc9d94a1 100644 --- a/src/journal/journal-authenticate.c +++ b/src/journal/journal-authenticate.c @@ -461,8 +461,59 @@ int journal_file_append_first_tag(JournalFile *f) { return 0; } -bool journal_file_fss_enabled(JournalFile *f) { - assert(f); - return JOURNAL_HEADER_SEALED(f->header); +int journal_file_parse_verification_key(JournalFile *f, const char *key) { + uint8_t *seed; + size_t seed_size, c; + const char *k; + int r; + unsigned long long start, interval; + + seed_size = FSPRG_RECOMMENDED_SEEDLEN; + seed = malloc(seed_size); + if (!seed) + return -ENOMEM; + + k = key; + for (c = 0; c < seed_size; c++) { + int x, y; + + while (*k == '-') + k++; + + x = unhexchar(*k); + if (x < 0) { + free(seed); + return -EINVAL; + } + k++; + y = unhexchar(*k); + if (y < 0) { + free(seed); + return -EINVAL; + } + k++; + + seed[c] = (uint8_t) (x * 16 + y); + } + + if (*k != '/') { + free(seed); + return -EINVAL; + } + k++; + + r = sscanf(k, "%llx-%llx", &start, &interval); + if (r != 2) { + free(seed); + return -EINVAL; + } + + f->fsprg_seed = seed; + f->fsprg_seed_size = seed_size; + + f->fss_start_usec = start * interval; + f->fss_interval_usec = interval; + + return 0; } diff --git a/src/journal/journal-authenticate.h b/src/journal/journal-authenticate.h index 4f4f45b114..447c7b4657 100644 --- a/src/journal/journal-authenticate.h +++ b/src/journal/journal-authenticate.h @@ -36,7 +36,7 @@ int journal_file_hmac_put_header(JournalFile *f); int journal_file_hmac_put_object(JournalFile *f, int type, uint64_t p); int journal_file_fss_load(JournalFile *f); -bool journal_file_fss_enabled(JournalFile *f); +int journal_file_parse_verification_key(JournalFile *f, const char *key); int journal_file_fsprg_evolve(JournalFile *f, uint64_t realtime); int journal_file_fsprg_seek(JournalFile *f, uint64_t epoch); diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c index 760efaebbb..f01f12496c 100644 --- a/src/journal/journal-file.c +++ b/src/journal/journal-file.c @@ -64,9 +64,11 @@ void journal_file_close(JournalFile *f) { assert(f); +#ifdef HAVE_GCRYPT /* Write the final tag */ if (f->seal && f->writable) journal_file_append_tag(f); +#endif /* Sync everything to disk, before we mark the file offline */ if (f->mmap && f->fd >= 0) @@ -764,9 +766,11 @@ static int journal_file_append_data( if (r < 0) return r; +#ifdef HAVE_GCRYPT r = journal_file_hmac_put_object(f, OBJECT_DATA, p); if (r < 0) return r; +#endif /* The linking might have altered the window, so let's * refresh our pointer */ @@ -852,9 +856,11 @@ static int link_entry_into_array(JournalFile *f, if (r < 0) return r; +#ifdef HAVE_GCRYPT r = journal_file_hmac_put_object(f, OBJECT_ENTRY_ARRAY, q); if (r < 0) return r; +#endif o->entry_array.items[i] = htole64(p); @@ -996,9 +1002,11 @@ static int journal_file_append_entry_internal( o->entry.xor_hash = htole64(xor_hash); o->entry.boot_id = f->header->boot_id; +#ifdef HAVE_GCRYPT r = journal_file_hmac_put_object(f, OBJECT_ENTRY, np); if (r < 0) return r; +#endif r = journal_file_link_entry(f, o, np); if (r < 0) @@ -1049,9 +1057,11 @@ int journal_file_append_entry(JournalFile *f, const dual_timestamp *ts, const st ts->monotonic < le64toh(f->header->tail_entry_monotonic)) return -EINVAL; +#ifdef HAVE_GCRYPT r = journal_file_maybe_append_tag(f, ts->realtime); if (r < 0) return r; +#endif /* alloca() can't take 0, hence let's allocate at least one */ items = alloca(sizeof(EntryItem) * MAX(1, n_iovec)); @@ -2030,11 +2040,13 @@ int journal_file_open( if (f->last_stat.st_size == 0 && f->writable) { newly_created = true; +#ifdef HAVE_GCRYPT /* Try to load the FSPRG state, and if we can't, then * just don't do sealing */ r = journal_file_fss_load(f); if (r < 0) f->seal = false; +#endif r = journal_file_init_header(f, template); if (r < 0) @@ -2064,11 +2076,13 @@ int journal_file_open( goto fail; } +#ifdef HAVE_GCRYPT if (!newly_created && f->writable) { r = journal_file_fss_load(f); if (r < 0) goto fail; } +#endif if (f->writable) { if (metrics) { @@ -2082,9 +2096,11 @@ int journal_file_open( goto fail; } +#ifdef HAVE_GCRYPT r = journal_file_hmac_setup(f); if (r < 0) goto fail; +#endif if (newly_created) { r = journal_file_setup_field_hash_table(f); @@ -2095,9 +2111,11 @@ int journal_file_open( if (r < 0) goto fail; +#ifdef HAVE_GCRYPT r = journal_file_append_first_tag(f); if (r < 0) goto fail; +#endif } r = journal_file_map_field_hash_table(f); diff --git a/src/journal/journal-verify.c b/src/journal/journal-verify.c index 6afeab9a80..a76384bdb2 100644 --- a/src/journal/journal-verify.c +++ b/src/journal/journal-verify.c @@ -22,6 +22,7 @@ #include #include #include +#include #include "util.h" #include "macro.h" @@ -37,7 +38,6 @@ * * - evolve key even if nothing happened in regular intervals * - * - Allow building without libgcrypt * - check with sparse * - 64bit conversions * @@ -645,62 +645,6 @@ static int verify_entry_array( return 0; } -static int journal_file_parse_verification_key(JournalFile *f, const char *key) { - uint8_t *seed; - size_t seed_size, c; - const char *k; - int r; - unsigned long long start, interval; - - seed_size = FSPRG_RECOMMENDED_SEEDLEN; - seed = malloc(seed_size); - if (!seed) - return -ENOMEM; - - k = key; - for (c = 0; c < seed_size; c++) { - int x, y; - - while (*k == '-') - k++; - - x = unhexchar(*k); - if (x < 0) { - free(seed); - return -EINVAL; - } - k++; - y = unhexchar(*k); - if (y < 0) { - free(seed); - return -EINVAL; - } - k++; - - seed[c] = (uint8_t) (x * 16 + y); - } - - if (*k != '/') { - free(seed); - return -EINVAL; - } - k++; - - r = sscanf(k, "%llx-%llx", &start, &interval); - if (r != 2) { - free(seed); - return -EINVAL; - } - - f->fsprg_seed = seed; - f->fsprg_seed_size = seed_size; - - f->fss_start_usec = start * interval; - f->fss_interval_usec = interval; - - return 0; -} - int journal_file_verify( JournalFile *f, const char *key, @@ -724,11 +668,15 @@ int journal_file_verify( assert(f); if (key) { +#ifdef HAVE_GCRYPT r = journal_file_parse_verification_key(f, key); if (r < 0) { log_error("Failed to parse seed."); return r; } +#else + return -ENOTSUP; +#endif } else if (f->seal) return -ENOKEY; @@ -936,9 +884,7 @@ int journal_file_verify( n_entry_arrays++; break; - case OBJECT_TAG: { - uint64_t q, rt; - + case OBJECT_TAG: if (!JOURNAL_HEADER_SEALED(f->header)) { log_error("Tag object in file without sealing at %llu", (unsigned long long) p); r = -EBADMSG; @@ -957,7 +903,10 @@ int journal_file_verify( goto fail; } +#ifdef HAVE_GCRYPT if (f->seal) { + uint64_t q, rt; + log_debug("Checking tag %llu..", (unsigned long long) le64toh(o->tag.seqnum)); rt = f->fss_start_usec + o->tag.epoch * f->fss_interval_usec; @@ -1014,13 +963,13 @@ int journal_file_verify( last_tag_realtime = rt; last_sealed_realtime = entry_realtime; } +#endif last_tag = p + ALIGN64(le64toh(o->object.size)); last_epoch = le64toh(o->tag.epoch); n_tags ++; break; - } default: n_weird ++; diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c index e61ddf6d92..551cb311b5 100644 --- a/src/journal/journalctl.c +++ b/src/journal/journalctl.c @@ -62,7 +62,9 @@ static bool arg_this_boot = false; static const char *arg_directory = NULL; static int arg_priorities = 0xFF; static const char *arg_verify_key = NULL; +#ifdef HAVE_GCRYPT static usec_t arg_interval = DEFAULT_FSS_INTERVAL_USEC; +#endif static enum { ACTION_SHOW, @@ -93,11 +95,13 @@ static int help(void) { "Commands:\n" " --new-id128 Generate a new 128 Bit ID\n" " --header Show journal header information\n" +#ifdef HAVE_GCRYPT " --setup-keys Generate new FSS key pair\n" " --interval=TIME Time interval for changing the FSS sealing key\n" " --verify Verify journal file consistency\n" - " --verify-key=KEY Specify FSS verification key\n", - program_invocation_short_name); + " --verify-key=KEY Specify FSS verification key\n" +#endif + , program_invocation_short_name); return 0; } @@ -215,13 +219,15 @@ static int parse_argv(int argc, char *argv[]) { arg_action = ACTION_PRINT_HEADER; break; + case ARG_VERIFY: + arg_action = ACTION_VERIFY; + break; + +#ifdef HAVE_GCRYPT case ARG_SETUP_KEYS: arg_action = ACTION_SETUP_KEYS; break; - case ARG_VERIFY: - arg_action = ACTION_VERIFY; - break; case ARG_VERIFY_KEY: arg_action = ACTION_VERIFY; @@ -235,6 +241,13 @@ static int parse_argv(int argc, char *argv[]) { return -EINVAL; } break; +#else + case ARG_SETUP_KEYS: + case ARG_VERIFY_KEY: + case ARG_INTERVAL: + log_error("Forward-secure sealing not available."); + return -ENOTSUP; +#endif case 'p': { const char *dots; @@ -617,7 +630,8 @@ finish: return r; #else - log_error("Forward-secure journal verification not available."); + log_error("Forward-secure sealing not available."); + return -ENOTSUP; #endif } @@ -633,7 +647,7 @@ static int verify(sd_journal *j) { usec_t from, to, total; #ifdef HAVE_GCRYPT - if (!arg_verify_key && journal_file_fss_enabled(f)) + if (!arg_verify_key && JOURNAL_HEADER_SEALED(f->header)) log_warning("Journal file %s has sealing enabled but verification key has not been passed using --verify-key=.", f->path); #endif @@ -648,7 +662,7 @@ static int verify(sd_journal *j) { char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX], c[FORMAT_TIMESPAN_MAX]; log_info("PASS: %s", f->path); - if (arg_verify_key && journal_file_fss_enabled(f)) + if (arg_verify_key && JOURNAL_HEADER_SEALED(f->header)) log_info("=> Validated from %s to %s, %s missing", format_timestamp(a, sizeof(a), from), format_timestamp(b, sizeof(b), to), diff --git a/src/journal/test-journal-verify.c b/src/journal/test-journal-verify.c index ed6e21dc0c..b6677215c0 100644 --- a/src/journal/test-journal-verify.c +++ b/src/journal/test-journal-verify.c @@ -55,7 +55,7 @@ static int raw_verify(const char *fn, const char *verification_key) { JournalFile *f; int r; - r = journal_file_open(fn, O_RDONLY, 0666, true, true, NULL, NULL, NULL, &f); + r = journal_file_open(fn, O_RDONLY, 0666, true, !!verification_key, NULL, NULL, NULL, &f); if (r < 0) return r; @@ -107,18 +107,19 @@ int main(int argc, char *argv[]) { log_info("Verifying..."); - assert_se(journal_file_open("test.journal", O_RDONLY, 0666, true, true, NULL, NULL, NULL, &f) == 0); + assert_se(journal_file_open("test.journal", O_RDONLY, 0666, true, !!verification_key, NULL, NULL, NULL, &f) == 0); /* journal_file_print_header(f); */ journal_file_dump(f); assert_se(journal_file_verify(f, verification_key, &from, &to, &total, true) >= 0); - if (verification_key && journal_file_fss_enabled(f)) { + if (verification_key && JOURNAL_HEADER_SEALED(f->header)) { log_info("=> Validated from %s to %s, %s missing", format_timestamp(a, sizeof(a), from), format_timestamp(b, sizeof(b), to), format_timespan(c, sizeof(c), total > to ? total - to : 0)); } + journal_file_close(f); if (verification_key) { diff --git a/src/journal/test-journal.c b/src/journal/test-journal.c index 05bb2ea8ed..2273500100 100644 --- a/src/journal/test-journal.c +++ b/src/journal/test-journal.c @@ -59,7 +59,9 @@ int main(int argc, char *argv[]) { iovec.iov_len = strlen(test); assert_se(journal_file_append_entry(f, &ts, &iovec, 1, NULL, NULL, NULL) == 0); +#ifdef HAVE_GCRYPT journal_file_append_tag(f); +#endif journal_file_dump(f); assert(journal_file_next_entry(f, NULL, 0, DIRECTION_DOWN, &o, &p) == 1); -- cgit v1.2.3-54-g00ecf From 89fef99014662a5a63e7deaedd6292b7fb4ab2f8 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 21 Aug 2012 01:29:17 +0200 Subject: journal: automatically evolve FSS key even when nothing is logged --- src/journal/journal-authenticate.c | 19 ++++++++++++++++++ src/journal/journal-authenticate.h | 2 ++ src/journal/journal-verify.c | 8 -------- src/journal/journalctl.c | 1 + src/journal/journald.c | 41 ++++++++++++++++++++++++++++++-------- 5 files changed, 55 insertions(+), 16 deletions(-) (limited to 'src/journal/journal-authenticate.h') diff --git a/src/journal/journal-authenticate.c b/src/journal/journal-authenticate.c index 435481000d..fd81797cf9 100644 --- a/src/journal/journal-authenticate.c +++ b/src/journal/journal-authenticate.c @@ -211,6 +211,9 @@ int journal_file_maybe_append_tag(JournalFile *f, uint64_t realtime) { if (!f->seal) return 0; + if (realtime <= 0) + realtime = now(CLOCK_MONOTONIC); + r = journal_file_fsprg_need_evolve(f, realtime); if (r <= 0) return 0; @@ -517,3 +520,19 @@ int journal_file_parse_verification_key(JournalFile *f, const char *key) { return 0; } + +bool journal_file_next_evolve_usec(JournalFile *f, usec_t *u) { + uint64_t epoch; + + assert(f); + assert(u); + + if (!f->seal) + return false; + + epoch = FSPRG_GetEpoch(f->fsprg_state); + + *u = (usec_t) (f->fss_start_usec + f->fss_interval_usec * epoch + f->fss_interval_usec); + + return true; +} diff --git a/src/journal/journal-authenticate.h b/src/journal/journal-authenticate.h index 447c7b4657..3586464d1e 100644 --- a/src/journal/journal-authenticate.h +++ b/src/journal/journal-authenticate.h @@ -40,3 +40,5 @@ int journal_file_parse_verification_key(JournalFile *f, const char *key); int journal_file_fsprg_evolve(JournalFile *f, uint64_t realtime); int journal_file_fsprg_seek(JournalFile *f, uint64_t epoch); + +bool journal_file_next_evolve_usec(JournalFile *f, usec_t *u); diff --git a/src/journal/journal-verify.c b/src/journal/journal-verify.c index 29a9229e53..8604b6e7cb 100644 --- a/src/journal/journal-verify.c +++ b/src/journal/journal-verify.c @@ -34,14 +34,6 @@ #include "compress.h" #include "fsprg.h" -/* FIXME: - * - * - evolve key even if nothing happened in regular intervals - * - * - check with sparse - * - * */ - static int journal_file_object_verify(JournalFile *f, Object *o) { uint64_t i; diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c index 1dee74a935..0bbf4a045d 100644 --- a/src/journal/journalctl.c +++ b/src/journal/journalctl.c @@ -233,6 +233,7 @@ static int parse_argv(int argc, char *argv[]) { case ARG_VERIFY_KEY: arg_action = ACTION_VERIFY; arg_verify_key = optarg; + arg_local = true; break; case ARG_INTERVAL: diff --git a/src/journal/journald.c b/src/journal/journald.c index 7b3b6471de..f2dd4050b6 100644 --- a/src/journal/journald.c +++ b/src/journal/journald.c @@ -48,6 +48,7 @@ #include "journal-rate-limit.h" #include "journal-internal.h" #include "journal-vacuum.h" +#include "journal-authenticate.h" #include "conf-parser.h" #include "journald.h" #include "virt.h" @@ -2969,8 +2970,26 @@ int main(int argc, char *argv[]) { for (;;) { struct epoll_event event; + int t; - r = epoll_wait(server.epoll_fd, &event, 1, -1); +#ifdef HAVE_GCRYPT + usec_t u; + + if (server.system_journal && + journal_file_next_evolve_usec(server.system_journal, &u)) { + usec_t n; + + n = now(CLOCK_MONOTONIC); + + if (n >= u) + t = 0; + else + t = (int) ((u - n + USEC_PER_MSEC - 1) / USEC_PER_MSEC); + } else +#endif + t = -1; + + r = epoll_wait(server.epoll_fd, &event, 1, t); if (r < 0) { if (errno == EINTR) @@ -2979,14 +2998,20 @@ int main(int argc, char *argv[]) { log_error("epoll_wait() failed: %m"); r = -errno; goto finish; - } else if (r == 0) - break; + } - r = process_event(&server, &event); - if (r < 0) - goto finish; - else if (r == 0) - break; + if (r > 0) { + r = process_event(&server, &event); + if (r < 0) + goto finish; + else if (r == 0) + break; + } + +#ifdef HAVE_GCRYPT + if (server.system_journal) + journal_file_maybe_append_tag(server.system_journal, 0); +#endif } log_debug("systemd-journald stopped as pid %lu", (unsigned long) getpid()); -- cgit v1.2.3-54-g00ecf From 5996c7c295e073ce21d41305169132c8aa993ad0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 13 Sep 2012 17:06:04 +0200 Subject: journald: don't reposition window if we don't have to --- src/journal/journal-authenticate.c | 20 ++++++++++++-------- src/journal/journal-authenticate.h | 2 +- src/journal/journal-file.c | 16 ++++++++-------- src/journal/journal-verify.c | 2 +- 4 files changed, 22 insertions(+), 18 deletions(-) (limited to 'src/journal/journal-authenticate.h') diff --git a/src/journal/journal-authenticate.c b/src/journal/journal-authenticate.c index 593bf7eb2a..674f81218f 100644 --- a/src/journal/journal-authenticate.c +++ b/src/journal/journal-authenticate.c @@ -66,7 +66,7 @@ int journal_file_append_tag(JournalFile *f) { /* 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, p); + r = journal_file_hmac_put_object(f, OBJECT_TAG, o, p); if (r < 0) return r; @@ -229,9 +229,8 @@ int journal_file_maybe_append_tag(JournalFile *f, uint64_t realtime) { return 0; } -int journal_file_hmac_put_object(JournalFile *f, int type, uint64_t p) { +int journal_file_hmac_put_object(JournalFile *f, int type, Object *o, uint64_t p) { int r; - Object *o; assert(f); @@ -242,9 +241,14 @@ int journal_file_hmac_put_object(JournalFile *f, int type, uint64_t p) { if (r < 0) return r; - r = journal_file_move_to_object(f, type, p, &o); - if (r < 0) - return r; + if (!o) { + r = journal_file_move_to_object(f, type, p, &o); + if (r < 0) + return r; + } else { + if (type >= 0 && o->object.type != type) + return -EBADMSG; + } gcry_md_write(f->hmac, o, offsetof(ObjectHeader, payload)); @@ -460,7 +464,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, p); + r = journal_file_hmac_put_object(f, OBJECT_FIELD_HASH_TABLE, NULL, p); if (r < 0) return r; @@ -469,7 +473,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_DATA_HASH_TABLE, p); + r = journal_file_hmac_put_object(f, OBJECT_DATA_HASH_TABLE, NULL, p); if (r < 0) return r; diff --git a/src/journal/journal-authenticate.h b/src/journal/journal-authenticate.h index 3586464d1e..0aaf836721 100644 --- a/src/journal/journal-authenticate.h +++ b/src/journal/journal-authenticate.h @@ -33,7 +33,7 @@ int journal_file_append_first_tag(JournalFile *f); int journal_file_hmac_setup(JournalFile *f); int journal_file_hmac_start(JournalFile *f); int journal_file_hmac_put_header(JournalFile *f); -int journal_file_hmac_put_object(JournalFile *f, int type, uint64_t p); +int journal_file_hmac_put_object(JournalFile *f, int type, Object *o, uint64_t p); int journal_file_fss_load(JournalFile *f); int journal_file_parse_verification_key(JournalFile *f, const char *key); diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c index 8016852b91..e55162ab2c 100644 --- a/src/journal/journal-file.c +++ b/src/journal/journal-file.c @@ -775,18 +775,18 @@ static int journal_file_append_data( if (r < 0) return r; -#ifdef HAVE_GCRYPT - r = journal_file_hmac_put_object(f, OBJECT_DATA, p); - if (r < 0) - return r; -#endif - /* The linking might have altered the window, so let's * refresh our pointer */ r = journal_file_move_to_object(f, OBJECT_DATA, p, &o); if (r < 0) return r; +#ifdef HAVE_GCRYPT + r = journal_file_hmac_put_object(f, OBJECT_DATA, o, p); + if (r < 0) + return r; +#endif + if (ret) *ret = o; @@ -866,7 +866,7 @@ static int link_entry_into_array(JournalFile *f, return r; #ifdef HAVE_GCRYPT - r = journal_file_hmac_put_object(f, OBJECT_ENTRY_ARRAY, q); + r = journal_file_hmac_put_object(f, OBJECT_ENTRY_ARRAY, o, q); if (r < 0) return r; #endif @@ -1012,7 +1012,7 @@ static int journal_file_append_entry_internal( o->entry.boot_id = f->header->boot_id; #ifdef HAVE_GCRYPT - r = journal_file_hmac_put_object(f, OBJECT_ENTRY, np); + r = journal_file_hmac_put_object(f, OBJECT_ENTRY, o, np); if (r < 0) return r; #endif diff --git a/src/journal/journal-verify.c b/src/journal/journal-verify.c index 5d134bdb97..629b2389bc 100644 --- a/src/journal/journal-verify.c +++ b/src/journal/journal-verify.c @@ -959,7 +959,7 @@ int journal_file_verify( if (r < 0) goto fail; - r = journal_file_hmac_put_object(f, -1, q); + r = journal_file_hmac_put_object(f, -1, o, q); if (r < 0) goto fail; -- cgit v1.2.3-54-g00ecf