]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
journal: replace gcrypt with openssl
authorYu Watanabe <watanabe.yu+github@gmail.com>
Mon, 22 Jun 2026 07:34:35 +0000 (16:34 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Sat, 27 Jun 2026 15:26:56 +0000 (00:26 +0900)
src/journal/journalctl-authenticate.c
src/journal/journalctl.c
src/journal/journalctl.h
src/journal/meson.build
src/shared/journal-authenticate.c
src/test/meson.build
test/units/TEST-04-JOURNAL.fss.sh

index 721404a1f53f08715da3310b1fe1c3edaf0d8698..73c1579b88fed90eeaa2fcbad2a1963879b5a68b 100644 (file)
@@ -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");
 
index b5c4ec7aeefcc7658e3c473218c24bed7557d5d7..3ee4da9013b41106efe441a8586514092c559342 100644 (file)
@@ -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
index 406a16077be0f714ebd2e1f8829566cc9dbdaed9..504e5e6dd111598be87c5d89b3913b2fd0310962 100644 (file)
@@ -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
index 38f2e7bb7ed1dee855c5535f1ad3b0454dd693ab..e39381f03f63323924fc460486626ea1cd86e3ed 100644 (file)
@@ -94,6 +94,7 @@ executables += [
                 'link_with' : journalctl_link_with,
                 'dependencies' : [
                         liblz4_cflags,
+                        libopenssl_cflags,
                         libxz_cflags,
                         libzstd_cflags,
                 ],
index ea582f41b1ac8fd45175bbb50d7394742c86dea8..20434c9b0b2758ee8de84915ee98451f3da06113 100644 (file)
@@ -5,9 +5,9 @@
 #include <sys/stat.h>
 
 #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"
 #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 */
index 7970dc89506bdc9054675771e63b4f0886a937d8..ff0572fa0896d7395fdd590e0d1532069e5319ee 100644 (file)
@@ -344,7 +344,7 @@ executables += [
                         libgcrypt_cflags,
                         libopenssl_cflags,
                 ],
-                'conditions' : ['HAVE_GCRYPT'],
+                'conditions' : ['HAVE_OPENSSL'],
         },
         test_template + {
                 'sources' : files(
index 50f0608280e37f38e3ac1de8dbfa20e905121c82..b3f27195a7596e0ad31d902f3c2d396d7365b9c7 100755 (executable)
@@ -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