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) {
54 log_debug("Writing tag for epoch %llu\n", (unsigned long long) FSPRG_GetEpoch(f->fsprg_state));
58 r = journal_file_append_object(f, OBJECT_TAG, sizeof(struct TagObject), &o, &p);
62 o->tag.seqnum = htole64(journal_file_tag_seqnum(f));
64 /* Add the tag object itself, so that we can protect its
65 * header. This will exclude the actual hash value in it */
66 r = journal_file_hmac_put_object(f, OBJECT_TAG, p);
70 /* Get the HMAC tag and store it in the object */
71 memcpy(o->tag.tag, gcry_md_read(f->hmac, 0), TAG_LENGTH);
72 f->hmac_running = false;
77 static int journal_file_hmac_start(JournalFile *f) {
78 uint8_t key[256 / 8]; /* Let's pass 256 bit from FSPRG to HMAC */
88 /* Prepare HMAC for next cycle */
89 gcry_md_reset(f->hmac);
90 FSPRG_GetKey(f->fsprg_state, key, sizeof(key), 0);
91 gcry_md_setkey(f->hmac, key, sizeof(key));
93 f->hmac_running = true;
98 static int journal_file_get_epoch(JournalFile *f, uint64_t realtime, uint64_t *epoch) {
103 assert(f->authenticate);
105 if (f->fsprg_start_usec == 0 ||
106 f->fsprg_interval_usec == 0)
109 if (realtime < f->fsprg_start_usec)
112 t = realtime - f->fsprg_start_usec;
113 t = t / f->fsprg_interval_usec;
119 static int journal_file_need_evolve(JournalFile *f, uint64_t realtime) {
120 uint64_t goal, epoch;
124 if (!f->authenticate)
127 r = journal_file_get_epoch(f, realtime, &goal);
131 epoch = FSPRG_GetEpoch(f->fsprg_state);
135 return epoch != goal;
138 static int journal_file_evolve(JournalFile *f, uint64_t realtime) {
139 uint64_t goal, epoch;
144 if (!f->authenticate)
147 r = journal_file_get_epoch(f, realtime, &goal);
151 epoch = FSPRG_GetEpoch(f->fsprg_state);
153 log_debug("Evolving FSPRG key from epoch %llu to %llu.", (unsigned long long) epoch, (unsigned long long) goal);
161 FSPRG_Evolve(f->fsprg_state);
162 epoch = FSPRG_GetEpoch(f->fsprg_state);
166 int journal_file_maybe_append_tag(JournalFile *f, uint64_t realtime) {
171 if (!f->authenticate)
174 r = journal_file_need_evolve(f, realtime);
178 r = journal_file_append_tag(f);
182 r = journal_file_evolve(f, realtime);
186 r = journal_file_hmac_start(f);
193 int journal_file_hmac_put_object(JournalFile *f, int type, uint64_t p) {
199 if (!f->authenticate)
202 r = journal_file_hmac_start(f);
206 r = journal_file_move_to_object(f, type, p, &o);
210 gcry_md_write(f->hmac, o, offsetof(ObjectHeader, payload));
212 switch (o->object.type) {
215 /* All but: hash and payload are mutable */
216 gcry_md_write(f->hmac, &o->data.hash, sizeof(o->data.hash));
217 gcry_md_write(f->hmac, o->data.payload, le64toh(o->object.size) - offsetof(DataObject, payload));
222 gcry_md_write(f->hmac, &o->entry.seqnum, le64toh(o->object.size) - offsetof(EntryObject, seqnum));
225 case OBJECT_FIELD_HASH_TABLE:
226 case OBJECT_DATA_HASH_TABLE:
227 case OBJECT_ENTRY_ARRAY:
228 /* Nothing: everything is mutable */
232 /* All but the tag itself */
233 gcry_md_write(f->hmac, &o->tag.seqnum, sizeof(o->tag.seqnum));
242 int journal_file_hmac_put_header(JournalFile *f) {
247 if (!f->authenticate)
250 r = journal_file_hmac_start(f);
254 /* All but state+reserved, boot_id, arena_size,
255 * tail_object_offset, n_objects, n_entries, tail_seqnum,
256 * head_entry_realtime, tail_entry_realtime,
257 * tail_entry_monotonic, n_data, n_fields, header_tag */
259 gcry_md_write(f->hmac, f->header->signature, offsetof(Header, state) - offsetof(Header, signature));
260 gcry_md_write(f->hmac, &f->header->file_id, offsetof(Header, boot_id) - offsetof(Header, file_id));
261 gcry_md_write(f->hmac, &f->header->seqnum_id, offsetof(Header, arena_size) - offsetof(Header, seqnum_id));
262 gcry_md_write(f->hmac, &f->header->data_hash_table_offset, offsetof(Header, tail_object_offset) - offsetof(Header, data_hash_table_offset));
263 gcry_md_write(f->hmac, &f->header->head_entry_seqnum, offsetof(Header, head_entry_realtime) - offsetof(Header, head_entry_seqnum));
268 int journal_file_load_fsprg(JournalFile *f) {
272 FSPRGHeader *m = NULL;
277 if (!f->authenticate)
280 r = sd_id128_get_machine(&machine);
284 if (asprintf(&p, "/var/log/journal/" SD_ID128_FORMAT_STR "/fsprg",
285 SD_ID128_FORMAT_VAL(machine)) < 0)
288 fd = open(p, O_RDWR|O_CLOEXEC|O_NOCTTY, 0600);
290 log_error("Failed to open %s: %m", p);
295 if (fstat(fd, &st) < 0) {
300 if (st.st_size < (off_t) sizeof(FSPRGHeader)) {
305 m = mmap(NULL, PAGE_ALIGN(sizeof(FSPRGHeader)), PROT_READ, MAP_SHARED, fd, 0);
306 if (m == MAP_FAILED) {
312 if (memcmp(m->signature, FSPRG_HEADER_SIGNATURE, 8) != 0) {
317 if (m->incompatible_flags != 0) {
318 r = -EPROTONOSUPPORT;
322 if (le64toh(m->header_size) < sizeof(FSPRGHeader)) {
327 if (le64toh(m->state_size) != FSPRG_stateinbytes(m->secpar)) {
332 f->fsprg_file_size = le64toh(m->header_size) + le64toh(m->state_size);
333 if ((uint64_t) st.st_size < f->fsprg_file_size) {
338 if (!sd_id128_equal(machine, m->machine_id)) {
343 if (le64toh(m->fsprg_start_usec) <= 0 ||
344 le64toh(m->fsprg_interval_usec) <= 0) {
349 f->fsprg_file = mmap(NULL, PAGE_ALIGN(f->fsprg_file_size), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
350 if (f->fsprg_file == MAP_FAILED) {
351 f->fsprg_file = NULL;
356 f->fsprg_start_usec = le64toh(f->fsprg_file->fsprg_start_usec);
357 f->fsprg_interval_usec = le64toh(f->fsprg_file->fsprg_interval_usec);
359 f->fsprg_state = (uint8_t*) f->fsprg_file + le64toh(f->fsprg_file->header_size);
360 f->fsprg_state_size = le64toh(f->fsprg_file->state_size);
366 munmap(m, PAGE_ALIGN(sizeof(FSPRGHeader)));
369 close_nointr_nofail(fd);
375 int journal_file_setup_hmac(JournalFile *f) {
378 if (!f->authenticate)
381 e = gcry_md_open(&f->hmac, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC);
388 int journal_file_append_first_tag(JournalFile *f) {
392 if (!f->authenticate)
395 log_debug("Calculating first tag...");
397 r = journal_file_hmac_put_header(f);
401 p = le64toh(f->header->field_hash_table_offset);
402 if (p < offsetof(Object, hash_table.items))
404 p -= offsetof(Object, hash_table.items);
406 r = journal_file_hmac_put_object(f, OBJECT_FIELD_HASH_TABLE, p);
410 p = le64toh(f->header->data_hash_table_offset);
411 if (p < offsetof(Object, hash_table.items))
413 p -= offsetof(Object, hash_table.items);
415 r = journal_file_hmac_put_object(f, OBJECT_DATA_HASH_TABLE, p);
419 r = journal_file_append_tag(f);
426 bool journal_file_fsprg_enabled(JournalFile *f) {
429 return !!(le32toh(f->header->compatible_flags) & HEADER_COMPATIBLE_AUTHENTICATED);