1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2012 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
25 #include "journal-def.h"
26 #include "journal-file.h"
27 #include "journal-authenticate.h"
30 static uint64_t journal_file_tag_seqnum(JournalFile *f) {
35 r = le64toh(f->header->n_tags) + 1;
36 f->header->n_tags = htole64(r);
41 int journal_file_append_tag(JournalFile *f) {
56 r = journal_file_append_object(f, OBJECT_TAG, sizeof(struct TagObject), &o, &p);
60 o->tag.seqnum = htole64(journal_file_tag_seqnum(f));
61 o->tag.epoch = htole64(FSPRG_GetEpoch(f->fsprg_state));
63 log_debug("Writing tag %llu for epoch %llu\n",
64 (unsigned long long) le64toh(o->tag.seqnum),
65 (unsigned long long) FSPRG_GetEpoch(f->fsprg_state));
67 /* Add the tag object itself, so that we can protect its
68 * header. This will exclude the actual hash value in it */
69 r = journal_file_hmac_put_object(f, OBJECT_TAG, p);
73 /* Get the HMAC tag and store it in the object */
74 memcpy(o->tag.tag, gcry_md_read(f->hmac, 0), TAG_LENGTH);
75 f->hmac_running = false;
80 int journal_file_hmac_start(JournalFile *f) {
81 uint8_t key[256 / 8]; /* Let's pass 256 bit from FSPRG to HMAC */
90 /* Prepare HMAC for next cycle */
91 gcry_md_reset(f->hmac);
92 FSPRG_GetKey(f->fsprg_state, key, sizeof(key), 0);
93 gcry_md_setkey(f->hmac, key, sizeof(key));
95 f->hmac_running = true;
100 static int journal_file_get_epoch(JournalFile *f, uint64_t realtime, uint64_t *epoch) {
107 if (f->fss_start_usec == 0 ||
108 f->fss_interval_usec == 0)
111 if (realtime < f->fss_start_usec)
114 t = realtime - f->fss_start_usec;
115 t = t / f->fss_interval_usec;
121 static int journal_file_fsprg_need_evolve(JournalFile *f, uint64_t realtime) {
122 uint64_t goal, epoch;
129 r = journal_file_get_epoch(f, realtime, &goal);
133 epoch = FSPRG_GetEpoch(f->fsprg_state);
137 return epoch != goal;
140 int journal_file_fsprg_evolve(JournalFile *f, uint64_t realtime) {
141 uint64_t goal, epoch;
149 r = journal_file_get_epoch(f, realtime, &goal);
153 epoch = FSPRG_GetEpoch(f->fsprg_state);
155 log_debug("Evolving FSPRG key from epoch %llu to %llu.", (unsigned long long) epoch, (unsigned long long) goal);
163 FSPRG_Evolve(f->fsprg_state);
164 epoch = FSPRG_GetEpoch(f->fsprg_state);
168 int journal_file_fsprg_seek(JournalFile *f, uint64_t goal) {
177 assert(f->fsprg_seed);
179 if (f->fsprg_state) {
182 epoch = FSPRG_GetEpoch(f->fsprg_state);
186 if (goal == epoch+1) {
187 FSPRG_Evolve(f->fsprg_state);
191 f->fsprg_state_size = FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR);
192 f->fsprg_state = malloc(f->fsprg_state_size);
198 log_debug("Seeking FSPRG key to %llu.", (unsigned long long) goal);
200 msk = alloca(FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR));
201 FSPRG_GenMK(msk, NULL, f->fsprg_seed, f->fsprg_seed_size, FSPRG_RECOMMENDED_SECPAR);
202 FSPRG_Seek(f->fsprg_state, goal, msk, f->fsprg_seed, f->fsprg_seed_size);
206 int journal_file_maybe_append_tag(JournalFile *f, uint64_t realtime) {
214 r = journal_file_fsprg_need_evolve(f, realtime);
218 r = journal_file_append_tag(f);
222 r = journal_file_fsprg_evolve(f, realtime);
229 int journal_file_hmac_put_object(JournalFile *f, int type, uint64_t p) {
238 r = journal_file_hmac_start(f);
242 r = journal_file_move_to_object(f, type, p, &o);
246 gcry_md_write(f->hmac, o, offsetof(ObjectHeader, payload));
248 switch (o->object.type) {
251 /* All but hash and payload are mutable */
252 gcry_md_write(f->hmac, &o->data.hash, sizeof(o->data.hash));
253 gcry_md_write(f->hmac, o->data.payload, le64toh(o->object.size) - offsetof(DataObject, payload));
258 gcry_md_write(f->hmac, &o->entry.seqnum, le64toh(o->object.size) - offsetof(EntryObject, seqnum));
261 case OBJECT_FIELD_HASH_TABLE:
262 case OBJECT_DATA_HASH_TABLE:
263 case OBJECT_ENTRY_ARRAY:
264 /* Nothing: everything is mutable */
268 /* All but the tag itself */
269 gcry_md_write(f->hmac, &o->tag.seqnum, sizeof(o->tag.seqnum));
270 gcry_md_write(f->hmac, &o->tag.epoch, sizeof(o->tag.epoch));
279 int journal_file_hmac_put_header(JournalFile *f) {
287 r = journal_file_hmac_start(f);
291 /* All but state+reserved, boot_id, arena_size,
292 * tail_object_offset, n_objects, n_entries,
293 * tail_entry_seqnum, head_entry_seqnum, entry_array_offset,
294 * head_entry_realtime, tail_entry_realtime,
295 * tail_entry_monotonic, n_data, n_fields, n_tags,
298 gcry_md_write(f->hmac, f->header->signature, offsetof(Header, state) - offsetof(Header, signature));
299 gcry_md_write(f->hmac, &f->header->file_id, offsetof(Header, boot_id) - offsetof(Header, file_id));
300 gcry_md_write(f->hmac, &f->header->seqnum_id, offsetof(Header, arena_size) - offsetof(Header, seqnum_id));
301 gcry_md_write(f->hmac, &f->header->data_hash_table_offset, offsetof(Header, tail_object_offset) - offsetof(Header, data_hash_table_offset));
306 int journal_file_fss_load(JournalFile *f) {
318 r = sd_id128_get_machine(&machine);
322 if (asprintf(&p, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss",
323 SD_ID128_FORMAT_VAL(machine)) < 0)
326 fd = open(p, O_RDWR|O_CLOEXEC|O_NOCTTY, 0600);
328 log_error("Failed to open %s: %m", p);
333 if (fstat(fd, &st) < 0) {
338 if (st.st_size < (off_t) sizeof(FSSHeader)) {
343 m = mmap(NULL, PAGE_ALIGN(sizeof(FSSHeader)), PROT_READ, MAP_SHARED, fd, 0);
344 if (m == MAP_FAILED) {
350 if (memcmp(m->signature, FSS_HEADER_SIGNATURE, 8) != 0) {
355 if (m->incompatible_flags != 0) {
356 r = -EPROTONOSUPPORT;
360 if (le64toh(m->header_size) < sizeof(FSSHeader)) {
365 if (le64toh(m->fsprg_state_size) != FSPRG_stateinbytes(m->fsprg_secpar)) {
370 f->fss_file_size = le64toh(m->header_size) + le64toh(m->fsprg_state_size);
371 if ((uint64_t) st.st_size < f->fss_file_size) {
376 if (!sd_id128_equal(machine, m->machine_id)) {
381 if (le64toh(m->start_usec) <= 0 ||
382 le64toh(m->interval_usec) <= 0) {
387 f->fss_file = mmap(NULL, PAGE_ALIGN(f->fss_file_size), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
388 if (f->fss_file == MAP_FAILED) {
394 f->fss_start_usec = le64toh(f->fss_file->start_usec);
395 f->fss_interval_usec = le64toh(f->fss_file->interval_usec);
397 f->fsprg_state = (uint8_t*) f->fss_file + le64toh(f->fss_file->header_size);
398 f->fsprg_state_size = le64toh(f->fss_file->fsprg_state_size);
404 munmap(m, PAGE_ALIGN(sizeof(FSSHeader)));
407 close_nointr_nofail(fd);
413 int journal_file_hmac_setup(JournalFile *f) {
419 e = gcry_md_open(&f->hmac, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC);
426 int journal_file_append_first_tag(JournalFile *f) {
433 log_debug("Calculating first tag...");
435 r = journal_file_hmac_put_header(f);
439 p = le64toh(f->header->field_hash_table_offset);
440 if (p < offsetof(Object, hash_table.items))
442 p -= offsetof(Object, hash_table.items);
444 r = journal_file_hmac_put_object(f, OBJECT_FIELD_HASH_TABLE, p);
448 p = le64toh(f->header->data_hash_table_offset);
449 if (p < offsetof(Object, hash_table.items))
451 p -= offsetof(Object, hash_table.items);
453 r = journal_file_hmac_put_object(f, OBJECT_DATA_HASH_TABLE, p);
457 r = journal_file_append_tag(f);
465 int journal_file_parse_verification_key(JournalFile *f, const char *key) {
470 unsigned long long start, interval;
472 seed_size = FSPRG_RECOMMENDED_SEEDLEN;
473 seed = malloc(seed_size);
478 for (c = 0; c < seed_size; c++) {
497 seed[c] = (uint8_t) (x * 16 + y);
506 r = sscanf(k, "%llx-%llx", &start, &interval);
512 f->fsprg_seed = seed;
513 f->fsprg_seed_size = seed_size;
515 f->fss_start_usec = start * interval;
516 f->fss_interval_usec = interval;