mirror of
https://github.com/ostreedev/ostree.git
synced 2024-12-21 13:34:34 +03:00
sign: Support spki signature type
The current "ed25519" signing type assumes raw Ed25519 key format for both public and private keys. That requires custom processing of keys after generated with openssl tools, and also lacks cryptographic agility[1]; when Ed25519 becomes vulnerable, it would not be straightforward to migrate to other algorithms, such as post-quantum signature algorithms. This patch adds a new signature type "spki" which uses the X.509 SubjectPublicKeyInfo format for public keys. Keys in this format can easily be created with openssl tools and provide crypto agility as the format embeds algorithm identifier. Currently, the corresponding private keys shall be in the PKCS#8 format, while future extensions may support other format such as opaque key handles on a hardware token. The "spki" signature type prefers keys to be encoded in the PEM format on disk, while it still accepts base64 encoded keys when given through the command-line. 1. https://en.wikipedia.org/wiki/Cryptographic_agility Signed-off-by: Daiki Ueno <dueno@redhat.com>
This commit is contained in:
parent
5583563b8f
commit
e83eda0aec
@ -261,6 +261,8 @@ libostree_1_la_SOURCES += \
|
||||
src/libostree/ostree-sign-dummy.h \
|
||||
src/libostree/ostree-sign-ed25519.c \
|
||||
src/libostree/ostree-sign-ed25519.h \
|
||||
src/libostree/ostree-sign-spki.c \
|
||||
src/libostree/ostree-sign-spki.h \
|
||||
src/libostree/ostree-sign-private.h \
|
||||
src/libostree/ostree-blob-reader.c \
|
||||
src/libostree/ostree-blob-reader.h \
|
||||
|
@ -19,6 +19,7 @@ libotcore_la_SOURCES = \
|
||||
src/libotcore/otcore.h \
|
||||
src/libotcore/otcore-ed25519-verify.c \
|
||||
src/libotcore/otcore-prepare-root.c \
|
||||
src/libotcore/otcore-spki-verify.c \
|
||||
$(NULL)
|
||||
|
||||
libotcore_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)
|
||||
|
@ -156,12 +156,24 @@ _installed_or_uninstalled_test_scripts = \
|
||||
tests/test-summary-collections.sh \
|
||||
tests/test-pull-collections.sh \
|
||||
tests/test-config.sh \
|
||||
tests/test-signed-commit.sh \
|
||||
tests/test-signed-commit-dummy.sh \
|
||||
tests/test-signed-pull.sh \
|
||||
tests/test-pre-signed-pull.sh \
|
||||
tests/test-signed-pull-summary.sh \
|
||||
$(NULL)
|
||||
|
||||
if HAVE_ED25519
|
||||
_installed_or_uninstalled_test_scripts += \
|
||||
tests/test-signed-commit-ed25519.sh \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
if HAVE_SPKI
|
||||
_installed_or_uninstalled_test_scripts += \
|
||||
tests/test-signed-commit-spki.sh \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
if USE_GPGME
|
||||
_installed_or_uninstalled_test_scripts += \
|
||||
tests/test-remote-gpg-import.sh \
|
||||
|
15
configure.ac
15
configure.ac
@ -452,10 +452,19 @@ 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
|
||||
AM_CONDITIONAL([HAVE_ED25519], [test x$with_openssl != xno || test x$with_ed25519_libsodium != xno])
|
||||
|
||||
AM_COND_IF([HAVE_ED25519], [
|
||||
AC_DEFINE([HAVE_ED25519], 1, [Define if ed25519 is supported ])
|
||||
OSTREE_FEATURES="$OSTREE_FEATURES sign-ed25519"
|
||||
fi
|
||||
])
|
||||
|
||||
AM_CONDITIONAL([HAVE_SPKI], [test x$with_openssl != xno])
|
||||
|
||||
AM_COND_IF([HAVE_SPKI], [
|
||||
AC_DEFINE([HAVE_SPKI], 1, [Define if spki is supported ])
|
||||
OSTREE_FEATURES="$OSTREE_FEATURES sign-spki"
|
||||
])
|
||||
|
||||
dnl begin gnutls; in contrast to openssl this one only
|
||||
dnl supports --with-crypto=gnutls
|
||||
@ -697,7 +706,7 @@ echo "
|
||||
systemd: $with_libsystemd
|
||||
libmount: $with_libmount
|
||||
libsodium (ed25519 signatures): $with_ed25519_libsodium
|
||||
openssl (ed25519 signatures): $with_openssl
|
||||
openssl (ed25519 and spki signatures): $with_openssl
|
||||
libarchive (parse tar files directly): $with_libarchive
|
||||
static deltas: yes (always enabled now)
|
||||
O_TMPFILE: $enable_otmpfile
|
||||
|
@ -312,7 +312,7 @@ License along with this library. If not, see <https://www.gnu.org/licenses/>.
|
||||
<term><option>-s, --sign-type</option></term>
|
||||
<listitem><para>
|
||||
Use particular signature engine. Currently
|
||||
available <arg choice="plain">ed25519</arg> and <arg choice="plain">dummy</arg>
|
||||
available <arg choice="plain">ed25519</arg>, <arg choice="plain">spki</arg>, and <arg choice="plain">dummy</arg>
|
||||
signature types.
|
||||
|
||||
The default is <arg choice="plain">ed25519</arg>.
|
||||
@ -323,7 +323,8 @@ License along with this library. If not, see <https://www.gnu.org/licenses/>.
|
||||
<varlistentry>
|
||||
<term><option>--sign-from-file</option>="PATH"</term>
|
||||
<listitem><para>
|
||||
This will read a key (corresponding to the provided <literal>--sign-type</literal> from the provided path. The key should be base64 encoded.
|
||||
This will read a key (corresponding to the provided <literal>--sign-type</literal> from the provided path. The encoding of the key depends on
|
||||
signature engine. For ed25519 the key should be base64 encoded, for spki it should be in PEM format, and for dummy it should be an ASCII-string.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
@ -337,7 +338,7 @@ License along with this library. If not, see <https://www.gnu.org/licenses/>.
|
||||
The <literal>KEY-ID</literal> is:
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><option>for ed25519:</option></term>
|
||||
<term><option>for ed25519 and spki:</option></term>
|
||||
<listitem><para>
|
||||
<literal>base64</literal>-encoded secret key for commit signing.
|
||||
</para></listitem>
|
||||
|
@ -64,26 +64,28 @@ License along with this library. If not, see <https://www.gnu.org/licenses/>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
There are several "well-known" system places for `ed25519` trusted and revoked public keys -- expected single <literal>base64</literal>-encoded key per line.
|
||||
For `ed25519` and `spki`, there are several "well-known" system places for trusted and revoked public keys as listed below.
|
||||
</para>
|
||||
|
||||
<para>Files:
|
||||
<itemizedlist>
|
||||
<listitem><para><filename>/etc/ostree/trusted.ed25519</filename></para></listitem>
|
||||
<listitem><para><filename>/etc/ostree/revoked.ed25519</filename></para></listitem>
|
||||
<listitem><para><filename>/usr/share/ostree/trusted.ed25519</filename></para></listitem>
|
||||
<listitem><para><filename>/usr/share/ostree/revoked.ed25519</filename></para></listitem>
|
||||
<listitem><para><filename>/etc/ostree/trusted.<replaceable>SIGN-TYPE</replaceable></filename></para></listitem>
|
||||
<listitem><para><filename>/etc/ostree/revoked.<replaceable>SIGN-TYPE</replaceable></filename></para></listitem>
|
||||
<listitem><para><filename>/usr/share/ostree/trusted.<replaceable>SIGN-TYPE</replaceable></filename></para></listitem>
|
||||
<listitem><para><filename>/usr/share/ostree/revoked.<replaceable>SIGN-TYPE</replaceable></filename></para></listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
|
||||
<para>Directories containing files with keys:
|
||||
<itemizedlist>
|
||||
<listitem><para><filename>/etc/ostree/trusted.ed25519.d</filename></para></listitem>
|
||||
<listitem><para><filename>/etc/ostree/revoked.ed25519.d</filename></para></listitem>
|
||||
<listitem><para><filename>/usr/share/ostree/trusted.ed25519.d</filename></para></listitem>
|
||||
<listitem><para><filename>/usr/share/ostree/revoked.ed25519.d</filename></para></listitem>
|
||||
<listitem><para><filename>/etc/ostree/trusted.<replaceable>SIGN-TYPE</replaceable>.d</filename></para></listitem>
|
||||
<listitem><para><filename>/etc/ostree/revoked.<replaceable>SIGN-TYPE</replaceable>.d</filename></para></listitem>
|
||||
<listitem><para><filename>/usr/share/ostree/trusted.<replaceable>SIGN-TYPE</replaceable>.d</filename></para></listitem>
|
||||
<listitem><para><filename>/usr/share/ostree/revoked.<replaceable>SIGN-TYPE</replaceable>.d</filename></para></listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
|
||||
<para>The format of those files depends on the signature mechanism; for `ed25519`, keys are stored in the <literal>base64</literal> encoding per line, while for `spki` they are stored in the PEM "PUBLIC KEY" encoding.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
@ -95,7 +97,7 @@ License along with this library. If not, see <https://www.gnu.org/licenses/>.
|
||||
<listitem><para>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><option>for ed25519:</option></term>
|
||||
<term><option>for ed25519 and spki:</option></term>
|
||||
<listitem><para>
|
||||
<literal>base64</literal>-encoded secret (for signing) or public key (for verifying).
|
||||
</para></listitem>
|
||||
@ -120,7 +122,7 @@ License along with this library. If not, see <https://www.gnu.org/licenses/>.
|
||||
<term><option>-s, --sign-type</option></term>
|
||||
<listitem><para>
|
||||
Use particular signature mechanism. Currently
|
||||
available <arg choice="plain">ed25519</arg> and <arg choice="plain">dummy</arg>
|
||||
available <arg choice="plain">ed25519</arg>, <arg choice="plain">spki</arg>, and <arg choice="plain">dummy</arg>
|
||||
signature types.
|
||||
|
||||
The default is <arg choice="plain">ed25519</arg>.
|
||||
@ -133,8 +135,8 @@ License along with this library. If not, see <https://www.gnu.org/licenses/>.
|
||||
</para></listitem>
|
||||
|
||||
<listitem><para>
|
||||
Valid for <literal>ed25519</literal> signature type.
|
||||
For <literal>ed25519</literal> this file must contain <literal>base64</literal>-encoded
|
||||
Valid for <literal>ed25519</literal> and <literal>spki</literal> signature types.
|
||||
This file must contain <literal>base64</literal>-encoded
|
||||
secret key(s) (for signing) or public key(s) (for verifying) per line.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
@ -157,6 +157,7 @@ main ()
|
||||
PRINT_CONSTANT (OSTREE_SHA256_DIGEST_LEN);
|
||||
PRINT_CONSTANT (OSTREE_SHA256_STRING_LEN);
|
||||
PRINT_CONSTANT (OSTREE_SIGN_NAME_ED25519);
|
||||
PRINT_CONSTANT (OSTREE_SIGN_NAME_SPKI);
|
||||
PRINT_CONSTANT ((gint)OSTREE_STATIC_DELTA_GENERATE_OPT_LOWLATENCY);
|
||||
PRINT_CONSTANT ((gint)OSTREE_STATIC_DELTA_GENERATE_OPT_MAJOR);
|
||||
PRINT_CONSTANT ((gint)OSTREE_STATIC_DELTA_INDEX_FLAGS_NONE);
|
||||
|
636
src/libostree/ostree-sign-spki.c
Normal file
636
src/libostree/ostree-sign-spki.c
Normal file
@ -0,0 +1,636 @@
|
||||
/* vim:set et sw=2 cin cino=t0,f0,(0,{s,>2s,n-s,^-s,e2s: */
|
||||
/*
|
||||
* Copyright © 2019 Collabora Ltd.
|
||||
* Copyright © 2024 Red Hat, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.0+
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "ostree-sign-spki.h"
|
||||
#include "otcore.h"
|
||||
#include <libglnx.h>
|
||||
#include <ot-checksum-utils.h>
|
||||
#include <string.h>
|
||||
|
||||
#undef G_LOG_DOMAIN
|
||||
#define G_LOG_DOMAIN "OSTreeSign"
|
||||
|
||||
#define OSTREE_SIGN_SPKI_NAME "spki"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SPKI_OK,
|
||||
SPKI_NOT_SUPPORTED,
|
||||
SPKI_FAILED_INITIALIZATION
|
||||
} spki_state;
|
||||
|
||||
struct _OstreeSignSpki
|
||||
{
|
||||
GObject parent;
|
||||
spki_state state;
|
||||
GBytes *secret_key;
|
||||
GList *public_keys; /* GBytes */
|
||||
GList *revoked_keys; /* GBytes */
|
||||
};
|
||||
|
||||
static void ostree_sign_spki_iface_init (OstreeSignInterface *self);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (OstreeSignSpki, _ostree_sign_spki, G_TYPE_OBJECT,
|
||||
G_IMPLEMENT_INTERFACE (OSTREE_TYPE_SIGN, ostree_sign_spki_iface_init));
|
||||
|
||||
static void
|
||||
ostree_sign_spki_iface_init (OstreeSignInterface *self)
|
||||
{
|
||||
|
||||
self->data = ostree_sign_spki_data;
|
||||
self->data_verify = ostree_sign_spki_data_verify;
|
||||
self->get_name = ostree_sign_spki_get_name;
|
||||
self->metadata_key = ostree_sign_spki_metadata_key;
|
||||
self->metadata_format = ostree_sign_spki_metadata_format;
|
||||
self->clear_keys = ostree_sign_spki_clear_keys;
|
||||
self->set_sk = ostree_sign_spki_set_sk;
|
||||
self->set_pk = ostree_sign_spki_set_pk;
|
||||
self->add_pk = ostree_sign_spki_add_pk;
|
||||
self->load_pk = ostree_sign_spki_load_pk;
|
||||
}
|
||||
|
||||
static void
|
||||
_ostree_sign_spki_class_init (OstreeSignSpkiClass *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
_ostree_sign_spki_init (OstreeSignSpki *self)
|
||||
{
|
||||
|
||||
self->state = SPKI_OK;
|
||||
self->secret_key = NULL;
|
||||
self->public_keys = NULL;
|
||||
self->revoked_keys = NULL;
|
||||
|
||||
#if !defined(USE_OPENSSL)
|
||||
self->state = SPKI_NOT_SUPPORTED;
|
||||
#else
|
||||
if (!otcore_spki_init ())
|
||||
self->state = SPKI_FAILED_INITIALIZATION;
|
||||
#endif
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_ostree_sign_spki_is_initialized (OstreeSignSpki *self, GError **error)
|
||||
{
|
||||
switch (self->state)
|
||||
{
|
||||
case SPKI_OK:
|
||||
break;
|
||||
case SPKI_NOT_SUPPORTED:
|
||||
return glnx_throw (error, "spki: engine is not supported");
|
||||
case SPKI_FAILED_INITIALIZATION:
|
||||
return glnx_throw (error, "spki: crypto library isn't initialized properly");
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
ostree_sign_spki_data (OstreeSign *self, GBytes *data, GBytes **signature,
|
||||
GCancellable *cancellable, GError **error)
|
||||
{
|
||||
#if defined(USE_OPENSSL)
|
||||
g_assert (OSTREE_IS_SIGN (self));
|
||||
OstreeSignSpki *sign = _ostree_sign_spki_get_instance_private (OSTREE_SIGN_SPKI (self));
|
||||
|
||||
if (!_ostree_sign_spki_is_initialized (sign, error))
|
||||
return FALSE;
|
||||
|
||||
if (sign->secret_key == NULL)
|
||||
return glnx_throw (error, "Not able to sign: secret key is not set");
|
||||
|
||||
gsize secret_key_size;
|
||||
const guint8 *secret_key_buf = g_bytes_get_data (sign->secret_key, &secret_key_size);
|
||||
|
||||
EVP_MD_CTX *ctx = EVP_MD_CTX_new ();
|
||||
if (!ctx)
|
||||
return glnx_throw (error, "openssl: failed to allocate context");
|
||||
|
||||
const unsigned char *p = secret_key_buf;
|
||||
EVP_PKEY *pkey = d2i_AutoPrivateKey (NULL, &p, secret_key_size);
|
||||
if (!pkey)
|
||||
{
|
||||
EVP_MD_CTX_free (ctx);
|
||||
return glnx_throw (error, "openssl: Failed to initialize spki key");
|
||||
}
|
||||
|
||||
unsigned long long sig_size = 0;
|
||||
g_autofree guchar *sig = NULL;
|
||||
|
||||
size_t len;
|
||||
if (EVP_DigestSignInit (ctx, NULL, NULL, NULL, pkey)
|
||||
&& EVP_DigestSign (ctx, NULL, &len, g_bytes_get_data (data, NULL), g_bytes_get_size (data)))
|
||||
{
|
||||
sig = g_malloc0 (len);
|
||||
if (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);
|
||||
|
||||
if (sig_size == 0)
|
||||
return glnx_throw (error, "Failed to sign");
|
||||
|
||||
*signature = g_bytes_new_take (g_steal_pointer (&sig), sig_size);
|
||||
return TRUE;
|
||||
#else
|
||||
return glnx_throw (error, "spki signature validation requested, but support not compiled in");
|
||||
#endif
|
||||
}
|
||||
|
||||
gboolean
|
||||
ostree_sign_spki_data_verify (OstreeSign *self, GBytes *data, GVariant *signatures,
|
||||
char **out_success_message, GError **error)
|
||||
{
|
||||
g_assert (OSTREE_IS_SIGN (self));
|
||||
|
||||
if (data == NULL)
|
||||
return glnx_throw (error, "spki: unable to verify NULL data");
|
||||
|
||||
OstreeSignSpki *sign = _ostree_sign_spki_get_instance_private (OSTREE_SIGN_SPKI (self));
|
||||
|
||||
if (!_ostree_sign_spki_is_initialized (sign, error))
|
||||
return FALSE;
|
||||
|
||||
if (signatures == NULL)
|
||||
return glnx_throw (error, "spki: commit have no signatures of my type");
|
||||
|
||||
if (!g_variant_is_of_type (signatures, (GVariantType *)OSTREE_SIGN_METADATA_SPKI_TYPE))
|
||||
return glnx_throw (error, "spki: wrong type passed for verification");
|
||||
|
||||
/* If no keys pre-loaded then,
|
||||
* try to load public keys from storage(s) */
|
||||
if (sign->public_keys == NULL)
|
||||
{
|
||||
g_autoptr (GVariantBuilder) builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}"));
|
||||
g_autoptr (GVariant) options = g_variant_builder_end (builder);
|
||||
|
||||
if (!ostree_sign_spki_load_pk (self, options, error))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_debug ("verify: data hash = 0x%x", g_bytes_hash (data));
|
||||
|
||||
g_autoptr (GString) invalid_signatures = NULL;
|
||||
guint n_invalid_signatures = 0;
|
||||
|
||||
for (gsize i = 0; i < g_variant_n_children (signatures); i++)
|
||||
{
|
||||
g_autoptr (GVariant) child = g_variant_get_child_value (signatures, i);
|
||||
g_autoptr (GBytes) signature = g_variant_get_data_as_bytes (child);
|
||||
|
||||
g_debug ("Read signature %d: %s", (gint)i, g_variant_print (child, TRUE));
|
||||
|
||||
for (GList *l = sign->public_keys; l != NULL; l = l->next)
|
||||
{
|
||||
GBytes *public_key = l->data;
|
||||
/* TODO: use non-list for tons of revoked keys? */
|
||||
if (g_list_find_custom (sign->revoked_keys, public_key, g_bytes_compare) != NULL)
|
||||
{
|
||||
g_autofree char *hex = g_malloc0 (g_bytes_get_size (public_key) * 2 + 1);
|
||||
ot_bin2hex (hex, g_bytes_get_data (public_key, NULL), g_bytes_get_size (public_key));
|
||||
g_debug ("Skip revoked key '%s'", hex);
|
||||
continue;
|
||||
}
|
||||
|
||||
bool valid = false;
|
||||
if (!otcore_validate_spki_signature (data, public_key, signature, &valid, error))
|
||||
return FALSE;
|
||||
if (!valid)
|
||||
{
|
||||
/* Incorrect signature! */
|
||||
if (invalid_signatures == NULL)
|
||||
invalid_signatures = g_string_new ("");
|
||||
else
|
||||
g_string_append (invalid_signatures, "; ");
|
||||
n_invalid_signatures++;
|
||||
g_autofree char *hex = g_malloc0 (g_bytes_get_size (public_key) * 2 + 1);
|
||||
ot_bin2hex (hex, g_bytes_get_data (public_key, NULL), g_bytes_get_size (public_key));
|
||||
g_string_append_printf (invalid_signatures, "key '%s'", hex);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (out_success_message)
|
||||
{
|
||||
g_autofree char *hex = g_malloc0 (g_bytes_get_size (public_key) * 2 + 1);
|
||||
ot_bin2hex (hex, g_bytes_get_data (public_key, NULL),
|
||||
g_bytes_get_size (public_key));
|
||||
*out_success_message = g_strdup_printf (
|
||||
"spki: Signature verified successfully with key '%s'", hex);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (invalid_signatures)
|
||||
{
|
||||
g_assert_cmpuint (n_invalid_signatures, >, 0);
|
||||
/* The test suite has a key ring with 100 keys. This seems insane, let's
|
||||
* cap a reasonable error message at 3.
|
||||
*/
|
||||
if (n_invalid_signatures > 3)
|
||||
return glnx_throw (error, "spki: Signature couldn't be verified; tried %u keys",
|
||||
n_invalid_signatures);
|
||||
return glnx_throw (error, "spki: Signature couldn't be verified with: %s",
|
||||
invalid_signatures->str);
|
||||
}
|
||||
return glnx_throw (error, "spki: no signatures found");
|
||||
}
|
||||
|
||||
const gchar *
|
||||
ostree_sign_spki_get_name (OstreeSign *self)
|
||||
{
|
||||
g_assert (OSTREE_IS_SIGN (self));
|
||||
|
||||
return OSTREE_SIGN_SPKI_NAME;
|
||||
}
|
||||
|
||||
const gchar *
|
||||
ostree_sign_spki_metadata_key (OstreeSign *self)
|
||||
{
|
||||
|
||||
return OSTREE_SIGN_METADATA_SPKI_KEY;
|
||||
}
|
||||
|
||||
const gchar *
|
||||
ostree_sign_spki_metadata_format (OstreeSign *self)
|
||||
{
|
||||
|
||||
return OSTREE_SIGN_METADATA_SPKI_TYPE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
ostree_sign_spki_clear_keys (OstreeSign *self, GError **error)
|
||||
{
|
||||
g_assert (OSTREE_IS_SIGN (self));
|
||||
|
||||
OstreeSignSpki *sign = _ostree_sign_spki_get_instance_private (OSTREE_SIGN_SPKI (self));
|
||||
|
||||
if (!_ostree_sign_spki_is_initialized (sign, error))
|
||||
return FALSE;
|
||||
|
||||
/* Clear secret key */
|
||||
if (sign->secret_key != NULL)
|
||||
{
|
||||
gsize size;
|
||||
gpointer data = g_bytes_unref_to_data (sign->secret_key, &size);
|
||||
explicit_bzero (data, size);
|
||||
sign->secret_key = NULL;
|
||||
}
|
||||
|
||||
/* Clear already loaded trusted keys */
|
||||
if (sign->public_keys != NULL)
|
||||
{
|
||||
g_list_free_full (sign->public_keys, (GDestroyNotify)g_bytes_unref);
|
||||
sign->public_keys = NULL;
|
||||
}
|
||||
|
||||
/* Clear already loaded revoked keys */
|
||||
if (sign->revoked_keys != NULL)
|
||||
{
|
||||
g_list_free_full (sign->revoked_keys, (GDestroyNotify)g_bytes_unref);
|
||||
sign->revoked_keys = NULL;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Support 2 representations:
|
||||
* base64 ascii -- secret key is passed as string
|
||||
* raw key -- key is passed as bytes array
|
||||
* */
|
||||
gboolean
|
||||
ostree_sign_spki_set_sk (OstreeSign *self, GVariant *secret_key, GError **error)
|
||||
{
|
||||
g_assert (OSTREE_IS_SIGN (self));
|
||||
|
||||
if (!ostree_sign_spki_clear_keys (self, error))
|
||||
return FALSE;
|
||||
|
||||
OstreeSignSpki *sign = _ostree_sign_spki_get_instance_private (OSTREE_SIGN_SPKI (self));
|
||||
|
||||
gsize n_elements = 0;
|
||||
|
||||
g_autofree guchar *secret_key_buf = NULL;
|
||||
if (g_variant_is_of_type (secret_key, G_VARIANT_TYPE_STRING))
|
||||
{
|
||||
const gchar *sk_ascii = g_variant_get_string (secret_key, NULL);
|
||||
secret_key_buf = g_base64_decode (sk_ascii, &n_elements);
|
||||
}
|
||||
else if (g_variant_is_of_type (secret_key, G_VARIANT_TYPE_BYTESTRING))
|
||||
{
|
||||
secret_key_buf
|
||||
= (guchar *)g_variant_get_fixed_array (secret_key, &n_elements, sizeof (guchar));
|
||||
}
|
||||
else
|
||||
{
|
||||
return glnx_throw (error, "Unknown spki secret key type");
|
||||
}
|
||||
|
||||
sign->secret_key = g_bytes_new_take (g_steal_pointer (&secret_key_buf), n_elements);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Support 2 representations:
|
||||
* base64 ascii -- public key is passed as string
|
||||
* raw key -- key is passed as bytes array
|
||||
* */
|
||||
gboolean
|
||||
ostree_sign_spki_set_pk (OstreeSign *self, GVariant *public_key, GError **error)
|
||||
{
|
||||
g_assert (OSTREE_IS_SIGN (self));
|
||||
|
||||
if (!ostree_sign_spki_clear_keys (self, error))
|
||||
return FALSE;
|
||||
|
||||
return ostree_sign_spki_add_pk (self, public_key, error);
|
||||
}
|
||||
|
||||
/* Support 2 representations:
|
||||
* base64 ascii -- public key is passed as string
|
||||
* raw key -- key is passed as bytes array
|
||||
* */
|
||||
gboolean
|
||||
ostree_sign_spki_add_pk (OstreeSign *self, GVariant *public_key, GError **error)
|
||||
{
|
||||
g_assert (OSTREE_IS_SIGN (self));
|
||||
|
||||
OstreeSignSpki *sign = _ostree_sign_spki_get_instance_private (OSTREE_SIGN_SPKI (self));
|
||||
|
||||
if (!_ostree_sign_spki_is_initialized (sign, error))
|
||||
return FALSE;
|
||||
|
||||
g_autofree guint8 *key_owned = NULL;
|
||||
const guint8 *key = NULL;
|
||||
gsize n_elements = 0;
|
||||
|
||||
if (g_variant_is_of_type (public_key, G_VARIANT_TYPE_STRING))
|
||||
{
|
||||
const gchar *pk_ascii = g_variant_get_string (public_key, NULL);
|
||||
key = key_owned = g_base64_decode (pk_ascii, &n_elements);
|
||||
}
|
||||
else if (g_variant_is_of_type (public_key, G_VARIANT_TYPE_BYTESTRING))
|
||||
{
|
||||
key = g_variant_get_fixed_array (public_key, &n_elements, sizeof (guchar));
|
||||
}
|
||||
else
|
||||
{
|
||||
return glnx_throw (error, "Unknown spki public key type");
|
||||
}
|
||||
|
||||
g_autofree char *hex = g_malloc0 (n_elements * 2 + 1);
|
||||
ot_bin2hex (hex, key, n_elements);
|
||||
g_debug ("Read spki public key = %s", hex);
|
||||
|
||||
g_autoptr (GBytes) key_bytes = g_bytes_new_static (key, n_elements);
|
||||
if (g_list_find_custom (sign->public_keys, key_bytes, g_bytes_compare) == NULL)
|
||||
{
|
||||
GBytes *new_key_bytes = g_bytes_new (key, n_elements);
|
||||
sign->public_keys = g_list_prepend (sign->public_keys, new_key_bytes);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Add revoked public key */
|
||||
static gboolean
|
||||
_spki_add_revoked (OstreeSign *self, GVariant *revoked_key, GError **error)
|
||||
{
|
||||
g_assert (OSTREE_IS_SIGN (self));
|
||||
|
||||
OstreeSignSpki *sign = _ostree_sign_spki_get_instance_private (OSTREE_SIGN_SPKI (self));
|
||||
|
||||
g_autofree guint8 *key_owned = NULL;
|
||||
const guint8 *key = NULL;
|
||||
gsize n_elements = 0;
|
||||
|
||||
if (g_variant_is_of_type (revoked_key, G_VARIANT_TYPE_STRING))
|
||||
{
|
||||
const gchar *rk_ascii = g_variant_get_string (revoked_key, NULL);
|
||||
key = key_owned = g_base64_decode (rk_ascii, &n_elements);
|
||||
}
|
||||
else if (g_variant_is_of_type (revoked_key, G_VARIANT_TYPE_BYTESTRING))
|
||||
{
|
||||
key = g_variant_get_fixed_array (revoked_key, &n_elements, sizeof (guchar));
|
||||
}
|
||||
else
|
||||
{
|
||||
return glnx_throw (error, "Unknown spki revoked key type");
|
||||
}
|
||||
|
||||
g_autofree char *hex = g_malloc0 (n_elements * 2 + 1);
|
||||
ot_bin2hex (hex, key, n_elements);
|
||||
g_debug ("Read spki revoked key = %s", hex);
|
||||
|
||||
g_autoptr (GBytes) key_bytes = g_bytes_new_static (key, n_elements);
|
||||
if (g_list_find_custom (sign->revoked_keys, key, g_bytes_compare) == NULL)
|
||||
{
|
||||
GBytes *new_key_bytes = g_bytes_new (key, n_elements);
|
||||
sign->revoked_keys = g_list_prepend (sign->revoked_keys, new_key_bytes);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_load_pk_from_stream (OstreeSign *self, GInputStream *key_stream_in, gboolean trusted,
|
||||
GError **error)
|
||||
{
|
||||
if (key_stream_in == NULL)
|
||||
return glnx_throw (error, "spki: unable to read from NULL key-data input stream");
|
||||
|
||||
gboolean ret = FALSE;
|
||||
|
||||
g_autoptr (OstreeBlobReader) blob_reader = ostree_sign_read_pk (self, key_stream_in);
|
||||
g_assert (blob_reader);
|
||||
|
||||
/* Use simple file format with just a list of base64 public keys per line */
|
||||
while (TRUE)
|
||||
{
|
||||
gboolean added = FALSE;
|
||||
g_autoptr (GError) local_error = NULL;
|
||||
g_autoptr (GBytes) blob = ostree_blob_reader_read_blob (blob_reader, NULL, &local_error);
|
||||
|
||||
if (local_error != NULL)
|
||||
{
|
||||
g_propagate_error (error, g_steal_pointer (&local_error));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (blob == NULL)
|
||||
return ret;
|
||||
|
||||
/* Read the key itself */
|
||||
g_autoptr (GVariant) pk = g_variant_new_from_bytes (G_VARIANT_TYPE_BYTESTRING, blob, FALSE);
|
||||
|
||||
if (trusted)
|
||||
added = ostree_sign_spki_add_pk (self, pk, error);
|
||||
else
|
||||
added = _spki_add_revoked (self, pk, error);
|
||||
|
||||
g_autofree gchar *pk_printable = g_variant_print (pk, FALSE);
|
||||
g_debug ("%s %s key: %s", added ? "Added" : "Invalid", trusted ? "public" : "revoked",
|
||||
pk_printable);
|
||||
|
||||
/* Mark what we load at least one key */
|
||||
if (added)
|
||||
ret = TRUE;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_load_pk_from_file (OstreeSign *self, const gchar *filename, gboolean trusted, GError **error)
|
||||
{
|
||||
g_debug ("Processing file '%s'", filename);
|
||||
|
||||
if (!g_file_test (filename, G_FILE_TEST_IS_REGULAR))
|
||||
{
|
||||
g_debug ("Can't open file '%s' with public keys", filename);
|
||||
return glnx_throw (error, "File object '%s' is not a regular file", filename);
|
||||
}
|
||||
|
||||
g_autoptr (GFile) keyfile = keyfile = g_file_new_for_path (filename);
|
||||
g_autoptr (GFileInputStream) key_stream_in = g_file_read (keyfile, NULL, error);
|
||||
if (key_stream_in == NULL)
|
||||
return FALSE;
|
||||
|
||||
if (!_load_pk_from_stream (self, G_INPUT_STREAM (key_stream_in), trusted, error))
|
||||
{
|
||||
if (error == NULL || *error == NULL)
|
||||
return glnx_throw (error, "signature: spki: no valid keys in file '%s'", filename);
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_spki_load_pk (OstreeSign *self, GVariant *options, gboolean trusted, GError **error)
|
||||
{
|
||||
|
||||
gboolean ret = FALSE;
|
||||
const gchar *custom_dir = NULL;
|
||||
|
||||
g_autoptr (GPtrArray) base_dirs = g_ptr_array_new_with_free_func (g_free);
|
||||
g_autoptr (GPtrArray) spki_files = g_ptr_array_new_with_free_func (g_free);
|
||||
|
||||
if (g_variant_lookup (options, "basedir", "&s", &custom_dir))
|
||||
{
|
||||
/* Add custom directory */
|
||||
g_ptr_array_add (base_dirs, g_strdup (custom_dir));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Default paths where to find files with public keys */
|
||||
g_ptr_array_add (base_dirs, g_strdup ("/etc/ostree"));
|
||||
g_ptr_array_add (base_dirs, g_strdup (DATADIR "/ostree"));
|
||||
}
|
||||
|
||||
/* Scan all well-known directories and construct the list with file names to scan keys */
|
||||
for (gint i = 0; i < base_dirs->len; i++)
|
||||
{
|
||||
g_autofree gchar *base_name
|
||||
= g_build_filename ((gchar *)g_ptr_array_index (base_dirs, i),
|
||||
trusted ? "trusted.spki" : "revoked.spki", NULL);
|
||||
|
||||
g_debug ("Check spki keys from file: %s", base_name);
|
||||
g_autofree gchar *base_dir = g_strconcat (base_name, ".d", NULL);
|
||||
g_ptr_array_add (spki_files, g_steal_pointer (&base_name));
|
||||
|
||||
g_autoptr (GDir) dir = g_dir_open (base_dir, 0, error);
|
||||
if (dir == NULL)
|
||||
{
|
||||
g_clear_error (error);
|
||||
continue;
|
||||
}
|
||||
const gchar *entry = NULL;
|
||||
while ((entry = g_dir_read_name (dir)) != NULL)
|
||||
{
|
||||
gchar *filename = g_build_filename (base_dir, entry, NULL);
|
||||
g_debug ("Check spki keys from file: %s", filename);
|
||||
g_ptr_array_add (spki_files, filename);
|
||||
}
|
||||
}
|
||||
|
||||
/* Scan all well-known files */
|
||||
for (gint i = 0; i < spki_files->len; i++)
|
||||
{
|
||||
if (!_load_pk_from_file (self, (gchar *)g_ptr_array_index (spki_files, i), trusted, error))
|
||||
{
|
||||
g_debug ("Problem with loading spki %s keys from `%s`", trusted ? "public" : "revoked",
|
||||
(gchar *)g_ptr_array_index (spki_files, i));
|
||||
g_clear_error (error);
|
||||
}
|
||||
else
|
||||
ret = TRUE;
|
||||
}
|
||||
|
||||
if (!ret && (error == NULL || *error == NULL))
|
||||
return glnx_throw (error, "signature: spki: no keys loaded");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* options argument should be a{sv}:
|
||||
* - filename -- single file to use to load keys from;
|
||||
* - basedir -- directory containing subdirectories
|
||||
* 'trusted.spki.d' and 'revoked.spki.d' with appropriate
|
||||
* public keys. Used for testing and re-definition of system-wide
|
||||
* directories if defaults are not suitable for any reason.
|
||||
*/
|
||||
gboolean
|
||||
ostree_sign_spki_load_pk (OstreeSign *self, GVariant *options, GError **error)
|
||||
{
|
||||
|
||||
const gchar *filename = NULL;
|
||||
|
||||
OstreeSignSpki *sign = _ostree_sign_spki_get_instance_private (OSTREE_SIGN_SPKI (self));
|
||||
if (!_ostree_sign_spki_is_initialized (sign, error))
|
||||
return FALSE;
|
||||
|
||||
/* Read keys only from single file provided */
|
||||
if (g_variant_lookup (options, "filename", "&s", &filename))
|
||||
return _load_pk_from_file (self, filename, TRUE, error);
|
||||
|
||||
/* Load public keys from well-known directories and files */
|
||||
if (!_spki_load_pk (self, options, TRUE, error))
|
||||
return FALSE;
|
||||
|
||||
/* Load untrusted keys from well-known directories and files
|
||||
* Ignore the failure from this function -- it is expected to have
|
||||
* empty list of revoked keys.
|
||||
* */
|
||||
if (!_spki_load_pk (self, options, FALSE, error))
|
||||
g_clear_error (error);
|
||||
|
||||
return TRUE;
|
||||
}
|
54
src/libostree/ostree-sign-spki.h
Normal file
54
src/libostree/ostree-sign-spki.h
Normal file
@ -0,0 +1,54 @@
|
||||
/* vim:set et sw=2 cin cino=t0,f0,(0,{s,>2s,n-s,^-s,e2s: */
|
||||
|
||||
/*
|
||||
* Copyright © 2019 Collabora Ltd.
|
||||
* Copyright © 2024 Red Hat, Inc.
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.0+
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ostree-sign.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define OSTREE_TYPE_SIGN_SPKI (_ostree_sign_spki_get_type ())
|
||||
|
||||
_OSTREE_PUBLIC
|
||||
G_DECLARE_FINAL_TYPE (OstreeSignSpki, _ostree_sign_spki, OSTREE, SIGN_SPKI, GObject)
|
||||
|
||||
gboolean ostree_sign_spki_data (OstreeSign *self, GBytes *data, GBytes **signature,
|
||||
GCancellable *cancellable, GError **error);
|
||||
|
||||
gboolean ostree_sign_spki_data_verify (OstreeSign *self, GBytes *data, GVariant *signatures,
|
||||
char **out_success_message, GError **error);
|
||||
|
||||
const gchar *ostree_sign_spki_get_name (OstreeSign *self);
|
||||
const gchar *ostree_sign_spki_metadata_key (OstreeSign *self);
|
||||
const gchar *ostree_sign_spki_metadata_format (OstreeSign *self);
|
||||
|
||||
gboolean ostree_sign_spki_clear_keys (OstreeSign *self, GError **error);
|
||||
|
||||
gboolean ostree_sign_spki_set_sk (OstreeSign *self, GVariant *secret_key, GError **error);
|
||||
|
||||
gboolean ostree_sign_spki_set_pk (OstreeSign *self, GVariant *public_key, GError **error);
|
||||
|
||||
gboolean ostree_sign_spki_add_pk (OstreeSign *self, GVariant *public_key, GError **error);
|
||||
|
||||
gboolean ostree_sign_spki_load_pk (OstreeSign *self, GVariant *options, GError **error);
|
||||
|
||||
G_END_DECLS
|
@ -39,11 +39,13 @@
|
||||
|
||||
#include "ostree-autocleanups.h"
|
||||
#include "ostree-blob-reader-base64.h"
|
||||
#include "ostree-blob-reader-pem.h"
|
||||
#include "ostree-blob-reader-raw.h"
|
||||
#include "ostree-core.h"
|
||||
#include "ostree-sign-dummy.h"
|
||||
#include "ostree-sign-ed25519.h"
|
||||
#include "ostree-sign-private.h"
|
||||
#include "ostree-sign-spki.h"
|
||||
#include "ostree-sign.h"
|
||||
|
||||
#include "ostree-autocleanups.h"
|
||||
@ -61,6 +63,9 @@ typedef struct
|
||||
_sign_type sign_types[] = {
|
||||
#if defined(HAVE_ED25519)
|
||||
{ OSTREE_SIGN_NAME_ED25519, 0 },
|
||||
#endif
|
||||
#if defined(HAVE_SPKI)
|
||||
{ OSTREE_SIGN_NAME_SPKI, 0 },
|
||||
#endif
|
||||
{ "dummy", 0 }
|
||||
};
|
||||
@ -69,6 +74,9 @@ enum
|
||||
{
|
||||
#if defined(HAVE_ED25519)
|
||||
SIGN_ED25519,
|
||||
#endif
|
||||
#if defined(HAVE_SPKI)
|
||||
SIGN_SPKI,
|
||||
#endif
|
||||
SIGN_DUMMY
|
||||
};
|
||||
@ -538,6 +546,10 @@ ostree_sign_get_by_name (const gchar *name, GError **error)
|
||||
#if defined(HAVE_ED25519)
|
||||
if (sign_types[SIGN_ED25519].type == 0)
|
||||
sign_types[SIGN_ED25519].type = OSTREE_TYPE_SIGN_ED25519;
|
||||
#endif
|
||||
#if defined(HAVE_SPKI)
|
||||
if (sign_types[SIGN_SPKI].type == 0)
|
||||
sign_types[SIGN_SPKI].type = OSTREE_TYPE_SIGN_SPKI;
|
||||
#endif
|
||||
if (sign_types[SIGN_DUMMY].type == 0)
|
||||
sign_types[SIGN_DUMMY].type = OSTREE_TYPE_SIGN_DUMMY;
|
||||
@ -661,6 +673,10 @@ ostree_sign_read_pk (OstreeSign *self, GInputStream *stream)
|
||||
#if defined(HAVE_ED25519)
|
||||
if (OSTREE_IS_SIGN_ED25519 (self))
|
||||
return OSTREE_BLOB_READER (_ostree_blob_reader_base64_new (stream));
|
||||
#endif
|
||||
#if defined(HAVE_SPKI)
|
||||
if (OSTREE_IS_SIGN_SPKI (self))
|
||||
return OSTREE_BLOB_READER (_ostree_blob_reader_pem_new (stream, "PUBLIC KEY"));
|
||||
#endif
|
||||
if (OSTREE_IS_SIGN_DUMMY (self))
|
||||
return OSTREE_BLOB_READER (_ostree_blob_reader_raw_new (stream));
|
||||
@ -684,6 +700,10 @@ ostree_sign_read_sk (OstreeSign *self, GInputStream *stream)
|
||||
#if defined(HAVE_ED25519)
|
||||
if (OSTREE_IS_SIGN_ED25519 (self))
|
||||
return OSTREE_BLOB_READER (_ostree_blob_reader_base64_new (stream));
|
||||
#endif
|
||||
#if defined(HAVE_SPKI)
|
||||
if (OSTREE_IS_SIGN_SPKI (self))
|
||||
return OSTREE_BLOB_READER (_ostree_blob_reader_pem_new (stream, "PRIVATE KEY"));
|
||||
#endif
|
||||
if (OSTREE_IS_SIGN_DUMMY (self))
|
||||
return OSTREE_BLOB_READER (_ostree_blob_reader_raw_new (stream));
|
||||
|
@ -44,6 +44,14 @@ G_BEGIN_DECLS
|
||||
*/
|
||||
#define OSTREE_SIGN_NAME_ED25519 "ed25519"
|
||||
|
||||
/**
|
||||
* OSTREE_SIGN_NAME_SPKI:
|
||||
* The name of the spki signing type.
|
||||
*
|
||||
* Since: 2024.7
|
||||
*/
|
||||
#define OSTREE_SIGN_NAME_SPKI "spki"
|
||||
|
||||
_OSTREE_PUBLIC
|
||||
G_DECLARE_INTERFACE (OstreeSign, ostree_sign, OSTREE, SIGN, GObject)
|
||||
|
||||
|
89
src/libotcore/otcore-spki-verify.c
Normal file
89
src/libotcore/otcore-spki-verify.c
Normal file
@ -0,0 +1,89 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: LGPL-2.0+
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "otcore.h"
|
||||
|
||||
/* Initialize global state; may be called multiple times and is idempotent. */
|
||||
bool
|
||||
otcore_spki_init (void)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Validate a single spki signature. If there is an unexpected state, such
|
||||
* as an ill-forumed public key or signature, a hard error will be returned.
|
||||
*
|
||||
* If the signature is not correct, this function will return successfully, but
|
||||
* `out_valid` will be set to `false`.
|
||||
*
|
||||
* If the signature is correct, `out_valid` will be `true`.
|
||||
*/
|
||||
gboolean
|
||||
otcore_validate_spki_signature (GBytes *data, GBytes *public_key, GBytes *signature,
|
||||
bool *out_valid, GError **error)
|
||||
{
|
||||
// Since this is signature verification code, let's verify preconditions.
|
||||
g_assert (data);
|
||||
g_assert (public_key);
|
||||
g_assert (signature);
|
||||
g_assert (out_valid);
|
||||
// It is OK for error to be NULL, though according to GError rules.
|
||||
|
||||
#if defined(HAVE_OPENSSL)
|
||||
gsize public_key_size;
|
||||
const guint8 *public_key_buf = g_bytes_get_data (public_key, &public_key_size);
|
||||
|
||||
gsize signature_size;
|
||||
const guint8 *signature_buf = g_bytes_get_data (signature, &signature_size);
|
||||
|
||||
if (public_key_size > OSTREE_SIGN_MAX_METADATA_SIZE)
|
||||
return glnx_throw (
|
||||
error, "Invalid public key of %" G_GSIZE_FORMAT " bytes, expected <= %" G_GSIZE_FORMAT,
|
||||
public_key_size, (gsize)OSTREE_SIGN_MAX_METADATA_SIZE);
|
||||
|
||||
if (signature_size > OSTREE_SIGN_MAX_METADATA_SIZE)
|
||||
return glnx_throw (
|
||||
error, "Invalid signature of %" G_GSIZE_FORMAT " bytes, expected <= %" G_GSIZE_FORMAT,
|
||||
signature_size, (gsize)OSTREE_SIGN_MAX_METADATA_SIZE);
|
||||
|
||||
EVP_MD_CTX *ctx = EVP_MD_CTX_new ();
|
||||
if (!ctx)
|
||||
return glnx_throw (error, "openssl: failed to allocate context");
|
||||
|
||||
const unsigned char *p = public_key_buf;
|
||||
EVP_PKEY *pkey = d2i_PUBKEY (NULL, &p, public_key_size);
|
||||
if (!pkey)
|
||||
{
|
||||
EVP_MD_CTX_free (ctx);
|
||||
return glnx_throw (error, "openssl: Failed to initialize spki key");
|
||||
}
|
||||
if (EVP_DigestVerifyInit (ctx, NULL, NULL, NULL, pkey) != 0
|
||||
&& EVP_DigestVerify (ctx, signature_buf, signature_size, g_bytes_get_data (data, NULL),
|
||||
g_bytes_get_size (data))
|
||||
!= 0)
|
||||
{
|
||||
*out_valid = true;
|
||||
}
|
||||
EVP_PKEY_free (pkey);
|
||||
EVP_MD_CTX_free (ctx);
|
||||
return TRUE;
|
||||
#else
|
||||
return glnx_throw (error, "spki signature validation requested, but support not compiled in");
|
||||
#endif
|
||||
}
|
@ -27,6 +27,7 @@
|
||||
#define USE_LIBSODIUM
|
||||
#elif defined(HAVE_OPENSSL)
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/x509.h>
|
||||
#define USE_OPENSSL
|
||||
#endif
|
||||
|
||||
@ -39,10 +40,22 @@
|
||||
// The variant type
|
||||
#define OSTREE_SIGN_METADATA_ED25519_TYPE "aay"
|
||||
|
||||
// This key is stored inside commit metadata.
|
||||
#define OSTREE_SIGN_METADATA_SPKI_KEY "ostree.sign.spki"
|
||||
// The variant type
|
||||
#define OSTREE_SIGN_METADATA_SPKI_TYPE "aay"
|
||||
|
||||
// Maximum size of metadata in bytes, in sync with OSTREE_MAX_METADATA_SIZE
|
||||
#define OSTREE_SIGN_MAX_METADATA_SIZE (128 * 1024 * 1024)
|
||||
|
||||
bool otcore_ed25519_init (void);
|
||||
gboolean otcore_validate_ed25519_signature (GBytes *data, GBytes *pubkey, GBytes *signature,
|
||||
bool *out_valid, GError **error);
|
||||
|
||||
bool otcore_spki_init (void);
|
||||
gboolean otcore_validate_spki_signature (GBytes *data, GBytes *public_key, GBytes *signature,
|
||||
bool *out_valid, GError **error);
|
||||
|
||||
char *otcore_find_proc_cmdline_key (const char *cmdline, const char *key);
|
||||
gboolean otcore_get_ostree_target (const char *cmdline, gboolean *is_aboot, char **out_target,
|
||||
GError **error);
|
||||
|
@ -780,6 +780,40 @@ gen_ed25519_random_public()
|
||||
openssl genpkey -algorithm ED25519 | openssl pkey -outform DER | tail -c 32 | base64
|
||||
}
|
||||
|
||||
# Keys for spki signing tests
|
||||
SPKIPUBLICPEM=
|
||||
SPKISECRETPEM=
|
||||
|
||||
SPKIPUBLIC=
|
||||
SPKISECRET=
|
||||
|
||||
gen_spki_keys ()
|
||||
{
|
||||
# Generate private key in PEM format
|
||||
SPKISECRETPEM="$(mktemp -p ${test_tmpdir} ed448_sk_XXXXXX.pem)"
|
||||
openssl genpkey -algorithm ed448 -outform PEM -out "${SPKISECRETPEM}"
|
||||
SPKIPUBLICPEM="$(mktemp -p ${test_tmpdir} ed448_pk_XXXXXX.pem)"
|
||||
openssl pkey -outform PEM -pubout -in "${SPKISECRETPEM}" -out "${SPKIPUBLICPEM}"
|
||||
|
||||
SPKIPUBLIC="$(openssl pkey -inform PEM -outform DER -pubin -pubout -in ${SPKIPUBLICPEM} | base64 -w 0)"
|
||||
SPKISECRET="$(openssl pkey -inform PEM -outform DER -in ${SPKISECRETPEM} | base64 -w 0)"
|
||||
|
||||
echo "Generated ed448 keys:"
|
||||
echo "public: ${SPKIPUBLIC}"
|
||||
echo "secret: ${SPKISECRET}"
|
||||
}
|
||||
|
||||
gen_spki_random_public()
|
||||
{
|
||||
openssl genpkey -algorithm ed448 | openssl pkey -pubout -outform DER | base64 -w 0
|
||||
echo
|
||||
}
|
||||
|
||||
gen_spki_random_public_pem()
|
||||
{
|
||||
openssl genpkey -algorithm ed448 | openssl pkey -pubout -outform PEM
|
||||
}
|
||||
|
||||
is_bare_user_only_repo () {
|
||||
grep -q 'mode=bare-user-only' $1/config
|
||||
}
|
||||
|
61
tests/test-signed-commit-dummy.sh
Executable file
61
tests/test-signed-commit-dummy.sh
Executable file
@ -0,0 +1,61 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Copyright (C) 2019 Collabora Ltd.
|
||||
#
|
||||
# SPDX-License-Identifier: LGPL-2.0+
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This library is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
. $(dirname $0)/libtest.sh
|
||||
|
||||
# This is explicitly opt in for testing
|
||||
export OSTREE_DUMMY_SIGN_ENABLED=1
|
||||
|
||||
mkdir ${test_tmpdir}/repo
|
||||
ostree_repo_init repo --mode="archive"
|
||||
|
||||
echo "Unsigned commit" > file.txt
|
||||
${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo commit -b main -s 'Unsigned commit'
|
||||
COMMIT="$(ostree --repo=${test_tmpdir}/repo rev-parse main)"
|
||||
|
||||
# Test `ostree sign` with dummy module first
|
||||
DUMMYSIGN="dummysign"
|
||||
${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --sign-type=dummy ${COMMIT} ${DUMMYSIGN}
|
||||
|
||||
# Ensure that detached metadata really contain expected string
|
||||
EXPECTEDSIGN="$(echo $DUMMYSIGN | hexdump -n 9 -e '8/1 "0x%.2x, " 1/1 " 0x%.2x"')"
|
||||
${CMD_PREFIX} ostree --repo=repo show ${COMMIT} --print-detached-metadata-key=ostree.sign.dummy | grep -q -e "${EXPECTEDSIGN}"
|
||||
tap_ok "Detached dummy signature added"
|
||||
|
||||
# Verify vith sign mechanism
|
||||
${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --sign-type=dummy --verify ${COMMIT} ${DUMMYSIGN}
|
||||
tap_ok "dummy signature verified"
|
||||
|
||||
echo "Signed commit with dummy key: ${DUMMYSIGN}" >> file.txt
|
||||
${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo commit -b main -s 'Signed with dummy module' --sign=${DUMMYSIGN} --sign-type=dummy
|
||||
COMMIT="$(ostree --repo=${test_tmpdir}/repo rev-parse main)"
|
||||
${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --sign-type=dummy --verify ${COMMIT} ${DUMMYSIGN}
|
||||
tap_ok "commit with dummy signing"
|
||||
|
||||
if ${CMD_PREFIX} env -u OSTREE_DUMMY_SIGN_ENABLED ostree --repo=${test_tmpdir}/repo sign --sign-type=dummy --verify ${COMMIT} ${DUMMYSIGN} 2>err.txt; then
|
||||
fatal "verified dummy signature without env"
|
||||
fi
|
||||
# FIXME the error message here is broken
|
||||
#assert_file_has_content_literal err.txt 'dummy signature type is only for ostree testing'
|
||||
assert_file_has_content_literal err.txt ' No valid signatures found'
|
||||
tap_ok "dummy sig requires env"
|
||||
|
||||
tap_end
|
@ -27,48 +27,8 @@ export OSTREE_DUMMY_SIGN_ENABLED=1
|
||||
mkdir ${test_tmpdir}/repo
|
||||
ostree_repo_init repo --mode="archive"
|
||||
|
||||
echo "Unsigned commit" > file.txt
|
||||
${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo commit -b main -s 'Unsigned commit'
|
||||
COMMIT="$(ostree --repo=${test_tmpdir}/repo rev-parse main)"
|
||||
|
||||
# Test `ostree sign` with dummy module first
|
||||
# For multi-sign test
|
||||
DUMMYSIGN="dummysign"
|
||||
${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --sign-type=dummy ${COMMIT} ${DUMMYSIGN}
|
||||
|
||||
# Ensure that detached metadata really contain expected string
|
||||
EXPECTEDSIGN="$(echo $DUMMYSIGN | hexdump -n 9 -e '8/1 "0x%.2x, " 1/1 " 0x%.2x"')"
|
||||
${CMD_PREFIX} ostree --repo=repo show ${COMMIT} --print-detached-metadata-key=ostree.sign.dummy | grep -q -e "${EXPECTEDSIGN}"
|
||||
tap_ok "Detached dummy signature added"
|
||||
|
||||
# Verify vith sign mechanism
|
||||
${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --sign-type=dummy --verify ${COMMIT} ${DUMMYSIGN}
|
||||
tap_ok "dummy signature verified"
|
||||
|
||||
echo "Signed commit with dummy key: ${DUMMYSIGN}" >> file.txt
|
||||
${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo commit -b main -s 'Signed with dummy module' --sign=${DUMMYSIGN} --sign-type=dummy
|
||||
COMMIT="$(ostree --repo=${test_tmpdir}/repo rev-parse main)"
|
||||
${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --sign-type=dummy --verify ${COMMIT} ${DUMMYSIGN}
|
||||
tap_ok "commit with dummy signing"
|
||||
|
||||
if ${CMD_PREFIX} env -u OSTREE_DUMMY_SIGN_ENABLED ostree --repo=${test_tmpdir}/repo sign --sign-type=dummy --verify ${COMMIT} ${DUMMYSIGN} 2>err.txt; then
|
||||
fatal "verified dummy signature without env"
|
||||
fi
|
||||
# FIXME the error message here is broken
|
||||
#assert_file_has_content_literal err.txt 'dummy signature type is only for ostree testing'
|
||||
assert_file_has_content_literal err.txt ' No valid signatures found'
|
||||
tap_ok "dummy sig requires env"
|
||||
|
||||
# tests below require libsodium support
|
||||
if ! has_ostree_feature sign-ed25519; then
|
||||
tap_ok "Detached ed25519 signature # SKIP due libsodium unavailability"
|
||||
tap_ok "ed25519 signature verified # SKIP due libsodium unavailability"
|
||||
tap_ok "multiple signing # SKIP due libsodium unavailability"
|
||||
tap_ok "verify ed25519 keys file # SKIP due libsodium unavailability"
|
||||
tap_ok "sign with ed25519 keys file # SKIP due libsodium unavailability"
|
||||
tap_ok "verify ed25519 system-wide configuration # SKIP due libsodium unavailability"
|
||||
tap_ok "verify ed25519 revoking keys mechanism # SKIP due libsodium unavailability"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Test ostree sign with 'ed25519' module
|
||||
gen_ed25519_keys
|
164
tests/test-signed-commit-spki.sh
Executable file
164
tests/test-signed-commit-spki.sh
Executable file
@ -0,0 +1,164 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Copyright (C) 2019 Collabora Ltd.
|
||||
#
|
||||
# SPDX-License-Identifier: LGPL-2.0+
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This library is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
. $(dirname $0)/libtest.sh
|
||||
|
||||
# This is explicitly opt in for testing
|
||||
export OSTREE_DUMMY_SIGN_ENABLED=1
|
||||
|
||||
mkdir ${test_tmpdir}/repo
|
||||
ostree_repo_init repo --mode="archive"
|
||||
|
||||
# For multi-sign test
|
||||
DUMMYSIGN="dummysign"
|
||||
|
||||
# Test ostree sign with 'spki' module
|
||||
gen_spki_keys
|
||||
PUBLIC=${SPKIPUBLIC}
|
||||
SECRET=${SPKISECRET}
|
||||
|
||||
WRONG_PUBLIC="$(gen_spki_random_public)"
|
||||
|
||||
echo "PUBLIC = $PUBLIC"
|
||||
|
||||
echo "Signed commit with spki: ${SECRET}" >> file.txt
|
||||
${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo commit -b main -s "Signed with spki module" --sign="${SECRET}" --sign-type=spki
|
||||
COMMIT="$(ostree --repo=${test_tmpdir}/repo rev-parse main)"
|
||||
|
||||
# Ensure that detached metadata contain signature
|
||||
${CMD_PREFIX} ostree --repo=repo show ${COMMIT} --print-detached-metadata-key=ostree.sign.spki &>/dev/null
|
||||
tap_ok "Detached spki signature added"
|
||||
|
||||
# Verify vith sign mechanism
|
||||
if ${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --verify --sign-type=spki ${COMMIT} ${WRONG_PUBLIC}; then
|
||||
exit 1
|
||||
fi
|
||||
${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --verify --sign-type=spki ${COMMIT} ${PUBLIC}
|
||||
${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --verify --sign-type=spki ${COMMIT} ${PUBLIC} ${PUBLIC}
|
||||
${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --verify --sign-type=spki ${COMMIT} $(gen_spki_random_public) ${PUBLIC}
|
||||
${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --verify --sign-type=spki ${COMMIT} $(gen_spki_random_public) $(gen_spki_random_public) ${PUBLIC}
|
||||
${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --verify --sign-type=spki ${COMMIT} ${PUBLIC} $(gen_spki_random_public) $(gen_spki_random_public)
|
||||
${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --verify --sign-type=spki ${COMMIT} $(gen_spki_random_public) $(gen_spki_random_public) ${PUBLIC} $(gen_spki_random_public) $(gen_spki_random_public)
|
||||
tap_ok "spki signature verified"
|
||||
|
||||
# Check if we are able to use all available modules to sign the same commit
|
||||
echo "Unsigned commit for multi-sign" >> file.txt
|
||||
${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo commit -b main -s 'Unsigned commit'
|
||||
COMMIT="$(ostree --repo=${test_tmpdir}/repo rev-parse main)"
|
||||
# Check if we have no signatures
|
||||
for mod in "dummy" "spki"; do
|
||||
if ostree --repo=repo show ${COMMIT} --print-detached-metadata-key=ostree.sign.${mod}; then
|
||||
echo "Unexpected signature for ${mod} found"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
# Sign with all available modules
|
||||
${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --sign-type=dummy ${COMMIT} ${DUMMYSIGN}
|
||||
${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --sign-type=spki ${COMMIT} ${SECRET}
|
||||
# and verify
|
||||
${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --verify --sign-type=spki ${COMMIT} ${PUBLIC} >out.txt
|
||||
assert_file_has_content out.txt "spki: Signature verified successfully with key"
|
||||
${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --sign-type=dummy --verify ${COMMIT} ${DUMMYSIGN} >out.txt
|
||||
assert_file_has_content out.txt "dummy: Signature verified"
|
||||
tap_ok "multiple signing "
|
||||
|
||||
# Prepare files with public spki signatures
|
||||
PUBKEYS="$(mktemp -p ${test_tmpdir} spki_XXXXXX.spki)"
|
||||
|
||||
# Test if file contain no keys
|
||||
if ${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --verify --sign-type=spki --keys-file=${PUBKEYS} ${COMMIT}; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Test if have a problem with file object
|
||||
if ${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --verify --sign-type=spki --keys-file=${test_tmpdir} ${COMMIT}; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Test with single key in list
|
||||
cat ${SPKIPUBLICPEM} > ${PUBKEYS}
|
||||
${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --verify --sign-type=spki --keys-file=${PUBKEYS} ${COMMIT} >out.txt
|
||||
assert_file_has_content out.txt 'spki: Signature verified successfully'
|
||||
|
||||
# Test the file with multiple keys without a valid public key
|
||||
for((i=0;i<100;i++)); do
|
||||
# Generate a list with some public signatures
|
||||
gen_spki_random_public_pem
|
||||
done > ${PUBKEYS}
|
||||
# Check if file contain no valid signatures
|
||||
if ${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --verify --sign-type=spki --keys-file=${PUBKEYS} ${COMMIT} 2>err.txt; then
|
||||
fatal "validated with no signatures"
|
||||
fi
|
||||
assert_file_has_content err.txt 'error:.* spki: Signature couldn.t be verified; tried 100 keys'
|
||||
# Check if no valid signatures provided via args&file
|
||||
if ${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --verify --sign-type=spki --keys-file=${PUBKEYS} ${COMMIT} ${WRONG_PUBLIC}; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
#Test keys file and public key
|
||||
${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --verify --sign-type=spki --keys-file=${PUBKEYS} ${COMMIT} ${PUBLIC}
|
||||
|
||||
# Add correct key into the list
|
||||
cat "${SPKIPUBLICPEM}" >> ${PUBKEYS}
|
||||
${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --verify --sign-type=spki --keys-file=${PUBKEYS} ${COMMIT}
|
||||
|
||||
tap_ok "verify spki keys file"
|
||||
|
||||
# Check spki signing with secret file
|
||||
echo "Unsigned commit for secret file usage" >> file.txt
|
||||
${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo commit -b main -s 'Unsigned commit'
|
||||
COMMIT="$(ostree --repo=${test_tmpdir}/repo rev-parse main)"
|
||||
|
||||
KEYFILE="$(mktemp -p ${test_tmpdir} secret_XXXXXX.spki)"
|
||||
cat "${SPKISECRETPEM}" > ${KEYFILE}
|
||||
# Sign
|
||||
${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --sign-type=spki --keys-file=${KEYFILE} ${COMMIT}
|
||||
# Verify
|
||||
${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --verify --sign-type=spki --keys-file=${PUBKEYS} ${COMMIT}
|
||||
tap_ok "sign with spki keys file"
|
||||
|
||||
# Check the well-known places mechanism
|
||||
mkdir -p ${test_tmpdir}/{trusted,revoked}.spki.d
|
||||
for((i=0;i<100;i++)); do
|
||||
# Generate some key files with random public signatures
|
||||
gen_spki_random_public_pem > ${test_tmpdir}/trusted.spki.d/signature_$i
|
||||
done
|
||||
# Check no valid public keys are available
|
||||
if ${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --verify --sign-type=spki --keys-dir=${test_tmpdir} ${COMMIT}; then
|
||||
exit 1
|
||||
fi
|
||||
cat "${SPKIPUBLICPEM}" > ${test_tmpdir}/trusted.spki.d/correct
|
||||
# Verify with correct key
|
||||
${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --verify --sign-type=spki --keys-dir=${test_tmpdir} ${COMMIT}
|
||||
|
||||
tap_ok "verify spki system-wide configuration"
|
||||
|
||||
# Add the public key into revoked list
|
||||
cat "${SPKIPUBLICPEM}" > ${test_tmpdir}/revoked.spki.d/correct
|
||||
# Check if public key is not valid anymore
|
||||
if ${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo sign --verify --sign-type=spki --keys-dir=${test_tmpdir} ${COMMIT}; then
|
||||
exit 1
|
||||
fi
|
||||
rm -rf ${test_tmpdir}/{trusted,revoked}.spki.d
|
||||
tap_ok "verify spki revoking keys mechanism"
|
||||
|
||||
tap_end
|
Loading…
Reference in New Issue
Block a user