X-Git-Url: http://cgit.sxemacs.org/?a=blobdiff_plain;f=lisp%2Fmml-smime.el;h=caa1380a497d70856df487380238006494287c0f;hb=3b44d0724366741786a96801d29ddd1c5b949a38;hp=33050fecaeee153c49b4f27a0a0fd422e0ea07cc;hpb=ff79efac756f360c9a48b292b4619699fe19d057;p=gnus diff --git a/lisp/mml-smime.el b/lisp/mml-smime.el index 33050feca..caa1380a4 100644 --- a/lisp/mml-smime.el +++ b/lisp/mml-smime.el @@ -1,7 +1,6 @@ ;;; mml-smime.el --- S/MIME support for MML -;; Copyright (C) 2000, 2001, 2002, 2003, 2004, -;; 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. +;; Copyright (C) 2000-2014 Free Software Foundation, Inc. ;; Author: Simon Josefsson ;; Keywords: Gnus, MIME, S/MIME, MML @@ -25,10 +24,6 @@ ;;; Code: -;; For Emacs <22.2 and XEmacs. -(eval-and-compile - (unless (fboundp 'declare-function) (defmacro declare-function (&rest r)))) - (eval-when-compile (require 'cl)) (require 'smime) @@ -37,7 +32,12 @@ (autoload 'message-narrow-to-headers "message") (autoload 'message-fetch-field "message") -(defvar mml-smime-use 'openssl) +(defcustom mml-smime-use (if (featurep 'epg) 'epg 'openssl) + "Whether to use OpenSSL or EPG to decrypt S/MIME messages. +Defaults to EPG if it's loaded." + :group 'mime-security + :type '(choice (const :tag "EPG" epg) + (const :tag "OpenSSL" openssl))) (defvar mml-smime-function-alist '((openssl mml-smime-openssl-sign @@ -70,6 +70,18 @@ Whether the passphrase is cached at all is controlled by :group 'mime-security :type '(repeat (string :tag "Key ID"))) +(defcustom mml-smime-sign-with-sender nil + "If t, use message sender so find a key to sign with." + :group 'mime-security + :version "24.4" + :type 'boolean) + +(defcustom mml-smime-encrypt-to-self nil + "If t, add your own key ID to recipient list when encryption." + :group 'mime-security + :version "24.4" + :type 'boolean) + (defun mml-smime-sign (cont) (let ((func (nth 1 (assq mml-smime-use mml-smime-function-alist)))) (if func @@ -319,6 +331,7 @@ Whether the passphrase is cached at all is controlled by (autoload 'epg-encrypt-string "epg") (autoload 'epg-passphrase-callback-function "epg") (autoload 'epg-context-set-passphrase-callback "epg") + (autoload 'epg-sub-key-fingerprint "epg") (autoload 'epg-configuration "epg-config") (autoload 'epg-expand-group "epg-config") (autoload 'epa-select-keys "epa")) @@ -362,6 +375,24 @@ Whether the passphrase is cached at all is controlled by (setq pointer (cdr pointer)))) (setq keys (cdr keys))))) +;; XXX: since gpg --list-secret-keys does not return validity of each +;; key, `mml-smime-epg-find-usable-key' defined above is not enough for +;; secret keys. The function `mml-smime-epg-find-usable-secret-key' +;; below looks at appropriate public keys to check usability. +(defun mml-smime-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 (mml-smime-epg-find-usable-key + (epg-list-keys context (epg-sub-key-fingerprint + (car (epg-key-sub-key-list + (car secret-keys))))) + usage) + (setq secret-key (car secret-keys) + secret-keys nil) + (setq secret-keys (cdr secret-keys)))) + secret-key)) + (autoload 'mml-compute-boundary "mml") ;; We require mm-decode, which requires mm-bodies, which autoloads @@ -372,29 +403,36 @@ Whether the passphrase is cached at all is controlled by (let* ((inhibit-redisplay t) (context (epg-make-context 'CMS)) (boundary (mml-compute-boundary cont)) + (sender (message-options-get 'message-sender)) + (signer-names (or mml-smime-signers + (if (and mml-smime-sign-with-sender sender) + (list (concat "<" sender ">"))))) signer-key (signers (or (message-options-get 'mml-smime-epg-signers) (message-options-set - 'mml-smime-epg-signers - (if (eq mm-sign-option 'guided) - (epa-select-keys context "\ + 'mml-smime-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. " - mml-smime-signers t) - (if mml-smime-signers - (mapcar - (lambda (signer) - (setq signer-key (mml-smime-epg-find-usable-key - (epg-list-keys context signer t) - 'sign)) - (unless (or signer-key - (y-or-n-p - (format "No secret key for %s; skip it? " + signer-names + t) + (if (or sender mml-smime-signers) + (delq nil + (mapcar + (lambda (signer) + (setq signer-key + (mml-smime-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) - mml-smime-signers)))))) + (error "No secret key for %s" signer)) + signer-key) + signer-names))))))) signature micalg) (epg-context-set-signers context signers) (if mml-smime-cache-passphrase @@ -439,13 +477,17 @@ Content-Disposition: attachment; filename=smime.p7s (goto-char (point-max)))) (defun mml-smime-epg-encrypt (cont) - (let ((inhibit-redisplay t) - (context (epg-make-context 'CMS)) - (config (epg-configuration)) - (recipients (message-options-get 'mml-smime-epg-recipients)) - cipher signers - (boundary (mml-compute-boundary cont)) - recipient-key) + (let* ((inhibit-redisplay t) + (context (epg-make-context 'CMS)) + (config (epg-configuration)) + (recipients (message-options-get 'mml-smime-epg-recipients)) + cipher signers + (sender (message-options-get 'message-sender)) + (signer-names (or mml-smime-signers + (if (and mml-smime-sign-with-sender sender) + (list (concat "<" sender ">"))))) + (boundary (mml-compute-boundary cont)) + recipient-key) (unless recipients (setq recipients (apply #'nconc @@ -458,6 +500,10 @@ Content-Disposition: attachment; filename=smime.p7s (message-options-set 'message-recipients (read-string "Recipients: "))) "[ \f\t\n\r\v,]+")))) + (when mml-smime-encrypt-to-self + (unless signer-names + (error "Neither message sender nor mml-smime-signers are set")) + (setq recipients (nconc recipients signer-names))) (if (eq mm-encrypt-option 'guided) (setq recipients (epa-select-keys context "\ @@ -527,7 +573,7 @@ Content-Disposition: attachment; filename=smime.p7m (mm-set-handle-multipart-parameter mm-security-handle 'gnus-info "Corrupted") (throw 'error handle)) - (setq part (mm-replace-in-string part "\n" "\r\n" t) + (setq part (mm-replace-in-string part "\n" "\r\n") context (epg-make-context 'CMS)) (condition-case error (setq plain (epg-verify-string context (mm-get-part signature) part))