X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/325c5543035b411ae79839dda47bbbbde838d36b..368cb23fe249334bf9d230755ae07b6410ac6852:/lisp/gnus/mml2015.el?ds=sidebyside diff --git a/lisp/gnus/mml2015.el b/lisp/gnus/mml2015.el index 5104cea5ab..774821320f 100644 --- a/lisp/gnus/mml2015.el +++ b/lisp/gnus/mml2015.el @@ -1,6 +1,6 @@ ;;; mml2015.el --- MIME Security with Pretty Good Privacy (PGP) -;; Copyright (C) 2000-2015 Free Software Foundation, Inc. +;; Copyright (C) 2000-2016 Free Software Foundation, Inc. ;; Author: Shenghuo Zhu ;; Keywords: PGP MIME MML @@ -27,16 +27,12 @@ ;;; Code: -(eval-and-compile - (if (locate-library "password-cache") - (require 'password-cache) - (require 'password))) - (eval-when-compile (require 'cl)) (require 'mm-decode) (require 'mm-util) (require 'mml) (require 'mml-sec) +(require 'epg-config) (defvar mc-pgp-always-sign) @@ -47,27 +43,7 @@ ;; Maybe this should be in eg mml-sec.el (and have a different name). ;; Then mml1991 would not need to require mml2015, and mml1991-use ;; could be removed. -(defvar mml2015-use (or - (progn - (ignore-errors (require 'epg-config)) - (and (fboundp 'epg-check-configuration) - 'epg)) - (progn - (let ((abs-file (locate-library "pgg"))) - ;; Don't load PGG if it is marked as obsolete - ;; (Emacs 24). - (when (and abs-file - (not (string-match "/obsolete/[^/]*\\'" - abs-file))) - (ignore-errors (require 'pgg)) - (and (fboundp 'pgg-sign-region) - 'pgg)))) - (progn (ignore-errors - (load "mc-toplev")) - (and (fboundp 'mc-encrypt-generic) - (fboundp 'mc-sign-generic) - (fboundp 'mc-cleanup-recipient-headers) - 'mailcrypt))) +(defvar mml2015-use 'epg "The package used for PGP/MIME. Valid packages include `epg', `pgg' and `mailcrypt'.") @@ -111,6 +87,9 @@ Valid packages include `epg', `pgg' and `mailcrypt'.") "If t, cache passphrase." :group 'mime-security :type 'boolean) +(make-obsolete-variable 'mml2015-cache-passphrase + 'mml-secure-cache-passphrase + "25.1") (defcustom mml2015-passphrase-cache-expiry mml-secure-passphrase-cache-expiry "How many seconds the passphrase is cached. @@ -118,6 +97,9 @@ Whether the passphrase is cached at all is controlled by `mml2015-cache-passphrase'." :group 'mime-security :type 'integer) +(make-obsolete-variable 'mml2015-passphrase-cache-expiry + 'mml-secure-passphrase-cache-expiry + "25.1") (defcustom mml2015-signers nil "A list of your own key ID(s) which will be used to sign a message. @@ -481,14 +463,17 @@ If set, it overrides the setting of `mml2015-sign-with-sender'." (or (y-or-n-p "Sign the message? ") 'not)))) 'never))) - (mm-with-unibyte-current-buffer - (mc-encrypt-generic - (or (message-options-get 'message-recipients) - (message-options-set 'message-recipients - (mc-cleanup-recipient-headers - (read-string "Recipients: ")))) - nil nil nil - (message-options-get 'message-sender)))) + (insert + (with-temp-buffer + (set-buffer-multibyte nil) + (mc-encrypt-generic + (or (message-options-get 'message-recipients) + (message-options-set 'message-recipients + (mc-cleanup-recipient-headers + (read-string "Recipients: ")))) + nil nil nil + (message-options-get 'message-sender)) + (buffer-string)))) (goto-char (point-min)) (unless (looking-at "-----BEGIN PGP MESSAGE-----") (error "Fail to encrypt the message")) @@ -613,7 +598,7 @@ If set, it overrides the setting of `mml2015-sign-with-sender'." (insert "\r")) (forward-line) (end-of-line)) - (with-temp-file (setq signature-file (mm-make-temp-file "pgg")) + (with-temp-file (setq signature-file (make-temp-file "pgg")) (mm-insert-part signature)) (if (condition-case err (prog1 @@ -654,7 +639,7 @@ If set, it overrides the setting of `mml2015-sign-with-sender'." (if (condition-case err (prog1 (mm-with-unibyte-buffer - (insert (mm-encode-coding-string text coding-system)) + (insert (encode-coding-string text coding-system)) (pgg-verify-region (point-min) (point-max) nil t)) (goto-char (point-min)) (while (search-forward "\r\n" nil t) @@ -774,105 +759,10 @@ If set, it overrides the setting of `mml2015-sign-with-sender'." (autoload 'epg-expand-group "epg-config") (autoload 'epa-select-keys "epa") -(defvar mml2015-epg-secret-key-id-list nil) - -(defun mml2015-epg-passphrase-callback (context key-id ignore) - (if (eq key-id 'SYM) - (epg-passphrase-callback-function context key-id nil) - (let* ((password-cache-key-id - (if (eq key-id 'PIN) - "PIN" - key-id)) - entry - (passphrase - (password-read - (if (eq key-id 'PIN) - "Passphrase for PIN: " - (if (setq entry (assoc key-id epg-user-id-alist)) - (format "Passphrase for %s %s: " key-id (cdr entry)) - (format "Passphrase for %s: " key-id))) - password-cache-key-id))) - (when passphrase - (let ((password-cache-expiry mml2015-passphrase-cache-expiry)) - (password-cache-add password-cache-key-id passphrase)) - (setq mml2015-epg-secret-key-id-list - (cons password-cache-key-id mml2015-epg-secret-key-id-list)) - (copy-sequence passphrase))))) - -(defun mml2015-epg-check-user-id (key recipient) - (let ((pointer (epg-key-user-id-list key)) - result) - (while pointer - (if (and (equal (car (mail-header-parse-address - (epg-user-id-string (car pointer)))) - (car (mail-header-parse-address - recipient))) - (not (memq (epg-user-id-validity (car pointer)) - '(revoked expired)))) - (setq result t - pointer nil) - (setq pointer (cdr pointer)))) - result)) - -(defun mml2015-epg-check-sub-key (key usage) - (let ((pointer (epg-key-sub-key-list key)) - result) - ;; The primary key will be marked as disabled, when the entire - ;; key is disabled (see 12 Field, Format of colon listings, in - ;; gnupg/doc/DETAILS) - (unless (memq 'disabled (epg-sub-key-capability (car pointer))) - (while pointer - (if (and (memq usage (epg-sub-key-capability (car pointer))) - (not (memq (epg-sub-key-validity (car pointer)) - '(revoked expired)))) - (setq result t - pointer nil) - (setq pointer (cdr pointer))))) - result)) - -(defun mml2015-epg-find-usable-key (context name usage - &optional name-is-key-id) - (let ((keys (epg-list-keys context name)) - key) - (while keys - (if (and (or name-is-key-id - ;; Non email user-id can be supplied through - ;; mml2015-signers if mml2015-encrypt-to-self is set. - ;; Treat it as valid, as it is user's intention. - (not (string-match "\\`<" name)) - (mml2015-epg-check-user-id (car keys) name)) - (mml2015-epg-check-sub-key (car keys) usage)) - (setq key (car keys) - keys nil) - (setq keys (cdr keys)))) - key)) - -;; XXX: since gpg --list-secret-keys does not return validity of each -;; key, `mml2015-epg-find-usable-key' defined above is not enough for -;; secret keys. The function `mml2015-epg-find-usable-secret-key' -;; below looks at appropriate public keys to check usability. -(defun mml2015-epg-find-usable-secret-key (context name usage) - (let ((secret-keys (epg-list-keys context name t)) - secret-key) - (while (and (not secret-key) secret-keys) - (if (mml2015-epg-find-usable-key - context - (epg-sub-key-fingerprint - (car (epg-key-sub-key-list - (car secret-keys)))) - usage - t) - (setq secret-key (car secret-keys) - secret-keys nil) - (setq secret-keys (cdr secret-keys)))) - secret-key)) - -(autoload 'gnus-create-image "gnus-ems") - (defun mml2015-epg-key-image (key-id) "Return the image of a key, if any" (with-temp-buffer - (mm-set-buffer-multibyte nil) + (set-buffer-multibyte nil) (let* ((coding-system-for-write 'binary) (coding-system-for-read 'binary) (data (shell-command-to-string @@ -921,18 +811,15 @@ If set, it overrides the setting of `mml2015-sign-with-sender'." mm-security-handle 'gnus-info "Corrupted") (throw 'error handle)) (setq context (epg-make-context)) - (if mml2015-cache-passphrase + (if (or mml2015-cache-passphrase mml-secure-cache-passphrase) (epg-context-set-passphrase-callback context - #'mml2015-epg-passphrase-callback)) + (cons 'mml-secure-passphrase-callback 'OpenPGP))) (condition-case error (setq plain (epg-decrypt-string context (mm-get-part child)) - mml2015-epg-secret-key-id-list nil) + mml-secure-secret-key-id-list nil) (error - (while mml2015-epg-secret-key-id-list - (password-cache-remove (car mml2015-epg-secret-key-id-list)) - (setq mml2015-epg-secret-key-id-list - (cdr mml2015-epg-secret-key-id-list))) + (mml-secure-clear-secret-key-id-list) (mm-set-handle-multipart-parameter mm-security-handle 'gnus-info "Failed") (if (eq (car error) 'quit) @@ -968,18 +855,15 @@ If set, it overrides the setting of `mml2015-sign-with-sender'." (let ((inhibit-redisplay t) (context (epg-make-context)) plain) - (if mml2015-cache-passphrase + (if (or mml2015-cache-passphrase mml-secure-cache-passphrase) (epg-context-set-passphrase-callback context - #'mml2015-epg-passphrase-callback)) + (cons 'mml-secure-passphrase-callback 'OpenPGP))) (condition-case error (setq plain (epg-decrypt-string context (buffer-string)) - mml2015-epg-secret-key-id-list nil) + mml-secure-secret-key-id-list nil) (error - (while mml2015-epg-secret-key-id-list - (password-cache-remove (car mml2015-epg-secret-key-id-list)) - (setq mml2015-epg-secret-key-id-list - (cdr mml2015-epg-secret-key-id-list))) + (mml-secure-clear-secret-key-id-list) (mm-set-handle-multipart-parameter mm-security-handle 'gnus-info "Failed") (if (eq (car error) 'quit) @@ -1018,7 +902,7 @@ If set, it overrides the setting of `mml2015-sign-with-sender'." (mm-set-handle-multipart-parameter mm-security-handle 'gnus-info "Corrupted") (throw 'error handle)) - (setq part (mm-replace-in-string part "\n" "\r\n") + (setq part (replace-regexp-in-string "\n" "\r\n" part) signature (mm-get-part signature) context (epg-make-context)) (condition-case error @@ -1041,8 +925,8 @@ If set, it overrides the setting of `mml2015-sign-with-sender'." (defun mml2015-epg-clear-verify () (let ((inhibit-redisplay t) (context (epg-make-context)) - (signature (mm-encode-coding-string (buffer-string) - coding-system-for-write)) + (signature (encode-coding-string (buffer-string) + coding-system-for-write)) plain) (condition-case error (setq plain (epg-verify-string context signature)) @@ -1061,180 +945,41 @@ If set, it overrides the setting of `mml2015-sign-with-sender'." (mml2015-epg-verify-result-to-string (epg-context-result-for context 'verify))) (delete-region (point-min) (point-max)) - (insert (mm-decode-coding-string plain coding-system-for-read))) + (insert (decode-coding-string plain coding-system-for-read))) (mml2015-extract-cleartext-signature)))) (defun mml2015-epg-sign (cont) - (let* ((inhibit-redisplay t) - (context (epg-make-context)) - (boundary (mml-compute-boundary cont)) - (sender (message-options-get 'message-sender)) - (signer-names (or mml2015-signers - (if (and mml2015-sign-with-sender sender) - (list (concat "<" sender ">"))))) - signer-key - (signers - (or (message-options-get 'mml2015-epg-signers) - (message-options-set - 'mml2015-epg-signers - (if (eq mm-sign-option 'guided) - (epa-select-keys context "\ -Select keys for signing. -If no one is selected, default secret key is used. " - signer-names - t) - (if (or sender mml2015-signers) - (delq nil - (mapcar - (lambda (signer) - (setq signer-key - (mml2015-epg-find-usable-secret-key - context signer 'sign)) - (unless (or signer-key - (y-or-n-p - (format - "No secret key for %s; skip it? " - signer))) - (error "No secret key for %s" signer)) - signer-key) - signer-names))))))) - signature micalg) - (epg-context-set-armor context t) - (epg-context-set-textmode context t) - (epg-context-set-signers context signers) - (if mml2015-cache-passphrase - (epg-context-set-passphrase-callback - context - #'mml2015-epg-passphrase-callback)) + (let ((inhibit-redisplay t) + (boundary (mml-compute-boundary cont))) ;; Signed data must end with a newline (RFC 3156, 5). (goto-char (point-max)) (unless (bolp) (insert "\n")) - (condition-case error - (setq signature (epg-sign-string context (buffer-string) t) - mml2015-epg-secret-key-id-list nil) - (error - (while mml2015-epg-secret-key-id-list - (password-cache-remove (car mml2015-epg-secret-key-id-list)) - (setq mml2015-epg-secret-key-id-list - (cdr mml2015-epg-secret-key-id-list))) - (signal (car error) (cdr error)))) - (if (epg-context-result-for context 'sign) - (setq micalg (epg-new-signature-digest-algorithm - (car (epg-context-result-for context 'sign))))) - (goto-char (point-min)) - (insert (format "Content-Type: multipart/signed; boundary=\"%s\";\n" - boundary)) - (if micalg - (insert (format "\tmicalg=pgp-%s; " - (downcase - (cdr (assq micalg - epg-digest-algorithm-alist)))))) - (insert "protocol=\"application/pgp-signature\"\n") - (insert (format "\n--%s\n" boundary)) - (goto-char (point-max)) - (insert (format "\n--%s\n" boundary)) - (insert "Content-Type: application/pgp-signature; name=\"signature.asc\"\n\n") - (insert signature) - (goto-char (point-max)) - (insert (format "--%s--\n" boundary)) - (goto-char (point-max)))) + (let* ((pair (mml-secure-epg-sign 'OpenPGP t)) + (signature (car pair)) + (micalg (cdr pair))) + (goto-char (point-min)) + (insert (format "Content-Type: multipart/signed; boundary=\"%s\";\n" + boundary)) + (if micalg + (insert (format "\tmicalg=pgp-%s; " + (downcase + (cdr (assq micalg + epg-digest-algorithm-alist)))))) + (insert "protocol=\"application/pgp-signature\"\n") + (insert (format "\n--%s\n" boundary)) + (goto-char (point-max)) + (insert (format "\n--%s\n" boundary)) + (insert "Content-Type: application/pgp-signature; name=\"signature.asc\"\n\n") + (insert signature) + (goto-char (point-max)) + (insert (format "--%s--\n" boundary)) + (goto-char (point-max))))) (defun mml2015-epg-encrypt (cont &optional sign) (let* ((inhibit-redisplay t) - (context (epg-make-context)) (boundary (mml-compute-boundary cont)) - (config (epg-configuration)) - (recipients (message-options-get 'mml2015-epg-recipients)) - cipher - (sender (message-options-get 'message-sender)) - (signer-names (or mml2015-signers - (if (and mml2015-sign-with-sender sender) - (list (concat "<" sender ">"))))) - signers - recipient-key signer-key) - (unless recipients - (setq recipients - (apply #'nconc - (mapcar - (lambda (recipient) - (or (epg-expand-group config recipient) - (list (concat "<" recipient ">")))) - (split-string - (or (message-options-get 'message-recipients) - (message-options-set 'message-recipients - (read-string "Recipients: "))) - "[ \f\t\n\r\v,]+")))) - (when mml2015-encrypt-to-self - (unless signer-names - (error "Neither message sender nor mml2015-signers are set")) - (setq recipients (nconc recipients signer-names))) - (if (eq mm-encrypt-option 'guided) - (setq recipients - (epa-select-keys context "\ -Select recipients for encryption. -If no one is selected, symmetric encryption will be performed. " - recipients)) - (setq recipients - (delq nil - (mapcar - (lambda (recipient) - (setq recipient-key (mml2015-epg-find-usable-key - context recipient 'encrypt)) - (unless (or recipient-key - (y-or-n-p - (format "No public key for %s; skip it? " - recipient))) - (error "No public key for %s" recipient)) - recipient-key) - recipients))) - (unless recipients - (error "No recipient specified"))) - (message-options-set 'mml2015-epg-recipients recipients)) - (when sign - (setq signers - (or (message-options-get 'mml2015-epg-signers) - (message-options-set - 'mml2015-epg-signers - (if (eq mm-sign-option 'guided) - (epa-select-keys context "\ -Select keys for signing. -If no one is selected, default secret key is used. " - signer-names - t) - (if (or sender mml2015-signers) - (delq nil - (mapcar - (lambda (signer) - (setq signer-key - (mml2015-epg-find-usable-secret-key - context signer 'sign)) - (unless (or signer-key - (y-or-n-p - (format - "No secret key for %s; skip it? " - signer))) - (error "No secret key for %s" signer)) - signer-key) - signer-names))))))) - (epg-context-set-signers context signers)) - (epg-context-set-armor context t) - (epg-context-set-textmode context t) - (if mml2015-cache-passphrase - (epg-context-set-passphrase-callback - context - #'mml2015-epg-passphrase-callback)) - (condition-case error - (setq cipher - (epg-encrypt-string context (buffer-string) recipients sign - mml2015-always-trust) - mml2015-epg-secret-key-id-list nil) - (error - (while mml2015-epg-secret-key-id-list - (password-cache-remove (car mml2015-epg-secret-key-id-list)) - (setq mml2015-epg-secret-key-id-list - (cdr mml2015-epg-secret-key-id-list))) - (signal (car error) (cdr error)))) + (cipher (mml-secure-epg-encrypt 'OpenPGP cont sign))) (delete-region (point-min) (point-max)) (goto-char (point-min)) (insert (format "Content-Type: multipart/encrypted; boundary=\"%s\";\n"