
Instead of restyling curved quotes for every call to ‘format’, create a new function ‘format-message’ that does the restyling, and using the new function instead of ‘format’ only in contexts where this seems appropriate. Problem reported by Dmitry Gutov and Andreas Schwab in: http://lists.gnu.org/archive/html/emacs-devel/2015-08/msg00826.html http://lists.gnu.org/archive/html/emacs-devel/2015-08/msg00827.html * doc/lispref/commands.texi (Using Interactive): * doc/lispref/control.texi (Signaling Errors, Signaling Errors): * doc/lispref/display.texi (Displaying Messages, Progress): * doc/lispref/elisp.texi: * doc/lispref/help.texi (Keys in Documentation): * doc/lispref/minibuf.texi (Minibuffer Misc): * doc/lispref/strings.texi (Formatting Strings): * etc/NEWS: Document the changes. * lisp/abbrev.el (expand-region-abbrevs): * lisp/apropos.el (apropos-library): * lisp/calc/calc-ext.el (calc-record-message) (calc-user-function-list): * lisp/calc/calc-help.el (calc-describe-key, calc-full-help): * lisp/calc/calc-lang.el (math-read-big-balance): * lisp/calc/calc-store.el (calc-edit-variable): * lisp/calc/calc-units.el (math-build-units-table-buffer): * lisp/calc/calc-yank.el (calc-edit-mode): * lisp/calendar/icalendar.el (icalendar-export-region) (icalendar--add-diary-entry): * lisp/cedet/mode-local.el (mode-local-print-binding) (mode-local-describe-bindings-2): * lisp/cedet/semantic/complete.el (semantic-completion-message): * lisp/cedet/semantic/edit.el (semantic-parse-changes-failed): * lisp/cedet/semantic/wisent/comp.el (wisent-log): * lisp/cedet/srecode/insert.el (srecode-insert-show-error-report): * lisp/descr-text.el (describe-text-properties-1, describe-char): * lisp/dframe.el (dframe-message): * lisp/dired-aux.el (dired-query): * lisp/emacs-lisp/byte-opt.el (byte-compile-log-lap-1): * lisp/emacs-lisp/bytecomp.el (byte-compile-log) (byte-compile-log-file, byte-compile-warn, byte-compile-form): * lisp/emacs-lisp/cconv.el (cconv-convert, cconv--analyze-use) (cconv-analyze-form): * lisp/emacs-lisp/check-declare.el (check-declare-warn): * lisp/emacs-lisp/checkdoc.el (checkdoc-this-string-valid-engine): * lisp/emacs-lisp/cl-macs.el (cl-symbol-macrolet): * lisp/emacs-lisp/edebug.el (edebug-format): * lisp/emacs-lisp/eieio-core.el (eieio-oref): * lisp/emacs-lisp/eldoc.el (eldoc-minibuffer-message) (eldoc-message): * lisp/emacs-lisp/elint.el (elint-file, elint-log): * lisp/emacs-lisp/find-func.el (find-function-library): * lisp/emacs-lisp/macroexp.el (macroexp--obsolete-warning): * lisp/emacs-lisp/map-ynp.el (map-y-or-n-p): * lisp/emacs-lisp/nadvice.el (advice--make-docstring): * lisp/emacs-lisp/package.el (package-compute-transaction) (package-install-button-action, package-delete-button-action) (package-menu--list-to-prompt): * lisp/emacs-lisp/timer.el (timer-event-handler): * lisp/emacs-lisp/warnings.el (lwarn, warn): * lisp/emulation/viper-cmd.el: (viper-toggle-parse-sexp-ignore-comments) (viper-kill-buffer, viper-brac-function): * lisp/emulation/viper-macs.el (viper-record-kbd-macro): * lisp/facemenu.el (facemenu-add-new-face): * lisp/faces.el (face-documentation, read-face-name) (face-read-string, read-face-font, describe-face): * lisp/files.el (find-alternate-file, hack-local-variables) (hack-one-local-variable--obsolete, write-file) (basic-save-buffer, delete-directory): * lisp/format.el (format-write-file, format-find-file) (format-insert-file): * lisp/help-fns.el (help-fns--key-bindings) (help-fns--compiler-macro, help-fns--obsolete) (help-fns--interactive-only, describe-function-1) (describe-variable): * lisp/help.el (describe-mode): * lisp/info-xref.el (info-xref-output): * lisp/info.el (Info-virtual-index-find-node) (Info-virtual-index, info-apropos): * lisp/international/kkc.el (kkc-error): * lisp/international/mule-cmds.el: (select-safe-coding-system-interactively) (select-safe-coding-system, describe-input-method): * lisp/international/mule-conf.el (code-offset): * lisp/international/mule-diag.el (describe-character-set) (list-input-methods-1): * lisp/international/quail.el (quail-error): * lisp/minibuffer.el (minibuffer-message): * lisp/mpc.el (mpc--debug): * lisp/msb.el (msb--choose-menu): * lisp/net/ange-ftp.el (ange-ftp-message): * lisp/net/gnutls.el (gnutls-message-maybe): * lisp/net/newst-backend.el (newsticker--sentinel-work): * lisp/net/newst-treeview.el (newsticker--treeview-load): * lisp/net/nsm.el (nsm-query-user): * lisp/net/rlogin.el (rlogin): * lisp/net/soap-client.el (soap-warning): * lisp/net/tramp.el (tramp-debug-message): * lisp/nxml/nxml-outln.el (nxml-report-outline-error): * lisp/nxml/nxml-parse.el (nxml-parse-error): * lisp/nxml/rng-cmpct.el (rng-c-error): * lisp/nxml/rng-match.el (rng-compile-error): * lisp/nxml/rng-uri.el (rng-uri-error): * lisp/obsolete/iswitchb.el (iswitchb-possible-new-buffer): * lisp/org/org-ctags.el: (org-ctags-ask-rebuild-tags-file-then-find-tag): * lisp/proced.el (proced-log): * lisp/progmodes/ebnf2ps.el (ebnf-log): * lisp/progmodes/flymake.el (flymake-log): * lisp/progmodes/vhdl-mode.el (vhdl-warning-when-idle): * lisp/replace.el (occur-1): * lisp/simple.el (execute-extended-command) (undo-outer-limit-truncate, define-alternatives): * lisp/startup.el (command-line): * lisp/subr.el (error, user-error, add-to-list): * lisp/tutorial.el (tutorial--describe-nonstandard-key) (tutorial--find-changed-keys): * src/callint.c (Fcall_interactively): * src/editfns.c (Fmessage, Fmessage_box): Restyle the quotes of format strings intended for use as a diagnostic, when restyling seems appropriate. * lisp/subr.el (format-message): New function. * src/doc.c (Finternal__text_restyle): New function. (syms_of_doc): Define it.
508 lines
16 KiB
EmacsLisp
508 lines
16 KiB
EmacsLisp
;;; nsm.el --- Network Security Manager
|
|
|
|
;; Copyright (C) 2014-2015 Free Software Foundation, Inc.
|
|
|
|
;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
|
|
;; 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-permanent-host-settings nil)
|
|
(defvar nsm-temporary-host-settings nil)
|
|
|
|
(defgroup nsm nil
|
|
"Network Security Manager"
|
|
:version "25.1"
|
|
:group 'comm)
|
|
|
|
(defcustom network-security-level 'medium
|
|
"How secure the network should be.
|
|
If a potential problem with the security of the network
|
|
connection is found, the user is asked to give input into how the
|
|
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.
|
|
|
|
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)
|
|
(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)
|
|
|
|
(defcustom nsm-save-host-names nil
|
|
"If non-nil, always save host names in the structures in `nsm-settings-file'.
|
|
By default, only hosts that have exceptions have their names
|
|
stored in plain text."
|
|
:version "25.1"
|
|
:group 'nsm
|
|
:type 'boolean)
|
|
|
|
(defvar nsm-noninteractive nil
|
|
"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.
|
|
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 returned.
|
|
|
|
If SAVE-FINGERPRINT, always save the fingerprint of the
|
|
server (if the connection is a TLS connection). This is useful
|
|
to keep track of the TLS status of STARTTLS servers.
|
|
|
|
If WARN-UNENCRYPTED, query the user if the connection is
|
|
unencrypted."
|
|
(if (eq network-security-level 'low)
|
|
process
|
|
(let* ((status (gnutls-peer-status process))
|
|
(id (nsm-id host port))
|
|
(settings (nsm-host-settings id)))
|
|
(cond
|
|
((not (process-live-p process))
|
|
nil)
|
|
((not status)
|
|
;; This is a non-TLS connection.
|
|
(nsm-check-plain-connection process host port settings
|
|
warn-unencrypted))
|
|
(t
|
|
(let ((process
|
|
(nsm-check-tls-connection process host port status settings)))
|
|
(when (and process save-fingerprint
|
|
(null (nsm-host-settings id)))
|
|
(nsm-save-host host port status 'fingerprint 'always))
|
|
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
|
|
|
|
;; The certificate validated, but perhaps we want to do
|
|
;; certificate pinning.
|
|
((null warnings)
|
|
(cond
|
|
((< (nsm-level network-security-level) (nsm-level 'high))
|
|
process)
|
|
;; The certificate is fine, but if we're paranoid, we might
|
|
;; want to check whether it's changed anyway.
|
|
((and (>= (nsm-level network-security-level) (nsm-level 'high))
|
|
(not (nsm-fingerprint-ok-p host port status settings)))
|
|
(delete-process process)
|
|
nil)
|
|
;; We haven't seen this before, and we're paranoid.
|
|
((and (eq network-security-level 'paranoid)
|
|
(null settings)
|
|
(not (nsm-new-fingerprint-ok-p host port status)))
|
|
(delete-process process)
|
|
nil)
|
|
((>= (nsm-level network-security-level) (nsm-level 'high))
|
|
;; Save the host fingerprint so that we can check it the
|
|
;; next time we connect.
|
|
(nsm-save-host host port status 'fingerprint 'always)
|
|
process)
|
|
(t
|
|
process)))
|
|
|
|
;; The certificate did not validate.
|
|
((not (equal network-security-level 'low))
|
|
;; We always want to pin the certificate of invalid connections
|
|
;; to track man-in-the-middle or the like.
|
|
(if (not (nsm-fingerprint-ok-p host port status settings))
|
|
(progn
|
|
(delete-process process)
|
|
nil)
|
|
;; We have a warning, so query the user.
|
|
(if (and (not (nsm-warnings-ok-p status settings))
|
|
(not (nsm-query
|
|
host port status 'conditions
|
|
"The TLS connection to %s:%s is insecure for the following reason%s:\n\n%s"
|
|
host port
|
|
(if (> (length warnings) 1)
|
|
"s" "")
|
|
(mapconcat #'gnutls-peer-status-warning-describe
|
|
warnings
|
|
"\n"))))
|
|
(progn
|
|
(delete-process process)
|
|
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))
|
|
|
|
(defun nsm-fingerprint-ok-p (host port status settings)
|
|
(let ((did-query nil))
|
|
(if (and settings
|
|
(not (eq (plist-get settings :fingerprint) :none))
|
|
(not (equal (nsm-fingerprint status)
|
|
(plist-get settings :fingerprint)))
|
|
(not
|
|
(setq did-query
|
|
(nsm-query
|
|
host port status 'fingerprint
|
|
"The fingerprint for the connection to %s:%s has changed from %s to %s"
|
|
host port
|
|
(plist-get settings :fingerprint)
|
|
(nsm-fingerprint status)))))
|
|
;; Not OK.
|
|
nil
|
|
(when did-query
|
|
;; Remove any exceptions that have been set on the previous
|
|
;; certificate.
|
|
(plist-put settings :conditions nil))
|
|
t)))
|
|
|
|
(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: %s"
|
|
host port
|
|
(nsm-fingerprint status)))
|
|
|
|
(defun nsm-check-plain-connection (process host port settings warn-unencrypted)
|
|
;; 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.
|
|
(cond
|
|
((and (plist-get settings :fingerprint)
|
|
(not (eq (plist-get settings :fingerprint) :none))
|
|
(not
|
|
(nsm-query
|
|
host port nil 'conditions
|
|
"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)
|
|
((and warn-unencrypted
|
|
(not (memq :unencrypted (plist-get settings :conditions)))
|
|
(not (nsm-query
|
|
host port nil 'conditions
|
|
"The connection to %s:%s is unencrypted."
|
|
host port)))
|
|
(delete-process process)
|
|
nil)
|
|
(t
|
|
process)))
|
|
|
|
(defun nsm-query (host port status what message &rest args)
|
|
;; If there is no user to answer queries, then say `no' to everything.
|
|
(if (or noninteractive
|
|
nsm-noninteractive)
|
|
nil
|
|
(let ((response
|
|
(condition-case nil
|
|
(nsm-query-user message args (nsm-format-certificate status))
|
|
;; 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 host port status what response)
|
|
t))))
|
|
|
|
(defun nsm-query-user (message args cert)
|
|
(let ((buffer (get-buffer-create "*Network Security Manager*")))
|
|
(with-help-window buffer
|
|
(with-current-buffer buffer
|
|
(erase-buffer)
|
|
(when (> (length cert) 0)
|
|
(insert cert "\n"))
|
|
(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
|
|
(cdr
|
|
(assq (downcase
|
|
(read-char
|
|
(concat prefix
|
|
"Continue connecting? (No, Session only, Always) ")))
|
|
responses)))
|
|
(unless response
|
|
(ding)
|
|
(setq prefix "Invalid choice. ")))
|
|
(kill-buffer buffer)
|
|
;; If called from a callback, `read-char' will insert things
|
|
;; into the pending input. Clear that.
|
|
(clear-this-command-keys)
|
|
response)))
|
|
|
|
(defun nsm-save-host (host port status what permanency)
|
|
(let* ((id (nsm-id host port))
|
|
(saved
|
|
(list :id id
|
|
:fingerprint (or (nsm-fingerprint status)
|
|
;; Plain connection.
|
|
:none))))
|
|
(when (or (eq what 'conditions)
|
|
nsm-save-host-names)
|
|
(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.
|
|
(cond
|
|
((eq what 'conditions)
|
|
(cond
|
|
((not status)
|
|
(nconc saved '(:conditions (:unencrypted))))
|
|
((plist-get status :warnings)
|
|
(nconc saved
|
|
(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)
|
|
(nsm-remove-permanent-setting id)
|
|
(push saved nsm-permanent-host-settings)
|
|
(nsm-write-settings))
|
|
(nsm-remove-temporary-setting id)
|
|
(push saved nsm-temporary-host-settings))))
|
|
|
|
(defun nsm-write-settings ()
|
|
(with-temp-file nsm-settings-file
|
|
(insert "(\n")
|
|
(dolist (setting nsm-permanent-host-settings)
|
|
(insert " ")
|
|
(prin1 setting (current-buffer))
|
|
(insert "\n"))
|
|
(insert ")\n")))
|
|
|
|
(defun nsm-read-settings ()
|
|
(setq nsm-permanent-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-permanent-host-settings)
|
|
(file-exists-p nsm-settings-file))
|
|
(nsm-read-settings))
|
|
(let ((result nil))
|
|
(dolist (elem (append nsm-temporary-host-settings
|
|
nsm-permanent-host-settings))
|
|
(when (and (not result)
|
|
(equal (plist-get elem :id) id))
|
|
(setq result elem)))
|
|
result))
|
|
|
|
(defun nsm-warnings-ok-p (status settings)
|
|
(let ((ok t)
|
|
(conditions (plist-get settings :conditions)))
|
|
(dolist (warning (plist-get status :warnings))
|
|
(unless (memq warning conditions)
|
|
(setq ok nil)))
|
|
ok))
|
|
|
|
(defun nsm-remove-permanent-setting (id)
|
|
(setq nsm-permanent-host-settings
|
|
(cl-delete-if
|
|
(lambda (elem)
|
|
(equal (plist-get elem :id) id))
|
|
nsm-permanent-host-settings)))
|
|
|
|
(defun nsm-remove-temporary-setting (id)
|
|
(setq nsm-temporary-host-settings
|
|
(cl-delete-if
|
|
(lambda (elem)
|
|
(equal (plist-get elem :id) id))
|
|
nsm-temporary-host-settings)))
|
|
|
|
(defun nsm-format-certificate (status)
|
|
(let ((cert (plist-get status :certificate)))
|
|
(when cert
|
|
(with-temp-buffer
|
|
(insert
|
|
"Certificate information\n"
|
|
"Issued by:"
|
|
(nsm-certificate-part (plist-get cert :issuer) "CN" t) "\n"
|
|
"Issued to:"
|
|
(or (nsm-certificate-part (plist-get cert :subject) "O")
|
|
(nsm-certificate-part (plist-get cert :subject) "OU" t))
|
|
"\n"
|
|
"Hostname:"
|
|
(nsm-certificate-part (plist-get cert :subject) "CN" t) "\n")
|
|
(when (and (plist-get cert :public-key-algorithm)
|
|
(plist-get cert :signature-algorithm))
|
|
(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:"
|
|
(propertize (plist-get cert :certificate-security-level)
|
|
'face 'bold)
|
|
"\n"))
|
|
(insert
|
|
"Valid:From " (plist-get cert :valid-from)
|
|
" to " (plist-get cert :valid-to) "\n\n")
|
|
(goto-char (point-min))
|
|
(while (re-search-forward "^[^:]+:" nil t)
|
|
(insert (make-string (- 20 (current-column)) ? )))
|
|
(buffer-string)))))
|
|
|
|
(defun nsm-certificate-part (string part &optional full)
|
|
(let ((part (cadr (assoc part (nsm-parse-subject string)))))
|
|
(cond
|
|
(part part)
|
|
(full string)
|
|
(t nil))))
|
|
|
|
(defun nsm-parse-subject (string)
|
|
(with-temp-buffer
|
|
(insert string)
|
|
(goto-char (point-min))
|
|
(let ((start (point))
|
|
(result nil))
|
|
(while (not (eobp))
|
|
(push (replace-regexp-in-string
|
|
"[\\]\\(.\\)" "\\1"
|
|
(buffer-substring start
|
|
(if (re-search-forward "[^\\]," nil 'move)
|
|
(1- (point))
|
|
(point))))
|
|
result)
|
|
(setq start (point)))
|
|
(mapcar
|
|
(lambda (elem)
|
|
(let ((pos (cl-position ?= elem)))
|
|
(if pos
|
|
(list (substring elem 0 pos)
|
|
(substring elem (1+ pos)))
|
|
elem)))
|
|
(nreverse result)))))
|
|
|
|
(defun nsm-level (symbol)
|
|
"Return a numerical level for SYMBOL for easier comparison."
|
|
(cond
|
|
((eq symbol 'low) 0)
|
|
((eq symbol 'medium) 1)
|
|
((eq symbol 'high) 2)
|
|
(t 3)))
|
|
|
|
(provide 'nsm)
|
|
|
|
;;; nsm.el ends here
|