diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 8986b7fa92..dfc4eedc15 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -193,8 +193,10 @@ jobs: pre-checkout-setup: | apt-get update apt-get install -y git + extra-packages: >- + libssl-dev configure-options: >- - --with-composefs + --with-composefs --with-crypto=openssl # A build using libsoup3. After bookworm is released, this can # be switched to Debian Stable. diff --git a/Makefile-otutil.am b/Makefile-otutil.am index 79a9d3da89..291a2e807b 100644 --- a/Makefile-otutil.am +++ b/Makefile-otutil.am @@ -52,5 +52,5 @@ libotutil_la_SOURCES += \ $(NULL) endif -libotutil_la_CFLAGS = $(AM_CFLAGS) -I$(srcdir)/libglnx -I$(srcdir)/src/libotutil -DLOCALEDIR=\"$(datadir)/locale\" $(OT_INTERNAL_GIO_UNIX_CFLAGS) $(OT_INTERNAL_GPGME_CFLAGS) $(LIBSYSTEMD_CFLAGS) -libotutil_la_LIBADD = $(OT_INTERNAL_GIO_UNIX_LIBS) $(OT_INTERNAL_GPGME_LIBS) $(LIBSYSTEMD_LIBS) +libotutil_la_CFLAGS = $(AM_CFLAGS) -I$(srcdir)/libglnx -I$(srcdir)/src/libotutil -DLOCALEDIR=\"$(datadir)/locale\" $(OT_INTERNAL_GIO_UNIX_CFLAGS) $(OT_INTERNAL_GPGME_CFLAGS) $(OT_DEP_CRYPTO_LIBS) $(LIBSYSTEMD_CFLAGS) +libotutil_la_LIBADD = $(OT_INTERNAL_GIO_UNIX_LIBS) $(OT_INTERNAL_GPGME_LIBS) $(LIBSYSTEMD_LIBS) $(OT_DEP_CRYPTO_LIBS) diff --git a/configure.ac b/configure.ac index 723d2719cd..5eb7367e3c 100644 --- a/configure.ac +++ b/configure.ac @@ -311,7 +311,6 @@ AS_IF([test x$with_ed25519_libsodium != xno], [ AS_IF([ test x$have_libsodium = xno ], [ AC_MSG_ERROR([Need LIBSODIUM version $LIBSODIUM_DEPENDENCY or later]) ]) - OSTREE_FEATURES="$OSTREE_FEATURES sign-ed25519" ], with_ed25519_libsodium=no ) AM_CONDITIONAL(USE_LIBSODIUM, test "x$have_libsodium" = xyes) @@ -450,6 +449,11 @@ if test x$with_openssl != xno; then OSTREE_FEATURES="$OSTREE_FEATURES openssl"; AM_CONDITIONAL(USE_OPENSSL, test $with_openssl != no) dnl end openssl +if test x$with_openssl != xno || test x$with_ed25519_libsodium != xno; then + AC_DEFINE([HAVE_ED25519], 1, [Define if ed25519 is supported ]) + OSTREE_FEATURES="$OSTREE_FEATURES sign-ed25519" +fi + dnl begin gnutls; in contrast to openssl this one only dnl supports --with-crypto=gnutls GNUTLS_DEPENDENCY="gnutls >= 3.5.0" @@ -684,6 +688,7 @@ echo " systemd: $with_libsystemd libmount: $with_libmount libsodium (ed25519 signatures): $with_ed25519_libsodium + openssl (ed25519 signatures): $with_openssl libarchive (parse tar files directly): $with_libarchive static deltas: yes (always enabled now) O_TMPFILE: $enable_otmpfile diff --git a/src/libostree/ostree-sign-ed25519.c b/src/libostree/ostree-sign-ed25519.c index f93695a2e0..6ff132600b 100644 --- a/src/libostree/ostree-sign-ed25519.c +++ b/src/libostree/ostree-sign-ed25519.c @@ -25,8 +25,18 @@ #include "ostree-sign-ed25519.h" #include +#include + #ifdef HAVE_LIBSODIUM #include +#define USE_LIBSODIUM +#else + +#if defined(HAVE_OPENSSL) +#include +#define USE_OPENSSL +#endif + #endif #undef G_LOG_DOMAIN @@ -37,6 +47,12 @@ #define OSTREE_SIGN_METADATA_ED25519_KEY "ostree.sign.ed25519" #define OSTREE_SIGN_METADATA_ED25519_TYPE "aay" +#define OSTREE_SIGN_ED25519_SIG_SIZE 64U +#define OSTREE_SIGN_ED25519_PUBKEY_SIZE 32U +#define OSTREE_SIGN_ED25519_SEED_SIZE 32U +#define OSTREE_SIGN_ED25519_SECKEY_SIZE \ + (OSTREE_SIGN_ED25519_SEED_SIZE + OSTREE_SIGN_ED25519_PUBKEY_SIZE) + typedef enum { ED25519_OK, @@ -92,12 +108,13 @@ _ostree_sign_ed25519_init (OstreeSignEd25519 *self) self->public_keys = NULL; self->revoked_keys = NULL; -#ifdef HAVE_LIBSODIUM +#if defined(USE_LIBSODIUM) if (sodium_init () < 0) self->state = ED25519_FAILED_INITIALIZATION; +#elif defined(USE_OPENSSL) #else self->state = ED25519_NOT_SUPPORTED; -#endif /* HAVE_LIBSODIUM */ +#endif } static gboolean @@ -110,7 +127,7 @@ _ostree_sign_ed25519_is_initialized (OstreeSignEd25519 *self, GError **error) case ED25519_NOT_SUPPORTED: return glnx_throw (error, "ed25519: engine is not supported"); case ED25519_FAILED_INITIALIZATION: - return glnx_throw (error, "ed25519: libsodium library isn't initialized properly"); + return glnx_throw (error, "ed25519: crypto library isn't initialized properly"); } return TRUE; @@ -124,40 +141,53 @@ ostree_sign_ed25519_data (OstreeSign *self, GBytes *data, GBytes **signature, g_assert (OSTREE_IS_SIGN (self)); OstreeSignEd25519 *sign = _ostree_sign_ed25519_get_instance_private (OSTREE_SIGN_ED25519 (self)); -#ifdef HAVE_LIBSODIUM - guchar *sig = NULL; -#endif - if (!_ostree_sign_ed25519_is_initialized (sign, error)) return FALSE; if (sign->secret_key == NULL) return glnx_throw (error, "Not able to sign: secret key is not set"); -#ifdef HAVE_LIBSODIUM unsigned long long sig_size = 0; + g_autofree guchar *sig = g_malloc0 (OSTREE_SIGN_ED25519_SIG_SIZE); - sig = g_malloc0 (crypto_sign_BYTES); - +#if defined(USE_LIBSODIUM) if (crypto_sign_detached (sig, &sig_size, g_bytes_get_data (data, NULL), g_bytes_get_size (data), sign->secret_key)) + sig_size = 0; +#elif defined(USE_OPENSSL) + EVP_MD_CTX *ctx = EVP_MD_CTX_new (); + if (!ctx) + return glnx_throw (error, "openssl: failed to allocate context"); + EVP_PKEY *pkey = EVP_PKEY_new_raw_private_key (EVP_PKEY_ED25519, NULL, sign->secret_key, + OSTREE_SIGN_ED25519_SEED_SIZE); + if (!pkey) { - return glnx_throw (error, "Not able to sign: fail to sign the object"); + EVP_MD_CTX_free (ctx); + return glnx_throw (error, "openssl: Failed to initialize ed5519 key"); } - *signature = g_bytes_new_take (sig, sig_size); + size_t len; + if (EVP_DigestSignInit (ctx, NULL, NULL, NULL, pkey) + && EVP_DigestSign (ctx, sig, &len, g_bytes_get_data (data, NULL), g_bytes_get_size (data))) + sig_size = len; + + EVP_PKEY_free (pkey); + EVP_MD_CTX_free (ctx); + +#endif + + if (sig_size == 0) + return glnx_throw (error, "Failed to sign"); + + *signature = g_bytes_new_take (g_steal_pointer (&sig), sig_size); return TRUE; -#endif /* HAVE_LIBSODIUM */ - return FALSE; } -#ifdef HAVE_LIBSODIUM static gint _compare_ed25519_keys (gconstpointer a, gconstpointer b) { - return memcmp (a, b, crypto_sign_PUBLICKEYBYTES); + return memcmp (a, b, OSTREE_SIGN_ED25519_PUBKEY_SIZE); } -#endif gboolean ostree_sign_ed25519_data_verify (OstreeSign *self, GBytes *data, GVariant *signatures, @@ -179,7 +209,6 @@ ostree_sign_ed25519_data_verify (OstreeSign *self, GBytes *data, GVariant *signa if (!g_variant_is_of_type (signatures, (GVariantType *)OSTREE_SIGN_METADATA_ED25519_TYPE)) return glnx_throw (error, "ed25519: wrong type passed for verification"); -#ifdef HAVE_LIBSODIUM /* If no keys pre-loaded then, * try to load public keys from storage(s) */ if (sign->public_keys == NULL) @@ -203,14 +232,15 @@ ostree_sign_ed25519_data_verify (OstreeSign *self, GBytes *data, GVariant *signa { g_autoptr (GVariant) child = g_variant_get_child_value (signatures, i); g_autoptr (GBytes) signature = g_variant_get_data_as_bytes (child); + gboolean valid = FALSE; - if (g_bytes_get_size (signature) != crypto_sign_BYTES) - return glnx_throw (error, - "Invalid signature length of %" G_GSIZE_FORMAT - " bytes, expected %" G_GSIZE_FORMAT, - (gsize)g_bytes_get_size (signature), (gsize)crypto_sign_BYTES); + if (g_bytes_get_size (signature) != OSTREE_SIGN_ED25519_SIG_SIZE) + return glnx_throw ( + error, + "Invalid signature length of %" G_GSIZE_FORMAT " bytes, expected %" G_GSIZE_FORMAT, + (gsize)g_bytes_get_size (signature), (gsize)OSTREE_SIGN_ED25519_SIG_SIZE); - g_autofree char *hex = g_malloc0 (crypto_sign_PUBLICKEYBYTES * 2 + 1); + g_autofree char *hex = g_malloc0 (OSTREE_SIGN_ED25519_PUBKEY_SIZE * 2 + 1); g_debug ("Read signature %d: %s", (gint)i, g_variant_print (child, TRUE)); @@ -221,16 +251,38 @@ ostree_sign_ed25519_data_verify (OstreeSign *self, GBytes *data, GVariant *signa if (g_list_find_custom (sign->revoked_keys, public_key->data, _compare_ed25519_keys) != NULL) { - g_debug ("Skip revoked key '%s'", - sodium_bin2hex (hex, crypto_sign_PUBLICKEYBYTES * 2 + 1, public_key->data, - crypto_sign_PUBLICKEYBYTES)); + ot_bin2hex (hex, public_key->data, OSTREE_SIGN_ED25519_PUBKEY_SIZE); + g_debug ("Skip revoked key '%s'", hex); continue; } - if (crypto_sign_verify_detached ((guchar *)g_variant_get_data (child), - g_bytes_get_data (data, NULL), g_bytes_get_size (data), - public_key->data) - != 0) +#if defined(USE_LIBSODIUM) + valid = crypto_sign_verify_detached ((guchar *)g_variant_get_data (child), + g_bytes_get_data (data, NULL), + g_bytes_get_size (data), public_key->data) + == 0; +#elif defined(USE_OPENSSL) + EVP_MD_CTX *ctx = EVP_MD_CTX_new (); + if (!ctx) + return glnx_throw (error, "openssl: failed to allocate context"); + EVP_PKEY *pkey = EVP_PKEY_new_raw_public_key (EVP_PKEY_ED25519, NULL, public_key->data, + OSTREE_SIGN_ED25519_PUBKEY_SIZE); + if (!pkey) + { + EVP_MD_CTX_free (ctx); + return glnx_throw (error, "openssl: Failed to initialize ed5519 key"); + } + + valid = EVP_DigestVerifyInit (ctx, NULL, NULL, NULL, pkey) != 0 + && EVP_DigestVerify (ctx, g_bytes_get_data (signature, NULL), + g_bytes_get_size (signature), g_bytes_get_data (data, NULL), + g_bytes_get_size (data)) + != 0; + + EVP_PKEY_free (pkey); + EVP_MD_CTX_free (ctx); +#endif + if (!valid) { /* Incorrect signature! */ if (invalid_signatures == NULL) @@ -238,19 +290,16 @@ ostree_sign_ed25519_data_verify (OstreeSign *self, GBytes *data, GVariant *signa else g_string_append (invalid_signatures, "; "); n_invalid_signatures++; - g_string_append_printf (invalid_signatures, "key '%s'", - sodium_bin2hex (hex, crypto_sign_PUBLICKEYBYTES * 2 + 1, - public_key->data, - crypto_sign_PUBLICKEYBYTES)); + ot_bin2hex (hex, public_key->data, OSTREE_SIGN_ED25519_PUBKEY_SIZE); + g_string_append_printf (invalid_signatures, "key '%s'", hex); } else { if (out_success_message) { + ot_bin2hex (hex, public_key->data, OSTREE_SIGN_ED25519_PUBKEY_SIZE); *out_success_message = g_strdup_printf ( - "ed25519: Signature verified successfully with key '%s'", - sodium_bin2hex (hex, crypto_sign_PUBLICKEYBYTES * 2 + 1, public_key->data, - crypto_sign_PUBLICKEYBYTES)); + "ed25519: Signature verified successfully with key '%s'", hex); } return TRUE; } @@ -270,9 +319,6 @@ ostree_sign_ed25519_data_verify (OstreeSign *self, GBytes *data, GVariant *signa invalid_signatures->str); } return glnx_throw (error, "ed25519: no signatures found"); -#endif /* HAVE_LIBSODIUM */ - - return FALSE; } const gchar * @@ -307,11 +353,10 @@ ostree_sign_ed25519_clear_keys (OstreeSign *self, GError **error) if (!_ostree_sign_ed25519_is_initialized (sign, error)) return FALSE; -#ifdef HAVE_LIBSODIUM /* Clear secret key */ if (sign->secret_key != NULL) { - memset (sign->secret_key, 0, crypto_sign_SECRETKEYBYTES); + memset (sign->secret_key, 0, OSTREE_SIGN_ED25519_SECKEY_SIZE); g_free (sign->secret_key); sign->secret_key = NULL; } @@ -331,9 +376,6 @@ ostree_sign_ed25519_clear_keys (OstreeSign *self, GError **error) } return TRUE; -#endif /* HAVE_LIBSODIUM */ - - return FALSE; } /* Support 2 representations: @@ -348,7 +390,6 @@ ostree_sign_ed25519_set_sk (OstreeSign *self, GVariant *secret_key, GError **err if (!ostree_sign_ed25519_clear_keys (self, error)) return FALSE; -#ifdef HAVE_LIBSODIUM OstreeSignEd25519 *sign = _ostree_sign_ed25519_get_instance_private (OSTREE_SIGN_ED25519 (self)); gsize n_elements = 0; @@ -368,13 +409,10 @@ ostree_sign_ed25519_set_sk (OstreeSign *self, GVariant *secret_key, GError **err return glnx_throw (error, "Unknown ed25519 secret key type"); } - if (n_elements != crypto_sign_SECRETKEYBYTES) + if (n_elements != OSTREE_SIGN_ED25519_SECKEY_SIZE) return glnx_throw (error, "Incorrect ed25519 secret key"); return TRUE; -#endif /* HAVE_LIBSODIUM */ - - return FALSE; } /* Support 2 representations: @@ -406,7 +444,6 @@ ostree_sign_ed25519_add_pk (OstreeSign *self, GVariant *public_key, GError **err if (!_ostree_sign_ed25519_is_initialized (sign, error)) return FALSE; -#ifdef HAVE_LIBSODIUM gpointer key = NULL; gsize n_elements = 0; @@ -424,12 +461,12 @@ ostree_sign_ed25519_add_pk (OstreeSign *self, GVariant *public_key, GError **err return glnx_throw (error, "Unknown ed25519 public key type"); } - if (n_elements != crypto_sign_PUBLICKEYBYTES) + if (n_elements != OSTREE_SIGN_ED25519_PUBKEY_SIZE) return glnx_throw (error, "Incorrect ed25519 public key"); - g_autofree char *hex = g_malloc0 (crypto_sign_PUBLICKEYBYTES * 2 + 1); - g_debug ("Read ed25519 public key = %s", - sodium_bin2hex (hex, crypto_sign_PUBLICKEYBYTES * 2 + 1, key, n_elements)); + g_autofree char *hex = g_malloc0 (OSTREE_SIGN_ED25519_PUBKEY_SIZE * 2 + 1); + ot_bin2hex (hex, key, n_elements); + g_debug ("Read ed25519 public key = %s", hex); if (g_list_find_custom (sign->public_keys, key, _compare_ed25519_keys) == NULL) { @@ -437,11 +474,9 @@ ostree_sign_ed25519_add_pk (OstreeSign *self, GVariant *public_key, GError **err sign->public_keys = g_list_prepend (sign->public_keys, newkey); } -#endif /* HAVE_LIBSODIUM */ return TRUE; } -#ifdef HAVE_LIBSODIUM /* Add revoked public key */ static gboolean _ed25519_add_revoked (OstreeSign *self, GVariant *revoked_key, GError **error) @@ -457,14 +492,14 @@ _ed25519_add_revoked (OstreeSign *self, GVariant *revoked_key, GError **error) gsize n_elements = 0; gpointer key = g_base64_decode (rk_ascii, &n_elements); - if (n_elements != crypto_sign_PUBLICKEYBYTES) + if (n_elements != OSTREE_SIGN_ED25519_PUBKEY_SIZE) { return glnx_throw (error, "Incorrect ed25519 revoked key"); } - g_autofree char *hex = g_malloc0 (crypto_sign_PUBLICKEYBYTES * 2 + 1); - g_debug ("Read ed25519 revoked key = %s", - sodium_bin2hex (hex, crypto_sign_PUBLICKEYBYTES * 2 + 1, key, n_elements)); + g_autofree char *hex = g_malloc0 (OSTREE_SIGN_ED25519_PUBKEY_SIZE * 2 + 1); + ot_bin2hex (hex, key, n_elements); + g_debug ("Read ed25519 revoked key = %s", hex); if (g_list_find_custom (sign->revoked_keys, key, _compare_ed25519_keys) == NULL) { @@ -474,7 +509,6 @@ _ed25519_add_revoked (OstreeSign *self, GVariant *revoked_key, GError **error) return TRUE; } -#endif /* HAVE_LIBSODIUM */ static gboolean _load_pk_from_stream (OstreeSign *self, GDataInputStream *key_data_in, gboolean trusted, @@ -483,7 +517,6 @@ _load_pk_from_stream (OstreeSign *self, GDataInputStream *key_data_in, gboolean if (key_data_in == NULL) return glnx_throw (error, "ed25519: unable to read from NULL key-data input stream"); -#ifdef HAVE_LIBSODIUM gboolean ret = FALSE; /* Use simple file format with just a list of base64 public keys per line */ @@ -519,8 +552,8 @@ _load_pk_from_stream (OstreeSign *self, GDataInputStream *key_data_in, gboolean if (added) ret = TRUE; } -#endif /* HAVE_LIBSODIUM */ - return FALSE; + + return ret; } static gboolean diff --git a/src/libostree/ostree-sign.c b/src/libostree/ostree-sign.c index be333a3070..d76271bca7 100644 --- a/src/libostree/ostree-sign.c +++ b/src/libostree/ostree-sign.c @@ -40,11 +40,9 @@ #include "ostree-autocleanups.h" #include "ostree-core.h" #include "ostree-sign-dummy.h" +#include "ostree-sign-ed25519.h" #include "ostree-sign-private.h" #include "ostree-sign.h" -#ifdef HAVE_LIBSODIUM -#include "ostree-sign-ed25519.h" -#endif #include "ostree-autocleanups.h" #include "ostree-repo-private.h" @@ -59,7 +57,7 @@ typedef struct } _sign_type; _sign_type sign_types[] = { -#if defined(HAVE_LIBSODIUM) +#if defined(HAVE_ED25519) { OSTREE_SIGN_NAME_ED25519, 0 }, #endif { "dummy", 0 } @@ -67,7 +65,7 @@ _sign_type sign_types[] = { enum { -#if defined(HAVE_LIBSODIUM) +#if defined(HAVE_ED25519) SIGN_ED25519, #endif SIGN_DUMMY @@ -535,7 +533,7 @@ ostree_sign_get_by_name (const gchar *name, GError **error) OstreeSign *sign = NULL; /* Get types if not initialized yet */ -#if defined(HAVE_LIBSODIUM) +#if defined(HAVE_ED25519) if (sign_types[SIGN_ED25519].type == 0) sign_types[SIGN_ED25519].type = OSTREE_TYPE_SIGN_ED25519; #endif diff --git a/src/ostree/ot-builtin-sign.c b/src/ostree/ot-builtin-sign.c index cd331a486e..f51fc51e60 100644 --- a/src/ostree/ot-builtin-sign.c +++ b/src/ostree/ot-builtin-sign.c @@ -48,7 +48,7 @@ static GOptionEntry options[] { "verify", 0, 0, G_OPTION_ARG_NONE, &opt_verify, "Verify signatures", NULL }, { "sign-type", 's', 0, G_OPTION_ARG_STRING, &opt_sign_name, "Signature type to use (defaults to 'ed25519')", "NAME" }, -#if defined(HAVE_LIBSODIUM) +#if defined(HAVE_ED25519) { "keys-file", 0, 0, G_OPTION_ARG_STRING, &opt_filename, "Read key(s) from file", "NAME" }, { "keys-dir", 0, 0, G_OPTION_ARG_STRING, &opt_keysdir, "Redefine system-wide directories with public and revoked keys for verification", diff --git a/src/ostree/ot-builtin-static-delta.c b/src/ostree/ot-builtin-static-delta.c index a10040bdd1..ba9a2f2c4a 100644 --- a/src/ostree/ot-builtin-static-delta.c +++ b/src/ostree/ot-builtin-static-delta.c @@ -105,7 +105,7 @@ static GOptionEntry generate_options[] = { { "sign", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_key_ids, "Sign the delta with", "KEY_ID" }, { "sign-type", 0, 0, G_OPTION_ARG_STRING, &opt_sign_name, "Signature type to use (defaults to 'ed25519')", "NAME" }, -#if defined(HAVE_LIBSODIUM) +#if defined(HAVE_ED25519) { "keys-file", 0, 0, G_OPTION_ARG_STRING, &opt_keysfilename, "Read key(s) from file", "NAME" }, #endif { NULL } @@ -114,7 +114,7 @@ static GOptionEntry generate_options[] = { static GOptionEntry apply_offline_options[] = { { "sign-type", 0, 0, G_OPTION_ARG_STRING, &opt_sign_name, "Signature type to use (defaults to 'ed25519')", "NAME" }, -#if defined(HAVE_LIBSODIUM) +#if defined(HAVE_ED25519) { "keys-file", 0, 0, G_OPTION_ARG_STRING, &opt_keysfilename, "Read key(s) from file", "NAME" }, { "keys-dir", 0, 0, G_OPTION_ARG_STRING, &opt_keysdir, "Redefine system-wide directories with public and revoked keys for verification", "NAME" }, @@ -127,7 +127,7 @@ static GOptionEntry list_options[] = { { NULL } }; static GOptionEntry verify_options[] = { { "sign-type", 0, 0, G_OPTION_ARG_STRING, &opt_sign_name, "Signature type to use (defaults to 'ed25519')", "NAME" }, -#if defined(HAVE_LIBSODIUM) +#if defined(HAVE_ED25519) { "keys-file", 0, 0, G_OPTION_ARG_STRING, &opt_keysfilename, "Read key(s) from file", "NAME" }, { "keys-dir", 0, 0, G_OPTION_ARG_STRING, &opt_keysdir, "Redefine system-wide directories with public and revoked keys for verification", "NAME" }, @@ -513,7 +513,7 @@ ot_static_delta_builtin_apply_offline (int argc, char **argv, OstreeCommandInvoc return FALSE; } -#if defined(HAVE_LIBSODIUM) +#if defined(HAVE_ED25519) /* Initialize crypto system */ opt_sign_name = opt_sign_name ?: OSTREE_SIGN_NAME_ED25519; #endif