1 ;;; mml2015.el --- MIME Security with Pretty Good Privacy (PGP)
3 ;; Copyright (C) 2000, 2001, 2002, 2003, 2004,
4 ;; 2005, 2006, 2007 Free Software Foundation, Inc.
6 ;; Author: Shenghuo Zhu <zsh@cs.rochester.edu>
7 ;; Keywords: PGP MIME MML
9 ;; This file is part of GNU Emacs.
11 ;; GNU Emacs is free software; you can redistribute it and/or modify
12 ;; it under the terms of the GNU General Public License as published
13 ;; by the Free Software Foundation; either version 2, or (at your
14 ;; option) any later version.
16 ;; GNU Emacs is distributed in the hope that it will be useful, but
17 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 ;; General Public License for more details.
21 ;; You should have received a copy of the GNU General Public License
22 ;; along with GNU Emacs; see the file COPYING. If not, write to the
23 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
24 ;; Boston, MA 02110-1301, USA.
28 ;; RFC 2015 is updated by RFC 3156, this file should be compatible
33 (eval-when-compile (require 'cl))
39 (defvar mc-pgp-always-sign)
41 (defvar mml2015-use (or
45 (epg-check-configuration (epg-configuration))
50 ;; Avoid the "Recursive load suspected" error
52 (let ((recursive-load-depth-limit 100))
54 (and (fboundp 'pgg-sign-region)
59 (and (fboundp 'gpg-sign-detached)
63 (and (fboundp 'mc-encrypt-generic)
64 (fboundp 'mc-sign-generic)
65 (fboundp 'mc-cleanup-recipient-headers)
67 "The package used for PGP/MIME.
68 Valid packages include `epg', `pgg', `gpg' and `mailcrypt'.")
70 ;; Something is not RFC2015.
71 (defvar mml2015-function-alist
72 '((mailcrypt mml2015-mailcrypt-sign
73 mml2015-mailcrypt-encrypt
74 mml2015-mailcrypt-verify
75 mml2015-mailcrypt-decrypt
76 mml2015-mailcrypt-clear-verify
77 mml2015-mailcrypt-clear-decrypt)
82 mml2015-gpg-clear-verify
83 mml2015-gpg-clear-decrypt)
88 mml2015-pgg-clear-verify
89 mml2015-pgg-clear-decrypt)
94 mml2015-epg-clear-verify
95 mml2015-epg-clear-decrypt))
96 "Alist of PGP/MIME functions.")
98 (defvar mml2015-result-buffer nil)
100 (defcustom mml2015-unabbrev-trust-alist
101 '(("TRUST_UNDEFINED" . nil)
102 ("TRUST_NEVER" . nil)
103 ("TRUST_MARGINAL" . t)
105 ("TRUST_ULTIMATE" . t))
106 "Map GnuPG trust output values to a boolean saying if you trust the key."
108 :group 'mime-security
109 :type '(repeat (cons (regexp :tag "GnuPG output regexp")
110 (boolean :tag "Trust key"))))
112 (defcustom mml2015-verbose mml-secure-verbose
113 "If non-nil, ask the user about the current operation more verbosely."
114 :group 'mime-security
117 (defcustom mml2015-cache-passphrase mml-secure-cache-passphrase
118 "If t, cache passphrase."
119 :group 'mime-security
122 (defcustom mml2015-passphrase-cache-expiry mml-secure-passphrase-cache-expiry
123 "How many seconds the passphrase is cached.
124 Whether the passphrase is cached at all is controlled by
125 `mml2015-cache-passphrase'."
126 :group 'mime-security
129 (defcustom mml2015-signers nil
130 "A list of your own key ID which will be used to sign a message."
131 :group 'mime-security
132 :type '(repeat (string :tag "Key ID")))
134 (defcustom mml2015-encrypt-to-self nil
135 "If t, add your own key ID to recipient list when encryption."
136 :group 'mime-security
139 (defcustom mml2015-always-trust t
140 "If t, GnuPG skip key validation on encryption."
141 :group 'mime-security
144 ;;; mailcrypt wrapper
147 (autoload 'mailcrypt-decrypt "mailcrypt")
148 (autoload 'mailcrypt-verify "mailcrypt")
149 (autoload 'mc-pgp-always-sign "mailcrypt")
150 (autoload 'mc-encrypt-generic "mc-toplev")
151 (autoload 'mc-cleanup-recipient-headers "mc-toplev")
152 (autoload 'mc-sign-generic "mc-toplev"))
155 (defvar mc-default-scheme)
158 (defvar mml2015-decrypt-function 'mailcrypt-decrypt)
159 (defvar mml2015-verify-function 'mailcrypt-verify)
161 (defun mml2015-format-error (err)
162 (if (stringp (cadr err))
164 (format "%S" (cdr err))))
166 (defun mml2015-mailcrypt-decrypt (handle ctl)
168 (let (child handles result)
169 (unless (setq child (mm-find-part-by-type
171 "application/octet-stream" nil t))
172 (mm-set-handle-multipart-parameter
173 mm-security-handle 'gnus-info "Corrupted")
174 (throw 'error handle))
176 (mm-insert-part child)
179 (funcall mml2015-decrypt-function)
181 (mm-set-handle-multipart-parameter
182 mm-security-handle 'gnus-details (mml2015-format-error err))
185 (mm-set-handle-multipart-parameter
186 mm-security-handle 'gnus-details "Quit.")
189 (mm-set-handle-multipart-parameter
190 mm-security-handle 'gnus-info "Failed")
191 (throw 'error handle))
192 (setq handles (mm-dissect-buffer t)))
193 (mm-destroy-parts handle)
194 (mm-set-handle-multipart-parameter
195 mm-security-handle 'gnus-info
197 (let ((sig (with-current-buffer mml2015-result-buffer
198 (mml2015-gpg-extract-signature-details))))
199 (concat ", Signer: " sig))))
200 (if (listp (car handles))
204 (defun mml2015-mailcrypt-clear-decrypt ()
208 (funcall mml2015-decrypt-function)
210 (mm-set-handle-multipart-parameter
211 mm-security-handle 'gnus-details (mml2015-format-error err))
214 (mm-set-handle-multipart-parameter
215 mm-security-handle 'gnus-details "Quit.")
218 (mm-set-handle-multipart-parameter
219 mm-security-handle 'gnus-info "OK")
220 (mm-set-handle-multipart-parameter
221 mm-security-handle 'gnus-info "Failed"))))
223 (defun mml2015-fix-micalg (alg)
225 ;; Mutt/1.2.5i has seen sending micalg=php-sha1
226 (upcase (if (string-match "^p[gh]p-" alg)
227 (substring alg (match-end 0))
230 (defun mml2015-mailcrypt-verify (handle ctl)
233 (unless (setq part (mm-find-raw-part-by-type
234 ctl (or (mm-handle-multipart-ctl-parameter
236 "application/pgp-signature")
238 (mm-set-handle-multipart-parameter
239 mm-security-handle 'gnus-info "Corrupted")
240 (throw 'error handle))
242 (insert "-----BEGIN PGP SIGNED MESSAGE-----\n")
243 (insert (format "Hash: %s\n\n"
244 (or (mml2015-fix-micalg
245 (mm-handle-multipart-ctl-parameter
249 (narrow-to-region (point) (point))
251 (goto-char (point-min))
253 (if (looking-at "^-")
256 (unless (setq part (mm-find-part-by-type
257 (cdr handle) "application/pgp-signature" nil t))
258 (mm-set-handle-multipart-parameter
259 mm-security-handle 'gnus-info "Corrupted")
260 (throw 'error handle))
262 (narrow-to-region (point) (point))
263 (mm-insert-part part)
264 (goto-char (point-min))
265 (if (re-search-forward "^-----BEGIN PGP [^-]+-----\r?$" nil t)
266 (replace-match "-----BEGIN PGP SIGNATURE-----" t t))
267 (if (re-search-forward "^-----END PGP [^-]+-----\r?$" nil t)
268 (replace-match "-----END PGP SIGNATURE-----" t t)))
269 (let ((mc-gpg-debug-buffer (get-buffer-create " *gnus gpg debug*")))
270 (unless (condition-case err
272 (funcall mml2015-verify-function)
273 (if (get-buffer " *mailcrypt stderr temp")
274 (mm-set-handle-multipart-parameter
275 mm-security-handle 'gnus-details
276 (with-current-buffer " *mailcrypt stderr temp"
278 (if (get-buffer " *mailcrypt stdout temp")
279 (kill-buffer " *mailcrypt stdout temp"))
280 (if (get-buffer " *mailcrypt stderr temp")
281 (kill-buffer " *mailcrypt stderr temp"))
282 (if (get-buffer " *mailcrypt status temp")
283 (kill-buffer " *mailcrypt status temp"))
284 (if (get-buffer mc-gpg-debug-buffer)
285 (kill-buffer mc-gpg-debug-buffer)))
287 (mm-set-handle-multipart-parameter
288 mm-security-handle 'gnus-details (mml2015-format-error err))
291 (mm-set-handle-multipart-parameter
292 mm-security-handle 'gnus-details "Quit.")
294 (mm-set-handle-multipart-parameter
295 mm-security-handle 'gnus-info "Failed")
296 (throw 'error handle))))
297 (mm-set-handle-multipart-parameter
298 mm-security-handle 'gnus-info "OK")
301 (defun mml2015-mailcrypt-clear-verify ()
302 (let ((mc-gpg-debug-buffer (get-buffer-create " *gnus gpg debug*")))
303 (if (condition-case err
305 (funcall mml2015-verify-function)
306 (if (get-buffer " *mailcrypt stderr temp")
307 (mm-set-handle-multipart-parameter
308 mm-security-handle 'gnus-details
309 (with-current-buffer " *mailcrypt stderr temp"
311 (if (get-buffer " *mailcrypt stdout temp")
312 (kill-buffer " *mailcrypt stdout temp"))
313 (if (get-buffer " *mailcrypt stderr temp")
314 (kill-buffer " *mailcrypt stderr temp"))
315 (if (get-buffer " *mailcrypt status temp")
316 (kill-buffer " *mailcrypt status temp"))
317 (if (get-buffer mc-gpg-debug-buffer)
318 (kill-buffer mc-gpg-debug-buffer)))
320 (mm-set-handle-multipart-parameter
321 mm-security-handle 'gnus-details (mml2015-format-error err))
324 (mm-set-handle-multipart-parameter
325 mm-security-handle 'gnus-details "Quit.")
327 (mm-set-handle-multipart-parameter
328 mm-security-handle 'gnus-info "OK")
329 (mm-set-handle-multipart-parameter
330 mm-security-handle 'gnus-info "Failed"))))
332 (defun mml2015-mailcrypt-sign (cont)
333 (mc-sign-generic (message-options-get 'message-sender)
335 (let ((boundary (mml-compute-boundary cont))
337 (goto-char (point-min))
338 (unless (re-search-forward "^-----BEGIN PGP SIGNED MESSAGE-----\r?$" nil t)
339 (error "Cannot find signed begin line"))
340 (goto-char (match-beginning 0))
342 (unless (looking-at "Hash:[ \t]*\\([a-zA-Z0-9]+\\)")
343 (error "Cannot not find PGP hash"))
344 (setq hash (match-string 1))
345 (unless (re-search-forward "^$" nil t)
346 (error "Cannot not find PGP message"))
348 (delete-region (point-min) (point))
349 (insert (format "Content-Type: multipart/signed; boundary=\"%s\";\n"
351 (insert (format "\tmicalg=pgp-%s; protocol=\"application/pgp-signature\"\n"
353 (insert (format "\n--%s\n" boundary))
355 (goto-char (point-max))
356 (unless (re-search-backward "^-----END PGP SIGNATURE-----\r?$" nil t)
357 (error "Cannot find signature part"))
358 (replace-match "-----END PGP MESSAGE-----" t t)
359 (goto-char (match-beginning 0))
360 (unless (re-search-backward "^-----BEGIN PGP SIGNATURE-----\r?$"