mml2015.el 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224
  1. ;;; mml2015.el --- MIME Security with Pretty Good Privacy (PGP)
  2. ;; Copyright (C) 2000-2012 Free Software Foundation, Inc.
  3. ;; Author: Shenghuo Zhu <zsh@cs.rochester.edu>
  4. ;; Keywords: PGP MIME MML
  5. ;; This file is part of GNU Emacs.
  6. ;; GNU Emacs is free software: you can redistribute it and/or modify
  7. ;; it under the terms of the GNU General Public License as published by
  8. ;; the Free Software Foundation, either version 3 of the License, or
  9. ;; (at your option) any later version.
  10. ;; GNU Emacs is distributed in the hope that it will be useful,
  11. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ;; GNU General Public License for more details.
  14. ;; You should have received a copy of the GNU General Public License
  15. ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
  16. ;;; Commentary:
  17. ;; RFC 2015 is updated by RFC 3156, this file should be compatible
  18. ;; with both.
  19. ;;; Code:
  20. (eval-and-compile
  21. ;; For Emacs <22.2 and XEmacs.
  22. (unless (fboundp 'declare-function) (defmacro declare-function (&rest r)))
  23. (if (locate-library "password-cache")
  24. (require 'password-cache)
  25. (require 'password)))
  26. (eval-when-compile (require 'cl))
  27. (require 'mm-decode)
  28. (require 'mm-util)
  29. (require 'mml)
  30. (require 'mml-sec)
  31. (defvar mc-pgp-always-sign)
  32. (declare-function epg-check-configuration "ext:epg-config"
  33. (config &optional minimum-version))
  34. (declare-function epg-configuration "ext:epg-config" ())
  35. (defvar mml2015-use (or
  36. (condition-case nil
  37. (progn
  38. (require 'epg-config)
  39. (epg-check-configuration (epg-configuration))
  40. 'epg)
  41. (error))
  42. (progn
  43. (let ((abs-file (locate-library "pgg")))
  44. ;; Don't load PGG if it is marked as obsolete
  45. ;; (Emacs 24).
  46. (when (and abs-file
  47. (not (string-match "/obsolete/[^/]*\\'"
  48. abs-file)))
  49. (ignore-errors (require 'pgg))
  50. (and (fboundp 'pgg-sign-region)
  51. 'pgg))))
  52. (progn (ignore-errors
  53. (load "mc-toplev"))
  54. (and (fboundp 'mc-encrypt-generic)
  55. (fboundp 'mc-sign-generic)
  56. (fboundp 'mc-cleanup-recipient-headers)
  57. 'mailcrypt)))
  58. "The package used for PGP/MIME.
  59. Valid packages include `epg', `pgg' and `mailcrypt'.")
  60. ;; Something is not RFC2015.
  61. (defvar mml2015-function-alist
  62. '((mailcrypt mml2015-mailcrypt-sign
  63. mml2015-mailcrypt-encrypt
  64. mml2015-mailcrypt-verify
  65. mml2015-mailcrypt-decrypt
  66. mml2015-mailcrypt-clear-verify
  67. mml2015-mailcrypt-clear-decrypt)
  68. (pgg mml2015-pgg-sign
  69. mml2015-pgg-encrypt
  70. mml2015-pgg-verify
  71. mml2015-pgg-decrypt
  72. mml2015-pgg-clear-verify
  73. mml2015-pgg-clear-decrypt)
  74. (epg mml2015-epg-sign
  75. mml2015-epg-encrypt
  76. mml2015-epg-verify
  77. mml2015-epg-decrypt
  78. mml2015-epg-clear-verify
  79. mml2015-epg-clear-decrypt))
  80. "Alist of PGP/MIME functions.")
  81. (defvar mml2015-result-buffer nil)
  82. (defcustom mml2015-unabbrev-trust-alist
  83. '(("TRUST_UNDEFINED" . nil)
  84. ("TRUST_NEVER" . nil)
  85. ("TRUST_MARGINAL" . t)
  86. ("TRUST_FULLY" . t)
  87. ("TRUST_ULTIMATE" . t))
  88. "Map GnuPG trust output values to a boolean saying if you trust the key."
  89. :version "22.1"
  90. :group 'mime-security
  91. :type '(repeat (cons (regexp :tag "GnuPG output regexp")
  92. (boolean :tag "Trust key"))))
  93. (defcustom mml2015-cache-passphrase mml-secure-cache-passphrase
  94. "If t, cache passphrase."
  95. :group 'mime-security
  96. :type 'boolean)
  97. (defcustom mml2015-passphrase-cache-expiry mml-secure-passphrase-cache-expiry
  98. "How many seconds the passphrase is cached.
  99. Whether the passphrase is cached at all is controlled by
  100. `mml2015-cache-passphrase'."
  101. :group 'mime-security
  102. :type 'integer)
  103. (defcustom mml2015-signers nil
  104. "A list of your own key ID(s) which will be used to sign a message.
  105. If set, it overrides the setting of `mml2015-sign-with-sender'."
  106. :group 'mime-security
  107. :type '(repeat (string :tag "Key ID")))
  108. (defcustom mml2015-sign-with-sender nil
  109. "If t, use message sender so find a key to sign with."
  110. :group 'mime-security
  111. :type 'boolean
  112. :version "24.1")
  113. (defcustom mml2015-encrypt-to-self nil
  114. "If t, add your own key ID to recipient list when encryption."
  115. :group 'mime-security
  116. :type 'boolean)
  117. (defcustom mml2015-always-trust t
  118. "If t, GnuPG skip key validation on encryption."
  119. :group 'mime-security
  120. :type 'boolean)
  121. ;; Extract plaintext from cleartext signature. IMO, this kind of task
  122. ;; should be done by GnuPG rather than Elisp, but older PGP backends
  123. ;; (such as Mailcrypt, and PGG) discard the output from GnuPG.
  124. (defun mml2015-extract-cleartext-signature ()
  125. ;; Daiki Ueno in
  126. ;; <54a15d860801080142l70b95d7dkac4bf51a86196011@mail.gmail.com>: ``I still
  127. ;; believe that the right way is to use the plaintext output from GnuPG as
  128. ;; it is, and mml2015-extract-cleartext-signature is just a kludge for
  129. ;; misdesigned libraries like PGG, which have no ability to do that. So, I
  130. ;; think it should not have descriptive documentation.''
  131. ;;
  132. ;; This function doesn't handle NotDashEscaped correctly. EasyPG handles it
  133. ;; correctly.
  134. ;; http://thread.gmane.org/gmane.emacs.gnus.general/66062/focus=66082
  135. ;; http://thread.gmane.org/gmane.emacs.gnus.general/65087/focus=65109
  136. (goto-char (point-min))
  137. (forward-line)
  138. ;; We need to be careful not to strip beyond the armor headers.
  139. ;; Previously, an attacker could replace the text inside our
  140. ;; markup with trailing garbage by injecting whitespace into the
  141. ;; message.
  142. (while (looking-at "Hash:") ; The only header allowed in cleartext
  143. (forward-line)) ; signatures according to RFC2440.
  144. (when (looking-at "[\t ]*$")
  145. (forward-line))
  146. (delete-region (point-min) (point))
  147. (if (re-search-forward "^-----BEGIN PGP SIGNATURE-----" nil t)
  148. (delete-region (match-beginning 0) (point-max)))
  149. (goto-char (point-min))
  150. (while (re-search-forward "^- " nil t)
  151. (replace-match "" t t)
  152. (forward-line 1)))
  153. ;;; mailcrypt wrapper
  154. (autoload 'mailcrypt-decrypt "mailcrypt")
  155. (autoload 'mailcrypt-verify "mailcrypt")
  156. (autoload 'mc-pgp-always-sign "mailcrypt")
  157. (autoload 'mc-encrypt-generic "mc-toplev")
  158. (autoload 'mc-cleanup-recipient-headers "mc-toplev")
  159. (autoload 'mc-sign-generic "mc-toplev")
  160. (defvar mml2015-decrypt-function 'mailcrypt-decrypt)
  161. (defvar mml2015-verify-function 'mailcrypt-verify)
  162. (defun mml2015-format-error (err)
  163. (if (stringp (cadr err))
  164. (cadr err)
  165. (format "%S" (cdr err))))
  166. (defun mml2015-mailcrypt-decrypt (handle ctl)
  167. (catch 'error
  168. (let (child handles result)
  169. (unless (setq child (mm-find-part-by-type
  170. (cdr handle)
  171. "application/octet-stream" nil t))
  172. (mm-set-handle-multipart-parameter
  173. mm-security-handle 'gnus-info "Corrupted")
  174. (throw 'error handle))
  175. (with-temp-buffer
  176. (mm-insert-part child)
  177. (setq result
  178. (condition-case err
  179. (funcall mml2015-decrypt-function)
  180. (error
  181. (mm-set-handle-multipart-parameter
  182. mm-security-handle 'gnus-details (mml2015-format-error err))
  183. nil)
  184. (quit
  185. (mm-set-handle-multipart-parameter
  186. mm-security-handle 'gnus-details "Quit.")
  187. nil)))
  188. (unless (car result)
  189. (mm-set-handle-multipart-parameter
  190. mm-security-handle 'gnus-info "Failed")
  191. (throw 'error handle))
  192. (setq handles (mm-dissect-buffer t)))
  193. (mm-destroy-parts handle)
  194. (mm-set-handle-multipart-parameter
  195. mm-security-handle 'gnus-info
  196. (concat "OK"
  197. (let ((sig (with-current-buffer mml2015-result-buffer
  198. (mml2015-gpg-extract-signature-details))))
  199. (concat ", Signer: " sig))))
  200. (if (listp (car handles))
  201. handles
  202. (list handles)))))
  203. (defun mml2015-gpg-pretty-print-fpr (fingerprint)
  204. (let* ((result "")
  205. (fpr-length (string-width fingerprint))
  206. (n-slice 0)
  207. slice)
  208. (setq fingerprint (string-to-list fingerprint))
  209. (while fingerprint
  210. (setq fpr-length (- fpr-length 4))
  211. (setq slice (butlast fingerprint fpr-length))
  212. (setq fingerprint (nthcdr 4 fingerprint))
  213. (setq n-slice (1+ n-slice))
  214. (setq result
  215. (concat
  216. result
  217. (case n-slice
  218. (1 slice)
  219. (otherwise (concat " " slice))))))
  220. result))
  221. (defun mml2015-gpg-extract-signature-details ()
  222. (goto-char (point-min))
  223. (let* ((expired (re-search-forward
  224. "^\\[GNUPG:\\] SIGEXPIRED$"
  225. nil t))
  226. (signer (and (re-search-forward
  227. "^\\[GNUPG:\\] GOODSIG \\([0-9A-Za-z]*\\) \\(.*\\)$"
  228. nil t)
  229. (cons (match-string 1) (match-string 2))))
  230. (fprint (and (re-search-forward
  231. "^\\[GNUPG:\\] VALIDSIG \\([0-9a-zA-Z]*\\) "
  232. nil t)
  233. (match-string 1)))
  234. (trust (and (re-search-forward
  235. "^\\[GNUPG:\\] \\(TRUST_.*\\)$"
  236. nil t)
  237. (match-string 1)))
  238. (trust-good-enough-p
  239. (cdr (assoc trust mml2015-unabbrev-trust-alist))))
  240. (cond ((and signer fprint)
  241. (concat (cdr signer)
  242. (unless trust-good-enough-p
  243. (concat "\nUntrusted, Fingerprint: "
  244. (mml2015-gpg-pretty-print-fpr fprint)))
  245. (when expired
  246. (format "\nWARNING: Signature from expired key (%s)"
  247. (car signer)))))
  248. ((re-search-forward
  249. "^\\(gpg: \\)?Good signature from \"\\(.*\\)\"$" nil t)
  250. (match-string 2))
  251. (t
  252. "From unknown user"))))
  253. (defun mml2015-mailcrypt-clear-decrypt ()
  254. (let (result)
  255. (setq result
  256. (condition-case err
  257. (funcall mml2015-decrypt-function)
  258. (error
  259. (mm-set-handle-multipart-parameter
  260. mm-security-handle 'gnus-details (mml2015-format-error err))
  261. nil)
  262. (quit
  263. (mm-set-handle-multipart-parameter
  264. mm-security-handle 'gnus-details "Quit.")
  265. nil)))
  266. (if (car result)
  267. (mm-set-handle-multipart-parameter
  268. mm-security-handle 'gnus-info "OK")
  269. (mm-set-handle-multipart-parameter
  270. mm-security-handle 'gnus-info "Failed"))))
  271. (defun mml2015-fix-micalg (alg)
  272. (and alg
  273. ;; Mutt/1.2.5i has seen sending micalg=php-sha1
  274. (upcase (if (string-match "^p[gh]p-" alg)
  275. (substring alg (match-end 0))
  276. alg))))
  277. (defun mml2015-mailcrypt-verify (handle ctl)
  278. (catch 'error
  279. (let (part)
  280. (unless (setq part (mm-find-raw-part-by-type
  281. ctl (or (mm-handle-multipart-ctl-parameter
  282. ctl 'protocol)
  283. "application/pgp-signature")
  284. t))
  285. (mm-set-handle-multipart-parameter
  286. mm-security-handle 'gnus-info "Corrupted")
  287. (throw 'error handle))
  288. (with-temp-buffer
  289. (insert "-----BEGIN PGP SIGNED MESSAGE-----\n")
  290. (insert (format "Hash: %s\n\n"
  291. (or (mml2015-fix-micalg
  292. (mm-handle-multipart-ctl-parameter
  293. ctl 'micalg))
  294. "SHA1")))
  295. (save-restriction
  296. (narrow-to-region (point) (point))
  297. (insert part "\n")
  298. (goto-char (point-min))
  299. (while (not (eobp))
  300. (if (looking-at "^-")
  301. (insert "- "))
  302. (forward-line)))
  303. (unless (setq part (mm-find-part-by-type
  304. (cdr handle) "application/pgp-signature" nil t))
  305. (mm-set-handle-multipart-parameter
  306. mm-security-handle 'gnus-info "Corrupted")
  307. (throw 'error handle))
  308. (save-restriction
  309. (narrow-to-region (point) (point))
  310. (mm-insert-part part)
  311. (goto-char (point-min))
  312. (if (re-search-forward "^-----BEGIN PGP [^-]+-----\r?$" nil t)
  313. (replace-match "-----BEGIN PGP SIGNATURE-----" t t))
  314. (if (re-search-forward "^-----END PGP [^-]+-----\r?$" nil t)
  315. (replace-match "-----END PGP SIGNATURE-----" t t)))
  316. (let ((mc-gpg-debug-buffer (get-buffer-create " *gnus gpg debug*")))
  317. (unless (condition-case err
  318. (prog1
  319. (funcall mml2015-verify-function)
  320. (if (get-buffer " *mailcrypt stderr temp")
  321. (mm-set-handle-multipart-parameter
  322. mm-security-handle 'gnus-details
  323. (with-current-buffer " *mailcrypt stderr temp"
  324. (buffer-string))))
  325. (if (get-buffer " *mailcrypt stdout temp")
  326. (kill-buffer " *mailcrypt stdout temp"))
  327. (if (get-buffer " *mailcrypt stderr temp")
  328. (kill-buffer " *mailcrypt stderr temp"))
  329. (if (get-buffer " *mailcrypt status temp")
  330. (kill-buffer " *mailcrypt status temp"))
  331. (if (get-buffer mc-gpg-debug-buffer)
  332. (kill-buffer mc-gpg-debug-buffer)))
  333. (error
  334. (mm-set-handle-multipart-parameter
  335. mm-security-handle 'gnus-details (mml2015-format-error err))
  336. nil)
  337. (quit
  338. (mm-set-handle-multipart-parameter
  339. mm-security-handle 'gnus-details "Quit.")
  340. nil))
  341. (mm-set-handle-multipart-parameter
  342. mm-security-handle 'gnus-info "Failed")
  343. (throw 'error handle))))
  344. (mm-set-handle-multipart-parameter
  345. mm-security-handle 'gnus-info "OK")
  346. handle)))
  347. (defun mml2015-mailcrypt-clear-verify ()
  348. (let ((mc-gpg-debug-buffer (get-buffer-create " *gnus gpg debug*")))
  349. (if (condition-case err
  350. (prog1
  351. (funcall mml2015-verify-function)
  352. (if (get-buffer " *mailcrypt stderr temp")
  353. (mm-set-handle-multipart-parameter
  354. mm-security-handle 'gnus-details
  355. (with-current-buffer " *mailcrypt stderr temp"
  356. (buffer-string))))
  357. (if (get-buffer " *mailcrypt stdout temp")
  358. (kill-buffer " *mailcrypt stdout temp"))
  359. (if (get-buffer " *mailcrypt stderr temp")
  360. (kill-buffer " *mailcrypt stderr temp"))
  361. (if (get-buffer " *mailcrypt status temp")
  362. (kill-buffer " *mailcrypt status temp"))
  363. (if (get-buffer mc-gpg-debug-buffer)
  364. (kill-buffer mc-gpg-debug-buffer)))
  365. (error
  366. (mm-set-handle-multipart-parameter
  367. mm-security-handle 'gnus-details (mml2015-format-error err))
  368. nil)
  369. (quit
  370. (mm-set-handle-multipart-parameter
  371. mm-security-handle 'gnus-details "Quit.")
  372. nil))
  373. (mm-set-handle-multipart-parameter
  374. mm-security-handle 'gnus-info "OK")
  375. (mm-set-handle-multipart-parameter
  376. mm-security-handle 'gnus-info "Failed")))
  377. (mml2015-extract-cleartext-signature))
  378. (defun mml2015-mailcrypt-sign (cont)
  379. (mc-sign-generic (message-options-get 'message-sender)
  380. nil nil nil nil)
  381. (let ((boundary (mml-compute-boundary cont))
  382. hash point)
  383. (goto-char (point-min))
  384. (unless (re-search-forward "^-----BEGIN PGP SIGNED MESSAGE-----\r?$" nil t)
  385. (error "Cannot find signed begin line"))
  386. (goto-char (match-beginning 0))
  387. (forward-line 1)
  388. (unless (looking-at "Hash:[ \t]*\\([a-zA-Z0-9]+\\)")
  389. (error "Cannot not find PGP hash"))
  390. (setq hash (match-string 1))
  391. (unless (re-search-forward "^$" nil t)
  392. (error "Cannot not find PGP message"))
  393. (forward-line 1)
  394. (delete-region (point-min) (point))
  395. (insert (format "Content-Type: multipart/signed; boundary=\"%s\";\n"
  396. boundary))
  397. (insert (format "\tmicalg=pgp-%s; protocol=\"application/pgp-signature\"\n"
  398. (downcase hash)))
  399. (insert (format "\n--%s\n" boundary))
  400. (setq point (point))
  401. (goto-char (point-max))
  402. (unless (re-search-backward "^-----END PGP SIGNATURE-----\r?$" nil t)
  403. (error "Cannot find signature part"))
  404. (replace-match "-----END PGP MESSAGE-----" t t)
  405. (goto-char (match-beginning 0))
  406. (unless (re-search-backward "^-----BEGIN PGP SIGNATURE-----\r?$"
  407. nil t)
  408. (error "Cannot find signature part"))
  409. (replace-match "-----BEGIN PGP MESSAGE-----" t t)
  410. (goto-char (match-beginning 0))
  411. (save-restriction
  412. (narrow-to-region point (point))
  413. (goto-char point)
  414. (while (re-search-forward "^- -" nil t)
  415. (replace-match "-" t t))
  416. (goto-char (point-max)))
  417. (insert (format "--%s\n" boundary))
  418. (insert "Content-Type: application/pgp-signature\n\n")
  419. (goto-char (point-max))
  420. (insert (format "--%s--\n" boundary))
  421. (goto-char (point-max))))
  422. ;; We require mm-decode, which requires mm-bodies, which autoloads
  423. ;; message-options-get (!).
  424. (declare-function message-options-set "message" (symbol value))
  425. (defun mml2015-mailcrypt-encrypt (cont &optional sign)
  426. (let ((mc-pgp-always-sign
  427. (or mc-pgp-always-sign
  428. sign
  429. (eq t (or (message-options-get 'message-sign-encrypt)
  430. (message-options-set
  431. 'message-sign-encrypt
  432. (or (y-or-n-p "Sign the message? ")
  433. 'not))))
  434. 'never)))
  435. (mm-with-unibyte-current-buffer
  436. (mc-encrypt-generic
  437. (or (message-options-get 'message-recipients)
  438. (message-options-set 'message-recipients
  439. (mc-cleanup-recipient-headers
  440. (read-string "Recipients: "))))
  441. nil nil nil
  442. (message-options-get 'message-sender))))
  443. (goto-char (point-min))
  444. (unless (looking-at "-----BEGIN PGP MESSAGE-----")
  445. (error "Fail to encrypt the message"))
  446. (let ((boundary (mml-compute-boundary cont)))
  447. (insert (format "Content-Type: multipart/encrypted; boundary=\"%s\";\n"
  448. boundary))
  449. (insert "\tprotocol=\"application/pgp-encrypted\"\n\n")
  450. (insert (format "--%s\n" boundary))
  451. (insert "Content-Type: application/pgp-encrypted\n\n")
  452. (insert "Version: 1\n\n")
  453. (insert (format "--%s\n" boundary))
  454. (insert "Content-Type: application/octet-stream\n\n")
  455. (goto-char (point-max))
  456. (insert (format "--%s--\n" boundary))
  457. (goto-char (point-max))))
  458. ;;; pgg wrapper
  459. (defvar pgg-default-user-id)
  460. (defvar pgg-errors-buffer)
  461. (defvar pgg-output-buffer)
  462. (autoload 'pgg-decrypt-region "pgg")
  463. (autoload 'pgg-verify-region "pgg")
  464. (autoload 'pgg-sign-region "pgg")
  465. (autoload 'pgg-encrypt-region "pgg")
  466. (autoload 'pgg-parse-armor "pgg-parse")
  467. (defun mml2015-pgg-decrypt (handle ctl)
  468. (catch 'error
  469. (let ((pgg-errors-buffer mml2015-result-buffer)
  470. child handles result decrypt-status)
  471. (unless (setq child (mm-find-part-by-type
  472. (cdr handle)
  473. "application/octet-stream" nil t))
  474. (mm-set-handle-multipart-parameter
  475. mm-security-handle 'gnus-info "Corrupted")
  476. (throw 'error handle))
  477. (with-temp-buffer
  478. (mm-insert-part child)
  479. (if (condition-case err
  480. (prog1
  481. (pgg-decrypt-region (point-min) (point-max))
  482. (setq decrypt-status
  483. (with-current-buffer mml2015-result-buffer
  484. (buffer-string)))
  485. (mm-set-handle-multipart-parameter
  486. mm-security-handle 'gnus-details
  487. decrypt-status))
  488. (error
  489. (mm-set-handle-multipart-parameter
  490. mm-security-handle 'gnus-details (mml2015-format-error err))
  491. nil)
  492. (quit
  493. (mm-set-handle-multipart-parameter
  494. mm-security-handle 'gnus-details "Quit.")
  495. nil))
  496. (with-current-buffer pgg-output-buffer
  497. (goto-char (point-min))
  498. (while (search-forward "\r\n" nil t)
  499. (replace-match "\n" t t))
  500. (setq handles (mm-dissect-buffer t))
  501. (mm-destroy-parts handle)
  502. (mm-set-handle-multipart-parameter
  503. mm-security-handle 'gnus-info "OK")
  504. (mm-set-handle-multipart-parameter
  505. mm-security-handle 'gnus-details
  506. (concat decrypt-status
  507. (when (stringp (car handles))
  508. "\n" (mm-handle-multipart-ctl-parameter
  509. handles 'gnus-details))))
  510. (if (listp (car handles))
  511. handles
  512. (list handles)))
  513. (mm-set-handle-multipart-parameter
  514. mm-security-handle 'gnus-info "Failed")
  515. (throw 'error handle))))))
  516. (defun mml2015-pgg-clear-decrypt ()
  517. (let ((pgg-errors-buffer mml2015-result-buffer))
  518. (if (prog1
  519. (pgg-decrypt-region (point-min) (point-max))
  520. (mm-set-handle-multipart-parameter
  521. mm-security-handle 'gnus-details
  522. (with-current-buffer mml2015-result-buffer
  523. (buffer-string))))
  524. (progn
  525. (erase-buffer)
  526. ;; Treat data which pgg returns as a unibyte string.
  527. (mm-disable-multibyte)
  528. (insert-buffer-substring pgg-output-buffer)
  529. (goto-char (point-min))
  530. (while (search-forward "\r\n" nil t)
  531. (replace-match "\n" t t))
  532. (mm-set-handle-multipart-parameter
  533. mm-security-handle 'gnus-info "OK"))
  534. (mm-set-handle-multipart-parameter
  535. mm-security-handle 'gnus-info "Failed"))))
  536. (defun mml2015-pgg-verify (handle ctl)
  537. (let ((pgg-errors-buffer mml2015-result-buffer)
  538. signature-file part signature)
  539. (if (or (null (setq part (mm-find-raw-part-by-type
  540. ctl (or (mm-handle-multipart-ctl-parameter
  541. ctl 'protocol)
  542. "application/pgp-signature")
  543. t)))
  544. (null (setq signature (mm-find-part-by-type
  545. (cdr handle) "application/pgp-signature" nil t))))
  546. (progn
  547. (mm-set-handle-multipart-parameter
  548. mm-security-handle 'gnus-info "Corrupted")
  549. handle)
  550. (with-temp-buffer
  551. (insert part)
  552. ;; Convert <LF> to <CR><LF> in signed text. If --textmode is
  553. ;; specified when signing, the conversion is not necessary.
  554. (goto-char (point-min))
  555. (end-of-line)
  556. (while (not (eobp))
  557. (unless (eq (char-before) ?\r)
  558. (insert "\r"))
  559. (forward-line)
  560. (end-of-line))
  561. (with-temp-file (setq signature-file (mm-make-temp-file "pgg"))
  562. (mm-insert-part signature))
  563. (if (condition-case err
  564. (prog1
  565. (pgg-verify-region (point-min) (point-max)
  566. signature-file t)
  567. (goto-char (point-min))
  568. (while (search-forward "\r\n" nil t)
  569. (replace-match "\n" t t))
  570. (mm-set-handle-multipart-parameter
  571. mm-security-handle 'gnus-details
  572. (concat (with-current-buffer pgg-output-buffer
  573. (buffer-string))
  574. (with-current-buffer pgg-errors-buffer
  575. (buffer-string)))))
  576. (error
  577. (mm-set-handle-multipart-parameter
  578. mm-security-handle 'gnus-details (mml2015-format-error err))
  579. nil)
  580. (quit
  581. (mm-set-handle-multipart-parameter
  582. mm-security-handle 'gnus-details "Quit.")
  583. nil))
  584. (progn
  585. (delete-file signature-file)
  586. (mm-set-handle-multipart-parameter
  587. mm-security-handle 'gnus-info
  588. (with-current-buffer pgg-errors-buffer
  589. (mml2015-gpg-extract-signature-details))))
  590. (delete-file signature-file)
  591. (mm-set-handle-multipart-parameter
  592. mm-security-handle 'gnus-info "Failed")))))
  593. handle)
  594. (defun mml2015-pgg-clear-verify ()
  595. (let ((pgg-errors-buffer mml2015-result-buffer)
  596. (text (buffer-string))
  597. (coding-system buffer-file-coding-system))
  598. (if (condition-case err
  599. (prog1
  600. (mm-with-unibyte-buffer
  601. (insert (mm-encode-coding-string text coding-system))
  602. (pgg-verify-region (point-min) (point-max) nil t))
  603. (goto-char (point-min))
  604. (while (search-forward "\r\n" nil t)
  605. (replace-match "\n" t t))
  606. (mm-set-handle-multipart-parameter
  607. mm-security-handle 'gnus-details
  608. (concat (with-current-buffer pgg-output-buffer
  609. (buffer-string))
  610. (with-current-buffer pgg-errors-buffer
  611. (buffer-string)))))
  612. (error
  613. (mm-set-handle-multipart-parameter
  614. mm-security-handle 'gnus-details (mml2015-format-error err))
  615. nil)
  616. (quit
  617. (mm-set-handle-multipart-parameter
  618. mm-security-handle 'gnus-details "Quit.")
  619. nil))
  620. (mm-set-handle-multipart-parameter
  621. mm-security-handle 'gnus-info
  622. (with-current-buffer pgg-errors-buffer
  623. (mml2015-gpg-extract-signature-details)))
  624. (mm-set-handle-multipart-parameter
  625. mm-security-handle 'gnus-info "Failed")))
  626. (mml2015-extract-cleartext-signature))
  627. (defun mml2015-pgg-sign (cont)
  628. (let ((pgg-errors-buffer mml2015-result-buffer)
  629. (boundary (mml-compute-boundary cont))
  630. (pgg-default-user-id (or (message-options-get 'mml-sender)
  631. pgg-default-user-id))
  632. (pgg-text-mode t)
  633. entry)
  634. (unless (pgg-sign-region (point-min) (point-max))
  635. (pop-to-buffer mml2015-result-buffer)
  636. (error "Sign error"))
  637. (goto-char (point-min))
  638. (insert (format "Content-Type: multipart/signed; boundary=\"%s\";\n"
  639. boundary))
  640. (if (setq entry (assq 2 (pgg-parse-armor
  641. (with-current-buffer pgg-output-buffer
  642. (buffer-string)))))
  643. (setq entry (assq 'hash-algorithm (cdr entry))))
  644. (insert (format "\tmicalg=%s; "
  645. (if (cdr entry)
  646. (downcase (format "pgp-%s" (cdr entry)))
  647. "pgp-sha1")))
  648. (insert "protocol=\"application/pgp-signature\"\n")
  649. (insert (format "\n--%s\n" boundary))
  650. (goto-char (point-max))
  651. (insert (format "\n--%s\n" boundary))
  652. (insert "Content-Type: application/pgp-signature\n\n")
  653. (insert-buffer-substring pgg-output-buffer)
  654. (goto-char (point-max))
  655. (insert (format "--%s--\n" boundary))
  656. (goto-char (point-max))))
  657. (defun mml2015-pgg-encrypt (cont &optional sign)
  658. (let ((pgg-errors-buffer mml2015-result-buffer)
  659. (pgg-text-mode t)
  660. (boundary (mml-compute-boundary cont)))
  661. (unless (pgg-encrypt-region (point-min) (point-max)
  662. (split-string
  663. (or
  664. (message-options-get 'message-recipients)
  665. (message-options-set 'message-recipients
  666. (read-string "Recipients: ")))
  667. "[ \f\t\n\r\v,]+")
  668. sign)
  669. (pop-to-buffer mml2015-result-buffer)
  670. (error "Encrypt error"))
  671. (delete-region (point-min) (point-max))
  672. (goto-char (point-min))
  673. (insert (format "Content-Type: multipart/encrypted; boundary=\"%s\";\n"
  674. boundary))
  675. (insert "\tprotocol=\"application/pgp-encrypted\"\n\n")
  676. (insert (format "--%s\n" boundary))
  677. (insert "Content-Type: application/pgp-encrypted\n\n")
  678. (insert "Version: 1\n\n")
  679. (insert (format "--%s\n" boundary))
  680. (insert "Content-Type: application/octet-stream\n\n")
  681. (insert-buffer-substring pgg-output-buffer)
  682. (goto-char (point-max))
  683. (insert (format "--%s--\n" boundary))
  684. (goto-char (point-max))))
  685. ;;; epg wrapper
  686. (defvar epg-user-id-alist)
  687. (defvar epg-digest-algorithm-alist)
  688. (defvar inhibit-redisplay)
  689. (autoload 'epg-make-context "epg")
  690. (autoload 'epg-context-set-armor "epg")
  691. (autoload 'epg-context-set-textmode "epg")
  692. (autoload 'epg-context-set-signers "epg")
  693. (autoload 'epg-context-result-for "epg")
  694. (autoload 'epg-new-signature-digest-algorithm "epg")
  695. (autoload 'epg-verify-result-to-string "epg")
  696. (autoload 'epg-list-keys "epg")
  697. (autoload 'epg-decrypt-string "epg")
  698. (autoload 'epg-verify-string "epg")
  699. (autoload 'epg-sign-string "epg")
  700. (autoload 'epg-encrypt-string "epg")
  701. (autoload 'epg-passphrase-callback-function "epg")
  702. (autoload 'epg-context-set-passphrase-callback "epg")
  703. (autoload 'epg-key-sub-key-list "epg")
  704. (autoload 'epg-sub-key-capability "epg")
  705. (autoload 'epg-sub-key-validity "epg")
  706. (autoload 'epg-sub-key-fingerprint "epg")
  707. (autoload 'epg-configuration "epg-config")
  708. (autoload 'epg-expand-group "epg-config")
  709. (autoload 'epa-select-keys "epa")
  710. (defvar mml2015-epg-secret-key-id-list nil)
  711. (defun mml2015-epg-passphrase-callback (context key-id ignore)
  712. (if (eq key-id 'SYM)
  713. (epg-passphrase-callback-function context key-id nil)
  714. (let* ((password-cache-key-id
  715. (if (eq key-id 'PIN)
  716. "PIN"
  717. key-id))
  718. entry
  719. (passphrase
  720. (password-read
  721. (if (eq key-id 'PIN)
  722. "Passphrase for PIN: "
  723. (if (setq entry (assoc key-id epg-user-id-alist))
  724. (format "Passphrase for %s %s: " key-id (cdr entry))
  725. (format "Passphrase for %s: " key-id)))
  726. password-cache-key-id)))
  727. (when passphrase
  728. (let ((password-cache-expiry mml2015-passphrase-cache-expiry))
  729. (password-cache-add password-cache-key-id passphrase))
  730. (setq mml2015-epg-secret-key-id-list
  731. (cons password-cache-key-id mml2015-epg-secret-key-id-list))
  732. (copy-sequence passphrase)))))
  733. (defun mml2015-epg-find-usable-key (keys usage)
  734. (catch 'found
  735. (while keys
  736. (let ((pointer (epg-key-sub-key-list (car keys))))
  737. ;; The primary key will be marked as disabled, when the entire
  738. ;; key is disabled (see 12 Field, Format of colon listings, in
  739. ;; gnupg/doc/DETAILS)
  740. (unless (memq 'disabled (epg-sub-key-capability (car pointer)))
  741. (while pointer
  742. (if (and (memq usage (epg-sub-key-capability (car pointer)))
  743. (not (memq (epg-sub-key-validity (car pointer))
  744. '(revoked expired))))
  745. (throw 'found (car keys)))
  746. (setq pointer (cdr pointer)))))
  747. (setq keys (cdr keys)))))
  748. ;; XXX: since gpg --list-secret-keys does not return validity of each
  749. ;; key, `mml2015-epg-find-usable-key' defined above is not enough for
  750. ;; secret keys. The function `mml2015-epg-find-usable-secret-key'
  751. ;; below looks at appropriate public keys to check usability.
  752. (defun mml2015-epg-find-usable-secret-key (context name usage)
  753. (let ((secret-keys (epg-list-keys context name t))
  754. secret-key)
  755. (while (and (not secret-key) secret-keys)
  756. (if (mml2015-epg-find-usable-key
  757. (epg-list-keys context (epg-sub-key-fingerprint
  758. (car (epg-key-sub-key-list
  759. (car secret-keys)))))
  760. usage)
  761. (setq secret-key (car secret-keys)
  762. secret-keys nil)
  763. (setq secret-keys (cdr secret-keys))))
  764. secret-key))
  765. (defun mml2015-epg-decrypt (handle ctl)
  766. (catch 'error
  767. (let ((inhibit-redisplay t)
  768. context plain child handles result decrypt-status)
  769. (unless (setq child (mm-find-part-by-type
  770. (cdr handle)
  771. "application/octet-stream" nil t))
  772. (mm-set-handle-multipart-parameter
  773. mm-security-handle 'gnus-info "Corrupted")
  774. (throw 'error handle))
  775. (setq context (epg-make-context))
  776. (if mml2015-cache-passphrase
  777. (epg-context-set-passphrase-callback
  778. context
  779. #'mml2015-epg-passphrase-callback))
  780. (condition-case error
  781. (setq plain (epg-decrypt-string context (mm-get-part child))
  782. mml2015-epg-secret-key-id-list nil)
  783. (error
  784. (while mml2015-epg-secret-key-id-list
  785. (password-cache-remove (car mml2015-epg-secret-key-id-list))
  786. (setq mml2015-epg-secret-key-id-list
  787. (cdr mml2015-epg-secret-key-id-list)))
  788. (mm-set-handle-multipart-parameter
  789. mm-security-handle 'gnus-info "Failed")
  790. (if (eq (car error) 'quit)
  791. (mm-set-handle-multipart-parameter
  792. mm-security-handle 'gnus-details "Quit.")
  793. (mm-set-handle-multipart-parameter
  794. mm-security-handle 'gnus-details (mml2015-format-error error)))
  795. (throw 'error handle)))
  796. (with-temp-buffer
  797. (insert plain)
  798. (goto-char (point-min))
  799. (while (search-forward "\r\n" nil t)
  800. (replace-match "\n" t t))
  801. (setq handles (mm-dissect-buffer t))
  802. (mm-destroy-parts handle)
  803. (if (epg-context-result-for context 'verify)
  804. (mm-set-handle-multipart-parameter
  805. mm-security-handle 'gnus-info
  806. (concat "OK\n"
  807. (epg-verify-result-to-string
  808. (epg-context-result-for context 'verify))))
  809. (mm-set-handle-multipart-parameter
  810. mm-security-handle 'gnus-info "OK"))
  811. (if (stringp (car handles))
  812. (mm-set-handle-multipart-parameter
  813. mm-security-handle 'gnus-details
  814. (mm-handle-multipart-ctl-parameter handles 'gnus-details))))
  815. (if (listp (car handles))
  816. handles
  817. (list handles)))))
  818. (defun mml2015-epg-clear-decrypt ()
  819. (let ((inhibit-redisplay t)
  820. (context (epg-make-context))
  821. plain)
  822. (if mml2015-cache-passphrase
  823. (epg-context-set-passphrase-callback
  824. context
  825. #'mml2015-epg-passphrase-callback))
  826. (condition-case error
  827. (setq plain (epg-decrypt-string context (buffer-string))
  828. mml2015-epg-secret-key-id-list nil)
  829. (error
  830. (while mml2015-epg-secret-key-id-list
  831. (password-cache-remove (car mml2015-epg-secret-key-id-list))
  832. (setq mml2015-epg-secret-key-id-list
  833. (cdr mml2015-epg-secret-key-id-list)))
  834. (mm-set-handle-multipart-parameter
  835. mm-security-handle 'gnus-info "Failed")
  836. (if (eq (car error) 'quit)
  837. (mm-set-handle-multipart-parameter
  838. mm-security-handle 'gnus-details "Quit.")
  839. (mm-set-handle-multipart-parameter
  840. mm-security-handle 'gnus-details (mml2015-format-error error)))))
  841. (when plain
  842. (erase-buffer)
  843. ;; Treat data which epg returns as a unibyte string.
  844. (mm-disable-multibyte)
  845. (insert plain)
  846. (goto-char (point-min))
  847. (while (search-forward "\r\n" nil t)
  848. (replace-match "\n" t t))
  849. (mm-set-handle-multipart-parameter
  850. mm-security-handle 'gnus-info "OK")
  851. (if (epg-context-result-for context 'verify)
  852. (mm-set-handle-multipart-parameter
  853. mm-security-handle 'gnus-details
  854. (epg-verify-result-to-string
  855. (epg-context-result-for context 'verify)))))))
  856. (defun mml2015-epg-verify (handle ctl)
  857. (catch 'error
  858. (let ((inhibit-redisplay t)
  859. context plain signature-file part signature)
  860. (when (or (null (setq part (mm-find-raw-part-by-type
  861. ctl (or (mm-handle-multipart-ctl-parameter
  862. ctl 'protocol)
  863. "application/pgp-signature")
  864. t)))
  865. (null (setq signature (mm-find-part-by-type
  866. (cdr handle) "application/pgp-signature"
  867. nil t))))
  868. (mm-set-handle-multipart-parameter
  869. mm-security-handle 'gnus-info "Corrupted")
  870. (throw 'error handle))
  871. (setq part (mm-replace-in-string part "\n" "\r\n")
  872. signature (mm-get-part signature)
  873. context (epg-make-context))
  874. (condition-case error
  875. (setq plain (epg-verify-string context signature part))
  876. (error
  877. (mm-set-handle-multipart-parameter
  878. mm-security-handle 'gnus-info "Failed")
  879. (if (eq (car error) 'quit)
  880. (mm-set-handle-multipart-parameter
  881. mm-security-handle 'gnus-details "Quit.")
  882. (mm-set-handle-multipart-parameter
  883. mm-security-handle 'gnus-details (mml2015-format-error error)))
  884. (throw 'error handle)))
  885. (mm-set-handle-multipart-parameter
  886. mm-security-handle 'gnus-info
  887. (epg-verify-result-to-string (epg-context-result-for context 'verify)))
  888. handle)))
  889. (defun mml2015-epg-clear-verify ()
  890. (let ((inhibit-redisplay t)
  891. (context (epg-make-context))
  892. (signature (mm-encode-coding-string (buffer-string)
  893. coding-system-for-write))
  894. plain)
  895. (condition-case error
  896. (setq plain (epg-verify-string context signature))
  897. (error
  898. (mm-set-handle-multipart-parameter
  899. mm-security-handle 'gnus-info "Failed")
  900. (if (eq (car error) 'quit)
  901. (mm-set-handle-multipart-parameter
  902. mm-security-handle 'gnus-details "Quit.")
  903. (mm-set-handle-multipart-parameter
  904. mm-security-handle 'gnus-details (mml2015-format-error error)))))
  905. (if plain
  906. (progn
  907. (mm-set-handle-multipart-parameter
  908. mm-security-handle 'gnus-info
  909. (epg-verify-result-to-string
  910. (epg-context-result-for context 'verify)))
  911. (delete-region (point-min) (point-max))
  912. (insert (mm-decode-coding-string plain coding-system-for-read)))
  913. (mml2015-extract-cleartext-signature))))
  914. (defun mml2015-epg-sign (cont)
  915. (let* ((inhibit-redisplay t)
  916. (context (epg-make-context))
  917. (boundary (mml-compute-boundary cont))
  918. (sender (message-options-get 'message-sender))
  919. (signer-names (or mml2015-signers
  920. (if (and mml2015-sign-with-sender sender)
  921. (list (concat "<" sender ">")))))
  922. signer-key
  923. (signers
  924. (or (message-options-get 'mml2015-epg-signers)
  925. (message-options-set
  926. 'mml2015-epg-signers
  927. (if (eq mm-sign-option 'guided)
  928. (epa-select-keys context "\
  929. Select keys for signing.
  930. If no one is selected, default secret key is used. "
  931. signer-names
  932. t)
  933. (if (or sender mml2015-signers)
  934. (delq nil
  935. (mapcar
  936. (lambda (signer)
  937. (setq signer-key
  938. (mml2015-epg-find-usable-secret-key
  939. context signer 'sign))
  940. (unless (or signer-key
  941. (y-or-n-p
  942. (format
  943. "No secret key for %s; skip it? "
  944. signer)))
  945. (error "No secret key for %s" signer))
  946. signer-key)
  947. signer-names)))))))
  948. signature micalg)
  949. (epg-context-set-armor context t)
  950. (epg-context-set-textmode context t)
  951. (epg-context-set-signers context signers)
  952. (if mml2015-cache-passphrase
  953. (epg-context-set-passphrase-callback
  954. context
  955. #'mml2015-epg-passphrase-callback))
  956. (condition-case error
  957. (setq signature (epg-sign-string context (buffer-string) t)
  958. mml2015-epg-secret-key-id-list nil)
  959. (error
  960. (while mml2015-epg-secret-key-id-list
  961. (password-cache-remove (car mml2015-epg-secret-key-id-list))
  962. (setq mml2015-epg-secret-key-id-list
  963. (cdr mml2015-epg-secret-key-id-list)))
  964. (signal (car error) (cdr error))))
  965. (if (epg-context-result-for context 'sign)
  966. (setq micalg (epg-new-signature-digest-algorithm
  967. (car (epg-context-result-for context 'sign)))))
  968. (goto-char (point-min))
  969. (insert (format "Content-Type: multipart/signed; boundary=\"%s\";\n"
  970. boundary))
  971. (if micalg
  972. (insert (format "\tmicalg=pgp-%s; "
  973. (downcase
  974. (cdr (assq micalg
  975. epg-digest-algorithm-alist))))))
  976. (insert "protocol=\"application/pgp-signature\"\n")
  977. (insert (format "\n--%s\n" boundary))
  978. (goto-char (point-max))
  979. (insert (format "\n--%s\n" boundary))
  980. (insert "Content-Type: application/pgp-signature\n\n")
  981. (insert signature)
  982. (goto-char (point-max))
  983. (insert (format "--%s--\n" boundary))
  984. (goto-char (point-max))))
  985. (defun mml2015-epg-encrypt (cont &optional sign)
  986. (let* ((inhibit-redisplay t)
  987. (context (epg-make-context))
  988. (boundary (mml-compute-boundary cont))
  989. (config (epg-configuration))
  990. (recipients (message-options-get 'mml2015-epg-recipients))
  991. cipher
  992. (sender (message-options-get 'message-sender))
  993. (signer-names (or mml2015-signers
  994. (if (and mml2015-sign-with-sender sender)
  995. (list (concat "<" sender ">")))))
  996. signers
  997. recipient-key signer-key)
  998. (unless recipients
  999. (setq recipients
  1000. (apply #'nconc
  1001. (mapcar
  1002. (lambda (recipient)
  1003. (or (epg-expand-group config recipient)
  1004. (list (concat "<" recipient ">"))))
  1005. (split-string
  1006. (or (message-options-get 'message-recipients)
  1007. (message-options-set 'message-recipients
  1008. (read-string "Recipients: ")))
  1009. "[ \f\t\n\r\v,]+"))))
  1010. (when mml2015-encrypt-to-self
  1011. (unless signer-names
  1012. (error "Neither message sender nor mml2015-signers are set"))
  1013. (setq recipients (nconc recipients signer-names)))
  1014. (if (eq mm-encrypt-option 'guided)
  1015. (setq recipients
  1016. (epa-select-keys context "\
  1017. Select recipients for encryption.
  1018. If no one is selected, symmetric encryption will be performed. "
  1019. recipients))
  1020. (setq recipients
  1021. (delq nil
  1022. (mapcar
  1023. (lambda (recipient)
  1024. (setq recipient-key (mml2015-epg-find-usable-key
  1025. (epg-list-keys context recipient)
  1026. 'encrypt))
  1027. (unless (or recipient-key
  1028. (y-or-n-p
  1029. (format "No public key for %s; skip it? "
  1030. recipient)))
  1031. (error "No public key for %s" recipient))
  1032. recipient-key)
  1033. recipients)))
  1034. (unless recipients
  1035. (error "No recipient specified")))
  1036. (message-options-set 'mml2015-epg-recipients recipients))
  1037. (when sign
  1038. (setq signers
  1039. (or (message-options-get 'mml2015-epg-signers)
  1040. (message-options-set
  1041. 'mml2015-epg-signers
  1042. (if (eq mm-sign-option 'guided)
  1043. (epa-select-keys context "\
  1044. Select keys for signing.
  1045. If no one is selected, default secret key is used. "
  1046. signer-names
  1047. t)
  1048. (if (or sender mml2015-signers)
  1049. (delq nil
  1050. (mapcar
  1051. (lambda (signer)
  1052. (setq signer-key
  1053. (mml2015-epg-find-usable-secret-key
  1054. context signer 'sign))
  1055. (unless (or signer-key
  1056. (y-or-n-p
  1057. (format
  1058. "No secret key for %s; skip it? "
  1059. signer)))
  1060. (error "No secret key for %s" signer))
  1061. signer-key)
  1062. signer-names)))))))
  1063. (epg-context-set-signers context signers))
  1064. (epg-context-set-armor context t)
  1065. (epg-context-set-textmode context t)
  1066. (if mml2015-cache-passphrase
  1067. (epg-context-set-passphrase-callback
  1068. context
  1069. #'mml2015-epg-passphrase-callback))
  1070. (condition-case error
  1071. (setq cipher
  1072. (epg-encrypt-string context (buffer-string) recipients sign
  1073. mml2015-always-trust)
  1074. mml2015-epg-secret-key-id-list nil)
  1075. (error
  1076. (while mml2015-epg-secret-key-id-list
  1077. (password-cache-remove (car mml2015-epg-secret-key-id-list))
  1078. (setq mml2015-epg-secret-key-id-list
  1079. (cdr mml2015-epg-secret-key-id-list)))
  1080. (signal (car error) (cdr error))))
  1081. (delete-region (point-min) (point-max))
  1082. (goto-char (point-min))
  1083. (insert (format "Content-Type: multipart/encrypted; boundary=\"%s\";\n"
  1084. boundary))
  1085. (insert "\tprotocol=\"application/pgp-encrypted\"\n\n")
  1086. (insert (format "--%s\n" boundary))
  1087. (insert "Content-Type: application/pgp-encrypted\n\n")
  1088. (insert "Version: 1\n\n")
  1089. (insert (format "--%s\n" boundary))
  1090. (insert "Content-Type: application/octet-stream\n\n")
  1091. (insert cipher)
  1092. (goto-char (point-max))
  1093. (insert (format "--%s--\n" boundary))
  1094. (goto-char (point-max))))
  1095. ;;; General wrapper
  1096. (autoload 'gnus-buffer-live-p "gnus-util")
  1097. (autoload 'gnus-get-buffer-create "gnus")
  1098. (defun mml2015-clean-buffer ()
  1099. (if (gnus-buffer-live-p mml2015-result-buffer)
  1100. (with-current-buffer mml2015-result-buffer
  1101. (erase-buffer)
  1102. t)
  1103. (setq mml2015-result-buffer
  1104. (gnus-get-buffer-create " *MML2015 Result*"))
  1105. nil))
  1106. (defsubst mml2015-clear-decrypt-function ()
  1107. (nth 6 (assq mml2015-use mml2015-function-alist)))
  1108. (defsubst mml2015-clear-verify-function ()
  1109. (nth 5 (assq mml2015-use mml2015-function-alist)))
  1110. ;;;###autoload
  1111. (defun mml2015-decrypt (handle ctl)
  1112. (mml2015-clean-buffer)
  1113. (let ((func (nth 4 (assq mml2015-use mml2015-function-alist))))
  1114. (if func
  1115. (funcall func handle ctl)
  1116. handle)))
  1117. ;;;###autoload
  1118. (defun mml2015-decrypt-test (handle ctl)
  1119. mml2015-use)
  1120. ;;;###autoload
  1121. (defun mml2015-verify (handle ctl)
  1122. (mml2015-clean-buffer)
  1123. (let ((func (nth 3 (assq mml2015-use mml2015-function-alist))))
  1124. (if func
  1125. (funcall func handle ctl)
  1126. handle)))
  1127. ;;;###autoload
  1128. (defun mml2015-verify-test (handle ctl)
  1129. mml2015-use)
  1130. ;;;###autoload
  1131. (defun mml2015-encrypt (cont &optional sign)
  1132. (mml2015-clean-buffer)
  1133. (let ((func (nth 2 (assq mml2015-use mml2015-function-alist))))
  1134. (if func
  1135. (funcall func cont sign)
  1136. (error "Cannot find encrypt function"))))
  1137. ;;;###autoload
  1138. (defun mml2015-sign (cont)
  1139. (mml2015-clean-buffer)
  1140. (let ((func (nth 1 (assq mml2015-use mml2015-function-alist))))
  1141. (if func
  1142. (funcall func cont)
  1143. (error "Cannot find sign function"))))
  1144. ;;;###autoload
  1145. (defun mml2015-self-encrypt ()
  1146. (mml2015-encrypt nil))
  1147. (provide 'mml2015)
  1148. ;;; mml2015.el ends here