journal-authenticate.c revision 3e4b9b506d676d1cb8692306b38c05f8529e5cdb
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering This file is part of systemd.
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering Copyright 2012 Lennart Poettering
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering systemd is free software; you can redistribute it and/or modify it
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering under the terms of the GNU Lesser General Public License as published by
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering the Free Software Foundation; either version 2.1 of the License, or
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering (at your option) any later version.
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering systemd is distributed in the hope that it will be useful, but
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering Lesser General Public License for more details.
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering You should have received a copy of the GNU Lesser General Public License
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic uint64_t journal_file_tag_seqnum(JournalFile *f) {
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringint journal_file_append_tag(JournalFile *f) {
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering r = journal_file_append_object(f, OBJECT_TAG, sizeof(struct TagObject), &o, &p);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering o->tag.seqnum = htole64(journal_file_tag_seqnum(f));
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering o->tag.epoch = htole64(FSPRG_GetEpoch(f->fsprg_state));
e627440b41bb0284e4892f7aa9d84c77972487e2Lennart Poettering log_debug("Writing tag %llu for epoch %llu\n",
e627440b41bb0284e4892f7aa9d84c77972487e2Lennart Poettering (unsigned long long) le64toh(o->tag.seqnum),
e627440b41bb0284e4892f7aa9d84c77972487e2Lennart Poettering (unsigned long long) FSPRG_GetEpoch(f->fsprg_state));
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering /* Add the tag object itself, so that we can protect its
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering * header. This will exclude the actual hash value in it */
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering r = journal_file_hmac_put_object(f, OBJECT_TAG, p);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering /* Get the HMAC tag and store it in the object */
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering memcpy(o->tag.tag, gcry_md_read(f->hmac, 0), TAG_LENGTH);
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poetteringint journal_file_hmac_start(JournalFile *f) {
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering uint8_t key[256 / 8]; /* Let's pass 256 bit from FSPRG to HMAC */
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering /* Prepare HMAC for next cycle */
b7c9ae91d111b3e89d1ffc00e08f9ed97a8ff5dbLennart Poettering FSPRG_GetKey(f->fsprg_state, key, sizeof(key), 0);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering gcry_md_setkey(f->hmac, key, sizeof(key));
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic int journal_file_get_epoch(JournalFile *f, uint64_t realtime, uint64_t *epoch) {
baed47c3c20512507e497058d388782400a072f6Lennart Poetteringstatic int journal_file_fsprg_need_evolve(JournalFile *f, uint64_t realtime) {
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering r = journal_file_get_epoch(f, realtime, &goal);
baed47c3c20512507e497058d388782400a072f6Lennart Poetteringint journal_file_fsprg_evolve(JournalFile *f, uint64_t realtime) {
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering r = journal_file_get_epoch(f, realtime, &goal);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering log_debug("Evolving FSPRG key from epoch %llu to %llu.", (unsigned long long) epoch, (unsigned long long) goal);
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poetteringint journal_file_fsprg_seek(JournalFile *f, uint64_t goal) {
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering /* Cheaper... */
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering f->fsprg_state_size = FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR);
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering f->fsprg_state = malloc(f->fsprg_state_size);
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering log_debug("Seeking FSPRG key to %llu.", (unsigned long long) goal);
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering msk = alloca(FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR));
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering FSPRG_GenMK(msk, NULL, f->fsprg_seed, f->fsprg_seed_size, FSPRG_RECOMMENDED_SECPAR);
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering FSPRG_Seek(f->fsprg_state, goal, msk, f->fsprg_seed, f->fsprg_seed_size);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringint journal_file_maybe_append_tag(JournalFile *f, uint64_t realtime) {
baed47c3c20512507e497058d388782400a072f6Lennart Poettering r = journal_file_fsprg_need_evolve(f, realtime);
baed47c3c20512507e497058d388782400a072f6Lennart Poettering r = journal_file_fsprg_evolve(f, realtime);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringint journal_file_hmac_put_object(JournalFile *f, int type, uint64_t p) {
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering r = journal_file_move_to_object(f, type, p, &o);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering gcry_md_write(f->hmac, o, offsetof(ObjectHeader, payload));
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering /* All but hash and payload are mutable */
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering gcry_md_write(f->hmac, &o->data.hash, sizeof(o->data.hash));
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering gcry_md_write(f->hmac, o->data.payload, le64toh(o->object.size) - offsetof(DataObject, payload));
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering gcry_md_write(f->hmac, &o->entry.seqnum, le64toh(o->object.size) - offsetof(EntryObject, seqnum));
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering /* Nothing: everything is mutable */
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering /* All but the tag itself */
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering gcry_md_write(f->hmac, &o->tag.seqnum, sizeof(o->tag.seqnum));
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering gcry_md_write(f->hmac, &o->tag.epoch, sizeof(o->tag.epoch));
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringint journal_file_hmac_put_header(JournalFile *f) {
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering /* All but state+reserved, boot_id, arena_size,
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering * tail_object_offset, n_objects, n_entries,
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering * tail_entry_seqnum, head_entry_seqnum, entry_array_offset,
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering * head_entry_realtime, tail_entry_realtime,
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering * tail_entry_monotonic, n_data, n_fields, n_tags,
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering * n_entry_arrays. */
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering gcry_md_write(f->hmac, f->header->signature, offsetof(Header, state) - offsetof(Header, signature));
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering gcry_md_write(f->hmac, &f->header->file_id, offsetof(Header, boot_id) - offsetof(Header, file_id));
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering gcry_md_write(f->hmac, &f->header->seqnum_id, offsetof(Header, arena_size) - offsetof(Header, seqnum_id));
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering gcry_md_write(f->hmac, &f->header->data_hash_table_offset, offsetof(Header, tail_object_offset) - offsetof(Header, data_hash_table_offset));
baed47c3c20512507e497058d388782400a072f6Lennart Poetteringint journal_file_fss_load(JournalFile *f) {
baed47c3c20512507e497058d388782400a072f6Lennart Poettering if (asprintf(&p, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss",
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering fd = open(p, O_RDWR|O_CLOEXEC|O_NOCTTY, 0600);
baed47c3c20512507e497058d388782400a072f6Lennart Poettering if (st.st_size < (off_t) sizeof(FSSHeader)) {
baed47c3c20512507e497058d388782400a072f6Lennart Poettering m = mmap(NULL, PAGE_ALIGN(sizeof(FSSHeader)), PROT_READ, MAP_SHARED, fd, 0);
baed47c3c20512507e497058d388782400a072f6Lennart Poettering if (memcmp(m->signature, FSS_HEADER_SIGNATURE, 8) != 0) {
baed47c3c20512507e497058d388782400a072f6Lennart Poettering if (le64toh(m->header_size) < sizeof(FSSHeader)) {
3e4b9b506d676d1cb8692306b38c05f8529e5cdbLennart Poettering if (le64toh(m->fsprg_state_size) != FSPRG_stateinbytes(le16toh(m->fsprg_secpar))) {
baed47c3c20512507e497058d388782400a072f6Lennart Poettering f->fss_file_size = le64toh(m->header_size) + le64toh(m->fsprg_state_size);
baed47c3c20512507e497058d388782400a072f6Lennart Poettering if ((uint64_t) st.st_size < f->fss_file_size) {
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering if (!sd_id128_equal(machine, m->machine_id)) {
baed47c3c20512507e497058d388782400a072f6Lennart Poettering f->fss_file = mmap(NULL, PAGE_ALIGN(f->fss_file_size), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
baed47c3c20512507e497058d388782400a072f6Lennart Poettering f->fss_start_usec = le64toh(f->fss_file->start_usec);
baed47c3c20512507e497058d388782400a072f6Lennart Poettering f->fss_interval_usec = le64toh(f->fss_file->interval_usec);
baed47c3c20512507e497058d388782400a072f6Lennart Poettering f->fsprg_state = (uint8_t*) f->fss_file + le64toh(f->fss_file->header_size);
baed47c3c20512507e497058d388782400a072f6Lennart Poettering f->fsprg_state_size = le64toh(f->fss_file->fsprg_state_size);
baed47c3c20512507e497058d388782400a072f6Lennart Poettering munmap(m, PAGE_ALIGN(sizeof(FSSHeader)));
baed47c3c20512507e497058d388782400a072f6Lennart Poetteringint journal_file_hmac_setup(JournalFile *f) {
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering e = gcry_md_open(&f->hmac, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringint journal_file_append_first_tag(JournalFile *f) {
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering p = le64toh(f->header->field_hash_table_offset);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering if (p < offsetof(Object, hash_table.items))
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering r = journal_file_hmac_put_object(f, OBJECT_FIELD_HASH_TABLE, p);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering p = le64toh(f->header->data_hash_table_offset);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering if (p < offsetof(Object, hash_table.items))
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering r = journal_file_hmac_put_object(f, OBJECT_DATA_HASH_TABLE, p);
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poetteringint journal_file_parse_verification_key(JournalFile *f, const char *key) {
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering const char *k;
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering for (c = 0; c < seed_size; c++) {
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering while (*k == '-')
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering if (*k != '/') {
feb12d3ed2c7f9132c64773c7c41b9e3a608a814Lennart Poettering r = sscanf(k, "%llx-%llx", &start, &interval);