From 404aa33ce1dae6cfc888d6bf92e77dc7845ccc23 Mon Sep 17 00:00:00 2001 From: "Owen W. Taylor" Date: Tue, 17 Dec 2024 14:57:47 -0500 Subject: [PATCH] common: Check signatures when installing OCI images Co-authored-by: Sebastian Wick --- app/flatpak-builtins-build-import-bundle.c | 2 +- common/flatpak-dir-private.h | 7 + common/flatpak-dir.c | 47 ++++- common/flatpak-image-source-private.h | 1 + common/flatpak-image-source.c | 2 + common/flatpak-oci-registry-private.h | 13 +- common/flatpak-oci-registry.c | 137 ++++++++++++- common/flatpak-oci-signatures-private.h | 32 ++- common/flatpak-oci-signatures.c | 226 ++++++++++++++++++++- system-helper/flatpak-system-helper.c | 17 +- 10 files changed, 453 insertions(+), 31 deletions(-) diff --git a/app/flatpak-builtins-build-import-bundle.c b/app/flatpak-builtins-build-import-bundle.c index d623386f..6b06073f 100644 --- a/app/flatpak-builtins-build-import-bundle.c +++ b/app/flatpak-builtins-build-import-bundle.c @@ -68,7 +68,7 @@ import_oci (OstreeRepo *repo, GFile *file, ref = flatpak_image_source_get_ref (image_source); - commit_checksum = flatpak_pull_from_oci (repo, image_source, NULL, + commit_checksum = flatpak_pull_from_oci (repo, image_source, NULL, NULL, ref, FLATPAK_PULL_FLAGS_NONE, NULL, NULL, cancellable, error); if (commit_checksum == NULL) diff --git a/common/flatpak-dir-private.h b/common/flatpak-dir-private.h index 5bfc03f7..9a9f8a12 100644 --- a/common/flatpak-dir-private.h +++ b/common/flatpak-dir-private.h @@ -172,6 +172,13 @@ void flatpak_remote_state_add_sideload_dir (FlatpakRemoteState *self, GFile *path); void flatpak_remote_state_add_sideload_image_collection (FlatpakRemoteState *self, FlatpakImageCollection *image_collection); +FlatpakImageSource * flatpak_remote_state_fetch_image_source (FlatpakRemoteState *self, + FlatpakDir *dir, + const char *ref, + const char *opt_rev, + const char *token, + GCancellable *cancellable, + GError **error); G_DEFINE_AUTOPTR_CLEANUP_FUNC (FlatpakDir, g_object_unref) diff --git a/common/flatpak-dir.c b/common/flatpak-dir.c index 40c20774..f1e29de5 100644 --- a/common/flatpak-dir.c +++ b/common/flatpak-dir.c @@ -185,6 +185,9 @@ static gboolean flatpak_dir_lookup_remote_filter (FlatpakDir *self, GRegex **deny_regex, GError **error); +static char *flatpak_dir_get_remote_signature_lookaside (FlatpakDir *self, + const char *remote_name); + static void ensure_http_session (FlatpakDir *self); static void flatpak_dir_log (FlatpakDir *self, @@ -1200,15 +1203,17 @@ lookup_oci_registry_uri_from_summary (GVariant *summary, } static FlatpakImageSource * -flatpak_remote_state_new_image_source (FlatpakRemoteState *self, - const char *oci_repository, - const char *digest, - const char *token, - GCancellable *cancellable, - GError **error) +flatpak_remote_state_new_image_source (FlatpakRemoteState *self, + FlatpakDir *dir, + const char *oci_repository, + const char *digest, + const char *token, + GCancellable *cancellable, + GError **error) { g_autofree char *registry_uri = NULL; g_autoptr(FlatpakImageSource) image_source = NULL; + g_autofree char *signature_lookaside = NULL; if (!flatpak_remote_state_ensure_summary (self, error)) return NULL; @@ -1217,14 +1222,21 @@ flatpak_remote_state_new_image_source (FlatpakRemoteState *self, if (registry_uri == NULL) return NULL; - image_source = flatpak_image_source_new_remote (registry_uri, oci_repository, digest, token, NULL, error); + signature_lookaside = flatpak_dir_get_remote_signature_lookaside (dir, self->remote_name); + + image_source = flatpak_image_source_new_remote (registry_uri, + oci_repository, + digest, + token, + signature_lookaside, + NULL, error); if (image_source == NULL) return NULL; return g_steal_pointer (&image_source); } -static FlatpakImageSource * +FlatpakImageSource * flatpak_remote_state_fetch_image_source (FlatpakRemoteState *self, FlatpakDir *dir, const char *ref, @@ -1262,7 +1274,7 @@ flatpak_remote_state_fetch_image_source (FlatpakRemoteState *self, oci_digest = g_strconcat ("sha256:", opt_rev ? opt_rev : latest_rev, NULL); - image_source = flatpak_remote_state_new_image_source (self, oci_repository, oci_digest, token, cancellable, error); + image_source = flatpak_remote_state_new_image_source (self, dir, oci_repository, oci_digest, token, cancellable, error); if (image_source == NULL) return NULL; @@ -6867,7 +6879,7 @@ flatpak_dir_pull_oci (FlatpakDir *self, g_info ("Pulling OCI image %s", oci_digest); - checksum = flatpak_pull_from_oci (repo, image_source, + checksum = flatpak_pull_from_oci (repo, image_source, NULL, state->remote_name, ref, flatpak_flags, oci_pull_progress_cb, progress, cancellable, error); if (checksum == NULL) @@ -15297,6 +15309,21 @@ flatpak_dir_get_remote_disabled (FlatpakDir *self, return FALSE; } +static char * +flatpak_dir_get_remote_signature_lookaside (FlatpakDir *self, + const char *remote_name) +{ + GKeyFile *config = flatpak_dir_get_repo_config (self); + g_autofree char *group = get_group (remote_name); + g_autofree char *signature_lookaside = NULL; + + signature_lookaside = g_key_file_get_string (config, group, "xa.signature-lookaside", NULL); + if (signature_lookaside == NULL || *signature_lookaside == '\0') + return NULL; + + return g_steal_pointer (&signature_lookaside); +} + static char * flatpak_dir_get_remote_install_authenticator_name (FlatpakDir *self, const char *remote_name) diff --git a/common/flatpak-image-source-private.h b/common/flatpak-image-source-private.h index 5f9604d8..1259c134 100644 --- a/common/flatpak-image-source-private.h +++ b/common/flatpak-image-source-private.h @@ -46,6 +46,7 @@ FlatpakImageSource *flatpak_image_source_new_remote (const char *uri, const char *oci_repository, const char *digest, const char *token, + const char *signature_lookaside, GCancellable *cancellable, GError **error); FlatpakImageSource *flatpak_image_source_new_for_location (const char *location, diff --git a/common/flatpak-image-source.c b/common/flatpak-image-source.c index 66a19c81..eab92a1b 100644 --- a/common/flatpak-image-source.c +++ b/common/flatpak-image-source.c @@ -184,6 +184,7 @@ flatpak_image_source_new_remote (const char *uri, const char *oci_repository, const char *digest, const char *token, + const char *signature_lookaside, GCancellable *cancellable, GError **error) { @@ -194,6 +195,7 @@ flatpak_image_source_new_remote (const char *uri, return NULL; flatpak_oci_registry_set_token (registry, token); + flatpak_oci_registry_set_signature_lookaside (registry, signature_lookaside); return flatpak_image_source_new (registry, oci_repository, digest, cancellable, error); } diff --git a/common/flatpak-oci-registry-private.h b/common/flatpak-oci-registry-private.h index e50daaf1..ca56eab3 100644 --- a/common/flatpak-oci-registry-private.h +++ b/common/flatpak-oci-registry-private.h @@ -61,6 +61,8 @@ FlatpakOciRegistry * flatpak_oci_registry_new_for_archive (GFile *archi GError **error); void flatpak_oci_registry_set_token (FlatpakOciRegistry *self, const char *token); +void flatpak_oci_registry_set_signature_lookaside (FlatpakOciRegistry *self, + const char *signature_lookaside); gboolean flatpak_oci_registry_is_local (FlatpakOciRegistry *self); const char * flatpak_oci_registry_get_uri (FlatpakOciRegistry *self); FlatpakOciIndex * flatpak_oci_registry_load_index (FlatpakOciRegistry *self, @@ -164,16 +166,6 @@ gboolean flatpak_archive_read_open_fd_with_checksum (struct archive *a, GChecksum *checksum, GError **error); -GBytes *flatpak_oci_sign_data (GBytes *data, - const gchar **okey_ids, - const char *homedir, - GError **error); - -FlatpakOciSignature *flatpak_oci_verify_signature (OstreeRepo *repo, - const char *remote_name, - GBytes *signature, - GError **error); - gboolean flatpak_oci_index_ensure_cached (FlatpakHttpSession *http_session, const char *uri, GFile *index, @@ -202,6 +194,7 @@ typedef void (*FlatpakOciPullProgress) (guint64 total_size, char * flatpak_pull_from_oci (OstreeRepo *repo, FlatpakImageSource *image_source, + FlatpakImageSource *opt_dst_image_source, const char *remote, const char *ref, FlatpakPullFlags flags, diff --git a/common/flatpak-oci-registry.c b/common/flatpak-oci-registry.c index 1f9d2063..67b11b7b 100644 --- a/common/flatpak-oci-registry.c +++ b/common/flatpak-oci-registry.c @@ -30,6 +30,7 @@ #include #include "flatpak-image-source-private.h" #include "flatpak-oci-registry-private.h" +#include "flatpak-oci-signatures-private.h" #include "flatpak-repo-utils-private.h" #include "flatpak-utils-base-private.h" #include "flatpak-utils-private.h" @@ -73,6 +74,7 @@ struct FlatpakOciRegistry GFile *archive; int tmp_dfd; char *token; + char *signature_lookaside; /* Local repos */ int dfd; @@ -134,11 +136,12 @@ flatpak_oci_registry_finalize (GObject *object) g_clear_pointer (&self->http_session, flatpak_http_session_free); g_clear_pointer (&self->base_uri, g_uri_unref); - g_free (self->uri); - g_free (self->token); + g_clear_pointer (&self->uri, g_free); + g_clear_pointer (&self->token, g_free); g_clear_object (&self->archive); g_clear_pointer (&self->tmp_dir, glnx_tmpdir_free); g_clear_pointer (&self->certificates, flatpak_certificates_free); + g_clear_pointer (&self->signature_lookaside, g_free); G_OBJECT_CLASS (flatpak_oci_registry_parent_class)->finalize (object); } @@ -288,6 +291,21 @@ flatpak_oci_registry_set_token (FlatpakOciRegistry *self, 0, NULL, NULL); } +void +flatpak_oci_registry_set_signature_lookaside (FlatpakOciRegistry *self, + const char *signature_lookaside) +{ + g_set_str (&self->signature_lookaside, signature_lookaside); + + if (self->signature_lookaside != NULL) + { + size_t last = strlen (self->signature_lookaside) - 1; + + if (self->signature_lookaside[last] == '/') + self->signature_lookaside[last] = '\0'; + } +} + FlatpakOciRegistry * flatpak_oci_registry_new (const char *uri, gboolean for_write, @@ -2321,6 +2339,91 @@ flatpak_oci_registry_find_delta_manifest (FlatpakOciRegistry *registry, return NULL; } +static FlatpakOciSignatures * +remote_load_signatures (FlatpakOciRegistry *self, + const char *oci_repository, + const char *digest, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(FlatpakOciSignatures) signatures = flatpak_oci_signatures_new (); + g_autofree char *digest_algorithm = NULL; + g_autofree char *digest_value = NULL; + guint i; + const char *colon; + + if (self->signature_lookaside == NULL) + return g_steal_pointer (&signatures); + + /* + * Look for signatures via the containers/image separate storage protocol: + * + * https://github.com/containers/image/blob/main/docs/signature-protocols.md + */ + + colon = strchr (digest, ':'); + if (colon == NULL) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "can't parse digest %s", digest); + return NULL; + } + + digest_algorithm = g_strndup (digest, colon - digest); + digest_value = g_strdup (colon + 1); + + for (i = 1; i < G_MAXUINT; i++) + { + g_autoptr(GBytes) bytes = NULL; + g_autoptr(GError) local_error = NULL; + g_autofree char *uri_s = NULL; + + uri_s = g_strdup_printf ("%s/%s@%s=%s/signature-%u", self->signature_lookaside, + oci_repository, digest_algorithm, digest_value, i); + + bytes = flatpak_load_uri (self->http_session, + uri_s, FLATPAK_HTTP_FLAGS_ACCEPT_OCI, + NULL, + NULL, NULL, NULL, + cancellable, &local_error); + if (bytes == NULL) + { + if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) + break; + else + { + g_propagate_error (error, g_steal_pointer (&local_error)); + return NULL; + } + } + + g_info ("Found OCI signature at %s", uri_s); + flatpak_oci_signatures_add_signature (signatures, g_steal_pointer (&bytes)); + } + + return g_steal_pointer (&signatures); +} + +static FlatpakOciSignatures * +flatpak_oci_registry_load_signatures (FlatpakOciRegistry *self, + const char *oci_repository, + const char *digest, + GCancellable *cancellable, + GError **error) +{ + if (self->dfd != -1) + { + g_autoptr(FlatpakOciSignatures) signatures = flatpak_oci_signatures_new (); + + if (!flatpak_oci_signatures_load_from_dfd (signatures, self->dfd, cancellable, error)) + return NULL; + + return g_steal_pointer (&signatures); + } + else + return remote_load_signatures (self, oci_repository, digest, cancellable, error); +} + static const char * get_image_metadata (FlatpakOciIndexImage *img, const char *key) { @@ -3079,6 +3182,7 @@ flatpak_mirror_image_from_oci (FlatpakOciRegistry *dst_registry, OstreeRepoCommitState old_state = 0; g_autofree char *old_diffid = NULL; g_autoptr(FlatpakOciIndex) index = NULL; + g_autoptr(FlatpakOciSignatures) signatures = NULL; int n_layers; int i; @@ -3179,12 +3283,21 @@ flatpak_mirror_image_from_oci (FlatpakOciRegistry *dst_registry, if (!flatpak_oci_registry_save_index (dst_registry, index, cancellable, error)) return FALSE; + signatures = flatpak_oci_registry_load_signatures (registry, oci_repository, digest, + cancellable, error); + if (!signatures) + return FALSE; + + if (!flatpak_oci_signatures_save_to_dfd (signatures, dst_registry->dfd, cancellable, error)) + return FALSE; + return TRUE; } char * flatpak_pull_from_oci (OstreeRepo *repo, FlatpakImageSource *image_source, + FlatpakImageSource *opt_dst_image_source, const char *remote, const char *ref, FlatpakPullFlags flags, @@ -3216,13 +3329,31 @@ flatpak_pull_from_oci (OstreeRepo *repo, FlatpakOciPullProgressData progress_data = { progress_cb, progress_user_data }; g_autoptr(GVariantBuilder) metadata_builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}")); g_autoptr(GVariant) metadata = NULL; + g_autoptr(FlatpakOciSignatures) signatures = NULL; + FlatpakOciRegistry *dst_registry = opt_dst_image_source ? + flatpak_image_source_get_registry (opt_dst_image_source) : registry; + const char *dest_oci_repository = opt_dst_image_source ? + flatpak_image_source_get_oci_repository (opt_dst_image_source) : oci_repository; int n_layers; int i; g_assert (g_str_has_prefix (digest, "sha256:")); - manifest_ref = flatpak_image_source_get_ref (image_source); + signatures = flatpak_oci_registry_load_signatures (dst_registry, + dest_oci_repository, + digest, + cancellable, error); + if (!signatures) + return FALSE; + if (!flatpak_oci_signatures_verify (signatures, repo, remote, + dst_registry->uri, + dest_oci_repository, + digest, + error)) + return FALSE; + + manifest_ref = flatpak_image_source_get_ref (image_source); if (manifest_ref == NULL) { flatpak_fail_error (error, FLATPAK_ERROR_INVALID_DATA, _("No ref specified for OCI image %s"), digest); diff --git a/common/flatpak-oci-signatures-private.h b/common/flatpak-oci-signatures-private.h index f56c7d1d..26d5e2d7 100644 --- a/common/flatpak-oci-signatures-private.h +++ b/common/flatpak-oci-signatures-private.h @@ -9,9 +9,33 @@ typedef struct _FlatpakOciSignatures FlatpakOciSignatures; -FlatpakOciSignature *flatpak_oci_verify_signature (OstreeRepo *repo, - const char *remote_name, - GBytes *signature, - GError **error); +gboolean flatpak_remote_has_gpg_key (OstreeRepo *repo, + const char *remote_name); + +FlatpakOciSignatures *flatpak_oci_signatures_new (void); + +void flatpak_oci_signatures_free (FlatpakOciSignatures *self); + +void flatpak_oci_signatures_add_signature (FlatpakOciSignatures *self, + GBytes *signature); + +gboolean flatpak_oci_signatures_load_from_dfd (FlatpakOciSignatures *self, + int dfd, + GCancellable *cancellable, + GError **error); + +gboolean flatpak_oci_signatures_save_to_dfd (FlatpakOciSignatures *self, + int dfd, + GCancellable *cancellable, + GError **error); +gboolean flatpak_oci_signatures_verify (FlatpakOciSignatures *self, + OstreeRepo *repo, + const char *remote_name, + const char *registry_url, + const char *repository_name, + const char *digest, + GError **error); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(FlatpakOciSignatures, flatpak_oci_signatures_free) #endif /* __FLATPAK_OCI_SIGNATURES_H__ */ diff --git a/common/flatpak-oci-signatures.c b/common/flatpak-oci-signatures.c index aed1e029..8dfa842e 100644 --- a/common/flatpak-oci-signatures.c +++ b/common/flatpak-oci-signatures.c @@ -28,13 +28,26 @@ #include #include "flatpak-oci-signatures-private.h" +#include "flatpak-uri-private.h" #include "flatpak-utils-private.h" - G_DEFINE_AUTO_CLEANUP_FREE_FUNC (gpgme_data_t, gpgme_data_release, NULL) G_DEFINE_AUTO_CLEANUP_FREE_FUNC (gpgme_ctx_t, gpgme_release, NULL) G_DEFINE_AUTO_CLEANUP_FREE_FUNC (gpgme_key_t, gpgme_key_unref, NULL) +gboolean +flatpak_remote_has_gpg_key (OstreeRepo *repo, + const char *remote_name) +{ + g_autoptr(GFile) keyring_file = NULL; + g_autofree char *keyring_name = NULL; + + keyring_name = g_strdup_printf ("%s.trustedkeys.gpg", remote_name); + keyring_file = g_file_get_child (ostree_repo_get_path (repo), keyring_name); + + return g_file_query_exists (keyring_file, NULL); +} + static void flatpak_gpgme_error_to_gio_error (gpgme_error_t gpg_error, GError **error) @@ -158,7 +171,11 @@ flatpak_gpgme_ctx_tmp_home_dir (gpgme_ctx_t gpgme_ctx, return TRUE; } -FlatpakOciSignature * +/* WARNING: This verifies that the data is signed with the correct key, but + * does not verify the payload matches what is being installed. The caller + * must do that. + */ +static FlatpakOciSignature * flatpak_oci_verify_signature (OstreeRepo *repo, const char *remote_name, GBytes *signed_data, @@ -241,3 +258,208 @@ flatpak_oci_verify_signature (OstreeRepo *repo, return (FlatpakOciSignature *) g_steal_pointer (&json); } +struct _FlatpakOciSignatures +{ + GPtrArray *signatures; +}; + +FlatpakOciSignatures * +flatpak_oci_signatures_new (void) +{ + FlatpakOciSignatures *self = g_new0 (FlatpakOciSignatures, 1); + + self->signatures = g_ptr_array_new_with_free_func ((GDestroyNotify)g_bytes_unref); + + return self; +} + +void +flatpak_oci_signatures_free (FlatpakOciSignatures *self) +{ + g_clear_pointer (&self->signatures, g_ptr_array_unref); + g_free (self); +} + +void +flatpak_oci_signatures_add_signature (FlatpakOciSignatures *self, + GBytes *signature) +{ + g_ptr_array_add (self->signatures, g_bytes_ref (signature)); +} + +gboolean +flatpak_oci_signatures_load_from_dfd (FlatpakOciSignatures *self, + int dfd, + GCancellable *cancellable, + GError **error) +{ + for (guint i = 1; i < G_MAXUINT; i++) + { + g_autofree char *filename = g_strdup_printf ("signature-%u", i); + g_autoptr(GError) local_error = NULL; + GBytes *signature; + + signature = flatpak_load_file_at (dfd, filename, cancellable, &local_error); + if (local_error) + { + if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) + break; + + g_propagate_error (error, g_steal_pointer (&local_error)); + return FALSE; + } + + flatpak_oci_signatures_add_signature (self, g_steal_pointer (&signature)); + } + + return TRUE; +} + +gboolean +flatpak_oci_signatures_save_to_dfd (FlatpakOciSignatures *self, + int dfd, + GCancellable *cancellable, + GError **error) +{ + for (guint i = 0; i < self->signatures->len; i++) + { + g_autofree char *filename = g_strdup_printf ("signature-%u", i + 1); + GBytes *signature = g_ptr_array_index (self->signatures, i); + gconstpointer data; + gsize size; + + data = g_bytes_get_data (signature, &size); + + if (!glnx_file_replace_contents_at (dfd, filename, data, size, + 0, cancellable, error)) + return FALSE; + } + + return TRUE; +} + +/* + * Strip the tag and or digest off of a docker-reference. Regular expressions + * based off of: + * + * https://github.com/containers/image/tree/main/docker/reference + * + * For simplicity we don't do normalization - if the signature claims that it + * matches 'ubuntu', we don't match turn that into docker.io/library/ubuntu + * before matching against the domain and repository. + */ + +#define TAG "[0-9A-Za-z_][0-9A-Za-z_-]{0,127}" +#define DIGEST "[A-Za-z][A-Za-z0-9]*(?:[-_+.][A-Za-z][A-Za-z0-9]*)*[:][[:xdigit:]]{32,}" +#define STRIP_TAG_AND_DIGEST_RE "^(.*?)(?::" TAG ")?" "(?:@" DIGEST ")?$" + +static char * +reference_strip_tag_and_digest (const char *str) +{ + static gsize regex = 0; + g_autoptr(GMatchInfo) match_info = NULL; + gboolean matched; + + if (g_once_init_enter (®ex)) + { + g_autoptr(GRegex) compiled = g_regex_new (STRIP_TAG_AND_DIGEST_RE, + G_REGEX_DEFAULT, + G_REGEX_MATCH_DEFAULT, + NULL); + g_assert (compiled); + g_once_init_leave (®ex, (gsize) g_steal_pointer (&compiled)); + } + + matched = g_regex_match ((GRegex *) regex, str, + G_REGEX_MATCH_DEFAULT, &match_info); + if (!matched) + return NULL; + + return g_match_info_fetch (match_info, 1); +} + +gboolean +flatpak_oci_signatures_verify (FlatpakOciSignatures *self, + OstreeRepo *repo, + const char *remote_name, + const char *registry_url, + const char *repository_name, + const char *digest, + GError **error) +{ + g_autoptr(GUri) uri = NULL; + int port; + g_autofree char *port_prefix = NULL; + g_autofree char *expected_identity = NULL; + + if (!flatpak_remote_has_gpg_key (repo, remote_name)) + { + g_info ("%s: no GPG key, skipping verification", remote_name); + return TRUE; + } + + uri = g_uri_parse (registry_url, FLATPAK_HTTP_URI_FLAGS | G_URI_FLAGS_PARSE_RELAXED, error); + if (uri == NULL) + return FALSE; + + port = g_uri_get_port (uri); + if (port != -1 && port != 80 && port != 443) + port_prefix = g_strdup_printf (":%d", g_uri_get_port (uri)); + + expected_identity = g_strdup_printf ("%s%s/%s", + g_uri_get_host (uri), + port_prefix ? port_prefix : "", + repository_name); + + for (guint i = 0; i < self->signatures->len; i++) + { + g_autoptr(FlatpakOciSignature) signature = NULL; + g_autoptr(GError) local_error = NULL; + + signature = flatpak_oci_verify_signature (repo, remote_name, + g_ptr_array_index (self->signatures, i), + &local_error); + + if (signature == NULL) + { + g_info ("Couldn't verify signature: %s", local_error->message); + continue; + } + + if (signature->critical.image.digest == NULL) + { + g_warning ("Signature is missing digest"); + continue; + } + + if (strcmp (signature->critical.image.digest, digest) != 0) + { + g_warning ("Digest in signature (%s) does not match %s", + signature->critical.image.digest, digest); + continue; + } + + if (signature->critical.identity.reference != NULL) + { + g_autofree char *stripped = NULL; + + stripped = reference_strip_tag_and_digest (signature->critical.identity.reference); + + if (g_strcmp0 (expected_identity, stripped) != 0) + { + g_info ("Identity in signature (%s) does not match %s", + signature->critical.identity.reference, + expected_identity); + continue; + } + } + + g_info ("%s: found valid signature for %s@%s", + remote_name, expected_identity, digest); + return TRUE; + } + + return flatpak_fail_error (error, FLATPAK_ERROR_UNTRUSTED, + "%s: no valid signatures for %s@%s", + remote_name, expected_identity, digest); +} diff --git a/system-helper/flatpak-system-helper.c b/system-helper/flatpak-system-helper.c index 8a5bd70f..93ac33f2 100644 --- a/system-helper/flatpak-system-helper.c +++ b/system-helper/flatpak-system-helper.c @@ -493,6 +493,7 @@ handle_deploy (FlatpakSystemHelper *object, const char *image_source_digest; const char *verified_digest; g_autofree char *upstream_url = NULL; + g_autoptr(FlatpakImageSource) system_image_source = NULL; ostree_repo_remote_get_url (flatpak_dir_get_repo (system), arg_origin, @@ -550,7 +551,21 @@ handle_deploy (FlatpakSystemHelper *object, return G_DBUS_METHOD_INVOCATION_HANDLED; } - checksum = flatpak_pull_from_oci (flatpak_dir_get_repo (system), image_source, + system_image_source = + flatpak_remote_state_fetch_image_source (state, + system, + arg_ref, + verified_digest, + NULL, + NULL, &error); + if (!system_image_source) + { + g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, + "Can't fetch image source: %s", error->message); + return G_DBUS_METHOD_INVOCATION_HANDLED; + } + + checksum = flatpak_pull_from_oci (flatpak_dir_get_repo (system), image_source, system_image_source, arg_origin, arg_ref, FLATPAK_PULL_FLAGS_NONE, NULL, NULL, NULL, &error); if (checksum == NULL) {