[gmime] Added gmime-gpgme-utils.[c,h]
- From: Jeffrey Stedfast <fejj src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gmime] Added gmime-gpgme-utils.[c,h]
- Date: Wed, 8 Mar 2017 13:34:46 +0000 (UTC)
commit de1b42a8104abe2b3e17c67c99ea196a0e6fd72b
Author: Jeffrey Stedfast <jestedfa microsoft com>
Date: Sun Feb 26 09:21:48 2017 -0500
Added gmime-gpgme-utils.[c,h]
gmime/gmime-gpgme-utils.c | 315 +++++++++++++++++++++++++++++++++++++++++++++
gmime/gmime-gpgme-utils.h | 52 ++++++++
2 files changed, 367 insertions(+), 0 deletions(-)
---
diff --git a/gmime/gmime-gpgme-utils.c b/gmime/gmime-gpgme-utils.c
new file mode 100644
index 0000000..a64354d
--- /dev/null
+++ b/gmime/gmime-gpgme-utils.c
@@ -0,0 +1,315 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* GMime
+ * Copyright (C) 2000-2014 Jeffrey Stedfast
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#include "gmime-gpgme-utils.h"
+#include "gmime-stream-pipe.h"
+#include "gmime-error.h"
+
+#ifdef ENABLE_CRYPTO
+
+#define _(x) x
+
+gpgme_error_t
+g_mime_gpgme_passphrase_callback (void *hook, const char *uid_hint, const char *passphrase_info, int
prev_was_bad, int fd)
+{
+ GMimeCryptoContext *context = (GMimeCryptoContext *) hook;
+ GMimeStream *stream;
+ gpgme_error_t error;
+ GError *err = NULL;
+ gboolean rv;
+
+ if (context->request_passwd) {
+ stream = g_mime_stream_pipe_new (fd);
+ rv = context->request_passwd (context, uid_hint, passphrase_info, prev_was_bad, stream, &err);
+ g_object_unref (stream);
+ } else {
+ return GPG_ERR_GENERAL;
+ }
+
+ if (!rv) {
+ error = GPG_ERR_CANCELED;
+ g_error_free (err);
+ } else {
+ error = GPG_ERR_NO_ERROR;
+ }
+
+ return error;
+}
+
+
+#define KEY_IS_OK(k) (!((k)->expired || (k)->revoked || \
+ (k)->disabled || (k)->invalid))
+
+gpgme_key_t
+g_mime_gpgme_get_key_by_name (gpgme_ctx_t ctx, const char *name, gboolean secret, GError **err)
+{
+ time_t now = time (NULL);
+ gpgme_key_t key = NULL;
+ gpgme_subkey_t subkey;
+ gboolean bad = FALSE;
+ gpgme_error_t error;
+ int errval = 0;
+
+ if ((error = gpgme_op_keylist_start (ctx, name, secret)) != GPG_ERR_NO_ERROR) {
+ if (secret)
+ g_set_error (err, GMIME_GPGME_ERROR, error, _("Could not list secret keys for \"%s\":
%s"), name, gpgme_strerror (error));
+ else
+ g_set_error (err, GMIME_GPGME_ERROR, error, _("Could not list keys for \"%s\": %s"),
name, gpgme_strerror (error));
+ return NULL;
+ }
+
+ while ((error = gpgme_op_keylist_next (ctx, &key)) == GPG_ERR_NO_ERROR) {
+ /* check if this key and the relevant subkey are usable */
+ if (KEY_IS_OK (key)) {
+ subkey = key->subkeys;
+
+ while (subkey && ((secret && !subkey->can_sign) ||
+ (!secret && !subkey->can_encrypt)))
+ subkey = subkey->next;
+
+ if (subkey && KEY_IS_OK (subkey) &&
+ (subkey->expires == 0 || subkey->expires > now))
+ break;
+
+ if (subkey->expired)
+ errval = GPG_ERR_KEY_EXPIRED;
+ else
+ errval = GPG_ERR_BAD_KEY;
+ } else {
+ if (key->expired)
+ errval = GPG_ERR_KEY_EXPIRED;
+ else
+ errval = GPG_ERR_BAD_KEY;
+ }
+
+ gpgme_key_unref (key);
+ bad = TRUE;
+ key = NULL;
+ }
+
+ gpgme_op_keylist_end (ctx);
+
+ if (error != GPG_ERR_NO_ERROR && error != GPG_ERR_EOF) {
+ if (secret)
+ g_set_error (err, GMIME_GPGME_ERROR, error, _("Could not list secret keys for \"%s\":
%s"), name, gpgme_strerror (error));
+ else
+ g_set_error (err, GMIME_GPGME_ERROR, error, _("Could not list keys for \"%s\": %s"),
name, gpgme_strerror (error));
+
+ return NULL;
+ }
+
+ if (!key) {
+ if (strchr (name, '@')) {
+ if (bad)
+ g_set_error (err, GMIME_GPGME_ERROR, errval,
+ _("A key for %s is present, but it is expired, disabled, revoked
or invalid"),
+ name);
+ else
+ g_set_error (err, GMIME_GPGME_ERROR, GPG_ERR_NOT_FOUND,
+ _("Could not find a key for %s"), name);
+ } else {
+ if (bad)
+ g_set_error (err, GMIME_GPGME_ERROR, errval,
+ _("A key with id %s is present, but it is expired, disabled,
revoked or invalid"),
+ name);
+ else
+ g_set_error (err, GMIME_GPGME_ERROR, GPG_ERR_NOT_FOUND,
+ _("Could not find a key with id %s"), name);
+ }
+
+ return NULL;
+ }
+
+ return key;
+}
+
+gboolean
+g_mime_gpgme_add_signer (gpgme_ctx_t ctx, const char *signer, GError **err)
+{
+ gpgme_key_t key = NULL;
+ gpgme_error_t error;
+
+ if (!(key = g_mime_gpgme_get_key_by_name (ctx, signer, TRUE, err)))
+ return FALSE;
+
+ error = gpgme_signers_add (ctx, key);
+ gpgme_key_unref (key);
+
+ if (error != GPG_ERR_NO_ERROR) {
+ g_set_error (err, GMIME_GPGME_ERROR, error, _("Failed to add signer \"%s\": %s"), signer,
gpgme_strerror (error));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static GMimeCertificateTrust
+get_trust (gpgme_validity_t trust)
+{
+ switch (trust) {
+ case GPGME_VALIDITY_UNKNOWN:
+ default:
+ return GMIME_CERTIFICATE_TRUST_NONE;
+ case GPGME_VALIDITY_UNDEFINED:
+ return GMIME_CERTIFICATE_TRUST_UNDEFINED;
+ case GPGME_VALIDITY_NEVER:
+ return GMIME_CERTIFICATE_TRUST_NEVER;
+ case GPGME_VALIDITY_MARGINAL:
+ return GMIME_CERTIFICATE_TRUST_MARGINAL;
+ case GPGME_VALIDITY_FULL:
+ return GMIME_CERTIFICATE_TRUST_FULLY;
+ case GPGME_VALIDITY_ULTIMATE:
+ return GMIME_CERTIFICATE_TRUST_ULTIMATE;
+ }
+}
+
+GMimeSignatureList *
+g_mime_gpgme_get_signatures (gpgme_ctx_t ctx, gboolean verify)
+{
+ GMimeSignatureList *signatures;
+ GMimeSignature *signature;
+ gpgme_verify_result_t result;
+ gpgme_signature_t sig;
+ gpgme_subkey_t subkey;
+ gpgme_user_id_t uid;
+ gpgme_key_t key;
+
+ /* get the signature verification results from GpgMe */
+ if (!(result = gpgme_op_verify_result (ctx)) || !result->signatures)
+ return verify ? g_mime_signature_list_new () : NULL;
+
+ /* create a new signature list to return */
+ signatures = g_mime_signature_list_new ();
+
+ sig = result->signatures;
+
+ while (sig != NULL) {
+ signature = g_mime_signature_new ();
+ g_mime_signature_list_add (signatures, signature);
+ g_mime_signature_set_status (signature, (GMimeSignatureStatus) sig->summary);
+ g_mime_signature_set_expires (signature, sig->exp_timestamp);
+ g_mime_signature_set_created (signature, sig->timestamp);
+
+ g_mime_certificate_set_pubkey_algo (signature->cert, (GMimePubKeyAlgo) sig->pubkey_algo);
+ g_mime_certificate_set_digest_algo (signature->cert, (GMimeDigestAlgo) sig->hash_algo);
+ g_mime_certificate_set_fingerprint (signature->cert, sig->fpr);
+
+ if (gpgme_get_key (ctx, sig->fpr, &key, 0) == GPG_ERR_NO_ERROR && key) {
+ /* get more signer info from their signing key */
+ g_mime_certificate_set_trust (signature->cert, get_trust (key->owner_trust));
+ g_mime_certificate_set_issuer_serial (signature->cert, key->issuer_serial);
+ g_mime_certificate_set_issuer_name (signature->cert, key->issuer_name);
+
+ /* get the keyid, name, and email address */
+ uid = key->uids;
+ while (uid) {
+ if (uid->name && *uid->name)
+ g_mime_certificate_set_name (signature->cert, uid->name);
+
+ if (uid->email && *uid->email)
+ g_mime_certificate_set_email (signature->cert, uid->email);
+
+ if (uid->uid && *uid->uid)
+ g_mime_certificate_set_key_id (signature->cert, uid->uid);
+
+ if (signature->cert->name && signature->cert->email && signature->cert->keyid)
+ break;
+
+ uid = uid->next;
+ }
+
+ /* get the subkey used for signing */
+ subkey = key->subkeys;
+ while (subkey && !subkey->can_sign)
+ subkey = subkey->next;
+
+ if (subkey) {
+ g_mime_certificate_set_created (signature->cert, subkey->timestamp);
+ g_mime_certificate_set_expires (signature->cert, subkey->expires);
+ }
+
+ gpgme_key_unref (key);
+ } else {
+ /* If we don't have the signer's public key, then we can't tell what
+ * the status is, so set it to ERROR if it hasn't already been
+ * designated as BAD. */
+ g_mime_certificate_set_trust (signature->cert, GMIME_CERTIFICATE_TRUST_UNDEFINED);
+ }
+
+ sig = sig->next;
+ }
+
+ return signatures;
+}
+
+void
+g_mime_gpgme_keylist_free (gpgme_key_t *keys)
+{
+ gpgme_key_t *key = keys;
+
+ while (*key != NULL) {
+ gpgme_key_unref (*key);
+ key++;
+ }
+
+ g_free (keys);
+}
+
+GMimeDecryptResult *
+g_mime_gpgme_get_decrypt_result (gpgme_ctx_t ctx)
+{
+ GMimeDecryptResult *result;
+ gpgme_decrypt_result_t res;
+ gpgme_recipient_t recipient;
+ GMimeCertificate *cert;
+
+ result = g_mime_decrypt_result_new ();
+ result->recipients = g_mime_certificate_list_new ();
+ result->signatures = g_mime_gpgme_get_signatures (ctx, FALSE);
+
+ // TODO: ciper, mdc
+
+ if (!(res = gpgme_op_decrypt_result (ctx)) || !res->recipients)
+ return result;
+
+ //if (res->session_key)
+ // result->session_key = g_strdup (res->session_key);
+
+ recipient = res->recipients;
+ while (recipient != NULL) {
+ cert = g_mime_certificate_new ();
+ g_mime_certificate_list_add (result->recipients, cert);
+
+ g_mime_certificate_set_pubkey_algo (cert, (GMimePubKeyAlgo) recipient->pubkey_algo);
+ g_mime_certificate_set_key_id (cert, recipient->keyid);
+
+ recipient = recipient->next;
+ }
+
+ return result;
+}
+
+#endif /* ENABLE_CRYPTO */
diff --git a/gmime/gmime-gpgme-utils.h b/gmime/gmime-gpgme-utils.h
new file mode 100644
index 0000000..82d92cf
--- /dev/null
+++ b/gmime/gmime-gpgme-utils.h
@@ -0,0 +1,52 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* GMime
+ * Copyright (C) 2000-2014 Jeffrey Stedfast
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+
+#ifndef __GMIME_GPGME_UTILS_H__
+#define __GMIME_GPGME_UTILS_H__
+
+#ifdef ENABLE_CRYPTO
+
+#include <glib.h>
+#include <gpgme.h>
+#include <gmime/gmime-crypto-context.h>
+
+G_BEGIN_DECLS
+
+G_GNUC_INTERNAL gpgme_error_t g_mime_gpgme_passphrase_callback (void *hook, const char *uid_hint,
+ const char *passphrase_info,
+ int prev_was_bad, int fd);
+
+G_GNUC_INTERNAL gpgme_key_t g_mime_gpgme_get_key_by_name (gpgme_ctx_t ctx, const char *name,
+ gboolean secret, GError **err);
+
+G_GNUC_INTERNAL gboolean g_mime_gpgme_add_signer (gpgme_ctx_t ctx, const char *signer, GError **err);
+
+G_GNUC_INTERNAL GMimeSignatureList *g_mime_gpgme_get_signatures (gpgme_ctx_t ctx, gboolean verify);
+
+G_GNUC_INTERNAL void g_mime_gpgme_keylist_free (gpgme_key_t *keys);
+
+G_GNUC_INTERNAL GMimeDecryptResult *g_mime_gpgme_get_decrypt_result (gpgme_ctx_t ctx);
+
+G_END_DECLS
+
+#endif /* ENABLE_CRYPTO */
+
+#endif /* __GMIME_GPGME_UTILS_H__ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]