From 622054fc6d73c12c294f2172765c31cd90c7c361 Mon Sep 17 00:00:00 2001 From: Jabber Developer Date: Mon, 29 Jun 2026 14:08:40 +0000 Subject: [PATCH] fix(pgp): prevent plaintext fallback in PGP/OX encryption Block all three code paths in message_send_chat_pgp that previously fell back to sending unencrypted messages: encryption failure, missing PGP key, and missing LibGPGME. Each path now shows a specific error in the chat window and returns NULL so the caller skips logging and display. Also replace the generic cons_show for OX signcrypt failure with a win_println on the current window, ensuring the user sees the error even when the chat window is not focused. Improve p_gpg_encrypt error reporting by adding a gchar** err out-parameter. Each failure path now sets a descriptive message (e.g. missing recipient key, missing sender key, GPGME context failure, encryption failure) so the caller can display the exact reason to the user. Fix a memory leak: gpgme_key_unref(receiver_key) was missing from the sender_key failure path. --- src/pgp/gpg.c | 11 +++++++++-- src/pgp/gpg.h | 2 +- src/xmpp/message.c | 37 ++++++++++++++++++++++++++++--------- 3 files changed, 38 insertions(+), 12 deletions(-) diff --git a/src/pgp/gpg.c b/src/pgp/gpg.c index ee9d11f6..dd4e799b 100644 --- a/src/pgp/gpg.c +++ b/src/pgp/gpg.c @@ -519,13 +519,15 @@ p_gpg_sign(const gchar* const str, const gchar* const fp) } gchar* -p_gpg_encrypt(const gchar* const barejid, const gchar* const message, const gchar* const fp) +p_gpg_encrypt(const gchar* const barejid, const gchar* const message, const gchar* const fp, gchar** err) { ProfPGPPubKeyId* pubkeyid = g_hash_table_lookup(pubkeys, barejid); if (!pubkeyid) { + *err = g_strdup("No PGP key found for recipient"); return NULL; } if (!pubkeyid->id) { + *err = g_strdup("No key ID found for recipient"); return NULL; } @@ -538,6 +540,7 @@ p_gpg_encrypt(const gchar* const barejid, const gchar* const message, const gcha gpgme_ctx_t ctx; gpgme_error_t error = gpgme_new(&ctx); if (error) { + *err = g_strdup_printf("Failed to create GPGME context: %s %s", gpgme_strsource(error), gpgme_strerror(error)); log_error("GPG: Failed to create gpgme context. %s %s", gpgme_strsource(error), gpgme_strerror(error)); return NULL; } @@ -545,6 +548,7 @@ p_gpg_encrypt(const gchar* const barejid, const gchar* const message, const gcha gpgme_key_t receiver_key; error = gpgme_get_key(ctx, pubkeyid->id, &receiver_key, 0); if (error || receiver_key == NULL) { + *err = g_strdup_printf("Failed to get receiver key '%s': %s %s", pubkeyid->id, gpgme_strsource(error), gpgme_strerror(error)); log_error("GPG: Failed to get receiver_key. %s %s", gpgme_strsource(error), gpgme_strerror(error)); gpgme_release(ctx); return NULL; @@ -554,8 +558,10 @@ p_gpg_encrypt(const gchar* const barejid, const gchar* const message, const gcha gpgme_key_t sender_key = NULL; error = gpgme_get_key(ctx, fp, &sender_key, 0); if (error || sender_key == NULL) { + *err = g_strdup_printf("Failed to get sender key '%s': %s %s", fp, gpgme_strsource(error), gpgme_strerror(error)); log_error("GPG: Failed to get sender_key. %s %s", gpgme_strsource(error), gpgme_strerror(error)); gpgme_release(ctx); + gpgme_key_unref(receiver_key); return NULL; } keys[1] = sender_key; @@ -574,7 +580,8 @@ p_gpg_encrypt(const gchar* const barejid, const gchar* const message, const gcha gpgme_key_unref(sender_key); if (error) { - log_error("GPG: Failed to encrypt message. %s %s", gpgme_strsource(error), gpgme_strerror(error)); + *err = g_strdup_printf("Encryption failed: (%s) %s", gpgme_strsource(error), gpgme_strerror(error)); + log_error("GPG: Failed to encrypt message. (%s) %s", gpgme_strsource(error), gpgme_strerror(error)); return NULL; } diff --git a/src/pgp/gpg.h b/src/pgp/gpg.h index 0ad19607..179fa015 100644 --- a/src/pgp/gpg.h +++ b/src/pgp/gpg.h @@ -42,7 +42,7 @@ gboolean p_gpg_available(const gchar* const barejid); const gchar* p_gpg_libver(void); gchar* p_gpg_sign(const gchar* const str, const gchar* const fp); void p_gpg_verify(const gchar* const barejid, const gchar* const sign); -gchar* p_gpg_encrypt(const gchar* const barejid, const gchar* const message, const gchar* const fp); +gchar* p_gpg_encrypt(const gchar* const barejid, const gchar* const message, const gchar* const fp, gchar** err); gchar* p_gpg_decrypt(const gchar* const cipher); void p_gpg_free_decrypted(gchar* decrypted); gchar* p_gpg_autocomplete_key(const gchar* const search_str, gboolean previous, void* context); diff --git a/src/xmpp/message.c b/src/xmpp/message.c index c6040bf1..2de5ea4e 100644 --- a/src/xmpp/message.c +++ b/src/xmpp/message.c @@ -467,12 +467,15 @@ message_send_chat_pgp(const char* const barejid, const char* const msg, gboolean auto_char char* jid = chat_session_get_jid(barejid); char* id = connection_create_stanza_id(); + ProfWin* current = wins_get_current(); + xmpp_stanza_t* message = NULL; #ifdef HAVE_LIBGPGME ProfAccount* account = accounts_get_account(session_get_account_name()); if (account->pgp_keyid) { auto_jid Jid* jidp = jid_create(jid); - auto_gchar gchar* encrypted = p_gpg_encrypt(jidp->barejid, msg, account->pgp_keyid); + auto_gchar gchar* err = NULL; + auto_gchar gchar* encrypted = p_gpg_encrypt(jidp->barejid, msg, account->pgp_keyid, &err); if (encrypted) { message = xmpp_message_new(ctx, STANZA_TYPE_CHAT, jid, id); xmpp_message_set_body(message, "This message is encrypted (XEP-0027)."); @@ -486,18 +489,31 @@ message_send_chat_pgp(const char* const barejid, const char* const msg, gboolean xmpp_stanza_add_child(message, x); xmpp_stanza_release(x); } else { - message = xmpp_message_new(ctx, STANZA_TYPE_CHAT, jid, id); - xmpp_message_set_body(message, msg); + if (current) { + win_println(current, THEME_ERROR, "-", "Unable to encrypt message for %s: %s.", jid, err); + } + log_error("Message not encrypted for %s: %s.", jid, err); + account_free(account); + free(id); + return NULL; } } else { - message = xmpp_message_new(ctx, STANZA_TYPE_CHAT, jid, id); - xmpp_message_set_body(message, msg); + if (current) { + win_println(current, THEME_ERROR, "-", "No PGP key configured for this account."); + } + log_error("No PGP key configured, message not sent."); + account_free(account); + free(id); + return NULL; } account_free(account); #else - // ? - message = xmpp_message_new(ctx, STANZA_TYPE_CHAT, jid, id); - xmpp_message_set_body(message, msg); + if (current) { + win_println(current, THEME_ERROR, "-", "LibGPGME not available, message not sent."); + } + log_error("LibGPGME not available, message not sent."); + free(id); + return NULL; #endif if (state) { @@ -546,7 +562,10 @@ message_send_chat_ox(const char* const barejid, const char* const msg, gboolean xmpp_stanza_to_text(signcrypt, &c, &s); char* signcrypt_e = p_ox_gpg_signcrypt(account->jid, barejid, c); if (signcrypt_e == NULL) { - cons_show("Unable to send OX message. Check log file and profanity-ox-setup man page for details."); + ProfWin* current = wins_get_current(); + if (current) { + win_println(current, THEME_ERROR, "-", "Unable to send OX message. Check log file and profanity-ox-setup man page for details."); + } log_error("Message not signcrypted."); return NULL; }