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, o, 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) {
215 realtime = now(CLOCK_REALTIME);
217 r = journal_file_fsprg_need_evolve(f, realtime);
221 r = journal_file_append_tag(f);
225 r = journal_file_fsprg_evolve(f, realtime);
232 int journal_file_hmac_put_object(JournalFile *f, int type, Object *o, uint64_t p) {
240 r = journal_file_hmac_start(f);
245 r = journal_file_move_to_object(f, type, p, &o);
249 if (type >= 0 && o->object.type != type)
253 gcry_md_write(f->hmac, o, offsetof(ObjectHeader, payload));
255 switch (o->object.type) {
258 /* All but hash and payload are mutable */
259 gcry_md_write(f->hmac, &o->data.hash, sizeof(o->data.hash));
260 gcry_md_write(f->hmac, o->data.payload, le64toh(o->object.size) - offsetof(DataObject, payload));
265 gcry_md_write(f->hmac, &o->entry.seqnum, le64toh(o->object.size) - offsetof(EntryObject, seqnum));
268 case OBJECT_FIELD_HASH_TABLE:
269 case OBJECT_DATA_HASH_TABLE:
270 case OBJECT_ENTRY_ARRAY:
271 /* Nothing: everything is mutable */
275 /* All but the tag itself */
276 gcry_md_write(f->hmac, &o->tag.seqnum, sizeof(o->tag.seqnum));
277 gcry_md_write(f->hmac, &o->tag.epoch, sizeof(o->tag.epoch));
286 int journal_file_hmac_put_header(JournalFile *f) {
294 r = journal_file_hmac_start(f);
298 /* All but state+reserved, boot_id, arena_size,
299 * tail_object_offset, n_objects, n_entries,
300 * tail_entry_seqnum, head_entry_seqnum, entry_array_offset,
301 * head_entry_realtime, tail_entry_realtime,
302 * tail_entry_monotonic, n_data, n_fields, n_tags,
305 gcry_md_write(f->hmac, f->header->signature, offsetof(Header, state) - offsetof(Header, signature));
306 gcry_md_write(f->hmac, &f->header->file_id, offsetof(Header, boot_id) - offsetof(Header, file_id));
307 gcry_md_write(f->hmac, &f->header->seqnum_id, offsetof(Header, arena_size) - offsetof(Header, seqnum_id));
308 gcry_md_write(f->hmac, &f->header->data_hash_table_offset, offsetof(Header, tail_object_offset) - offsetof(Header, data_hash_table_offset));
313 int journal_file_fss_load(JournalFile *f) {
325 r = sd_id128_get_machine(&machine);
329 if (asprintf(&p, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss",
330 SD_ID128_FORMAT_VAL(machine)) < 0)
333 fd = open(p, O_RDWR|O_CLOEXEC|O_NOCTTY, 0600);
336 log_error("Failed to open %s: %m", p);
342 if (fstat(fd, &st) < 0) {
347 if (st.st_size < (off_t) sizeof(FSSHeader)) {
352 m = mmap(NULL, PAGE_ALIGN(sizeof(FSSHeader)), PROT_READ, MAP_SHARED, fd, 0);
353 if (m == MAP_FAILED) {
359 if (memcmp(m->signature, FSS_HEADER_SIGNATURE, 8) != 0) {
364 if (m->incompatible_flags != 0) {
365 r = -EPROTONOSUPPORT;
369 if (le64toh(m->header_size) < sizeof(FSSHeader)) {
374 if (le64toh(m->fsprg_state_size) != FSPRG_stateinbytes(le16toh(m->fsprg_secpar))) {
379 f->fss_file_size = le64toh(m->header_size) + le64toh(m->fsprg_state_size);
380 if ((uint64_t) st.st_size < f->fss_file_size) {
385 if (!sd_id128_equal(machine, m->machine_id)) {
390 if (le64toh(m->start_usec) <= 0 ||
391 le64toh(m->interval_usec) <= 0) {
396 f->fss_file = mmap(NULL, PAGE_ALIGN(f->fss_file_size), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
397 if (f->fss_file == MAP_FAILED) {
403 f->fss_start_usec = le64toh(f->fss_file->start_usec);
404 f->fss_interval_usec = le64toh(f->fss_file->interval_usec);
406 f->fsprg_state = (uint8_t*) f->fss_file + le64toh(f->fss_file->header_size);
407 f->fsprg_state_size = le64toh(f->fss_file->fsprg_state_size);
413 munmap(m, PAGE_ALIGN(sizeof(FSSHeader)));
416 close_nointr_nofail(fd);
422 static void initialize_libgcrypt(void) {
425 if (gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P))
428 p = gcry_check_version("1.4.5");
431 gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);
434 int journal_file_hmac_setup(JournalFile *f) {
440 initialize_libgcrypt();
442 e = gcry_md_open(&f->hmac, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC);
449 int journal_file_append_first_tag(JournalFile *f) {
456 log_debug("Calculating first tag...");
458 r = journal_file_hmac_put_header(f);
462 p = le64toh(f->header->field_hash_table_offset);
463 if (p < offsetof(Object, hash_table.items))
465 p -= offsetof(Object, hash_table.items);
467 r = journal_file_hmac_put_object(f, OBJECT_FIELD_HASH_TABLE, NULL, p);
471 p = le64toh(f->header->data_hash_table_offset);
472 if (p < offsetof(Object, hash_table.items))
474 p -= offsetof(Object, hash_table.items);
476 r = journal_file_hmac_put_object(f, OBJECT_DATA_HASH_TABLE, NULL, p);
480 r = journal_file_append_tag(f);
488 int journal_file_parse_verification_key(JournalFile *f, const char *key) {
493 unsigned long long start, interval;
495 seed_size = FSPRG_RECOMMENDED_SEEDLEN;
496 seed = malloc(seed_size);
501 for (c = 0; c < seed_size; c++) {
520 seed[c] = (uint8_t) (x * 16 + y);
529 r = sscanf(k, "%llx-%llx", &start, &interval);
535 f->fsprg_seed = seed;
536 f->fsprg_seed_size = seed_size;
538 f->fss_start_usec = start * interval;
539 f->fss_interval_usec = interval;
544 bool journal_file_next_evolve_usec(JournalFile *f, usec_t *u) {
553 epoch = FSPRG_GetEpoch(f->fsprg_state);
555 *u = (usec_t) (f->fss_start_usec + f->fss_interval_usec * epoch + f->fss_interval_usec);