From: Yu Watanabe Date: Mon, 22 Jun 2026 07:34:35 +0000 (+0900) Subject: journal: replace gcrypt with openssl X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=005e94da1786b410cf8b56c8220d5e084957bca5;p=thirdparty%2Fsystemd.git journal: replace gcrypt with openssl --- diff --git a/src/journal/journalctl-authenticate.c b/src/journal/journalctl-authenticate.c index 721404a1f53..73c1579b88f 100644 --- a/src/journal/journalctl-authenticate.c +++ b/src/journal/journalctl-authenticate.c @@ -7,11 +7,11 @@ #include "alloc-util.h" #include "ansi-color.h" #include "chattr-util.h" +#include "crypto-util.h" #include "errno-util.h" #include "fd-util.h" #include "fs-util.h" -#include "fsprg.h" -#include "gcrypt-util.h" +#include "fsprg-openssl.h" #include "hostname-setup.h" #include "hostname-util.h" #include "io-util.h" @@ -30,7 +30,7 @@ #include "time-util.h" #include "tmpfile-util.h" -#if HAVE_GCRYPT +#if HAVE_OPENSSL static int format_key( const struct iovec *seed, uint64_t start, @@ -60,7 +60,7 @@ static int format_key( #endif int action_setup_keys(void) { -#if HAVE_GCRYPT +#if HAVE_OPENSSL _cleanup_(unlink_and_freep) char *tmpfile = NULL; _cleanup_close_ int fd = -EBADF; _cleanup_free_ char *path = NULL; @@ -70,7 +70,7 @@ int action_setup_keys(void) { assert(arg_action == ACTION_SETUP_KEYS); - r = DLOPEN_GCRYPT(LOG_ERR, SD_ELF_NOTE_DLOPEN_PRIORITY_RECOMMENDED); + r = DLOPEN_LIBCRYPTO(LOG_ERR, SD_ELF_NOTE_DLOPEN_PRIORITY_RECOMMENDED); if (r < 0) return r; @@ -103,9 +103,8 @@ int action_setup_keys(void) { "Sealing key file %s exists already. Use --force to recreate.", path); _cleanup_(iovec_erase) struct iovec - mpk = IOVEC_ALLOCA(FSPRG_mpkinbytes(FSPRG_RECOMMENDED_SECPAR)), seed = IOVEC_ALLOCA(FSPRG_RECOMMENDED_SEEDLEN), - state = IOVEC_ALLOCA(FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR)); + state = IOVEC_ALLOCA(fsprg_state_size(FSPRG_RECOMMENDED_SECPAR)); if (!arg_quiet) log_info("Generating seed..."); @@ -113,15 +112,9 @@ int action_setup_keys(void) { if (r < 0) return log_error_errno(r, "Failed to acquire random seed: %m"); - if (!arg_quiet) - log_info("Generating key pair..."); - r = FSPRG_GenMK(NULL, mpk.iov_base, seed.iov_base, seed.iov_len, FSPRG_RECOMMENDED_SECPAR); - if (r < 0) - return log_error_errno(r, "Failed to generate key pair: %m"); - if (!arg_quiet) log_info("Generating sealing key..."); - r = FSPRG_GenState0(state.iov_base, mpk.iov_base, seed.iov_base, seed.iov_len); + r = fsprg_generate_state(FSPRG_RECOMMENDED_SECPAR, /* epoch= */ 0, &seed, &state); if (r < 0) return log_error_errno(r, "Failed to generate sealing key: %m"); diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c index b5c4ec7aeef..3ee4da9013b 100644 --- a/src/journal/journalctl.c +++ b/src/journal/journalctl.c @@ -81,7 +81,7 @@ bool arg_file_stdin = false; int arg_priorities = 0; Set *arg_facilities = NULL; char *arg_verify_key = NULL; -#if HAVE_GCRYPT +#if HAVE_OPENSSL usec_t arg_interval = DEFAULT_FSS_INTERVAL_USEC; bool arg_force = false; #endif @@ -769,7 +769,7 @@ static int parse_argv(int argc, char *argv[], char ***remaining_args) { OPTION_GROUP("Forward Secure Sealing (FSS) Options"): {} OPTION_LONG("interval", "TIME", "Time interval for changing the FSS sealing key"): -#if HAVE_GCRYPT +#if HAVE_OPENSSL r = parse_sec(opts.arg, &arg_interval); if (r < 0 || arg_interval <= 0) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), @@ -781,7 +781,7 @@ static int parse_argv(int argc, char *argv[], char ***remaining_args) { #endif OPTION_LONG("verify-key", "KEY", "Specify FSS verification key"): -#if HAVE_GCRYPT +#if HAVE_OPENSSL erase_and_free(arg_verify_key); arg_verify_key = strdup(opts.arg); if (!arg_verify_key) @@ -800,7 +800,7 @@ static int parse_argv(int argc, char *argv[], char ***remaining_args) { #endif OPTION_LONG("force", NULL, "Override of the FSS key pair with --setup-keys"): -#if HAVE_GCRYPT +#if HAVE_OPENSSL arg_force = true; break; #else @@ -909,7 +909,7 @@ static int parse_argv(int argc, char *argv[], char ***remaining_args) { break; OPTION_LONG("setup-keys", NULL, "Generate a new FSS key pair"): -#if HAVE_GCRYPT +#if HAVE_OPENSSL arg_action = ACTION_SETUP_KEYS; break; #else diff --git a/src/journal/journalctl.h b/src/journal/journalctl.h index 406a16077be..504e5e6dd11 100644 --- a/src/journal/journalctl.h +++ b/src/journal/journalctl.h @@ -57,7 +57,7 @@ extern bool arg_file_stdin; extern int arg_priorities; extern Set *arg_facilities; extern char *arg_verify_key; -#if HAVE_GCRYPT +#if HAVE_OPENSSL extern usec_t arg_interval; extern bool arg_force; #endif diff --git a/src/journal/meson.build b/src/journal/meson.build index 38f2e7bb7ed..e39381f03f6 100644 --- a/src/journal/meson.build +++ b/src/journal/meson.build @@ -94,6 +94,7 @@ executables += [ 'link_with' : journalctl_link_with, 'dependencies' : [ liblz4_cflags, + libopenssl_cflags, libxz_cflags, libzstd_cflags, ], diff --git a/src/shared/journal-authenticate.c b/src/shared/journal-authenticate.c index ea582f41b1a..20434c9b0b2 100644 --- a/src/shared/journal-authenticate.c +++ b/src/shared/journal-authenticate.c @@ -5,9 +5,9 @@ #include #include "alloc-util.h" +#include "crypto-util.h" #include "fd-util.h" -#include "fsprg.h" -#include "gcrypt-util.h" +#include "fsprg-openssl.h" #include "hexdecoct.h" #include "iovec-util.h" #include "journal-authenticate.h" @@ -18,10 +18,12 @@ #include "string-util.h" #include "time-util.h" -#if HAVE_GCRYPT +#if HAVE_OPENSSL struct JournalAuthContext { - gcry_md_hd_t hmac; + EVP_MAC *hmac; + EVP_MAC_CTX *hmac_ctx; + OSSL_PARAM *ossl_params; bool hmac_running; FSSHeader *fss_file; @@ -45,8 +47,12 @@ static JournalAuthContext* journal_auth_free(JournalAuthContext *c) { iovec_done_erase(&c->fsprg_seed); + if (c->ossl_params) + sym_OSSL_PARAM_free(c->ossl_params); + if (c->hmac_ctx) + sym_EVP_MAC_CTX_free(c->hmac_ctx); if (c->hmac) - sym_gcry_md_close(c->hmac); + sym_EVP_MAC_free(c->hmac); return mfree(c); } @@ -111,7 +117,11 @@ static int journal_auth_load(JournalAuthContext **ret) { if (le64toh(header->header_size) < sizeof(FSSHeader)) return -EBADMSG; - if (le64toh(header->fsprg_state_size) != FSPRG_stateinbytes(le16toh(header->fsprg_secpar))) + uint16_t secpar = le16toh(header->fsprg_secpar); + if (!fsprg_secpar_is_valid(secpar)) + return -EBADMSG; + + if (le64toh(header->fsprg_state_size) != fsprg_state_size(secpar)) return -EBADMSG; uint64_t fss_file_size; @@ -239,9 +249,14 @@ static int journal_auth_epoch_to_realtime_usec(const JournalAuthContext *c, uint } static int journal_auth_next_evolve_usec(const JournalAuthContext *c, usec_t *ret) { + int r; + assert(c); - uint64_t epoch = FSPRG_GetEpoch(c->fsprg_state.iov_base); + uint64_t epoch; + r = fsprg_get_epoch(&c->fsprg_state, &epoch); + if (r < 0) + return r; return journal_auth_epoch_to_realtime_usec(c, epoch, /* ret_start= */ NULL, ret); } @@ -253,26 +268,23 @@ static int journal_auth_seek(JournalAuthContext *c, uint64_t goal) { assert(iovec_is_set(&c->fsprg_seed)); if (iovec_is_set(&c->fsprg_state)) { - uint64_t epoch = FSPRG_GetEpoch(c->fsprg_state.iov_base); + uint64_t epoch; + r = fsprg_get_epoch(&c->fsprg_state, &epoch); + if (r < 0) + return r; if (goal == epoch) return 0; if (goal == epoch + 1) - return FSPRG_Evolve(c->fsprg_state.iov_base); + return fsprg_evolve(&c->fsprg_state); } else { - r = iovec_alloc(FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR), &c->fsprg_state); + r = iovec_alloc(fsprg_state_size(FSPRG_RECOMMENDED_SECPAR), &c->fsprg_state); if (r < 0) return r; } log_debug("Seeking FSPRG key to %"PRIu64".", goal); - - _cleanup_(iovec_erase) struct iovec msk = IOVEC_ALLOCA(FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR)); - r = FSPRG_GenMK(msk.iov_base, NULL, c->fsprg_seed.iov_base, c->fsprg_seed.iov_len, FSPRG_RECOMMENDED_SECPAR); - if (r < 0) - return r; - - return FSPRG_Seek(c->fsprg_state.iov_base, goal, msk.iov_base, c->fsprg_seed.iov_base, c->fsprg_seed.iov_len); + return fsprg_generate_state(FSPRG_RECOMMENDED_SECPAR, goal, &c->fsprg_seed, &c->fsprg_state); } static int journal_auth_setup(JournalAuthContext *c) { @@ -283,13 +295,32 @@ static int journal_auth_setup(JournalAuthContext *c) { if (c->hmac) return 0; - r = initialize_libgcrypt(true); + r = dlopen_libcrypto(LOG_DEBUG); if (r < 0) return r; - if (sym_gcry_md_open(&c->hmac, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC) != 0) - return -EOPNOTSUPP; + _cleanup_(EVP_MAC_freep) EVP_MAC *hmac = sym_EVP_MAC_fetch(NULL, "HMAC", NULL); + if (!hmac) + return log_openssl_errors(LOG_DEBUG, "EVP_MAC_fetch() failed"); + + _cleanup_(EVP_MAC_CTX_freep) EVP_MAC_CTX *ctx = sym_EVP_MAC_CTX_new(hmac); + if (!ctx) + return log_openssl_errors(LOG_DEBUG, "EVP_MAC_CTX_new() failed"); + + _cleanup_(OSSL_PARAM_BLD_freep) OSSL_PARAM_BLD *bld = sym_OSSL_PARAM_BLD_new(); + if (!bld) + return log_openssl_errors(LOG_DEBUG, "OSSL_PARAM_BLD_new() failed"); + if (sym_OSSL_PARAM_BLD_push_utf8_string(bld, OSSL_MAC_PARAM_DIGEST, "SHA256", 0) <= 0) + return log_openssl_errors(LOG_DEBUG, "OSSL_PARAM_BLD_push_utf8_string() failed"); + + _cleanup_(OSSL_PARAM_freep) OSSL_PARAM *params = sym_OSSL_PARAM_BLD_to_param(bld); + if (!params) + return log_openssl_errors(LOG_DEBUG, "OSSL_PARAM_BLD_to_param() failed"); + + c->hmac = TAKE_PTR(hmac); + c->hmac_ctx = TAKE_PTR(ctx); + c->ossl_params = TAKE_PTR(params); return 0; } @@ -305,20 +336,15 @@ static int journal_auth_start(JournalAuthContext *c) { if (r < 0) return r; - /* Prepare HMAC for next cycle */ - sym_gcry_md_reset(c->hmac); - uint8_t key[256 / 8]; /* Let's pass 256 bit from FSPRG to HMAC */ CLEANUP_ERASE(key); - r = FSPRG_GetKey(c->fsprg_state.iov_base, key, sizeof(key), 0); + r = fsprg_get_key(&c->fsprg_state, &IOVEC_MAKE(key, sizeof(key))); if (r < 0) return r; - gcry_error_t err = sym_gcry_md_setkey(c->hmac, key, sizeof(key)); - if (gcry_err_code(err) != GPG_ERR_NO_ERROR) - return log_debug_errno(SYNTHETIC_ERRNO(EIO), - "sym_gcry_md_setkey() failed with error code: %s", - sym_gcry_strerror(err)); + /* Prepare HMAC for next cycle */ + if (sym_EVP_MAC_init(c->hmac_ctx, key, sizeof(key), c->ossl_params) <= 0) + return log_openssl_errors(LOG_DEBUG, "sym_EVP_MAC_init() failed"); c->hmac_running = true; return 0; @@ -331,8 +357,16 @@ static int journal_auth_end(JournalAuthContext *c, uint8_t ret[static TAG_LENGTH if (!c->hmac_running) return -EINVAL; - memcpy(ret, sym_gcry_md_read(c->hmac, 0), TAG_LENGTH); c->hmac_running = false; + + uint8_t tag[TAG_LENGTH]; + CLEANUP_ERASE(tag); + + size_t len; + if (sym_EVP_MAC_final(c->hmac_ctx, tag, &len, TAG_LENGTH) <= 0 || len != TAG_LENGTH) + return -EIO; + + memcpy(ret, tag, TAG_LENGTH); return 0; } @@ -353,10 +387,14 @@ static int journal_auth_put_header(JournalAuthContext *c, JournalFile *f) { * tail_entry_monotonic, n_data, n_fields, n_tags, * n_entry_arrays. */ - sym_gcry_md_write(c->hmac, f->header->signature, offsetof(Header, state) - offsetof(Header, signature)); - sym_gcry_md_write(c->hmac, &f->header->file_id, offsetof(Header, tail_entry_boot_id) - offsetof(Header, file_id)); - sym_gcry_md_write(c->hmac, &f->header->seqnum_id, offsetof(Header, arena_size) - offsetof(Header, seqnum_id)); - sym_gcry_md_write(c->hmac, &f->header->data_hash_table_offset, offsetof(Header, tail_object_offset) - offsetof(Header, data_hash_table_offset)); + if (sym_EVP_MAC_update(c->hmac_ctx, f->header->signature, offsetof(Header, state) - offsetof(Header, signature)) <= 0) + return -EIO; + if (sym_EVP_MAC_update(c->hmac_ctx, (void*) &f->header->file_id, offsetof(Header, tail_entry_boot_id) - offsetof(Header, file_id)) <= 0) + return -EIO; + if (sym_EVP_MAC_update(c->hmac_ctx, (void*) &f->header->seqnum_id, offsetof(Header, arena_size) - offsetof(Header, seqnum_id)) <= 0) + return -EIO; + if (sym_EVP_MAC_update(c->hmac_ctx, (void*) &f->header->data_hash_table_offset, offsetof(Header, tail_object_offset) - offsetof(Header, data_hash_table_offset)) <= 0) + return -EIO; return 0; } @@ -378,25 +416,31 @@ static int journal_auth_put_object(JournalAuthContext *c, JournalFile *f, Object } else if (type > OBJECT_UNUSED && o->object.type != type) return -EBADMSG; - sym_gcry_md_write(c->hmac, o, offsetof(ObjectHeader, payload)); + if (sym_EVP_MAC_update(c->hmac_ctx, (void*) o, offsetof(ObjectHeader, payload)) <= 0) + return -EIO; switch (o->object.type) { case OBJECT_DATA: /* All but hash and payload are mutable */ - sym_gcry_md_write(c->hmac, &o->data.hash, sizeof(o->data.hash)); - sym_gcry_md_write(c->hmac, journal_file_data_payload_field(f, o), le64toh(o->object.size) - journal_file_data_payload_offset(f)); + if (sym_EVP_MAC_update(c->hmac_ctx, (void*) &o->data.hash, sizeof(o->data.hash)) <= 0) + return -EIO; + if (sym_EVP_MAC_update(c->hmac_ctx, journal_file_data_payload_field(f, o), le64toh(o->object.size) - journal_file_data_payload_offset(f)) <= 0) + return -EIO; break; case OBJECT_FIELD: /* Same here */ - sym_gcry_md_write(c->hmac, &o->field.hash, sizeof(o->field.hash)); - sym_gcry_md_write(c->hmac, o->field.payload, le64toh(o->object.size) - offsetof(Object, field.payload)); + if (sym_EVP_MAC_update(c->hmac_ctx, (void*) &o->field.hash, sizeof(o->field.hash)) <= 0) + return -EIO; + if (sym_EVP_MAC_update(c->hmac_ctx, o->field.payload, le64toh(o->object.size) - offsetof(Object, field.payload)) <= 0) + return -EIO; break; case OBJECT_ENTRY: /* All */ - sym_gcry_md_write(c->hmac, &o->entry.seqnum, le64toh(o->object.size) - offsetof(Object, entry.seqnum)); + if (sym_EVP_MAC_update(c->hmac_ctx, (void*) &o->entry.seqnum, le64toh(o->object.size) - offsetof(Object, entry.seqnum)) <= 0) + return -EIO; break; case OBJECT_FIELD_HASH_TABLE: @@ -407,8 +451,10 @@ static int journal_auth_put_object(JournalAuthContext *c, JournalFile *f, Object case OBJECT_TAG: /* All but the tag itself */ - sym_gcry_md_write(c->hmac, &o->tag.seqnum, sizeof(o->tag.seqnum)); - sym_gcry_md_write(c->hmac, &o->tag.epoch, sizeof(o->tag.epoch)); + if (sym_EVP_MAC_update(c->hmac_ctx, (void*) &o->tag.seqnum, sizeof(o->tag.seqnum)) <= 0) + return -EIO; + if (sym_EVP_MAC_update(c->hmac_ctx, (void*) &o->tag.epoch, sizeof(o->tag.epoch)) <= 0) + return -EIO; break; default: return -EINVAL; @@ -437,10 +483,15 @@ static int journal_auth_append_tag(JournalAuthContext *c, JournalFile *f) { f->header->n_tags = htole64(seqnum); o->tag.seqnum = htole64(seqnum); - o->tag.epoch = htole64(FSPRG_GetEpoch(c->fsprg_state.iov_base)); + + uint64_t epoch; + r = fsprg_get_epoch(&c->fsprg_state, &epoch); + if (r < 0) + return r; + o->tag.epoch = htole64(epoch); log_debug("Writing tag %"PRIu64" for epoch %"PRIu64"", - le64toh(o->tag.seqnum), le64toh(o->tag.epoch)); + le64toh(o->tag.seqnum), epoch); /* Add the tag object itself, so that we can protect its * header. This will exclude the actual hash value in it */ @@ -500,7 +551,10 @@ static int journal_auth_append_tag_maybe(JournalAuthContext *c, JournalFile *f, uint64_t goal = usec_sub_unsigned(realtime, c->fss_start_usec) / c->fss_interval_usec; for (;;) { - uint64_t epoch = FSPRG_GetEpoch(c->fsprg_state.iov_base); + uint64_t epoch; + r = fsprg_get_epoch(&c->fsprg_state, &epoch); + if (r < 0) + return r; if (epoch >= goal) return 0; @@ -508,7 +562,7 @@ static int journal_auth_append_tag_maybe(JournalAuthContext *c, JournalFile *f, if (r < 0) return r; - r = FSPRG_Evolve(c->fsprg_state.iov_base); + r = fsprg_evolve(&c->fsprg_state); if (r < 0) return r; } @@ -539,4 +593,4 @@ void journal_auth_init(void) { void journal_auth_init(void) { } -#endif /* HAVE_GCRYPT */ +#endif /* HAVE_OPENSSL */ diff --git a/src/test/meson.build b/src/test/meson.build index 7970dc89506..ff0572fa089 100644 --- a/src/test/meson.build +++ b/src/test/meson.build @@ -344,7 +344,7 @@ executables += [ libgcrypt_cflags, libopenssl_cflags, ], - 'conditions' : ['HAVE_GCRYPT'], + 'conditions' : ['HAVE_OPENSSL'], }, test_template + { 'sources' : files( diff --git a/test/units/TEST-04-JOURNAL.fss.sh b/test/units/TEST-04-JOURNAL.fss.sh index 50f0608280e..b3f27195a75 100755 --- a/test/units/TEST-04-JOURNAL.fss.sh +++ b/test/units/TEST-04-JOURNAL.fss.sh @@ -5,8 +5,8 @@ set -o pipefail # Forward Secure Sealing -if ! journalctl --version | grep -F +GCRYPT >/dev/null; then - echo "Built without gcrypt, skipping the FSS tests" +if ! journalctl --version | grep -F +OPENSSL >/dev/null; then + echo "Built without openssl, skipping the FSS tests" exit 0 fi