Import No Gnus v0.3.
[elisp/gnus.git-] / contrib / ssl.el
1 ;;; ssl.el --- ssl functions for emacsen without them builtin
2 ;; Keywords: comm
3
4 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
5 ;;; Copyright (c) 1995, 1996 by William M. Perry <wmperry@cs.indiana.edu>
6 ;;; Copyright (c) 1996 - 1999 Free Software Foundation, Inc.
7 ;;;
8 ;;; This file is part of GNU Emacs.
9 ;;;
10 ;;; GNU Emacs is free software; you can redistribute it and/or modify
11 ;;; it under the terms of the GNU General Public License as published by
12 ;;; the Free Software Foundation; either version 2, or (at your option)
13 ;;; any later version.
14 ;;;
15 ;;; GNU Emacs is distributed in the hope that it will be useful,
16 ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 ;;; GNU General Public License for more details.
19 ;;;
20 ;;; You should have received a copy of the GNU General Public License
21 ;;; along with GNU Emacs; see the file COPYING.  If not, write to the
22 ;;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 ;;; Boston, MA 02111-1307, USA.
24 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
25
26 (eval-when-compile (require 'cl))
27 (require 'base64)
28
29 (eval-and-compile
30   (condition-case ()
31       (require 'custom)
32     (error nil))
33   (if (and (featurep 'custom) (fboundp 'custom-declare-variable))
34       nil ;; We've got what we needed
35     ;; We have the old custom-library, hack around it!
36     (defmacro defgroup (&rest args)
37       nil)
38     (defmacro defcustom (var value doc &rest args) 
39       (` (defvar (, var) (, value) (, doc))))))
40
41 (defgroup ssl nil
42   "Support for `Secure Sockets Layer' encryption."
43   :group 'comm)
44   
45 (defcustom ssl-certificate-directory "~/.w3/certs/"
46   "*Directory to store CA certificates in"
47   :group 'ssl
48   :type 'directory)
49
50 (defcustom ssl-rehash-program-name "c_rehash"
51   "*Program to run after adding a cert to a directory .
52 Run with one argument, the directory name."
53   :group 'ssl
54   :type 'string)
55
56 (defcustom ssl-view-certificate-program-name "x509"
57   "*The program to run to provide a human-readable view of a certificate."
58   :group 'ssl
59   :type 'string)
60
61 (defcustom ssl-view-certificate-program-arguments '("-text" "-inform" "DER")
62   "*Arguments that should be passed to the certificate viewing program.
63 The certificate is piped to it.
64 Maybe a way of passing a file should be implemented"
65   :group 'ssl
66   :type 'list)
67
68 (defcustom ssl-certificate-directory-style 'ssleay
69   "*Style of cert database to use, the only valid value right now is `ssleay'.
70 This means a directory of pem encoded certificates with hash symlinks."
71   :group 'ssl
72   :type '(choice (const :tag "SSLeay" :value ssleay)
73                  (const :tag "OpenSSL" :value openssl)))
74
75 (defcustom ssl-certificate-verification-policy 0
76   "*How far up the certificate chain we should verify."
77   :group 'ssl
78   :type '(choice (const :tag "No verification" :value 0)
79                  (const :tag "Verification required" :value 1)
80                  (const :tag "Reject connection if verification fails" :value 3)
81                  (const :tag "SSL_VERIFY_CLIENT_ONCE" :value 5)))
82
83 (defcustom ssl-program-name "openssl"
84   "*The program to run in a subprocess to open an SSL connection."
85   :group 'ssl
86   :type 'string)
87
88 (defcustom ssl-program-arguments
89   '("s_client"
90     "-quiet"
91     "-host" host
92     "-port" service
93     "-verify" (int-to-string ssl-certificate-verification-policy)
94     "-CApath" ssl-certificate-directory
95     )
96   "*Arguments that should be passed to the program `ssl-program-name'.
97 This should be used if your SSL program needs command line switches to
98 specify any behaviour (certificate file locations, etc).
99 The special symbols 'host and 'port may be used in the list of arguments
100 and will be replaced with the hostname and service/port that will be connected
101 to."
102   :group 'ssl
103   :type 'list)
104
105 (defun ssl-certificate-information (der)
106   "Return an assoc list of information about a certificate in DER format."
107   (let ((certificate (concat "-----BEGIN CERTIFICATE-----\n"
108                              (base64-encode-string der)
109                              "\n-----END CERTIFICATE-----\n"))
110         (exit-code 0))
111     (save-excursion
112       (set-buffer (get-buffer-create " *openssl*"))
113       (erase-buffer)
114       (insert certificate)
115       (setq exit-code (condition-case ()
116                           (call-process-region (point-min) (point-max)
117                                                ssl-program-name
118                                                t (list (current-buffer) nil) t
119                                                "x509"
120                                                "-subject" ; Print the subject DN
121                                                "-issuer" ; Print the issuer DN
122                                                "-dates" ; Both before and after dates
123                                                "-serial" ; print out serial number
124                                                "-noout" ; Don't spit out the certificate
125                                                )
126                         (error -1)))
127       (if (/= exit-code 0)
128           nil
129         (let ((vals nil))
130           (goto-char (point-min))
131           (while (re-search-forward "^\\([^=\n\r]+\\)\\s *=\\s *\\(.*\\)" nil t)
132             (push (cons (match-string 1) (match-string 2)) vals))
133           vals)))))
134   
135 (defun ssl-accept-ca-certificate ()
136   "Ask if the user is willing to accept a new CA certificate. The buffer-name
137 should be the intended name of the certificate, and the buffer should probably
138 be in DER encoding"
139   ;; TODO, check if it is really new or if we already know it
140   (let* ((process-connection-type nil)
141          (tmpbuf (generate-new-buffer "X509 CA Certificate Information"))
142          (response (save-excursion
143                      (and (eq 0 
144                               (apply 'call-process-region
145                                      (point-min) (point-max) 
146                                      ssl-view-certificate-program-name 
147                                      nil tmpbuf t
148                                      ssl-view-certificate-program-arguments))
149                           (switch-to-buffer tmpbuf)
150                           (goto-char (point-min))
151                           (or (recenter) t)
152                           (yes-or-no-p
153                            "Accept this CA to vouch for secure server identities? ")
154                           (kill-buffer tmpbuf)))))
155     (if (not response)
156         nil
157       (if (not (file-directory-p ssl-certificate-directory))
158           (make-directory ssl-certificate-directory))
159       (case ssl-certificate-directory-style
160         (ssleay
161          (base64-encode-region (point-min) (point-max))
162          (goto-char (point-min))
163          (insert "-----BEGIN CERTIFICATE-----\n")
164          (goto-char (point-max))
165          (insert "-----END CERTIFICATE-----\n")
166          (let ((f (expand-file-name
167                    (concat (file-name-sans-extension (buffer-name)) ".pem")
168                    ssl-certificate-directory)))
169            (write-file f)
170            (call-process ssl-rehash-program-name
171                          nil nil nil
172                          (expand-file-name ssl-certificate-directory))))))))
173
174 (defun open-ssl-stream (name buffer host service)
175   "Open a SSL connection for a service to a host.
176 Returns a subprocess-object to represent the connection.
177 Input and output work as for subprocesses; `delete-process' closes it.
178 Args are NAME BUFFER HOST SERVICE.
179 NAME is name for process.  It is modified if necessary to make it unique.
180 BUFFER is the buffer (or buffer-name) to associate with the process.
181  Process output goes at end of that buffer, unless you specify
182  an output stream or filter function to handle the output.
183  BUFFER may be also nil, meaning that this process is not associated
184  with any buffer
185 Third arg is name of the host to connect to, or its IP address.
186 Fourth arg SERVICE is name of the service desired, or an integer
187 specifying a port number to connect to."
188   (if (integerp service) (setq service (int-to-string service)))
189   (let* ((process-connection-type nil)
190          (port service)
191          (proc (eval
192                 (`
193                  (start-process name buffer ssl-program-name
194                                 (,@ ssl-program-arguments))))))
195     (process-kill-without-query proc)
196     proc))
197
198 (provide 'ssl)
199
200 ;;; arch-tag: 659fae92-1c67-4055-939f-32153c2f5114