mirror of
https://git.proxmox.com/git/fwupd
synced 2025-08-06 04:57:59 +00:00
Return the authority and timestamp as part of the signing validation
This means we return an error when encountering a rollback attack. This can currently be performed by providing the old metadata and old signature when calling into UpdateMetadata.
This commit is contained in:
parent
7cc2679f09
commit
f69a4810fa
@ -18,6 +18,7 @@ colorhug_pkcs7_signature = custom_target('firmware.bin.p7b',
|
|||||||
input: 'firmware.bin',
|
input: 'firmware.bin',
|
||||||
output: 'firmware.bin.p7b',
|
output: 'firmware.bin.p7b',
|
||||||
command: [certtool, '--p7-detached-sign',
|
command: [certtool, '--p7-detached-sign',
|
||||||
|
'--p7-time',
|
||||||
'--load-privkey', pkcs7_privkey,
|
'--load-privkey', pkcs7_privkey,
|
||||||
'--load-certificate', pkcs7_certificate,
|
'--load-certificate', pkcs7_certificate,
|
||||||
'--infile', '@INPUT@',
|
'--infile', '@INPUT@',
|
||||||
|
@ -304,6 +304,7 @@ fu_engine_get_release_trust_flags (AsRelease *release,
|
|||||||
g_autofree gchar *pki_dir = NULL;
|
g_autofree gchar *pki_dir = NULL;
|
||||||
g_autoptr(GError) error_local = NULL;
|
g_autoptr(GError) error_local = NULL;
|
||||||
g_autoptr(FuKeyring) kr = NULL;
|
g_autoptr(FuKeyring) kr = NULL;
|
||||||
|
g_autoptr(FuKeyringResult) kr_result = NULL;
|
||||||
struct {
|
struct {
|
||||||
FwupdKeyringKind kind;
|
FwupdKeyringKind kind;
|
||||||
const gchar *ext;
|
const gchar *ext;
|
||||||
@ -365,7 +366,8 @@ fu_engine_get_release_trust_flags (AsRelease *release,
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
if (!fu_keyring_setup (kr, pki_dir, error))
|
if (!fu_keyring_setup (kr, pki_dir, error))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
if (!fu_keyring_verify_data (kr, blob_payload, blob_signature, &error_local)) {
|
kr_result = fu_keyring_verify_data (kr, blob_payload, blob_signature, &error_local);
|
||||||
|
if (kr_result == NULL) {
|
||||||
g_warning ("untrusted as failed to verify: %s",
|
g_warning ("untrusted as failed to verify: %s",
|
||||||
error_local->message);
|
error_local->message);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
@ -1432,6 +1434,23 @@ fu_engine_load_metadata_store (FuEngine *self, GError **error)
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static FuKeyringResult *
|
||||||
|
fu_engine_get_existing_keyring_result (FuEngine *self,
|
||||||
|
FuKeyring *kr,
|
||||||
|
FwupdRemote *remote,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
g_autoptr(GBytes) blob = NULL;
|
||||||
|
g_autoptr(GBytes) blob_sig = NULL;
|
||||||
|
blob = fu_common_get_contents_bytes (fwupd_remote_get_filename_cache (remote), error);
|
||||||
|
if (blob == NULL)
|
||||||
|
return NULL;
|
||||||
|
blob_sig = fu_common_get_contents_bytes (fwupd_remote_get_filename_cache_sig (remote), error);
|
||||||
|
if (blob_sig == NULL)
|
||||||
|
return NULL;
|
||||||
|
return fu_keyring_verify_data (kr, blob, blob_sig, error);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* fu_engine_update_metadata:
|
* fu_engine_update_metadata:
|
||||||
* @self: A #FuEngine
|
* @self: A #FuEngine
|
||||||
@ -1499,13 +1518,52 @@ fu_engine_update_metadata (FuEngine *self, const gchar *remote_id,
|
|||||||
keyring_kind = fwupd_remote_get_keyring_kind (remote);
|
keyring_kind = fwupd_remote_get_keyring_kind (remote);
|
||||||
if (keyring_kind != FWUPD_KEYRING_KIND_NONE) {
|
if (keyring_kind != FWUPD_KEYRING_KIND_NONE) {
|
||||||
g_autoptr(FuKeyring) kr = NULL;
|
g_autoptr(FuKeyring) kr = NULL;
|
||||||
|
g_autoptr(FuKeyringResult) kr_result = NULL;
|
||||||
|
g_autoptr(FuKeyringResult) kr_result_old = NULL;
|
||||||
|
g_autoptr(GError) error_local = NULL;
|
||||||
kr = fu_engine_get_keyring_for_kind (keyring_kind, error);
|
kr = fu_engine_get_keyring_for_kind (keyring_kind, error);
|
||||||
if (kr == NULL)
|
if (kr == NULL)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
if (!fu_keyring_setup (kr, "/etc/pki/fwupd-metadata", error))
|
if (!fu_keyring_setup (kr, "/etc/pki/fwupd-metadata", error))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
if (!fu_keyring_verify_data (kr, bytes_raw, bytes_sig, error))
|
kr_result = fu_keyring_verify_data (kr, bytes_raw, bytes_sig, error);
|
||||||
|
if (kr_result == NULL)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
|
/* verify the metadata was signed later than the existing
|
||||||
|
* metadata for this remote to mitigate a rollback attack */
|
||||||
|
kr_result_old = fu_engine_get_existing_keyring_result (self, kr,
|
||||||
|
remote,
|
||||||
|
&error_local);
|
||||||
|
if (kr_result_old == NULL) {
|
||||||
|
if (g_error_matches (error_local,
|
||||||
|
G_FILE_ERROR,
|
||||||
|
G_FILE_ERROR_NOENT)) {
|
||||||
|
g_debug ("no existing valid keyrings: %s",
|
||||||
|
error_local->message);
|
||||||
|
} else {
|
||||||
|
g_warning ("could not get existing keyring result: %s",
|
||||||
|
error_local->message);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
gint64 delta = 0;
|
||||||
|
if (fu_keyring_result_get_timestamp (kr_result) > 0 &&
|
||||||
|
fu_keyring_result_get_timestamp (kr_result_old) > 0) {
|
||||||
|
delta = fu_keyring_result_get_timestamp (kr_result) -
|
||||||
|
fu_keyring_result_get_timestamp (kr_result_old);
|
||||||
|
}
|
||||||
|
if (delta < 0) {
|
||||||
|
g_set_error (error,
|
||||||
|
FWUPD_ERROR,
|
||||||
|
FWUPD_ERROR_INVALID_FILE,
|
||||||
|
"new signing timestamp was %"
|
||||||
|
G_GINT64_FORMAT " seconds older",
|
||||||
|
-delta);
|
||||||
|
return FALSE;
|
||||||
|
} else if (delta > 0) {
|
||||||
|
g_debug ("timestamp increased, so no rollback");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* save XML and signature to remotes.d */
|
/* save XML and signature to remotes.d */
|
||||||
|
@ -233,7 +233,7 @@ fu_keyring_gpg_check_signature (gpgme_signature_t signature, GError **error)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static FuKeyringResult *
|
||||||
fu_keyring_gpg_verify_data (FuKeyring *keyring,
|
fu_keyring_gpg_verify_data (FuKeyring *keyring,
|
||||||
GBytes *blob,
|
GBytes *blob,
|
||||||
GBytes *blob_signature,
|
GBytes *blob_signature,
|
||||||
@ -243,8 +243,10 @@ fu_keyring_gpg_verify_data (FuKeyring *keyring,
|
|||||||
gpgme_error_t rc;
|
gpgme_error_t rc;
|
||||||
gpgme_signature_t s;
|
gpgme_signature_t s;
|
||||||
gpgme_verify_result_t result;
|
gpgme_verify_result_t result;
|
||||||
|
gint64 timestamp_newest = 0;
|
||||||
g_auto(gpgme_data_t) data = NULL;
|
g_auto(gpgme_data_t) data = NULL;
|
||||||
g_auto(gpgme_data_t) sig = NULL;
|
g_auto(gpgme_data_t) sig = NULL;
|
||||||
|
g_autoptr(GString) authority_newest = g_string_new (NULL);
|
||||||
|
|
||||||
/* load file data */
|
/* load file data */
|
||||||
rc = gpgme_data_new_from_mem (&data,
|
rc = gpgme_data_new_from_mem (&data,
|
||||||
@ -256,7 +258,7 @@ fu_keyring_gpg_verify_data (FuKeyring *keyring,
|
|||||||
FWUPD_ERROR_INTERNAL,
|
FWUPD_ERROR_INTERNAL,
|
||||||
"failed to load data: %s",
|
"failed to load data: %s",
|
||||||
gpgme_strerror (rc));
|
gpgme_strerror (rc));
|
||||||
return FALSE;
|
return NULL;
|
||||||
}
|
}
|
||||||
rc = gpgme_data_new_from_mem (&sig,
|
rc = gpgme_data_new_from_mem (&sig,
|
||||||
g_bytes_get_data (blob_signature, NULL),
|
g_bytes_get_data (blob_signature, NULL),
|
||||||
@ -267,7 +269,7 @@ fu_keyring_gpg_verify_data (FuKeyring *keyring,
|
|||||||
FWUPD_ERROR_INTERNAL,
|
FWUPD_ERROR_INTERNAL,
|
||||||
"failed to load signature: %s",
|
"failed to load signature: %s",
|
||||||
gpgme_strerror (rc));
|
gpgme_strerror (rc));
|
||||||
return FALSE;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* verify */
|
/* verify */
|
||||||
@ -278,7 +280,7 @@ fu_keyring_gpg_verify_data (FuKeyring *keyring,
|
|||||||
FWUPD_ERROR_INTERNAL,
|
FWUPD_ERROR_INTERNAL,
|
||||||
"failed to verify data: %s",
|
"failed to verify data: %s",
|
||||||
gpgme_strerror (rc));
|
gpgme_strerror (rc));
|
||||||
return FALSE;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -289,16 +291,25 @@ fu_keyring_gpg_verify_data (FuKeyring *keyring,
|
|||||||
FWUPD_ERROR,
|
FWUPD_ERROR,
|
||||||
FWUPD_ERROR_INTERNAL,
|
FWUPD_ERROR_INTERNAL,
|
||||||
"no result record from libgpgme");
|
"no result record from libgpgme");
|
||||||
return FALSE;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* look at each signature */
|
/* look at each signature */
|
||||||
for (s = result->signatures; s != NULL ; s = s->next ) {
|
for (s = result->signatures; s != NULL ; s = s->next ) {
|
||||||
g_debug ("returned signature fingerprint %s", s->fpr);
|
g_debug ("returned signature fingerprint %s", s->fpr);
|
||||||
if (!fu_keyring_gpg_check_signature (s, error))
|
if (!fu_keyring_gpg_check_signature (s, error))
|
||||||
return FALSE;
|
return NULL;
|
||||||
|
|
||||||
|
/* save details about the key for the result */
|
||||||
|
if ((gint64) s->timestamp > timestamp_newest) {
|
||||||
|
timestamp_newest = (gint64) s->timestamp;
|
||||||
|
g_string_assign (authority_newest, s->fpr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return TRUE;
|
return FU_KEYRING_RESULT (g_object_new (FU_TYPE_KEYRING_RESULT,
|
||||||
|
"timestamp", timestamp_newest,
|
||||||
|
"authority", authority_newest->str,
|
||||||
|
NULL));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -36,6 +36,7 @@ struct _FuKeyringPkcs7
|
|||||||
G_DEFINE_TYPE (FuKeyringPkcs7, fu_keyring_pkcs7, FU_TYPE_KEYRING)
|
G_DEFINE_TYPE (FuKeyringPkcs7, fu_keyring_pkcs7, FU_TYPE_KEYRING)
|
||||||
|
|
||||||
G_DEFINE_AUTO_CLEANUP_FREE_FUNC(gnutls_pkcs7_t, gnutls_pkcs7_deinit, NULL)
|
G_DEFINE_AUTO_CLEANUP_FREE_FUNC(gnutls_pkcs7_t, gnutls_pkcs7_deinit, NULL)
|
||||||
|
G_DEFINE_AUTO_CLEANUP_FREE_FUNC(gnutls_x509_dn_t, gnutls_x509_dn_deinit, NULL)
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
fu_keyring_pkcs7_add_public_key (FuKeyringPkcs7 *self,
|
fu_keyring_pkcs7_add_public_key (FuKeyringPkcs7 *self,
|
||||||
@ -120,7 +121,35 @@ fu_keyring_pkcs7_setup (FuKeyring *keyring, const gchar *public_key_dir, GError
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static void
|
||||||
|
_gnutls_datum_deinit (gnutls_datum_t *d)
|
||||||
|
{
|
||||||
|
gnutls_free (d->data);
|
||||||
|
gnutls_free (d);
|
||||||
|
}
|
||||||
|
|
||||||
|
G_DEFINE_AUTOPTR_CLEANUP_FUNC(gnutls_datum_t, _gnutls_datum_deinit)
|
||||||
|
|
||||||
|
static gchar *
|
||||||
|
fu_keyring_pkcs7_datum_to_dn_str (const gnutls_datum_t *raw)
|
||||||
|
{
|
||||||
|
g_auto(gnutls_x509_dn_t) dn = NULL;
|
||||||
|
g_autoptr(gnutls_datum_t) str = NULL;
|
||||||
|
int rc;
|
||||||
|
rc = gnutls_x509_dn_init (&dn);
|
||||||
|
if (rc < 0)
|
||||||
|
return NULL;
|
||||||
|
rc = gnutls_x509_dn_import (dn, raw);
|
||||||
|
if (rc < 0)
|
||||||
|
return NULL;
|
||||||
|
str = (gnutls_datum_t *) gnutls_malloc (sizeof (gnutls_datum_t));
|
||||||
|
rc = gnutls_x509_dn_get_str2 (dn, str, 0);
|
||||||
|
if (rc < 0)
|
||||||
|
return NULL;
|
||||||
|
return g_strndup ((const gchar *) str->data, str->size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static FuKeyringResult *
|
||||||
fu_keyring_pkcs7_verify_data (FuKeyring *keyring,
|
fu_keyring_pkcs7_verify_data (FuKeyring *keyring,
|
||||||
GBytes *blob,
|
GBytes *blob,
|
||||||
GBytes *blob_signature,
|
GBytes *blob_signature,
|
||||||
@ -128,9 +157,11 @@ fu_keyring_pkcs7_verify_data (FuKeyring *keyring,
|
|||||||
{
|
{
|
||||||
FuKeyringPkcs7 *self = FU_KEYRING_PKCS7 (keyring);
|
FuKeyringPkcs7 *self = FU_KEYRING_PKCS7 (keyring);
|
||||||
gnutls_datum_t datum;
|
gnutls_datum_t datum;
|
||||||
|
gint64 timestamp_newest = 0;
|
||||||
int count;
|
int count;
|
||||||
int rc;
|
int rc;
|
||||||
g_auto(gnutls_pkcs7_t) pkcs7 = NULL;
|
g_auto(gnutls_pkcs7_t) pkcs7 = NULL;
|
||||||
|
g_autoptr(GString) authority_newest = g_string_new (NULL);
|
||||||
|
|
||||||
/* startup */
|
/* startup */
|
||||||
rc = gnutls_pkcs7_init (&pkcs7);
|
rc = gnutls_pkcs7_init (&pkcs7);
|
||||||
@ -140,7 +171,7 @@ fu_keyring_pkcs7_verify_data (FuKeyring *keyring,
|
|||||||
FWUPD_ERROR_SIGNATURE_INVALID,
|
FWUPD_ERROR_SIGNATURE_INVALID,
|
||||||
"failed to init pkcs7: %s [%i]",
|
"failed to init pkcs7: %s [%i]",
|
||||||
gnutls_strerror (rc), rc);
|
gnutls_strerror (rc), rc);
|
||||||
return FALSE;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* import the signature */
|
/* import the signature */
|
||||||
@ -153,7 +184,7 @@ fu_keyring_pkcs7_verify_data (FuKeyring *keyring,
|
|||||||
FWUPD_ERROR_SIGNATURE_INVALID,
|
FWUPD_ERROR_SIGNATURE_INVALID,
|
||||||
"failed to import the PKCS7 signature: %s [%i]",
|
"failed to import the PKCS7 signature: %s [%i]",
|
||||||
gnutls_strerror (rc), rc);
|
gnutls_strerror (rc), rc);
|
||||||
return FALSE;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* verify the blob */
|
/* verify the blob */
|
||||||
@ -166,9 +197,13 @@ fu_keyring_pkcs7_verify_data (FuKeyring *keyring,
|
|||||||
FWUPD_ERROR,
|
FWUPD_ERROR,
|
||||||
FWUPD_ERROR_SIGNATURE_INVALID,
|
FWUPD_ERROR_SIGNATURE_INVALID,
|
||||||
"no PKCS7 signatures found");
|
"no PKCS7 signatures found");
|
||||||
return FALSE;
|
return NULL;
|
||||||
}
|
}
|
||||||
for (gint i = 0; i < count; i++) {
|
for (gint i = 0; i < count; i++) {
|
||||||
|
gnutls_pkcs7_signature_info_st info;
|
||||||
|
gint64 signing_time = 0;
|
||||||
|
|
||||||
|
/* verify the data against the detached signature */
|
||||||
rc = gnutls_pkcs7_verify (pkcs7, self->tl,
|
rc = gnutls_pkcs7_verify (pkcs7, self->tl,
|
||||||
NULL, /* vdata */
|
NULL, /* vdata */
|
||||||
0, /* vdata_size */
|
0, /* vdata_size */
|
||||||
@ -181,12 +216,34 @@ fu_keyring_pkcs7_verify_data (FuKeyring *keyring,
|
|||||||
FWUPD_ERROR_SIGNATURE_INVALID,
|
FWUPD_ERROR_SIGNATURE_INVALID,
|
||||||
"failed to verify data: %s [%i]",
|
"failed to verify data: %s [%i]",
|
||||||
gnutls_strerror (rc), rc);
|
gnutls_strerror (rc), rc);
|
||||||
return FALSE;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* save details about the key for the result */
|
||||||
|
rc = gnutls_pkcs7_get_signature_info (pkcs7, i, &info);
|
||||||
|
if (rc < 0) {
|
||||||
|
g_set_error (error,
|
||||||
|
FWUPD_ERROR,
|
||||||
|
FWUPD_ERROR_SIGNATURE_INVALID,
|
||||||
|
"failed to get signature info: %s [%i]",
|
||||||
|
gnutls_strerror (rc), rc);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
signing_time = info.signing_time > 0 ? (gint64) info.signing_time : 1;
|
||||||
|
if (signing_time > timestamp_newest) {
|
||||||
|
g_autofree gchar *dn = NULL;
|
||||||
|
timestamp_newest = signing_time;
|
||||||
|
dn = fu_keyring_pkcs7_datum_to_dn_str (&info.issuer_dn);
|
||||||
|
g_string_assign (authority_newest, dn);
|
||||||
|
}
|
||||||
|
gnutls_pkcs7_signature_info_deinit (&info);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* success */
|
/* success */
|
||||||
return TRUE;
|
return FU_KEYRING_RESULT (g_object_new (FU_TYPE_KEYRING_RESULT,
|
||||||
|
"timestamp", timestamp_newest,
|
||||||
|
"authority", authority_newest->str,
|
||||||
|
NULL));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
125
src/fu-keyring-result.c
Normal file
125
src/fu-keyring-result.c
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017 Richard Hughes <richard@hughsie.com>
|
||||||
|
*
|
||||||
|
* Licensed under the GNU General Public License Version 2
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program 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 General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include "fwupd-error.h"
|
||||||
|
|
||||||
|
#include "fu-keyring-result.h"
|
||||||
|
|
||||||
|
struct _FuKeyringResult
|
||||||
|
{
|
||||||
|
GObject parent_instance;
|
||||||
|
gint64 timestamp;
|
||||||
|
gchar *authority;
|
||||||
|
};
|
||||||
|
|
||||||
|
G_DEFINE_TYPE (FuKeyringResult, fu_keyring_result, G_TYPE_OBJECT)
|
||||||
|
|
||||||
|
enum {
|
||||||
|
PROP_0,
|
||||||
|
PROP_TIMESTAMP,
|
||||||
|
PROP_AUTHORITY,
|
||||||
|
PROP_LAST
|
||||||
|
};
|
||||||
|
|
||||||
|
gint64
|
||||||
|
fu_keyring_result_get_timestamp (FuKeyringResult *self)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (FU_IS_KEYRING_RESULT (self), 0);
|
||||||
|
return self->timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
const gchar *
|
||||||
|
fu_keyring_result_get_authority (FuKeyringResult *self)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (FU_IS_KEYRING_RESULT (self), NULL);
|
||||||
|
return self->authority;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fu_keyring_result_finalize (GObject *object)
|
||||||
|
{
|
||||||
|
FuKeyringResult *self = FU_KEYRING_RESULT (object);
|
||||||
|
g_free (self->authority);
|
||||||
|
G_OBJECT_CLASS (fu_keyring_result_parent_class)->finalize (object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fu_keyring_result_get_property (GObject *object, guint prop_id,
|
||||||
|
GValue *value, GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
FuKeyringResult *self = FU_KEYRING_RESULT (object);
|
||||||
|
switch (prop_id) {
|
||||||
|
case PROP_TIMESTAMP:
|
||||||
|
g_value_set_int64 (value, self->timestamp);
|
||||||
|
break;
|
||||||
|
case PROP_AUTHORITY:
|
||||||
|
g_value_set_string (value, self->authority);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fu_keyring_result_set_property (GObject *object, guint prop_id,
|
||||||
|
const GValue *value, GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
FuKeyringResult *self = FU_KEYRING_RESULT (object);
|
||||||
|
switch (prop_id) {
|
||||||
|
case PROP_TIMESTAMP:
|
||||||
|
self->timestamp = g_value_get_int64 (value);
|
||||||
|
break;
|
||||||
|
case PROP_AUTHORITY:
|
||||||
|
self->authority = g_value_dup_string (value);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fu_keyring_result_class_init (FuKeyringResultClass *klass)
|
||||||
|
{
|
||||||
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||||
|
GParamSpec *pspec;
|
||||||
|
|
||||||
|
object_class->get_property = fu_keyring_result_get_property;
|
||||||
|
object_class->set_property = fu_keyring_result_set_property;
|
||||||
|
object_class->finalize = fu_keyring_result_finalize;
|
||||||
|
|
||||||
|
pspec = g_param_spec_int64 ("timestamp", NULL, NULL,
|
||||||
|
0, G_MAXINT64, 0,
|
||||||
|
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
|
||||||
|
g_object_class_install_property (object_class, PROP_TIMESTAMP, pspec);
|
||||||
|
|
||||||
|
pspec = g_param_spec_string ("authority", NULL, NULL, NULL,
|
||||||
|
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
|
||||||
|
g_object_class_install_property (object_class, PROP_AUTHORITY, pspec);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fu_keyring_result_init (FuKeyringResult *self)
|
||||||
|
{
|
||||||
|
}
|
38
src/fu-keyring-result.h
Normal file
38
src/fu-keyring-result.h
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017 Richard Hughes <richard@hughsie.com>
|
||||||
|
*
|
||||||
|
* Licensed under the GNU General Public License Version 2
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program 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 General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __FU_KEYRING_RESULT_H
|
||||||
|
#define __FU_KEYRING_RESULT_H
|
||||||
|
|
||||||
|
#include <glib-object.h>
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
#define FU_TYPE_KEYRING_RESULT (fu_keyring_result_get_type ())
|
||||||
|
|
||||||
|
G_DECLARE_FINAL_TYPE (FuKeyringResult, fu_keyring_result, FU, KEYRING_RESULT, GObject)
|
||||||
|
|
||||||
|
gint64 fu_keyring_result_get_timestamp (FuKeyringResult *self);
|
||||||
|
const gchar *fu_keyring_result_get_authority (FuKeyringResult *self);
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
|
#endif /* __FU_KEYRING_RESULT_H */
|
@ -41,7 +41,7 @@ fu_keyring_setup (FuKeyring *keyring, const gchar *public_key_dir, GError **erro
|
|||||||
return klass->setup (keyring, public_key_dir, error);
|
return klass->setup (keyring, public_key_dir, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
FuKeyringResult *
|
||||||
fu_keyring_verify_data (FuKeyring *keyring,
|
fu_keyring_verify_data (FuKeyring *keyring,
|
||||||
GBytes *blob,
|
GBytes *blob,
|
||||||
GBytes *blob_signature,
|
GBytes *blob_signature,
|
||||||
|
@ -25,6 +25,8 @@
|
|||||||
#include <glib-object.h>
|
#include <glib-object.h>
|
||||||
#include <gio/gio.h>
|
#include <gio/gio.h>
|
||||||
|
|
||||||
|
#include "fu-keyring-result.h"
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
#define FU_TYPE_KEYRING (fu_keyring_get_type ())
|
#define FU_TYPE_KEYRING (fu_keyring_get_type ())
|
||||||
@ -36,7 +38,7 @@ struct _FuKeyringClass
|
|||||||
gboolean (*setup) (FuKeyring *keyring,
|
gboolean (*setup) (FuKeyring *keyring,
|
||||||
const gchar *public_key_dir,
|
const gchar *public_key_dir,
|
||||||
GError **error);
|
GError **error);
|
||||||
gboolean (*verify_data) (FuKeyring *keyring,
|
FuKeyringResult *(*verify_data) (FuKeyring *keyring,
|
||||||
GBytes *payload,
|
GBytes *payload,
|
||||||
GBytes *payload_signature,
|
GBytes *payload_signature,
|
||||||
GError **error);
|
GError **error);
|
||||||
@ -45,7 +47,7 @@ struct _FuKeyringClass
|
|||||||
gboolean fu_keyring_setup (FuKeyring *keyring,
|
gboolean fu_keyring_setup (FuKeyring *keyring,
|
||||||
const gchar *public_key_dir,
|
const gchar *public_key_dir,
|
||||||
GError **error);
|
GError **error);
|
||||||
gboolean fu_keyring_verify_data (FuKeyring *keyring,
|
FuKeyringResult *fu_keyring_verify_data (FuKeyring *keyring,
|
||||||
GBytes *blob,
|
GBytes *blob,
|
||||||
GBytes *blob_signature,
|
GBytes *blob_signature,
|
||||||
GError **error);
|
GError **error);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
|
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
|
||||||
*
|
*
|
||||||
* Copyright (C) 2015 Richard Hughes <richard@hughsie.com>
|
* Copyright (C) 2015-2017 Richard Hughes <richard@hughsie.com>
|
||||||
*
|
*
|
||||||
* Licensed under the GNU General Public License Version 2
|
* Licensed under the GNU General Public License Version 2
|
||||||
*
|
*
|
||||||
@ -385,6 +385,8 @@ fu_keyring_gpg_func (void)
|
|||||||
g_autofree gchar *fw_pass = NULL;
|
g_autofree gchar *fw_pass = NULL;
|
||||||
g_autofree gchar *pki_dir = NULL;
|
g_autofree gchar *pki_dir = NULL;
|
||||||
g_autoptr(FuKeyring) keyring = NULL;
|
g_autoptr(FuKeyring) keyring = NULL;
|
||||||
|
g_autoptr(FuKeyringResult) result_fail = NULL;
|
||||||
|
g_autoptr(FuKeyringResult) result_pass = NULL;
|
||||||
g_autoptr(GBytes) blob_fail = NULL;
|
g_autoptr(GBytes) blob_fail = NULL;
|
||||||
g_autoptr(GBytes) blob_pass = NULL;
|
g_autoptr(GBytes) blob_pass = NULL;
|
||||||
g_autoptr(GBytes) blob_sig = NULL;
|
g_autoptr(GBytes) blob_sig = NULL;
|
||||||
@ -415,9 +417,12 @@ fu_keyring_gpg_func (void)
|
|||||||
g_assert_no_error (error);
|
g_assert_no_error (error);
|
||||||
g_assert_nonnull (blob_pass);
|
g_assert_nonnull (blob_pass);
|
||||||
blob_sig = g_bytes_new_static (sig_gpgme, strlen (sig_gpgme));
|
blob_sig = g_bytes_new_static (sig_gpgme, strlen (sig_gpgme));
|
||||||
ret = fu_keyring_verify_data (keyring, blob_pass, blob_sig, &error);
|
result_pass = fu_keyring_verify_data (keyring, blob_pass, blob_sig, &error);
|
||||||
g_assert_no_error (error);
|
g_assert_no_error (error);
|
||||||
g_assert_true (ret);
|
g_assert_nonnull (result_pass);
|
||||||
|
g_assert_cmpint (fu_keyring_result_get_timestamp (result_pass), == , 1438072952);
|
||||||
|
g_assert_cmpstr (fu_keyring_result_get_authority (result_pass), == ,
|
||||||
|
"3FC6B804410ED0840D8F2F9748A6D80E4538BAC2");
|
||||||
|
|
||||||
/* verify will fail with GnuPG */
|
/* verify will fail with GnuPG */
|
||||||
fw_fail = fu_test_get_filename (TESTDATADIR, "colorhug/colorhug-als-3.0.2.cab");
|
fw_fail = fu_test_get_filename (TESTDATADIR, "colorhug/colorhug-als-3.0.2.cab");
|
||||||
@ -425,9 +430,9 @@ fu_keyring_gpg_func (void)
|
|||||||
blob_fail = fu_common_get_contents_bytes (fw_fail, &error);
|
blob_fail = fu_common_get_contents_bytes (fw_fail, &error);
|
||||||
g_assert_no_error (error);
|
g_assert_no_error (error);
|
||||||
g_assert_nonnull (blob_fail);
|
g_assert_nonnull (blob_fail);
|
||||||
ret = fu_keyring_verify_data (keyring, blob_fail, blob_sig, &error);
|
result_fail = fu_keyring_verify_data (keyring, blob_fail, blob_sig, &error);
|
||||||
g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_SIGNATURE_INVALID);
|
g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_SIGNATURE_INVALID);
|
||||||
g_assert_false (ret);
|
g_assert_null (result_fail);
|
||||||
g_clear_error (&error);
|
g_clear_error (&error);
|
||||||
#else
|
#else
|
||||||
g_test_skip ("no GnuPG support enabled");
|
g_test_skip ("no GnuPG support enabled");
|
||||||
@ -444,6 +449,8 @@ fu_keyring_pkcs7_func (void)
|
|||||||
g_autofree gchar *pki_dir = NULL;
|
g_autofree gchar *pki_dir = NULL;
|
||||||
g_autofree gchar *sig_fn = NULL;
|
g_autofree gchar *sig_fn = NULL;
|
||||||
g_autoptr(FuKeyring) keyring = NULL;
|
g_autoptr(FuKeyring) keyring = NULL;
|
||||||
|
g_autoptr(FuKeyringResult) result_fail = NULL;
|
||||||
|
g_autoptr(FuKeyringResult) result_pass = NULL;
|
||||||
g_autoptr(GBytes) blob_fail = NULL;
|
g_autoptr(GBytes) blob_fail = NULL;
|
||||||
g_autoptr(GBytes) blob_pass = NULL;
|
g_autoptr(GBytes) blob_pass = NULL;
|
||||||
g_autoptr(GBytes) blob_sig = NULL;
|
g_autoptr(GBytes) blob_sig = NULL;
|
||||||
@ -468,9 +475,11 @@ fu_keyring_pkcs7_func (void)
|
|||||||
blob_sig = fu_common_get_contents_bytes (sig_fn, &error);
|
blob_sig = fu_common_get_contents_bytes (sig_fn, &error);
|
||||||
g_assert_no_error (error);
|
g_assert_no_error (error);
|
||||||
g_assert_nonnull (blob_sig);
|
g_assert_nonnull (blob_sig);
|
||||||
ret = fu_keyring_verify_data (keyring, blob_pass, blob_sig, &error);
|
result_pass = fu_keyring_verify_data (keyring, blob_pass, blob_sig, &error);
|
||||||
g_assert_no_error (error);
|
g_assert_no_error (error);
|
||||||
g_assert_true (ret);
|
g_assert_nonnull (result_pass);
|
||||||
|
g_assert_cmpint (fu_keyring_result_get_timestamp (result_pass), >= , 1502871248);
|
||||||
|
g_assert_cmpstr (fu_keyring_result_get_authority (result_pass), == , "O=Hughski Limited");
|
||||||
|
|
||||||
/* verify will fail with GnuTLS */
|
/* verify will fail with GnuTLS */
|
||||||
fw_fail = fu_test_get_filename (TESTDATADIR, "colorhug/colorhug-als-3.0.2.cab");
|
fw_fail = fu_test_get_filename (TESTDATADIR, "colorhug/colorhug-als-3.0.2.cab");
|
||||||
@ -478,9 +487,9 @@ fu_keyring_pkcs7_func (void)
|
|||||||
blob_fail = fu_common_get_contents_bytes (fw_fail, &error);
|
blob_fail = fu_common_get_contents_bytes (fw_fail, &error);
|
||||||
g_assert_no_error (error);
|
g_assert_no_error (error);
|
||||||
g_assert_nonnull (blob_fail);
|
g_assert_nonnull (blob_fail);
|
||||||
ret = fu_keyring_verify_data (keyring, blob_fail, blob_sig, &error);
|
result_fail = fu_keyring_verify_data (keyring, blob_fail, blob_sig, &error);
|
||||||
g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_SIGNATURE_INVALID);
|
g_assert_error (error, FWUPD_ERROR, FWUPD_ERROR_SIGNATURE_INVALID);
|
||||||
g_assert_false (ret);
|
g_assert_null (result_fail);
|
||||||
g_clear_error (&error);
|
g_clear_error (&error);
|
||||||
#else
|
#else
|
||||||
g_test_skip ("no GnuTLS support enabled");
|
g_test_skip ("no GnuTLS support enabled");
|
||||||
|
@ -97,6 +97,7 @@ executable(
|
|||||||
'fu-common.c',
|
'fu-common.c',
|
||||||
'fu-config.c',
|
'fu-config.c',
|
||||||
'fu-keyring.c',
|
'fu-keyring.c',
|
||||||
|
'fu-keyring-result.c',
|
||||||
'fu-engine.c',
|
'fu-engine.c',
|
||||||
'fu-main.c',
|
'fu-main.c',
|
||||||
'fu-hwids.c',
|
'fu-hwids.c',
|
||||||
@ -151,6 +152,7 @@ if get_option('enable-tests')
|
|||||||
'fu-device.c',
|
'fu-device.c',
|
||||||
'fu-pending.c',
|
'fu-pending.c',
|
||||||
'fu-keyring.c',
|
'fu-keyring.c',
|
||||||
|
'fu-keyring-result.c',
|
||||||
'fu-plugin.c',
|
'fu-plugin.c',
|
||||||
'fu-test.c',
|
'fu-test.c',
|
||||||
],
|
],
|
||||||
|
Loading…
Reference in New Issue
Block a user