Reported by: Daniel Kahn Gillmor <dkg <at> fifthhorseman.net>
Date: Fri, 16 May 2025 03:57:02 UTC
Severity: normal
Found in version 30.1
To reply to this bug, email your comments to 78448 AT debbugs.gnu.org.
Toggle the display of automated, internal messages from the tracker.
View this report as an mbox folder, status mbox, maintainer mbox
bug-gnu-emacs <at> gnu.org, bugs <at> gnus.org:bug#78448; Package emacs,gnus.
(Fri, 16 May 2025 03:57:03 GMT) Full text and rfc822 format available.Daniel Kahn Gillmor <dkg <at> fifthhorseman.net>:bug-gnu-emacs <at> gnu.org, bugs <at> gnus.org.
(Fri, 16 May 2025 03:57:03 GMT) Full text and rfc822 format available.Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):
From: Daniel Kahn Gillmor <dkg <at> fifthhorseman.net> To: bug-gnu-emacs <at> gnu.org, bugs <at> gnus.org Subject: 30.1; mml: Produce Unobtrusive Signatures Date: Thu, 15 May 2025 23:56:25 -0400
[Message part 1 (text/plain, inline)]
Package: emacs,gnus
Version: 30.1
I'm running emacs 30.1 on debian. When sending cleartext mail, i want
to be able to produce an "Unobtrusive Signature" using OpenPGP as
described in
https://datatracker.ietf.org/doc/draft-gallagher-email-unobtrusive-signatures/
Those kinds of signatures provide end-to-end cryptographic protection
for headers (based on
https://datatracker.ietf.org/doc/draft-ietf-lamps-header-protection/ )
as well as the message body, and are less likely to inflict bad UX or
bad rendering on recipients using legacy MUAs compared to PGP/MIME (or
inline PGP, for that matter).
These three patches appear to do the trick for me. I'm not an elisp
guru or a gnus expert. I'm happy to hear any feedback about how they
could be improved.
Regards,
--dkg
[0001-mml-Pass-likely-headers-through-to-mml-sec-functions.patch (text/x-diff, inline)]
From 81c3e7f5de0bbb24bbd2a2b43a103fb83c530f6d Mon Sep 17 00:00:00 2001 From: Daniel Kahn Gillmor <dkg <at> fifthhorseman.net> Date: Thu, 15 May 2025 21:49:32 -0400 Subject: [PATCH 1/3] mml: Pass likely headers through to mml-sec functions By pre-computing the likely headers for an outbound message, and passing them along as a tag in mml-parse, we create an opportunity to provide Header Protection as described in https://datatracker.ietf.org/doc/draft-ietf-lamps-header-protection/ Signed-off-by: Daniel Kahn Gillmor <dkg <at> fifthhorseman.net> --- lisp/gnus/mml.el | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/lisp/gnus/mml.el b/lisp/gnus/mml.el index 51d8d2c3769..11a8de7c011 100644 --- a/lisp/gnus/mml.el +++ b/lisp/gnus/mml.el @@ -265,6 +265,8 @@ part. This is for the internal use, you should never modify the value.") (apply #'mml-insert-tag secure-mode `(,@tags + ,"likely-headers" + ,(mml-get-likely-headers) ,(if keyfile "keyfile") ,keyfile ,@(apply #'append @@ -492,6 +494,21 @@ If MML is non-nil, return the buffer up till the correspondent mml tag." (declare-function libxml-parse-html-region "xml.c" (start end &optional base-url discard-comments)) +(defun mml-get-likely-headers () + "Get likely final headers from the existing message" + (save-excursion + (save-restriction + (message-narrow-to-headers-or-head) + (let ((x (buffer-substring (point-min) (point-max)))) + (with-temp-buffer + (insert x) + (message-remove-header "Bcc") + (message-remove-header message-ignored-mail-headers t) + (mail-encode-encoded-word-buffer) + (message-cleanup-headers) + (buffer-string) + ))))) + (defun mml-generate-mime (&optional multipart-type content-type) "Generate a MIME message based on the current MML document. MULTIPART-TYPE defaults to \"mixed\", but can also -- 2.47.2
[0002-mml-Enable-production-of-Unobtrusive-Signatures-via-.patch (text/x-diff, inline)]
From 75f8c5c936deafea1ee44edad5e0f530ec6c4dfc Mon Sep 17 00:00:00 2001
From: Daniel Kahn Gillmor <dkg <at> fifthhorseman.net>
Date: Thu, 15 May 2025 21:54:06 -0400
Subject: [PATCH 2/3] mml: Enable production of Unobtrusive Signatures via epg
https://datatracker.ietf.org/doc/draft-gallagher-email-invisible-signatures/
describes a mechanism to produce cleartext signatures over MIME messages
that are less likely to cause problems than traditional PGP/MIME.
With this patch, it's possible to produce those signatures with:
(mml-secure-message "unobtrusive" 'sign)
This patch only works with epg, not with mailcrypt or pgg, because epg
is what i'm familiar with and what i can easily test.
Signed-off-by: Daniel Kahn Gillmor <dkg <at> fifthhorseman.net>
---
lisp/gnus/mml-sec.el | 6 ++++++
lisp/gnus/mml2015.el | 39 +++++++++++++++++++++++++++++++++++++++
2 files changed, 45 insertions(+)
diff --git a/lisp/gnus/mml-sec.el b/lisp/gnus/mml-sec.el
index 8dffcf872f3..6fb82836e9a 100644
--- a/lisp/gnus/mml-sec.el
+++ b/lisp/gnus/mml-sec.el
@@ -34,6 +34,7 @@
(autoload 'mail-strip-quoted-names "mail-utils")
(autoload 'mml2015-sign "mml2015")
(autoload 'mml2015-encrypt "mml2015")
+(autoload 'mml-unobtrusive-sign "mml2015")
(autoload 'mml1991-sign "mml1991")
(autoload 'mml1991-encrypt "mml1991")
(autoload 'message-fetch-field "message")
@@ -56,6 +57,7 @@
'(("smime" mml-smime-sign-buffer mml-smime-sign-query)
("pgp" mml-pgp-sign-buffer list)
("pgpauto" mml-pgpauto-sign-buffer list)
+ ("unobtrusive" mml-unobtrusive-sign-buffer list)
("pgpmime" mml-pgpmime-sign-buffer list))
"Alist of MIME signer functions.")
@@ -198,6 +200,10 @@ You can also customize or set `mml-signencrypt-style-alist' instead."
(or (mml2015-sign cont)
(error "Signing failed... inspect message logs for errors")))
+(defun mml-unobtrusive-sign-buffer (cont)
+ (or (mml-unobtrusive-sign cont)
+ (error "Signing failed... inspect message logs for errors")))
+
(defun mml-pgpmime-encrypt-buffer (cont &optional sign)
(or (mml2015-encrypt cont sign)
(error "Encryption failed... inspect message logs for errors")))
diff --git a/lisp/gnus/mml2015.el b/lisp/gnus/mml2015.el
index a46aa68f56a..646fb018a31 100644
--- a/lisp/gnus/mml2015.el
+++ b/lisp/gnus/mml2015.el
@@ -25,6 +25,9 @@
;; RFC 2015 is updated by RFC 3156, this file should be compatible
;; with both.
+;; This is also capable of producing unobtrusive signatures based on
+;; draft-gallagher-email-unobtrusive-signatures
+
;;; Code:
(eval-when-compile (require 'cl-lib))
@@ -945,6 +948,42 @@ If set, it overrides the setting of `mml2015-sign-with-sender'."
(insert (format "--%s--\n" boundary))
(goto-char (point-max))))
+;;; Unobtrusive Signatures, see:
+;;; https://datatracker.ietf.org/doc/draft-gallagher-email-unobtrusive-signatures/
+
+; convert ASCII-armored PGP SIGNATURE block to base64-encoded with FWS
+; at the start of each line:
+(defun pgpsig-armor-to-wrapped-b64 (s)
+ (string-join
+ (string-split
+ (string-trim-right
+ (string-trim-left s "-----BEGIN PGP SIGNATURE-----\n\\(?:[^\n]+\n\\)*\n")
+ "\n\\(?:=....\n\\)?-----END PGP SIGNATURE-----\n?")
+ "\n")
+ "\n "))
+
+(defun mml-unobtrusive-sign (cont)
+ (goto-char (point-min))
+ (insert (cdr (assq 'likely-headers cont)))
+ (re-search-forward "^Content-Type: [^\n]*\\(\n[ \t][^\n]*$\\)*")
+ (insert "; hp=\"clear\"")
+ (re-search-forward "^")
+ (let* ((pair (mml-secure-epg-sign 'OpenPGP t))
+ (signature (car pair)))
+ (unless (stringp signature)
+ (error "Signature failed"))
+ (goto-char (point-min))
+ (insert (format "Sig: t=p; b=%s\n"
+ (pgpsig-armor-to-wrapped-b64 signature)))
+ (let ((boundary (mml-compute-boundary cont)))
+ (goto-char (point-min))
+ (insert (format "Content-Type: multipart/mixed; boundary=\"%s\";\n"
+ boundary))
+ (insert (format "\n--%s\n" boundary))
+ (goto-char (point-max))
+ (insert (format "\n--%s--\n" boundary))
+ (goto-char (point-max)))))
+
;;; General wrapper
(autoload 'gnus-buffer-live-p "gnus-util")
--
2.47.2
[0003-mml-Add-C-c-RET-s-u-to-make-Unobtrusive-Signature.patch (text/x-diff, inline)]
From f03c16ddedaa0b7a39692629ab61e7c3b3e06201 Mon Sep 17 00:00:00 2001
From: Daniel Kahn Gillmor <dkg <at> fifthhorseman.net>
Date: Thu, 15 May 2025 22:03:25 -0400
Subject: [PATCH 3/3] mml: Add C-c RET s u to make Unobtrusive Signature
This adds to the default keymap to make it relatively easy to make an
Unobtrusive Signature when sending mail.
Signed-off-by: Daniel Kahn Gillmor <dkg <at> fifthhorseman.net>
---
lisp/gnus/mml-sec.el | 5 +++++
lisp/gnus/mml.el | 6 ++++--
2 files changed, 9 insertions(+), 2 deletions(-)
diff --git a/lisp/gnus/mml-sec.el b/lisp/gnus/mml-sec.el
index 6fb82836e9a..9b703abd5f4 100644
--- a/lisp/gnus/mml-sec.el
+++ b/lisp/gnus/mml-sec.el
@@ -285,6 +285,11 @@ Use METHOD if given. Else use `mml-secure-method' or
(interactive nil mml-mode)
(mml-secure-part "pgpmime" 'sign))
+(defun mml-secure-sign-unobtrusive ()
+ "Add MML tags to unobtrusively sign this MML part."
+ (interactive nil mml-mode)
+ (mml-secure-part "unobtrusive" 'sign))
+
(defun mml-secure-sign-smime ()
"Add MML tags to S/MIME sign this MML part."
(interactive nil mml-mode)
diff --git a/lisp/gnus/mml.el b/lisp/gnus/mml.el
index 11a8de7c011..7d849335154 100644
--- a/lisp/gnus/mml.el
+++ b/lisp/gnus/mml.el
@@ -1178,11 +1178,13 @@ If HANDLES is non-nil, use it instead reparsing the buffer."
"s" (define-keymap
"p" #'mml-secure-message-sign-pgpmime
"o" #'mml-secure-message-sign-pgp
- "s" #'mml-secure-message-sign-smime)
+ "s" #'mml-secure-message-sign-smime
+ "u" #'mml-secure-message-sign-unobtrusive)
"S" (define-keymap
"p" #'mml-secure-sign-pgpmime
"o" #'mml-secure-sign-pgp
- "s" #'mml-secure-sign-smime)
+ "s" #'mml-secure-sign-smime
+ "u" #'mml-secure-message-sign-unobtrusive)
"c" (define-keymap
"p" #'mml-secure-message-encrypt-pgpmime
"o" #'mml-secure-message-encrypt-pgp
--
2.47.2
[signature.asc (application/pgp-signature, inline)]
bug-gnu-emacs <at> gnu.org, bugs <at> gnus.org:bug#78448; Package emacs,gnus.
(Sat, 17 May 2025 10:17:02 GMT) Full text and rfc822 format available.Message #8 received at 78448 <at> debbugs.gnu.org (full text, mbox):
From: Eli Zaretskii <eliz <at> gnu.org> To: Daniel Kahn Gillmor <dkg <at> fifthhorseman.net>, Eric Abrahamsen <eric <at> ericabrahamsen.net> Cc: 78448 <at> debbugs.gnu.org Subject: Re: bug#78448: 30.1; mml: Produce Unobtrusive Signatures Date: Sat, 17 May 2025 13:15:43 +0300
> From: Daniel Kahn Gillmor <dkg <at> fifthhorseman.net> > Date: Thu, 15 May 2025 23:56:25 -0400 > > Package: emacs,gnus > Version: 30.1 > > I'm running emacs 30.1 on debian. When sending cleartext mail, i want > to be able to produce an "Unobtrusive Signature" using OpenPGP as > described in > https://datatracker.ietf.org/doc/draft-gallagher-email-unobtrusive-signatures/ > > Those kinds of signatures provide end-to-end cryptographic protection > for headers (based on > https://datatracker.ietf.org/doc/draft-ietf-lamps-header-protection/ ) > as well as the message body, and are less likely to inflict bad UX or > bad rendering on recipients using legacy MUAs compared to PGP/MIME (or > inline PGP, for that matter). > > These three patches appear to do the trick for me. I'm not an elisp > guru or a gnus expert. I'm happy to hear any feedback about how they > could be improved. Eric, any comments to the patch or to the issue? In any case, Daniel, to accept a contribution this large, we will need you to assign to the FSF the copyright for your Emacs-related changes. If you agree to do that, I will send you the form to fill and the instructions to go with it. Thanks.
bug-gnu-emacs <at> gnu.org, bugs <at> gnus.org:bug#78448; Package emacs,gnus.
(Sun, 18 May 2025 03:17:01 GMT) Full text and rfc822 format available.Message #11 received at 78448 <at> debbugs.gnu.org (full text, mbox):
From: Daniel Kahn Gillmor <dkg <at> fifthhorseman.net> To: Eli Zaretskii <eliz <at> gnu.org>, Eric Abrahamsen <eric <at> ericabrahamsen.net> Cc: 78448 <at> debbugs.gnu.org Subject: Re: bug#78448: 30.1; mml: Produce Unobtrusive Signatures Date: Sat, 17 May 2025 23:16:39 -0400
[Message part 1 (text/plain, inline)]
Hi Eli--
On Sat 2025-05-17 13:15:43 +0300, Eli Zaretskii wrote:
> In any case, Daniel, to accept a contribution this large, we will need
> you to assign to the FSF the copyright for your Emacs-related changes.
> If you agree to do that, I will send you the form to fill and the
> instructions to go with it.
I'm pretty frustrated and disappointed with the FSF these days, but i
still care about emacs, so i'm willing to make a copyright assignment
for the sake of the tooling here and the broader ecosystem around it.
Please send me the form and instructions.
--dkg
[signature.asc (application/pgp-signature, inline)]
bug-gnu-emacs <at> gnu.org, bugs <at> gnus.org:bug#78448; Package emacs,gnus.
(Sun, 18 May 2025 05:17:02 GMT) Full text and rfc822 format available.Message #14 received at 78448 <at> debbugs.gnu.org (full text, mbox):
From: Eli Zaretskii <eliz <at> gnu.org> To: Daniel Kahn Gillmor <dkg <at> fifthhorseman.net> Cc: eric <at> ericabrahamsen.net, 78448 <at> debbugs.gnu.org Subject: Re: bug#78448: 30.1; mml: Produce Unobtrusive Signatures Date: Sun, 18 May 2025 08:16:26 +0300
> From: Daniel Kahn Gillmor <dkg <at> fifthhorseman.net> > Cc: 78448 <at> debbugs.gnu.org > Date: Sat, 17 May 2025 23:16:39 -0400 > > Hi Eli-- > > On Sat 2025-05-17 13:15:43 +0300, Eli Zaretskii wrote: > > In any case, Daniel, to accept a contribution this large, we will need > > you to assign to the FSF the copyright for your Emacs-related changes. > > If you agree to do that, I will send you the form to fill and the > > instructions to go with it. > > I'm pretty frustrated and disappointed with the FSF these days, but i > still care about emacs, so i'm willing to make a copyright assignment > for the sake of the tooling here and the broader ecosystem around it. > > Please send me the form and instructions. Thanks, form sent off-list.
bug-gnu-emacs <at> gnu.org, bugs <at> gnus.org:bug#78448; Package emacs,gnus.
(Tue, 20 May 2025 18:48:01 GMT) Full text and rfc822 format available.Message #17 received at 78448 <at> debbugs.gnu.org (full text, mbox):
From: Daniel Kahn Gillmor <dkg <at> fifthhorseman.net> To: 78448 <at> debbugs.gnu.org Subject: [PATCH 3/3 v2] Re: 30.1; mml: Produce Unobtrusive Signatures Date: Tue, 20 May 2025 14:47:00 -0400
[Message part 1 (text/plain, inline)]
Attached is a revised version of patch 3, which corrects the default
keybindings.
--dkg
[0003-mml-Add-C-c-RET-s-u-to-make-Unobtrusive-Signature.patch (text/x-diff, inline)]
From a5de7ee57e1933a0783c8346db52c569074c07f7 Mon Sep 17 00:00:00 2001
From: Daniel Kahn Gillmor <dkg <at> fifthhorseman.net>
Date: Thu, 15 May 2025 22:03:25 -0400
Subject: [PATCH] mml: Add C-c RET s u to make Unobtrusive Signature
This adds to the default keymap to make it relatively easy to make an
Unobtrusive Signature when sending mail.
Unobtrusive Signatures are defined on a per-message basis, and
explicitly ignored per-part, so we do not facilitate part-based signing.
Signed-off-by: Daniel Kahn Gillmor <dkg <at> fifthhorseman.net>
---
lisp/gnus/mml-sec.el | 5 +++++
lisp/gnus/mml.el | 3 ++-
2 files changed, 7 insertions(+), 1 deletion(-)
diff --git a/lisp/gnus/mml-sec.el b/lisp/gnus/mml-sec.el
index 6fb82836e9a..71913c8e8cc 100644
--- a/lisp/gnus/mml-sec.el
+++ b/lisp/gnus/mml-sec.el
@@ -399,6 +399,11 @@ Use METHOD if given. Else use `mml-secure-method' or
(or method mml-secure-method mml-default-sign-method)
'encrypt))
+(defun mml-secure-message-sign-unobtrusive ()
+ "Add MML tag to encrypt/sign the entire message."
+ (interactive nil mml-mode)
+ (mml-secure-message "unobtrusive" 'sign))
+
(defun mml-secure-message-sign-smime ()
"Add MML tag to encrypt/sign the entire message."
(interactive nil mml-mode)
diff --git a/lisp/gnus/mml.el b/lisp/gnus/mml.el
index 11a8de7c011..52c9c63833a 100644
--- a/lisp/gnus/mml.el
+++ b/lisp/gnus/mml.el
@@ -1178,7 +1178,8 @@ If HANDLES is non-nil, use it instead reparsing the buffer."
"s" (define-keymap
"p" #'mml-secure-message-sign-pgpmime
"o" #'mml-secure-message-sign-pgp
- "s" #'mml-secure-message-sign-smime)
+ "s" #'mml-secure-message-sign-smime
+ "u" #'mml-secure-message-sign-unobtrusive)
"S" (define-keymap
"p" #'mml-secure-sign-pgpmime
"o" #'mml-secure-sign-pgp
--
2.47.2
bug-gnu-emacs <at> gnu.org, bugs <at> gnus.org:bug#78448; Package emacs,gnus.
(Wed, 28 May 2025 12:45:02 GMT) Full text and rfc822 format available.Message #20 received at 78448 <at> debbugs.gnu.org (full text, mbox):
From: Richard Stallman <rms <at> gnu.org> To: Eli Zaretskii <eliz <at> gnu.org> Cc: eric <at> ericabrahamsen.net, 78448 <at> debbugs.gnu.org, dkg <at> fifthhorseman.net Subject: Re: bug#78448: 30.1; mml: Produce Unobtrusive Signatures Date: Wed, 28 May 2025 08:44:21 -0400
[[[ To any NSA and FBI agents reading my email: please consider ]]] [[[ whether defending the US Constitution against all enemies, ]]] [[[ foreign or domestic, requires you to follow Snowden's example. ]]] > i want > > to be able to produce an "Unobtrusive Signature" using OpenPGP as > > described in > > https://datatracker.ietf.org/doc/draft-gallagher-email-unobtrusive-signatures/ Can GPG do this job also? If so, we should by default use GPG to do this, unless the user specifies a different command to use. -- Dr Richard Stallman (https://stallman.org) Chief GNUisance of the GNU Project (https://gnu.org) Founder, Free Software Foundation (https://fsf.org) Internet Hall-of-Famer (https://internethalloffame.org)
bug-gnu-emacs <at> gnu.org, bugs <at> gnus.org:bug#78448; Package emacs,gnus.
(Wed, 28 May 2025 14:14:01 GMT) Full text and rfc822 format available.Message #23 received at 78448 <at> debbugs.gnu.org (full text, mbox):
From: Daniel Kahn Gillmor <dkg <at> fifthhorseman.net> To: rms <at> gnu.org, Eli Zaretskii <eliz <at> gnu.org> Cc: eric <at> ericabrahamsen.net, 78448 <at> debbugs.gnu.org Subject: Re: bug#78448: 30.1; mml: Produce Unobtrusive Signatures Date: Wed, 28 May 2025 10:07:25 -0400
[Message part 1 (text/plain, inline)]
On Wed 2025-05-28 08:44:21 -0400, Richard Stallman wrote:
> [ dkg wrote: ]
> > > i want to be able to produce an "Unobtrusive Signature" using
> > > OpenPGP as described in
> > > https://datatracker.ietf.org/doc/draft-gallagher-email-unobtrusive-signatures/
>
> Can GPG do this job also? If so, we should by default use GPG to do
> this, unless the user specifies a different command to use.
The proposed patch series explicitly relies on emacs's epg to make the
actual signature. epg is an emacs library to use GPG. So i think what
you're asking for is already being done in this series.
For background: GPG typically does not handle e-mails directly. Rather,
the mail user agent (MUA) needs to figure out how to modify the pending
e-mail message to be able to feed it into GPG as a text or binary
document to make an OpenPGP signature; then the MUA has to restructure
the message again to ship both the substance and the signature into a
single e-mail message.
Regards,
--dkg
bug-gnu-emacs <at> gnu.org, bugs <at> gnus.org:bug#78448; Package emacs,gnus.
(Sat, 31 May 2025 09:22:03 GMT) Full text and rfc822 format available.Message #26 received at 78448 <at> debbugs.gnu.org (full text, mbox):
From: Eli Zaretskii <eliz <at> gnu.org> To: Daniel Kahn Gillmor <dkg <at> fifthhorseman.net>, eric <at> ericabrahamsen.net Cc: 78448 <at> debbugs.gnu.org, rms <at> gnu.org Subject: Re: bug#78448: 30.1; mml: Produce Unobtrusive Signatures Date: Sat, 31 May 2025 12:21:10 +0300
Ping! Eric, would you please chime in and comment on the patch? > From: Daniel Kahn Gillmor <dkg <at> fifthhorseman.net> > Cc: eric <at> ericabrahamsen.net, 78448 <at> debbugs.gnu.org > Date: Wed, 28 May 2025 10:07:25 -0400 > > On Wed 2025-05-28 08:44:21 -0400, Richard Stallman wrote: > > [ dkg wrote: ] > > > > i want to be able to produce an "Unobtrusive Signature" using > > > > OpenPGP as described in > > > > https://datatracker.ietf.org/doc/draft-gallagher-email-unobtrusive-signatures/ > > > > Can GPG do this job also? If so, we should by default use GPG to do > > this, unless the user specifies a different command to use. > > The proposed patch series explicitly relies on emacs's epg to make the > actual signature. epg is an emacs library to use GPG. So i think what > you're asking for is already being done in this series. > > For background: GPG typically does not handle e-mails directly. Rather, > the mail user agent (MUA) needs to figure out how to modify the pending > e-mail message to be able to feed it into GPG as a text or binary > document to make an OpenPGP signature; then the MUA has to restructure > the message again to ship both the substance and the signature into a > single e-mail message. > > Regards, > > --dkg
bug-gnu-emacs <at> gnu.org, bugs <at> gnus.org:bug#78448; Package emacs,gnus.
(Tue, 03 Jun 2025 09:33:01 GMT) Full text and rfc822 format available.Message #29 received at 78448 <at> debbugs.gnu.org (full text, mbox):
From: Robert Pluim <rpluim <at> gmail.com> To: Eli Zaretskii <eliz <at> gnu.org> Cc: eric <at> ericabrahamsen.net, 78448 <at> debbugs.gnu.org, rms <at> gnu.org, Daniel Kahn Gillmor <dkg <at> fifthhorseman.net> Subject: Re: bug#78448: 30.1; mml: Produce Unobtrusive Signatures Date: Tue, 03 Jun 2025 11:32:36 +0200
>>>>> On Sat, 31 May 2025 12:21:10 +0300, Eli Zaretskii <eliz <at> gnu.org> said:
Eli> Ping! Eric, would you please chime in and comment on the
Eli> patch?
Iʼm not Eric, but I have comments and questions below
Daniel> These three patches appear to do the trick for me. I'm not an elisp
Daniel> guru or a gnus expert. I'm happy to hear any feedback about how they
Daniel> could be improved.
Daniel> Regards,
Daniel> --dkg
Daniel> From 81c3e7f5de0bbb24bbd2a2b43a103fb83c530f6d Mon Sep 17 00:00:00 2001
Daniel> From: Daniel Kahn Gillmor <dkg <at> fifthhorseman.net>
Daniel> Date: Thu, 15 May 2025 21:49:32 -0400
Daniel> Subject: [PATCH 1/3] mml: Pass likely headers through to mml-sec functions
Daniel> By pre-computing the likely headers for an outbound message, and passing
Daniel> them along as a tag in mml-parse, we create an opportunity to provide
Daniel> Header Protection as described in
Daniel> https://datatracker.ietf.org/doc/draft-ietf-lamps-header-protection/
Is this necessary for unobtrusive signatures to work? If itʼs to
enable future functionality Iʼd rather leave it out.
Daniel> Signed-off-by: Daniel Kahn Gillmor <dkg <at> fifthhorseman.net>
We donʼt use Signed-off-by (and I think a change of this size probably
requires copyright assignment).
Daniel> ---
Daniel> lisp/gnus/mml.el | 17 +++++++++++++++++
Daniel> 1 file changed, 17 insertions(+)
Daniel> diff --git a/lisp/gnus/mml.el b/lisp/gnus/mml.el
Daniel> index 51d8d2c3769..11a8de7c011 100644
Daniel> --- a/lisp/gnus/mml.el
Daniel> +++ b/lisp/gnus/mml.el
Daniel> @@ -265,6 +265,8 @@ part. This is for the internal use, you should never modify the value.")
Daniel> (apply #'mml-insert-tag
Daniel> secure-mode
Daniel> `(,@tags
Daniel> + ,"likely-headers"
Daniel> + ,(mml-get-likely-headers)
Daniel> ,(if keyfile "keyfile")
Daniel> ,keyfile
Daniel> ,@(apply #'append
Daniel> @@ -492,6 +494,21 @@ If MML is non-nil, return the buffer up till the correspondent mml tag."
Daniel> (declare-function libxml-parse-html-region "xml.c"
Daniel> (start end &optional base-url discard-comments))
Daniel> +(defun mml-get-likely-headers ()
Daniel> + "Get likely final headers from the existing message"
Daniel> + (save-excursion
Daniel> + (save-restriction
Daniel> + (message-narrow-to-headers-or-head)
Daniel> + (let ((x (buffer-substring (point-min) (point-max))))
Daniel> + (with-temp-buffer
Daniel> + (insert x)
Daniel> + (message-remove-header "Bcc")
Daniel> + (message-remove-header message-ignored-mail-headers t)
Daniel> + (mail-encode-encoded-word-buffer)
Daniel> + (message-cleanup-headers)
Daniel> + (buffer-string)
Daniel> + )))))
Daniel> +
`with-output-to-string' is what youʼre looking for here, I think.
Daniel> (defun mml-generate-mime (&optional multipart-type content-type)
Daniel> "Generate a MIME message based on the current MML document.
Daniel> MULTIPART-TYPE defaults to \"mixed\", but can also
Daniel> --
Daniel> 2.47.2
Daniel> From 75f8c5c936deafea1ee44edad5e0f530ec6c4dfc Mon Sep 17 00:00:00 2001
Daniel> From: Daniel Kahn Gillmor <dkg <at> fifthhorseman.net>
Daniel> Date: Thu, 15 May 2025 21:54:06 -0400
Daniel> Subject: [PATCH 2/3] mml: Enable production of Unobtrusive Signatures via epg
Daniel> https://datatracker.ietf.org/doc/draft-gallagher-email-invisible-signatures/
Daniel> describes a mechanism to produce cleartext signatures over MIME messages
Daniel> that are less likely to cause problems than traditional PGP/MIME.
Daniel> With this patch, it's possible to produce those signatures with:
Daniel> (mml-secure-message "unobtrusive" 'sign)
Daniel> This patch only works with epg, not with mailcrypt or pgg, because epg
Daniel> is what i'm familiar with and what i can easily test.
pgg is marked obsolete, and I think mailcrypt is external, so thatʼs
ok.
Daniel> Signed-off-by: Daniel Kahn Gillmor <dkg <at> fifthhorseman.net>
Daniel> ---
Daniel> lisp/gnus/mml-sec.el | 6 ++++++
Daniel> lisp/gnus/mml2015.el | 39 +++++++++++++++++++++++++++++++++++++++
Daniel> 2 files changed, 45 insertions(+)
Daniel> diff --git a/lisp/gnus/mml-sec.el b/lisp/gnus/mml-sec.el
Daniel> index 8dffcf872f3..6fb82836e9a 100644
Daniel> --- a/lisp/gnus/mml-sec.el
Daniel> +++ b/lisp/gnus/mml-sec.el
Daniel> @@ -34,6 +34,7 @@
Daniel> (autoload 'mail-strip-quoted-names "mail-utils")
Daniel> (autoload 'mml2015-sign "mml2015")
Daniel> (autoload 'mml2015-encrypt "mml2015")
Daniel> +(autoload 'mml-unobtrusive-sign "mml2015")
Daniel> (autoload 'mml1991-sign "mml1991")
Daniel> (autoload 'mml1991-encrypt "mml1991")
Daniel> (autoload 'message-fetch-field "message")
Daniel> @@ -56,6 +57,7 @@
Daniel> '(("smime" mml-smime-sign-buffer mml-smime-sign-query)
Daniel> ("pgp" mml-pgp-sign-buffer list)
Daniel> ("pgpauto" mml-pgpauto-sign-buffer list)
Daniel> + ("unobtrusive" mml-unobtrusive-sign-buffer list)
Daniel> ("pgpmime" mml-pgpmime-sign-buffer list))
Daniel> "Alist of MIME signer functions.")
Daniel> @@ -198,6 +200,10 @@ You can also customize or set `mml-signencrypt-style-alist' instead."
Daniel> (or (mml2015-sign cont)
Daniel> (error "Signing failed... inspect message logs for errors")))
Daniel> +(defun mml-unobtrusive-sign-buffer (cont)
Daniel> + (or (mml-unobtrusive-sign cont)
Daniel> + (error "Signing failed... inspect message logs for errors")))
Daniel> +
Daniel> (defun mml-pgpmime-encrypt-buffer (cont &optional sign)
Daniel> (or (mml2015-encrypt cont sign)
Daniel> (error "Encryption failed... inspect message logs for errors")))
Daniel> diff --git a/lisp/gnus/mml2015.el b/lisp/gnus/mml2015.el
Daniel> index a46aa68f56a..646fb018a31 100644
Daniel> --- a/lisp/gnus/mml2015.el
Daniel> +++ b/lisp/gnus/mml2015.el
Daniel> @@ -25,6 +25,9 @@
Daniel> ;; RFC 2015 is updated by RFC 3156, this file should be compatible
Daniel> ;; with both.
Daniel> +;; This is also capable of producing unobtrusive signatures based on
Daniel> +;; draft-gallagher-email-unobtrusive-signatures
Daniel> +
Daniel> ;;; Code:
Daniel> (eval-when-compile (require 'cl-lib))
Daniel> @@ -945,6 +948,42 @@ If set, it overrides the setting of `mml2015-sign-with-sender'."
Daniel> (insert (format "--%s--\n" boundary))
Daniel> (goto-char (point-max))))
Daniel> +;;; Unobtrusive Signatures, see:
Daniel> +;;; https://datatracker.ietf.org/doc/draft-gallagher-email-unobtrusive-signatures/
Daniel> +
Daniel> +; convert ASCII-armored PGP SIGNATURE block to base64-encoded with FWS
Daniel> +; at the start of each line:
Daniel> +(defun pgpsig-armor-to-wrapped-b64 (s)
Daniel> + (string-join
Daniel> + (string-split
Daniel> + (string-trim-right
Daniel> + (string-trim-left s "-----BEGIN PGP SIGNATURE-----\n\\(?:[^\n]+\n\\)*\n")
Daniel> + "\n\\(?:=....\n\\)?-----END PGP SIGNATURE-----\n?")
Daniel> + "\n")
Daniel> + "\n "))
Daniel> +
Daniel> +(defun mml-unobtrusive-sign (cont)
Daniel> + (goto-char (point-min))
Daniel> + (insert (cdr (assq 'likely-headers cont)))
Daniel> + (re-search-forward "^Content-Type: [^\n]*\\(\n[ \t][^\n]*$\\)*")
Daniel> + (insert "; hp=\"clear\"")
Daniel> + (re-search-forward "^")
I think thatʼs better expressed as:
(forward-line 1)
Also, what is the chance that this will end up inserting certain
headers twice?
Robert
--
bug-gnu-emacs <at> gnu.org, bugs <at> gnus.org:bug#78448; Package emacs,gnus.
(Fri, 06 Jun 2025 20:33:02 GMT) Full text and rfc822 format available.Message #32 received at 78448 <at> debbugs.gnu.org (full text, mbox):
From: Daniel Kahn Gillmor <dkg <at> fifthhorseman.net> To: Robert Pluim <rpluim <at> gmail.com>, Eli Zaretskii <eliz <at> gnu.org> Cc: eric <at> ericabrahamsen.net, 78448 <at> debbugs.gnu.org, rms <at> gnu.org Subject: Re: bug#78448: 30.1; mml: Produce Unobtrusive Signatures Date: Fri, 06 Jun 2025 16:32:18 -0400
[Message part 1 (text/plain, inline)]
Hi Robert--
Thank you for the review!
On Tue 2025-06-03 11:32:36 +0200, Robert Pluim wrote:
> Daniel> By pre-computing the likely headers for an outbound message, and passing
> Daniel> them along as a tag in mml-parse, we create an opportunity to provide
> Daniel> Header Protection as described in
> Daniel> https://datatracker.ietf.org/doc/draft-ietf-lamps-header-protection/
>
> Is this necessary for unobtrusive signatures to work? If itʼs to
> enable future functionality Iʼd rather leave it out.
Yes, unobtrusive signatures are defined with header protection
mandatory.
Please see
https://datatracker.ietf.org/doc/draft-gallagher-email-unobtrusive-signatures/
> We donʼt use Signed-off-by (and I think a change of this size probably
> requires copyright assignment).
OK, feel fre to strip Signed-off-by when applying, that doesn't matter
to me at all. I'm already in communication with assign <at> gnu.org about
copyright assignment.
> Daniel> +(defun mml-get-likely-headers ()
> Daniel> + "Get likely final headers from the existing message"
> Daniel> + (save-excursion
> Daniel> + (save-restriction
> Daniel> + (message-narrow-to-headers-or-head)
> Daniel> + (let ((x (buffer-substring (point-min) (point-max))))
> Daniel> + (with-temp-buffer
> Daniel> + (insert x)
> Daniel> + (message-remove-header "Bcc")
> Daniel> + (message-remove-header message-ignored-mail-headers t)
> Daniel> + (mail-encode-encoded-word-buffer)
> Daniel> + (message-cleanup-headers)
> Daniel> + (buffer-string)
> Daniel> + )))))
> Daniel> +
>
> `with-output-to-string' is what youʼre looking for here, I think.
with-output-to-string seems to transform stdout (standard output) to a
string. But i don't see what i'm doing above as using stdout. I thnk
they're all manipulatig a buffer, which is why i've wrapped them in the
various staging functions (save-excursion, save-restriction,
with-temp-buffer). Which part should be replaced with
with-output-to-string?
> pgg is marked obsolete, and I think mailcrypt is external, so thatʼs
> ok.
Thanks! That status was unclear to me.
> Daniel> + (re-search-forward "^")
>
> I think thatʼs better expressed as:
>
> (forward-line 1)
Got it, thanks.
> Also, what is the chance that this will end up inserting certain
> headers twice?
For a signed-only e-mail with header-protection, all of the headers that
the generating MUA knows about will appear twice in the message: Once in
the outer message header section (outside of the cryptographic
envelope), and once in the cryptographic payload (so that they're
covered by the signature).
It's certainly possible to trim down the message size in the future by
dropping header fields that we expect to be ignored in transit by MTAs.
But i wouldn't try to do that until we're confident that most receiving
MUAs will handle the signed header fields in the Cryptographic Payload.
In practice, the cost of all duplicated header fields in aggregate is
small compared to, say, a single attached jpg, a boilerplate disclaimer,
or (depending on the algorithm) even the signature itself. So I'm not
particularly concerned about size.
Regards,
--dkg
bug-gnu-emacs <at> gnu.org, bugs <at> gnus.org:bug#78448; Package emacs,gnus.
(Mon, 09 Jun 2025 12:46:02 GMT) Full text and rfc822 format available.Message #35 received at 78448 <at> debbugs.gnu.org (full text, mbox):
From: Robert Pluim <rpluim <at> gmail.com> To: Daniel Kahn Gillmor <dkg <at> fifthhorseman.net> Cc: eric <at> ericabrahamsen.net, 78448 <at> debbugs.gnu.org, Eli Zaretskii <eliz <at> gnu.org>, rms <at> gnu.org Subject: Re: bug#78448: 30.1; mml: Produce Unobtrusive Signatures Date: Mon, 09 Jun 2025 14:45:23 +0200
>>>>> On Fri, 06 Jun 2025 16:32:18 -0400, Daniel Kahn Gillmor <dkg <at> fifthhorseman.net> said:
Daniel> Hi Robert--
Daniel> Thank you for the review!
Daniel> On Tue 2025-06-03 11:32:36 +0200, Robert Pluim wrote:
Daniel> By pre-computing the likely headers for an outbound message, and passing
Daniel> them along as a tag in mml-parse, we create an opportunity to provide
Daniel> Header Protection as described in
Daniel> https://datatracker.ietf.org/doc/draft-ietf-lamps-header-protection/
>>
>> Is this necessary for unobtrusive signatures to work? If itʼs to
>> enable future functionality Iʼd rather leave it out.
Daniel> Yes, unobtrusive signatures are defined with header protection
Daniel> mandatory.
OK, itʼs just that the wording sounded like future work.
Daniel> Please see
Daniel> https://datatracker.ietf.org/doc/draft-gallagher-email-unobtrusive-signatures/
>> We donʼt use Signed-off-by (and I think a change of this size probably
>> requires copyright assignment).
Daniel> OK, feel fre to strip Signed-off-by when applying, that doesn't matter
Daniel> to me at all. I'm already in communication with assign <at> gnu.org about
Daniel> copyright assignment.
OK. Itʼs just slightly annoying, because our default commit hooks
refuse Signed-off-by. But Iʼll probably need to edit the commit
message anyway.
Daniel> +(defun mml-get-likely-headers ()
Daniel> + "Get likely final headers from the existing message"
Daniel> + (save-excursion
Daniel> + (save-restriction
Daniel> + (message-narrow-to-headers-or-head)
Daniel> + (let ((x (buffer-substring (point-min) (point-max))))
Daniel> + (with-temp-buffer
Daniel> + (insert x)
Daniel> + (message-remove-header "Bcc")
Daniel> + (message-remove-header message-ignored-mail-headers t)
Daniel> + (mail-encode-encoded-word-buffer)
Daniel> + (message-cleanup-headers)
Daniel> + (buffer-string)
Daniel> + )))))
Daniel> +
>>
>> `with-output-to-string' is what youʼre looking for here, I think.
Daniel> with-output-to-string seems to transform stdout (standard output) to a
Daniel> string. But i don't see what i'm doing above as using stdout. I thnk
Daniel> they're all manipulatig a buffer, which is why i've wrapped them in the
Daniel> various staging functions (save-excursion, save-restriction,
Daniel> with-temp-buffer). Which part should be replaced with
Daniel> with-output-to-string?
You could use it instead of `with-temp-buffer', but itʼs not a major
point.
>> Also, what is the chance that this will end up inserting certain
>> headers twice?
Daniel> For a signed-only e-mail with header-protection, all of the headers that
Daniel> the generating MUA knows about will appear twice in the message: Once in
Daniel> the outer message header section (outside of the cryptographic
Daniel> envelope), and once in the cryptographic payload (so that they're
Daniel> covered by the signature).
Thanks, Iʼd missed that the headers were repeated in a separate
part. I donʼt think it will be an issue.
Daniel> It's certainly possible to trim down the message size in the future by
Daniel> dropping header fields that we expect to be ignored in transit by MTAs.
Daniel> But i wouldn't try to do that until we're confident that most receiving
Daniel> MUAs will handle the signed header fields in the Cryptographic Payload.
Daniel> In practice, the cost of all duplicated header fields in aggregate is
Daniel> small compared to, say, a single attached jpg, a boilerplate disclaimer,
Daniel> or (depending on the algorithm) even the signature itself. So I'm not
Daniel> particularly concerned about size.
I just tried it, I needed the small patch below to get it to compile
without warnings.
What goes out on the wire to gmail looks correct, and whatʼs stored
there is correct as well. I canʼt see the Sig header in Gnus, but
maybe thatʼs Gnus not parsing the message correctly :-)
Robert
--
diff --git a/lisp/gnus/mml.el b/lisp/gnus/mml.el
index 972f1bce0a1..cfe4709f275 100644
--- a/lisp/gnus/mml.el
+++ b/lisp/gnus/mml.el
@@ -494,6 +494,9 @@ mml-inhibit-compute-boundary
(declare-function libxml-parse-html-region "xml.c"
(start end &optional base-url discard-comments))
+(defvar message-ignored-mail-headers)
+(declare-function message-cleanup-headers "message")
+
(defun mml-get-likely-headers ()
"Get likely final headers from the existing message"
(save-excursion
bug-gnu-emacs <at> gnu.org, bugs <at> gnus.org:bug#78448; Package emacs,gnus.
(Mon, 09 Jun 2025 22:55:02 GMT) Full text and rfc822 format available.Message #38 received at 78448 <at> debbugs.gnu.org (full text, mbox):
From: Daniel Kahn Gillmor <dkg <at> fifthhorseman.net> To: Robert Pluim <rpluim <at> gmail.com> Cc: eric <at> ericabrahamsen.net, 78448 <at> debbugs.gnu.org, Eli Zaretskii <eliz <at> gnu.org>, rms <at> gnu.org Subject: Re: bug#78448: 30.1; mml: Produce Unobtrusive Signatures Date: Mon, 09 Jun 2025 18:54:01 -0400
[Message part 1 (text/plain, inline)]
On Mon 2025-06-09 14:45:23 +0200, Robert Pluim wrote:
> I just tried it, I needed the small patch below to get it to compile
> without warnings.
[…]
> diff --git a/lisp/gnus/mml.el b/lisp/gnus/mml.el
> index 972f1bce0a1..cfe4709f275 100644
> --- a/lisp/gnus/mml.el
> +++ b/lisp/gnus/mml.el
> @@ -494,6 +494,9 @@ mml-inhibit-compute-boundary
> (declare-function libxml-parse-html-region "xml.c"
> (start end &optional base-url discard-comments))
>
> +(defvar message-ignored-mail-headers)
> +(declare-function message-cleanup-headers "message")
> +
> (defun mml-get-likely-headers ()
> "Get likely final headers from the existing message"
> (save-excursion
Thanks for this! I've updated the patch series to include your
feedback, and to drop the Signed-off-by: lines that were interfering
with the project expectations.
I'm including the three revised patches here.
Please let me know if you notice anything else that needs improvement.
Regards,
--dkg
[0001-mml-Pass-likely-headers-through-to-mml-sec-functions.patch (text/x-diff, inline)]
From 3a27bb0ce3a18eff2fd965a1f7da6a97a45a6744 Mon Sep 17 00:00:00 2001 From: Daniel Kahn Gillmor <dkg <at> fifthhorseman.net> Date: Thu, 15 May 2025 21:49:32 -0400 Subject: [PATCH 1/3] mml: Pass likely headers through to mml-sec functions By pre-computing the likely headers for an outbound message, and passing them along as a tag in mml-parse, we create an opportunity to provide Header Protection as described in https://datatracker.ietf.org/doc/draft-ietf-lamps-header-protection/ --- lisp/gnus/mml.el | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/lisp/gnus/mml.el b/lisp/gnus/mml.el index 51d8d2c3769..8e37dbe0bf6 100644 --- a/lisp/gnus/mml.el +++ b/lisp/gnus/mml.el @@ -265,6 +265,8 @@ part. This is for the internal use, you should never modify the value.") (apply #'mml-insert-tag secure-mode `(,@tags + ,"likely-headers" + ,(mml-get-likely-headers) ,(if keyfile "keyfile") ,keyfile ,@(apply #'append @@ -492,6 +494,24 @@ If MML is non-nil, return the buffer up till the correspondent mml tag." (declare-function libxml-parse-html-region "xml.c" (start end &optional base-url discard-comments)) +(defvar message-ignored-mail-headers) +(declare-function message-cleanup-headers "message") + +(defun mml-get-likely-headers () + "Get likely final headers from the existing message" + (save-excursion + (save-restriction + (message-narrow-to-headers-or-head) + (let ((x (buffer-substring (point-min) (point-max)))) + (with-temp-buffer + (insert x) + (message-remove-header "Bcc") + (message-remove-header message-ignored-mail-headers t) + (mail-encode-encoded-word-buffer) + (message-cleanup-headers) + (buffer-string) + ))))) + (defun mml-generate-mime (&optional multipart-type content-type) "Generate a MIME message based on the current MML document. MULTIPART-TYPE defaults to \"mixed\", but can also -- 2.47.2
[0002-mml-Enable-production-of-Unobtrusive-Signatures-via-.patch (text/x-diff, inline)]
From 9b4beb63f36c7af2f7b5b63c8fd81f2ac7bc877e Mon Sep 17 00:00:00 2001
From: Daniel Kahn Gillmor <dkg <at> fifthhorseman.net>
Date: Thu, 15 May 2025 21:54:06 -0400
Subject: [PATCH 2/3] mml: Enable production of Unobtrusive Signatures via epg
https://datatracker.ietf.org/doc/draft-gallagher-email-invisible-signatures/
describes a mechanism to produce cleartext signatures over MIME messages
that are less likely to cause problems than traditional PGP/MIME.
With this patch, it's possible to produce those signatures with:
(mml-secure-message "unobtrusive" 'sign)
This patch only works with epg, not with mailcrypt or pgg, because epg
is what i'm familiar with and what i can easily test.
---
lisp/gnus/mml-sec.el | 6 ++++++
lisp/gnus/mml2015.el | 39 +++++++++++++++++++++++++++++++++++++++
2 files changed, 45 insertions(+)
diff --git a/lisp/gnus/mml-sec.el b/lisp/gnus/mml-sec.el
index 8dffcf872f3..6fb82836e9a 100644
--- a/lisp/gnus/mml-sec.el
+++ b/lisp/gnus/mml-sec.el
@@ -34,6 +34,7 @@
(autoload 'mail-strip-quoted-names "mail-utils")
(autoload 'mml2015-sign "mml2015")
(autoload 'mml2015-encrypt "mml2015")
+(autoload 'mml-unobtrusive-sign "mml2015")
(autoload 'mml1991-sign "mml1991")
(autoload 'mml1991-encrypt "mml1991")
(autoload 'message-fetch-field "message")
@@ -56,6 +57,7 @@
'(("smime" mml-smime-sign-buffer mml-smime-sign-query)
("pgp" mml-pgp-sign-buffer list)
("pgpauto" mml-pgpauto-sign-buffer list)
+ ("unobtrusive" mml-unobtrusive-sign-buffer list)
("pgpmime" mml-pgpmime-sign-buffer list))
"Alist of MIME signer functions.")
@@ -198,6 +200,10 @@ You can also customize or set `mml-signencrypt-style-alist' instead."
(or (mml2015-sign cont)
(error "Signing failed... inspect message logs for errors")))
+(defun mml-unobtrusive-sign-buffer (cont)
+ (or (mml-unobtrusive-sign cont)
+ (error "Signing failed... inspect message logs for errors")))
+
(defun mml-pgpmime-encrypt-buffer (cont &optional sign)
(or (mml2015-encrypt cont sign)
(error "Encryption failed... inspect message logs for errors")))
diff --git a/lisp/gnus/mml2015.el b/lisp/gnus/mml2015.el
index a46aa68f56a..bbe6cec589f 100644
--- a/lisp/gnus/mml2015.el
+++ b/lisp/gnus/mml2015.el
@@ -25,6 +25,9 @@
;; RFC 2015 is updated by RFC 3156, this file should be compatible
;; with both.
+;; This is also capable of producing unobtrusive signatures based on
+;; draft-gallagher-email-unobtrusive-signatures
+
;;; Code:
(eval-when-compile (require 'cl-lib))
@@ -945,6 +948,42 @@ If set, it overrides the setting of `mml2015-sign-with-sender'."
(insert (format "--%s--\n" boundary))
(goto-char (point-max))))
+;;; Unobtrusive Signatures, see:
+;;; https://datatracker.ietf.org/doc/draft-gallagher-email-unobtrusive-signatures/
+
+; convert ASCII-armored PGP SIGNATURE block to base64-encoded with FWS
+; at the start of each line:
+(defun pgpsig-armor-to-wrapped-b64 (s)
+ (string-join
+ (string-split
+ (string-trim-right
+ (string-trim-left s "-----BEGIN PGP SIGNATURE-----\n\\(?:[^\n]+\n\\)*\n")
+ "\n\\(?:=....\n\\)?-----END PGP SIGNATURE-----\n?")
+ "\n")
+ "\n "))
+
+(defun mml-unobtrusive-sign (cont)
+ (goto-char (point-min))
+ (insert (cdr (assq 'likely-headers cont)))
+ (re-search-forward "^Content-Type: [^\n]*\\(\n[ \t][^\n]*$\\)*")
+ (insert "; hp=\"clear\"")
+ (forward-line 1)
+ (let* ((pair (mml-secure-epg-sign 'OpenPGP t))
+ (signature (car pair)))
+ (unless (stringp signature)
+ (error "Signature failed"))
+ (goto-char (point-min))
+ (insert (format "Sig: t=p; b=%s\n"
+ (pgpsig-armor-to-wrapped-b64 signature)))
+ (let ((boundary (mml-compute-boundary cont)))
+ (goto-char (point-min))
+ (insert (format "Content-Type: multipart/mixed; boundary=\"%s\";\n"
+ boundary))
+ (insert (format "\n--%s\n" boundary))
+ (goto-char (point-max))
+ (insert (format "\n--%s--\n" boundary))
+ (goto-char (point-max)))))
+
;;; General wrapper
(autoload 'gnus-buffer-live-p "gnus-util")
--
2.47.2
[0003-mml-Add-C-c-RET-s-u-to-make-Unobtrusive-Signature.patch (text/x-diff, inline)]
From 8ec14c812328ae1b4180656f8813211d83215b42 Mon Sep 17 00:00:00 2001
From: Daniel Kahn Gillmor <dkg <at> fifthhorseman.net>
Date: Thu, 15 May 2025 22:03:25 -0400
Subject: [PATCH 3/3] mml: Add C-c RET s u to make Unobtrusive Signature
This adds to the default keymap to make it relatively easy to make an
Unobtrusive Signature when sending mail.
Unobtrusive Signatures are defined on a per-message basis, and
explicitly ignored per-part, so we do not facilitate part-based signing.
---
lisp/gnus/mml-sec.el | 5 +++++
lisp/gnus/mml.el | 3 ++-
2 files changed, 7 insertions(+), 1 deletion(-)
diff --git a/lisp/gnus/mml-sec.el b/lisp/gnus/mml-sec.el
index 6fb82836e9a..71913c8e8cc 100644
--- a/lisp/gnus/mml-sec.el
+++ b/lisp/gnus/mml-sec.el
@@ -399,6 +399,11 @@ Use METHOD if given. Else use `mml-secure-method' or
(or method mml-secure-method mml-default-sign-method)
'encrypt))
+(defun mml-secure-message-sign-unobtrusive ()
+ "Add MML tag to encrypt/sign the entire message."
+ (interactive nil mml-mode)
+ (mml-secure-message "unobtrusive" 'sign))
+
(defun mml-secure-message-sign-smime ()
"Add MML tag to encrypt/sign the entire message."
(interactive nil mml-mode)
diff --git a/lisp/gnus/mml.el b/lisp/gnus/mml.el
index 8e37dbe0bf6..0667c937803 100644
--- a/lisp/gnus/mml.el
+++ b/lisp/gnus/mml.el
@@ -1181,7 +1181,8 @@ If HANDLES is non-nil, use it instead reparsing the buffer."
"s" (define-keymap
"p" #'mml-secure-message-sign-pgpmime
"o" #'mml-secure-message-sign-pgp
- "s" #'mml-secure-message-sign-smime)
+ "s" #'mml-secure-message-sign-smime
+ "u" #'mml-secure-message-sign-unobtrusive)
"S" (define-keymap
"p" #'mml-secure-sign-pgpmime
"o" #'mml-secure-sign-pgp
--
2.47.2
bug-gnu-emacs <at> gnu.org, bugs <at> gnus.org:bug#78448; Package emacs,gnus.
(Fri, 13 Jun 2025 17:59:03 GMT) Full text and rfc822 format available.Message #41 received at 78448 <at> debbugs.gnu.org (full text, mbox):
From: Daniel Kahn Gillmor <dkg <at> fifthhorseman.net> To: Robert Pluim <rpluim <at> gmail.com> Cc: eric <at> ericabrahamsen.net, 78448 <at> debbugs.gnu.org, Eli Zaretskii <eliz <at> gnu.org>, rms <at> gnu.org, Michael Richardson <mcr <at> sandelman.ca> Subject: Re: bug#78448: 30.1; mml: Produce Unobtrusive Signatures Date: Fri, 13 Jun 2025 12:22:14 -0400
[Message part 1 (text/plain, inline)]
On Mon 2025-06-09 18:54:01 -0400, Daniel Kahn Gillmor wrote: > I'm including the three revised patches here. Michael Richardson observed that I had an extra semicolon which might cause a complaint (see the patch here, which you might decide you want to merge down into patch 0002 when applying). I'm grateful for his attention to detail! --dkg
[0004-Remove-stray-semicolon.patch (text/x-diff, inline)]
From d15a519c3c8d9cad72a827f8fba24fb79df25db5 Mon Sep 17 00:00:00 2001
From: Daniel Kahn Gillmor <dkg <at> fifthhorseman.net>
Date: Thu, 12 Jun 2025 18:06:22 -0400
Subject: [PATCH] Remove stray semicolon
Identified by Michael Richardson <mcr <at> sandelman.ca>
---
lisp/gnus/mml2015.el | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lisp/gnus/mml2015.el b/lisp/gnus/mml2015.el
index bbe6cec589f..503b7a8a5fa 100644
--- a/lisp/gnus/mml2015.el
+++ b/lisp/gnus/mml2015.el
@@ -977,7 +977,7 @@ If set, it overrides the setting of `mml2015-sign-with-sender'."
(pgpsig-armor-to-wrapped-b64 signature)))
(let ((boundary (mml-compute-boundary cont)))
(goto-char (point-min))
- (insert (format "Content-Type: multipart/mixed; boundary=\"%s\";\n"
+ (insert (format "Content-Type: multipart/mixed; boundary=\"%s\"\n"
boundary))
(insert (format "\n--%s\n" boundary))
(goto-char (point-max))
--
2.47.2
bug-gnu-emacs <at> gnu.org, bugs <at> gnus.org:bug#78448; Package emacs,gnus.
(Wed, 29 Oct 2025 16:32:01 GMT) Full text and rfc822 format available.Message #44 received at 78448 <at> debbugs.gnu.org (full text, mbox):
From: Daniel Kahn Gillmor <dkg <at> fifthhorseman.net> To: 78448 <at> debbugs.gnu.org, Eli Zaretskii <eliz <at> gnu.org> Subject: Re: 30.1; mml: Produce Unobtrusive Signatures Date: Wed, 29 Oct 2025 12:30:30 -0400
Hey folks--
Just wondering where this work on emitting unobtrusive signatures stands
in terms of merging.
If I understand correctly, all the paperwork involving my employer and
the FSF has been completed.
I just checked, and the series looks to me like it applies cleanly to
the emacs-30 branch and to the master branch as seen on
https://git.savannah.gnu.org/git/emacs.git
Please let me know if there's anything else you'd like me to improve!
--dkg
bug-gnu-emacs <at> gnu.org, bugs <at> gnus.org:bug#78448; Package emacs,gnus.
(Wed, 29 Oct 2025 17:02:01 GMT) Full text and rfc822 format available.Message #47 received at 78448 <at> debbugs.gnu.org (full text, mbox):
From: Eli Zaretskii <eliz <at> gnu.org> To: Daniel Kahn Gillmor <dkg <at> fifthhorseman.net>, Robert Pluim <rpluim <at> gmail.com> Cc: 78448 <at> debbugs.gnu.org Subject: Re: 30.1; mml: Produce Unobtrusive Signatures Date: Wed, 29 Oct 2025 19:00:30 +0200
> From: Daniel Kahn Gillmor <dkg <at> fifthhorseman.net> > Date: Wed, 29 Oct 2025 12:30:30 -0400 > > Hey folks-- > > Just wondering where this work on emitting unobtrusive signatures stands > in terms of merging. > > If I understand correctly, all the paperwork involving my employer and > the FSF has been completed. Sorry, I don't see your assignment on file yet. Did you receive from the FSF the assignment signed both by you and by the FSF? If not, please ping them and CC me. > I just checked, and the series looks to me like it applies cleanly to > the emacs-30 branch and to the master branch as seen on > https://git.savannah.gnu.org/git/emacs.git > > Please let me know if there's anything else you'd like me to improve! I don't use Gnus, and Robert (CC'd) was the only one who reviewed the patches. If Robert is happy with the last version, we can install it, once your assignment paperwork is complete. Thanks.
bug-gnu-emacs <at> gnu.org, bugs <at> gnus.org:bug#78448; Package emacs,gnus.
(Sat, 15 Nov 2025 09:09:01 GMT) Full text and rfc822 format available.Message #50 received at 78448 <at> debbugs.gnu.org (full text, mbox):
From: Eli Zaretskii <eliz <at> gnu.org> To: rpluim <at> gmail.com Cc: 78448 <at> debbugs.gnu.org, dkg <at> fifthhorseman.net Subject: Re: bug#78448: 30.1; mml: Produce Unobtrusive Signatures Date: Sat, 15 Nov 2025 11:08:17 +0200
> Cc: 78448 <at> debbugs.gnu.org > Date: Wed, 29 Oct 2025 19:00:30 +0200 > From: Eli Zaretskii <eliz <at> gnu.org> > > > From: Daniel Kahn Gillmor <dkg <at> fifthhorseman.net> > > Date: Wed, 29 Oct 2025 12:30:30 -0400 > > > > Hey folks-- > > > > Just wondering where this work on emitting unobtrusive signatures stands > > in terms of merging. > > > > If I understand correctly, all the paperwork involving my employer and > > the FSF has been completed. > > Sorry, I don't see your assignment on file yet. > > Did you receive from the FSF the assignment signed both by you and by > the FSF? If not, please ping them and CC me. > > > I just checked, and the series looks to me like it applies cleanly to > > the emacs-30 branch and to the master branch as seen on > > https://git.savannah.gnu.org/git/emacs.git > > > > Please let me know if there's anything else you'd like me to improve! > > I don't use Gnus, and Robert (CC'd) was the only one who reviewed the > patches. If Robert is happy with the last version, we can install it, > once your assignment paperwork is complete. Robert, is it okay to install these changes? The copyright issue is resolved for these contributions, so if you are happy with the changes, please install them. Thanks.
bug-gnu-emacs <at> gnu.org, bugs <at> gnus.org:bug#78448; Package emacs,gnus.
(Sat, 15 Nov 2025 11:49:01 GMT) Full text and rfc822 format available.Message #53 received at 78448 <at> debbugs.gnu.org (full text, mbox):
From: Daniel Kahn Gillmor <dkg <at> fifthhorseman.net> To: Eli Zaretskii <eliz <at> gnu.org>, rpluim <at> gmail.com Cc: 78448 <at> debbugs.gnu.org Subject: Re: bug#78448: 30.1; mml: Produce Unobtrusive Signatures Date: Sat, 15 Nov 2025 06:48:44 -0500
[Message part 1 (text/plain, inline)]
On Sat 2025-11-15 11:08:17 +0200, Eli Zaretskii wrote:
> Robert, is it okay to install these changes? The copyright issue is
> resolved for these contributions, so if you are happy with the
> changes, please install them.
I'm glad this has been resolved now!
I think Robert asked me for a squashed patch, so i've done that, and I
offer it here.
Thanks for shepherding this process, Eli and Robert! Let me know if you
need anything else from me.
--dkg
[0001-mml-generate-unobtrusive-signatures.patch (text/x-diff, inline)]
From 708acaacb3e54c21d357b44007e422c9bda142c8 Mon Sep 17 00:00:00 2001
From: Daniel Kahn Gillmor <dkg <at> fifthhorseman.net>
Date: Thu, 15 May 2025 21:49:32 -0400
Subject: [PATCH] mml: generate unobtrusive signatures
- Pass likely headers through to mml-sec functions
By pre-computing the likely headers for an outbound message, and passing
them along as a tag in mml-parse, we create an opportunity to provide
Header Protection as described in
https://datatracker.ietf.org/doc/draft-ietf-lamps-header-protection/
- produce Unobtrusive Signatures via epg
https://datatracker.ietf.org/doc/draft-gallagher-email-invisible-signatures/
describes a mechanism to produce cleartext signatures over MIME messages
that are less likely to cause problems than traditional PGP/MIME.
With this patch, it's possible to produce those signatures with:
(mml-secure-message "unobtrusive" 'sign)
This patch only works with epg, not with mailcrypt or pgg, because epg
is what i'm familiar with and what i can easily test.
- Add C-c RET s u to make Unobtrusive Signature
This adds to the default keymap to make it relatively easy to make an
Unobtrusive Signature when sending mail.
Unobtrusive Signatures are defined on a per-message basis, and
explicitly ignored per-part, so we do not facilitate part-based signing.
---
lisp/gnus/mml-sec.el | 11 +++++++++++
lisp/gnus/mml.el | 20 +++++++++++++++++++-
lisp/gnus/mml2015.el | 39 +++++++++++++++++++++++++++++++++++++++
3 files changed, 69 insertions(+), 1 deletion(-)
diff --git a/lisp/gnus/mml-sec.el b/lisp/gnus/mml-sec.el
index 8dffcf872f3..71913c8e8cc 100644
--- a/lisp/gnus/mml-sec.el
+++ b/lisp/gnus/mml-sec.el
@@ -34,6 +34,7 @@
(autoload 'mail-strip-quoted-names "mail-utils")
(autoload 'mml2015-sign "mml2015")
(autoload 'mml2015-encrypt "mml2015")
+(autoload 'mml-unobtrusive-sign "mml2015")
(autoload 'mml1991-sign "mml1991")
(autoload 'mml1991-encrypt "mml1991")
(autoload 'message-fetch-field "message")
@@ -56,6 +57,7 @@
'(("smime" mml-smime-sign-buffer mml-smime-sign-query)
("pgp" mml-pgp-sign-buffer list)
("pgpauto" mml-pgpauto-sign-buffer list)
+ ("unobtrusive" mml-unobtrusive-sign-buffer list)
("pgpmime" mml-pgpmime-sign-buffer list))
"Alist of MIME signer functions.")
@@ -198,6 +200,10 @@ You can also customize or set `mml-signencrypt-style-alist' instead."
(or (mml2015-sign cont)
(error "Signing failed... inspect message logs for errors")))
+(defun mml-unobtrusive-sign-buffer (cont)
+ (or (mml-unobtrusive-sign cont)
+ (error "Signing failed... inspect message logs for errors")))
+
(defun mml-pgpmime-encrypt-buffer (cont &optional sign)
(or (mml2015-encrypt cont sign)
(error "Encryption failed... inspect message logs for errors")))
@@ -393,6 +399,11 @@ Use METHOD if given. Else use `mml-secure-method' or
(or method mml-secure-method mml-default-sign-method)
'encrypt))
+(defun mml-secure-message-sign-unobtrusive ()
+ "Add MML tag to encrypt/sign the entire message."
+ (interactive nil mml-mode)
+ (mml-secure-message "unobtrusive" 'sign))
+
(defun mml-secure-message-sign-smime ()
"Add MML tag to encrypt/sign the entire message."
(interactive nil mml-mode)
diff --git a/lisp/gnus/mml.el b/lisp/gnus/mml.el
index e53d35146e8..972f1bce0a1 100644
--- a/lisp/gnus/mml.el
+++ b/lisp/gnus/mml.el
@@ -265,6 +265,8 @@ part. This is for the internal use, you should never modify the value.")
(apply #'mml-insert-tag
secure-mode
`(,@tags
+ ,"likely-headers"
+ ,(mml-get-likely-headers)
,(if keyfile "keyfile")
,keyfile
,@(apply #'append
@@ -492,6 +494,21 @@ If MML is non-nil, return the buffer up till the correspondent mml tag."
(declare-function libxml-parse-html-region "xml.c"
(start end &optional base-url discard-comments))
+(defun mml-get-likely-headers ()
+ "Get likely final headers from the existing message"
+ (save-excursion
+ (save-restriction
+ (message-narrow-to-headers-or-head)
+ (let ((x (buffer-substring (point-min) (point-max))))
+ (with-temp-buffer
+ (insert x)
+ (message-remove-header "Bcc")
+ (message-remove-header message-ignored-mail-headers t)
+ (mail-encode-encoded-word-buffer)
+ (message-cleanup-headers)
+ (buffer-string)
+ )))))
+
(defun mml-generate-mime (&optional multipart-type content-type)
"Generate a MIME message based on the current MML document.
MULTIPART-TYPE defaults to \"mixed\", but can also
@@ -1161,7 +1178,8 @@ If HANDLES is non-nil, use it instead reparsing the buffer."
"s" (define-keymap
"p" #'mml-secure-message-sign-pgpmime
"o" #'mml-secure-message-sign-pgp
- "s" #'mml-secure-message-sign-smime)
+ "s" #'mml-secure-message-sign-smime
+ "u" #'mml-secure-message-sign-unobtrusive)
"S" (define-keymap
"p" #'mml-secure-sign-pgpmime
"o" #'mml-secure-sign-pgp
diff --git a/lisp/gnus/mml2015.el b/lisp/gnus/mml2015.el
index a46aa68f56a..646fb018a31 100644
--- a/lisp/gnus/mml2015.el
+++ b/lisp/gnus/mml2015.el
@@ -25,6 +25,9 @@
;; RFC 2015 is updated by RFC 3156, this file should be compatible
;; with both.
+;; This is also capable of producing unobtrusive signatures based on
+;; draft-gallagher-email-unobtrusive-signatures
+
;;; Code:
(eval-when-compile (require 'cl-lib))
@@ -945,6 +948,42 @@ If set, it overrides the setting of `mml2015-sign-with-sender'."
(insert (format "--%s--\n" boundary))
(goto-char (point-max))))
+;;; Unobtrusive Signatures, see:
+;;; https://datatracker.ietf.org/doc/draft-gallagher-email-unobtrusive-signatures/
+
+; convert ASCII-armored PGP SIGNATURE block to base64-encoded with FWS
+; at the start of each line:
+(defun pgpsig-armor-to-wrapped-b64 (s)
+ (string-join
+ (string-split
+ (string-trim-right
+ (string-trim-left s "-----BEGIN PGP SIGNATURE-----\n\\(?:[^\n]+\n\\)*\n")
+ "\n\\(?:=....\n\\)?-----END PGP SIGNATURE-----\n?")
+ "\n")
+ "\n "))
+
+(defun mml-unobtrusive-sign (cont)
+ (goto-char (point-min))
+ (insert (cdr (assq 'likely-headers cont)))
+ (re-search-forward "^Content-Type: [^\n]*\\(\n[ \t][^\n]*$\\)*")
+ (insert "; hp=\"clear\"")
+ (re-search-forward "^")
+ (let* ((pair (mml-secure-epg-sign 'OpenPGP t))
+ (signature (car pair)))
+ (unless (stringp signature)
+ (error "Signature failed"))
+ (goto-char (point-min))
+ (insert (format "Sig: t=p; b=%s\n"
+ (pgpsig-armor-to-wrapped-b64 signature)))
+ (let ((boundary (mml-compute-boundary cont)))
+ (goto-char (point-min))
+ (insert (format "Content-Type: multipart/mixed; boundary=\"%s\";\n"
+ boundary))
+ (insert (format "\n--%s\n" boundary))
+ (goto-char (point-max))
+ (insert (format "\n--%s--\n" boundary))
+ (goto-char (point-max)))))
+
;;; General wrapper
(autoload 'gnus-buffer-live-p "gnus-util")
--
2.51.0
[signature.asc (application/pgp-signature, inline)]
bug-gnu-emacs <at> gnu.org, bugs <at> gnus.org:bug#78448; Package emacs,gnus.
(Thu, 20 Nov 2025 15:17:02 GMT) Full text and rfc822 format available.Message #56 received at 78448 <at> debbugs.gnu.org (full text, mbox):
From: Robert Pluim <rpluim <at> gmail.com> To: Daniel Kahn Gillmor <dkg <at> fifthhorseman.net> Cc: 78448 <at> debbugs.gnu.org, Eli Zaretskii <eliz <at> gnu.org> Subject: Re: bug#78448: 30.1; mml: Produce Unobtrusive Signatures Date: Thu, 20 Nov 2025 16:16:09 +0100
>>>>> On Sat, 15 Nov 2025 06:48:44 -0500, Daniel Kahn Gillmor <dkg <at> fifthhorseman.net> said:
Daniel> On Sat 2025-11-15 11:08:17 +0200, Eli Zaretskii wrote:
>> Robert, is it okay to install these changes? The copyright issue is
>> resolved for these contributions, so if you are happy with the
>> changes, please install them.
Daniel> I'm glad this has been resolved now!
Daniel> I think Robert asked me for a squashed patch, so i've done that, and I
Daniel> offer it here.
Daniel> Thanks for shepherding this process, Eli and Robert! Let me know if you
Daniel> need anything else from me.
I get byte-compiler warnings after I apply the patch, could you take a
look?
Also, we normally require a ChangeLog style commit message. I can
write one for this change and show it to you.
Thanks
Robert
--
bug-gnu-emacs <at> gnu.org, bugs <at> gnus.org:bug#78448; Package emacs,gnus.
(Tue, 25 Nov 2025 20:17:23 GMT) Full text and rfc822 format available.Message #59 received at 78448 <at> debbugs.gnu.org (full text, mbox):
From: Daniel Kahn Gillmor <dkg <at> fifthhorseman.net> To: Robert Pluim <rpluim <at> gmail.com> Cc: 78448 <at> debbugs.gnu.org, Eli Zaretskii <eliz <at> gnu.org> Subject: Re: bug#78448: 30.1; mml: Produce Unobtrusive Signatures Date: Fri, 21 Nov 2025 11:01:34 -0500
[Message part 1 (text/plain, inline)]
Hi Robert--
On Thu 2025-11-20 16:16:09 +0100, Robert Pluim wrote:
> I get byte-compiler warnings after I apply the patch, could you take a
> look?
I'd be happy to look further. What byte-compiler warnings are you
seeing? What steps do you take to trigger those warnings?
> Also, we normally require a ChangeLog style commit message. I can
> write one for this change and show it to you.
Thanks, i'd appreciate that. I'm used to intent-oriented commit
messages, since they explain the *why* of the change; I usually let the
diff itself shows what specifically changed. But i'm happy to use
whatever is the preferred convention.
--dkg
[signature.asc (application/pgp-signature, inline)]
bug-gnu-emacs <at> gnu.org, bugs <at> gnus.org:bug#78448; Package emacs,gnus.
(Fri, 05 Dec 2025 23:17:02 GMT) Full text and rfc822 format available.Message #62 received at 78448 <at> debbugs.gnu.org (full text, mbox):
From: Daniel Kahn Gillmor <dkg <at> fifthhorseman.net> To: Robert Pluim <rpluim <at> gmail.com> Cc: 78448 <at> debbugs.gnu.org, Eli Zaretskii <eliz <at> gnu.org> Subject: Re: bug#78448: 30.1; mml: Produce Unobtrusive Signatures Date: Fri, 05 Dec 2025 18:16:01 -0500
[Message part 1 (text/plain, inline)]
Hi Robert--
On Fri 2025-11-21 11:01:34 -0500, Daniel Kahn Gillmor wrote:
> On Thu 2025-11-20 16:16:09 +0100, Robert Pluim wrote:
>> I get byte-compiler warnings after I apply the patch, could you take a
>> look?
>
> I'd be happy to look further. What byte-compiler warnings are you
> seeing? What steps do you take to trigger those warnings?
>
>> Also, we normally require a ChangeLog style commit message. I can
>> write one for this change and show it to you.
I think i've identified th byte-compiler warnings and cleaned them up by
forward-declaring some functions and variables.
I also identified some logic in mml.el that caused a spurious warning
(to *Messages*) when signing, based on a presumption that the elements
in mml-sign-alist matched mml-encryptsign-alist. Since unobtrusive
signatures are only acceptable in signed-only mail, that assumption is
no longer true. I've included a patch that avoids that error without
changing the underlying logic.
Since unobtrusive signatures are now formally adopted by the IETF's
MAILMAINT working group, i've also updated comments to point to the
specification's new landing page.
I've also updated the commit message to be in what i think is "Changelog
style". Please let me know if you have any other concerns or
recommendations. It would be great to get this landed in mml-mode!
All the best,
--dkg
[0001-mml-Enable-generation-of-Unobtrusively-Signed-mail-m.patch (text/x-diff, inline)]
From 91bab92ab2e6e6ea3a56403ea3c41b01a4258451 Mon Sep 17 00:00:00 2001
From: Daniel Kahn Gillmor <dkg <at> fifthhorseman.net>
Date: Thu, 15 May 2025 21:49:32 -0400
Subject: [PATCH] mml: Enable generation of Unobtrusively Signed mail messages
Implement draft-ietf-mailmaint-email-unobtrusive-signatures (Bug#78448)
* lisp/gnus/mml2015.el (pgpsig-armor-to-wrapped-b64): new function.
(mml-unobtrusive-sign): new function.
* lisp/gnus/mml.el (mml-get-likely-headers): predict
headers for the newly composed message. (mml-parse-1): copy likely
headers to a tag during message parsing. (mml-mode-map): add
keybinding "C-c RET s u" to create an unobtrusively signed
message. (mml-generate-mime-1): clean up logic to avoid invoking
mml-signencrypt-style when message is not encrypted.
* lisp/gnus/mml-sec.el (mml-unobtrusive-sign-buffer,
mml-secure-message-sign-unobtrusive): new functions, using likely
headers for RFC 9788 Header Protection. (mml-sign-alist):
Add "unobtrusive" as a signature style.
--
https://datatracker.ietf.org/doc/draft-ietf-mailmaint-email-unobtrusive-signatures/
describes a way to generate signed e-mail messages that will not cause
problems with legacy mail user agents.
This patch lets mml generate this sort of signature on outbound
signed-only mail.
Unobtrusive signatures require RFC 9788-style header protection, so this
patch enables that sort of header protection as well during the signing process.
This patch only works with epg, not with mailcrypt or pgg.
---
lisp/gnus/mml-sec.el | 11 +++++++++
lisp/gnus/mml.el | 57 +++++++++++++++++++++++++++++---------------
lisp/gnus/mml2015.el | 39 ++++++++++++++++++++++++++++++
3 files changed, 88 insertions(+), 19 deletions(-)
diff --git a/lisp/gnus/mml-sec.el b/lisp/gnus/mml-sec.el
index 8dffcf872f3..71913c8e8cc 100644
--- a/lisp/gnus/mml-sec.el
+++ b/lisp/gnus/mml-sec.el
@@ -34,6 +34,7 @@
(autoload 'mail-strip-quoted-names "mail-utils")
(autoload 'mml2015-sign "mml2015")
(autoload 'mml2015-encrypt "mml2015")
+(autoload 'mml-unobtrusive-sign "mml2015")
(autoload 'mml1991-sign "mml1991")
(autoload 'mml1991-encrypt "mml1991")
(autoload 'message-fetch-field "message")
@@ -56,6 +57,7 @@
'(("smime" mml-smime-sign-buffer mml-smime-sign-query)
("pgp" mml-pgp-sign-buffer list)
("pgpauto" mml-pgpauto-sign-buffer list)
+ ("unobtrusive" mml-unobtrusive-sign-buffer list)
("pgpmime" mml-pgpmime-sign-buffer list))
"Alist of MIME signer functions.")
@@ -198,6 +200,10 @@ You can also customize or set `mml-signencrypt-style-alist' instead."
(or (mml2015-sign cont)
(error "Signing failed... inspect message logs for errors")))
+(defun mml-unobtrusive-sign-buffer (cont)
+ (or (mml-unobtrusive-sign cont)
+ (error "Signing failed... inspect message logs for errors")))
+
(defun mml-pgpmime-encrypt-buffer (cont &optional sign)
(or (mml2015-encrypt cont sign)
(error "Encryption failed... inspect message logs for errors")))
@@ -393,6 +399,11 @@ Use METHOD if given. Else use `mml-secure-method' or
(or method mml-secure-method mml-default-sign-method)
'encrypt))
+(defun mml-secure-message-sign-unobtrusive ()
+ "Add MML tag to encrypt/sign the entire message."
+ (interactive nil mml-mode)
+ (mml-secure-message "unobtrusive" 'sign))
+
(defun mml-secure-message-sign-smime ()
"Add MML tag to encrypt/sign the entire message."
(interactive nil mml-mode)
diff --git a/lisp/gnus/mml.el b/lisp/gnus/mml.el
index e53d35146e8..3154b6d326a 100644
--- a/lisp/gnus/mml.el
+++ b/lisp/gnus/mml.el
@@ -40,10 +40,11 @@
(autoload 'message-posting-charset "message")
(autoload 'dnd-get-local-file-name "dnd")
-(autoload 'message-options-set "message")
-(autoload 'message-narrow-to-head "message")
-(autoload 'message-in-body-p "message")
-(autoload 'message-mail-p "message")
+(autoload 'message-options-set "message")
+(autoload 'message-narrow-to-head "message")
+(autoload 'message-in-body-p "message")
+(autoload 'message-mail-p "message")
+(autoload 'message-cleanup-headers "message")
(defvar gnus-article-mime-handles)
(defvar gnus-newsrc-hashtb)
@@ -51,6 +52,7 @@
(defvar message-options)
(defvar message-posting-charset)
(defvar message-required-mail-headers)
+(defvar message-ignored-mail-headers)
(defvar message-required-news-headers)
(defvar dnd-protocol-alist)
(defvar mml-dnd-protocol-alist)
@@ -265,6 +267,8 @@ part. This is for the internal use, you should never modify the value.")
(apply #'mml-insert-tag
secure-mode
`(,@tags
+ ,"likely-headers"
+ ,(mml-get-likely-headers)
,(if keyfile "keyfile")
,keyfile
,@(apply #'append
@@ -492,6 +496,21 @@ If MML is non-nil, return the buffer up till the correspondent mml tag."
(declare-function libxml-parse-html-region "xml.c"
(start end &optional base-url discard-comments))
+(defun mml-get-likely-headers ()
+ "Get likely final headers from the existing message"
+ (save-excursion
+ (save-restriction
+ (message-narrow-to-headers-or-head)
+ (let ((x (buffer-substring (point-min) (point-max))))
+ (with-temp-buffer
+ (insert x)
+ (message-remove-header "Bcc")
+ (message-remove-header message-ignored-mail-headers t)
+ (mail-encode-encoded-word-buffer)
+ (message-cleanup-headers)
+ (buffer-string)
+ )))))
+
(defun mml-generate-mime (&optional multipart-type content-type)
"Generate a MIME message based on the current MML document.
MULTIPART-TYPE defaults to \"mixed\", but can also
@@ -832,20 +851,19 @@ type detected."
(message-options-set 'message-sender sender))
(if (setq recipients (cdr (assq 'recipients cont)))
(message-options-set 'message-recipients recipients))
- (let ((style (mml-signencrypt-style
- (car (or sign-item encrypt-item)))))
- ;; check if: we're both signing & encrypting, both methods
- ;; are the same (why would they be different?!), and that
- ;; the signencrypt style allows for combined operation.
- (if (and sign-item encrypt-item (equal (car sign-item)
- (car encrypt-item))
- (equal style 'combined))
- (funcall (nth 1 encrypt-item) cont t)
- ;; otherwise, revert to the old behavior.
- (when sign-item
- (funcall (nth 1 sign-item) cont))
- (when encrypt-item
- (funcall (nth 1 encrypt-item) cont)))))))))
+ ;; check if: we're both signing & encrypting, both methods
+ ;; are the same (why would they be different?!), and that
+ ;; the signencrypt style allows for combined operation.
+ (if (and sign-item encrypt-item (equal (car sign-item)
+ (car encrypt-item))
+ (equal 'combined (mml-signencrypt-style
+ (car encrypt-item))))
+ (funcall (nth 1 encrypt-item) cont t)
+ ;; otherwise, revert to the old behavior.
+ (when sign-item
+ (funcall (nth 1 sign-item) cont))
+ (when encrypt-item
+ (funcall (nth 1 encrypt-item) cont))))))))
(defun mml-compute-boundary (cont)
"Return a unique boundary that does not exist in CONT."
@@ -1161,7 +1179,8 @@ If HANDLES is non-nil, use it instead reparsing the buffer."
"s" (define-keymap
"p" #'mml-secure-message-sign-pgpmime
"o" #'mml-secure-message-sign-pgp
- "s" #'mml-secure-message-sign-smime)
+ "s" #'mml-secure-message-sign-smime
+ "u" #'mml-secure-message-sign-unobtrusive)
"S" (define-keymap
"p" #'mml-secure-sign-pgpmime
"o" #'mml-secure-sign-pgp
diff --git a/lisp/gnus/mml2015.el b/lisp/gnus/mml2015.el
index a46aa68f56a..45b64d5246f 100644
--- a/lisp/gnus/mml2015.el
+++ b/lisp/gnus/mml2015.el
@@ -25,6 +25,9 @@
;; RFC 2015 is updated by RFC 3156, this file should be compatible
;; with both.
+;; This is also capable of producing unobtrusive signatures based on
+;; draft-ietf-mailmaint-email-unobtrusive-signatures
+
;;; Code:
(eval-when-compile (require 'cl-lib))
@@ -945,6 +948,42 @@ If set, it overrides the setting of `mml2015-sign-with-sender'."
(insert (format "--%s--\n" boundary))
(goto-char (point-max))))
+;;; Unobtrusive Signatures, see:
+;;; https://datatracker.ietf.org/doc/draft-ietf-mailmaint-email-unobtrusive-signatures/
+
+; convert ASCII-armored PGP SIGNATURE block to base64-encoded with FWS
+; at the start of each line:
+(defun pgpsig-armor-to-wrapped-b64 (s)
+ (string-join
+ (string-split
+ (string-trim-right
+ (string-trim-left s "-----BEGIN PGP SIGNATURE-----\n\\(?:[^\n]+\n\\)*\n")
+ "\n\\(?:=....\n\\)?-----END PGP SIGNATURE-----\n?")
+ "\n")
+ "\n "))
+
+(defun mml-unobtrusive-sign (cont)
+ (goto-char (point-min))
+ (insert (cdr (assq 'likely-headers cont)))
+ (re-search-forward "^Content-Type: [^\n]*\\(\n[ \t][^\n]*$\\)*")
+ (insert "; hp=\"clear\"")
+ (re-search-forward "^")
+ (let* ((pair (mml-secure-epg-sign 'OpenPGP t))
+ (signature (car pair)))
+ (unless (stringp signature)
+ (error "Signature failed"))
+ (goto-char (point-min))
+ (insert (format "Sig: t=p; b=%s\n"
+ (pgpsig-armor-to-wrapped-b64 signature)))
+ (let ((boundary (mml-compute-boundary cont)))
+ (goto-char (point-min))
+ (insert (format "Content-Type: multipart/mixed; boundary=\"%s\";\n"
+ boundary))
+ (insert (format "\n--%s\n" boundary))
+ (goto-char (point-max))
+ (insert (format "\n--%s--\n" boundary))
+ (goto-char (point-max)))))
+
;;; General wrapper
(autoload 'gnus-buffer-live-p "gnus-util")
--
2.51.0
[signature.asc (application/pgp-signature, inline)]
bug-gnu-emacs <at> gnu.org, bugs <at> gnus.org:bug#78448; Package emacs,gnus.
(Wed, 17 Dec 2025 15:49:02 GMT) Full text and rfc822 format available.Message #65 received at 78448 <at> debbugs.gnu.org (full text, mbox):
From: Daniel Kahn Gillmor <dkg <at> fifthhorseman.net> To: Robert Pluim <rpluim <at> gmail.com> Cc: 78448 <at> debbugs.gnu.org, Eli Zaretskii <eliz <at> gnu.org> Subject: Re: bug#78448: 30.1; mml: Produce Unobtrusive Signatures Date: Wed, 17 Dec 2025 10:48:28 -0500
[Message part 1 (text/plain, inline)]
Hi Robert, Eli--
Just a nudge here for unobtrusive signatures. It looks to me like
everything is in order:
- copyright assignment paperwork is completed
- byte-compiler warnings are resolved
- spurious Message warning is avoided
- code merged down to a single patch
- commit message is in (what i think is) changelog style
Do y'all need anything else from me to land this in emacs?
--dkg
bug-gnu-emacs <at> gnu.org, bugs <at> gnus.org:bug#78448; Package emacs,gnus.
(Wed, 17 Dec 2025 16:46:01 GMT) Full text and rfc822 format available.Message #68 received at 78448 <at> debbugs.gnu.org (full text, mbox):
From: Eli Zaretskii <eliz <at> gnu.org> To: Daniel Kahn Gillmor <dkg <at> fifthhorseman.net> Cc: 78448 <at> debbugs.gnu.org, rpluim <at> gmail.com Subject: Re: bug#78448: 30.1; mml: Produce Unobtrusive Signatures Date: Wed, 17 Dec 2025 18:45:37 +0200
> From: Daniel Kahn Gillmor <dkg <at> fifthhorseman.net> > Cc: Eli Zaretskii <eliz <at> gnu.org>, 78448 <at> debbugs.gnu.org > Date: Wed, 17 Dec 2025 10:48:28 -0500 > > Hi Robert, Eli-- > > Just a nudge here for unobtrusive signatures. It looks to me like > everything is in order: > > - copyright assignment paperwork is completed > - byte-compiler warnings are resolved > - spurious Message warning is avoided > - code merged down to a single patch > - commit message is in (what i think is) changelog style > > Do y'all need anything else from me to land this in emacs? I'd like Robert to review the latest version of the patch.
bug-gnu-emacs <at> gnu.org, bugs <at> gnus.org:bug#78448; Package emacs,gnus.
(Thu, 18 Dec 2025 09:44:02 GMT) Full text and rfc822 format available.Message #71 received at 78448 <at> debbugs.gnu.org (full text, mbox):
From: Robert Pluim <rpluim <at> gmail.com> To: Eli Zaretskii <eliz <at> gnu.org> Cc: 78448 <at> debbugs.gnu.org, Daniel Kahn Gillmor <dkg <at> fifthhorseman.net> Subject: Re: bug#78448: 30.1; mml: Produce Unobtrusive Signatures Date: Thu, 18 Dec 2025 10:43:13 +0100
>>>>> On Wed, 17 Dec 2025 18:45:37 +0200, Eli Zaretskii <eliz <at> gnu.org> said:
>> From: Daniel Kahn Gillmor <dkg <at> fifthhorseman.net>
>> Cc: Eli Zaretskii <eliz <at> gnu.org>, 78448 <at> debbugs.gnu.org
>> Date: Wed, 17 Dec 2025 10:48:28 -0500
>>
>> Hi Robert, Eli--
>>
>> Just a nudge here for unobtrusive signatures. It looks to me like
>> everything is in order:
>>
>> - copyright assignment paperwork is completed
>> - byte-compiler warnings are resolved
>> - spurious Message warning is avoided
>> - code merged down to a single patch
>> - commit message is in (what i think is) changelog style
>>
>> Do y'all need anything else from me to land this in emacs?
Eli> I'd like Robert to review the latest version of the patch.
Itʼs first on my list of marked messages. The holiday season starts
soon, so Iʼll get to it then.
Robert
--
bug-gnu-emacs <at> gnu.org, bugs <at> gnus.org:bug#78448; Package emacs,gnus.
(Wed, 31 Dec 2025 17:36:02 GMT) Full text and rfc822 format available.Message #74 received at 78448 <at> debbugs.gnu.org (full text, mbox):
From: Daniel Kahn Gillmor <dkg <at> fifthhorseman.net> To: Robert Pluim <rpluim <at> gmail.com>, Eli Zaretskii <eliz <at> gnu.org> Cc: 78448 <at> debbugs.gnu.org Subject: Re: bug#78448: 30.1; mml: Produce Unobtrusive Signatures Date: Wed, 31 Dec 2025 12:35:40 -0500
[Message part 1 (text/plain, inline)]
On Thu 2025-12-18 10:43:13 +0100, Robert Pluim wrote:
>>>>>> On Wed, 17 Dec 2025 18:45:37 +0200, Eli Zaretskii <eliz <at> gnu.org> said:
> Eli> I'd like Robert to review the latest version of the patch.
>
> Itʼs first on my list of marked messages. The holiday season starts
> soon, so Iʼll get to it then.
Just a gentle nudge, hoping to move this along. Robert, please let me
know if i can do anything to help with the review.
Wishing you all a happy new year, if you're into this whole Gregorian
calendar thing.
--dkg
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.