]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/journal/journal-authenticate.c
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 void *fsprg_state(JournalFile
*f
) {
37 a
= le64toh(f
->fsprg_header
->header_size
);
38 b
= le64toh(f
->fsprg_header
->state_size
);
40 if (a
+ b
> f
->fsprg_size
)
43 return (uint8_t*) f
->fsprg_header
+ a
;
46 static uint64_t journal_file_tag_seqnum(JournalFile
*f
) {
51 r
= le64toh(f
->header
->n_tags
) + 1;
52 f
->header
->n_tags
= htole64(r
);
57 int journal_file_append_tag(JournalFile
*f
) {
70 log_debug("Writing tag for epoch %llu\n", (unsigned long long) FSPRG_GetEpoch(fsprg_state(f
)));
74 r
= journal_file_append_object(f
, OBJECT_TAG
, sizeof(struct TagObject
), &o
, &p
);
78 o
->tag
.seqnum
= htole64(journal_file_tag_seqnum(f
));
80 /* Add the tag object itself, so that we can protect its
81 * header. This will exclude the actual hash value in it */
82 r
= journal_file_hmac_put_object(f
, OBJECT_TAG
, p
);
86 /* Get the HMAC tag and store it in the object */
87 memcpy(o
->tag
.tag
, gcry_md_read(f
->hmac
, 0), TAG_LENGTH
);
88 f
->hmac_running
= false;
93 static int journal_file_hmac_start(JournalFile
*f
) {
94 uint8_t key
[256 / 8]; /* Let's pass 256 bit from FSPRG to HMAC */
104 /* Prepare HMAC for next cycle */
105 gcry_md_reset(f
->hmac
);
106 FSPRG_GetKey(fsprg_state(f
), key
, sizeof(key
), 0);
107 gcry_md_setkey(f
->hmac
, key
, sizeof(key
));
109 f
->hmac_running
= true;
114 static int journal_file_get_epoch(JournalFile
*f
, uint64_t realtime
, uint64_t *epoch
) {
119 assert(f
->authenticate
);
121 if (le64toh(f
->fsprg_header
->fsprg_start_usec
) == 0 ||
122 le64toh(f
->fsprg_header
->fsprg_interval_usec
) == 0)
125 if (realtime
< le64toh(f
->fsprg_header
->fsprg_start_usec
))
128 t
= realtime
- le64toh(f
->fsprg_header
->fsprg_start_usec
);
129 t
= t
/ le64toh(f
->fsprg_header
->fsprg_interval_usec
);
135 static int journal_file_need_evolve(JournalFile
*f
, uint64_t realtime
) {
136 uint64_t goal
, epoch
;
140 if (!f
->authenticate
)
143 r
= journal_file_get_epoch(f
, realtime
, &goal
);
147 epoch
= FSPRG_GetEpoch(fsprg_state(f
));
151 return epoch
!= goal
;
154 static int journal_file_evolve(JournalFile
*f
, uint64_t realtime
) {
155 uint64_t goal
, epoch
;
160 if (!f
->authenticate
)
163 r
= journal_file_get_epoch(f
, realtime
, &goal
);
167 epoch
= FSPRG_GetEpoch(fsprg_state(f
));
169 log_debug("Evolving FSPRG key from epoch %llu to %llu.", (unsigned long long) epoch
, (unsigned long long) goal
);
177 FSPRG_Evolve(fsprg_state(f
));
178 epoch
= FSPRG_GetEpoch(fsprg_state(f
));
182 int journal_file_maybe_append_tag(JournalFile
*f
, uint64_t realtime
) {
187 if (!f
->authenticate
)
190 r
= journal_file_need_evolve(f
, realtime
);
194 r
= journal_file_append_tag(f
);
198 r
= journal_file_evolve(f
, realtime
);
202 r
= journal_file_hmac_start(f
);
209 int journal_file_hmac_put_object(JournalFile
*f
, int type
, uint64_t p
) {
215 if (!f
->authenticate
)
218 r
= journal_file_hmac_start(f
);
222 r
= journal_file_move_to_object(f
, type
, p
, &o
);
226 gcry_md_write(f
->hmac
, o
, offsetof(ObjectHeader
, payload
));
228 switch (o
->object
.type
) {
231 /* All but: hash and payload are mutable */
232 gcry_md_write(f
->hmac
, &o
->data
.hash
, sizeof(o
->data
.hash
));
233 gcry_md_write(f
->hmac
, o
->data
.payload
, le64toh(o
->object
.size
) - offsetof(DataObject
, payload
));
238 gcry_md_write(f
->hmac
, &o
->entry
.seqnum
, le64toh(o
->object
.size
) - offsetof(EntryObject
, seqnum
));
241 case OBJECT_FIELD_HASH_TABLE
:
242 case OBJECT_DATA_HASH_TABLE
:
243 case OBJECT_ENTRY_ARRAY
:
244 /* Nothing: everything is mutable */
248 /* All but the tag itself */
249 gcry_md_write(f
->hmac
, &o
->tag
.seqnum
, sizeof(o
->tag
.seqnum
));
258 int journal_file_hmac_put_header(JournalFile
*f
) {
263 if (!f
->authenticate
)
266 r
= journal_file_hmac_start(f
);
270 /* All but state+reserved, boot_id, arena_size,
271 * tail_object_offset, n_objects, n_entries, tail_seqnum,
272 * head_entry_realtime, tail_entry_realtime,
273 * tail_entry_monotonic, n_data, n_fields, header_tag */
275 gcry_md_write(f
->hmac
, f
->header
->signature
, offsetof(Header
, state
) - offsetof(Header
, signature
));
276 gcry_md_write(f
->hmac
, &f
->header
->file_id
, offsetof(Header
, boot_id
) - offsetof(Header
, file_id
));
277 gcry_md_write(f
->hmac
, &f
->header
->seqnum_id
, offsetof(Header
, arena_size
) - offsetof(Header
, seqnum_id
));
278 gcry_md_write(f
->hmac
, &f
->header
->data_hash_table_offset
, offsetof(Header
, tail_object_offset
) - offsetof(Header
, data_hash_table_offset
));
279 gcry_md_write(f
->hmac
, &f
->header
->head_entry_seqnum
, offsetof(Header
, head_entry_realtime
) - offsetof(Header
, head_entry_seqnum
));
284 int journal_file_load_fsprg(JournalFile
*f
) {
288 FSPRGHeader
*m
= NULL
;
293 if (!f
->authenticate
)
296 r
= sd_id128_get_machine(&machine
);
300 if (asprintf(&p
, "/var/log/journal/" SD_ID128_FORMAT_STR
"/fsprg",
301 SD_ID128_FORMAT_VAL(machine
)) < 0)
304 fd
= open(p
, O_RDWR
|O_CLOEXEC
|O_NOCTTY
, 0600);
306 log_error("Failed to open %s: %m", p
);
311 if (fstat(fd
, &st
) < 0) {
316 if (st
.st_size
< (off_t
) sizeof(FSPRGHeader
)) {
321 m
= mmap(NULL
, PAGE_ALIGN(sizeof(FSPRGHeader
)), PROT_READ
, MAP_SHARED
, fd
, 0);
322 if (m
== MAP_FAILED
) {
328 if (memcmp(m
->signature
, FSPRG_HEADER_SIGNATURE
, 8) != 0) {
333 if (m
->incompatible_flags
!= 0) {
334 r
= -EPROTONOSUPPORT
;
338 if (le64toh(m
->header_size
) < sizeof(FSPRGHeader
)) {
343 if (le64toh(m
->state_size
) != FSPRG_stateinbytes(m
->secpar
)) {
348 f
->fsprg_size
= le64toh(m
->header_size
) + le64toh(m
->state_size
);
349 if ((uint64_t) st
.st_size
< f
->fsprg_size
) {
354 if (!sd_id128_equal(machine
, m
->machine_id
)) {
359 if (le64toh(m
->fsprg_start_usec
) <= 0 ||
360 le64toh(m
->fsprg_interval_usec
) <= 0) {
365 f
->fsprg_header
= mmap(NULL
, PAGE_ALIGN(f
->fsprg_size
), PROT_READ
|PROT_WRITE
, MAP_SHARED
, fd
, 0);
366 if (f
->fsprg_header
== MAP_FAILED
) {
367 f
->fsprg_header
= NULL
;
376 munmap(m
, PAGE_ALIGN(sizeof(FSPRGHeader
)));
379 close_nointr_nofail(fd
);
385 int journal_file_setup_hmac(JournalFile
*f
) {
388 if (!f
->authenticate
)
391 e
= gcry_md_open(&f
->hmac
, GCRY_MD_SHA256
, GCRY_MD_FLAG_HMAC
);
398 int journal_file_append_first_tag(JournalFile
*f
) {
402 if (!f
->authenticate
)
405 log_debug("Calculating first tag...");
407 r
= journal_file_hmac_put_header(f
);
411 p
= le64toh(f
->header
->field_hash_table_offset
);
412 if (p
< offsetof(Object
, hash_table
.items
))
414 p
-= offsetof(Object
, hash_table
.items
);
416 r
= journal_file_hmac_put_object(f
, OBJECT_FIELD_HASH_TABLE
, p
);
420 p
= le64toh(f
->header
->data_hash_table_offset
);
421 if (p
< offsetof(Object
, hash_table
.items
))
423 p
-= offsetof(Object
, hash_table
.items
);
425 r
= journal_file_hmac_put_object(f
, OBJECT_DATA_HASH_TABLE
, p
);
429 r
= journal_file_append_tag(f
);