From mboxrd@z Thu Jan 1 00:00:00 1970 X-Msuck: nntp://news.gmane.io/gmane.emacs.gnus.general/28842 Path: main.gmane.org!not-for-mail From: Florian Weimer Newsgroups: gmane.emacs.gnus.general Subject: Re: Request: Mails that are encrypted and/or signed using MIME Date: 18 Jan 2000 22:31:16 +0100 Sender: owner-ding@hpc.uh.edu Message-ID: <87bt6j5aor.fsf@deneb.cygnus.argh.org> References: NNTP-Posting-Host: coloc-standby.netfonds.no Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Trace: main.gmane.org 1035165618 31938 80.91.224.250 (21 Oct 2002 02:00:18 GMT) X-Complaints-To: usenet@main.gmane.org NNTP-Posting-Date: Mon, 21 Oct 2002 02:00:18 +0000 (UTC) Return-Path: Original-Received: from bart.math.uh.edu (bart.math.uh.edu [129.7.128.48]) by mailhost.sclp.com (Postfix) with ESMTP id 923BED051E for ; Wed, 19 Jan 2000 01:37:38 -0500 (EST) Original-Received: from sina.hpc.uh.edu (lists@Sina.HPC.UH.EDU [129.7.3.5]) by bart.math.uh.edu (8.9.1/8.9.1) with ESMTP id AAB13518; Wed, 19 Jan 2000 00:36:32 -0600 (CST) Original-Received: by sina.hpc.uh.edu (TLB v0.09a (1.20 tibbs 1996/10/09 22:03:07)); Wed, 19 Jan 2000 00:32:12 -0600 (CST) Original-Received: from mailhost.sclp.com (postfix@sclp3.sclp.com [204.252.123.139]) by sina.hpc.uh.edu (8.9.3/8.9.3) with ESMTP id AAA26289 for ; Wed, 19 Jan 2000 00:31:50 -0600 (CST) Original-Received: from mail.cid.net (cephyr.cid.net [212.172.21.2]) by mailhost.sclp.com (Postfix) with ESMTP id 991B1D051E for ; Wed, 19 Jan 2000 01:31:39 -0500 (EST) Original-Received: from uucp by mail.cid.net (Exim 3.11) with local-bsmtp id 12AoeO-0005ui-00; Wed, 19 Jan 2000 07:31:28 +0100 Original-Received: from deneb.cygnus.argh.org ([192.168.1.2]) by cygnus.argh.org with esmtp (Exim 3.12 #1) id 12AocG-000062-00 for ding@gnus.org; Wed, 19 Jan 2000 07:29:16 +0100 Original-Received: from fw by deneb.cygnus.argh.org with local (Exim 3.12 #1) id 12AgDd-0006cx-00 for ding@gnus.org; Tue, 18 Jan 2000 22:31:17 +0100 Original-To: ding@gnus.org In-Reply-To: Jonas Steverud's message of "18 Jan 2000 17:09:37 +0100" Original-Lines: 428 User-Agent: Gnus/5.0804 (Gnus v5.8.4) Emacs/20.4 Precedence: list X-Majordomo: 1.94.jlt7 Xref: main.gmane.org gmane.emacs.gnus.general:28842 X-Report-Spam: http://spam.gmane.org/gmane.emacs.gnus.general:28842 --=-=-= Jonas Steverud writes: > I currently tries to write some code that would make Gnus and > Mailcrypt aware of PGP-MIME. > > 1. I need examples. Could someone send me one mail encrypted and one > mail signed with the Subject "PGP-MIME test"? If you're doing MIME-PGP development, it's quite handy to have mutt installed. ;) RFC 2015 contains some examples as well. Here're are some old explanations I wrote several months ago. --=-=-= Content-Disposition: inline I don't think that this hook can be used. Let's have a look at the following message which conforms to RFC 2015: ---------------------------------------------------------------------- Date: Sun, 13 Jun 1999 13:32:15 +0200 From: mutt@cygnus.stuttgart.netsurf.de To: Florian Weimer Subject: Signed with attachment X-Gnus-Mail-Source: directory:~/Mail/INCOMING/ Message-ID: <19990613133215.B2917@deneb.cygnus.stuttgart.netsurf.de> Mime-Version: 1.0 Content-Type: multipart/signed; boundary=YD3LsXFS42OYHhNZ; micalg=pgp-md5; protocol="application/pgp-signature" X-Mailer: Mutt 0.95.1i Lines: 50 Xref: deneb.cygnus.stuttgart.netsurf.de misc:178 --YD3LsXFS42OYHhNZ Content-Type: multipart/mixed; boundary=ADZbWkCsHQ7r3kzd --ADZbWkCsHQ7r3kzd Content-Type: text/plain; charset=us-ascii Content-Description: Message A signed message with an attachment. --ADZbWkCsHQ7r3kzd Content-Type: text/plain; charset=us-ascii Content-Description: Assembler code Content-Disposition: attachment; filename="t.s" .file "t.c" .version "01.01" gcc2_compiled.: .text .align 4 .globl foo .type foo,@function foo: pushl %ebp movl %esp,%ebp movl 4660,%eax movl %ebp,%esp popl %ebp ret .Lfe1: .size foo,.Lfe1-foo .ident "GCC: (GNU) egcs-2.91.57 19980901 (egcs-1.1 release)" --ADZbWkCsHQ7r3kzd-- --YD3LsXFS42OYHhNZ Content-Type: application/pgp-signature -----BEGIN PGP SIGNATURE----- Version: 2.6.3i iQBFAwUBN2OWvzyNAitYx2a1AQHgRgGA5fYIevSaZao25ZMudtaN+PDAbLIze3rn aChV9rUthqm8lOp2nsD313AiGxpJwhr/ =eKxI -----END PGP SIGNATURE----- --YD3LsXFS42OYHhNZ-- ---------------------------------------------------------------------- The `micalg' and `protocol' parameters in the primary `Content-Type' header are vital, but it seems as if they aren't passed to functions listed in `gnus-mime-multipart-functions'. In addition, everything between the first and second `--YD3LsXFS42OYHhNZ' boundary is covered by the PGP signature, including the MIME headers and boundaries, which get lost during the translation from raw message text to MIME handles. [NOTE (January 2000): `mml-generate-multipart-alist' solves this.] Finally, in the `multipart/encrypted' case, as shown below, the encrypted part contains data which has to be put through the MIME translation process as well. This has not happend during the first translation, because obviously, the data contained in the part wasn't readable then. ---------------------------------------------------------------------- Date: Sun, 13 Jun 1999 12:17:23 +0200 From: mutt@cygnus.stuttgart.netsurf.de To: Florian Weimer Subject: test X-Gnus-Mail-Source: directory:~/Mail/INCOMING/ Message-ID: <19990613121723.A2917@deneb.cygnus.stuttgart.netsurf.de> Mime-Version: 1.0 Content-Type: multipart/encrypted; boundary=Kj7319i9nmIyA2yE; protocol="application/pgp-encrypted" X-Mailer: Mutt 0.95.1i Lines: 24 Xref: deneb.cygnus.stuttgart.netsurf.de misc:177 --Kj7319i9nmIyA2yE Content-Type: application/pgp-encrypted Version: 1 --Kj7319i9nmIyA2yE Content-Type: application/octet-stream -----BEGIN PGP MESSAGE----- Version: 2.6.3i hIwDbSMVHQQS92EBBACFUjqnO8eDDinYfo183PYgd7GQInt3BHhZCnRP807uGwra F2zAc4PBgGhBKYnU/nZiOZvqYVh+CA7JqjTzku0sM12RLg2R6bg2nB+V+CzOkK8R 5TQczKGI/Tyhs/ktej0pbMxR5rt5FwvDuB8hcCNKPPTfaeu/4RQsfnlaxsJXm4Q8 AzyNAitYx2a1AQGAug9oiCsl6+omafWxqlJBohEjXJCKjAASE9pfBHNqk6vhUMx3 qbLv6ai7AXOa9voApgAAAFwh2dnqGHsvY9WxPhIGgwkE9/CdjCX8p+jIG50F05Qe HUyZLv61ibRCm8EYEO2SBUO0brS2u7wtJuOhtGO03SLiDuPuZh2gaqIkpB7xwDxv T3BUKwC4W9ZIVybX7A== =oXnI -----END PGP MESSAGE----- --Kj7319i9nmIyA2yE-- ---------------------------------------------------------------------- The encrypted data looks like this (but it might contain attachments and other MIME mess as well): ---------------------------------------------------------------------- Content-Type: text/plain; charset=us-ascii Just another test ---------------------------------------------------------------------- IMHO, an appropiate hook into `mm-dissect-buffer' would allow to do all these things in a relatively straightforward manner. `gnus-mime-multipart-functions' could be used to put information gathered during the MIME translation process (signer, valid/invalid signature, beginning/end of signed data) into the *Article* buffer in a nicely formatted form. [...] --=-=-= > 2. Anyone else who writes or have written anything like this? I will > contact the people behind Mailcrypt ASAP. Below you find a message I sent to them a few months ago which summarizes the changes required for proper detached signature handling. I'm afraid, but I didn't get a reply. I'm working on a clean interface to GnuPG which is written from scratch, but I got carried away once more, this time by some Emacs bugs. :-/ Currently, it's complicated to get meaningful and machine-readable status codes for signatures from GnuPG or even PGP. A coworker of mine is working on a proposal for machine-readable status codes for OpenPGP signatures with standardized semantics. Discussions has just begun, but we plan to provide a sample implementation based on GnuPG. --=-=-= Content-Type: message/rfc822 Content-Disposition: inline To: Len Budney Subject: Mailcrypt support for detached signatures From: Florian Weimer Date: 10 Oct 1999 19:44:31 +0200 Message-ID: <87zoxrqfeo.fsf@deneb.cygnus.argh.org> User-Agent: Gnus/5.07009701 (Pterodactyl Gnus v0.97.1) Emacs/20.4 MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Lines: 243 Xref: deneb.cygnus.argh.org archive.1999-10.sent-mail:51 Hi! I'm working on MIME/PGP support for Pterodactyl Gnus. Of course, I'd like to use Mailcrypt, but I've discovered a few shortcomings: * No support for detached signatures. For the signing part, this is mostly trivial. Something like this could do the trick: (defun rfc2015-pgp-mc-sign-buffer (&optional id) "Replace the text in the current buffer with detached PGP signature. If non-nil, ID specifies the user ID which is used for signing. This function is a modifed version of `mc-pgp-sign-region' which generates a detached signature as required by RFC 2015. (All the code is based on Mailcrypt 3.5.3.) (let ((process-environment process-environment) (buffer (get-buffer-create mc-buffer-name)) passwd args key) (setq key (mc-pgp-lookup-key (or id mc-pgp-user-id))) (setq passwd (mc-activate-passwd (cdr key) (format "PGP passphrase for %s (%s): " (car key) (cdr key)))) (setenv "PGPPASSFD" "0") (setq args (list "-fasbt" "+verbose=1" "+language=en" "+batchmode" "-u" (cdr key))) (mc-process-region (point-min) (point-max) passwd mc-pgp-path args 'mc-pgp-generic-parser buffer))) (As you can see, I care only about PGP 2.6.x support at the moment.) There's a minor efficiency problem: the data which is being signed is replaced by the signature, but this doesn't matter currently. The verification is quite a bit harder. I had to modify `mc-process-region' because the original didn't suit the needs. Of course, the following is nothing more than a quick hack, but you'll get the idea anyway: (defun rfc2015-pgp-mc-process (passwd program args parser &optional buffer) "Like `mc-process-region', but doesn't send any data to PGP. PARSER is called with one argument, the exit status of PROGRAM." (let ((obuf (current-buffer)) (process-connection-type nil) mybuf result rgn proc) (unwind-protect (progn (setq mybuf (or buffer (generate-new-buffer " *mailcrypt temp"))) (set-buffer mybuf) (erase-buffer) (set-buffer obuf) (buffer-disable-undo mybuf) (setq proc (apply 'start-process "*PGP*" mybuf program args)) (if passwd (progn (process-send-string proc (concat passwd "\n")) (or mc-passwd-timeout (mc-deactivate-passwd t)))) (process-send-eof proc) (while (eq 'run (process-status proc)) (accept-process-output proc 5)) (setq result (process-exit-status proc)) ;; Hack to force a status_notify() in Emacs 19.29 (delete-process proc) (set-buffer mybuf) (goto-char (point-max)) (if (re-search-backward "\nProcess \\*PGP.*\n\\'" nil t) (delete-region (match-beginning 0) (match-end 0))) (goto-char (point-min)) ;; CRNL -> NL (while (search-forward "\r\n" nil t) (replace-match "\n")) ;; Hurm. FIXME; must get better result codes. (if (stringp result) (error "%s exited abnormally: '%s'" program result) (funcall parser result))) ;; Cleanup even on nonlocal exit (if (and proc (eq 'run (process-status proc))) (interrupt-process proc)) (set-buffer obuf) (or buffer (null mybuf) (kill-buffer mybuf))))) This addresses the output-replaces-input problem: (defun rfc2015-mc-process-region-preserve (beg end passwd program args parser &optional buffer) "Like `mc-process-region', but the region isn't replaced. PARSER is called with one argument, the exit status of PROGRAM." (let ((obuf (current-buffer)) (process-connection-type nil) mybuf result rgn proc) (unwind-protect (progn (setq mybuf (or buffer (generate-new-buffer " *mailcrypt temp"))) (set-buffer mybuf) (erase-buffer) (set-buffer obuf) (buffer-disable-undo mybuf) (setq proc (apply 'start-process "*PGP*" mybuf program args)) (if passwd (progn (process-send-string proc (concat passwd "\n")) (or mc-passwd-timeout (mc-deactivate-passwd t)))) (process-send-region proc beg end) (process-send-eof proc) (while (eq 'run (process-status proc)) (accept-process-output proc 5)) (setq result (process-exit-status proc)) ;; Hack to force a status_notify() in Emacs 19.29 (delete-process proc) (set-buffer mybuf) (goto-char (point-max)) (if (re-search-backward "\nProcess \\*PGP.*\n\\'" nil t) (delete-region (match-beginning 0) (match-end 0))) (goto-char (point-min)) ;; CRNL -> NL (while (search-forward "\r\n" nil t) (replace-match "\n")) ;; Hurm. FIXME; must get better result codes. (if (stringp result) (error "%s exited abnormally: '%s'" program result) (funcall parser result))) ;; Cleanup even on nonlocal exit (if (and proc (eq 'run (process-status proc))) (interrupt-process proc)) (set-buffer obuf) (or buffer (null mybuf) (kill-buffer mybuf))))) Here's the parser for the PGP output. Note that the report status gives quite a lot information on the signature quality (see below for an additional comment on this issue). (defun rfc2015-pgp-mc-verify-parser (result) "Parse PGP output in current buffer." (goto-char (point-min)) (or ;; Valid signature. (save-excursion (when (re-search-forward "^Good signature from user \"" nil t) (goto-char (match-beginning 0)) (let* ((start (point)) (trusted (save-excursion (goto-char (point-min)) ;; Is signature trusted? (if (re-search-forward "^WARNING: Because this public key is not certified" nil t) 'good-no-confidence 'good))) (msg (progn (forward-line 2) (buffer-substring-no-properties start (point)))) (message (if (eq trusted 'good) msg (concat msg "WARNING: This key is not certified by a trusted signature .\n")))) (cons trusted message)))) ;; Invalid signature. (save-excursion (when (re-search-forward "^Bad signature from user \"" nil t) (goto-char (match-beginning 0)) (let ((start (point))) (forward-line 2) (cons 'bad (buffer-substring-no-properties start (point)))))) ;; Unknown public key. (save-excursion (when (re-search-forward "Key matching expected Key ID [0-9A-E]\\{8,8\\} not found" nil t) (cons 'unknown (concat "Can't check signature integrity.\n" (buffer-substring-no-properties (match-beginning 0) (match-end 0)) ".\n")))) ;; Unknown error. (cons 'unknown "An internal error occured.\n"))) Now the verification function: (defun rfc2015-pgp-mc-verify-buffer (message signature) "Check string MESSAGE against string SIGNATURE using PGP. On success, returns a pair (QUALITY . STRING) where QUALITY is one of the symbols `good', `good-no-confidence' (signature is good, but there's not much confidence in the public key), `bad', `unknown' (public key isn't available) and STRING is an explanatory message. In case of a fatal error, `nil' is returned." (let ((message-file (concat (temp-directory) "/" (make-temp-name "gnusmsg"))) (signature-file (concat (temp-directory) "/" (make-temp-name "gnussig"))) (buffer (get-buffer-create mc-buffer-name)) args) (unwind-protect (progn ;; Save message. (with-temp-file message-file (insert message) (rfc2015-normalize-buffer)) ;; Save signature. (with-temp-file signature-file (insert signature)) ;; Prepare call to PGP. (setq args `(,signature-file ,message-file "+verbose=1" "+batchmode" "+language=en")) (if mc-pgp-alternate-keyring (setq args `(,@args ,(format "+pubring=%s" mc-pgp-alternate-keyring)))) (with-temp-buffer (rfc2015-pgp-mc-process nil mc-pgp-path args 'rfc2015-pgp-mc-verify-parser buffer))) ;; Always delete temporary files. (ignore-errors (delete-file message-file)) (ignore-errors (delete-file signature-file))))) * Information on signature qualtiy is missing. Key management is one of the most critical issues with cryptography. Currently, Mailcrypt doesn't give to the user much information on the quality of a signature it encounters, which is a major deficiency (IMHO). The above functions try to address this as far as the signature verification process is concerned, distinguishing good signatures, good signatures by an untrusted key, and bad signatures. Similar things have to be implemented for the decryption process as well (which might have to deal with a signature, too). (For MIME/PGP support, I'm only interested in appropriate signature quality indication from the backend functions. My Gnus extension will provide its own user interface anyway.) These are the issues I'd like to discuss. I think it would be great if some upcoming release of Mailcrypt solved these problems. (Of course, I could distribute the functions along with my Gnus extension, but this might become cumbersome as Mailcrypt development continues and changes the internal interfaces.) I'm glad if I can answer any questions, and feel free to use the code if you think it might be useful. Regards, Florian --=-=-= --=-=-=--