chiark / gitweb /
journal: add FSPRG journal authentication
[elogind.git] / src / journal / journal-authenticate.c
index 5a0314b4f6538ab50b4c61ca4d919c0d0320b5dc..c087ad4c8b5781998c2d2ab9be4ac688d25b39ed 100644 (file)
 #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;
 
@@ -67,7 +51,7 @@ int journal_file_append_tag(JournalFile *f) {
         if (!f->hmac_running)
                 return 0;
 
-        log_debug("Writing tag for epoch %llu\n", (unsigned long long) FSPRG_GetEpoch(fsprg_state(f)));
+        log_debug("Writing tag for epoch %llu\n", (unsigned long long) FSPRG_GetEpoch(f->fsprg_state));
 
         assert(f->hmac);
 
@@ -76,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 */
@@ -90,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)
@@ -103,7 +87,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;
@@ -118,15 +102,15 @@ static int journal_file_get_epoch(JournalFile *f, uint64_t realtime, uint64_t *e
         assert(epoch);
         assert(f->authenticate);
 
-        if (le64toh(f->fsprg_header->fsprg_start_usec) == 0 ||
-            le64toh(f->fsprg_header->fsprg_interval_usec) == 0)
+        if (f->fsprg_start_usec == 0 ||
+            f->fsprg_interval_usec == 0)
                 return -ENOTSUP;
 
-        if (realtime < le64toh(f->fsprg_header->fsprg_start_usec))
+        if (realtime < f->fsprg_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->fsprg_start_usec;
+        t = t / f->fsprg_interval_usec;
 
         *epoch = t;
         return 0;
@@ -144,7 +128,7 @@ static int journal_file_need_evolve(JournalFile *f, uint64_t realtime) {
         if (r < 0)
                 return r;
 
-        epoch = FSPRG_GetEpoch(fsprg_state(f));
+        epoch = FSPRG_GetEpoch(f->fsprg_state);
         if (epoch > goal)
                 return -ESTALE;
 
@@ -164,7 +148,7 @@ static int journal_file_evolve(JournalFile *f, uint64_t realtime) {
         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,11 +158,49 @@ 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->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;
 
@@ -228,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;
@@ -247,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;
@@ -268,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;
 }
@@ -345,8 +369,8 @@ int journal_file_load_fsprg(JournalFile *f) {
                 goto finish;
         }
 
-        f->fsprg_size = le64toh(m->header_size) + le64toh(m->state_size);
-        if ((uint64_t) st.st_size < f->fsprg_size) {
+        f->fsprg_file_size = le64toh(m->header_size) + le64toh(m->state_size);
+        if ((uint64_t) st.st_size < f->fsprg_file_size) {
                 r = -ENODATA;
                 goto finish;
         }
@@ -362,13 +386,19 @@ int journal_file_load_fsprg(JournalFile *f) {
                 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->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;
                 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->fsprg_state = (uint8_t*) f->fsprg_file + le64toh(f->fsprg_file->header_size);
+        f->fsprg_state_size = le64toh(f->fsprg_file->state_size);
+
         r = 0;
 
 finish: