Accept the moronic openssl s_client -starttls output, too.
[gnus] / lisp / smime.el
index eecfffb..2492007 100644 (file)
@@ -1,32 +1,32 @@
 ;;; smime.el --- S/MIME support library
-;; Copyright (c) 2000, 2001 Free Software Foundation, Inc.
+
+;; Copyright (C) 2000, 2001, 2002, 2003, 2004,
+;;   2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
 
 ;; Author: Simon Josefsson <simon@josefsson.org>
 ;; Keywords: SMIME X.509 PEM OpenSSL
 
-;; This file is not a part of GNU Emacs, but the same permissions apply.
+;; This file is part of GNU Emacs.
 
-;; GNU Emacs is free software; you can redistribute it and/or modify
-;; it under the terms of the GNU General Public License as published
-;; by the Free Software Foundation; either version 2, or (at your
-;; option) any later version.
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
 
-;; GNU Emacs is distributed in the hope that it will be useful, but
-;; WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-;; General Public License for more details.
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
 
 ;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs; see the file COPYING.  If not, write to the
-;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
 
 ;;; Commentary:
 
 ;; This library perform S/MIME operations from within Emacs.
 ;;
 ;; Functions for fetching certificates from public repositories are
-;; provided, currently only from DNS.  LDAP support (via EUDC) is planned.
+;; provided, currently from DNS and LDAP.
 ;;
 ;; It uses OpenSSL (tested with version 0.9.5a and 0.9.6) for signing,
 ;; encryption and decryption.
@@ -41,6 +41,9 @@
 ;; PKCSx or similar, it's intended to perform common operations
 ;; done on messages encoded in these formats.  The terminology chosen
 ;; reflect this.
+;;
+;; The home of this file is in Gnus, but also available from
+;; http://josefsson.org/smime.html.
 
 ;;; Quick introduction:
 
@@ -60,7 +63,7 @@
 ;;
 ;; Now you should be able to sign messages!  Create a buffer and write
 ;; something and run M-x smime-sign-buffer RET RET and you should see
-;; your message MIME armoured and a signature.  Encryption, M-x
+;; your message MIME armored and a signature.  Encryption, M-x
 ;; smime-encrypt-buffer, should also work.
 ;;
 ;; To be able to verify messages you need to build up trust with
@@ -93,7 +96,7 @@
 ;;
 ;; Suggestions and comments are appreciated, mail me at simon@josefsson.org.
 
-;; <rant>
+;; begin rant
 ;;
 ;; I would include pointers to introductory text on concepts used in
 ;; this library here, but the material I've read are so horrible I
 ;; Also, I'm not going to mention anything about the wonders of
 ;; cryptopolitics.  Oops, I just did.
 ;;
-;; </rant>
+;; end rant
 
 ;;; Revision history:
 
-;; version 0 not released
+;; 2000-06-05  initial version, committed to Gnus CVS contrib/
+;; 2000-10-28  retrieve certificates via DNS CERT RRs
+;; 2001-10-14  posted to gnu.emacs.sources
+;; 2005-02-13  retrieve certificates via LDAP
 
 ;;; Code:
 
+;; For Emacs < 22.2.
+(eval-and-compile
+  (unless (fboundp 'declare-function) (defmacro declare-function (&rest r))))
 (require 'dig)
-(require 'comint)
+
+(if (locate-library "password-cache")
+    (require 'password-cache)
+  (require 'password))
+
 (eval-when-compile (require 'cl))
 
+(eval-and-compile
+  (cond
+   ((fboundp 'replace-in-string)
+    (defalias 'smime-replace-in-string 'replace-in-string))
+   ((fboundp 'replace-regexp-in-string)
+    (defun smime-replace-in-string  (string regexp newtext &optional literal)
+      "Replace all matches for REGEXP with NEWTEXT in STRING.
+If LITERAL is non-nil, insert NEWTEXT literally.  Return a new
+string containing the replacements.
+
+This is a compatibility function for different Emacsen."
+      (replace-regexp-in-string regexp newtext string nil literal)))))
+
 (defgroup smime nil
-  "S/MIME configuration.")
+  "S/MIME configuration."
+  :group 'mime)
 
 (defcustom smime-keys nil
   "*Map mail addresses to a file containing Certificate (and private key).
@@ -135,7 +162,7 @@ certificates to be sent with every message to each address."
 Directory should contain files (in PEM format) named to the X.509
 hash of the certificate.  This can be done using OpenSSL such as:
 
-$ ln -s ca.pem `openssl x509 -noout -hash -in ca.pem`
+$ ln -s ca.pem `openssl x509 -noout -hash -in ca.pem`.0
 
 where `ca.pem' is the file containing a PEM encoded X.509 CA
 certificate."
@@ -146,6 +173,7 @@ certificate."
 (defcustom smime-CA-file nil
   "*Files containing certificates for CAs you trust.
 File should contain certificates in PEM format."
+  :version "22.1"
   :type '(choice (const :tag "none" nil)
                 file)
   :group 'smime)
@@ -173,6 +201,7 @@ and the files themself should be in PEM format."
 
 (defcustom smime-encrypt-cipher "-des3"
   "*Cipher algorithm used for encryption."
+  :version "22.1"
   :type '(choice (const :tag "Triple DES" "-des3")
                 (const :tag "DES"  "-des")
                 (const :tag "RC2 40 bits" "-rc2-40")
@@ -180,15 +209,46 @@ and the files themself should be in PEM format."
                 (const :tag "RC2 128 bits" "-rc2-128"))
   :group 'smime)
 
+(defcustom smime-crl-check nil
+  "*Check revocation status of signers certificate using CRLs.
+Enabling this will have OpenSSL check the signers certificate
+against a certificate revocation list (CRL).
+
+For this to work the CRL must be up-to-date and since they are
+normally updated quite often (ie. several times a day) you
+probably need some tool to keep them up-to-date. Unfortunately
+Gnus cannot do this for you.
+
+The CRL should either be appended (in PEM format) to your
+`smime-CA-file' or be located in a file (also in PEM format) in
+your `smime-certificate-directory' named to the X.509 hash of the
+certificate with .r0 as file name extension.
+
+At least OpenSSL version 0.9.7 is required for this to work."
+  :type '(choice (const :tag "No check" nil)
+                (const :tag "Check certificate" "-crl_check")
+                (const :tag "Check certificate chain" "-crl_check_all"))
+  :group 'smime)
+
 (defcustom smime-dns-server nil
   "*DNS server to query certificates from.
 If nil, use system defaults."
+  :version "22.1"
   :type '(choice (const :tag "System defaults")
                 string)
   :group 'smime)
 
+(defcustom smime-ldap-host-list nil
+  "A list of LDAP hosts with S/MIME user certificates.
+If needed search base, binddn, passwd, etc. for the LDAP host
+must be set in `ldap-host-parameters-alist'."
+  :type '(repeat (string :tag "Host name"))
+  :version "23.1" ;; No Gnus
+  :group 'smime)
+
 (defvar smime-details-buffer "*OpenSSL output*")
 
+;; Use mm-util?
 (eval-and-compile
   (defalias 'smime-make-temp-file
     (if (fboundp 'make-temp-file)
@@ -196,15 +256,20 @@ If nil, use system defaults."
       (lambda (prefix &optional dir-flag) ;; Simple implementation
        (expand-file-name
         (make-temp-name prefix)
-        temporary-file-directory)))))
+        (if (fboundp 'temp-directory)
+            (temp-directory)
+          temporary-file-directory))))))
 
 ;; Password dialog function
+(declare-function password-read-and-add "password-cache" (prompt &optional key))
 
-(defun smime-ask-passphrase ()
-  "Asks the passphrase to unlock the secret key."
+(defun smime-ask-passphrase (&optional cache-key)
+  "Asks the passphrase to unlock the secret key.
+If `cache-key' and `password-cache' is non-nil then cache the
+password under `cache-key'."
   (let ((passphrase
-        (comint-read-noecho
-         "Passphrase for secret key (RET for no passphrase): " t)))
+        (password-read-and-add
+         "Passphrase for secret key (RET for no passphrase): " cache-key)))
     (if (string= passphrase "")
        nil
       passphrase)))
@@ -227,18 +292,20 @@ If nil, use system defaults."
 
 ;; Sign+encrypt region
 
-(defun smime-sign-region (b e keyfiles)
-  "Sign region with certified key in KEYFILES.
+(defun smime-sign-region (b e keyfile)
+  "Sign region with certified key in KEYFILE.
 If signing fails, the buffer is not modified.  Region is assumed to
-have proper MIME tags.  KEYFILES is expected to contain a PEM encoded
-private key and certificate as its car, and a list of additional certificates
-to include in its caar."
+have proper MIME tags.  KEYFILE is expected to contain a PEM encoded
+private key and certificate as its car, and a list of additional
+certificates to include in its caar.  If no additional certificates is
+included, KEYFILE may be the file containing the PEM encoded private
+key and certificate itself."
   (smime-new-details-buffer)
-  (let ((keyfile (car keyfiles))
-       (certfiles (and (cdr keyfiles) (cadr keyfiles)))
-       (buffer (generate-new-buffer (generate-new-buffer-name " *smime*")))
-       (passphrase (smime-ask-passphrase))
-       (tmpfile (smime-make-temp-file "smime")))
+  (let* ((certfiles (and (cdr-safe keyfile) (cadr keyfile)))
+        (keyfile (or (car-safe keyfile) keyfile))
+        (buffer (generate-new