forked from Mirrors/flatpak-builder
OCI: Verify signatures
parent
68035c1e4e
commit
5b0ad227e8
|
@ -116,7 +116,7 @@ import_oci (OstreeRepo *repo, GFile *file,
|
|||
}
|
||||
|
||||
commit_checksum = flatpak_pull_from_oci (repo, registry, oci_digest, manifest,
|
||||
target_ref, NULL, NULL, cancellable, error);
|
||||
NULL, target_ref, NULL, NULL, NULL, cancellable, error);
|
||||
if (commit_checksum == NULL)
|
||||
return NULL;
|
||||
|
||||
|
|
|
@ -2046,6 +2046,7 @@ static char *
|
|||
flatpak_dir_lookup_ref_from_summary (FlatpakDir *self,
|
||||
const char *remote,
|
||||
const char *ref,
|
||||
GVariant **out_variant,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
|
@ -2060,7 +2061,7 @@ flatpak_dir_lookup_ref_from_summary (FlatpakDir *self,
|
|||
|
||||
summary = g_variant_ref_sink (g_variant_new_from_bytes (OSTREE_SUMMARY_GVARIANT_FORMAT,
|
||||
summary_bytes, FALSE));
|
||||
if (!flatpak_summary_lookup_ref (summary, ref, &latest_rev))
|
||||
if (!flatpak_summary_lookup_ref (summary, ref, &latest_rev, out_variant))
|
||||
{
|
||||
flatpak_fail (error, "No such ref '%s' in remote %s", ref, remote);
|
||||
return NULL;
|
||||
|
@ -2130,6 +2131,9 @@ flatpak_dir_mirror_oci (FlatpakDir *self,
|
|||
g_autofree char *latest_rev = NULL;
|
||||
g_auto(GLnxConsoleRef) console = { 0, };
|
||||
g_autoptr(OstreeAsyncProgress) console_progress = NULL;
|
||||
g_autoptr(GVariant) summary_element = NULL;
|
||||
g_autoptr(GVariant) metadata = NULL;
|
||||
g_autofree char *signature_digest = NULL;
|
||||
gboolean res;
|
||||
|
||||
if (!ostree_repo_remote_get_url (self->repo,
|
||||
|
@ -2139,11 +2143,14 @@ flatpak_dir_mirror_oci (FlatpakDir *self,
|
|||
return FALSE;
|
||||
|
||||
/* We use the summary so that we can reuse any cached json */
|
||||
latest_rev = flatpak_dir_lookup_ref_from_summary (self, remote, ref,
|
||||
latest_rev = flatpak_dir_lookup_ref_from_summary (self, remote, ref, &summary_element,
|
||||
cancellable, error);
|
||||
if (latest_rev == NULL)
|
||||
return FALSE;
|
||||
|
||||
metadata = g_variant_get_child_value (summary_element, 2);
|
||||
g_variant_lookup (metadata, "xa.oci-signature", "s", &signature_digest);
|
||||
|
||||
if (skip_if_current_is != NULL && strcmp (latest_rev, skip_if_current_is) == 0)
|
||||
{
|
||||
g_set_error (error, FLATPAK_ERROR, FLATPAK_ERROR_ALREADY_INSTALLED,
|
||||
|
@ -2171,7 +2178,7 @@ flatpak_dir_mirror_oci (FlatpakDir *self,
|
|||
|
||||
g_debug ("Mirroring OCI image %s\n", oci_digest);
|
||||
|
||||
res = flatpak_mirror_image_from_oci (dst_registry, registry, oci_digest, oci_pull_progress_cb,
|
||||
res = flatpak_mirror_image_from_oci (dst_registry, registry, oci_digest, signature_digest, oci_pull_progress_cb,
|
||||
progress, cancellable, error);
|
||||
|
||||
if (progress)
|
||||
|
@ -2203,6 +2210,8 @@ flatpak_dir_pull_oci (FlatpakDir *self,
|
|||
g_autofree char *checksum = NULL;
|
||||
g_auto(GLnxConsoleRef) console = { 0, };
|
||||
g_autoptr(OstreeAsyncProgress) console_progress = NULL;
|
||||
g_autoptr(GVariant) summary_element = NULL;
|
||||
g_autofree char *signature_digest = NULL;
|
||||
g_autofree char *latest_alt_commit = NULL;
|
||||
g_autofree char *latest_commit = flatpak_dir_read_latest (self, remote, ref,
|
||||
&latest_alt_commit,
|
||||
|
@ -2220,13 +2229,18 @@ flatpak_dir_pull_oci (FlatpakDir *self,
|
|||
}
|
||||
else
|
||||
{
|
||||
g_autoptr(GVariant) metadata = NULL;
|
||||
/* We use the summary so that we can reuse any cached json */
|
||||
g_autofree char *latest_rev =
|
||||
flatpak_dir_lookup_ref_from_summary (self, remote, ref,
|
||||
flatpak_dir_lookup_ref_from_summary (self, remote, ref, &summary_element,
|
||||
cancellable, error);
|
||||
if (latest_rev == NULL)
|
||||
return FALSE;
|
||||
|
||||
metadata = g_variant_get_child_value (summary_element, 2);
|
||||
|
||||
g_variant_lookup (metadata, "xa.oci-signature", "s", &signature_digest);
|
||||
|
||||
oci_digest = g_strconcat ("sha256:", latest_rev, NULL);
|
||||
}
|
||||
|
||||
|
@ -2270,7 +2284,7 @@ flatpak_dir_pull_oci (FlatpakDir *self,
|
|||
g_debug ("Pulling OCI image %s\n", oci_digest);
|
||||
|
||||
checksum = flatpak_pull_from_oci (repo, registry, oci_digest, FLATPAK_OCI_MANIFEST (versioned),
|
||||
full_ref, oci_pull_progress_cb, progress, cancellable, error);
|
||||
remote, ref, signature_digest, oci_pull_progress_cb, progress, cancellable, error);
|
||||
|
||||
if (progress)
|
||||
ostree_async_progress_finish (progress);
|
||||
|
@ -2328,7 +2342,7 @@ flatpak_dir_pull (FlatpakDir *self,
|
|||
rev = opt_rev;
|
||||
else
|
||||
{
|
||||
rev = flatpak_dir_lookup_ref_from_summary (self, repository, ref, cancellable, error);
|
||||
rev = flatpak_dir_lookup_ref_from_summary (self, repository, ref, NULL, cancellable, error);
|
||||
if (rev == NULL)
|
||||
return FALSE;
|
||||
}
|
||||
|
@ -2548,7 +2562,7 @@ flatpak_dir_pull_untrusted_local (FlatpakDir *self,
|
|||
summary = g_variant_ref_sink (g_variant_new_from_bytes (OSTREE_SUMMARY_GVARIANT_FORMAT, summary_bytes, FALSE));
|
||||
if (!flatpak_summary_lookup_ref (summary,
|
||||
ref,
|
||||
&checksum))
|
||||
&checksum, NULL))
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
|
||||
_("Can't find %s in remote %s"), ref, remote_name);
|
||||
|
@ -4980,7 +4994,7 @@ flatpak_dir_update (FlatpakDir *self,
|
|||
|
||||
if (flatpak_summary_lookup_ref (summary,
|
||||
ref,
|
||||
&latest_rev))
|
||||
&latest_rev, NULL))
|
||||
{
|
||||
if (g_strcmp0 (latest_rev, installed_commit) == 0 ||
|
||||
g_strcmp0 (latest_rev, installed_alt_id) == 0)
|
||||
|
@ -5999,7 +6013,9 @@ flatpak_dir_remote_make_oci_summary (FlatpakDir *self,
|
|||
guint64 download_size = 0;
|
||||
const char *installed_size_str;
|
||||
const char *download_size_str;
|
||||
const char *signature_digest;
|
||||
const char *metadata_contents = NULL;
|
||||
g_autoptr(GVariantBuilder) ref_metadata_builder = NULL;
|
||||
|
||||
ref = flatpak_oci_manifest_descriptor_get_ref (m);
|
||||
if (ref == NULL)
|
||||
|
@ -6025,13 +6041,18 @@ flatpak_dir_remote_make_oci_summary (FlatpakDir *self,
|
|||
if (download_size_str)
|
||||
download_size = g_ascii_strtoull (download_size_str, NULL, 10);
|
||||
|
||||
ref_metadata_builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}"));
|
||||
|
||||
signature_digest = g_hash_table_lookup (d->annotations, "org.flatpak.signature-digest");
|
||||
if (signature_digest)
|
||||
g_variant_builder_add (ref_metadata_builder, "{sv}", "xa.oci-signature",
|
||||
g_variant_new_string (signature_digest));
|
||||
|
||||
g_variant_builder_add_value (refs_builder,
|
||||
g_variant_new ("(s(t@ay@a{sv}))", ref,
|
||||
0,
|
||||
ostree_checksum_to_bytes_v (fake_commit),
|
||||
flatpak_gvariant_new_empty_string_dict ()));
|
||||
|
||||
g_variant_builder_end (ref_metadata_builder)));
|
||||
g_variant_builder_add (ref_data_builder, "{s(tts)}",
|
||||
ref,
|
||||
GUINT64_TO_BE (installed_size),
|
||||
|
@ -6145,7 +6166,7 @@ flatpak_dir_remote_has_ref (FlatpakDir *self,
|
|||
summary = g_variant_ref_sink (g_variant_new_from_bytes (OSTREE_SUMMARY_GVARIANT_FORMAT,
|
||||
summary_bytes, FALSE));
|
||||
|
||||
return flatpak_summary_lookup_ref (summary, ref, NULL);
|
||||
return flatpak_summary_lookup_ref (summary, ref, NULL, NULL);
|
||||
}
|
||||
|
||||
/* This duplicates ostree_repo_list_refs so it can use flatpak_dir_remote_fetch_summary
|
||||
|
@ -7951,9 +7972,7 @@ flatpak_dir_find_remote_related (FlatpakDir *self,
|
|||
|
||||
extension_ref = g_build_filename ("runtime", extension, parts[2], branch, NULL);
|
||||
|
||||
if (flatpak_summary_lookup_ref (summary,
|
||||
extension_ref,
|
||||
&checksum))
|
||||
if (flatpak_summary_lookup_ref (summary, extension_ref, &checksum, NULL))
|
||||
{
|
||||
add_related (self, related, extension, extension_ref, checksum, no_autodownload, download_if, autodelete);
|
||||
}
|
||||
|
@ -7963,9 +7982,7 @@ flatpak_dir_find_remote_related (FlatpakDir *self,
|
|||
int j;
|
||||
for (j = 0; refs[j] != NULL; j++)
|
||||
{
|
||||
if (flatpak_summary_lookup_ref (summary,
|
||||
refs[j],
|
||||
&checksum))
|
||||
if (flatpak_summary_lookup_ref (summary, refs[j], &checksum, NULL))
|
||||
add_related (self, related, extension, refs[j], checksum, no_autodownload, download_if, autodelete);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1449,28 +1449,6 @@ set_errno_from_gio_error (GError *error)
|
|||
}
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
data_read_cb (void *handle, void *buffer, size_t size)
|
||||
{
|
||||
GInputStream *input_stream = handle;
|
||||
gsize bytes_read;
|
||||
GError *local_error = NULL;
|
||||
|
||||
g_return_val_if_fail (G_IS_INPUT_STREAM (input_stream), -1);
|
||||
|
||||
g_input_stream_read_all (input_stream, buffer, size,
|
||||
&bytes_read, NULL, &local_error);
|
||||
|
||||
if (local_error != NULL)
|
||||
{
|
||||
set_errno_from_gio_error (local_error);
|
||||
g_clear_error (&local_error);
|
||||
bytes_read = -1;
|
||||
}
|
||||
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
data_write_cb (void *handle, const void *buffer, size_t size)
|
||||
{
|
||||
|
@ -1554,13 +1532,6 @@ data_release_cb (void *handle)
|
|||
g_object_unref (stream);
|
||||
}
|
||||
|
||||
static struct gpgme_data_cbs data_input_cbs = {
|
||||
data_read_cb,
|
||||
NULL,
|
||||
data_seek_cb,
|
||||
data_release_cb
|
||||
};
|
||||
|
||||
static struct gpgme_data_cbs data_output_cbs = {
|
||||
NULL,
|
||||
data_write_cb,
|
||||
|
@ -1568,29 +1539,6 @@ static struct gpgme_data_cbs data_output_cbs = {
|
|||
data_release_cb
|
||||
};
|
||||
|
||||
static gpgme_data_t
|
||||
flatpak_gpgme_data_input (GInputStream *input_stream)
|
||||
{
|
||||
gpgme_data_t data = NULL;
|
||||
gpgme_error_t gpg_error;
|
||||
|
||||
g_return_val_if_fail (G_IS_INPUT_STREAM (input_stream), NULL);
|
||||
|
||||
gpg_error = gpgme_data_new_from_cbs (&data, &data_input_cbs, input_stream);
|
||||
|
||||
/* The only possible error is ENOMEM, which we abort on. */
|
||||
if (gpg_error != GPG_ERR_NO_ERROR)
|
||||
{
|
||||
g_assert (gpgme_err_code (gpg_error) == GPG_ERR_ENOMEM);
|
||||
flatpak_gpgme_error_to_gio_error (gpg_error, NULL);
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
g_object_ref (input_stream);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static gpgme_data_t
|
||||
flatpak_gpgme_data_output (GOutputStream *output_stream)
|
||||
{
|
||||
|
@ -1730,3 +1678,196 @@ flatpak_oci_sign_data (GBytes *data,
|
|||
|
||||
return g_mapped_file_get_bytes (signature_file);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
signature_is_valid (gpgme_signature_t signature)
|
||||
{
|
||||
/* Mimic the way librepo tests for a valid signature, checking both
|
||||
* summary and status fields.
|
||||
*
|
||||
* - VALID summary flag means the signature is fully valid.
|
||||
* - GREEN summary flag means the signature is valid with caveats.
|
||||
* - No summary but also no error means the signature is valid but
|
||||
* the signing key is not certified with a trusted signature.
|
||||
*/
|
||||
return (signature->summary & GPGME_SIGSUM_VALID) ||
|
||||
(signature->summary & GPGME_SIGSUM_GREEN) ||
|
||||
(signature->summary == 0 && signature->status == GPG_ERR_NO_ERROR);
|
||||
}
|
||||
|
||||
static GString *
|
||||
read_gpg_buffer (gpgme_data_t buffer, GError **error)
|
||||
{
|
||||
g_autoptr(GString) res = g_string_new ("");
|
||||
char buf[1024];
|
||||
int ret;
|
||||
|
||||
ret = gpgme_data_seek (buffer, 0, SEEK_SET);
|
||||
if (ret)
|
||||
{
|
||||
flatpak_fail (error, "Can't seek in gpg plain text");
|
||||
return NULL;
|
||||
}
|
||||
while ((ret = gpgme_data_read (buffer, buf, sizeof(buf)-1)) > 0)
|
||||
g_string_append_len (res, buf, ret);
|
||||
if (ret < 0)
|
||||
{
|
||||
flatpak_fail (error, "Can't read in gpg plain text");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return g_steal_pointer (&res);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
flatpak_gpgme_ctx_tmp_home_dir (gpgme_ctx_t gpgme_ctx,
|
||||
char **out_tmp_home_dir,
|
||||
OstreeRepo *repo,
|
||||
const char *remote_name,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
g_autofree char *tmp_home_dir = NULL;
|
||||
gpgme_error_t gpg_error;
|
||||
gboolean ret = FALSE;
|
||||
g_autoptr(GFile) keyring_file = NULL;
|
||||
g_autofree char *keyring_name = NULL;
|
||||
g_autoptr(GFile) pubring_file = NULL;
|
||||
g_autofree char *pubring_path = NULL;
|
||||
|
||||
g_return_val_if_fail (gpgme_ctx != NULL, FALSE);
|
||||
|
||||
/* GPGME has no API for using multiple keyrings (aka, gpg --keyring),
|
||||
* so we create a temporary directory and tell GPGME to use it as the
|
||||
* home directory. Then (optionally) create a pubring.gpg file there
|
||||
* and hand the caller an open output stream to concatenate necessary
|
||||
* keyring files. */
|
||||
|
||||
tmp_home_dir = g_build_filename (g_get_tmp_dir (), "flatpak-gpg-XXXXXX", NULL);
|
||||
if (mkdtemp (tmp_home_dir) == NULL)
|
||||
{
|
||||
glnx_set_error_from_errno (error);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Not documented, but gpgme_ctx_set_engine_info() accepts NULL for
|
||||
* the executable file name, which leaves the old setting unchanged. */
|
||||
gpg_error = gpgme_ctx_set_engine_info (gpgme_ctx,
|
||||
GPGME_PROTOCOL_OpenPGP,
|
||||
NULL, tmp_home_dir);
|
||||
if (gpg_error != GPG_ERR_NO_ERROR)
|
||||
{
|
||||
flatpak_gpgme_error_to_gio_error (gpg_error, error);
|
||||
goto out;
|
||||
}
|
||||
|
||||
keyring_name = g_strdup_printf ("%s.trustedkeys.gpg", remote_name);
|
||||
keyring_file = g_file_get_child (ostree_repo_get_path (repo), keyring_name);
|
||||
|
||||
pubring_path = g_build_filename (tmp_home_dir, "pubring.gpg", NULL);
|
||||
pubring_file = g_file_new_for_path (pubring_path);
|
||||
|
||||
if (g_file_query_exists (keyring_file, NULL) &&
|
||||
!glnx_file_copy_at (AT_FDCWD, flatpak_file_get_path_cached (keyring_file), NULL,
|
||||
AT_FDCWD, flatpak_file_get_path_cached (pubring_file),
|
||||
GLNX_FILE_COPY_OVERWRITE | GLNX_FILE_COPY_NOXATTRS,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
|
||||
if (out_tmp_home_dir != NULL)
|
||||
*out_tmp_home_dir = g_steal_pointer (&tmp_home_dir);
|
||||
|
||||
ret = TRUE;
|
||||
|
||||
out:
|
||||
if (!ret)
|
||||
{
|
||||
/* Clean up our mess on error. */
|
||||
(void) glnx_shutil_rm_rf_at (AT_FDCWD, tmp_home_dir, NULL, NULL);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
FlatpakOciSignature *
|
||||
flatpak_oci_verify_signature (OstreeRepo *repo,
|
||||
const char *remote_name,
|
||||
GBytes *signed_data,
|
||||
GError **error)
|
||||
{
|
||||
gpgme_ctx_t context;
|
||||
gpgme_error_t gpg_error;
|
||||
flatpak_auto_gpgme_data gpgme_data_t signed_data_buffer = NULL;
|
||||
flatpak_auto_gpgme_data gpgme_data_t plain_buffer = NULL;
|
||||
g_autofree char *tmp_home_dir = NULL;
|
||||
gpgme_verify_result_t vresult;
|
||||
gpgme_signature_t sig;
|
||||
int valid_count;
|
||||
g_autoptr(GString) plain = NULL;
|
||||
g_autoptr(GBytes) plain_bytes = NULL;
|
||||
g_autoptr(FlatpakJson) json = NULL;
|
||||
|
||||
gpg_error = gpgme_new (&context);
|
||||
if (gpg_error != GPG_ERR_NO_ERROR)
|
||||
{
|
||||
flatpak_gpgme_error_to_gio_error (gpg_error, error);
|
||||
g_prefix_error (error, "Unable to create context: ");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!flatpak_gpgme_ctx_tmp_home_dir (context, &tmp_home_dir, repo, remote_name, NULL, error))
|
||||
return NULL;
|
||||
|
||||
gpg_error = gpgme_data_new_from_mem (&signed_data_buffer,
|
||||
g_bytes_get_data (signed_data, NULL),
|
||||
g_bytes_get_size (signed_data),
|
||||
0 /* do not copy */);
|
||||
if (gpg_error != GPG_ERR_NO_ERROR)
|
||||
{
|
||||
flatpak_gpgme_error_to_gio_error (gpg_error, error);
|
||||
g_prefix_error (error, "Unable to read signed data: ");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gpg_error = gpgme_data_new (&plain_buffer);
|
||||
if (gpg_error != GPG_ERR_NO_ERROR)
|
||||
{
|
||||
flatpak_gpgme_error_to_gio_error (gpg_error, error);
|
||||
g_prefix_error (error, "Unable to allocate plain buffer: ");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gpg_error = gpgme_op_verify (context, signed_data_buffer, NULL, plain_buffer);
|
||||
if (gpg_error != GPG_ERR_NO_ERROR)
|
||||
{
|
||||
flatpak_gpgme_error_to_gio_error (gpg_error, error);
|
||||
g_prefix_error (error, "Unable to complete signature verification: ");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vresult = gpgme_op_verify_result (context);
|
||||
|
||||
valid_count = 0;
|
||||
for (sig = vresult->signatures; sig != NULL; sig = sig->next)
|
||||
{
|
||||
if (signature_is_valid (sig))
|
||||
valid_count++;
|
||||
}
|
||||
|
||||
if (valid_count == 0)
|
||||
{
|
||||
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"GPG signatures found, but none are in trusted keyring");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
plain = read_gpg_buffer (plain_buffer, error);
|
||||
if (plain == NULL)
|
||||
return NULL;
|
||||
plain_bytes = g_string_free_to_bytes (g_steal_pointer (&plain));
|
||||
json = flatpak_json_from_bytes (plain_bytes, FLATPAK_TYPE_OCI_SIGNATURE, error);
|
||||
if (json == NULL)
|
||||
return FALSE;
|
||||
|
||||
return g_steal_pointer (&json);
|
||||
}
|
||||
|
|
|
@ -117,8 +117,13 @@ gboolean flatpak_archive_read_open_fd_with_checksum (struct archive *a,
|
|||
GError **error);
|
||||
|
||||
GBytes *flatpak_oci_sign_data (GBytes *data,
|
||||
const gchar **key_ids,
|
||||
const gchar **okey_ids,
|
||||
const char *homedir,
|
||||
GError **error);
|
||||
|
||||
FlatpakOciSignature *flatpak_oci_verify_signature (OstreeRepo *repo,
|
||||
const char *remote_name,
|
||||
GBytes *signature,
|
||||
GError **error);
|
||||
|
||||
#endif /* __FLATPAK_OCI_REGISTRY_H__ */
|
||||
|
|
|
@ -2587,7 +2587,7 @@ flatpak_summary_match_subrefs (GVariant *summary, const char *ref)
|
|||
}
|
||||
|
||||
gboolean
|
||||
flatpak_summary_lookup_ref (GVariant *summary, const char *ref, char **out_checksum)
|
||||
flatpak_summary_lookup_ref (GVariant *summary, const char *ref, char **out_checksum, GVariant **out_variant)
|
||||
{
|
||||
g_autoptr(GVariant) refs = g_variant_get_child_value (summary, 0);
|
||||
int pos;
|
||||
|
@ -2609,6 +2609,9 @@ flatpak_summary_lookup_ref (GVariant *summary, const char *ref, char **out_check
|
|||
if (out_checksum)
|
||||
*out_checksum = ostree_checksum_from_bytes_v (commit_csum_v);
|
||||
|
||||
if (out_variant)
|
||||
*out_variant = g_steal_pointer (&reftargetdata);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -2952,7 +2955,7 @@ flatpak_repo_update (OstreeRepo *repo,
|
|||
g_autoptr(GVariant) old_commit_data_v = g_variant_get_child_value (old_element, 1);
|
||||
CommitData *old_rev_data;
|
||||
|
||||
if (flatpak_summary_lookup_ref (old_summary, old_ref, &old_rev))
|
||||
if (flatpak_summary_lookup_ref (old_summary, old_ref, &old_rev, NULL))
|
||||
{
|
||||
guint64 old_installed_size, old_download_size;
|
||||
g_autofree char *old_metadata = NULL;
|
||||
|
@ -4415,6 +4418,7 @@ gboolean
|
|||
flatpak_mirror_image_from_oci (FlatpakOciRegistry *dst_registry,
|
||||
FlatpakOciRegistry *registry,
|
||||
const char *digest,
|
||||
const char *signature_digest,
|
||||
FlatpakOciPullProgress progress_cb,
|
||||
gpointer progress_user_data,
|
||||
GCancellable *cancellable,
|
||||
|
@ -4436,6 +4440,10 @@ flatpak_mirror_image_from_oci (FlatpakOciRegistry *dst_registry,
|
|||
if (!flatpak_oci_registry_mirror_blob (dst_registry, registry, digest, NULL, NULL, cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
if (signature_digest &&
|
||||
!flatpak_oci_registry_mirror_blob (dst_registry, registry, signature_digest, NULL, NULL, cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
versioned = flatpak_oci_registry_load_versioned (dst_registry, digest, &versioned_size, cancellable, error);
|
||||
if (versioned == NULL)
|
||||
return FALSE;
|
||||
|
@ -4489,6 +4497,11 @@ flatpak_mirror_image_from_oci (FlatpakOciRegistry *dst_registry,
|
|||
|
||||
flatpak_oci_export_annotations (manifest->annotations, manifest_desc->annotations);
|
||||
|
||||
if (signature_digest)
|
||||
g_hash_table_replace (manifest_desc->annotations,
|
||||
g_strdup ("org.flatpak.signature-digest"),
|
||||
g_strdup (signature_digest));
|
||||
|
||||
flatpak_oci_index_add_manifest (index, manifest_desc);
|
||||
|
||||
if (!flatpak_oci_registry_save_index (dst_registry, index, cancellable, error))
|
||||
|
@ -4503,7 +4516,9 @@ flatpak_pull_from_oci (OstreeRepo *repo,
|
|||
FlatpakOciRegistry *registry,
|
||||
const char *digest,
|
||||
FlatpakOciManifest *manifest,
|
||||
const char *remote,
|
||||
const char *ref,
|
||||
const char *signature_digest,
|
||||
FlatpakOciPullProgress progress_cb,
|
||||
gpointer progress_user_data,
|
||||
GCancellable *cancellable,
|
||||
|
@ -4516,21 +4531,64 @@ flatpak_pull_from_oci (OstreeRepo *repo,
|
|||
g_autofree char *subject = NULL;
|
||||
g_autofree char *body = NULL;
|
||||
g_autofree char *manifest_ref = NULL;
|
||||
g_autofree char *parsed_remote = NULL;
|
||||
g_autofree char *parsed_ref = NULL;
|
||||
g_autofree char *full_ref = NULL;
|
||||
guint64 timestamp = 0;
|
||||
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;
|
||||
GHashTable *annotations;
|
||||
gboolean gpg_verify = FALSE;
|
||||
int i;
|
||||
|
||||
g_assert (ref != NULL);
|
||||
g_assert (g_str_has_prefix (digest, "sha256:"));
|
||||
|
||||
if (!ostree_parse_refspec (ref, &parsed_remote, &parsed_ref, error))
|
||||
if (remote &&
|
||||
!ostree_repo_remote_get_gpg_verify (repo, remote,
|
||||
&gpg_verify, error))
|
||||
return NULL;
|
||||
|
||||
if (gpg_verify)
|
||||
{
|
||||
g_autoptr(GBytes) signature_bytes = NULL;
|
||||
g_autoptr(FlatpakOciSignature) signature = NULL;
|
||||
|
||||
if (signature_digest == NULL)
|
||||
{
|
||||
flatpak_fail (error, "GPG verification enabled, but no OCI signature found");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
signature_bytes = flatpak_oci_registry_load_blob (registry, signature_digest, cancellable, error);
|
||||
if (signature_bytes == NULL)
|
||||
return NULL;
|
||||
|
||||
signature = flatpak_oci_verify_signature (repo, remote, signature_bytes, error);
|
||||
if (signature == NULL)
|
||||
return NULL;
|
||||
|
||||
if (g_strcmp0 (signature->critical.type, FLATPAK_OCI_SIGNATURE_TYPE_FLATPAK) != 0)
|
||||
{
|
||||
flatpak_fail (error, "Invalid signature type %s", signature->critical.type);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (g_strcmp0 (signature->critical.image.digest, digest) != 0)
|
||||
{
|
||||
flatpak_fail (error, "Invalid signature digest %s", signature->critical.image.digest);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (g_strcmp0 (signature->critical.identity.ref, ref) != 0)
|
||||
{
|
||||
flatpak_fail (error, "Invalid signature ref %s", signature->critical.identity.ref);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Success! It is valid */
|
||||
g_debug ("Verified OCI signature for %s %s\n", signature->critical.identity.ref, digest);
|
||||
}
|
||||
|
||||
annotations = flatpak_oci_manifest_get_annotations (manifest);
|
||||
if (annotations)
|
||||
flatpak_oci_parse_commit_annotations (annotations, ×tamp,
|
||||
|
@ -4543,7 +4601,7 @@ flatpak_pull_from_oci (OstreeRepo *repo,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
if (strcmp (manifest_ref, parsed_ref) != 0)
|
||||
if (strcmp (manifest_ref, ref) != 0)
|
||||
{
|
||||
flatpak_fail (error, "Wrong ref (%s) specified for OCI image %s, expected %s\n", manifest_ref, digest, ref);
|
||||
return NULL;
|
||||
|
@ -4639,7 +4697,12 @@ flatpak_pull_from_oci (OstreeRepo *repo,
|
|||
cancellable, error))
|
||||
goto error;
|
||||
|
||||
ostree_repo_transaction_set_ref (repo, NULL, ref, commit_checksum);
|
||||
if (remote)
|
||||
full_ref = g_strdup_printf ("%s:%s", remote, ref);
|
||||
else
|
||||
full_ref = g_strdup (ref);
|
||||
|
||||
ostree_repo_transaction_set_ref (repo, NULL, full_ref, commit_checksum);
|
||||
|
||||
if (!ostree_repo_commit_transaction (repo, NULL, cancellable, error))
|
||||
return NULL;
|
||||
|
|
|
@ -117,7 +117,8 @@ char ** flatpak_summary_match_subrefs (GVariant *summary,
|
|||
const char *ref);
|
||||
gboolean flatpak_summary_lookup_ref (GVariant *summary,
|
||||
const char *ref,
|
||||
char **out_checksum);
|
||||
char **out_checksum,
|
||||
GVariant **out_variant);
|
||||
|
||||
gboolean flatpak_has_name_prefix (const char *string,
|
||||
const char *name);
|
||||
|
@ -343,7 +344,9 @@ char * flatpak_pull_from_oci (OstreeRepo *repo,
|
|||
FlatpakOciRegistry *registry,
|
||||
const char *digest,
|
||||
FlatpakOciManifest *manifest,
|
||||
const char *remote,
|
||||
const char *ref,
|
||||
const char *signature_digest,
|
||||
FlatpakOciPullProgress progress_cb,
|
||||
gpointer progress_data,
|
||||
GCancellable *cancellable,
|
||||
|
@ -352,6 +355,7 @@ char * flatpak_pull_from_oci (OstreeRepo *repo,
|
|||
gboolean flatpak_mirror_image_from_oci (FlatpakOciRegistry *dst_registry,
|
||||
FlatpakOciRegistry *registry,
|
||||
const char *digest,
|
||||
const char *signature_digest,
|
||||
FlatpakOciPullProgress progress_cb,
|
||||
gpointer progress_data,
|
||||
GCancellable *cancellable,
|
||||
|
|
|
@ -229,8 +229,8 @@ handle_deploy (FlatpakSystemHelper *object,
|
|||
g_autoptr(FlatpakOciIndex) index = NULL;
|
||||
const FlatpakOciManifestDescriptor *desc;
|
||||
g_autoptr(FlatpakOciVersioned) versioned = NULL;
|
||||
g_autofree char *full_ref = NULL;
|
||||
g_autofree char *checksum = NULL;
|
||||
const char *signature_digest;
|
||||
|
||||
registry = flatpak_oci_registry_new (registry_uri, FALSE, -1, NULL, &error);
|
||||
if (registry == NULL)
|
||||
|
@ -256,6 +256,8 @@ handle_deploy (FlatpakSystemHelper *object,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
signature_digest = g_hash_table_lookup (desc->parent.annotations, "org.flatpak.signature-digest");
|
||||
|
||||
versioned = flatpak_oci_registry_load_versioned (registry, desc->parent.digest, NULL,
|
||||
NULL, &error);
|
||||
if (versioned == NULL || !FLATPAK_IS_OCI_MANIFEST (versioned))
|
||||
|
@ -265,14 +267,12 @@ handle_deploy (FlatpakSystemHelper *object,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
full_ref = g_strdup_printf ("%s:%s", arg_origin, arg_ref);
|
||||
|
||||
checksum = flatpak_pull_from_oci (flatpak_dir_get_repo (system), registry, desc->parent.digest, FLATPAK_OCI_MANIFEST (versioned),
|
||||
full_ref, NULL, NULL, NULL, &error);
|
||||
arg_origin, arg_ref, signature_digest, NULL, NULL, NULL, &error);
|
||||
if (checksum == NULL)
|
||||
{
|
||||
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
|
||||
"Can't pull ref %s from child OCI registry index: %s", arg_ref);
|
||||
"Can't pull ref %s from child OCI registry index: %s", arg_ref, error->message);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
@ -414,8 +414,8 @@ handle_deploy_appstream (FlatpakSystemHelper *object,
|
|||
g_autoptr(FlatpakOciIndex) index = NULL;
|
||||
const FlatpakOciManifestDescriptor *desc;
|
||||
g_autoptr(FlatpakOciVersioned) versioned = NULL;
|
||||
g_autofree char *full_ref = NULL;
|
||||
g_autofree char *checksum = NULL;
|
||||
const char *signature_digest;
|
||||
|
||||
registry = flatpak_oci_registry_new (registry_uri, FALSE, -1, NULL, &error);
|
||||
if (registry == NULL)
|
||||
|
@ -441,6 +441,8 @@ handle_deploy_appstream (FlatpakSystemHelper *object,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
signature_digest = g_hash_table_lookup (desc->parent.annotations, "org.flatpak.signature-digest");
|
||||
|
||||
versioned = flatpak_oci_registry_load_versioned (registry, desc->parent.digest, NULL,
|
||||
NULL, &error);
|
||||
if (versioned == NULL || !FLATPAK_IS_OCI_MANIFEST (versioned))
|
||||
|
@ -450,14 +452,12 @@ handle_deploy_appstream (FlatpakSystemHelper *object,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
full_ref = g_strdup_printf ("%s:%s", arg_origin, branch);
|
||||
|
||||
checksum = flatpak_pull_from_oci (flatpak_dir_get_repo (system), registry, desc->parent.digest, FLATPAK_OCI_MANIFEST (versioned),
|
||||
full_ref, NULL, NULL, NULL, &error);
|
||||
arg_origin, branch, signature_digest, NULL, NULL, NULL, &error);
|
||||
if (checksum == NULL)
|
||||
{
|
||||
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
|
||||
"Can't pull ref %s from child OCI registry index: %s", branch);
|
||||
"Can't pull ref %s from child OCI registry index: %s", branch, error->message);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue