emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Emacs-diffs] [emacs] 03/03: * net/nsm.el: New file to provide network s


From: Lars Ingebrigtsen
Subject: [Emacs-diffs] [emacs] 03/03: * net/nsm.el: New file to provide network security management.
Date: Mon, 17 Nov 2014 22:45:41 +0000

branch: nsm
commit cc67a74cf37b5ea8e271c11f1aca2a99988c3df0
Author: Lars Magne Ingebrigtsen <address@hidden>
Date:   Mon Nov 17 23:45:07 2014 +0100

    * net/nsm.el: New file to provide network security management.
---
 lisp/ChangeLog  |    4 +
 lisp/net/nsm.el |  230 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 234 insertions(+), 0 deletions(-)

diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index 54df183..b5587bd 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,3 +1,7 @@
+2014-11-17  Lars Magne Ingebrigtsen  <address@hidden>
+
+       * net/nsm.el: New file to provide network security management.
+
 2014-11-17  Eli Zaretskii  <address@hidden>
 
        * vc/vc-bzr.el (vc-bzr-print-log, vc-bzr-expanded-log-entry):
diff --git a/lisp/net/nsm.el b/lisp/net/nsm.el
new file mode 100644
index 0000000..94bd35f
--- /dev/null
+++ b/lisp/net/nsm.el
@@ -0,0 +1,230 @@
+;;; nsm.el --- Network Security Manager
+
+;; Copyright (C) 2014 Free Software Foundation, Inc.
+
+;; Author: Lars Magne Ingebrigtsen <address@hidden>
+;; Keywords: encryption, security, network
+
+;; 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 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.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'cl-lib)
+
+(defvar nsm-host-settings nil)
+
+(defgroup nsm nil
+  "Network Security Manager"
+  :version "25.1"
+  :group 'comm)
+
+(defcustom nsm-security-level 'medium
+  "How secure the network should be."
+  :version "25.1"
+  :group 'nsm
+  :type '(choice (const :tag "Low" 'low)
+                (const :tag "Medium" 'medium)
+                (const :tag "High" 'high)
+                (const :tag "Paranoid" 'paranoid)))
+
+(defcustom nsm-settings-file (expand-file-name "network-security.data"
+                                                user-emacs-directory)
+  "The file the security manager settings will be stored in."
+  :version "25.1"
+  :group 'nsm
+  :type 'file)
+
+(defun nsm-verify-connection (process host port)
+  "Verify the security status of PROCESS that's connected to HOST:PORT.
+If PROCESS is a gnutls connection, the certificate validity will
+be examined.  If it's a non-TLS connection, it may be compared
+against previous connections.  If the function determines that
+there is something odd about the connection, the user will be
+queried about what to do about it.
+
+The process it returned if everything is OK, and otherwise, the
+process will be deleted and nil is returne."
+  (let ((status (gnutls-peer-status process))
+       (settings (nsm-host-settings (nsm-id host port))))
+    (cond
+     ((not (process-live-p process))
+      nil)
+     ((not status)
+      ;; This is a non-TLS connection.
+      (nsm-check-plain-connection process host port settings))
+     (t
+      (nsm-check-tls-connection process host port status settings)))))
+
+(defun nsm-check-tls-connection (process host port status settings)
+  (let ((warnings (plist-get status :warnings)))
+    (cond
+     ((null warnings)
+      ;; The certificate is fine, but if we're paranoid, we might
+      ;; want to check whether it's changed anyway.
+      (if (not (equal nsm-security-level 'paranoid))
+         process
+       (if (and settings
+                (not (equal (plist-get status :fingerprint)
+                            (plist-get settings :fingerprint)))
+                (not (nsm-query
+                      (nsm-id host port)
+                      status
+                      "The fingerprint for the connection to %s:%s has changed 
from\n%s to\n%s"
+                      host port
+                      (plist-get status :fingerprint)
+                      (plist-get settings :fingerprint))))
+           (progn
+             (delete-process process)
+             nil)
+         (nsm-save-host (nsm-id host port) status)
+         process)))
+     ((not (equal nsm-security-level 'low))
+      ;; We have a warning, so query the user.
+      (if (and (not (nsm-warnings-ok-p status settings))
+              (not (nsm-query
+                    (nsm-id host port)
+                    status
+                    "The TLS connection to %s:%s is insecure\nfor the 
following reason%s:\n\n%s"
+                    host port
+                    (if (> (length warnings) 1)
+                        "s" "")
+                    (mapconcat 'cadr warnings "\n"))))
+         (progn
+           (delete-process process)
+           nil)
+       process)))))
+
+(defun nsm-check-plain-connection (process host port settings)
+  ;; If this connection used to be TLS, but is now plain, then it's
+  ;; possible that we're being Man-In-The-Middled by a proxy that's
+  ;; stripping out STARTTLS announcements.
+  (if (and (plist-get settings :fingerprint)
+          (nsm-query
+           (nsm-id host port)
+           nil
+           "The connection to %s:%s used to be an encrypted connection, but is 
now\nunencrypted.  This might mean that there's a man-in-the-middle 
tapping\nthis connection."
+           host port))
+      (progn
+       (delete-process process)
+       nil)
+    process))
+
+(defun nsm-query (id status message &rest args)
+  (let ((response
+        (condition-case nil
+            (nsm-query-user message args)
+          ;; Make sure we manage to close the process if the user hits
+          ;; `C-g'.
+          (quit 'no)
+          (error 'no))))
+    (if (eq response 'no)
+       nil
+      (nsm-save-host id status response)
+      t)))
+
+(defun nsm-query-user (message args)
+  (let ((responses '((?n . no)
+                    (?s . session)
+                    (?a . always)))
+       (prefix "")
+       response)
+    (while (not response)
+      (setq response
+           (cdr
+            (assq (downcase
+                   (read-char (concat prefix
+                                      (apply 'format message args)
+                                      "\n\nContinue connecting? (No, Session 
only, Always)")))
+                  responses)))
+      (unless response
+       (ding)
+       (setq prefix "Invalid choice.\n")))
+    response))
+
+(defun nsm-save-host (id status &optional permanency)
+  (nsm-remove-setting id)
+  (push
+   (list :id id
+        :fingerprint (if status
+                         (plist-get status :fingerprint)
+                       ;; Plain connection.
+                       :none)
+        :conditions
+        (cond
+         ((not status)
+          `((:unencrypted ,permanency)))
+         ((not permanency)
+          nil)
+         (t
+          (mapcar
+           (lambda (elem)
+             (list (car elem) permanency))
+           (plist-get status :warnings)))))
+   nsm-host-settings)
+  (nsm-write-settings))
+
+(defun nsm-write-settings ()
+  (with-temp-file nsm-settings-file
+    (insert "(\n")
+    (dolist (setting nsm-host-settings)
+      ;; Only save those settings that are saved for paranoid tracking
+      ;; purposes, or permanent settings.
+      (when (or (null (plist-get setting :conditions))
+               (eq (cadr (car (plist-get setting :conditions))) 'always))
+       (prin1 setting (current-buffer)))
+      (insert "\n"))
+    (insert ")\n")))
+
+(defun nsm-read-settings ()
+  (setq nsm-host-settings
+       (with-temp-buffer
+         (insert-file-contents nsm-settings-file)
+         (goto-char (point-min))
+         (ignore-errors (read (current-buffer))))))
+
+(defun nsm-id (host port)
+  (concat "sha1:" (sha1 (format "%s:%s" host port))))
+
+(defun nsm-host-settings (id)
+  (when (and (not nsm-host-settings)
+            (file-exists-p nsm-settings-file))
+    (nsm-read-settings))
+  (let ((result nil))
+    (dolist (elem nsm-host-settings)
+      (when (equal (plist-get elem :id) id)
+       (setq result elem)))
+    result))
+
+(defun nsm-warnings-ok-p (status settings)
+  (let ((not-ok nil)
+       (conditions (plist-get settings :conditions)))
+    (dolist (warning (plist-get status :warnings))
+      (unless (memq (cadr (memq (car warning) conditions))
+                   '(always session))
+       (setq not-ok t)))
+    not-ok))
+
+(defun nsm-remove-setting (id)
+  (setq nsm-host-settings (cl-delete-if
+                          (lambda (elem)
+                            (equal (plist-get elem :id) id))
+                          nsm-host-settings)))
+
+(provide 'nsm)
+
+;;; nsm.el ends here



reply via email to

[Prev in Thread] Current Thread [Next in Thread]