X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fjournal%2Fjournal-authenticate.c;h=bd7100a8d5c86aeaebaf3a52c3373d70743679b2;hp=c087ad4c8b5781998c2d2ab9be4ac688d25b39ed;hb=0c24bb2346b6b6232d67aacd5236b56ea4989de4;hpb=14d10188de1fd58e663d73683a400d8d7dc67dba diff --git a/src/journal/journal-authenticate.c b/src/journal/journal-authenticate.c index c087ad4c8..bd7100a8d 100644 --- a/src/journal/journal-authenticate.c +++ b/src/journal/journal-authenticate.c @@ -45,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(f->fsprg_state)); - assert(f->hmac); r = journal_file_append_object(f, OBJECT_TAG, sizeof(struct TagObject), &o, &p); @@ -62,9 +60,13 @@ int journal_file_append_tag(JournalFile *f) { o->tag.seqnum = htole64(journal_file_tag_seqnum(f)); o->tag.epoch = htole64(FSPRG_GetEpoch(f->fsprg_state)); + log_debug("Writing tag %"PRIu64" for epoch %"PRIu64"\n", + le64toh(o->tag.seqnum), + 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 */ - 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; @@ -79,7 +81,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 +102,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 +137,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); @@ -150,7 +152,7 @@ static int journal_file_evolve(JournalFile *f, uint64_t realtime) { 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); + log_debug("Evolving FSPRG key from epoch %"PRIu64" to %"PRIu64".", epoch, goal); for (;;) { if (epoch > goal) @@ -169,7 +171,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); @@ -193,7 +195,7 @@ int journal_file_fsprg_seek(JournalFile *f, uint64_t goal) { return -ENOMEM; } - log_debug("Seeking FSPRG key to %llu.", (unsigned long long) goal); + log_debug("Seeking FSPRG key to %"PRIu64".", goal); msk = alloca(FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR)); FSPRG_GenMK(msk, NULL, f->fsprg_seed, f->fsprg_seed_size, FSPRG_RECOMMENDED_SECPAR); @@ -206,10 +208,13 @@ 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); + if (realtime <= 0) + realtime = now(CLOCK_REALTIME); + + r = journal_file_fsprg_need_evolve(f, realtime); if (r <= 0) return 0; @@ -217,33 +222,33 @@ 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; 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); - if (!f->authenticate) + if (!f->seal) return 0; r = journal_file_hmac_start(f); 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)); @@ -255,6 +260,12 @@ int journal_file_hmac_put_object(JournalFile *f, int type, uint64_t p) { gcry_md_write(f->hmac, o->data.payload, le64toh(o->object.size) - offsetof(DataObject, payload)); break; + case OBJECT_FIELD: + /* Same here */ + gcry_md_write(f->hmac, &o->field.hash, sizeof(o->field.hash)); + gcry_md_write(f->hmac, o->field.payload, le64toh(o->object.size) - offsetof(FieldObject, payload)); + break; + case OBJECT_ENTRY: /* All */ gcry_md_write(f->hmac, &o->entry.seqnum, le64toh(o->object.size) - offsetof(EntryObject, seqnum)); @@ -283,7 +294,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,29 +316,31 @@ 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; fd = open(p, O_RDWR|O_CLOEXEC|O_NOCTTY, 0600); if (fd < 0) { - log_error("Failed to open %s: %m", p); + if (errno != ENOENT) + log_error("Failed to open %s: %m", p); + r = -errno; goto finish; } @@ -337,19 +350,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 +372,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(le16toh(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 +393,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,12 +425,26 @@ finish: return r; } -int journal_file_setup_hmac(JournalFile *f) { +static void initialize_libgcrypt(void) { + const char *p; + + if (gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P)) + return; + + p = gcry_check_version("1.4.5"); + assert(p); + + gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0); +} + +int journal_file_hmac_setup(JournalFile *f) { gcry_error_t e; - if (!f->authenticate) + if (!f->seal) return 0; + initialize_libgcrypt(); + e = gcry_md_open(&f->hmac, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC); if (e != 0) return -ENOTSUP; @@ -429,7 +456,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..."); @@ -443,7 +470,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; @@ -452,7 +479,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; @@ -463,8 +490,74 @@ int journal_file_append_first_tag(JournalFile *f) { return 0; } -bool journal_file_fsprg_enabled(JournalFile *f) { +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; +} + +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 !!(le32toh(f->header->compatible_flags) & HEADER_COMPATIBLE_AUTHENTICATED); + return true; }