about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--src/command/command.c1
-rw-r--r--src/command/commands.c16
-rw-r--r--src/pgp/gpg.c76
-rw-r--r--src/pgp/gpg.h3
-rw-r--r--src/profanity.c3
-rw-r--r--src/xmpp/presence.c35
-rw-r--r--tests/pgp/stub_gpg.c10
7 files changed, 130 insertions, 14 deletions
diff --git a/src/command/command.c b/src/command/command.c
index 8e709601..994c1155 100644
--- a/src/command/command.c
+++ b/src/command/command.c
@@ -1579,6 +1579,7 @@ cmd_init(void)
 
     pgp_ac = autocomplete_new();
     autocomplete_add(pgp_ac, "keys");
+    autocomplete_add(pgp_ac, "fps");
     autocomplete_add(pgp_ac, "libver");
 }
 
diff --git a/src/command/commands.c b/src/command/commands.c
index 0dc19e41..5b73954b 100644
--- a/src/command/commands.c
+++ b/src/command/commands.c
@@ -4093,6 +4093,22 @@ cmd_pgp(gchar **args, struct cmd_help_t help)
             cons_show("No keys found");
         }
         g_slist_free_full(keys, (GDestroyNotify)p_gpg_free_key);
+    } else if (g_strcmp0(args[0], "fps") == 0) {
+        GHashTable *fingerprints = p_gpg_fingerprints();
+        GList *jids = g_hash_table_get_keys(fingerprints);
+        if (jids) {
+            cons_show("Received PGP fingerprints:");
+            GList *curr = jids;
+            while (curr) {
+                char *jid = curr->data;
+                char *fingerprint = g_hash_table_lookup(fingerprints, jid);
+                cons_show("  %s: %s", jid, fingerprint);
+                curr = g_list_next(curr);
+            }
+        } else {
+            cons_show("No PGP fingerprints received.");
+        }
+        g_list_free(jids);
     } else if (g_strcmp0(args[0], "libver") == 0) {
         const char *libver = p_gpg_libver();
         if (libver) {
diff --git a/src/pgp/gpg.c b/src/pgp/gpg.c
index 1a9f81c7..69723c01 100644
--- a/src/pgp/gpg.c
+++ b/src/pgp/gpg.c
@@ -42,11 +42,14 @@
 #include "pgp/gpg.h"
 #include "log.h"
 
+#define PGP_HEADER "-----BEGIN PGP SIGNATURE-----"
 #define PGP_FOOTER "-----END PGP SIGNATURE-----"
 
 static const char *libversion;
+static GHashTable *fingerprints;
 
 static char* _remove_header_footer(char *str);
+static char* _add_header_footer(const char * const str);
 
 void
 p_gpg_init(void)
@@ -54,6 +57,15 @@ p_gpg_init(void)
     libversion = gpgme_check_version(NULL);
     log_debug("GPG: Found gpgme version: %s", libversion);
     gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL));
+
+    // TODO add close function to clean up
+    fingerprints = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
+}
+
+void
+p_gpg_close(void)
+{
+    g_hash_table_destroy(fingerprints);
 }
 
 GSList *
@@ -96,6 +108,12 @@ p_gpg_list_keys(void)
     return result;
 }
 
+GHashTable *
+p_gpg_fingerprints(void)
+{
+    return fingerprints;
+}
+
 const char*
 p_gpg_libver(void)
 {
@@ -113,6 +131,45 @@ p_gpg_free_key(ProfPGPKey *key)
     }
 }
 
+void
+p_gpg_verify(const char * const barejid, const char *const sign)
+{
+    if (!sign) {
+        return;
+    }
+
+    gpgme_ctx_t ctx;
+    gpgme_error_t error = gpgme_new(&ctx);
+    if (error) {
+        log_error("GPG: Failed to create gpgme context. %s %s", gpgme_strsource(error), gpgme_strerror(error));
+        return;
+    }
+
+    gpgme_data_t sign_data;
+    gpgme_data_t plain_data;
+    char *sign_with_header_footer = _add_header_footer(sign);
+    gpgme_data_new_from_mem(&sign_data, sign_with_header_footer, strlen(sign_with_header_footer), 1);
+    gpgme_data_new(&plain_data);
+
+    error = gpgme_op_verify(ctx, sign_data, NULL, plain_data);
+    if (error) {
+        log_error("GPG: Failed to verify. %s %s", gpgme_strsource(error), gpgme_strerror(error));
+        gpgme_release(ctx);
+        return;
+    }
+
+    gpgme_verify_result_t result = gpgme_op_verify_result(ctx);
+    if (result) {
+        if (result->signatures) {
+            log_debug("Fingerprint found for %s: %s ", barejid, result->signatures->fpr);
+            g_hash_table_replace(fingerprints, strdup(barejid), strdup(result->signatures->fpr));
+        }
+    }
+
+    gpgme_data_release(sign_data);
+    gpgme_data_release(plain_data);
+}
+
 char*
 p_gpg_sign_str(const char * const str, const char * const fp)
 {
@@ -196,4 +253,21 @@ _remove_header_footer(char *str)
     stripped[strlen(pointer)-strlen(PGP_FOOTER)] = '\0';
 
     return stripped;
-}
\ No newline at end of file
+}
+
+static char*
+_add_header_footer(const char * const str)
+{
+    GString *result_str = g_string_new("");
+
+    g_string_append(result_str, PGP_HEADER);
+    g_string_append(result_str, "\n\n");
+    g_string_append(result_str, str);
+    g_string_append(result_str, "\n");
+    g_string_append(result_str, PGP_FOOTER);
+
+    char *result = result_str->str;
+    g_string_free(result_str, FALSE);
+
+    return result;
+}
diff --git a/src/pgp/gpg.h b/src/pgp/gpg.h
index f017f14b..7c058024 100644
--- a/src/pgp/gpg.h
+++ b/src/pgp/gpg.h
@@ -42,9 +42,12 @@ typedef struct pgp_key_t {
 } ProfPGPKey;
 
 void p_gpg_init(void);
