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);
332 log_error("Failed to open %s: %m", p);
338 if (fstat(fd, &st) < 0) {
343 if (st.st_size < (off_t) sizeof(FSSHeader)) {
348 m = mmap(NULL, PAGE_ALIGN(sizeof(FSSHeader)), PROT_READ, MAP_SHARED, fd, 0);
349 if (m == MAP_FAILED) {
355 if (memcmp(m->signature, FSS_HEADER_SIGNATURE, 8) != 0) {
360 if (m->incompatible_flags != 0) {
361 r = -EPROTONOSUPPORT;
365 if (le64toh(m->header_size) < sizeof(FSSHeader)) {
370 if (le64toh(m->fsprg_state_size) != FSPRG_stateinbytes(le16toh(m->fsprg_secpar))) {
375 f->fss_file_size = le64toh(m->header_size) + le64toh(m->fsprg_state_size);
376 if ((uint64_t) st.st_size < f->fss_file_size) {
381 if (!sd_id128_equal(machine, m->machine_id)) {
386 if (le64toh(m->start_usec) <= 0 ||
387 le64toh(m->interval_usec) <= 0) {
392 f->fss_file = mmap(NULL, PAGE_ALIGN(f->fss_file_size), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
393 if (f->fss_file == MAP_FAILED) {
399 f->fss_start_usec = le64toh(f->fss_file->start_usec);
400 f->fss_interval_usec = le64toh(f->fss_file->interval_usec);
402 f->fsprg_state = (uint8_t*) f->fss_file + le64toh(f->fss_file->header_size);
403 f->fsprg_state_size = le64toh(f->fss_file->fsprg_state_size);
409 munmap(m, PAGE_ALIGN(sizeof(FSSHeader)));
412 close_nointr_nofail(fd);
418 static void initialize_libgcrypt(void) {
421 if (gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P))
424 p = gcry_check_version("1.4.5");
427 gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);
430 int journal_file_hmac_setup(JournalFile *f) {
436 initialize_libgcrypt();
438 e = gcry_md_open(&f->hmac, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC);
445 int journal_file_append_first_tag(JournalFile *f) {
452 log_debug("Calculating first tag...");
454 r = journal_file_hmac_put_header(f);
458 p = le64toh(f->header->field_hash_table_offset);
459 if (p < offsetof(Object, hash_table.items))
461 p -= offsetof(Object, hash_table.items);
463 r = journal_file_hmac_put_object(f, OBJECT_FIELD_HASH_TABLE, p);
467 p = le64toh(f->header->data_hash_table_offset);
468 if (p < offsetof(Object, hash_table.items))
470 p -= offsetof(Object, hash_table.items);
472 r = journal_file_hmac_put_object(f, OBJECT_DATA_HASH_TABLE, p);
476 r = journal_file_append_tag(f);
484 int journal_file_parse_verification_key(JournalFile *f, const char *key) {
489 unsigned long long start, interval;
491 seed_size = FSPRG_RECOMMENDED_SEEDLEN;
492 seed = malloc(seed_size);
497 for (c = 0; c < seed_size; c++) {
516 seed[c] = (uint8_t) (x * 16 + y);
525 r = sscanf(k, "%llx-%llx", &start, &interval);
531 f->fsprg_seed = seed;
532 f->fsprg_seed_size = seed_size;
534 f->fss_start_usec = start * interval;
535 f->fss_interval_usec = interval;
540 bool journal_file_next_evolve_usec(JournalFile *f, usec_t *u) {
549 epoch = FSPRG_GetEpoch(f->fsprg_state);
551 *u = (usec_t) (f->fss_start_usec + f->fss_interval_usec * epoch + f->fss_interval_usec);