1 ;;; mml-smime.el --- S/MIME support for MML
3 ;; Copyright (C) 2000, 2001, 2002, 2003, 2004,
4 ;; 2005, 2006 Free Software Foundation, Inc.
6 ;; Author: Simon Josefsson <simon@josefsson.org>
7 ;; Keywords: Gnus, MIME, S/MIME, MML
9 ;; This file is part of GNU Emacs.
11 ;; GNU Emacs is free software; you can redistribute it and/or modify
12 ;; it under the terms of the GNU General Public License as published
13 ;; by the Free Software Foundation; either version 2, or (at your
14 ;; option) any later version.
16 ;; GNU Emacs is distributed in the hope that it will be useful, but
17 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 ;; General Public License for more details.
21 ;; You should have received a copy of the GNU General Public License
22 ;; along with GNU Emacs; see the file COPYING. If not, write to the
23 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
24 ;; Boston, MA 02110-1301, USA.
30 (eval-when-compile (require 'cl
))
34 (autoload 'message-narrow-to-headers
"message")
35 (autoload 'message-fetch-field
"message")
37 (defun mml-smime-sign (cont)
38 (when (null smime-keys
)
39 (customize-variable 'smime-keys
)
40 (error "No S/MIME keys configured, use customize to add your key"))
41 (smime-sign-buffer (cdr (assq 'keyfile cont
)))
42 (goto-char (point-min))
43 (while (search-forward "\r\n" nil t
)
44 (replace-match "\n" t t
))
45 (goto-char (point-max)))
47 (defun mml-smime-encrypt (cont)
48 (let (certnames certfiles tmp file tmpfiles
)
49 ;; xxx tmp files are always an security issue
50 (while (setq tmp
(pop cont
))
51 (if (and (consp tmp
) (eq (car tmp
) 'certfile
))
52 (push (cdr tmp
) certnames
)))
53 (while (setq tmp
(pop certnames
))
54 (if (not (and (not (file-exists-p tmp
))
57 (setq file
(mm-make-temp-file (expand-file-name "mml."
59 (with-current-buffer tmp
60 (write-region (point-min) (point-max) file
))
62 (push file tmpfiles
)))
63 (if (smime-encrypt-buffer certfiles
)
65 (while (setq tmp
(pop tmpfiles
))
68 (while (setq tmp
(pop tmpfiles
))
71 (goto-char (point-max)))
73 (defun mml-smime-sign-query ()
74 ;; query information (what certificate) from user when MML tag is
75 ;; added, for use later by the signing process
76 (when (null smime-keys
)
77 (customize-variable 'smime-keys
)
78 (error "No S/MIME keys configured, use customize to add your key"))
80 (if (= (length smime-keys
) 1)
82 (or (let ((from (cadr (funcall (if (boundp
83 'gnus-extract-address-components
)
84 gnus-extract-address-components
85 'mail-extract-address-components
)
88 (message-narrow-to-headers)
89 (message-fetch-field "from")))
91 (and from
(smime-get-key-by-email from
)))
92 (smime-get-key-by-email
93 (completing-read "Sign this part with what signature? "
95 (and (listp (car-safe smime-keys
))
96 (caar smime-keys
))))))))
98 (defun mml-smime-get-file-cert ()
100 (list 'certfile
(read-file-name
101 "File with recipient's S/MIME certificate: "
102 smime-certificate-directory nil t
""))))
104 (defun mml-smime-get-dns-cert ()
105 ;; todo: deal with comma separated multiple recipients
106 (let (result who bad cert
)
109 (setq who
(read-from-minibuffer
110 (format "%sLookup certificate for: " (or bad
""))
111 (cadr (funcall (if (boundp
112 'gnus-extract-address-components
)
113 gnus-extract-address-components
114 'mail-extract-address-components
)
117 (message-narrow-to-headers)
118 (message-fetch-field "to")))
120 (if (setq cert
(smime-cert-by-dns who
))
121 (setq result
(list 'certfile
(buffer-name cert
)))
122 (setq bad
(format "`%s' not found. " who
))))
126 (defun mml-smime-encrypt-query ()
127 ;; todo: add ldap support (xemacs ldap api?)
128 ;; todo: try dns/ldap automatically first, before prompting user
131 (ecase (read (gnus-completing-read-with-default
132 "dns" "Fetch certificate from"
133 '(("dns") ("file")) nil t
))
134 (dns (setq certs
(append certs
135 (mml-smime-get-dns-cert))))
136 (file (setq certs
(append certs
137 (mml-smime-get-file-cert)))))
138 (setq done
(not (y-or-n-p "Add more recipients? "))))
141 (defun mml-smime-verify (handle ctl
)
143 (insert-buffer-substring (mm-handle-multipart-original-buffer ctl
))
144 (goto-char (point-min))
145 (insert (format "Content-Type: %s; " (mm-handle-media-type ctl
)))
146 (insert (format "protocol=\"%s\"; "
147 (mm-handle-multipart-ctl-parameter ctl
'protocol
)))
148 (insert (format "micalg=\"%s\"; "
149 (mm-handle-multipart-ctl-parameter ctl
'micalg
)))
150 (insert (format "boundary=\"%s\"\n\n"
151 (mm-handle-multipart-ctl-parameter ctl
'boundary
)))
152 (when (get-buffer smime-details-buffer
)
153 (kill-buffer smime-details-buffer
))
154 (let ((buf (current-buffer))
155 (good-signature (smime-noverify-buffer))
156 (good-certificate (and (or smime-CA-file smime-CA-directory
)
157 (smime-verify-buffer)))
158 addresses openssl-output
)
159 (setq openssl-output
(with-current-buffer smime-details-buffer
161 (if (not good-signature
)
163 ;; we couldn't verify message, fail with openssl output as message
164 (mm-set-handle-multipart-parameter
165 mm-security-handle
'gnus-info
"Failed")
166 (mm-set-handle-multipart-parameter
167 mm-security-handle
'gnus-details
168 (concat "OpenSSL failed to verify message integrity:\n"
169 "-------------------------------------------\n"
171 ;; verify mail addresses in mail against those in certificate
172 (when (and (smime-pkcs7-region (point-min) (point-max))
173 (smime-pkcs7-certificates-region (point-min) (point-max)))
175 (insert-buffer-substring buf
)
176 (goto-char (point-min))
177 (while (re-search-forward "-----END CERTIFICATE-----" nil t
)
178 (when (smime-pkcs7-email-region (point-min) (point))
179 (setq addresses
(append (smime-buffer-as-string-region
180 (point-min) (point)) addresses
)))
181 (delete-region (point-min) (point)))
182 (setq addresses
(mapcar 'downcase addresses
))))
183 (if (not (member (downcase (or (mm-handle-multipart-from ctl
) "")) addresses
))
184 (mm-set-handle-multipart-parameter
185 mm-security-handle
'gnus-info
"Sender address forged")
187 (mm-set-handle-multipart-parameter
188 mm-security-handle
'gnus-info
"Ok (sender authenticated)")
189 (mm-set-handle-multipart-parameter
190 mm-security-handle
'gnus-info
"Ok (sender not trusted)")))
191 (mm-set-handle-multipart-parameter
192 mm-security-handle
'gnus-details
193 (concat "Sender claimed to be: " (mm-handle-multipart-from ctl
) "\n"
195 (concat "Addresses in certificate: "
196 (mapconcat 'identity addresses
", "))
197 "No addresses found in certificate. (Requires OpenSSL 0.9.6 or later.)")
200 "---------------\n" openssl-output
"\n"
201 "Certificate(s) inside S/MIME signature:\n"
202 "---------------------------------------\n"
203 (buffer-string) "\n")))))
206 (defun mml-smime-verify-test (handle ctl
)
207 smime-openssl-program
)
211 ;;; arch-tag: f1bf94d4-f2cd-4c6f-b059-ad69492817e2
212 ;;; mml-smime.el ends here