From eb5cb7b2f8a07c43a5cbd62e60b982493d17882b Mon Sep 17 00:00:00 2001 From: James Booth Date: Tue, 24 Mar 2015 23:34:24 +0000 Subject: [PATCH] Send encrypted messages --- src/pgp/gpg.c | 92 +++++++++++++++++++++++++++++++++++++-------- src/pgp/gpg.h | 3 +- src/xmpp/message.c | 30 ++++++++++++++- src/xmpp/presence.c | 2 +- src/xmpp/stanza.h | 1 + 5 files changed, 109 insertions(+), 19 deletions(-) diff --git a/src/pgp/gpg.c b/src/pgp/gpg.c index 69723c01..68fe6526 100644 --- a/src/pgp/gpg.c +++ b/src/pgp/gpg.c @@ -42,13 +42,14 @@ #include "pgp/gpg.h" #include "log.h" -#define PGP_HEADER "-----BEGIN PGP SIGNATURE-----" -#define PGP_FOOTER "-----END PGP SIGNATURE-----" +#define PGP_SIGNATURE_HEADER "-----BEGIN PGP SIGNATURE-----" +#define PGP_SIGNATURE_FOOTER "-----END PGP SIGNATURE-----" +#define PGP_MESSAGE_FOOTER "-----END PGP MESSAGE-----" static const char *libversion; static GHashTable *fingerprints; -static char* _remove_header_footer(char *str); +static char* _remove_header_footer(char *str, const char * const footer); static char* _add_header_footer(const char * const str); void @@ -171,7 +172,7 @@ p_gpg_verify(const char * const barejid, const char *const sign) } char* -p_gpg_sign_str(const char * const str, const char * const fp) +p_gpg_sign(const char * const str, const char * const fp) { gpgme_ctx_t ctx; gpgme_error_t error = gpgme_new(&ctx); @@ -222,7 +223,7 @@ p_gpg_sign_str(const char * const str, const char * const fp) char *signed_str = gpgme_data_release_and_get_mem(signed_data, &len); if (signed_str != NULL) { signed_str[len] = 0; - result = _remove_header_footer(signed_str); + result = _remove_header_footer(signed_str, PGP_SIGNATURE_FOOTER); } gpgme_free(signed_str); gpgme_release(ctx); @@ -231,26 +232,85 @@ p_gpg_sign_str(const char * const str, const char * const fp) return result; } -static char* -_remove_header_footer(char *str) +char * +p_gpg_encrypt(const char * const barejid, const char * const message) { - char *pointer = str; + char *fp = g_hash_table_lookup(fingerprints, barejid); + if (!fp) { + return NULL; + } + + gpgme_key_t keys[2]; + + keys[0] = NULL; + keys[1] = NULL; + + 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 NULL; + } + + gpgme_key_t key; + error = gpgme_get_key(ctx, fp, &key, 0); + if (error || key == NULL) { + log_error("GPG: Failed to get key. %s %s", gpgme_strsource(error), gpgme_strerror(error)); + gpgme_release(ctx); + return NULL; + } + + keys[0] = key; + + gpgme_data_t plain; + gpgme_data_t cipher; + gpgme_data_new_from_mem(&plain, message, strlen(message), 1); + gpgme_data_new(&cipher); + + gpgme_set_armor(ctx, 1); + error = gpgme_op_encrypt(ctx, keys, GPGME_ENCRYPT_ALWAYS_TRUST, plain, cipher); + if (error) { + log_error("GPG: Failed to encrypt message. %s %s", gpgme_strsource(error), gpgme_strerror(error)); + gpgme_release(ctx); + return NULL; + } + gpgme_data_release(plain); + + char *cipher_str = NULL; + char *result = NULL; + size_t len; + cipher_str = gpgme_data_release_and_get_mem(cipher, &len); + if (cipher_str) { + result = _remove_header_footer(cipher_str, PGP_MESSAGE_FOOTER); + } + + gpgme_free(cipher_str); + gpgme_release(ctx); + + return result; +} + +static char* +_remove_header_footer(char *str, const char * const footer) +{ + int pos = 0; int newlines = 0; + while (newlines < 3) { - if (pointer[0] == '\n') { + if (str[pos] == '\n') { newlines++; } - pointer++; + pos++; - if (strlen(pointer) == 0) { + if (str[pos] == '\0') { return NULL; } } - char *stripped = malloc(strlen(pointer)+1-strlen(PGP_FOOTER)); - strncpy(stripped,pointer,strlen(pointer)-strlen(PGP_FOOTER)); - stripped[strlen(pointer)-strlen(PGP_FOOTER)] = '\0'; + char *stripped = strdup(&str[pos]); + char *footer_start = g_strrstr(stripped, footer); + footer_start[0] = '\0'; return stripped; } @@ -260,11 +320,11 @@ _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, PGP_SIGNATURE_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); + g_string_append(result_str, PGP_SIGNATURE_FOOTER); char *result = result_str->str; g_string_free(result_str, FALSE); diff --git a/src/pgp/gpg.h b/src/pgp/gpg.h index 7c058024..bd60f439 100644 --- a/src/pgp/gpg.h +++ b/src/pgp/gpg.h @@ -47,7 +47,8 @@ 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); +char* p_gpg_sign(const char * const str, const char * const fp); void p_gpg_verify(const char * const barejid, const char *const sign); +char* p_gpg_encrypt(const char * const barejid, const char * const message); #endif diff --git a/src/xmpp/message.c b/src/xmpp/message.c index e6927f76..57e434c5 100644 --- a/src/xmpp/message.c +++ b/src/xmpp/message.c @@ -49,6 +49,7 @@ #include "roster_list.h" #include "xmpp/stanza.h" #include "xmpp/xmpp.h" +#include "pgp/gpg.h" #define HANDLE(ns, type, func) xmpp_handler_add(conn, func, ns, STANZA_NAME_MESSAGE, type, ctx) @@ -104,7 +105,34 @@ message_send_chat(const char * const barejid, const char * const msg) } char *id = create_unique_id("msg"); - xmpp_stanza_t *message = stanza_create_message(ctx, id, jid, STANZA_TYPE_CHAT, msg); + xmpp_stanza_t *message = NULL; + +#ifdef HAVE_LIBGPGME + char *account_name = jabber_get_account_name(); + ProfAccount *account = accounts_get_account(account_name); + if (account->pgp_keyid) { + Jid *jidp = jid_create(jid); + char *encrypted = p_gpg_encrypt(jidp->barejid, msg); + if (encrypted) { + message = stanza_create_message(ctx, id, jid, STANZA_TYPE_CHAT, "This message is encrypted."); + xmpp_stanza_t *x = xmpp_stanza_new(ctx); + xmpp_stanza_set_name(x, STANZA_NAME_X); + xmpp_stanza_set_ns(x, STANZA_NS_ENCRYPTED); + xmpp_stanza_t *enc_st = xmpp_stanza_new(ctx); + xmpp_stanza_set_text(enc_st, encrypted); + xmpp_stanza_add_child(x, enc_st); + xmpp_stanza_release(enc_st); + xmpp_stanza_add_child(message, x); + xmpp_stanza_release(x); + free(encrypted); + } else { + message = stanza_create_message(ctx, id, jid, STANZA_TYPE_CHAT, msg); + } + } +#else + message = stanza_create_message(ctx, id, jid, STANZA_TYPE_CHAT, msg); +#endif + free(jid); if (state) { diff --git a/src/xmpp/presence.c b/src/xmpp/presence.c index 241932e6..07ac05dd 100644 --- a/src/xmpp/presence.c +++ b/src/xmpp/presence.c @@ -232,7 +232,7 @@ 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) { - char *signed_status = p_gpg_sign_str(msg, account->pgp_keyid); + char *signed_status = p_gpg_sign(msg, account->pgp_keyid); if (signed_status) { xmpp_stanza_t *x = xmpp_stanza_new(ctx); diff --git a/src/xmpp/stanza.h b/src/xmpp/stanza.h index 1460642d..6bd01ab4 100644 --- a/src/xmpp/stanza.h +++ b/src/xmpp/stanza.h @@ -160,6 +160,7 @@ #define STANZA_NS_FORWARD "urn:xmpp:forward:0" #define STANZA_NS_RECEIPTS "urn:xmpp:receipts" #define STANZA_NS_SIGNED "jabber:x:signed" +#define STANZA_NS_ENCRYPTED "jabber:x:encrypted" #define STANZA_DATAFORM_SOFTWARE "urn:xmpp:dataforms:softwareinfo"