pgg-parse.el 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524
  1. ;;; pgg-parse.el --- OpenPGP packet parsing
  2. ;; Copyright (C) 1999, 2002-2015 Free Software Foundation, Inc.
  3. ;; Author: Daiki Ueno <ueno@unixuser.org>
  4. ;; Created: 1999/10/28
  5. ;; Keywords: PGP, OpenPGP, GnuPG
  6. ;; Package: pgg
  7. ;; Obsolete-since: 24.1
  8. ;; This file is part of GNU Emacs.
  9. ;; GNU Emacs is free software: you can redistribute it and/or modify
  10. ;; it under the terms of the GNU General Public License as published by
  11. ;; the Free Software Foundation, either version 3 of the License, or
  12. ;; (at your option) any later version.
  13. ;; GNU Emacs is distributed in the hope that it will be useful,
  14. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. ;; GNU General Public License for more details.
  17. ;; You should have received a copy of the GNU General Public License
  18. ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
  19. ;;; Commentary:
  20. ;; This module is based on
  21. ;; [OpenPGP] RFC 2440: "OpenPGP Message Format"
  22. ;; by John W. Noerenberg, II <jwn2@qualcomm.com>,
  23. ;; Jon Callas <jon@pgp.com>, Lutz Donnerhacke <lutz@iks-jena.de>,
  24. ;; Hal Finney <hal@pgp.com> and Rodney Thayer <rodney@unitran.com>
  25. ;; (1998/11)
  26. ;;; Code:
  27. (eval-when-compile
  28. ;; For Emacs <22.2 and XEmacs.
  29. (unless (fboundp 'declare-function) (defmacro declare-function (&rest r)))
  30. (require 'cl))
  31. (defgroup pgg-parse ()
  32. "OpenPGP packet parsing."
  33. :group 'pgg)
  34. (defcustom pgg-parse-public-key-algorithm-alist
  35. '((1 . RSA) (2 . RSA-E) (3 . RSA-S) (16 . ELG-E) (17 . DSA) (20 . ELG))
  36. "Alist of the assigned number to the public key algorithm."
  37. :group 'pgg-parse
  38. :type '(repeat
  39. (cons (sexp :tag "Number") (sexp :tag "Type"))))
  40. (defcustom pgg-parse-symmetric-key-algorithm-alist
  41. '((1 . IDEA) (2 . 3DES) (4 . CAST5) (5 . SAFER-SK128))
  42. "Alist of the assigned number to the symmetric key algorithm."
  43. :group 'pgg-parse
  44. :type '(repeat
  45. (cons (sexp :tag "Number") (sexp :tag "Type"))))
  46. (defcustom pgg-parse-hash-algorithm-alist
  47. '((1 . MD5) (2 . SHA1) (3 . RIPEMD160) (5 . MD2) (8 . SHA256) (9 . SHA384)
  48. (10 . SHA512))
  49. "Alist of the assigned number to the cryptographic hash algorithm."
  50. :group 'pgg-parse
  51. :type '(repeat
  52. (cons (sexp :tag "Number") (sexp :tag "Type"))))
  53. (defcustom pgg-parse-compression-algorithm-alist
  54. '((0 . nil); Uncompressed
  55. (1 . ZIP)
  56. (2 . ZLIB))
  57. "Alist of the assigned number to the compression algorithm."
  58. :group 'pgg-parse
  59. :type '(repeat
  60. (cons (sexp :tag "Number") (sexp :tag "Type"))))
  61. (defcustom pgg-parse-signature-type-alist
  62. '((0 . "Signature of a binary document")
  63. (1 . "Signature of a canonical text document")
  64. (2 . "Standalone signature")
  65. (16 . "Generic certification of a User ID and Public Key packet")
  66. (17 . "Persona certification of a User ID and Public Key packet")
  67. (18 . "Casual certification of a User ID and Public Key packet")
  68. (19 . "Positive certification of a User ID and Public Key packet")
  69. (24 . "Subkey Binding Signature")
  70. (31 . "Signature directly on a key")
  71. (32 . "Key revocation signature")
  72. (40 . "Subkey revocation signature")
  73. (48 . "Certification revocation signature")
  74. (64 . "Timestamp signature."))
  75. "Alist of the assigned number to the signature type."
  76. :group 'pgg-parse
  77. :type '(repeat
  78. (cons (sexp :tag "Number") (sexp :tag "Type"))))
  79. (defcustom pgg-ignore-packet-checksum t; XXX
  80. "If non-nil checksum of each ascii armored packet will be ignored."
  81. :group 'pgg-parse
  82. :type 'boolean)
  83. (defvar pgg-armor-header-lines
  84. '("^-----BEGIN PGP MESSAGE\\(, PART [0-9]+\\(/[0-9]+\\)?\\)?-----\r?$"
  85. "^-----BEGIN PGP PUBLIC KEY BLOCK-----\r?$"
  86. "^-----BEGIN PGP PRIVATE KEY BLOCK-----\r?$"
  87. "^-----BEGIN PGP SIGNATURE-----\r?$")
  88. "Armor headers.")
  89. (eval-and-compile
  90. (defalias 'pgg-char-int (if (fboundp 'char-int)
  91. 'char-int
  92. 'identity)))
  93. (defmacro pgg-format-key-identifier (string)
  94. `(mapconcat (lambda (c) (format "%02X" (pgg-char-int c)))
  95. ,string "")
  96. ;; `(upcase (apply #'format "%02x%02x%02x%02x%02x%02x%02x%02x"
  97. ;; (string-to-number-list ,string)))
  98. )
  99. (defmacro pgg-parse-time-field (bytes)
  100. `(list (logior (lsh (car ,bytes) 8)
  101. (nth 1 ,bytes))
  102. (logior (lsh (nth 2 ,bytes) 8)
  103. (nth 3 ,bytes))
  104. 0))
  105. (defmacro pgg-byte-after (&optional pos)
  106. `(pgg-char-int (char-after ,(or pos `(point)))))
  107. (defmacro pgg-read-byte ()
  108. `(pgg-char-int (char-after (prog1 (point) (forward-char)))))
  109. (defmacro pgg-read-bytes-string (nbytes)
  110. `(buffer-substring
  111. (point) (prog1 (+ ,nbytes (point))
  112. (forward-char ,nbytes))))
  113. (defmacro pgg-read-bytes (nbytes)
  114. `(mapcar #'pgg-char-int (pgg-read-bytes-string ,nbytes))
  115. ;; `(string-to-number-list (pgg-read-bytes-string ,nbytes))
  116. )
  117. (defmacro pgg-read-body-string (ptag)
  118. `(if (nth 1 ,ptag)
  119. (pgg-read-bytes-string (nth 1 ,ptag))
  120. (pgg-read-bytes-string (- (point-max) (point)))))
  121. (defmacro pgg-read-body (ptag)
  122. `(mapcar #'pgg-char-int (pgg-read-body-string ,ptag))
  123. ;; `(string-to-number-list (pgg-read-body-string ,ptag))
  124. )
  125. (defalias 'pgg-skip-bytes 'forward-char)
  126. (defmacro pgg-skip-header (ptag)
  127. `(pgg-skip-bytes (nth 2 ,ptag)))
  128. (defmacro pgg-skip-body (ptag)
  129. `(pgg-skip-bytes (nth 1 ,ptag)))
  130. (defmacro pgg-set-alist (alist key value)
  131. `(setq ,alist (nconc ,alist (list (cons ,key ,value)))))
  132. (when (fboundp 'define-ccl-program)
  133. (define-ccl-program pgg-parse-crc24
  134. '(1
  135. ((loop
  136. (read r0) (r1 ^= r0) (r2 ^= 0)
  137. (r5 = 0)
  138. (loop
  139. (r1 <<= 1)
  140. (r1 += ((r2 >> 15) & 1))
  141. (r2 <<= 1)
  142. (if (r1 & 256)
  143. ((r1 ^= 390) (r2 ^= 19707)))
  144. (if (r5 < 7)
  145. ((r5 += 1)
  146. (repeat))))
  147. (repeat)))))
  148. (defvar pgg-parse-crc24)
  149. (defun pgg-parse-crc24-string (string)
  150. (let ((h (vector nil 183 1230 nil nil nil nil nil nil)))
  151. (ccl-execute-on-string pgg-parse-crc24 h string)
  152. (format "%c%c%c"
  153. (logand (aref h 1) 255)
  154. (logand (lsh (aref h 2) -8) 255)
  155. (logand (aref h 2) 255)))))
  156. (defmacro pgg-parse-length-type (c)
  157. `(cond
  158. ((< ,c 192) (cons ,c 1))
  159. ((< ,c 224)
  160. (cons (+ (lsh (- ,c 192) 8)
  161. (pgg-byte-after (+ 2 (point)))
  162. 192)
  163. 2))
  164. ((= ,c 255)
  165. (cons (cons (logior (lsh (pgg-byte-after (+ 2 (point))) 8)
  166. (pgg-byte-after (+ 3 (point))))
  167. (logior (lsh (pgg-byte-after (+ 4 (point))) 8)
  168. (pgg-byte-after (+ 5 (point)))))
  169. 5))
  170. (t;partial body length
  171. '(0 . 0))))
  172. (defun pgg-parse-packet-header ()
  173. (let ((ptag (pgg-byte-after))
  174. length-type content-tag packet-bytes header-bytes)
  175. (if (zerop (logand 64 ptag));Old format
  176. (progn
  177. (setq length-type (logand ptag 3)
  178. length-type (if (= 3 length-type) 0 (lsh 1 length-type))
  179. content-tag (logand 15 (lsh ptag -2))
  180. packet-bytes 0
  181. header-bytes (1+ length-type))
  182. (dotimes (i length-type)
  183. (setq packet-bytes
  184. (logior (lsh packet-bytes 8)
  185. (pgg-byte-after (+ 1 i (point)))))))
  186. (setq content-tag (logand 63 ptag)
  187. length-type (pgg-parse-length-type
  188. (pgg-byte-after (1+ (point))))
  189. packet-bytes (car length-type)
  190. header-bytes (1+ (cdr length-type))))
  191. (list content-tag packet-bytes header-bytes)))
  192. (defun pgg-parse-packet (ptag)
  193. (case (car ptag)
  194. (1 ;Public-Key Encrypted Session Key Packet
  195. (pgg-parse-public-key-encrypted-session-key-packet ptag))
  196. (2 ;Signature Packet
  197. (pgg-parse-signature-packet ptag))
  198. (3 ;Symmetric-Key Encrypted Session Key Packet
  199. (pgg-parse-symmetric-key-encrypted-session-key-packet ptag))
  200. ;; 4 -- One-Pass Signature Packet
  201. ;; 5 -- Secret Key Packet
  202. (6 ;Public Key Packet
  203. (pgg-parse-public-key-packet ptag))
  204. ;; 7 -- Secret Subkey Packet
  205. ;; 8 -- Compressed Data Packet
  206. (9 ;Symmetrically Encrypted Data Packet
  207. (pgg-read-body-string ptag))
  208. (10 ;Marker Packet
  209. (pgg-read-body-string ptag))
  210. (11 ;Literal Data Packet
  211. (pgg-read-body-string ptag))
  212. ;; 12 -- Trust Packet
  213. (13 ;User ID Packet
  214. (pgg-read-body-string ptag))
  215. ;; 14 -- Public Subkey Packet
  216. ;; 60 .. 63 -- Private or Experimental Values
  217. ))
  218. (defun pgg-parse-packets (&optional header-parser body-parser)
  219. (let ((header-parser
  220. (or header-parser
  221. (function pgg-parse-packet-header)))
  222. (body-parser
  223. (or body-parser
  224. (function pgg-parse-packet)))
  225. result ptag)
  226. (while (> (point-max) (1+ (point)))
  227. (setq ptag (funcall header-parser))
  228. (pgg-skip-header ptag)
  229. (push (cons (car ptag)
  230. (save-excursion
  231. (funcall body-parser ptag)))
  232. result)
  233. (if (zerop (nth 1 ptag))
  234. (goto-char (point-max))
  235. (forward-char (nth 1 ptag))))
  236. result))
  237. (defun pgg-parse-signature-subpacket-header ()
  238. (let ((length-type (pgg-parse-length-type (pgg-byte-after))))
  239. (list (pgg-byte-after (+ (cdr length-type) (point)))
  240. (1- (car length-type))
  241. (1+ (cdr length-type)))))
  242. (defun pgg-parse-signature-subpacket (ptag)
  243. (case (car ptag)
  244. (2 ;signature creation time
  245. (cons 'creation-time
  246. (let ((bytes (pgg-read-bytes 4)))
  247. (pgg-parse-time-field bytes))))
  248. (3 ;signature expiration time
  249. (cons 'signature-expiry
  250. (let ((bytes (pgg-read-bytes 4)))
  251. (pgg-parse-time-field bytes))))
  252. (4 ;exportable certification
  253. (cons 'exportability (pgg-read-byte)))
  254. (5 ;trust signature
  255. (cons 'trust-level (pgg-read-byte)))
  256. (6 ;regular expression
  257. (cons 'regular-expression
  258. (pgg-read-body-string ptag)))
  259. (7 ;revocable
  260. (cons 'revocability (pgg-read-byte)))
  261. (9 ;key expiration time
  262. (cons 'key-expiry
  263. (let ((bytes (pgg-read-bytes 4)))
  264. (pgg-parse-time-field bytes))))
  265. ;; 10 = placeholder for backward compatibility
  266. (11 ;preferred symmetric algorithms
  267. (cons 'preferred-symmetric-key-algorithm
  268. (cdr (assq (pgg-read-byte)
  269. pgg-parse-symmetric-key-algorithm-alist))))
  270. (12 ;revocation key
  271. )
  272. (16 ;issuer key ID
  273. (cons 'key-identifier
  274. (pgg-format-key-identifier (pgg-read-body-string ptag))))
  275. (20 ;notation data
  276. (pgg-skip-bytes 4)
  277. (cons 'notation
  278. (let ((name-bytes (pgg-read-bytes 2))
  279. (value-bytes (pgg-read-bytes 2)))
  280. (cons (pgg-read-bytes-string
  281. (logior (lsh (car name-bytes) 8)
  282. (nth 1 name-bytes)))
  283. (pgg-read-bytes-string
  284. (logior (lsh (car value-bytes) 8)
  285. (nth 1 value-bytes)))))))
  286. (21 ;preferred hash algorithms
  287. (cons 'preferred-hash-algorithm
  288. (cdr (assq (pgg-read-byte)
  289. pgg-parse-hash-algorithm-alist))))
  290. (22 ;preferred compression algorithms
  291. (cons 'preferred-compression-algorithm
  292. (cdr (assq (pgg-read-byte)
  293. pgg-parse-compression-algorithm-alist))))
  294. (23 ;key server preferences
  295. (cons 'key-server-preferences
  296. (pgg-read-body ptag)))
  297. (24 ;preferred key server
  298. (cons 'preferred-key-server
  299. (pgg-read-body-string ptag)))
  300. ;; 25 = primary user id
  301. (26 ;policy URL
  302. (cons 'policy-url (pgg-read-body-string ptag)))
  303. ;; 27 = key flags
  304. ;; 28 = signer's user id
  305. ;; 29 = reason for revocation
  306. ;; 100 to 110 = internal or user-defined
  307. ))
  308. (defun pgg-parse-signature-packet (ptag)
  309. (let* ((signature-version (pgg-byte-after))
  310. (result (list (cons 'version signature-version)))
  311. hashed-material field n)
  312. (cond
  313. ((= signature-version 3)
  314. (pgg-skip-bytes 2)
  315. (setq hashed-material (pgg-read-bytes 5))
  316. (pgg-set-alist result
  317. 'signature-type
  318. (cdr (assq (pop hashed-material)
  319. pgg-parse-signature-type-alist)))
  320. (pgg-set-alist result
  321. 'creation-time
  322. (pgg-parse-time-field hashed-material))
  323. (pgg-set-alist result
  324. 'key-identifier
  325. (pgg-format-key-identifier
  326. (pgg-read-bytes-string 8)))
  327. (pgg-set-alist result
  328. 'public-key-algorithm (pgg-read-byte))
  329. (pgg-set-alist result
  330. 'hash-algorithm (pgg-read-byte)))
  331. ((= signature-version 4)
  332. (pgg-skip-bytes 1)
  333. (pgg-set-alist result
  334. 'signature-type
  335. (cdr (assq (pgg-read-byte)
  336. pgg-parse-signature-type-alist)))
  337. (pgg-set-alist result
  338. 'public-key-algorithm
  339. (pgg-read-byte))
  340. (pgg-set-alist result
  341. 'hash-algorithm (pgg-read-byte))
  342. (when (>= 10000 (setq n (pgg-read-bytes 2)
  343. n (logior (lsh (car n) 8)
  344. (nth 1 n))))
  345. (save-restriction
  346. (narrow-to-region (point)(+ n (point)))
  347. (nconc result
  348. (mapcar (function cdr) ;remove packet types
  349. (pgg-parse-packets
  350. #'pgg-parse-signature-subpacket-header
  351. #'pgg-parse-signature-subpacket)))
  352. (goto-char (point-max))))
  353. (when (>= 10000 (setq n (pgg-read-bytes 2)
  354. n (logior (lsh (car n) 8)
  355. (nth 1 n))))
  356. (save-restriction
  357. (narrow-to-region (point)(+ n (point)))
  358. (nconc result
  359. (mapcar (function cdr) ;remove packet types
  360. (pgg-parse-packets
  361. #'pgg-parse-signature-subpacket-header
  362. #'pgg-parse-signature-subpacket)))))))
  363. (setcdr (setq field (assq 'public-key-algorithm
  364. result))
  365. (cdr (assq (cdr field)
  366. pgg-parse-public-key-algorithm-alist)))
  367. (setcdr (setq field (assq 'hash-algorithm
  368. result))
  369. (cdr (assq (cdr field)
  370. pgg-parse-hash-algorithm-alist)))
  371. result))
  372. (defun pgg-parse-public-key-encrypted-session-key-packet (ptag)
  373. (let (result)
  374. (pgg-set-alist result
  375. 'version (pgg-read-byte))
  376. (pgg-set-alist result
  377. 'key-identifier
  378. (pgg-format-key-identifier
  379. (pgg-read-bytes-string 8)))
  380. (pgg-set-alist result
  381. 'public-key-algorithm
  382. (cdr (assq (pgg-read-byte)
  383. pgg-parse-public-key-algorithm-alist)))
  384. result))
  385. (defun pgg-parse-symmetric-key-encrypted-session-key-packet (ptag)
  386. (let (result)
  387. (pgg-set-alist result
  388. 'version
  389. (pgg-read-byte))
  390. (pgg-set-alist result
  391. 'symmetric-key-algorithm
  392. (cdr (assq (pgg-read-byte)
  393. pgg-parse-symmetric-key-algorithm-alist)))
  394. result))
  395. (defun pgg-parse-public-key-packet (ptag)
  396. (let* ((key-version (pgg-read-byte))
  397. (result (list (cons 'version key-version)))
  398. field)
  399. (cond
  400. ((= 3 key-version)
  401. (pgg-set-alist result
  402. 'creation-time
  403. (let ((bytes (pgg-read-bytes 4)))
  404. (pgg-parse-time-field bytes)))
  405. (pgg-set-alist result
  406. 'key-expiry (pgg-read-bytes 2))
  407. (pgg-set-alist result
  408. 'public-key-algorithm (pgg-read-byte)))
  409. ((= 4 key-version)
  410. (pgg-set-alist result
  411. 'creation-time
  412. (let ((bytes (pgg-read-bytes 4)))
  413. (pgg-parse-time-field bytes)))
  414. (pgg-set-alist result
  415. 'public-key-algorithm (pgg-read-byte))))
  416. (setcdr (setq field (assq 'public-key-algorithm
  417. result))
  418. (cdr (assq (cdr field)
  419. pgg-parse-public-key-algorithm-alist)))
  420. result))
  421. ;; p-d-p only calls this if it is defined, but the compiler does not
  422. ;; recognize that.
  423. (declare-function pgg-parse-crc24-string "pgg-parse" (string))
  424. (defun pgg-decode-packets ()
  425. (if (re-search-forward "^=\\([A-Za-z0-9+/]\\{4\\}\\)$" nil t)
  426. (let ((p (match-beginning 0))
  427. (checksum (match-string 1)))
  428. (delete-region p (point-max))
  429. (if (ignore-errors (base64-decode-region (point-min) p))
  430. (or (not (fboundp 'pgg-parse-crc24-string))
  431. pgg-ignore-packet-checksum
  432. (string-equal (base64-encode-string (pgg-parse-crc24-string
  433. (buffer-string)))
  434. checksum)
  435. (progn
  436. (message "PGP packet checksum does not match")
  437. nil))
  438. (message "PGP packet contain invalid base64")
  439. nil))
  440. (message "PGP packet checksum not found")
  441. nil))
  442. (defun pgg-decode-armor-region (start end)
  443. (save-restriction
  444. (narrow-to-region start end)
  445. (goto-char (point-min))
  446. (re-search-forward "^-+BEGIN PGP" nil t)
  447. (delete-region (point-min)
  448. (and (search-forward "\n\n")
  449. (match-end 0)))
  450. (when (pgg-decode-packets)
  451. (goto-char (point-min))
  452. (pgg-parse-packets))))
  453. (defun pgg-parse-armor (string)
  454. (with-temp-buffer
  455. (buffer-disable-undo)
  456. (unless (featurep 'xemacs)
  457. (set-buffer-multibyte nil))
  458. (insert string)
  459. (pgg-decode-armor-region (point-min)(point))))
  460. (eval-and-compile
  461. (defalias 'pgg-string-as-unibyte (if (fboundp 'string-as-unibyte)
  462. 'string-as-unibyte
  463. 'identity)))
  464. (defun pgg-parse-armor-region (start end)
  465. (pgg-parse-armor (pgg-string-as-unibyte (buffer-substring start end))))
  466. (provide 'pgg-parse)
  467. ;;; pgg-parse.el ends here