2003-03-26 11:48:32 +00:00
|
|
|
;;; tls.el --- TLS/SSL support via wrapper around GnuTLS
|
|
|
|
|
2020-01-01 00:19:43 +00:00
|
|
|
;; Copyright (C) 1996-1999, 2002-2020 Free Software Foundation, Inc.
|
2003-03-26 11:48:32 +00:00
|
|
|
|
|
|
|
;; Author: Simon Josefsson <simon@josefsson.org>
|
|
|
|
;; Keywords: comm, tls, gnutls, ssl
|
2018-06-18 22:19:57 -04:00
|
|
|
;; Obsolete-since: 27.1
|
2003-03-26 11:48:32 +00:00
|
|
|
|
|
|
|
;; This file is part of GNU Emacs.
|
|
|
|
|
2008-05-06 07:31:51 +00:00
|
|
|
;; GNU Emacs is free software: you can redistribute it and/or modify
|
2003-03-26 11:48:32 +00:00
|
|
|
;; it under the terms of the GNU General Public License as published by
|
2008-05-06 07:31:51 +00:00
|
|
|
;; the Free Software Foundation, either version 3 of the License, or
|
|
|
|
;; (at your option) any later version.
|
2003-03-26 11:48:32 +00:00
|
|
|
|
|
|
|
;; GNU Emacs is distributed in the hope that it will be useful,
|
|
|
|
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
2008-05-06 07:31:51 +00:00
|
|
|
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
2003-03-26 11:48:32 +00:00
|
|
|
;; GNU General Public License for more details.
|
|
|
|
|
|
|
|
;; You should have received a copy of the GNU General Public License
|
2017-09-13 15:52:52 -07:00
|
|
|
;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
|
2003-03-26 11:48:32 +00:00
|
|
|
|
|
|
|
;;; Commentary:
|
|
|
|
|
|
|
|
;; This package implements a simple wrapper around "gnutls-cli" to
|
|
|
|
;; make Emacs support TLS/SSL.
|
|
|
|
;;
|
|
|
|
;; Usage is the same as `open-network-stream', i.e.:
|
|
|
|
;;
|
|
|
|
;; (setq tmp (open-tls-stream "test" (current-buffer) "news.mozilla.org" 563))
|
|
|
|
;; ...
|
|
|
|
;; #<process test>
|
|
|
|
;; (process-send-string tmp "mode reader\n")
|
|
|
|
;; 200 secnews.netscape.com Netscape-Collabra/3.52 03615 NNRP ready ...
|
|
|
|
;; nil
|
|
|
|
;; (process-send-string tmp "quit\n")
|
|
|
|
;; 205
|
|
|
|
;; nil
|
|
|
|
|
|
|
|
;; To use this package as a replacement for ssl.el by William M. Perry
|
|
|
|
;; <wmperry@cs.indiana.edu>, you need to evaluate the following:
|
|
|
|
;;
|
|
|
|
;; (defalias 'open-ssl-stream 'open-tls-stream)
|
|
|
|
|
|
|
|
;;; Code:
|
|
|
|
|
2015-12-29 14:46:20 +01:00
|
|
|
(require 'gnutls)
|
|
|
|
|
2003-03-26 11:48:32 +00:00
|
|
|
(defgroup tls nil
|
|
|
|
"Transport Layer Security (TLS) parameters."
|
|
|
|
:group 'comm)
|
|
|
|
|
2007-11-04 01:22:45 +00:00
|
|
|
(defcustom tls-end-of-info
|
2007-11-04 01:26:09 +00:00
|
|
|
(concat
|
|
|
|
"\\("
|
|
|
|
;; `openssl s_client' regexp. See ssl/ssl_txt.c lines 219-220.
|
|
|
|
;; According to apps/s_client.c line 1515 `---' is always the last
|
|
|
|
;; line that is printed by s_client before the real data.
|
|
|
|
"^ Verify return code: .+\n---\n\\|"
|
|
|
|
;; `gnutls' regexp. See src/cli.c lines 721-.
|
|
|
|
"^- Simple Client Mode:\n"
|
|
|
|
"\\(\n\\|" ; ignore blank lines
|
2007-11-08 13:20:11 +00:00
|
|
|
;; According to GnuTLS v2.1.5 src/cli.c lines 640-650 and 705-715
|
2007-11-09 13:06:05 +00:00
|
|
|
;; in `main' the handshake will start after this message. If the
|
2007-11-08 13:20:11 +00:00
|
|
|
;; handshake fails, the programs will abort.
|
2007-11-04 01:26:09 +00:00
|
|
|
"^\\*\\*\\* Starting TLS handshake\n\\)*"
|
|
|
|
"\\)")
|
2007-11-04 01:22:45 +00:00
|
|
|
"Regexp matching end of TLS client informational messages.
|
2017-04-24 20:06:14 -04:00
|
|
|
Client data stream begins after the last character this matches.
|
|
|
|
The default matches the output of \"gnutls-cli\" (version 2.0.1)."
|
2007-11-04 01:22:45 +00:00
|
|
|
:version "22.2"
|
|
|
|
:type 'regexp
|
|
|
|
:group 'tls)
|
|
|
|
|
2015-12-29 14:46:20 +01:00
|
|
|
(defcustom tls-program
|
|
|
|
'("gnutls-cli --x509cafile %t -p %p %h"
|
2017-04-24 19:58:45 -04:00
|
|
|
"gnutls-cli --x509cafile %t -p %p %h --protocols ssl3")
|
2003-03-26 11:48:32 +00:00
|
|
|
"List of strings containing commands to start TLS stream to a host.
|
|
|
|
Each entry in the list is tried until a connection is successful.
|
2016-02-05 18:13:34 +11:00
|
|
|
%h is replaced with the server hostname, %p with the port to
|
|
|
|
connect to, and %t with a file name containing trusted certificates.
|
2014-03-14 01:22:33 +01:00
|
|
|
The program should read input on stdin and write output to stdout.
|
2007-12-06 00:21:00 +00:00
|
|
|
|
|
|
|
See `tls-checktrust' on how to check trusted root certs.
|
|
|
|
|
|
|
|
Also see `tls-success' for what the program should output after
|
|
|
|
successful negotiation."
|
|
|
|
:type
|
|
|
|
'(choice
|
2012-12-13 10:48:54 +01:00
|
|
|
(const :tag "Default list of commands"
|
2015-12-29 14:46:20 +01:00
|
|
|
("gnutls-cli --x509cafile %t -p %p %h"
|
2017-04-24 19:58:45 -04:00
|
|
|
"gnutls-cli --x509cafile %t -p %p %h --protocols ssl3"))
|
2007-12-06 00:21:00 +00:00
|
|
|
(list :tag "Choose commands"
|
|
|
|
:value
|
2015-12-29 14:46:20 +01:00
|
|
|
("gnutls-cli --x509cafile %t -p %p %h"
|
2017-04-24 19:58:45 -04:00
|
|
|
"gnutls-cli --x509cafile %t -p %p %h --protocols ssl3")
|
2007-12-06 00:21:00 +00:00
|
|
|
(set :inline t
|
|
|
|
;; FIXME: add brief `:tag "..."' descriptions.
|
|
|
|
;; (repeat :inline t :tag "Other" (string))
|
|
|
|
;; No trust check:
|
2015-12-29 14:46:20 +01:00
|
|
|
(const "gnutls-cli --insecure -p %p %h")
|
2017-04-24 19:58:45 -04:00
|
|
|
(const "gnutls-cli --insecure -p %p %h --protocols ssl3"))
|
2007-12-06 00:21:00 +00:00
|
|
|
(repeat :inline t :tag "Other" (string)))
|
|
|
|
(list :tag "List of commands"
|
|
|
|
(repeat :tag "Command" (string))))
|
2017-09-14 16:35:43 -04:00
|
|
|
:version "26.1" ; remove s_client
|
2003-03-26 11:48:32 +00:00
|
|
|
:group 'tls)
|
|
|
|
|
|
|
|
(defcustom tls-process-connection-type nil
|
2007-12-06 00:21:00 +00:00
|
|
|
"Value for `process-connection-type' to use when starting TLS process."
|
2005-02-09 15:50:47 +00:00
|
|
|
:version "22.1"
|
2003-03-26 11:48:32 +00:00
|
|
|
:type 'boolean
|
|
|
|
:group 'tls)
|
|
|
|
|
2005-12-17 21:41:34 +00:00
|
|
|
(defcustom tls-success "- Handshake was completed\\|SSL handshake has read "
|
2007-12-06 00:21:00 +00:00
|
|
|
"Regular expression indicating completed TLS handshakes.
|
2017-04-24 20:06:14 -04:00
|
|
|
The default is what GnuTLS's \"gnutls-cli\" outputs."
|
|
|
|
;; or OpenSSL's \"openssl s_client\"
|
2005-02-09 15:50:47 +00:00
|
|
|
:version "22.1"
|
2003-03-26 11:48:32 +00:00
|
|
|
:type 'regexp
|
|
|
|
:group 'tls)
|
|
|
|
|
2007-12-06 00:21:00 +00:00
|
|
|
(defcustom tls-checktrust nil
|
|
|
|
"Indicate if certificates should be checked against trusted root certs.
|
|
|
|
If this is `ask', the user can decide whether to accept an
|
|
|
|
untrusted certificate. You may have to adapt `tls-program' in
|
|
|
|
order to make this feature work properly, i.e., to ensure that
|
|
|
|
the external program knows about the root certificates you
|
|
|
|
consider trustworthy, e.g.:
|
|
|
|
|
|
|
|
\(setq tls-program
|
2020-12-19 17:26:58 +01:00
|
|
|
\\='(\"gnutls-cli --x509cafile /etc/ssl/certs/ca-certificates.crt \\
|
|
|
|
-p %p %h\"
|
|
|
|
\"gnutls-cli --x509cafile /etc/ssl/certs/ca-certificates.crt \\
|
|
|
|
-p %p %h --protocols ssl3\"))"
|
2007-12-06 00:21:00 +00:00
|
|
|
:type '(choice (const :tag "Always" t)
|
|
|
|
(const :tag "Never" nil)
|
|
|
|
(const :tag "Ask" ask))
|
2008-02-29 04:02:43 +00:00
|
|
|
:version "23.1" ;; No Gnus
|
2007-12-06 00:21:00 +00:00
|
|
|
:group 'tls)
|
|
|
|
|
|
|
|
(defcustom tls-untrusted
|
|
|
|
"- Peer's certificate is NOT trusted\\|Verify return code: \\([^0] \\|.[^ ]\\)"
|
|
|
|
"Regular expression indicating failure of TLS certificate verification.
|
2017-04-24 20:06:14 -04:00
|
|
|
The default is what GnuTLS's \"gnutls-cli\" returns in the event of
|
|
|
|
unsuccessful verification."
|
|
|
|
;; or OpenSSL's \"openssl s_client\"
|
2007-12-06 00:21:00 +00:00
|
|
|
:type 'regexp
|
2008-02-29 04:02:43 +00:00
|
|
|
:version "23.1" ;; No Gnus
|
2007-12-06 00:21:00 +00:00
|
|
|
:group 'tls)
|
|
|
|
|
|
|
|
(defcustom tls-hostmismatch
|
|
|
|
"# The hostname in the certificate does NOT match"
|
|
|
|
"Regular expression indicating a host name mismatch in certificate.
|
|
|
|
When the host name specified in the certificate doesn't match the
|
|
|
|
name of the host you are connecting to, gnutls-cli issues a
|
|
|
|
warning to this effect. There is no such feature in openssl. Set
|
|
|
|
this to nil if you want to ignore host name mismatches."
|
|
|
|
:type 'regexp
|
2008-02-29 04:02:43 +00:00
|
|
|
:version "23.1" ;; No Gnus
|
2007-12-06 00:21:00 +00:00
|
|
|
:group 'tls)
|
|
|
|
|
2013-12-27 17:24:15 -08:00
|
|
|
(defcustom tls-certtool-program "certtool"
|
|
|
|
"Name of GnuTLS certtool.
|
2004-10-12 09:40:45 +00:00
|
|
|
Used by `tls-certificate-information'."
|
2005-02-09 15:50:47 +00:00
|
|
|
:version "22.1"
|
2007-02-24 18:07:17 +00:00
|
|
|
:type 'string
|
2004-10-12 09:40:45 +00:00
|
|
|
:group 'tls)
|
|
|
|
|
2015-09-01 22:59:53 +00:00
|
|
|
(defalias 'tls-format-message
|
|
|
|
(if (fboundp 'format-message) 'format-message
|
2015-08-31 18:14:15 -07:00
|
|
|
;; for Emacs < 25, and XEmacs, don't worry about quote translation.
|
2015-09-01 22:59:53 +00:00
|
|
|
'format))
|
2015-08-31 18:14:15 -07:00
|
|
|
|
2004-10-12 09:40:45 +00:00
|
|
|
(defun tls-certificate-information (der)
|
|
|
|
"Parse X.509 certificate in DER format into an assoc list."
|
|
|
|
(let ((certificate (concat "-----BEGIN CERTIFICATE-----\n"
|
|
|
|
(base64-encode-string der)
|
|
|
|
"\n-----END CERTIFICATE-----\n"))
|
|
|
|
(exit-code 0))
|
|
|
|
(with-current-buffer (get-buffer-create " *certtool*")
|
|
|
|
(erase-buffer)
|
|
|
|
(insert certificate)
|
|
|
|
(setq exit-code (condition-case ()
|
|
|
|
(call-process-region (point-min) (point-max)
|
|
|
|
tls-certtool-program
|
|
|
|
t (list (current-buffer) nil) t
|
|
|
|
"--certificate-info")
|
|
|
|
(error -1)))
|
|
|
|
(if (/= exit-code 0)
|
|
|
|
nil
|
|
|
|
(let ((vals nil))
|
|
|
|
(goto-char (point-min))
|
|
|
|
(while (re-search-forward "^\\([^:]+\\): \\(.*\\)" nil t)
|
|
|
|
(push (cons (match-string 1) (match-string 2)) vals))
|
|
|
|
(nreverse vals))))))
|
|
|
|
|
2010-10-13 22:21:20 +00:00
|
|
|
(defun open-tls-stream (name buffer host port)
|
2005-12-17 21:41:34 +00:00
|
|
|
"Open a TLS connection for a port to a host.
|
2003-03-26 11:48:32 +00:00
|
|
|
Returns a subprocess-object to represent the connection.
|
|
|
|
Input and output work as for subprocesses; `delete-process' closes it.
|
2005-12-17 21:41:34 +00:00
|
|
|
Args are NAME BUFFER HOST PORT.
|
2003-03-26 11:48:32 +00:00
|
|
|
NAME is name for process. It is modified if necessary to make it unique.
|
2007-12-06 00:21:00 +00:00
|
|
|
BUFFER is the buffer (or buffer name) to associate with the process.
|
2003-03-26 11:48:32 +00:00
|
|
|
Process output goes at end of that buffer, unless you specify
|
2018-02-05 19:36:27 -05:00
|
|
|
a filter function to handle the output.
|
2003-03-26 11:48:32 +00:00
|
|
|
BUFFER may be also nil, meaning that this process is not associated
|
|
|
|
with any buffer
|
|
|
|
Third arg is name of the host to connect to, or its IP address.
|
2005-12-17 21:41:34 +00:00
|
|
|
Fourth arg PORT is an integer specifying a port to connect to."
|
2007-04-07 04:33:00 +00:00
|
|
|
(let ((cmds tls-program)
|
|
|
|
(use-temp-buffer (null buffer))
|
|
|
|
process cmd done)
|
|
|
|
(if use-temp-buffer
|
2008-07-18 00:59:10 +00:00
|
|
|
(setq buffer (generate-new-buffer " TLS"))
|
|
|
|
;; BUFFER is a string but does not exist as a buffer object.
|
|
|
|
(unless (and (get-buffer buffer)
|
|
|
|
(buffer-name (get-buffer buffer)))
|
|
|
|
(generate-new-buffer buffer)))
|
2007-11-04 01:26:09 +00:00
|
|
|
(with-current-buffer buffer
|
2007-11-04 01:22:45 +00:00
|
|
|
(message "Opening TLS connection to `%s'..." host)
|
|
|
|
(while (and (not done) (setq cmd (pop cmds)))
|
|
|
|
(let ((process-connection-type tls-process-connection-type)
|
2008-10-01 23:48:57 +00:00
|
|
|
(formatted-cmd
|
Fix and extend format-spec (bug#41758)
* lisp/format-spec.el: Use lexical-binding. Remove dependence on
subr-x.el.
(format-spec-make): Clarify docstring.
(format-spec--parse-modifiers): Rename to...
(format-spec--parse-flags): ...this and simplify. In particular,
don't bother parsing :space-pad which is redundant and unused.
(format-spec--pad): Remove, replacing with...
(format-spec--do-flags): ...this new helper function which performs
more of format-spec's supported text manipulation.
(format-spec): Autoload. Allow optional argument to take on special
values 'ignore' and 'delete' for more control over what happens when
a replacement for a format specification isn't provided. Bring back
proper support for a precision modifier similar to that of 'format'.
* lisp/battery.el (battery-format): Rewrite in terms of format-spec.
(battery-echo-area-format, battery-mode-line-format): Mention
support of format-spec syntax in docstrings.
* doc/lispref/strings.texi (Custom Format Strings):
* etc/NEWS: Document and announce these changes.
* lisp/dired-aux.el (dired-do-compress-to):
* lisp/erc/erc-match.el (erc-log-matches):
* lisp/erc/erc.el (erc-update-mode-line-buffer):
* lisp/gnus/gnus-sieve.el (gnus-sieve-update):
* lisp/gnus/gssapi.el (open-gssapi-stream):
* lisp/gnus/mail-source.el (mail-source-fetch-file)
(mail-source-fetch-directory, mail-source-fetch-pop)
(mail-source-fetch-imap):
* lisp/gnus/message.el (message-insert-formatted-citation-line):
* lisp/image-dired.el:
* lisp/net/eww.el:
* lisp/net/imap.el (imap-kerberos4-open, imap-gssapi-open)
(imap-shell-open):
* lisp/net/network-stream.el (network-stream-open-shell):
* lisp/obsolete/tls.el (open-tls-stream):
* lisp/textmodes/tex-mode.el:
Remove extraneous loads and autoloads of format-spec now that it is
autoloaded and simplify its uses where possible.
* test/lisp/battery-tests.el (battery-format): Test new format-spec
support.
* test/lisp/format-spec-tests.el (test-format-spec): Rename to...
(format-spec) ...this, extending test cases.
(test-format-unknown): Rename to...
(format-spec-unknown): ...this, extending test cases.
(test-format-modifiers): Rename to...
(format-spec-flags): ...this.
(format-spec-make, format-spec-parse-flags, format-spec-do-flags)
(format-spec-do-flags-truncate, format-spec-do-flags-pad)
(format-spec-do-flags-chop, format-spec-do-flags-case): New tests.
2020-05-29 19:56:14 +01:00
|
|
|
(format-spec cmd `((?t . ,(car (gnutls-trustfiles)))
|
|
|
|
(?h . ,host)
|
|
|
|
(?p . ,(if (integerp port)
|
|
|
|
(number-to-string port)
|
|
|
|
port))))))
|
2008-10-01 23:48:57 +00:00
|
|
|
(message "Opening TLS connection with `%s'..." formatted-cmd)
|
2007-11-04 01:22:45 +00:00
|
|
|
(setq process (start-process
|
|
|
|
name buffer shell-file-name shell-command-switch
|
2008-10-01 23:48:57 +00:00
|
|
|
formatted-cmd))
|
2007-11-04 01:22:45 +00:00
|
|
|
(while (and process
|
|
|
|
(memq (process-status process) '(open run))
|
|
|
|
(progn
|
|
|
|
(goto-char (point-min))
|
2008-03-03 02:11:04 +00:00
|
|
|
(not (setq done (re-search-forward
|
|
|
|
tls-success nil t)))))
|
2007-11-04 01:22:45 +00:00
|
|
|
(unless (accept-process-output process 1)
|
|
|
|
(sit-for 1)))
|
2008-10-01 23:48:57 +00:00
|
|
|
(message "Opening TLS connection with `%s'...%s" formatted-cmd
|
2007-11-04 01:22:45 +00:00
|
|
|
(if done "done" "failed"))
|
2008-03-03 02:11:04 +00:00
|
|
|
(if (not done)
|
|
|
|
(delete-process process)
|
|
|
|
;; advance point to after all informational messages that
|
|
|
|
;; `openssl s_client' and `gnutls' print
|
|
|
|
(let ((start-of-data nil))
|
|
|
|
(while
|
2008-03-19 21:32:23 +00:00
|
|
|
(not (setq start-of-data
|
|
|
|
;; the string matching `tls-end-of-info'
|
|
|
|
;; might come in separate chunks from
|
|
|
|
;; `accept-process-output', so start the
|
|
|
|
;; search where `tls-success' ended
|
|
|
|
(save-excursion
|
|
|
|
(if (re-search-forward tls-end-of-info nil t)
|
|
|
|
(match-end 0)))))
|
2008-03-03 02:11:04 +00:00
|
|
|
(accept-process-output process 1))
|
|
|
|
(if start-of-data
|
|
|
|
;; move point to start of client data
|
|
|
|
(goto-char start-of-data)))
|
2008-03-19 21:32:23 +00:00
|
|
|
(setq done process))))
|
2008-03-03 02:11:04 +00:00
|
|
|
(when (and done
|
|
|
|
(or
|
|
|
|
(and tls-checktrust
|
|
|
|
(save-excursion
|
|
|
|
(goto-char (point-min))
|
|
|
|
(re-search-forward tls-untrusted nil t))
|
|
|
|
(or
|
|
|
|
(and (not (eq tls-checktrust 'ask))
|
|
|
|
(message "The certificate presented by `%s' is \
|
|
|
|
NOT trusted." host))
|
|
|
|
(not (yes-or-no-p
|
2015-08-31 18:14:15 -07:00
|
|
|
(tls-format-message "\
|
|
|
|
The certificate presented by `%s' is NOT trusted. Accept anyway? " host)))))
|
2008-03-03 02:11:04 +00:00
|
|
|
(and tls-hostmismatch
|
|
|
|
(save-excursion
|
|
|
|
(goto-char (point-min))
|
|
|
|
(re-search-forward tls-hostmismatch nil t))
|
|
|
|
(not (yes-or-no-p
|
|
|
|
(format "Host name in certificate doesn't \
|
|
|
|
match `%s'. Connect anyway? " host))))))
|
|
|
|
(setq done nil)
|
2013-06-05 11:03:37 -04:00
|
|
|
(delete-process process))
|
|
|
|
;; Delete all the informational messages that could confuse
|
|
|
|
;; future uses of `buffer'.
|
|
|
|
(delete-region (point-min) (point)))
|
2008-03-03 02:11:04 +00:00
|
|
|
(message "Opening TLS connection to `%s'...%s"
|
|
|
|
host (if done "done" "failed"))
|
2007-04-07 04:33:00 +00:00
|
|
|
(when use-temp-buffer
|
2007-04-07 04:40:28 +00:00
|
|
|
(if done (set-process-buffer process nil))
|
2007-04-07 04:33:00 +00:00
|
|
|
(kill-buffer buffer))
|
2003-03-26 11:48:32 +00:00
|
|
|
done))
|
|
|
|
|
|
|
|
(provide 'tls)
|
|
|
|
|
|
|
|
;;; tls.el ends here
|