summaryrefslogtreecommitdiff
path: root/src/libostree/ostree-gpg-verifier.c
diff options
context:
space:
mode:
authorMatthew Barnes <mbarnes@redhat.com>2015-03-04 12:44:47 -0500
committerMatthew Barnes <mbarnes@redhat.com>2015-03-18 11:52:22 -0400
commit4a2733f9e7e2ca127ff27433c045c977000ca346 (patch)
treed9ebb75c80aad9935c7196990847288dc47a0ca8 /src/libostree/ostree-gpg-verifier.c
parent553d7840d5d5ada906da8328fc84bc8b40c6d8b1 (diff)
downloadostree-4a2733f9e7e2ca127ff27433c045c977000ca346.tar.gz
gpg: Add OstreeGpgVerifyResult
Wrappers a referenced gpgme_verify_result_t so detailed verify results can be examined independently of executing a verify operation. _ostree_gpg_verifier_check_signature() now returns this object instead of a single valid/invalid boolean, but the idea is for OstreeRepo to also return this object for commit signature verification so it can be utilized at the CLI layer (and possibly by other programs).
Diffstat (limited to 'src/libostree/ostree-gpg-verifier.c')
-rw-r--r--src/libostree/ostree-gpg-verifier.c140
1 files changed, 51 insertions, 89 deletions
diff --git a/src/libostree/ostree-gpg-verifier.c b/src/libostree/ostree-gpg-verifier.c
index 5f4189fc..3c6c9152 100644
--- a/src/libostree/ostree-gpg-verifier.c
+++ b/src/libostree/ostree-gpg-verifier.c
@@ -24,6 +24,7 @@
#include "config.h"
#include "ostree-gpg-verifier.h"
+#include "ostree-gpg-verify-result-private.h"
#include "otutil.h"
#include <stdlib.h>
@@ -160,40 +161,6 @@ out:
return ret;
}
-static void
-gpg_error_to_gio_error (gpgme_error_t gpg_error,
- GError **error)
-{
- GIOErrorEnum errcode;
-
- /* XXX This list is incomplete. Add cases as needed. */
-
- switch (gpg_error)
- {
- /* special case - shouldn't be here */
- case GPG_ERR_NO_ERROR:
- g_return_if_reached ();
-
- /* special case - abort on out-of-memory */
- case GPG_ERR_ENOMEM:
- g_error ("%s: %s",
- gpgme_strsource (gpg_error),
- gpgme_strerror (gpg_error));
-
- case GPG_ERR_INV_VALUE:
- errcode = G_IO_ERROR_INVALID_ARGUMENT;
- break;
-
- default:
- errcode = G_IO_ERROR_FAILED;
- break;
- }
-
- g_set_error (error, G_IO_ERROR, errcode, "%s: %s",
- gpgme_strsource (gpg_error),
- gpgme_strerror (gpg_error));
-}
-
static gboolean
override_gpgme_home_dir (gpgme_ctx_t gpg_ctx,
const char *home_dir,
@@ -220,7 +187,7 @@ override_gpgme_home_dir (gpgme_ctx_t gpg_ctx,
home_dir);
if (gpg_error != GPG_ERR_NO_ERROR)
{
- gpg_error_to_gio_error (gpg_error, error);
+ _ostree_gpg_error_to_gio_error (gpg_error, error);
goto out;
}
@@ -241,11 +208,23 @@ out:
return ret;
}
-gboolean
+static void
+verify_result_finalized_cb (gpointer data,
+ GObject *finalized_verify_result)
+{
+ g_autofree gchar *temp_dir = data; /* assume ownership */
+
+ /* XXX OstreeGpgVerifyResult could do this cleanup in its own
+ * finalize() method, but I didn't want this keyring hack
+ * bleeding into multiple classes. */
+
+ (void) glnx_shutil_rm_rf_at (AT_FDCWD, temp_dir, NULL, NULL);
+}
+
+OstreeGpgVerifyResult *
_ostree_gpg_verifier_check_signature (OstreeGpgVerifier *self,
GBytes *signed_data,
GBytes *signatures,
- gboolean *out_had_valid_sig,
GCancellable *cancellable,
GError **error)
{
@@ -253,13 +232,11 @@ _ostree_gpg_verifier_check_signature (OstreeGpgVerifier *self,
gpgme_error_t gpg_error = NULL;
gpgme_data_t data_buffer = NULL;
gpgme_data_t signature_buffer = NULL;
- gpgme_verify_result_t verify_result;
- gpgme_signature_t signature_iter;
gs_unref_object GFile *pubring_file = NULL;
gs_free char *pubring_path = NULL;
gs_free char *temp_dir = NULL;
- gboolean had_valid_sig = FALSE;
- gboolean ret = FALSE;
+ 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
@@ -283,15 +260,12 @@ _ostree_gpg_verifier_check_signature (OstreeGpgVerifier *self,
if (!concatenate_keyrings (self, pubring_file, cancellable, error))
goto out;
- gpg_error = gpgme_new (&gpg_ctx);
- if (gpg_error != GPG_ERR_NO_ERROR)
- {
- gpg_error_to_gio_error (gpg_error, error);
- g_prefix_error (error, "Unable to create context: ");
- goto out;
- }
+ result = g_initable_new (OSTREE_TYPE_GPG_VERIFY_RESULT,
+ cancellable, error, NULL);
+ if (result == NULL)
+ goto out;
- if (!override_gpgme_home_dir (gpg_ctx, temp_dir, error))
+ if (!override_gpgme_home_dir (result->context, temp_dir, error))
goto out;
/* Both the signed data and signature GBytes instances will outlive the
@@ -304,7 +278,7 @@ _ostree_gpg_verifier_check_signature (OstreeGpgVerifier *self,
0 /* do not copy */);
if (gpg_error != GPG_ERR_NO_ERROR)
{
- gpg_error_to_gio_error (gpg_error, error);
+ _ostree_gpg_error_to_gio_error (gpg_error, error);
g_prefix_error (error, "Unable to read signed data: ");
goto out;
}
@@ -315,60 +289,28 @@ _ostree_gpg_verifier_check_signature (OstreeGpgVerifier *self,
0 /* do not copy */);
if (gpg_error != GPG_ERR_NO_ERROR)
{
- gpg_error_to_gio_error (gpg_error, error);
+ _ostree_gpg_error_to_gio_error (gpg_error, error);
g_prefix_error (error, "Unable to read signature: ");
goto out;
}
- gpg_error = gpgme_op_verify (gpg_ctx, signature_buffer, data_buffer, NULL);
+ gpg_error = gpgme_op_verify (result->context, signature_buffer, data_buffer, NULL);
if (gpg_error != GPG_ERR_NO_ERROR)
{
- gpg_error_to_gio_error (gpg_error, error);
+ _ostree_gpg_error_to_gio_error (gpg_error, error);
g_prefix_error (error, "Unable to complete signature verification: ");
goto out;
}
/* Result data is owned by the context. */
- verify_result = gpgme_op_verify_result (gpg_ctx);
-
- /* XXX Needs improvement. We're throwing away a bunch of result data
- * here that could be used for more advanced signature operations.
- * Don't want to expose GPGME types in libostree but maybe we can
- * wrapper it in GLib types. */
-
- for (signature_iter = verify_result->signatures;
- signature_iter != NULL;
- signature_iter = signature_iter->next)
- {
- /* 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.
- */
- if ((signature_iter->summary & GPGME_SIGSUM_VALID) ||
- (signature_iter->summary & GPGME_SIGSUM_GREEN) ||
- (signature_iter->summary == 0 &&
- signature_iter->status == GPG_ERR_NO_ERROR))
- {
- had_valid_sig = TRUE;
- break;
- }
- }
+ result->details = gpgme_op_verify_result (result->context);
- if (out_had_valid_sig != NULL)
- *out_had_valid_sig = had_valid_sig;
+ gpgme_result_ref (result->details);
- ret = TRUE;
+ success = TRUE;
out:
- /* Try to clean up the temporary directory. */
- if (temp_dir != NULL)
- (void) glnx_shutil_rm_rf_at (-1, temp_dir, NULL, NULL);
-
if (gpg_ctx != NULL)
gpgme_release (gpg_ctx);
if (data_buffer != NULL)
@@ -376,9 +318,29 @@ out:
if (signature_buffer != NULL)
gpgme_data_release (signature_buffer);
+ if (success)
+ {
+ /* Keep the temporary directory around for the life of the result
+ * object so its GPGME context remains valid. It may yet have to
+ * extract user details from signing keys and will need to access
+ * the fabricated pubring.gpg keyring. */
+ g_object_weak_ref (G_OBJECT (result),
+ verify_result_finalized_cb,
+ g_strdup (temp_dir));
+ }
+ else
+ {
+ /* Destroy the result object on error. */
+ g_clear_object (&result);
+
+ /* Try to clean up the temporary directory. */
+ if (temp_dir != NULL)
+ (void) glnx_shutil_rm_rf_at (AT_FDCWD, temp_dir, NULL, NULL);
+ }
+
g_prefix_error (error, "GPG: ");
- return ret;
+ return result;
}
gboolean