"SfR Fresh" - the SfR Freeware/Shareware Archive 
Member "gnus-5.10.10/lisp/canlock.el" of archive gnus-5.10.10.tar.gz:
As a special service "SfR Fresh" has tried to format the requested source page into HTML format using (guessed) Lisp source code syntax highlighting with prefixed line numbers.
Alternatively you can here view or download the uninterpreted source code file.
That can be also achieved for any archive member file by clicking within an archive contents listing on the first character of the file(path) respectively on the according byte size field.
1 ;;; canlock.el --- functions for Cancel-Lock feature
2
3 ;; Copyright (C) 1998, 1999, 2001, 2002, 2003, 2004,
4 ;; 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
5
6 ;; Author: Katsumi Yamaoka <yamaoka@jpl.org>
7 ;; Keywords: news, cancel-lock, hmac, sha1, rfc2104
8
9 ;; This program is free software; you can redistribute it and/or modify
10 ;; it under the terms of the GNU General Public License as published by
11 ;; the Free Software Foundation; either version 3, or (at your option)
12 ;; any later version.
13
14 ;; This program is distributed in the hope that it will be useful,
15 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 ;; GNU General Public License for more details.
18
19 ;; You should have received a copy of the GNU General Public License
20 ;; along with this program; see the file COPYING. If not, write to the
21 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 ;; Boston, MA 02110-1301, USA.
23
24 ;;; Commentary:
25
26 ;; Canlock is a library for generating and verifying Cancel-Lock and/or
27 ;; Cancel-Key header in news articles. This is used to protect articles
28 ;; from rogue cancel, supersede or replace attacks. The method is based
29 ;; on draft-ietf-usefor-cancel-lock-01.txt which was released on November
30 ;; 3rd 1998. For instance, you can add Cancel-Lock (and possibly Cancel-
31 ;; Key) header in a news article by using a hook which will be evaluated
32 ;; just before sending an article as follows:
33 ;;
34 ;; (add-hook '*e**a*e-header-hook 'canlock-insert-header t)
35 ;;
36 ;; Verifying Cancel-Lock is mainly a function of news servers, however,
37 ;; you can verify your own article using the command `canlock-verify' in
38 ;; the (raw) article buffer. You will be prompted for the password for
39 ;; each time if the option `canlock-password' or `canlock-password-for-
40 ;; verify' is nil. Note that setting these options is a bit unsafe.
41
42 ;;; Code:
43
44 (eval-when-compile
45 (require 'cl))
46
47 (require 'sha1)
48
49 (defvar mail-header-separator)
50
51 (defgroup canlock nil
52 "The Cancel-Lock feature."
53 :group 'news)
54
55 (defcustom canlock-password nil
56 "Password to use when signing a Cancel-Lock or a Cancel-Key header."
57 :type '(radio (const :format "Not specified " nil)
58 (string :tag "Password"))
59 :group 'canlock)
60
61 (defcustom canlock-password-for-verify canlock-password
62 "Password to use when verifying a Cancel-Lock or a Cancel-Key header."
63 :type '(radio (const :format "Not specified " nil)
64 (string :tag "Password"))
65 :group 'canlock)
66
67 (defcustom canlock-force-insert-header nil
68 "If non-nil, insert a Cancel-Lock or a Cancel-Key header even if the
69 buffer does not look like a news message."
70 :type 'boolean
71 :group 'canlock)
72
73 (eval-when-compile
74 (defmacro canlock-string-as-unibyte (string)
75 "Return a unibyte string with the same individual bytes as STRING."
76 (if (fboundp 'string-as-unibyte)
77 (list 'string-as-unibyte string)
78 string)))
79
80 (defun canlock-sha1 (message)
81 "Make a SHA-1 digest of MESSAGE as a unibyte string of length 20 bytes."
82 (let (sha1-maximum-internal-length)
83 (sha1 message nil nil 'binary)))
84
85 (defun canlock-make-cancel-key (message-id password)
86 "Make a Cancel-Key header."
87 (when (> (length password) 20)
88 (setq password (canlock-sha1 password)))
89 (setq password (concat password (make-string (- 64 (length password)) 0)))
90 (let ((ipad (mapconcat (lambda (byte)
91 (char-to-string (logxor 54 byte)))
92 password ""))
93 (opad (mapconcat (lambda (byte)
94 (char-to-string (logxor 92 byte)))
95 password "")))
96 (base64-encode-string
97 (canlock-sha1
98 (concat opad
99 (canlock-sha1
100 (concat ipad (canlock-string-as-unibyte message-id))))))))
101
102 (defun canlock-narrow-to-header ()
103 "Narrow the buffer to the head of the message."
104 (let (case-fold-search)
105 (narrow-to-region
106 (goto-char (point-min))
107 (goto-char (if (re-search-forward
108 (format "^$\\|^%s$"
109 (regexp-quote mail-header-separator))
110 nil t)
111 (match-beginning 0)
112 (point-max))))))
113
114 (defun canlock-delete-headers ()
115 "Delete Cancel-Key or Cancel-Lock headers in the narrowed buffer."
116 (let ((case-fold-search t))
117 (goto-char (point-min))
118 (while (re-search-forward "^Cancel-\\(Key\\|Lock\\):" nil t)
119 (delete-region (match-beginning 0)
120 (if (re-search-forward "^[^\t ]" nil t)
121 (goto-char (match-beginning 0))
122 (point-max))))))
123
124 (defun canlock-fetch-fields (&optional key)
125 "Return a list of the values of Cancel-Lock header.
126 If KEY is non-nil, look for a Cancel-Key header instead. The buffer
127 is expected to be narrowed to just the headers of the message."
128 (let ((field (mail-fetch-field (if key "Cancel-Key" "Cancel-Lock")))
129 fields rest
130 (case-fold-search t))
131 (when field
132 (setq fields (split-string field "[\t\n\r ,]+"))
133 (while fields
134 (when (string-match "^sha1:" (setq field (pop fields)))
135 (push (substring field 5) rest)))
136 (nreverse rest))))
137
138 (defun canlock-fetch-id-for-key ()
139 "Return a Message-ID in Cancel, Supersedes or Replaces header.
140 The buffer is expected to be narrowed to just the headers of the
141 message."
142 (or (let ((cancel (mail-fetch-field "Control")))
143 (and cancel
144 (string-match "^cancel[\t ]+\\(<[^\t\n @<>]+@[^\t\n @<>]+>\\)"
145 cancel)
146 (match-string 1 cancel)))
147 (mail-fetch-field "Supersedes")
148 (mail-fetch-field "Replaces")))
149
150 ;;;###autoload
151 (defun canlock-insert-header (&optional id-for-key id-for-lock password)
152 "Insert a Cancel-Key and/or a Cancel-Lock header if possible."
153 (let (news control key-for-key key-for-lock)
154 (save-excursion
155 (save-restriction
156 (canlock-narrow-to-header)
157 (when (setq news (or canlock-force-insert-header
158 (mail-fetch-field "Newsgroups")))
159 (unless id-for-key
160 (setq id-for-key (canlock-fetch-id-for-key)))
161 (if (and (setq control (mail-fetch-field "Control"))
162 (string-match "^cancel[\t ]+<[^\t\n @<>]+@[^\t\n @<>]+>"
163 control))
164 (setq id-for-lock nil)
165 (unless id-for-lock
166 (setq id-for-lock (mail-fetch-field "Message-ID"))))
167 (canlock-delete-headers)
168 (goto-char (point-max))))
169 (when news
170 (if (not (or id-for-key id-for-lock))
171 (message "There are no Message-ID(s)")
172 (unless password
173 (setq password (or canlock-password
174 (read-passwd
175 "Password for Canlock: "))))
176 (if (or (not (stringp password)) (zerop (length password)))
177 (message "Password for Canlock is bad")
178 (setq key-for-key (when id-for-key
179 (canlock-make-cancel-key
180 id-for-key password))
181 key-for-lock (when id-for-lock
182 (canlock-make-cancel-key
183 id-for-lock password)))
184 (if (not (or key-for-key key-for-lock))
185 (message "Couldn't insert Canlock header")
186 (when key-for-key
187 (insert "Cancel-Key: sha1:" key-for-key "\n"))
188 (when key-for-lock
189 (insert "Cancel-Lock: sha1:"
190 (base64-encode-string (canlock-sha1 key-for-lock))
191 "\n")))))))))
192
193 ;;;###autoload
194 (defun canlock-verify (&optional buffer)
195 "Verify Cancel-Lock or Cancel-Key in BUFFER.
196 If BUFFER is nil, the current buffer is assumed. Signal an error if
197 it fails."
198 (interactive)
199 (let (keys locks errmsg id-for-key id-for-lock password
200 key-for-key key-for-lock match)
201 (save-excursion
202 (when buffer
203 (set-buffer buffer))
204 (save-restriction
205 (widen)
206 (canlock-narrow-to-header)
207 (setq keys (canlock-fetch-fields 'key)
208 locks (canlock-fetch-fields))
209 (if (not (or keys locks))
210 (setq errmsg
211 "There are neither Cancel-Lock nor Cancel-Key headers")
212 (setq id-for-key (canlock-fetch-id-for-key)
213 id-for-lock (mail-fetch-field "Message-ID"))
214 (or id-for-key id-for-lock
215 (setq errmsg "There are no Message-ID(s)")))))
216 (if errmsg
217 (error "%s" errmsg)
218 (setq password (or canlock-password-for-verify
219 (read-passwd "Password for Canlock: ")))
220 (if (or (not (stringp password)) (zerop (length password)))
221 (error "Password for Canlock is bad")
222 (when keys
223 (when id-for-key
224 (setq key-for-key (canlock-make-cancel-key id-for-key password))
225 (while (and keys (not match))
226 (setq match (string-equal key-for-key (pop keys)))))
227 (setq keys (if match "good" "bad")))
228 (setq match nil)
229 (when locks
230 (when id-for-lock
231 (setq key-for-lock
232 (base64-encode-string
233 (canlock-sha1 (canlock-make-cancel-key id-for-lock
234 password))))
235 (when (and locks (not match))
236 (setq match (string-equal key-for-lock (pop locks)))))
237 (setq locks (if match "good" "bad")))
238 (prog1
239 (when (member "bad" (list keys locks))
240 "bad")
241 (cond ((and keys locks)
242 (message "Cancel-Key is %s, Cancel-Lock is %s" keys locks))
243 (locks
244 (message "Cancel-Lock is %s" locks))
245 (keys
246 (message "Cancel-Key is %s" keys))))))))
247
248 (provide 'canlock)
249
250 ;;; arch-tag: 033c4f09-b9f1-459d-bd0d-254430283f78
251 ;;; canlock.el ends here