fix(pgp): prevent plaintext fallback in PGP/OX encryption #143
Reference in New Issue
Block a user
No description provided.
Delete Branch "fix/unencrypted-send"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Introduced change
Block all code paths in
message_send_chat_pgpthat previously fell back to sending unencrypted plaintext when encryption failed, no key was configured, or LibGPGME was unavailable. Each path now displays a specific error in the chat window and returnsNULLso the caller skips logging and display.Capabilities
p_gpg_encryptnow returns a detailed error string viagchar** err— missing recipient key, missing sender key, GPGME context failure, or encryption failurewin_printlnon the current chat window instead ofcons_show, so users see them even when the chat is not focusedwin_printlnon the current windowReasoning behind the change
Previously, if
p_gpg_encryptreturnedNULL(e.g. recipient had no key, or GPGME operation failed), the function silently constructed a message with the plaintext body and sent it over the wire. This defeats the purpose of PGP encryption entirely and could leak sensitive messages.The same issue existed for the other two branches: when no PGP key was configured for the account, or when LibGPGME was not compiled in, the function still sent the message as plaintext.
Users need to know why encryption failed so they can fix the root cause — add a recipient key, configure their own key, or check their GPG setup.
Implementation details
p_gpg_encryptAPI change (src/pgp/gpg.c,src/pgp/gpg.h)Added
gchar** errout-parameter. Each failure path sets a descriptive message:"No PGP key found for recipient""No key ID found for recipient""Failed to create GPGME context: <source> <strerror>""Failed to get receiver key '<id>': <source> <strerror>""Failed to get sender key '<fp>': <source> <strerror>""Encryption failed: (<source>) <strerror>"message_send_chat_pgp(src/xmpp/message.c)Three error paths replaced plaintext fallback with
win_println+return NULL:"Unable to encrypt message for <jid>: <err>""No PGP key configured for this account.""LibGPGME not available, message not sent."All paths free
id(allocated viaconnection_create_stanza_id()) before returning to avoid a memory leak.message_send_chat_ox(src/xmpp/message.c)Replaced
cons_showwithwin_printlnon the current window for OX signcrypt failure, consistent with the PGP changes.Memory leak fix
gpgme_key_unref(receiver_key)was missing from the sender_key failure path inp_gpg_encrypt.Testing
Resolves #142
Maybe worth a look before merge
p_gpg_encryptcan returnNULLwithout setting*err—src/pgp/gpg.c, theelseofif (cipher_str). Ifgpgme_data_release_and_get_mem()ever returnsNULLafter a successful encrypt, the function returnsNULLbut never assigns*err, and the caller then doeswin_println(..., "%s", err)witherr == NULL(prints(null)). Not a crash or a plaintext leak — just a confusing message — but it seems to be the one path that breaks this PR's own "NULL ⇒ err set" contract. Perhaps something like*err = g_strdup("Encryption produced no ciphertext");?Minor — and possibly pre-existing
cipherlooks leaked on the encrypt-error branch —src/pgp/gpg.c, theif (error)right aftergpgme_op_encrypt.plain/ctx/keys are released, butcipherdoesn't appear to be. Pre-existing — this PR only added the*err = …line into that branch — so not introduced here, just adjacent. Agpgme_data_release(cipher);before the return would cover it, if it's worth sweeping up.src/xmpp/message.c, thesigncrypt_e == NULLearly return.id,account,message,openpgp,signcryptand thecbuffer don't look freed there. Also pre-existing (the PR only swappedcons_show→win_printlnon this path), but since failing-closed is now a normal outcome it might be worth tidying.Nits — probably fine as-is
*erris written on every error path with no NULL-guard and isn't initialized at entry; the siblingp_gpg_valid_key()guards each write withif (err_str). Not reachable today (the only caller passes a real pointer), so this is just a consistency thought.if (current), so ifwins_get_current()were everNULLthe user would get only a log line. Almost certainly neverNULLin an interactive send, so likely a non-issue.Things that checked out
message_send_groupchat()doesn't appear to do per-message PGP/OX at all here, so there's likely nothing to fix there.account->jidderef in the OX path looks byte-identical to before this PR, so it seems out of scope.