Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remote GPG key info #2401

Merged
merged 12 commits into from
Aug 20, 2021
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions Makefile-libostree.am
Original file line number Diff line number Diff line change
Expand Up @@ -173,9 +173,9 @@ endif # USE_GPGME
symbol_files = $(top_srcdir)/src/libostree/libostree-released.sym

# Uncomment this include when adding new development symbols.
#if BUILDOPT_IS_DEVEL_BUILD
#symbol_files += $(top_srcdir)/src/libostree/libostree-devel.sym
#endif
if BUILDOPT_IS_DEVEL_BUILD
symbol_files += $(top_srcdir)/src/libostree/libostree-devel.sym
endif

# http://blog.jgc.org/2007/06/escaping-comma-and-space-in-gnu-make.html
wl_versionscript_arg = -Wl,--version-script=
Expand Down
3 changes: 3 additions & 0 deletions apidoc/ostree-sections.txt
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,7 @@ ostree_repo_remote_list_collection_refs
ostree_repo_remote_get_url
ostree_repo_remote_get_gpg_verify
ostree_repo_remote_get_gpg_verify_summary
ostree_repo_remote_get_gpg_keys
ostree_repo_remote_gpg_import
ostree_repo_remote_fetch_summary
ostree_repo_remote_fetch_summary_with_options
Expand Down Expand Up @@ -482,6 +483,8 @@ ostree_repo_regenerate_summary
OSTREE_REPO
OSTREE_IS_REPO
OSTREE_TYPE_REPO
OSTREE_GPG_KEY_GVARIANT_STRING
OSTREE_GPG_KEY_GVARIANT_FORMAT
ostree_repo_get_type
ostree_repo_commit_modifier_get_type
ostree_repo_transaction_stats_get_type
Expand Down
5 changes: 5 additions & 0 deletions src/libostree/libostree-devel.sym
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@
- uncomment the include in Makefile-libostree.am
*/

LIBOSTREE_2021.4 {
global:
ostree_repo_remote_get_gpg_keys;
} LIBOSTREE_2021.3;

/* Stub section for the stable release *after* this development one; don't
* edit this other than to update the year. This is just a copy/paste
* source. Replace $LASTSTABLE with the last stable version, and $NEWVERSION
Expand Down
194 changes: 149 additions & 45 deletions src/libostree/ostree-gpg-verifier.c
Original file line number Diff line number Diff line change
Expand Up @@ -91,43 +91,16 @@ verify_result_finalized_cb (gpointer data,
(void) glnx_shutil_rm_rf_at (AT_FDCWD, tmp_dir, NULL, NULL);
}

OstreeGpgVerifyResult *
_ostree_gpg_verifier_check_signature (OstreeGpgVerifier *self,
GBytes *signed_data,
GBytes *signatures,
GCancellable *cancellable,
GError **error)
static gboolean
_ostree_gpg_verifier_import_keys (OstreeGpgVerifier *self,
gpgme_ctx_t gpgme_ctx,
GOutputStream *pubring_stream,
GCancellable *cancellable,
GError **error)
{
GLNX_AUTO_PREFIX_ERROR("GPG", error);
gpgme_error_t gpg_error = 0;
g_auto(gpgme_data_t) data_buffer = NULL;
g_auto(gpgme_data_t) signature_buffer = NULL;
g_autofree char *tmp_dir = NULL;
g_autoptr(GOutputStream) target_stream = NULL;
OstreeGpgVerifyResult *result = NULL;
gboolean success = FALSE;
GList *link;
int armor;

/* GPGME has no API for using multiple keyrings (aka, gpg --keyring),
* so we concatenate all the keyring files into one pubring.gpg in a
* temporary directory, then tell GPGME to use that directory as the
* home directory. */

if (g_cancellable_set_error_if_cancelled (cancellable, error))
goto out;

result = g_initable_new (OSTREE_TYPE_GPG_VERIFY_RESULT,
cancellable, error, NULL);
if (result == NULL)
goto out;

