mml2015.el 44 KB

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