]> code.delx.au - gnu-emacs/blobdiff - lisp/net/nsm.el
Update copyright year to 2016
[gnu-emacs] / lisp / net / nsm.el
index 067de556b671e66760e48a9076905626eacd5ca7..31f2b32792fb385e9e476c1287a5e934a0d6888f 100644 (file)
@@ -1,6 +1,6 @@
 ;;; nsm.el --- Network Security Manager
 
-;; Copyright (C) 2014 Free Software Foundation, Inc.
+;; Copyright (C) 2014-2016 Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;; Keywords: encryption, security, network
@@ -43,22 +43,13 @@ connection should be handled.
 The following values are possible:
 
 `low': Absolutely no checks are performed.
+`medium': This is the default level, should be reasonable for most usage.
+`high': This warns about additional things that many people would
+not find useful.
+`paranoid': On this level, the user is queried for most new connections.
 
-`medium': This is the default level, and the following things will
-be prompted for.
-
-* invalid, self-signed or otherwise unverifiable certificates
-* whether a previously accepted unverifiable certificate has changed
-* when a connection that was previously protected by STARTTLS is
-  now unencrypted
-
-`high': In addition to the above.
-
-* any certificate that changes its public key
-
-`paranoid': In addition to the above.
-
-* any new certificate that you haven't seen before"
+See the Emacs manual for a description of all things that are
+checked and warned against."
   :version "25.1"
   :group 'nsm
   :type '(choice (const :tag "Low" low)
@@ -85,6 +76,8 @@ stored in plain text."
   "If non-nil, the connection is opened in a non-interactive context.
 This means that no queries should be performed.")
 
+(declare-function gnutls-peer-status "gnutls.c" (proc))
+
 (defun nsm-verify-connection (process host port &optional
                                      save-fingerprint warn-unencrypted)
   "Verify the security status of PROCESS that's connected to HOST:PORT.
@@ -124,6 +117,17 @@ unencrypted."
          process))))))
 
 (defun nsm-check-tls-connection (process host port status settings)
+  (let ((process (nsm-check-certificate process host port status settings)))
+    (if (and process
+            (>= (nsm-level network-security-level) (nsm-level 'high)))
+       ;; Do further protocol-level checks if the security is high.
+       (nsm-check-protocol process host port status settings)
+      process)))
+
+(declare-function gnutls-peer-status-warning-describe "gnutls.c"
+                 (status-symbol))
+
+(defun nsm-check-certificate (process host port status settings)
   (let ((warnings (plist-get status :warnings)))
     (cond
 
@@ -165,7 +169,7 @@ unencrypted."
        (if (and (not (nsm-warnings-ok-p status settings))
                 (not (nsm-query
                       host port status 'conditions
-                      "The TLS connection to %s:%s is insecure\nfor the following reason%s:\n\n%s"
+                      "The TLS connection to %s:%s is insecure for the following reason%s:\n\n%s"
                       host port
                       (if (> (length warnings) 1)
                           "s" "")
@@ -177,6 +181,47 @@ unencrypted."
              nil)
          process))))))
 
+(defun nsm-check-protocol (process host port status settings)
+  (let ((prime-bits (plist-get status :diffie-hellman-prime-bits))
+       (encryption (format "%s-%s-%s"
+                           (plist-get status :key-exchange)
+                           (plist-get status :cipher)
+                           (plist-get status :mac)))
+       (protocol (plist-get status :protocol)))
+    (cond
+     ((and prime-bits
+          (< prime-bits 1024)
+          (not (memq :diffie-hellman-prime-bits
+                     (plist-get settings :conditions)))
+          (not
+           (nsm-query
+            host port status :diffie-hellman-prime-bits
+            "The Diffie-Hellman prime bits (%s) used for this connection to %s:%s is less than what is considered safe (%s)."
+            prime-bits host port 1024)))
+      (delete-process process)
+      nil)
+     ((and (string-match "\\bRC4\\b" encryption)
+          (not (memq :rc4 (plist-get settings :conditions)))
+          (not
+           (nsm-query
+            host port status :rc4
+            "The connection to %s:%s uses the RC4 algorithm (%s), which is believed to be unsafe."
+            host port encryption)))
+      (delete-process process)
+      nil)
+     ((and protocol
+          (string-match "SSL" protocol)
+          (not (memq :ssl (plist-get settings :conditions)))
+          (not
+           (nsm-query
+            host port status :ssl
+            "The connection to %s:%s uses the %s protocol, which is believed to be unsafe."
+            host port protocol)))
+      (delete-process process)
+      nil)
+     (t
+      process))))
+
 (defun nsm-fingerprint (status)
   (plist-get (plist-get status :certificate) :public-key-id))
 
@@ -190,7 +235,7 @@ unencrypted."
              (setq did-query
                    (nsm-query
                     host port status 'fingerprint
-                    "The fingerprint for the connection to %s:%s has changed from\n%s to\n%s"
+                    "The fingerprint for the connection to %s:%s has changed from %s to %s"
                     host port
                     (plist-get settings :fingerprint)
                     (nsm-fingerprint status)))))
@@ -205,7 +250,7 @@ unencrypted."
 (defun nsm-new-fingerprint-ok-p (host port status)
   (nsm-query
    host port status 'fingerprint
-   "The fingerprint for the connection to %s:%s is new:\n%s"
+   "The fingerprint for the connection to %s:%s is new: %s"
    host port
    (nsm-fingerprint status)))
 
@@ -219,7 +264,7 @@ unencrypted."
         (not
          (nsm-query
           host port nil 'conditions
-          "The connection to %s:%s used to be an encrypted\nconnection, but is now unencrypted.  This might mean that there's a\nman-in-the-middle tapping this connection."
+          "The connection to %s:%s used to be an encrypted connection, but is now unencrypted.  This might mean that there's a man-in-the-middle tapping this connection."
           host port)))
     (delete-process process)
     nil)
@@ -258,11 +303,17 @@ unencrypted."
        (erase-buffer)
        (when (> (length cert) 0)
          (insert cert "\n"))
-       (insert (apply 'format message args))))
+       (let ((start (point)))
+         (insert (apply #'format-message message args))
+         (goto-char start)
+         ;; Fill the first line of the message, which usually
+         ;; contains lots of explanatory text.
+         (fill-region (point) (line-end-position)))))
     (let ((responses '((?n . no)
                       (?s . session)
                       (?a . always)))
          (prefix "")
+         (cursor-in-echo-area t)
          response)
       (while (not response)
        (setq response
@@ -270,7 +321,7 @@ unencrypted."
               (assq (downcase
                      (read-char
                       (concat prefix
-                              "Continue connecting? (No, Session only, Always)")))
+                              "Continue connecting? (No, Session only, Always) ")))
                     responses)))
        (unless response
          (ding)
@@ -293,14 +344,22 @@ unencrypted."
       (nconc saved (list :host (format "%s:%s" host port))))
     ;; We either want to save/update the fingerprint or the conditions
     ;; of the certificate/unencrypted connection.
-    (when (eq what 'conditions)
-      (nconc saved (list :host (format "%s:%s" host port)))
+    (cond
+     ((eq what 'conditions)
       (cond
        ((not status)
-       (nconc saved `(:conditions (:unencrypted))))
+       (nconc saved '(:conditions (:unencrypted))))
        ((plist-get status :warnings)
        (nconc saved
-              `(:conditions ,(plist-get status :warnings))))))
+              (list :conditions (plist-get status :warnings))))))
+     ((not (eq what 'fingerprint))
+      ;; Store additional protocol settings.
+      (let ((settings (nsm-host-settings id)))
+       (when settings
+         (setq saved settings))
+       (if (plist-get saved :conditions)
+           (nconc (plist-get saved :conditions) (list what))
+         (nconc saved (list :conditions (list what)))))))
     (if (eq permanency 'always)
        (progn
          (nsm-remove-temporary-setting id)
@@ -382,6 +441,15 @@ unencrypted."
          (insert
           "Public key:" (plist-get cert :public-key-algorithm)
           ", signature: " (plist-get cert :signature-algorithm) "\n"))
+       (when (and (plist-get status :key-exchange)
+                  (plist-get status :cipher)
+                  (plist-get status :mac)
+                  (plist-get status :protocol))
+         (insert
+          "Protocol:" (plist-get status :protocol)
+          ", key: " (plist-get status :key-exchange)
+          ", cipher: " (plist-get status :cipher)
+          ", mac: " (plist-get status :mac) "\n"))
        (when (plist-get cert :certificate-security-level)
          (insert
           "Security level:"