#include <unistd.h>
#include <sys/mman.h>
#include <fcntl.h>
+#include <stddef.h>
#include "util.h"
#include "macro.h"
#include "compress.h"
#include "fsprg.h"
-/* FIXME:
- *
- * - write bit mucking test
- * - evolve key even if nothing happened in regular intervals
- *
- * - Allow building without libgcrypt
- * - check with sparse
- * - 64bit conversions
- *
- * */
-
static int journal_file_object_verify(JournalFile *f, Object *o) {
uint64_t i;
return -EBADMSG;
if (le64toh(o->entry.seqnum) <= 0 ||
- le64toh(o->entry.realtime) <= 0)
+ !VALID_REALTIME(le64toh(o->entry.realtime)) ||
+ !VALID_MONOTONIC(le64toh(o->entry.monotonic)))
return -EBADMSG;
for (i = 0; i < journal_file_entry_n_items(o); i++) {
case OBJECT_TAG:
if (le64toh(o->object.size) != sizeof(TagObject))
return -EBADMSG;
+
+ if (!VALID_EPOCH(o->tag.epoch))
+ return -EBADMSG;
+
break;
}
if (*z == p)
return 1;
+ if (a + 1 >= b)
+ return 0;
+
if (p < *z)
b = c;
- else
+ else {
a = c;
+ }
}
return 0;
return 0;
}
-static int journal_file_parse_verification_key(JournalFile *f, const char *key) {
- uint8_t *seed;
- size_t seed_size, c;
- const char *k;
- int r;
- unsigned long long start, interval;
-
- seed_size = FSPRG_RECOMMENDED_SEEDLEN;
- seed = malloc(seed_size);
- if (!seed)
- return -ENOMEM;
-
- k = key;
- for (c = 0; c < seed_size; c++) {
- int x, y;
-
- while (*k == '-')
- k++;
-
- x = unhexchar(*k);
- if (x < 0) {
- free(seed);
- return -EINVAL;
- }
- k++;
- y = unhexchar(*k);
- if (y < 0) {
- free(seed);
- return -EINVAL;
- }
- k++;
-
- seed[c] = (uint8_t) (x * 16 + y);
- }
-
- if (*k != '/') {
- free(seed);
- return -EINVAL;
- }
- k++;
-
- r = sscanf(k, "%llx-%llx", &start, &interval);
- if (r != 2) {
- free(seed);
- return -EINVAL;
- }
-
- f->fsprg_seed = seed;
- f->fsprg_seed_size = seed_size;
-
- f->fss_start_usec = start * interval;
- f->fss_interval_usec = interval;
-
- return 0;
-}
-
int journal_file_verify(
JournalFile *f,
const char *key,
bool show_progress) {
int r;
Object *o;
- uint64_t p = 0, last_tag = 0, last_epoch = 0, last_tag_realtime = 0;
+ uint64_t p = 0, last_tag = 0, last_epoch = 0, last_tag_realtime = 0, last_sealed_realtime = 0;
uint64_t entry_seqnum = 0, entry_monotonic = 0, entry_realtime = 0;
sd_id128_t entry_boot_id;
bool entry_seqnum_set = false, entry_monotonic_set = false, entry_realtime_set = false, found_main_entry_array = false;
assert(f);
if (key) {
+#ifdef HAVE_GCRYPT
r = journal_file_parse_verification_key(f, key);
if (r < 0) {
log_error("Failed to parse seed.");
return r;
}
+#else
+ return -ENOTSUP;
+#endif
} else if (f->seal)
return -ENOKEY;
goto fail;
}
- if (o->object.flags & OBJECT_COMPRESSED &&
- !(le32toh(f->header->incompatible_flags) & HEADER_INCOMPATIBLE_COMPRESSED)) {
+ if ((o->object.flags & OBJECT_COMPRESSED) && !JOURNAL_HEADER_COMPRESSED(f->header)) {
log_error("Compressed object in file without compression at %llu", (unsigned long long) p);
r = -EBADMSG;
goto fail;
break;
case OBJECT_ENTRY:
- if ((le32toh(f->header->compatible_flags) & HEADER_COMPATIBLE_SEALED) && n_tags <= 0) {
+ if (JOURNAL_HEADER_SEALED(f->header) && n_tags <= 0) {
log_error("First entry before first tag at %llu", (unsigned long long) p);
r = -EBADMSG;
goto fail;
if (r < 0)
goto fail;
- if (last_tag_realtime > le64toh(o->entry.realtime)) {
+ if (le64toh(o->entry.realtime) < last_tag_realtime) {
log_error("Older entry after newer tag at %llu", (unsigned long long) p);
r = -EBADMSG;
goto fail;
n_entry_arrays++;
break;
- case OBJECT_TAG: {
- uint64_t q, rt;
-
- if (!(le32toh(f->header->compatible_flags) & HEADER_COMPATIBLE_SEALED)) {
+ case OBJECT_TAG:
+ if (!JOURNAL_HEADER_SEALED(f->header)) {
log_error("Tag object in file without sealing at %llu", (unsigned long long) p);
r = -EBADMSG;
goto fail;
goto fail;
}
+#ifdef HAVE_GCRYPT
if (f->seal) {
+ uint64_t q, rt;
+
log_debug("Checking tag %llu..", (unsigned long long) le64toh(o->tag.seqnum));
- rt = (o->tag.epoch + 1) * f->fss_interval_usec + f->fss_start_usec;
- if (entry_realtime_set && entry_realtime >= rt) {
+ rt = f->fss_start_usec + o->tag.epoch * f->fss_interval_usec;
+ if (entry_realtime_set && entry_realtime >= rt + f->fss_interval_usec) {
log_error("Tag/entry realtime timestamp out of synchronization at %llu", (unsigned long long) p);
r = -EBADMSG;
goto fail;
f->hmac_running = false;
last_tag_realtime = rt;
+ last_sealed_realtime = entry_realtime;
}
+#endif
last_tag = p + ALIGN64(le64toh(o->object.size));
last_epoch = le64toh(o->tag.epoch);
n_tags ++;
break;
- }
default:
n_weird ++;
if (first_validated)
*first_validated = last_tag_realtime ? le64toh(f->header->head_entry_realtime) : 0;
if (last_validated)
- *last_validated = last_tag_realtime;
+ *last_validated = last_sealed_realtime;
if (last_contained)
*last_contained = le64toh(f->header->tail_entry_realtime);