1 /* SPDX-License-Identifier: LGPL-2.1+ */
8 #include "gcrypt-util.h"
10 #include "journal-authenticate.h"
11 #include "journal-def.h"
12 #include "journal-file.h"
13 #include "memory-util.h"
14 #include "time-util.h"
16 static uint64_t journal_file_tag_seqnum(JournalFile
*f
) {
21 r
= le64toh(f
->header
->n_tags
) + 1;
22 f
->header
->n_tags
= htole64(r
);
27 int journal_file_append_tag(JournalFile
*f
) {
42 r
= journal_file_append_object(f
, OBJECT_TAG
, sizeof(struct TagObject
), &o
, &p
);
46 o
->tag
.seqnum
= htole64(journal_file_tag_seqnum(f
));
47 o
->tag
.epoch
= htole64(FSPRG_GetEpoch(f
->fsprg_state
));
49 log_debug("Writing tag %"PRIu64
" for epoch %"PRIu64
"",
50 le64toh(o
->tag
.seqnum
),
51 FSPRG_GetEpoch(f
->fsprg_state
));
53 /* Add the tag object itself, so that we can protect its
54 * header. This will exclude the actual hash value in it */
55 r
= journal_file_hmac_put_object(f
, OBJECT_TAG
, o
, p
);
59 /* Get the HMAC tag and store it in the object */
60 memcpy(o
->tag
.tag
, gcry_md_read(f
->hmac
, 0), TAG_LENGTH
);
61 f
->hmac_running
= false;
66 int journal_file_hmac_start(JournalFile
*f
) {
67 uint8_t key
[256 / 8]; /* Let's pass 256 bit from FSPRG to HMAC */
76 /* Prepare HMAC for next cycle */
77 gcry_md_reset(f
->hmac
);
78 FSPRG_GetKey(f
->fsprg_state
, key
, sizeof(key
), 0);
79 gcry_md_setkey(f
->hmac
, key
, sizeof(key
));
81 f
->hmac_running
= true;
86 static int journal_file_get_epoch(JournalFile
*f
, uint64_t realtime
, uint64_t *epoch
) {
93 if (f
->fss_start_usec
== 0 ||
94 f
->fss_interval_usec
== 0)
97 if (realtime
< f
->fss_start_usec
)
100 t
= realtime
- f
->fss_start_usec
;
101 t
= t
/ f
->fss_interval_usec
;
107 static int journal_file_fsprg_need_evolve(JournalFile
*f
, uint64_t realtime
) {
108 uint64_t goal
, epoch
;
115 r
= journal_file_get_epoch(f
, realtime
, &goal
);
119 epoch
= FSPRG_GetEpoch(f
->fsprg_state
);
123 return epoch
!= goal
;
126 int journal_file_fsprg_evolve(JournalFile
*f
, uint64_t realtime
) {
127 uint64_t goal
, epoch
;
135 r
= journal_file_get_epoch(f
, realtime
, &goal
);
139 epoch
= FSPRG_GetEpoch(f
->fsprg_state
);
141 log_debug("Evolving FSPRG key from epoch %"PRIu64
" to %"PRIu64
".", epoch
, goal
);
149 FSPRG_Evolve(f
->fsprg_state
);
150 epoch
= FSPRG_GetEpoch(f
->fsprg_state
);
154 int journal_file_fsprg_seek(JournalFile
*f
, uint64_t goal
) {
163 assert(f
->fsprg_seed
);
165 if (f
->fsprg_state
) {
168 epoch
= FSPRG_GetEpoch(f
->fsprg_state
);
172 if (goal
== epoch
+1) {
173 FSPRG_Evolve(f
->fsprg_state
);
177 f
->fsprg_state_size
= FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR
);
178 f
->fsprg_state
= malloc(f
->fsprg_state_size
);
184 log_debug("Seeking FSPRG key to %"PRIu64
".", goal
);
186 msk
= alloca(FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR
));
187 FSPRG_GenMK(msk
, NULL
, f
->fsprg_seed
, f
->fsprg_seed_size
, FSPRG_RECOMMENDED_SECPAR
);
188 FSPRG_Seek(f
->fsprg_state
, goal
, msk
, f
->fsprg_seed
, f
->fsprg_seed_size
);
192 int journal_file_maybe_append_tag(JournalFile
*f
, uint64_t realtime
) {
201 realtime
= now(CLOCK_REALTIME
);
203 r
= journal_file_fsprg_need_evolve(f
, realtime
);
207 r
= journal_file_append_tag(f
);
211 r
= journal_file_fsprg_evolve(f
, realtime
);
218 int journal_file_hmac_put_object(JournalFile
*f
, ObjectType type
, Object
*o
, uint64_t p
) {
226 r
= journal_file_hmac_start(f
);
231 r
= journal_file_move_to_object(f
, type
, p
, &o
);
235 if (type
> OBJECT_UNUSED
&& o
->object
.type
!= type
)
239 gcry_md_write(f
->hmac
, o
, offsetof(ObjectHeader
, payload
));
241 switch (o
->object
.type
) {
244 /* All but hash and payload are mutable */
245 gcry_md_write(f
->hmac
, &o
->data
.hash
, sizeof(o
->data
.hash
));
246 gcry_md_write(f
->hmac
, o
->data
.payload
, le64toh(o
->object
.size
) - offsetof(DataObject
, payload
));
251 gcry_md_write(f
->hmac
, &o
->field
.hash
, sizeof(o
->field
.hash
));
252 gcry_md_write(f
->hmac
, o
->field
.payload
, le64toh(o
->object
.size
) - offsetof(FieldObject
, payload
));
257 gcry_md_write(f
->hmac
, &o
->entry
.seqnum
, le64toh(o
->object
.size
) - offsetof(EntryObject
, seqnum
));
260 case OBJECT_FIELD_HASH_TABLE
:
261 case OBJECT_DATA_HASH_TABLE
:
262 case OBJECT_ENTRY_ARRAY
:
263 /* Nothing: everything is mutable */
267 /* All but the tag itself */
268 gcry_md_write(f
->hmac
, &o
->tag
.seqnum
, sizeof(o
->tag
.seqnum
));
269 gcry_md_write(f
->hmac
, &o
->tag
.epoch
, sizeof(o
->tag
.epoch
));
278 int journal_file_hmac_put_header(JournalFile
*f
) {
286 r
= journal_file_hmac_start(f
);
290 /* All but state+reserved, boot_id, arena_size,
291 * tail_object_offset, n_objects, n_entries,
292 * tail_entry_seqnum, head_entry_seqnum, entry_array_offset,
293 * head_entry_realtime, tail_entry_realtime,
294 * tail_entry_monotonic, n_data, n_fields, n_tags,
297 gcry_md_write(f
->hmac
, f
->header
->signature
, offsetof(Header
, state
) - offsetof(Header
, signature
));
298 gcry_md_write(f
->hmac
, &f
->header
->file_id
, offsetof(Header
, boot_id
) - offsetof(Header
, file_id
));
299 gcry_md_write(f
->hmac
, &f
->header
->seqnum_id
, offsetof(Header
, arena_size
) - offsetof(Header
, seqnum_id
));
300 gcry_md_write(f
->hmac
, &f
->header
->data_hash_table_offset
, offsetof(Header
, tail_object_offset
) - offsetof(Header
, data_hash_table_offset
));
305 int journal_file_fss_load(JournalFile
*f
) {
317 r
= sd_id128_get_machine(&machine
);
321 if (asprintf(&p
, "/var/log/journal/" SD_ID128_FORMAT_STR
"/fss",
322 SD_ID128_FORMAT_VAL(machine
)) < 0)
325 fd
= open(p
, O_RDWR
|O_CLOEXEC
|O_NOCTTY
, 0600);
328 log_error_errno(errno
, "Failed to open %s: %m", p
);
334 if (fstat(fd
, &st
) < 0) {
339 if (st
.st_size
< (off_t
) sizeof(FSSHeader
)) {
344 m
= mmap(NULL
, PAGE_ALIGN(sizeof(FSSHeader
)), PROT_READ
, MAP_SHARED
, fd
, 0);
345 if (m
== MAP_FAILED
) {
351 if (memcmp(m
->signature
, FSS_HEADER_SIGNATURE
, 8) != 0) {
356 if (m
->incompatible_flags
!= 0) {
357 r
= -EPROTONOSUPPORT
;
361 if (le64toh(m
->header_size
) < sizeof(FSSHeader
)) {
366 if (le64toh(m
->fsprg_state_size
) != FSPRG_stateinbytes(le16toh(m
->fsprg_secpar
))) {
371 f
->fss_file_size
= le64toh(m
->header_size
) + le64toh(m
->fsprg_state_size
);
372 if ((uint64_t) st
.st_size
< f
->fss_file_size
) {
377 if (!sd_id128_equal(machine
, m
->machine_id
)) {
382 if (le64toh(m
->start_usec
) <= 0 ||
383 le64toh(m
->interval_usec
) <= 0) {
388 f
->fss_file
= mmap(NULL
, PAGE_ALIGN(f
->fss_file_size
), PROT_READ
|PROT_WRITE
, MAP_SHARED
, fd
, 0);
389 if (f
->fss_file
== MAP_FAILED
) {
395 f
->fss_start_usec
= le64toh(f
->fss_file
->start_usec
);
396 f
->fss_interval_usec
= le64toh(f
->fss_file
->interval_usec
);
398 f
->fsprg_state
= (uint8_t*) f
->fss_file
+ le64toh(f
->fss_file
->header_size
);
399 f
->fsprg_state_size
= le64toh(f
->fss_file
->fsprg_state_size
);
405 munmap(m
, PAGE_ALIGN(sizeof(FSSHeader
)));
413 int journal_file_hmac_setup(JournalFile
*f
) {
419 initialize_libgcrypt(true);
421 e
= gcry_md_open(&f
->hmac
, GCRY_MD_SHA256
, GCRY_MD_FLAG_HMAC
);
428 int journal_file_append_first_tag(JournalFile
*f
) {
435 log_debug("Calculating first tag...");
437 r
= journal_file_hmac_put_header(f
);
441 p
= le64toh(f
->header
->field_hash_table_offset
);
442 if (p
< offsetof(Object
, hash_table
.items
))
444 p
-= offsetof(Object
, hash_table
.items
);
446 r
= journal_file_hmac_put_object(f
, OBJECT_FIELD_HASH_TABLE
, NULL
, p
);
450 p
= le64toh(f
->header
->data_hash_table_offset
);
451 if (p
< offsetof(Object
, hash_table
.items
))
453 p
-= offsetof(Object
, hash_table
.items
);
455 r
= journal_file_hmac_put_object(f
, OBJECT_DATA_HASH_TABLE
, NULL
, p
);
459 r
= journal_file_append_tag(f
);
466 int journal_file_parse_verification_key(JournalFile
*f
, const char *key
) {
471 unsigned long long start
, interval
;
473 seed_size
= FSPRG_RECOMMENDED_SEEDLEN
;
474 seed
= malloc(seed_size
);
479 for (c
= 0; c
< seed_size
; c
++) {
498 seed
[c
] = (uint8_t) (x
* 16 + y
);
507 r
= sscanf(k
, "%llx-%llx", &start
, &interval
);
513 f
->fsprg_seed
= seed
;
514 f
->fsprg_seed_size
= seed_size
;
516 f
->fss_start_usec
= start
* interval
;
517 f
->fss_interval_usec
= interval
;
522 bool journal_file_next_evolve_usec(JournalFile
*f
, usec_t
*u
) {
531 epoch
= FSPRG_GetEpoch(f
->fsprg_state
);
533 *u
= (usec_t
) (f
->fss_start_usec
+ f
->fss_interval_usec
* epoch
+ f
->fss_interval_usec
);