2 This file is part of systemd.
4 Copyright 2012 Lennart Poettering
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
25 #include "hexdecoct.h"
26 #include "journal-authenticate.h"
27 #include "journal-def.h"
28 #include "journal-file.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 %"PRIu64
" for epoch %"PRIu64
"",
64 le64toh(o
->tag
.seqnum
),
65 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 %"PRIu64
" to %"PRIu64
".", epoch
, 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 %"PRIu64
".", 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
, ObjectType 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
> OBJECT_UNUSED
&& 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
->field
.hash
, sizeof(o
->field
.hash
));
266 gcry_md_write(f
->hmac
, o
->field
.payload
, le64toh(o
->object
.size
) - offsetof(FieldObject
, payload
));
271 gcry_md_write(f
->hmac
, &o
->entry
.seqnum
, le64toh(o
->object
.size
) - offsetof(EntryObject
, seqnum
));
274 case OBJECT_FIELD_HASH_TABLE
:
275 case OBJECT_DATA_HASH_TABLE
:
276 case OBJECT_ENTRY_ARRAY
:
277 /* Nothing: everything is mutable */
281 /* All but the tag itself */
282 gcry_md_write(f
->hmac
, &o
->tag
.seqnum
, sizeof(o
->tag
.seqnum
));
283 gcry_md_write(f
->hmac
, &o
->tag
.epoch
, sizeof(o
->tag
.epoch
));
292 int journal_file_hmac_put_header(JournalFile
*f
) {
300 r
= journal_file_hmac_start(f
);
304 /* All but state+reserved, boot_id, arena_size,
305 * tail_object_offset, n_objects, n_entries,
306 * tail_entry_seqnum, head_entry_seqnum, entry_array_offset,
307 * head_entry_realtime, tail_entry_realtime,
308 * tail_entry_monotonic, n_data, n_fields, n_tags,
311 gcry_md_write(f
->hmac
, f
->header
->signature
, offsetof(Header
, state
) - offsetof(Header
, signature
));
312 gcry_md_write(f
->hmac
, &f
->header
->file_id
, offsetof(Header
, boot_id
) - offsetof(Header
, file_id
));
313 gcry_md_write(f
->hmac
, &f
->header
->seqnum_id
, offsetof(Header
, arena_size
) - offsetof(Header
, seqnum_id
));
314 gcry_md_write(f
->hmac
, &f
->header
->data_hash_table_offset
, offsetof(Header
, tail_object_offset
) - offsetof(Header
, data_hash_table_offset
));
319 int journal_file_fss_load(JournalFile
*f
) {
331 r
= sd_id128_get_machine(&machine
);
335 if (asprintf(&p
, "/var/log/journal/" SD_ID128_FORMAT_STR
"/fss",
336 SD_ID128_FORMAT_VAL(machine
)) < 0)
339 fd
= open(p
, O_RDWR
|O_CLOEXEC
|O_NOCTTY
, 0600);
342 log_error_errno(errno
, "Failed to open %s: %m", p
);
348 if (fstat(fd
, &st
) < 0) {
353 if (st
.st_size
< (off_t
) sizeof(FSSHeader
)) {
358 m
= mmap(NULL
, PAGE_ALIGN(sizeof(FSSHeader
)), PROT_READ
, MAP_SHARED
, fd
, 0);
359 if (m
== MAP_FAILED
) {
365 if (memcmp(m
->signature
, FSS_HEADER_SIGNATURE
, 8) != 0) {
370 if (m
->incompatible_flags
!= 0) {
371 r
= -EPROTONOSUPPORT
;
375 if (le64toh(m
->header_size
) < sizeof(FSSHeader
)) {
380 if (le64toh(m
->fsprg_state_size
) != FSPRG_stateinbytes(le16toh(m
->fsprg_secpar
))) {
385 f
->fss_file_size
= le64toh(m
->header_size
) + le64toh(m
->fsprg_state_size
);
386 if ((uint64_t) st
.st_size
< f
->fss_file_size
) {
391 if (!sd_id128_equal(machine
, m
->machine_id
)) {
396 if (le64toh(m
->start_usec
) <= 0 ||
397 le64toh(m
->interval_usec
) <= 0) {
402 f
->fss_file
= mmap(NULL
, PAGE_ALIGN(f
->fss_file_size
), PROT_READ
|PROT_WRITE
, MAP_SHARED
, fd
, 0);
403 if (f
->fss_file
== MAP_FAILED
) {
409 f
->fss_start_usec
= le64toh(f
->fss_file
->start_usec
);
410 f
->fss_interval_usec
= le64toh(f
->fss_file
->interval_usec
);
412 f
->fsprg_state
= (uint8_t*) f
->fss_file
+ le64toh(f
->fss_file
->header_size
);
413 f
->fsprg_state_size
= le64toh(f
->fss_file
->fsprg_state_size
);
419 munmap(m
, PAGE_ALIGN(sizeof(FSSHeader
)));
427 static void initialize_libgcrypt(void) {
430 if (gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P
))
433 p
= gcry_check_version("1.4.5");
436 gcry_control(GCRYCTL_INITIALIZATION_FINISHED
, 0);
439 int journal_file_hmac_setup(JournalFile
*f
) {
445 initialize_libgcrypt();
447 e
= gcry_md_open(&f
->hmac
, GCRY_MD_SHA256
, GCRY_MD_FLAG_HMAC
);
454 int journal_file_append_first_tag(JournalFile
*f
) {
461 log_debug("Calculating first tag...");
463 r
= journal_file_hmac_put_header(f
);
467 p
= le64toh(f
->header
->field_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_FIELD_HASH_TABLE
, NULL
, p
);
476 p
= le64toh(f
->header
->data_hash_table_offset
);
477 if (p
< offsetof(Object
, hash_table
.items
))
479 p
-= offsetof(Object
, hash_table
.items
);
481 r
= journal_file_hmac_put_object(f
, OBJECT_DATA_HASH_TABLE
, NULL
, p
);
485 r
= journal_file_append_tag(f
);
492 int journal_file_parse_verification_key(JournalFile
*f
, const char *key
) {
497 unsigned long long start
, interval
;
499 seed_size
= FSPRG_RECOMMENDED_SEEDLEN
;
500 seed
= malloc(seed_size
);
505 for (c
= 0; c
< seed_size
; c
++) {
524 seed
[c
] = (uint8_t) (x
* 16 + y
);
533 r
= sscanf(k
, "%llx-%llx", &start
, &interval
);
539 f
->fsprg_seed
= seed
;
540 f
->fsprg_seed_size
= seed_size
;
542 f
->fss_start_usec
= start
* interval
;
543 f
->fss_interval_usec
= interval
;
548 bool journal_file_next_evolve_usec(JournalFile
*f
, usec_t
*u
) {
557 epoch
= FSPRG_GetEpoch(f
->fsprg_state
);
559 *u
= (usec_t
) (f
->fss_start_usec
+ f
->fss_interval_usec
* epoch
+ f
->fss_interval_usec
);