34219
|
1 ;;; starttls.el --- STARTTLS functions
|
|
2
|
88155
|
3 ;; Copyright (C) 1999, 2000, 2002, 2003, 2004,
|
|
4 ;; 2005 Free Software Foundation, Inc.
|
34219
|
5
|
|
6 ;; Author: Daiki Ueno <ueno@unixuser.org>
|
88155
|
7 ;; Author: Simon Josefsson <simon@josefsson.org>
|
34219
|
8 ;; Created: 1999/11/20
|
88155
|
9 ;; Keywords: TLS, SSL, OpenSSL, GNUTLS, mail, news
|
34219
|
10
|
34220
|
11 ;; This file is part of GNU Emacs.
|
34219
|
12
|
34220
|
13 ;; GNU Emacs is free software; you can redistribute it and/or modify
|
|
14 ;; it under the terms of the GNU General Public License as published by
|
|
15 ;; the Free Software Foundation; either version 2, or (at your option)
|
|
16 ;; any later version.
|
34219
|
17
|
34220
|
18 ;; GNU Emacs is distributed in the hope that it will be useful,
|
|
19 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
20 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
21 ;; GNU General Public License for more details.
|
34219
|
22
|
|
23 ;; You should have received a copy of the GNU General Public License
|
|
24 ;; along with GNU Emacs; see the file COPYING. If not, write to the
|
88155
|
25 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
26 ;; Boston, MA 02110-1301, USA.
|
34219
|
27
|
|
28 ;;; Commentary:
|
|
29
|
|
30 ;; This module defines some utility functions for STARTTLS profiles.
|
|
31
|
|
32 ;; [RFC 2595] "Using TLS with IMAP, POP3 and ACAP"
|
|
33 ;; by Chris Newman <chris.newman@innosoft.com> (1999/06)
|
|
34
|
88155
|
35 ;; This file now contains a combination of the two previous
|
|
36 ;; implementations both called "starttls.el". The first one is Daiki
|
|
37 ;; Ueno's starttls.el which uses his own "starttls" command line tool,
|
|
38 ;; and the second one is Simon Josefsson's starttls.el which uses
|
|
39 ;; "gnutls-cli" from GNUTLS.
|
|
40 ;;
|
|
41 ;; If "starttls" is available, it is prefered by the code over
|
|
42 ;; "gnutls-cli", for backwards compatibility. Use
|
|
43 ;; `starttls-use-gnutls' to toggle between implementations if you have
|
|
44 ;; both tools installed. It is recommended to use GNUTLS, though, as
|
|
45 ;; it performs more verification of the certificates.
|
|
46
|
|
47 ;; The GNUTLS support requires GNUTLS 0.9.90 (released 2003-10-08) or
|
|
48 ;; later, from <http://www.gnu.org/software/gnutls/>, or "starttls"
|
|
49 ;; from <ftp://ftp.opaopa.org/pub/elisp/>.
|
|
50
|
|
51 ;; Usage is similar to `open-network-stream'. For example:
|
|
52 ;;
|
|
53 ;; (when (setq tmp (starttls-open-stream
|
|
54 ;; "test" (current-buffer) "yxa.extundo.com" 25))
|
|
55 ;; (accept-process-output tmp 15)
|
|
56 ;; (process-send-string tmp "STARTTLS\n")
|
|
57 ;; (accept-process-output tmp 15)
|
|
58 ;; (message "STARTTLS output:\n%s" (starttls-negotiate tmp))
|
|
59 ;; (process-send-string tmp "EHLO foo\n"))
|
|
60
|
|
61 ;; An example run yields the following output:
|
|
62 ;;
|
|
63 ;; 220 yxa.extundo.com ESMTP Sendmail 8.12.11/8.12.11/Debian-3; Wed, 26 May 2004 19:12:29 +0200; (No UCE/UBE) logging access from: c494102a.s-bi.bostream.se(OK)-c494102a.s-bi.bostream.se [217.215.27.65]
|
|
64 ;; 220 2.0.0 Ready to start TLS
|
|
65 ;; 250-yxa.extundo.com Hello c494102a.s-bi.bostream.se [217.215.27.65], pleased to meet you
|
|
66 ;; 250-ENHANCEDSTATUSCODES
|
|
67 ;; 250-PIPELINING
|
|
68 ;; 250-EXPN
|
|
69 ;; 250-VERB
|
|
70 ;; 250-8BITMIME
|
|
71 ;; 250-SIZE
|
|
72 ;; 250-DSN
|
|
73 ;; 250-ETRN
|
|
74 ;; 250-AUTH DIGEST-MD5 CRAM-MD5 PLAIN LOGIN
|
|
75 ;; 250-DELIVERBY
|
|
76 ;; 250 HELP
|
|
77 ;; nil
|
|
78 ;;
|
|
79 ;; With the message buffer containing:
|
|
80 ;;
|
|
81 ;; STARTTLS output:
|
|
82 ;; *** Starting TLS handshake
|
|
83 ;; - Server's trusted authorities:
|
|
84 ;; [0]: C=SE,ST=Stockholm,L=Stockholm,O=YXA,OU=CA,CN=yxa.extundo.com,EMAIL=staff@yxa.extundo.com
|
|
85 ;; - Certificate type: X.509
|
|
86 ;; - Got a certificate list of 2 certificates.
|
|
87 ;;
|
|
88 ;; - Certificate[0] info:
|
|
89 ;; # The hostname in the certificate matches 'yxa.extundo.com'.
|
|
90 ;; # valid since: Wed May 26 12:16:00 CEST 2004
|
|
91 ;; # expires at: Wed Jul 26 12:16:00 CEST 2023
|
|
92 ;; # serial number: 04
|
|
93 ;; # fingerprint: 7c 04 4b c1 fa 26 9b 5d 90 22 52 3c 65 3d 85 3a
|
|
94 ;; # version: #1
|
|
95 ;; # public key algorithm: RSA
|
|
96 ;; # Modulus: 1024 bits
|
|
97 ;; # Subject's DN: C=SE,ST=Stockholm,L=Stockholm,O=YXA,OU=Mail server,CN=yxa.extundo.com,EMAIL=staff@yxa.extundo.com
|
|
98 ;; # Issuer's DN: C=SE,ST=Stockholm,L=Stockholm,O=YXA,OU=CA,CN=yxa.extundo.com,EMAIL=staff@yxa.extundo.com
|
|
99 ;;
|
|
100 ;; - Certificate[1] info:
|
|
101 ;; # valid since: Sun May 23 11:35:00 CEST 2004
|
|
102 ;; # expires at: Sun Jul 23 11:35:00 CEST 2023
|
|
103 ;; # serial number: 00
|
|
104 ;; # fingerprint: fc 76 d8 63 1a c9 0b 3b fa 40 fe ed 47 7a 58 ae
|
|
105 ;; # version: #3
|
|
106 ;; # public key algorithm: RSA
|
|
107 ;; # Modulus: 1024 bits
|
|
108 ;; # Subject's DN: C=SE,ST=Stockholm,L=Stockholm,O=YXA,OU=CA,CN=yxa.extundo.com,EMAIL=staff@yxa.extundo.com
|
|
109 ;; # Issuer's DN: C=SE,ST=Stockholm,L=Stockholm,O=YXA,OU=CA,CN=yxa.extundo.com,EMAIL=staff@yxa.extundo.com
|
|
110 ;;
|
|
111 ;; - Peer's certificate issuer is unknown
|
|
112 ;; - Peer's certificate is NOT trusted
|
|
113 ;; - Version: TLS 1.0
|
|
114 ;; - Key Exchange: RSA
|
|
115 ;; - Cipher: ARCFOUR 128
|
|
116 ;; - MAC: SHA
|
|
117 ;; - Compression: NULL
|
|
118
|
34219
|
119 ;;; Code:
|
|
120
|
|
121 (defgroup starttls nil
|
|
122 "Support for `Transport Layer Security' protocol."
|
34220
|
123 :version "21.1"
|
|
124 :group 'mail)
|
34219
|
125
|
88155
|
126 (defcustom starttls-gnutls-program "gnutls-cli"
|
|
127 "Name of GNUTLS command line tool.
|
|
128 This program is used when GNUTLS is used, i.e. when
|
|
129 `starttls-use-gnutls' is non-nil."
|
|
130 :version "22.1"
|
|
131 :type 'string
|
|
132 :group 'starttls)
|
|
133
|
34219
|
134 (defcustom starttls-program "starttls"
|
88155
|
135 "The program to run in a subprocess to open an TLSv1 connection.
|
|
136 This program is used when the `starttls' command is used,
|
|
137 i.e. when `starttls-use-gnutls' is nil."
|
34220
|
138 :type 'string
|
34219
|
139 :group 'starttls)
|
|
140
|
88155
|
141 (defcustom starttls-use-gnutls (not (executable-find starttls-program))
|
|
142 "*Whether to use GNUTLS instead of the `starttls' command."
|
|
143 :version "22.1"
|
|
144 :type 'boolean
|
|
145 :group 'starttls)
|
|
146
|
34219
|
147 (defcustom starttls-extra-args nil
|
88155
|
148 "Extra arguments to `starttls-program'.
|
|
149 These apply when the `starttls' command is used, i.e. when
|
|
150 `starttls-use-gnutls' is nil."
|
|
151 :type '(repeat string)
|
|
152 :group 'starttls)
|
|
153
|
|
154 (defcustom starttls-extra-arguments nil
|
|
155 "Extra arguments to `starttls-program'.
|
|
156 These apply when GNUTLS is used, i.e. when `starttls-use-gnutls' is non-nil.
|
|
157
|
|
158 For example, non-TLS compliant servers may require
|
|
159 '(\"--protocols\" \"ssl3\"). Invoke \"gnutls-cli --help\" to
|
|
160 find out which parameters are available."
|
|
161 :version "22.1"
|
34220
|
162 :type '(repeat string)
|
34219
|
163 :group 'starttls)
|
|
164
|
88155
|
165 (defcustom starttls-process-connection-type nil
|
|
166 "*Value for `process-connection-type' to use when starting STARTTLS process."
|
|
167 :version "22.1"
|
|
168 :type 'boolean
|
|
169 :group 'starttls)
|
|
170
|
|
171 (defcustom starttls-connect "- Simple Client Mode:\n\n"
|
|
172 "*Regular expression indicating successful connection.
|
|
173 The default is what GNUTLS's \"gnutls-cli\" outputs."
|
|
174 ;; GNUTLS cli.c:main() prints this string when it is starting to run
|
|
175 ;; in the application read/write phase. If the logic, or the string
|
|
176 ;; itself, is modified, this must be updated.
|
|
177 :version "22.1"
|
|
178 :type 'regexp
|
|
179 :group 'starttls)
|
|
180
|
|
181 (defcustom starttls-failure "\\*\\*\\* Handshake has failed"
|
|
182 "*Regular expression indicating failed TLS handshake.
|
|
183 The default is what GNUTLS's \"gnutls-cli\" outputs."
|
|
184 ;; GNUTLS cli.c:do_handshake() prints this string on failure. If the
|
|
185 ;; logic, or the string itself, is modified, this must be updated.
|
|
186 :version "22.1"
|
|
187 :type 'regexp
|
|
188 :group 'starttls)
|
|
189
|
|
190 (defcustom starttls-success "- Compression: "
|
|
191 "*Regular expression indicating completed TLS handshakes.
|
|
192 The default is what GNUTLS's \"gnutls-cli\" outputs."
|
|
193 ;; GNUTLS cli.c:do_handshake() calls, on success,
|
|
194 ;; common.c:print_info(), that unconditionally print this string
|
|
195 ;; last. If that logic, or the string itself, is modified, this
|
|
196 ;; must be updated.
|
|
197 :version "22.1"
|
|
198 :type 'regexp
|
|
199 :group 'starttls)
|
34219
|
200
|
88155
|
201 (defun starttls-negotiate-gnutls (process)
|
|
202 "Negotiate TLS on PROCESS opened by `open-starttls-stream'.
|
|
203 This should typically only be done once. It typically returns a
|
|
204 multi-line informational message with information about the
|
|
205 handshake, or nil on failure."
|
|
206 (let (buffer info old-max done-ok done-bad)
|
|
207 (if (null (setq buffer (process-buffer process)))
|
|
208 ;; XXX How to remove/extract the TLS negotiation junk?
|
|
209 (signal-process (process-id process) 'SIGALRM)
|
|
210 (with-current-buffer buffer
|
|
211 (save-excursion
|
|
212 (setq old-max (goto-char (point-max)))
|
|
213 (signal-process (process-id process) 'SIGALRM)
|
|
214 (while (and (processp process)
|
|
215 (eq (process-status process) 'run)
|
|
216 (save-excursion
|
|
217 (goto-char old-max)
|
|
218 (not (or (setq done-ok (re-search-forward
|
|
219 starttls-success nil t))
|
|
220 (setq done-bad (re-search-forward
|
|
221 starttls-failure nil t))))))
|
|
222 (accept-process-output process 1 100)
|
|
223 (sit-for 0.1))
|
|
224 (setq info (buffer-substring-no-properties old-max (point-max)))
|
|
225 (delete-region old-max (point-max))
|
|
226 (if (or (and done-ok (not done-bad))
|
|
227 ;; Prevent mitm that fake success msg after failure msg.
|
|
228 (and done-ok done-bad (< done-ok done-bad)))
|
|
229 info
|
|
230 (message "STARTTLS negotiation failed: %s" info)
|
|
231 nil))))))
|
|
232
|
|
233 (defun starttls-negotiate (process)
|
|
234 (if starttls-use-gnutls
|
|
235 (starttls-negotiate-gnutls process)
|
|
236 (signal-process (process-id process) 'SIGALRM)))
|
|
237
|
|
238 (eval-and-compile
|
|
239 (if (fboundp 'set-process-query-on-exit-flag)
|
|
240 (defalias 'starttls-set-process-query-on-exit-flag
|
|
241 'set-process-query-on-exit-flag)
|
|
242 (defalias 'starttls-set-process-query-on-exit-flag
|
|
243 'process-kill-without-query)))
|
|
244
|
|
245 (defun starttls-open-stream-gnutls (name buffer host port)
|
|
246 (message "Opening STARTTLS connection to `%s'..." host)
|
|
247 (let* (done
|
|
248 (old-max (with-current-buffer buffer (point-max)))
|
|
249 (process-connection-type starttls-process-connection-type)
|
|
250 (process (apply #'start-process name buffer
|
|
251 starttls-gnutls-program "-s" host
|
|
252 "-p" (if (integerp port)
|
|
253 (int-to-string port)
|
|
254 port)
|
|
255 starttls-extra-arguments)))
|
|
256 (starttls-set-process-query-on-exit-flag process nil)
|
|
257 (while (and (processp process)
|
|
258 (eq (process-status process) 'run)
|
|
259 (save-excursion
|
|
260 (set-buffer buffer)
|
|
261 (goto-char old-max)
|
|
262 (not (setq done (re-search-forward
|
|
263 starttls-connect nil t)))))
|
|
264 (accept-process-output process 0 100)
|
|
265 (sit-for 0.1))
|
|
266 (if done
|
|
267 (with-current-buffer buffer
|
|
268 (delete-region old-max done))
|
|
269 (delete-process process)
|
|
270 (setq process nil))
|
|
271 (message "Opening STARTTLS connection to `%s'...%s"
|
|
272 host (if done "done" "failed"))
|
|
273 process))
|
|
274
|
|
275 (defun starttls-open-stream (name buffer host port)
|
|
276 "Open a TLS connection for a port to a host.
|
|
277 Returns a subprocess object to represent the connection.
|
34219
|
278 Input and output work as for subprocesses; `delete-process' closes it.
|
88155
|
279 Args are NAME BUFFER HOST PORT.
|
34219
|
280 NAME is name for process. It is modified if necessary to make it unique.
|
|
281 BUFFER is the buffer (or `buffer-name') to associate with the process.
|
|
282 Process output goes at end of that buffer, unless you specify
|
|
283 an output stream or filter function to handle the output.
|
|
284 BUFFER may be also nil, meaning that this process is not associated
|
|
285 with any buffer
|
|
286 Third arg is name of the host to connect to, or its IP address.
|
88155
|
287 Fourth arg PORT is an integer specifying a port to connect to.
|
|
288 If `starttls-use-gnutls' is nil, this may also be a service name, but
|
|
289 GNUTLS requires a port number."
|
|
290 (if starttls-use-gnutls
|
|
291 (starttls-open-stream-gnutls name buffer host port)
|
|
292 (let* ((process-connection-type starttls-process-connection-type)
|
|
293 (process (apply #'start-process
|
|
294 name buffer starttls-program
|
|
295 host (format "%s" port)
|
|
296 starttls-extra-args)))
|
|
297 (starttls-set-process-query-on-exit-flag process nil)
|
|
298 process)))
|
34219
|
299
|
|
300 (provide 'starttls)
|
|
301
|
88155
|
302 ;;; arch-tag: 648b3bd8-63bd-47f5-904c-7c819aea2297
|
34219
|
303 ;;; starttls.el ends here
|