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) {
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, uint64_t p) {
241 r = journal_file_hmac_start(f);
245 r = journal_file_move_to_object(f, type, p, &o);
249 gcry_md_write(f->hmac, o, offsetof(ObjectHeader, payload));
251 switch (o->object.type) {
254 /* All but hash and payload are mutable */
255 gcry_md_write(f->hmac, &o->data.hash, sizeof(o->data.hash));
256 gcry_md_write(f->hmac, o->data.payload, le64toh(o->object.size) - offsetof(DataObject, payload));
261 gcry_md_write(f->hmac, &o->entry.seqnum, le64toh(o->object.size) - offsetof(EntryObject, seqnum));
264 case OBJECT_FIELD_HASH_TABLE:
265 case OBJECT_DATA_HASH_TABLE:
266 case OBJECT_ENTRY_ARRAY:
267 /* Nothing: everything is mutable */
271 /* All but the tag itself */
272 gcry_md_write(f->hmac, &o->tag.seqnum, sizeof(o->tag.seqnum));
273 gcry_md_write(f->hmac, &o->tag.epoch, sizeof(o->tag.epoch));
282 int journal_file_hmac_put_header(JournalFile *f) {
290 r = journal_file_hmac_start(f);
294 /* All but state+reserved, boot_id, arena_size,
295 * tail_object_offset, n_objects, n_entries,
296 * tail_entry_seqnum, head_entry_seqnum, entry_array_offset,
297 * head_entry_realtime, tail_entry_realtime,
298 * tail_entry_monotonic, n_data, n_fields, n_tags,
301 gcry_md_write(f->hmac, f->header->signature, offsetof(Header, state) - offsetof(Header, signature));
302 gcry_md_write(f->hmac, &f->header->file_id, offsetof(Header, boot_id) - offsetof(Header, file_id));
303 gcry_md_write(f->hmac, &f->header->seqnum_id, offsetof(Header, arena_size) - offsetof(Header, seqnum_id));
304 gcry_md_write(f->hmac, &f->header->data_hash_table_offset, offsetof(Header, tail_object_offset) - offsetof(Header, data_hash_table_offset));
309 int journal_file_fss_load(JournalFile *f) {
321 r = sd_id128_get_machine(&machine);
325 if (asprintf(&p, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss",
326 SD_ID128_FORMAT_VAL(machine)) < 0)
329 fd = open(p, O_RDWR|O_CLOEXEC|O_NOCTTY, 0600);
331 log_error("Failed to open %s: %m", p);
336 if (fstat(fd, &st) < 0) {
341 if (st.st_size < (off_t) sizeof(FSSHeader)) {
346 m = mmap(NULL, PAGE_ALIGN(sizeof(FSSHeader)), PROT_READ, MAP_SHARED, fd, 0);
347 if (m == MAP_FAILED) {
353 if (memcmp(m->signature, FSS_HEADER_SIGNATURE, 8) != 0) {
358 if (m->incompatible_flags != 0) {
359 r = -EPROTONOSUPPORT;
363 if (le64toh(m->header_size) < sizeof(FSSHeader)) {
368 if (le64toh(m->fsprg_state_size) != FSPRG_stateinbytes(le16toh(m->fsprg_secpar))) {
373 f->fss_file_size = le64toh(m->header_size) + le64toh(m->fsprg_state_size);
374 if ((uint64_t) st.st_size < f->fss_file_size) {
379 if (!sd_id128_equal(machine, m->machine_id)) {
384 if (le64toh(m->start_usec) <= 0 ||
385 le64toh(m->interval_usec) <= 0) {
390 f->fss_file = mmap(NULL, PAGE_ALIGN(f->fss_file_size), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
391 if (f->fss_file == MAP_FAILED) {
397 f->fss_start_usec = le64toh(f->fss_file->start_usec);
398 f->fss_interval_usec = le64toh(f->fss_file->interval_usec);
400 f->fsprg_state = (uint8_t*) f->fss_file + le64toh(f->fss_file->header_size);
401 f->fsprg_state_size = le64toh(f->fss_file->fsprg_state_size);
407 munmap(m, PAGE_ALIGN(sizeof(FSSHeader)));
410 close_nointr_nofail(fd);
416 static void initialize_libgcrypt(void) {
419 if (gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P))
422 p = gcry_check_version("1.4.5");
425 gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);
428 int journal_file_hmac_setup(JournalFile *f) {
434 initialize_libgcrypt();
436 e = gcry_md_open(&f->hmac, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC);
443 int journal_file_append_first_tag(JournalFile *f) {
450 log_debug("Calculating first tag...");
452 r = journal_file_hmac_put_header(f);
456 p = le64toh(f->header->field_hash_table_offset);
457 if (p < offsetof(Object, hash_table.items))
459 p -= offsetof(Object, hash_table.items);
461 r = journal_file_hmac_put_object(f, OBJECT_FIELD_HASH_TABLE, p);
465 p = le64toh(f->header->data_hash_table_offset);
466 if (p < offsetof(Object, hash_table.items))
468 p -= offsetof(Object, hash_table.items);
470 r = journal_file_hmac_put_object(f, OBJECT_DATA_HASH_TABLE, p);
474 r = journal_file_append_tag(f);
482 int journal_file_parse_verification_key(JournalFile *f, const char *key) {
487 unsigned long long start, interval;
489 seed_size = FSPRG_RECOMMENDED_SEEDLEN;
490 seed = malloc(seed_size);
495 for (c = 0; c < seed_size; c++) {
514 seed[c] = (uint8_t) (x * 16 + y);
523 r = sscanf(k, "%llx-%llx", &start, &interval);
529 f->fsprg_seed = seed;
530 f->fsprg_seed_size = seed_size;
532 f->fss_start_usec = start * interval;
533 f->fss_interval_usec = interval;
538 bool journal_file_next_evolve_usec(JournalFile *f, usec_t *u) {
547 epoch = FSPRG_GetEpoch(f->fsprg_state);
549 *u = (usec_t) (f->fss_start_usec + f->fss_interval_usec * epoch + f->fss_interval_usec);