1 ;;; mml2015.el --- MIME Security with Pretty Good Privacy (PGP)
3 ;; Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
4 ;; 2008 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 by
13 ;; the Free Software Foundation, either version 3 of the License, or
14 ;; (at your option) any later version.
16 ;; GNU Emacs is distributed in the hope that it will be useful,
17 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 ;; GNU General Public License for more details.
21 ;; You should have received a copy of the GNU General Public License
22 ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
26 ;; RFC 2015 is updated by RFC 3156, this file should be compatible
33 (unless (fboundp 'declare-function
) (defmacro declare-function
(&rest r
))))
35 (eval-when-compile (require 'cl
))
41 (defvar mc-pgp-always-sign
)
43 (declare-function epg-check-configuration
"ext:epg-config"
44 (config &optional minimum-version
))
45 (declare-function epg-configuration
"ext:epg-config" ())
47 (defvar mml2015-use
(or
51 (epg-check-configuration (epg-configuration))
56 ;; Avoid the "Recursive load suspected" error
58 (let ((recursive-load-depth-limit 100))
60 (and (fboundp 'pgg-sign-region
)
65 (and (fboundp 'gpg-sign-detached
)
69 (and (fboundp 'mc-encrypt-generic
)
70 (fboundp 'mc-sign-generic
)
71 (fboundp 'mc-cleanup-recipient-headers
)
73 "The package used for PGP/MIME.
74 Valid packages include `epg', `pgg', `gpg' and `mailcrypt'.")
76 ;; Something is not RFC2015.
77 (defvar mml2015-function-alist
78 '((mailcrypt mml2015-mailcrypt-sign
79 mml2015-mailcrypt-encrypt
80 mml2015-mailcrypt-verify
81 mml2015-mailcrypt-decrypt
82 mml2015-mailcrypt-clear-verify
83 mml2015-mailcrypt-clear-decrypt
)
88 mml2015-gpg-clear-verify
89 mml2015-gpg-clear-decrypt
)
94 mml2015-pgg-clear-verify
95 mml2015-pgg-clear-decrypt
)
100 mml2015-epg-clear-verify
101 mml2015-epg-clear-decrypt
))
102 "Alist of PGP/MIME functions.")
104 (defvar mml2015-result-buffer nil
)
106 (defcustom mml2015-unabbrev-trust-alist
107 '(("TRUST_UNDEFINED" . nil
)
108 ("TRUST_NEVER" . nil
)
109 ("TRUST_MARGINAL" . t
)
111 ("TRUST_ULTIMATE" . t
))
112 "Map GnuPG trust output values to a boolean saying if you trust the key."
114 :group
'mime-security
115 :type
'(repeat (cons (regexp :tag
"GnuPG output regexp")
116 (boolean :tag
"Trust key"))))
118 (defcustom mml2015-verbose mml-secure-verbose
119 "If non-nil, ask the user about the current operation more verbosely."
120 :group
'mime-security
123 (defcustom mml2015-cache-passphrase mml-secure-cache-passphrase
124 "If t, cache passphrase."
125 :group
'mime-security
128 (defcustom mml2015-passphrase-cache-expiry mml-secure-passphrase-cache-expiry
129 "How many seconds the passphrase is cached.
130 Whether the passphrase is cached at all is controlled by
131 `mml2015-cache-passphrase'."
132 :group
'mime-security
135 (defcustom mml2015-signers nil
136 "A list of your own key ID which will be used to sign a message."
137 :group
'mime-security
138 :type
'(repeat (string :tag
"Key ID")))
140 (defcustom mml2015-encrypt-to-self nil
141 "If t, add your own key ID to recipient list when encryption."
142 :group
'mime-security
145 (defcustom mml2015-always-trust t
146 "If t, GnuPG skip key validation on encryption."
147 :group
'mime-security
150 ;; Extract plaintext from cleartext signature. IMO, this kind of task
151 ;; should be done by GnuPG rather than Elisp, but older PGP backends
152 ;; (such as Mailcrypt, PGG, and gpg.el) discard the output from GnuPG.
153 (defun mml2015-extract-cleartext-signature ()
155 ;; <54a15d860801080142l70b95d7dkac4bf51a86196011@mail.gmail.com>: ``I still
156 ;; believe that the right way is to use the plaintext output from GnuPG as
157 ;; it is, and mml2015-extract-cleartext-signature is just a kludge for
158 ;; misdesigned libraries like PGG, which have no ability to do that. So, I
159 ;; think it should not have descriptive documentation.''
161 ;; This function doesn't handle NotDashEscaped correctly. EasyPG handles it
163 ;; http://thread.gmane.org/gmane.emacs.gnus.general/66062/focus=66082
164 ;; http://thread.gmane.org/gmane.emacs.gnus.general/65087/focus=65109
165 (goto-char (point-min))
167 ;; We need to be careful not to strip beyond the armor headers.
168 ;; Previously, an attacker could replace the text inside our
169 ;; markup with trailing garbage by injecting whitespace into the
171 (while (looking-at "Hash:") ; The only header allowed in cleartext
172 (forward-line)) ; signatures according to RFC2440.
173 (when (looking-at "[\t ]*$")
175 (delete-region (point-min) (point))
176 (if (re-search-forward "^-----BEGIN PGP SIGNATURE-----" nil t
)
177 (delete-region (match-beginning 0) (point-max)))
178 (goto-char (point-min))
179 (while (re-search-forward "^- " nil t
)
180 (replace-match "" t t
)
183 ;;; mailcrypt wrapper
185 (autoload 'mailcrypt-decrypt
"mailcrypt")
186 (autoload 'mailcrypt-verify
"mailcrypt")
187 (autoload 'mc-pgp-always-sign
"mailcrypt")
188 (autoload 'mc-encrypt-generic
"mc-toplev")
189 (autoload 'mc-cleanup-recipient-headers
"mc-toplev")
190 (autoload 'mc-sign-generic
"mc-toplev")
192 (defvar mc-default-scheme
)
195 (defvar mml2015-decrypt-function
'mailcrypt-decrypt
)
196 (defvar mml2015-verify-function
'mailcrypt-verify
)
198 (defun mml2015-format-error (err)
199 (if (stringp (cadr err
))
201 (format "%S" (cdr err
))))
203 (defun mml2015-mailcrypt-decrypt (handle ctl
)
205 (let (child handles result
)
206 (unless (setq child
(mm-find-part-by-type
208 "application/octet-stream" nil t
))
209 (mm-set-handle-multipart-parameter
210 mm-security-handle
'gnus-info
"Corrupted")
211 (throw 'error handle
))
213 (mm-insert-part child
)
216 (funcall mml2015-decrypt-function
)
218 (mm-set-handle-multipart-parameter
219 mm-security-handle
'gnus-details
(mml2015-format-error err
))
222 (mm-set-handle-multipart-parameter
223 mm-security-handle
'gnus-details
"Quit.")
226 (mm-set-handle-multipart-parameter
227 mm-security-handle
'gnus-info
"Failed")
228 (throw 'error handle
))
229 (setq handles
(mm-dissect-buffer t
)))
230 (mm-destroy-parts handle
)
231 (mm-set-handle-multipart-parameter
232 mm-security-handle
'gnus-info
234 (let ((sig (with-current-buffer mml2015-result-buffer
235 (mml2015-gpg-extract-signature-details))))
236 (concat ", Signer: " sig
))))
237 (if (listp (car handles
))
241 (defun mml2015-mailcrypt-clear-decrypt ()
245 (funcall mml2015-decrypt-function
)
247 (mm-set-handle-multipart-parameter
248 mm-security-handle
'gnus-details
(mml2015-format-error err
))
251 (mm-set-handle-multipart-parameter
252 mm-security-handle
'gnus-details
"Quit.")
255 (mm-set-handle-multipart-parameter
256 mm-security-handle
'gnus-info
"OK")
257 (mm-set-handle-multipart-parameter
258 mm-security-handle
'gnus-info
"Failed"))))
260 (defun mml2015-fix-micalg (alg)
262 ;; Mutt/1.2.5i has seen sending micalg=php-sha1
263 (upcase (if (string-match "^p[gh]p-" alg
)
264 (substring alg
(match-end 0))
267 (defun mml2015-mailcrypt-verify (handle ctl
)
270 (unless (setq part
(mm-find-raw-part-by-type
271 ctl
(or (mm-handle-multipart-ctl-parameter
273 "application/pgp-signature")
275 (mm-set-handle-multipart-parameter
276 mm-security-handle
'gnus-info
"Corrupted")
277 (throw 'error handle
))
279 (insert "-----BEGIN PGP SIGNED MESSAGE-----\n")
280 (insert (format "Hash: %s\n\n"
281 (or (mml2015-fix-micalg
282 (mm-handle-multipart-ctl-parameter
286 (narrow-to-region (point) (point))
288 (goto-char (point-min))
290 (if (looking-at "^-")
293 (unless (setq part
(mm-find-part-by-type
294 (cdr handle
) "application/pgp-signature" nil t
))
295 (mm-set-handle-multipart-parameter
296 mm-security-handle
'gnus-info
"Corrupted")
297 (throw 'error handle
))
299 (narrow-to-region (point) (point))
300 (mm-insert-part part
)
301 (goto-char (point-min))
302 (if (re-search-forward "^-----BEGIN PGP [^-]+-----\r?$" nil t
)
303 (replace-match "-----BEGIN PGP SIGNATURE-----" t t
))
304 (if (re-search-forward "^-----END PGP [^-]+-----\r?$" nil t
)
305 (replace-match "-----END PGP SIGNATURE-----" t t
)))
306 (let ((mc-gpg-debug-buffer (get-buffer-create " *gnus gpg debug*")))
307 (unless (condition-case err
309 (funcall mml2015-verify-function
)
310 (if (get-buffer " *mailcrypt stderr temp")
311 (mm-set-handle-multipart-parameter
312 mm-security-handle
'gnus-details
313 (with-current-buffer " *mailcrypt stderr temp"
315 (if (get-buffer " *mailcrypt stdout temp")
316 (kill-buffer " *mailcrypt stdout temp"))
317 (if (get-buffer " *mailcrypt stderr temp")
318 (kill-buffer " *mailcrypt stderr temp"))
319 (if (get-buffer " *mailcrypt status temp")
320 (kill-buffer " *mailcrypt status temp"))
321 (if (get-buffer mc-gpg-debug-buffer
)
322 (kill-buffer mc-gpg-debug-buffer
)))
324 (mm-set-handle-multipart-parameter
325 mm-security-handle
'gnus-details
(mml2015-format-error err
))
328 (mm-set-handle-multipart-parameter
329 mm-security-handle
'gnus-details
"Quit.")
331 (mm-set-handle-multipart-parameter
332 mm-security-handle
'gnus-info
"Failed")
333 (throw 'error handle
))))
334 (mm-set-handle-multipart-parameter
335 mm-security-handle
'gnus-info
"OK")
338 (defun mml2015-mailcrypt-clear-verify ()
339 (let ((mc-gpg-debug-buffer (get-buffer-create " *gnus gpg debug*")))
340 (if (condition-case err
342 (funcall mml2015-verify-function
)
343 (if (get-buffer " *mailcrypt stderr temp")
344 (mm-set-handle-multipart-parameter
345 mm-security-handle
'gnus-details
346 (with-current-buffer " *mailcrypt stderr temp"
348 (if (get-buffer " *mailcrypt stdout temp")
349 (kill-buffer " *mailcrypt stdout temp"))
350 (if (get-buffer " *mailcrypt stderr temp")
351 (kill-buffer " *mailcrypt stderr temp"))
352 (if (get-buffer " *mailcrypt status temp")
353 (kill-buffer " *mailcrypt status temp"))
354 (if (get-buffer mc-gpg-debug-buffer
)
355 (kill-buffer mc-gpg-debug-buffer
)))
357 (mm-set-handle-multipart-parameter
358 mm-security-handle
'gnus-details
(mml2015-format-error err
))
361 (mm-set-handle-multipart-parameter
362 mm-security-handle
'gnus-details
"Quit.")
364 (mm-set-handle-multipart-parameter
365 mm-security-handle
'gnus-info
"OK")
366 (mm-set-handle-multipart-parameter
367 mm-security-handle
'gnus-info
"Failed")))
368 (mml2015-extract-cleartext-signature))
370 (defun mml2015-mailcrypt-sign (cont)
371 (mc-sign-generic (message-options-get 'message-sender
)
373 (let ((boundary (mml-compute-boundary cont
))
375 (goto-char (point-min))
376 (unless (re-search-forward "^-----BEGIN PGP SIGNED MESSAGE-----\r?$" nil t
)
377 (error "Cannot find signed begin line"))
378 (goto-char (match-beginning 0))
380 (unless (looking-at "Hash:[ \t]*\\([a-zA-Z0-9]+\\)")
381 (error "Cannot not find PGP hash"))
382 (setq hash
(match-string 1))
383 (unless (re-search-forward "^$" nil t
)
384 (error "Cannot not find PGP message"))
386 (delete-region (point-min) (point))
387 (insert (format "Content-Type: multipart/signed; boundary=\"%s\";\n"
389 (insert (format "\tmicalg=pgp-%s; protocol=\"application/pgp-signature\"\n"
391 (insert (format "\n--%s\n" boundary
))
393 (goto-char (point-max))
394 (unless (re-search-backward "^-----END PGP SIGNATURE-----\r?$" nil t
)
395 (error "Cannot find signature part"))
396 (replace-match "-----END PGP MESSAGE-----" t t
)
397 (goto-char (match-beginning 0))
398 (unless (re-search-backward "^-----BEGIN PGP SIGNATURE-----\r?$"
400 (error "Cannot find signature part"))
401 (replace-match "-----BEGIN PGP MESSAGE-----" t t
)
402 (goto-char (match-beginning 0))
404 (narrow-to-region point
(point))
406 (while (re-search-forward "^- -" nil t
)
407 (replace-match "-" t t
))
408 (goto-char (point-max)))
409 (insert (format "--%s\n" boundary
))
410 (insert "Content-Type: application/pgp-signature\n\n")
411 (goto-char (point-max))
412 (insert (format "--%s--\n" boundary
))
413 (goto-char (point-max))))
415 ;; We require mm-decode, which requires mm-bodies, which autoloads
416 ;; message-options-get (!).
417 (declare-function message-options-set
"message" (symbol value
))
419 (defun mml2015-mailcrypt-encrypt (cont &optional sign
)
420 (let ((mc-pgp-always-sign
421 (or mc-pgp-always-sign
423 (eq t
(or (message-options-get 'message-sign-encrypt
)
425 'message-sign-encrypt
426 (or (y-or-n-p "Sign the message? ")
429 (mm-with-unibyte-current-buffer
431 (or (message-options-get 'message-recipients
)
432 (message-options-set 'message-recipients
433 (mc-cleanup-recipient-headers
434 (read-string "Recipients: "))))
436 (message-options-get 'message-sender
))))
437 (goto-char (point-min))
438 (unless (looking-at "-----BEGIN PGP MESSAGE-----")
439 (error "Fail to encrypt the message"))
440 (let ((boundary (mml-compute-boundary cont
)))
441 (insert (format "Content-Type: multipart/encrypted; boundary=\"%s\";\n"
443 (insert "\tprotocol=\"application/pgp-encrypted\"\n\n")
444 (insert (format "--%s\n" boundary
))
445 (insert "Content-Type: application/pgp-encrypted\n\n")
446 (insert "Version: 1\n\n")
447 (insert (format "--%s\n" boundary
))
448 (insert "Content-Type: application/octet-stream\n\n")
449 (goto-char (point-max))
450 (insert (format "--%s--\n" boundary
))
451 (goto-char (point-max))))
455 (autoload 'gpg-decrypt
"gpg")
456 (autoload 'gpg-verify
"gpg")
457 (autoload 'gpg-verify-cleartext
"gpg")
458 (autoload 'gpg-sign-detached
"gpg")
459 (autoload 'gpg-sign-encrypt
"gpg")
460 (autoload 'gpg-encrypt
"gpg")
461 (autoload 'gpg-passphrase-read
"gpg")
463 (defun mml2015-gpg-passphrase ()
464 (or (message-options-get 'gpg-passphrase
)
465 (message-options-set 'gpg-passphrase
(gpg-passphrase-read))))
467 (defun mml2015-gpg-decrypt-1 ()
468 (let ((cipher (current-buffer)) plain result
)
469 (if (with-temp-buffer
471 (gpg-decrypt cipher
(setq plain
(current-buffer))
472 mml2015-result-buffer nil
)
473 (mm-set-handle-multipart-parameter
474 mm-security-handle
'gnus-details
475 (with-current-buffer mml2015-result-buffer
479 (insert-buffer-substring plain
)
480 (goto-char (point-min))
481 (while (search-forward "\r\n" nil t
)
482 (replace-match "\n" t t
))))
484 ;; Some wrong with the return value, check plain text buffer.
485 (if (> (point-max) (point-min))
489 (defun mml2015-gpg-decrypt (handle ctl
)
490 (let ((mml2015-decrypt-function 'mml2015-gpg-decrypt-1
))
491 (mml2015-mailcrypt-decrypt handle ctl
)))
493 (defun mml2015-gpg-clear-decrypt ()
495 (setq result
(mml2015-gpg-decrypt-1))
497 (mm-set-handle-multipart-parameter
498 mm-security-handle
'gnus-info
"OK")
499 (mm-set-handle-multipart-parameter
500 mm-security-handle
'gnus-info
"Failed"))))
502 (defun mml2015-gpg-pretty-print-fpr (fingerprint)
504 (fpr-length (string-width fingerprint
))
507 (setq fingerprint
(string-to-list fingerprint
))
509 (setq fpr-length
(- fpr-length
4))
510 (setq slice
(butlast fingerprint fpr-length
))
511 (setq fingerprint
(nthcdr 4 fingerprint
))
512 (setq n-slice
(1+ n-slice
))
518 (otherwise (concat " " slice
))))))
521 (defun mml2015-gpg-extract-signature-details ()
522 (goto-char (point-min))
523 (let* ((expired (re-search-forward
524 "^\\[GNUPG:\\] SIGEXPIRED$"
526 (signer (and (re-search-forward
527 "^\\[GNUPG:\\] GOODSIG \\([0-9A-Za-z]*\\) \\(.*\\)$"
529 (cons (match-string 1) (match-string 2))))
530 (fprint (and (re-search-forward
531 "^\\[GNUPG:\\] VALIDSIG \\([0-9a-zA-Z]*\\) "
534 (trust (and (re-search-forward
535 "^\\[GNUPG:\\] \\(TRUST_.*\\)$"
539 (cdr (assoc trust mml2015-unabbrev-trust-alist
))))
540 (cond ((and signer fprint
)
542 (unless trust-good-enough-p
543 (concat "\nUntrusted, Fingerprint: "
544 (mml2015-gpg-pretty-print-fpr fprint
)))
546 (format "\nWARNING: Signature from expired key (%s)"
549 "^\\(gpg: \\)?Good signature from \"\\(.*\\)\"$" nil t
)
552 "From unknown user"))))
554 (defun mml2015-gpg-verify (handle ctl
)
556 (let (part message signature info-is-set-p
)
557 (unless (setq part
(mm-find-raw-part-by-type
558 ctl
(or (mm-handle-multipart-ctl-parameter
560 "application/pgp-signature")
562 (mm-set-handle-multipart-parameter
563 mm-security-handle
'gnus-info
"Corrupted")
564 (throw 'error handle
))
566 (setq message
(current-buffer))
568 ;; Convert <LF> to <CR><LF> in signed text. If --textmode is
569 ;; specified when signing, the conversion is not necessary.
570 (goto-char (point-min))
573 (unless (eq (char-before) ?
\r)
578 (setq signature
(current-buffer))
579 (unless (setq part
(mm-find-part-by-type
580 (cdr handle
) "application/pgp-signature" nil t
))
581 (mm-set-handle-multipart-parameter
582 mm-security-handle
'gnus-info
"Corrupted")
583 (throw 'error handle
))
584 (mm-insert-part part
)
585 (unless (condition-case err
587 (gpg-verify message signature mml2015-result-buffer
)
588 (mm-set-handle-multipart-parameter
589 mm-security-handle
'gnus-details
590 (with-current-buffer mml2015-result-buffer
593 (mm-set-handle-multipart-parameter
594 mm-security-handle
'gnus-details
(mml2015-format-error err
))
595 (mm-set-handle-multipart-parameter
596 mm-security-handle
'gnus-info
"Error.")
597 (setq info-is-set-p t
)
600 (mm-set-handle-multipart-parameter
601 mm-security-handle
'gnus-details
"Quit.")
602 (mm-set-handle-multipart-parameter
603 mm-security-handle
'gnus-info
"Quit.")
604 (setq info-is-set-p t
)
606 (unless info-is-set-p
607 (mm-set-handle-multipart-parameter
608 mm-security-handle
'gnus-info
"Failed"))
609 (throw 'error handle
)))
610 (mm-set-handle-multipart-parameter
611 mm-security-handle
'gnus-info
612 (with-current-buffer mml2015-result-buffer
613 (mml2015-gpg-extract-signature-details))))
616 (defun mml2015-gpg-clear-verify ()
617 (if (condition-case err
619 (gpg-verify-cleartext (current-buffer) mml2015-result-buffer
)
620 (mm-set-handle-multipart-parameter
621 mm-security-handle
'gnus-details
622 (with-current-buffer mml2015-result-buffer
625 (mm-set-handle-multipart-parameter
626 mm-security-handle
'gnus-details
(mml2015-format-error err
))
629 (mm-set-handle-multipart-parameter
630 mm-security-handle
'gnus-details
"Quit.")
632 (mm-set-handle-multipart-parameter
633 mm-security-handle
'gnus-info
634 (with-current-buffer mml2015-result-buffer
635 (mml2015-gpg-extract-signature-details)))
636 (mm-set-handle-multipart-parameter
637 mm-security-handle
'gnus-info
"Failed"))
638 (mml2015-extract-cleartext-signature))
640 (defun mml2015-gpg-sign (cont)
641 (let ((boundary (mml-compute-boundary cont
))
642 (text (current-buffer)) signature
)
643 (goto-char (point-max))
647 (unless (gpg-sign-detached text
(setq signature
(current-buffer))
648 mml2015-result-buffer
650 (message-options-get 'message-sender
)
651 t t
) ; armor & textmode
652 (unless (> (point-max) (point-min))
653 (pop-to-buffer mml2015-result-buffer
)
654 (error "Sign error")))
655 (goto-char (point-min))
656 (while (re-search-forward "\r+$" nil t
)
657 (replace-match "" t t
))
659 (goto-char (point-min))
660 (insert (format "Content-Type: multipart/signed; boundary=\"%s\";\n"
662 ;;; FIXME: what is the micalg?
663 (insert "\tmicalg=pgp-sha1; protocol=\"application/pgp-signature\"\n")
664 (insert (format "\n--%s\n" boundary
))
665 (goto-char (point-max))
666 (insert (format "\n--%s\n" boundary
))
667 (insert "Content-Type: application/pgp-signature\n\n")
668 (insert-buffer-substring signature
)
669 (goto-char (point-max))
670 (insert (format "--%s--\n" boundary
))
671 (goto-char (point-max)))))
673 (defun mml2015-gpg-encrypt (cont &optional sign
)
674 (let ((boundary (mml-compute-boundary cont
))
675 (text (current-buffer))
677 (mm-with-unibyte-current-buffer
679 ;; set up a function to call the correct gpg encrypt routine
680 ;; with the right arguments. (FIXME: this should be done
682 (flet ((gpg-encrypt-func
683 (sign plaintext ciphertext result recipients
&optional
684 passphrase sign-with-key armor textmode
)
687 plaintext ciphertext result recipients passphrase
688 sign-with-key armor textmode
)
690 plaintext ciphertext result recipients passphrase
692 (unless (gpg-encrypt-func
693 sign
; passed in when using signencrypt
694 text
(setq cipher
(current-buffer))
695 mml2015-result-buffer
698 (message-options-get 'message-recipients
)
699 (message-options-set 'message-recipients
700 (read-string "Recipients: ")))
703 (message-options-get 'message-sender
)
704 t t
) ; armor & textmode
705 (unless (> (point-max) (point-min))
706 (pop-to-buffer mml2015-result-buffer
)
707 (error "Encrypt error"))))
708 (goto-char (point-min))
709 (while (re-search-forward "\r+$" nil t
)
710 (replace-match "" t t
))
712 (delete-region (point-min) (point-max))
713 (insert (format "Content-Type: multipart/encrypted; boundary=\"%s\";\n"
715 (insert "\tprotocol=\"application/pgp-encrypted\"\n\n")
716 (insert (format "--%s\n" boundary
))
717 (insert "Content-Type: application/pgp-encrypted\n\n")
718 (insert "Version: 1\n\n")
719 (insert (format "--%s\n" boundary
))
720 (insert "Content-Type: application/octet-stream\n\n")
721 (insert-buffer-substring cipher
)
722 (goto-char (point-max))
723 (insert (format "--%s--\n" boundary
))
724 (goto-char (point-max))))))
728 (defvar pgg-default-user-id
)
729 (defvar pgg-errors-buffer
)
730 (defvar pgg-output-buffer
)
732 (autoload 'pgg-decrypt-region
"pgg")
733 (autoload 'pgg-verify-region
"pgg")
734 (autoload 'pgg-sign-region
"pgg")
735 (autoload 'pgg-encrypt-region
"pgg")
736 (autoload 'pgg-parse-armor
"pgg-parse")
738 (defun mml2015-pgg-decrypt (handle ctl
)
740 (let ((pgg-errors-buffer mml2015-result-buffer
)
741 child handles result decrypt-status
)
742 (unless (setq child
(mm-find-part-by-type
744 "application/octet-stream" nil t
))
745 (mm-set-handle-multipart-parameter
746 mm-security-handle
'gnus-info
"Corrupted")
747 (throw 'error handle
))
749 (mm-insert-part child
)
750 (if (condition-case err
752 (pgg-decrypt-region (point-min) (point-max))
754 (with-current-buffer mml2015-result-buffer
756 (mm-set-handle-multipart-parameter
757 mm-security-handle
'gnus-details
760 (mm-set-handle-multipart-parameter
761 mm-security-handle
'gnus-details
(mml2015-format-error err
))
764 (mm-set-handle-multipart-parameter
765 mm-security-handle
'gnus-details
"Quit.")
767 (with-current-buffer pgg-output-buffer
768 (goto-char (point-min))
769 (while (search-forward "\r\n" nil t
)
770 (replace-match "\n" t t
))
771 (setq handles
(mm-dissect-buffer t
))
772 (mm-destroy-parts handle
)
773 (mm-set-handle-multipart-parameter
774 mm-security-handle
'gnus-info
"OK")
775 (mm-set-handle-multipart-parameter
776 mm-security-handle
'gnus-details
777 (concat decrypt-status
778 (when (stringp (car handles
))
779 "\n" (mm-handle-multipart-ctl-parameter
780 handles
'gnus-details
))))
781 (if (listp (car handles
))
784 (mm-set-handle-multipart-parameter
785 mm-security-handle
'gnus-info
"Failed")
786 (throw 'error handle
))))))
788 (defun mml2015-pgg-clear-decrypt ()
789 (let ((pgg-errors-buffer mml2015-result-buffer
))
791 (pgg-decrypt-region (point-min) (point-max))
792 (mm-set-handle-multipart-parameter
793 mm-security-handle
'gnus-details
794 (with-current-buffer mml2015-result-buffer
798 ;; Treat data which pgg returns as a unibyte string.
799 (mm-disable-multibyte)
800 (insert-buffer-substring pgg-output-buffer
)
801 (goto-char (point-min))
802 (while (search-forward "\r\n" nil t
)
803 (replace-match "\n" t t
))
804 (mm-set-handle-multipart-parameter
805 mm-security-handle
'gnus-info
"OK"))
806 (mm-set-handle-multipart-parameter
807 mm-security-handle
'gnus-info
"Failed"))))
809 (defun mml2015-pgg-verify (handle ctl
)
810 (let ((pgg-errors-buffer mml2015-result-buffer
)
811 signature-file part signature
)
812 (if (or (null (setq part
(mm-find-raw-part-by-type
813 ctl
(or (mm-handle-multipart-ctl-parameter
815 "application/pgp-signature")
817 (null (setq signature
(mm-find-part-by-type
818 (cdr handle
) "application/pgp-signature" nil t
))))
820 (mm-set-handle-multipart-parameter
821 mm-security-handle
'gnus-info
"Corrupted")
825 ;; Convert <LF> to <CR><LF> in signed text. If --textmode is
826 ;; specified when signing, the conversion is not necessary.
827 (goto-char (point-min))
830 (unless (eq (char-before) ?
\r)
834 (with-temp-file (setq signature-file
(mm-make-temp-file "pgg"))
835 (mm-insert-part signature
))
836 (if (condition-case err
838 (pgg-verify-region (point-min) (point-max)
840 (goto-char (point-min))
841 (while (search-forward "\r\n" nil t
)
842 (replace-match "\n" t t
))
843 (mm-set-handle-multipart-parameter
844 mm-security-handle
'gnus-details
845 (concat (with-current-buffer pgg-output-buffer
847 (with-current-buffer pgg-errors-buffer
850 (mm-set-handle-multipart-parameter
851 mm-security-handle
'gnus-details
(mml2015-format-error err
))
854 (mm-set-handle-multipart-parameter
855 mm-security-handle
'gnus-details
"Quit.")
858 (delete-file signature-file
)
859 (mm-set-handle-multipart-parameter
860 mm-security-handle
'gnus-info
861 (with-current-buffer pgg-errors-buffer
862 (mml2015-gpg-extract-signature-details))))
863 (delete-file signature-file
)
864 (mm-set-handle-multipart-parameter
865 mm-security-handle
'gnus-info
"Failed")))))
868 (defun mml2015-pgg-clear-verify ()
869 (let ((pgg-errors-buffer mml2015-result-buffer
)
870 (text (buffer-string))
871 (coding-system buffer-file-coding-system
))
872 (if (condition-case err
874 (mm-with-unibyte-buffer
875 (insert (mm-encode-coding-string text coding-system
))
876 (pgg-verify-region (point-min) (point-max) nil t
))
877 (goto-char (point-min))
878 (while (search-forward "\r\n" nil t
)
879 (replace-match "\n" t t
))
880 (mm-set-handle-multipart-parameter
881 mm-security-handle
'gnus-details
882 (concat (with-current-buffer pgg-output-buffer
884 (with-current-buffer pgg-errors-buffer
887 (mm-set-handle-multipart-parameter
888 mm-security-handle
'gnus-details
(mml2015-format-error err
))
891 (mm-set-handle-multipart-parameter
892 mm-security-handle
'gnus-details
"Quit.")
894 (mm-set-handle-multipart-parameter
895 mm-security-handle
'gnus-info
896 (with-current-buffer pgg-errors-buffer
897 (mml2015-gpg-extract-signature-details)))
898 (mm-set-handle-multipart-parameter
899 mm-security-handle
'gnus-info
"Failed")))
900 (mml2015-extract-cleartext-signature))
902 (defun mml2015-pgg-sign (cont)
903 (let ((pgg-errors-buffer mml2015-result-buffer
)
904 (boundary (mml-compute-boundary cont
))
905 (pgg-default-user-id (or (message-options-get 'mml-sender
)
906 pgg-default-user-id
))
909 (unless (pgg-sign-region (point-min) (point-max))
910 (pop-to-buffer mml2015-result-buffer
)
911 (error "Sign error"))
912 (goto-char (point-min))
913 (insert (format "Content-Type: multipart/signed; boundary=\"%s\";\n"
915 (if (setq entry
(assq 2 (pgg-parse-armor
916 (with-current-buffer pgg-output-buffer
918 (setq entry
(assq 'hash-algorithm
(cdr entry
))))
919 (insert (format "\tmicalg=%s; "
921 (downcase (format "pgp-%s" (cdr entry
)))
923 (insert "protocol=\"application/pgp-signature\"\n")
924 (insert (format "\n--%s\n" boundary
))
925 (goto-char (point-max))
926 (insert (format "\n--%s\n" boundary
))
927 (insert "Content-Type: application/pgp-signature\n\n")
928 (insert-buffer-substring pgg-output-buffer
)
929 (goto-char (point-max))
930 (insert (format "--%s--\n" boundary
))
931 (goto-char (point-max))))
933 (defun mml2015-pgg-encrypt (cont &optional sign
)
934 (let ((pgg-errors-buffer mml2015-result-buffer
)
936 (boundary (mml-compute-boundary cont
)))
937 (unless (pgg-encrypt-region (point-min) (point-max)
940 (message-options-get 'message-recipients
)
941 (message-options-set 'message-recipients
942 (read-string "Recipients: ")))
945 (pop-to-buffer mml2015-result-buffer
)
946 (error "Encrypt error"))
947 (delete-region (point-min) (point-max))
948 (goto-char (point-min))
949 (insert (format "Content-Type: multipart/encrypted; boundary=\"%s\";\n"
951 (insert "\tprotocol=\"application/pgp-encrypted\"\n\n")
952 (insert (format "--%s\n" boundary
))
953 (insert "Content-Type: application/pgp-encrypted\n\n")
954 (insert "Version: 1\n\n")
955 (insert (format "--%s\n" boundary
))
956 (insert "Content-Type: application/octet-stream\n\n")
957 (insert-buffer-substring pgg-output-buffer
)
958 (goto-char (point-max))
959 (insert (format "--%s--\n" boundary
))
960 (goto-char (point-max))))
964 (defvar epg-user-id-alist
)
965 (defvar epg-digest-algorithm-alist
)
966 (defvar inhibit-redisplay
)
968 (autoload 'epg-make-context
"epg")
969 (autoload 'epg-context-set-armor
"epg")
970 (autoload 'epg-context-set-textmode
"epg")
971 (autoload 'epg-context-set-signers
"epg")
972 (autoload 'epg-context-result-for
"epg")
973 (autoload 'epg-new-signature-digest-algorithm
"epg")
974 (autoload 'epg-verify-result-to-string
"epg")
975 (autoload 'epg-list-keys
"epg")
976 (autoload 'epg-decrypt-string
"epg")
977 (autoload 'epg-verify-string
"epg")
978 (autoload 'epg-sign-string
"epg")
979 (autoload 'epg-encrypt-string
"epg")
980 (autoload 'epg-passphrase-callback-function
"epg")
981 (autoload 'epg-context-set-passphrase-callback
"epg")
982 (autoload 'epg-key-sub-key-list
"epg")
983 (autoload 'epg-sub-key-capability
"epg")
984 (autoload 'epg-sub-key-validity
"epg")
985 (autoload 'epg-configuration
"epg-config")
986 (autoload 'epg-expand-group
"epg-config")
987 (autoload 'epa-select-keys
"epa")
989 (defvar password-cache-expiry
)
991 (defvar mml2015-epg-secret-key-id-list nil
)
993 (defun mml2015-epg-passphrase-callback (context key-id ignore
)
995 (epg-passphrase-callback-function context key-id nil
)
996 (let* ((password-cache-key-id
1003 (if (eq key-id
'PIN
)
1004 "Passphrase for PIN: "
1005 (if (setq entry
(assoc key-id epg-user-id-alist
))
1006 (format "Passphrase for %s %s: " key-id
(cdr entry
))
1007 (format "Passphrase for %s: " key-id
)))
1008 password-cache-key-id
)))
1010 (let ((password-cache-expiry mml2015-passphrase-cache-expiry
))
1011 (password-cache-add password-cache-key-id passphrase
))
1012 (setq mml2015-epg-secret-key-id-list
1013 (cons password-cache-key-id mml2015-epg-secret-key-id-list
))
1014 (copy-sequence passphrase
)))))
1016 (defun mml2015-epg-find-usable-key (keys usage
)
1019 (let ((pointer (epg-key-sub-key-list (car keys
))))
1021 (if (and (memq usage
(epg-sub-key-capability (car pointer
)))
1022 (not (memq (epg-sub-key-validity (car pointer
))
1023 '(revoked expired
))))
1024 (throw 'found
(car keys
)))
1025 (setq pointer
(cdr pointer
))))
1026 (setq keys
(cdr keys
)))))
1028 (defun mml2015-epg-decrypt (handle ctl
)
1030 (let ((inhibit-redisplay t
)
1031 context plain child handles result decrypt-status
)
1032 (unless (setq child
(mm-find-part-by-type
1034 "application/octet-stream" nil t
))
1035 (mm-set-handle-multipart-parameter
1036 mm-security-handle
'gnus-info
"Corrupted")
1037 (throw 'error handle
))
1038 (setq context
(epg-make-context))
1039 (if mml2015-cache-passphrase
1040 (epg-context-set-passphrase-callback
1042 #'mml2015-epg-passphrase-callback
))
1043 (condition-case error
1044 (setq plain
(epg-decrypt-string context
(mm-get-part child
))
1045 mml2015-epg-secret-key-id-list nil
)
1047 (while mml2015-epg-secret-key-id-list
1048 (password-cache-remove (car mml2015-epg-secret-key-id-list
))
1049 (setq mml2015-epg-secret-key-id-list
1050 (cdr mml2015-epg-secret-key-id-list
)))
1051 (mm-set-handle-multipart-parameter
1052 mm-security-handle
'gnus-info
"Failed")
1053 (if (eq (car error
) 'quit
)
1054 (mm-set-handle-multipart-parameter
1055 mm-security-handle
'gnus-details
"Quit.")
1056 (mm-set-handle-multipart-parameter
1057 mm-security-handle
'gnus-details
(mml2015-format-error error
)))
1058 (throw 'error handle
)))
1061 (goto-char (point-min))
1062 (while (search-forward "\r\n" nil t
)
1063 (replace-match "\n" t t
))
1064 (setq handles
(mm-dissect-buffer t
))
1065 (mm-destroy-parts handle
)
1066 (if (epg-context-result-for context
'verify
)
1067 (mm-set-handle-multipart-parameter
1068 mm-security-handle
'gnus-info
1070 (epg-verify-result-to-string
1071 (epg-context-result-for context
'verify
))))
1072 (mm-set-handle-multipart-parameter
1073 mm-security-handle
'gnus-info
"OK"))
1074 (if (stringp (car handles
))
1075 (mm-set-handle-multipart-parameter
1076 mm-security-handle
'gnus-details
1077 (mm-handle-multipart-ctl-parameter handles
'gnus-details
))))
1078 (if (listp (car handles
))
1082 (defun mml2015-epg-clear-decrypt ()
1083 (let ((inhibit-redisplay t
)
1084 (context (epg-make-context))
1086 (if mml2015-cache-passphrase
1087 (epg-context-set-passphrase-callback
1089 #'mml2015-epg-passphrase-callback
))
1090 (condition-case error
1091 (setq plain
(epg-decrypt-string context
(buffer-string))
1092 mml2015-epg-secret-key-id-list nil
)
1094 (while mml2015-epg-secret-key-id-list
1095 (password-cache-remove (car mml2015-epg-secret-key-id-list
))
1096 (setq mml2015-epg-secret-key-id-list
1097 (cdr mml2015-epg-secret-key-id-list
)))
1098 (mm-set-handle-multipart-parameter
1099 mm-security-handle
'gnus-info
"Failed")
1100 (if (eq (car error
) 'quit
)
1101 (mm-set-handle-multipart-parameter
1102 mm-security-handle
'gnus-details
"Quit.")
1103 (mm-set-handle-multipart-parameter
1104 mm-security-handle
'gnus-details
(mml2015-format-error error
)))))
1107 ;; Treat data which epg returns as a unibyte string.
1108 (mm-disable-multibyte)
1110 (goto-char (point-min))
1111 (while (search-forward "\r\n" nil t
)
1112 (replace-match "\n" t t
))
1113 (mm-set-handle-multipart-parameter
1114 mm-security-handle
'gnus-info
"OK")
1115 (if (epg-context-result-for context
'verify
)
1116 (mm-set-handle-multipart-parameter
1117 mm-security-handle
'gnus-details
1118 (epg-verify-result-to-string
1119 (epg-context-result-for context
'verify
)))))))
1121 (defun mml2015-epg-verify (handle ctl
)
1123 (let ((inhibit-redisplay t
)
1124 context plain signature-file part signature
)
1125 (when (or (null (setq part
(mm-find-raw-part-by-type
1126 ctl
(or (mm-handle-multipart-ctl-parameter
1128 "application/pgp-signature")
1130 (null (setq signature
(mm-find-part-by-type
1131 (cdr handle
) "application/pgp-signature"
1133 (mm-set-handle-multipart-parameter
1134 mm-security-handle
'gnus-info
"Corrupted")
1135 (throw 'error handle
))
1136 (setq part
(mm-replace-in-string part
"\n" "\r\n" t
)
1137 signature
(mm-get-part signature
)
1138 context
(epg-make-context))
1139 (condition-case error
1140 (setq plain
(epg-verify-string context signature part
))
1142 (mm-set-handle-multipart-parameter
1143 mm-security-handle
'gnus-info
"Failed")
1144 (if (eq (car error
) 'quit
)
1145 (mm-set-handle-multipart-parameter
1146 mm-security-handle
'gnus-details
"Quit.")
1147 (mm-set-handle-multipart-parameter
1148 mm-security-handle
'gnus-details
(mml2015-format-error error
)))
1149 (throw 'error handle
)))
1150 (mm-set-handle-multipart-parameter
1151 mm-security-handle
'gnus-info
1152 (epg-verify-result-to-string (epg-context-result-for context
'verify
)))
1155 (defun mml2015-epg-clear-verify ()
1156 (let ((inhibit-redisplay t
)
1157 (context (epg-make-context))
1158 (signature (mm-encode-coding-string (buffer-string)
1159 coding-system-for-write
))
1161 (condition-case error
1162 (setq plain
(epg-verify-string context signature
))
1164 (mm-set-handle-multipart-parameter
1165 mm-security-handle
'gnus-info
"Failed")
1166 (if (eq (car error
) 'quit
)
1167 (mm-set-handle-multipart-parameter
1168 mm-security-handle
'gnus-details
"Quit.")
1169 (mm-set-handle-multipart-parameter
1170 mm-security-handle
'gnus-details
(mml2015-format-error error
)))))
1173 (mm-set-handle-multipart-parameter
1174 mm-security-handle
'gnus-info
1175 (epg-verify-result-to-string
1176 (epg-context-result-for context
'verify
)))
1177 (delete-region (point-min) (point-max))
1178 (insert (mm-decode-coding-string plain coding-system-for-read
)))
1179 (mml2015-extract-cleartext-signature))))
1181 (defun mml2015-epg-sign (cont)
1182 (let* ((inhibit-redisplay t
)
1183 (context (epg-make-context))
1184 (boundary (mml-compute-boundary cont
))
1187 (or (message-options-get 'mml2015-epg-signers
)
1188 (message-options-set
1189 'mml2015-epg-signers
1191 (epa-select-keys context
"\
1192 Select keys for signing.
1193 If no one is selected, default secret key is used. "
1199 (setq signer-key
(mml2015-epg-find-usable-key
1200 (epg-list-keys context signer t
)
1202 (unless (or signer-key
1205 "No secret key for %s; skip it? "
1207 (error "No secret key for %s" signer
))
1209 mml2015-signers
)))))))
1211 (epg-context-set-armor context t
)
1212 (epg-context-set-textmode context t
)
1213 (epg-context-set-signers context signers
)
1214 (if mml2015-cache-passphrase
1215 (epg-context-set-passphrase-callback
1217 #'mml2015-epg-passphrase-callback
))
1218 (condition-case error
1219 (setq signature
(epg-sign-string context
(buffer-string) t
)
1220 mml2015-epg-secret-key-id-list nil
)
1222 (while mml2015-epg-secret-key-id-list
1223 (password-cache-remove (car mml2015-epg-secret-key-id-list
))
1224 (setq mml2015-epg-secret-key-id-list
1225 (cdr mml2015-epg-secret-key-id-list
)))
1226 (signal (car error
) (cdr error
))))
1227 (if (epg-context-result-for context
'sign
)
1228 (setq micalg
(epg-new-signature-digest-algorithm
1229 (car (epg-context-result-for context
'sign
)))))
1230 (goto-char (point-min))
1231 (insert (format "Content-Type: multipart/signed; boundary=\"%s\";\n"
1234 (insert (format "\tmicalg=pgp-%s; "
1237 epg-digest-algorithm-alist
))))))
1238 (insert "protocol=\"application/pgp-signature\"\n")
1239 (insert (format "\n--%s\n" boundary
))
1240 (goto-char (point-max))
1241 (insert (format "\n--%s\n" boundary
))
1242 (insert "Content-Type: application/pgp-signature\n\n")
1244 (goto-char (point-max))
1245 (insert (format "--%s--\n" boundary
))
1246 (goto-char (point-max))))
1248 (defun mml2015-epg-encrypt (cont &optional sign
)
1249 (let ((inhibit-redisplay t
)
1250 (context (epg-make-context))
1251 (config (epg-configuration))
1252 (recipients (message-options-get 'mml2015-epg-recipients
))
1254 (boundary (mml-compute-boundary cont
))
1255 recipient-key signer-key
)
1261 (or (epg-expand-group config recipient
)
1262 (list (concat "<" recipient
">"))))
1264 (or (message-options-get 'message-recipients
)
1265 (message-options-set 'message-recipients
1266 (read-string "Recipients: ")))
1267 "[ \f\t\n\r\v,]+"))))
1268 (when mml2015-encrypt-to-self
1269 (unless mml2015-signers
1270 (error "mml2015-signers not set"))
1271 (setq recipients
(nconc recipients mml2015-signers
)))
1274 (epa-select-keys context
"\
1275 Select recipients for encryption.
1276 If no one is selected, symmetric encryption will be performed. "
1282 (setq recipient-key
(mml2015-epg-find-usable-key
1283 (epg-list-keys context recipient
)
1285 (unless (or recipient-key
1287 (format "No public key for %s; skip it? "
1289 (error "No public key for %s" recipient
))
1293 (error "No recipient specified")))
1294 (message-options-set 'mml2015-epg-recipients recipients
))
1297 (or (message-options-get 'mml2015-epg-signers
)
1298 (message-options-set
1299 'mml2015-epg-signers
1301 (epa-select-keys context
"\
1302 Select keys for signing.
1303 If no one is selected, default secret key is used. "
1309 (setq signer-key
(mml2015-epg-find-usable-key
1310 (epg-list-keys context signer t
)
1312 (unless (or signer-key
1315 "No secret key for %s; skip it? "
1317 (error "No secret key for %s" signer
))
1319 mml2015-signers
)))))))
1320 (epg-context-set-signers context signers
))
1321 (epg-context-set-armor context t
)
1322 (epg-context-set-textmode context t
)
1323 (if mml2015-cache-passphrase
1324 (epg-context-set-passphrase-callback
1326 #'mml2015-epg-passphrase-callback
))
1327 (condition-case error
1329 (epg-encrypt-string context
(buffer-string) recipients sign
1330 mml2015-always-trust
)
1331 mml2015-epg-secret-key-id-list nil
)
1333 (while mml2015-epg-secret-key-id-list
1334 (password-cache-remove (car mml2015-epg-secret-key-id-list
))
1335 (setq mml2015-epg-secret-key-id-list
1336 (cdr mml2015-epg-secret-key-id-list
)))
1337 (signal (car error
) (cdr error
))))
1338 (delete-region (point-min) (point-max))
1339 (goto-char (point-min))
1340 (insert (format "Content-Type: multipart/encrypted; boundary=\"%s\";\n"
1342 (insert "\tprotocol=\"application/pgp-encrypted\"\n\n")
1343 (insert (format "--%s\n" boundary
))
1344 (insert "Content-Type: application/pgp-encrypted\n\n")
1345 (insert "Version: 1\n\n")
1346 (insert (format "--%s\n" boundary
))
1347 (insert "Content-Type: application/octet-stream\n\n")
1349 (goto-char (point-max))
1350 (insert (format "--%s--\n" boundary
))
1351 (goto-char (point-max))))
1355 (autoload 'gnus-buffer-live-p
"gnus-util")
1356 (autoload 'gnus-get-buffer-create
"gnus")
1358 (defun mml2015-clean-buffer ()
1359 (if (gnus-buffer-live-p mml2015-result-buffer
)
1360 (with-current-buffer mml2015-result-buffer
1363 (setq mml2015-result-buffer
1364 (gnus-get-buffer-create " *MML2015 Result*"))
1367 (defsubst mml2015-clear-decrypt-function
()
1368 (nth 6 (assq mml2015-use mml2015-function-alist
)))
1370 (defsubst mml2015-clear-verify-function
()
1371 (nth 5 (assq mml2015-use mml2015-function-alist
)))
1374 (defun mml2015-decrypt (handle ctl
)
1375 (mml2015-clean-buffer)
1376 (let ((func (nth 4 (assq mml2015-use mml2015-function-alist
))))
1378 (funcall func handle ctl
)
1382 (defun mml2015-decrypt-test (handle ctl
)
1386 (defun mml2015-verify (handle ctl
)
1387 (mml2015-clean-buffer)
1388 (let ((func (nth 3 (assq mml2015-use mml2015-function-alist
))))
1390 (funcall func handle ctl
)
1394 (defun mml2015-verify-test (handle ctl
)
1398 (defun mml2015-encrypt (cont &optional sign
)
1399 (mml2015-clean-buffer)
1400 (let ((func (nth 2 (assq mml2015-use mml2015-function-alist
))))
1402 (funcall func cont sign
)
1403 (error "Cannot find encrypt function"))))
1406 (defun mml2015-sign (cont)
1407 (mml2015-clean-buffer)
1408 (let ((func (nth 1 (assq mml2015-use mml2015-function-alist
))))
1411 (error "Cannot find sign function"))))
1414 (defun mml2015-self-encrypt ()
1415 (mml2015-encrypt nil
))
1419 ;; arch-tag: b04701d5-0b09-44d8-bed8-de901bf435f2
1420 ;;; mml2015.el ends here