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.
This commit is contained in:
Lennart Poettering 2012-08-17 00:45:18 +02:00
parent 14d10188de
commit baed47c3c2
7 changed files with 178 additions and 170 deletions

View File

@ -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);
}

View File

@ -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);

View File

@ -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;
};

View File

@ -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);
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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))
fputs(ANSI_HIGHLIGHT_OFF "\n", stderr);
if (isatty(STDOUT_FILENO)) {
char tsb[FORMAT_TIMESPAN_MAX];
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));