if (!ot_gpgme_ctx_tmp_home_dir (result->context,
&tmp_dir, &target_stream,
cancellable, error))
goto out;

for (link = self->keyrings; link != NULL; link = link->next)
for (GList *link = self->keyrings; link != NULL; link = link->next)
{
g_autoptr(GFileInputStream) source_stream = NULL;
GFile *keyring_file = link->data;
Expand All @@ -145,15 +118,15 @@ _ostree_gpg_verifier_check_signature (OstreeGpgVerifier *self,
else if (local_error != NULL)
{
g_propagate_error (error, local_error);
goto out;
return FALSE;
}

bytes_written = g_output_stream_splice (target_stream,
bytes_written = g_output_stream_splice (pubring_stream,
G_INPUT_STREAM (source_stream),
G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE,
cancellable, error);
if (bytes_written < 0)
goto out;
return FALSE;
}

for (guint i = 0; i < self->keyring_data->len; i++)
Expand All @@ -162,23 +135,25 @@ _ostree_gpg_verifier_check_signature (OstreeGpgVerifier *self,
gsize len;
gsize bytes_written;
const guint8 *buf = g_bytes_get_data (keyringd, &len);
if (!g_output_stream_write_all (target_stream, buf, len, &bytes_written,
if (!g_output_stream_write_all (pubring_stream, buf, len, &bytes_written,
cancellable, error))
goto out;
return FALSE;
}

if (!g_output_stream_close (target_stream, cancellable, error))
goto out;
if (!g_output_stream_close (pubring_stream, cancellable, error))
return FALSE;

/* Save the previous armor value - we need it on for importing ASCII keys */
armor = gpgme_get_armor (result->context);
gpgme_set_armor (result->context, 1);
gboolean ret = FALSE;
int armor = gpgme_get_armor (gpgme_ctx);
gpgme_set_armor (gpgme_ctx, 1);

/* Now, use the API to import ASCII-armored keys */
if (self->key_ascii_files)
{
for (guint i = 0; i < self->key_ascii_files->len; i++)
{
gpgme_error_t gpg_error;
const char *path = self->key_ascii_files->pdata[i];
glnx_autofd int fd = -1;
g_auto(gpgme_data_t) kdata = NULL;
Expand All @@ -193,7 +168,7 @@ _ostree_gpg_verifier_check_signature (OstreeGpgVerifier *self,
goto out;
}

gpg_error = gpgme_op_import (result->context, kdata);
gpg_error = gpgme_op_import (gpgme_ctx, kdata);
if (gpg_error != GPG_ERR_NO_ERROR)
{
ot_gpgme_throw (gpg_error, error, "Failed to import key");
Expand All @@ -202,7 +177,136 @@ _ostree_gpg_verifier_check_signature (OstreeGpgVerifier *self,
}
}

gpgme_set_armor (result->context, armor);
ret = TRUE;

out:
gpgme_set_armor (gpgme_ctx, armor);

return ret;
}

gboolean
_ostree_gpg_verifier_list_keys (OstreeGpgVerifier *self,
const char * const *key_ids,
GPtrArray **out_keys,
GCancellable *cancellable,
GError **error)
{
GLNX_AUTO_PREFIX_ERROR("GPG", error);
g_auto(gpgme_ctx_t) context = NULL;
g_autoptr(GOutputStream) pubring_stream = NULL;
g_autofree char *tmp_dir = NULL;
g_autoptr(GPtrArray) keys = NULL;
gpgme_error_t gpg_error = 0;
gboolean ret = FALSE;

if (g_cancellable_set_error_if_cancelled (cancellable, error))
goto out;

context = ot_gpgme_new_ctx (NULL, error);
if (context == NULL)
goto out;

if (!ot_gpgme_ctx_tmp_home_dir (context, &tmp_dir, &pubring_stream,
cancellable, error))
goto out;

if (!_ostree_gpg_verifier_import_keys (self, context, pubring_stream,
cancellable, error))
goto out;

keys = g_ptr_array_new_with_free_func ((GDestroyNotify) gpgme_key_unref);
if (key_ids != NULL)
{
for (guint i = 0; key_ids[i] != NULL; i++)
{
gpgme_key_t key = NULL;

gpg_error = gpgme_get_key (context, key_ids[i], &key, 0);
if (gpg_error != GPG_ERR_NO_ERROR)
{
ot_gpgme_throw (gpg_error, error, "Unable to find key \"%s\"",
key_ids[i]);
goto out;
}

/* Transfer ownership. */
g_ptr_array_add (keys, key);
}
}
else
{
gpg_error = gpgme_op_keylist_start (context, NULL, 0);
while (gpg_error == GPG_ERR_NO_ERROR)
{
gpgme_key_t key = NULL;

gpg_error = gpgme_op_keylist_next (context, &key);
if (gpg_error != GPG_ERR_NO_ERROR)
break;

/* Transfer ownership. */
g_ptr_array_add (keys, key);
}

if (gpgme_err_code (gpg_error) != GPG_ERR_EOF)
{
ot_gpgme_throw (gpg_error, error, "Unable to list keys");
goto out;
}
}

if (out_keys != NULL)
*out_keys = g_steal_pointer (&keys);

ret = TRUE;

out:
if (tmp_dir != NULL) {
ot_gpgme_kill_agent (tmp_dir);
(void) glnx_shutil_rm_rf_at (AT_FDCWD, tmp_dir, NULL, NULL);
Comment on lines +265 to +267
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can probably make these autocleanups too in the future.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think so. The gpgme code could use some sprucing up.

}

return ret;
}

OstreeGpgVerifyResult *
_ostree_gpg_verifier_check_signature (OstreeGpgVerifier *self,
GBytes *signed_data,
GBytes *signatures,
GCancellable *cancellable,
GError **error)
{
GLNX_AUTO_PREFIX_ERROR("GPG", error);
gpgme_error_t gpg_error = 0;
g_auto(gpgme_data_t) data_buffer = NULL;
g_auto(gpgme_data_t) signature_buffer = NULL;
g_autofree char *tmp_dir = NULL;
g_autoptr(GOutputStream) target_stream = NULL;
OstreeGpgVerifyResult *result = NULL;
gboolean success = FALSE;

/* GPGME has no API for using multiple keyrings (aka, gpg --keyring),
* so we concatenate all the keyring files into one pubring.gpg in a
* temporary directory, then tell GPGME to use that directory as the
* home directory. */

if (g_cancellable_set_error_if_cancelled (cancellable, error))
goto out;

result = g_initable_new (OSTREE_TYPE_GPG_VERIFY_RESULT,
cancellable, error, NULL);
if (result == NULL)
goto out;

if (!ot_gpgme_ctx_tmp_home_dir (result->context,
&tmp_dir, &target_stream,
cancellable, error))
goto out;

if (!_ostree_gpg_verifier_import_keys (self, result->context, target_stream,
cancellable, error))
goto out;

/* Both the signed data and signature GBytes instances will outlive the
* gpgme_data_t structs, so we can safely reuse the GBytes memory buffer
Expand Down
6 changes: 6 additions & 0 deletions src/libostree/ostree-gpg-verifier.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,12 @@ OstreeGpgVerifyResult *_ostree_gpg_verifier_check_signature (OstreeGpgVerifier *
GCancellable *cancellable,
GError **error);

gboolean _ostree_gpg_verifier_list_keys (OstreeGpgVerifier *self,
const char * const *key_ids,
GPtrArray **out_keys,
GCancellable *cancellable,
GError **error);

gboolean _ostree_gpg_verifier_add_keyring_dir (OstreeGpgVerifier *self,
GFile *path,
GCancellable *cancellable,
Expand Down
Loading