+void p_gpg_close(void);
 GSList* p_gpg_list_keys(void);
+GHashTable* p_gpg_fingerprints(void);
 const char* p_gpg_libver(void);
 void p_gpg_free_key(ProfPGPKey *key);
 char* p_gpg_sign_str(const char * const str, const char * const fp);
+void p_gpg_verify(const char * const barejid, const char *const sign);
 
 #endif
diff --git a/src/profanity.c b/src/profanity.c
index e54aa7a2..47063ae8 100644
--- a/src/profanity.c
+++ b/src/profanity.c
@@ -271,6 +271,9 @@ _shutdown(void)
 #ifdef HAVE_LIBOTR
     otr_shutdown();
 #endif
+#ifdef HAVE_LIBGPGME
+    p_gpg_close();
+#endif
     chat_log_close();
     prefs_close();
     theme_close();
diff --git a/src/xmpp/presence.c b/src/xmpp/presence.c
index a8418673..241932e6 100644
--- a/src/xmpp/presence.c
+++ b/src/xmpp/presence.c
@@ -232,20 +232,21 @@ presence_update(const resource_presence_t presence_type, const char * const msg,
     char *account_name = jabber_get_account_name();
     ProfAccount *account = accounts_get_account(account_name);
     if (account->pgp_keyid) {
-        xmpp_stanza_t *x = xmpp_stanza_new(ctx);
-        xmpp_stanza_set_name(x, STANZA_NAME_X);
-        xmpp_stanza_set_ns(x, STANZA_NS_SIGNED);
-        xmpp_stanza_t *signed_text = xmpp_stanza_new(ctx);
-
         char *signed_status = p_gpg_sign_str(msg, account->pgp_keyid);
 
-        xmpp_stanza_set_text(signed_text, signed_status);
-        xmpp_stanza_add_child(x, signed_text);
-        xmpp_stanza_release(signed_text);
-        xmpp_stanza_add_child(presence, x);
-        xmpp_stanza_release(x);
-
-        free(signed_status);
+        if (signed_status) {
+            xmpp_stanza_t *x = xmpp_stanza_new(ctx);
+            xmpp_stanza_set_name(x, STANZA_NAME_X);
+            xmpp_stanza_set_ns(x, STANZA_NS_SIGNED);
+            xmpp_stanza_t *signed_text = xmpp_stanza_new(ctx);
+            xmpp_stanza_set_text(signed_text, signed_status);
+            xmpp_stanza_add_child(x, signed_text);
+            xmpp_stanza_release(signed_text);
+            xmpp_stanza_add_child(presence, x);
+            xmpp_stanza_release(x);
+
+            free(signed_status);
+        }
     }
 #endif
 
@@ -606,6 +607,16 @@ _available_handler(xmpp_conn_t * const conn,
         log_debug("Presence available handler fired for: %s", jid);
     }
 
+#ifdef HAVE_LIBGPGME
+    xmpp_stanza_t *x = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_SIGNED);
+    if (x) {
+        char *sign = xmpp_stanza_get_text(x);
+        if (sign) {
+            p_gpg_verify(xmpp_presence->jid->barejid, sign);
+        }
+    }
+#endif
+
     const char *my_jid_str = xmpp_conn_get_jid(conn);
     Jid *my_jid = jid_create(my_jid_str);
 
diff --git a/tests/pgp/stub_gpg.c b/tests/pgp/stub_gpg.c
index 29a1d828..14cdfe96 100644
--- a/tests/pgp/stub_gpg.c
+++ b/tests/pgp/stub_gpg.c
@@ -3,13 +3,21 @@
 #include "pgp/gpg.h"
 
 void p_gpg_init(void) {}
+void p_gpg_close(void) {}
 
 GSList* p_gpg_list_keys(void)
 {
     return NULL;
 }
 
-const char* p_gpg_libver(void) {
+GHashTable*
+p_gpg_fingerprints(void)
+{
+    return NULL;
+}
+
+const char* p_gpg_libver(void)
+{
     return NULL;
 }