]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/journal/journal-authenticate.c
do not filter out deprecated USER audit messages
[thirdparty/systemd.git] / src / journal / journal-authenticate.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
0284adc6
LP
2
3#include <fcntl.h>
4#include <sys/mman.h>
5
3ffd4af2
LP
6#include "fd-util.h"
7#include "fsprg.h"
91e023d8 8#include "gcrypt-util.h"
cf0fbc49 9#include "hexdecoct.h"
3ffd4af2 10#include "journal-authenticate.h"
0284adc6
LP
11#include "journal-def.h"
12#include "journal-file.h"
0284adc6 13
0284adc6
LP
14static uint64_t journal_file_tag_seqnum(JournalFile *f) {
15 uint64_t r;
16
17 assert(f);
18
19 r = le64toh(f->header->n_tags) + 1;
20 f->header->n_tags = htole64(r);
21
22 return r;
23}
24
25int journal_file_append_tag(JournalFile *f) {
26 Object *o;
27 uint64_t p;
28 int r;
29
30 assert(f);
31
baed47c3 32 if (!f->seal)
0284adc6
LP
33 return 0;
34
35 if (!f->hmac_running)
36 return 0;
37
0284adc6
LP
38 assert(f->hmac);
39
40 r = journal_file_append_object(f, OBJECT_TAG, sizeof(struct TagObject), &o, &p);
41 if (r < 0)
42 return r;
43
44 o->tag.seqnum = htole64(journal_file_tag_seqnum(f));
14d10188 45 o->tag.epoch = htole64(FSPRG_GetEpoch(f->fsprg_state));
0284adc6 46
9f6445e3 47 log_debug("Writing tag %"PRIu64" for epoch %"PRIu64"",
507f22bd
ZJS
48 le64toh(o->tag.seqnum),
49 FSPRG_GetEpoch(f->fsprg_state));
e627440b 50
0284adc6
LP
51 /* Add the tag object itself, so that we can protect its
52 * header. This will exclude the actual hash value in it */
5996c7c2 53 r = journal_file_hmac_put_object(f, OBJECT_TAG, o, p);
0284adc6
LP
54 if (r < 0)
55 return r;
56
57 /* Get the HMAC tag and store it in the object */
58 memcpy(o->tag.tag, gcry_md_read(f->hmac, 0), TAG_LENGTH);
59 f->hmac_running = false;
60
61 return 0;
62}
63
14d10188 64int journal_file_hmac_start(JournalFile *f) {
0284adc6 65 uint8_t key[256 / 8]; /* Let's pass 256 bit from FSPRG to HMAC */
0284adc6
LP
66 assert(f);
67
baed47c3 68 if (!f->seal)
0284adc6
LP
69 return 0;
70
71 if (f->hmac_running)
72 return 0;
73
74 /* Prepare HMAC for next cycle */
75 gcry_md_reset(f->hmac);
b7c9ae91 76 FSPRG_GetKey(f->fsprg_state, key, sizeof(key), 0);
0284adc6
LP
77 gcry_md_setkey(f->hmac, key, sizeof(key));
78
79 f->hmac_running = true;
80
81 return 0;
82}
83
84static int journal_file_get_epoch(JournalFile *f, uint64_t realtime, uint64_t *epoch) {
85 uint64_t t;
86
87 assert(f);
88 assert(epoch);
baed47c3 89 assert(f->seal);
0284adc6 90
baed47c3
LP
91 if (f->fss_start_usec == 0 ||
92 f->fss_interval_usec == 0)
15411c0c 93 return -EOPNOTSUPP;
0284adc6 94
baed47c3 95 if (realtime < f->fss_start_usec)
0284adc6
LP
96 return -ESTALE;
97
baed47c3
LP
98 t = realtime - f->fss_start_usec;
99 t = t / f->fss_interval_usec;
0284adc6
LP
100
101 *epoch = t;
102 return 0;
103}
104
baed47c3 105static int journal_file_fsprg_need_evolve(JournalFile *f, uint64_t realtime) {
0284adc6
LP
106 uint64_t goal, epoch;
107 int r;
108 assert(f);
109
baed47c3 110 if (!f->seal)
0284adc6
LP
111 return 0;
112
113 r = journal_file_get_epoch(f, realtime, &goal);
114 if (r < 0)
115 return r;
116
b7c9ae91 117 epoch = FSPRG_GetEpoch(f->fsprg_state);
0284adc6
LP
118 if (epoch > goal)
119 return -ESTALE;
120
121 return epoch != goal;
122}
123
baed47c3 124int journal_file_fsprg_evolve(JournalFile *f, uint64_t realtime) {
0284adc6
LP
125 uint64_t goal, epoch;
126 int r;
127
128 assert(f);
129
baed47c3 130 if (!f->seal)
0284adc6
LP
131 return 0;
132
133 r = journal_file_get_epoch(f, realtime, &goal);
134 if (r < 0)
135 return r;
136
b7c9ae91 137 epoch = FSPRG_GetEpoch(f->fsprg_state);
0284adc6 138 if (epoch < goal)
507f22bd 139 log_debug("Evolving FSPRG key from epoch %"PRIu64" to %"PRIu64".", epoch, goal);
0284adc6
LP
140
141 for (;;) {
142 if (epoch > goal)
143 return -ESTALE;
144 if (epoch == goal)
145 return 0;
146
b7c9ae91
LP
147 FSPRG_Evolve(f->fsprg_state);
148 epoch = FSPRG_GetEpoch(f->fsprg_state);
0284adc6
LP
149 }
150}
151
14d10188
LP
152int journal_file_fsprg_seek(JournalFile *f, uint64_t goal) {
153 void *msk;
154 uint64_t epoch;
155
156 assert(f);
157
baed47c3 158 if (!f->seal)
14d10188
LP
159 return 0;
160
161 assert(f->fsprg_seed);
162
163 if (f->fsprg_state) {
164 /* Cheaper... */
165
166 epoch = FSPRG_GetEpoch(f->fsprg_state);
167 if (goal == epoch)
168 return 0;
169
170 if (goal == epoch+1) {
171 FSPRG_Evolve(f->fsprg_state);
172 return 0;
173 }
174 } else {
175 f->fsprg_state_size = FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR);
176 f->fsprg_state = malloc(f->fsprg_state_size);
177
178 if (!f->fsprg_state)
179 return -ENOMEM;
180 }
181
507f22bd 182 log_debug("Seeking FSPRG key to %"PRIu64".", goal);
14d10188
LP
183
184 msk = alloca(FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR));
185 FSPRG_GenMK(msk, NULL, f->fsprg_seed, f->fsprg_seed_size, FSPRG_RECOMMENDED_SECPAR);
186 FSPRG_Seek(f->fsprg_state, goal, msk, f->fsprg_seed, f->fsprg_seed_size);
187 return 0;
188}
189
0284adc6
LP
190int journal_file_maybe_append_tag(JournalFile *f, uint64_t realtime) {
191 int r;
192
193 assert(f);
194
baed47c3 195 if (!f->seal)
0284adc6
LP
196 return 0;
197
89fef990 198 if (realtime <= 0)
671e021c 199 realtime = now(CLOCK_REALTIME);
89fef990 200
baed47c3 201 r = journal_file_fsprg_need_evolve(f, realtime);
0284adc6
LP
202 if (r <= 0)
203 return 0;
204
205 r = journal_file_append_tag(f);
206 if (r < 0)
207 return r;
208
baed47c3 209 r = journal_file_fsprg_evolve(f, realtime);
0284adc6
LP
210 if (r < 0)
211 return r;
212
0284adc6
LP
213 return 0;
214}
215
78519831 216int journal_file_hmac_put_object(JournalFile *f, ObjectType type, Object *o, uint64_t p) {
0284adc6 217 int r;
0284adc6
LP
218
219 assert(f);
220
baed47c3 221 if (!f->seal)
0284adc6
LP
222 return 0;
223
224 r = journal_file_hmac_start(f);
225 if (r < 0)
226 return r;
227
5996c7c2
LP
228 if (!o) {
229 r = journal_file_move_to_object(f, type, p, &o);
230 if (r < 0)
231 return r;
232 } else {
d05089d8 233 if (type > OBJECT_UNUSED && o->object.type != type)
5996c7c2
LP
234 return -EBADMSG;
235 }
0284adc6
LP
236
237 gcry_md_write(f->hmac, o, offsetof(ObjectHeader, payload));
238
239 switch (o->object.type) {
240
241 case OBJECT_DATA:
14d10188 242 /* All but hash and payload are mutable */
0284adc6
LP
243 gcry_md_write(f->hmac, &o->data.hash, sizeof(o->data.hash));
244 gcry_md_write(f->hmac, o->data.payload, le64toh(o->object.size) - offsetof(DataObject, payload));
245 break;
246
3c1668da
LP
247 case OBJECT_FIELD:
248 /* Same here */
249 gcry_md_write(f->hmac, &o->field.hash, sizeof(o->field.hash));
250 gcry_md_write(f->hmac, o->field.payload, le64toh(o->object.size) - offsetof(FieldObject, payload));
251 break;
252
0284adc6
LP
253 case OBJECT_ENTRY:
254 /* All */
255 gcry_md_write(f->hmac, &o->entry.seqnum, le64toh(o->object.size) - offsetof(EntryObject, seqnum));
256 break;
257
258 case OBJECT_FIELD_HASH_TABLE:
259 case OBJECT_DATA_HASH_TABLE:
260 case OBJECT_ENTRY_ARRAY:
261 /* Nothing: everything is mutable */
262 break;
263
264 case OBJECT_TAG:
265 /* All but the tag itself */
266 gcry_md_write(f->hmac, &o->tag.seqnum, sizeof(o->tag.seqnum));
14d10188 267 gcry_md_write(f->hmac, &o->tag.epoch, sizeof(o->tag.epoch));
0284adc6
LP
268 break;
269 default:
270 return -EINVAL;
271 }
272
273 return 0;
274}
275
276int journal_file_hmac_put_header(JournalFile *f) {
277 int r;
278
279 assert(f);
280
baed47c3 281 if (!f->seal)
0284adc6
LP
282 return 0;
283
284 r = journal_file_hmac_start(f);
285 if (r < 0)
286 return r;
287
288 /* All but state+reserved, boot_id, arena_size,
14d10188
LP
289 * tail_object_offset, n_objects, n_entries,
290 * tail_entry_seqnum, head_entry_seqnum, entry_array_offset,
0284adc6 291 * head_entry_realtime, tail_entry_realtime,
14d10188
LP
292 * tail_entry_monotonic, n_data, n_fields, n_tags,
293 * n_entry_arrays. */
0284adc6
LP
294
295 gcry_md_write(f->hmac, f->header->signature, offsetof(Header, state) - offsetof(Header, signature));
296 gcry_md_write(f->hmac, &f->header->file_id, offsetof(Header, boot_id) - offsetof(Header, file_id));
297 gcry_md_write(f->hmac, &f->header->seqnum_id, offsetof(Header, arena_size) - offsetof(Header, seqnum_id));
298 gcry_md_write(f->hmac, &f->header->data_hash_table_offset, offsetof(Header, tail_object_offset) - offsetof(Header, data_hash_table_offset));
0284adc6
LP
299
300 return 0;
301}
302
baed47c3 303int journal_file_fss_load(JournalFile *f) {
0284adc6
LP
304 int r, fd = -1;
305 char *p = NULL;
306 struct stat st;
baed47c3 307 FSSHeader *m = NULL;
0284adc6
LP
308 sd_id128_t machine;
309
310 assert(f);
311
baed47c3 312 if (!f->seal)
0284adc6
LP
313 return 0;
314
315 r = sd_id128_get_machine(&machine);
316 if (r < 0)
317 return r;
318
baed47c3 319 if (asprintf(&p, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss",
0284adc6
LP
320 SD_ID128_FORMAT_VAL(machine)) < 0)
321 return -ENOMEM;
322
323 fd = open(p, O_RDWR|O_CLOEXEC|O_NOCTTY, 0600);
324 if (fd < 0) {
272410e1 325 if (errno != ENOENT)
56f64d95 326 log_error_errno(errno, "Failed to open %s: %m", p);
272410e1 327
0284adc6
LP
328 r = -errno;
329 goto finish;
330 }
331
332 if (fstat(fd, &st) < 0) {
333 r = -errno;
334 goto finish;
335 }
336
baed47c3 337 if (st.st_size < (off_t) sizeof(FSSHeader)) {
0284adc6
LP
338 r = -ENODATA;
339 goto finish;
340 }
341
baed47c3 342 m = mmap(NULL, PAGE_ALIGN(sizeof(FSSHeader)), PROT_READ, MAP_SHARED, fd, 0);
0284adc6
LP
343 if (m == MAP_FAILED) {
344 m = NULL;
345 r = -errno;
346 goto finish;
347 }
348
baed47c3 349 if (memcmp(m->signature, FSS_HEADER_SIGNATURE, 8) != 0) {
0284adc6
LP
350 r = -EBADMSG;
351 goto finish;
352 }
353
354 if (m->incompatible_flags != 0) {
355 r = -EPROTONOSUPPORT;
356 goto finish;
357 }
358
baed47c3 359 if (le64toh(m->header_size) < sizeof(FSSHeader)) {
0284adc6
LP
360 r = -EBADMSG;
361 goto finish;
362 }
363
3e4b9b50 364 if (le64toh(m->fsprg_state_size) != FSPRG_stateinbytes(le16toh(m->fsprg_secpar))) {
0284adc6
LP
365 r = -EBADMSG;
366 goto finish;
367 }
368
baed47c3
LP
369 f->fss_file_size = le64toh(m->header_size) + le64toh(m->fsprg_state_size);
370 if ((uint64_t) st.st_size < f->fss_file_size) {
0284adc6
LP
371 r = -ENODATA;
372 goto finish;
373 }
374
375 if (!sd_id128_equal(machine, m->machine_id)) {
376 r = -EHOSTDOWN;
377 goto finish;
378 }
379
baed47c3
LP
380 if (le64toh(m->start_usec) <= 0 ||
381 le64toh(m->interval_usec) <= 0) {
0284adc6
LP
382 r = -EBADMSG;
383 goto finish;
384 }
385
baed47c3
LP
386 f->fss_file = mmap(NULL, PAGE_ALIGN(f->fss_file_size), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
387 if (f->fss_file == MAP_FAILED) {
388 f->fss_file = NULL;
0284adc6
LP
389 r = -errno;
390 goto finish;
391 }
392
baed47c3
LP
393 f->fss_start_usec = le64toh(f->fss_file->start_usec);
394 f->fss_interval_usec = le64toh(f->fss_file->interval_usec);
b7c9ae91 395
baed47c3
LP
396 f->fsprg_state = (uint8_t*) f->fss_file + le64toh(f->fss_file->header_size);
397 f->fsprg_state_size = le64toh(f->fss_file->fsprg_state_size);
b7c9ae91 398
0284adc6
LP
399 r = 0;
400
401finish:
402 if (m)
baed47c3 403 munmap(m, PAGE_ALIGN(sizeof(FSSHeader)));
0284adc6 404
03e334a1 405 safe_close(fd);
0284adc6 406 free(p);
03e334a1 407
0284adc6
LP
408 return r;
409}
410
baed47c3 411int journal_file_hmac_setup(JournalFile *f) {
0284adc6
LP
412 gcry_error_t e;
413
baed47c3 414 if (!f->seal)
0284adc6
LP
415 return 0;
416
91e023d8 417 initialize_libgcrypt(true);
72fbdd33 418
0284adc6
LP
419 e = gcry_md_open(&f->hmac, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC);
420 if (e != 0)
15411c0c 421 return -EOPNOTSUPP;
0284adc6
LP
422
423 return 0;
424}
425
426int journal_file_append_first_tag(JournalFile *f) {
427 int r;
428 uint64_t p;
429
baed47c3 430 if (!f->seal)
0284adc6
LP
431 return 0;
432
433 log_debug("Calculating first tag...");
434
435 r = journal_file_hmac_put_header(f);
436 if (r < 0)
437 return r;
438
439 p = le64toh(f->header->field_hash_table_offset);
440 if (p < offsetof(Object, hash_table.items))
441 return -EINVAL;
442 p -= offsetof(Object, hash_table.items);
443
5996c7c2 444 r = journal_file_hmac_put_object(f, OBJECT_FIELD_HASH_TABLE, NULL, p);
0284adc6
LP
445 if (r < 0)
446 return r;
447
448 p = le64toh(f->header->data_hash_table_offset);
449 if (p < offsetof(Object, hash_table.items))
450 return -EINVAL;
451 p -= offsetof(Object, hash_table.items);
452
5996c7c2 453 r = journal_file_hmac_put_object(f, OBJECT_DATA_HASH_TABLE, NULL, p);
0284adc6
LP
454 if (r < 0)
455 return r;
456
457 r = journal_file_append_tag(f);
458 if (r < 0)
459 return r;
460
461 return 0;
462}
4da416aa 463
feb12d3e
LP
464int journal_file_parse_verification_key(JournalFile *f, const char *key) {
465 uint8_t *seed;
466 size_t seed_size, c;
467 const char *k;
468 int r;
469 unsigned long long start, interval;
470
471 seed_size = FSPRG_RECOMMENDED_SEEDLEN;
472 seed = malloc(seed_size);
473 if (!seed)
474 return -ENOMEM;
475
476 k = key;
477 for (c = 0; c < seed_size; c++) {
478 int x, y;
479
480 while (*k == '-')
481 k++;
482
483 x = unhexchar(*k);
484 if (x < 0) {
485 free(seed);
486 return -EINVAL;
487 }
488 k++;
489 y = unhexchar(*k);
490 if (y < 0) {
491 free(seed);
492 return -EINVAL;
493 }
494 k++;
495
496 seed[c] = (uint8_t) (x * 16 + y);
497 }
498
499 if (*k != '/') {
500 free(seed);
501 return -EINVAL;
502 }
503 k++;
504
505 r = sscanf(k, "%llx-%llx", &start, &interval);
506 if (r != 2) {
507 free(seed);
508 return -EINVAL;
509 }
510
511 f->fsprg_seed = seed;
512 f->fsprg_seed_size = seed_size;
513
514 f->fss_start_usec = start * interval;
515 f->fss_interval_usec = interval;
516
517 return 0;
4da416aa 518}
89fef990
LP
519
520bool journal_file_next_evolve_usec(JournalFile *f, usec_t *u) {
521 uint64_t epoch;
522
523 assert(f);
524 assert(u);
525
526 if (!f->seal)
527 return false;
528
529 epoch = FSPRG_GetEpoch(f->fsprg_state);
530
531 *u = (usec_t) (f->fss_start_usec + f->fss_interval_usec * epoch + f->fss_interval_usec);
532
533 return true;
534}