X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fjournal%2Fjournal-authenticate.c;h=93cc9d94a1804e9fca421b78f23cf1e20a1efab5;hp=5a0314b4f6538ab50b4c61ca4d919c0d0320b5dc;hb=feb12d3ed2c7f9132c64773c7c41b9e3a608a814;hpb=4da416aa20b956571d74720bc91222881443e24b diff --git a/src/journal/journal-authenticate.c b/src/journal/journal-authenticate.c index 5a0314b4f..93cc9d94a 100644 --- a/src/journal/journal-authenticate.c +++ b/src/journal/journal-authenticate.c @@ -27,22 +27,6 @@ #include "journal-authenticate.h" #include "fsprg.h" -static void *fsprg_state(JournalFile *f) { - uint64_t a, b; - assert(f); - - if (!f->authenticate) - return NULL; - - a = le64toh(f->fsprg_header->header_size); - b = le64toh(f->fsprg_header->state_size); - - if (a + b > f->fsprg_size) - return NULL; - - return (uint8_t*) f->fsprg_header + a; -} - static uint64_t journal_file_tag_seqnum(JournalFile *f) { uint64_t r; @@ -61,14 +45,12 @@ int journal_file_append_tag(JournalFile *f) { assert(f); - if (!f->authenticate) + if (!f->seal) return 0; if (!f->hmac_running) return 0; - log_debug("Writing tag for epoch %llu\n", (unsigned long long) FSPRG_GetEpoch(fsprg_state(f))); - assert(f->hmac); r = journal_file_append_object(f, OBJECT_TAG, sizeof(struct TagObject), &o, &p); @@ -76,6 +58,11 @@ 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)); + + log_debug("Writing tag %llu for epoch %llu\n", + (unsigned long long) le64toh(o->tag.seqnum), + (unsigned long long) 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 */ @@ -90,12 +77,11 @@ 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) + if (!f->seal) return 0; if (f->hmac_running) @@ -103,7 +89,7 @@ static int journal_file_hmac_start(JournalFile *f) { /* Prepare HMAC for next cycle */ gcry_md_reset(f->hmac); - FSPRG_GetKey(fsprg_state(f), key, sizeof(key), 0); + FSPRG_GetKey(f->fsprg_state, key, sizeof(key), 0); gcry_md_setkey(f->hmac, key, sizeof(key)); f->hmac_running = true; @@ -116,55 +102,55 @@ 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 (le64toh(f->fsprg_header->fsprg_start_usec) == 0 || - le64toh(f->fsprg_header->fsprg_interval_usec) == 0) + if (f->fss_start_usec == 0 || + f->fss_interval_usec == 0) return -ENOTSUP; - if (realtime < le64toh(f->fsprg_header->fsprg_start_usec)) + if (realtime < f->fss_start_usec) return -ESTALE; - t = realtime - le64toh(f->fsprg_header->fsprg_start_usec); - t = t / le64toh(f->fsprg_header->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); if (r < 0) return r; - epoch = FSPRG_GetEpoch(fsprg_state(f)); + epoch = FSPRG_GetEpoch(f->fsprg_state); if (epoch > goal) return -ESTALE; 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); if (r < 0) return r; - epoch = FSPRG_GetEpoch(fsprg_state(f)); + epoch = FSPRG_GetEpoch(f->fsprg_state); if (epoch < goal) log_debug("Evolving FSPRG key from epoch %llu to %llu.", (unsigned long long) epoch, (unsigned long long) goal); @@ -174,20 +160,58 @@ static int journal_file_evolve(JournalFile *f, uint64_t realtime) { if (epoch == goal) return 0; - FSPRG_Evolve(fsprg_state(f)); - epoch = FSPRG_GetEpoch(fsprg_state(f)); + FSPRG_Evolve(f->fsprg_state); + epoch = FSPRG_GetEpoch(f->fsprg_state); } } +int journal_file_fsprg_seek(JournalFile *f, uint64_t goal) { + void *msk; + uint64_t epoch; + + assert(f); + + if (!f->seal) + 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; 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; @@ -195,11 +219,7 @@ int journal_file_maybe_append_tag(JournalFile *f, uint64_t realtime) { if (r < 0) return r; - r = journal_file_evolve(f, realtime); - if (r < 0) - return r; - - r = journal_file_hmac_start(f); + r = journal_file_fsprg_evolve(f, realtime); if (r < 0) return r; @@ -212,7 +232,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); @@ -228,7 +248,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; @@ -247,6 +267,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; @@ -260,7 +281,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); @@ -268,36 +289,37 @@ 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; } -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; @@ -313,19 +335,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; } @@ -335,18 +357,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_size = le64toh(m->header_size) + le64toh(m->state_size); - if ((uint64_t) st.st_size < f->fsprg_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; } @@ -356,24 +378,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_header = mmap(NULL, PAGE_ALIGN(f->fsprg_size), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); - if (f->fsprg_header == MAP_FAILED) { - f->fsprg_header = 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->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->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); @@ -382,10 +410,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); @@ -399,7 +427,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..."); @@ -433,8 +461,59 @@ 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); +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; }