pgp.lisp 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  1. (in-package :cl-user)
  2. (defpackage #:assboard.pgp
  3. (:use :cl :assboard.utils)
  4. (:export #:list-fingerprints
  5. #:recv-key
  6. #:delete-key
  7. #:verify))
  8. (in-package #:assboard.pgp)
  9. (defvar *gpg-program* "/usr/bin/gpg" "gpg command")
  10. (defvar *gpg-homedir* (make-pathname :name ".gnupg"
  11. :defaults +project-path+)
  12. "gpg homedir (key storage)")
  13. (defvar *gpg-keyserver* "pgpkeys.mit.edu" "Keyserver to use")
  14. (defmacro loop-lines (s &body body)
  15. `(with-input-from-string (stream ,s)
  16. (loop for line = (read-line stream nil :eof nil)
  17. until (eq line :eof)
  18. ,@body)))
  19. (defun extract-fingerprint (line)
  20. (let* ((last (1- (length line)))
  21. (first (1+ (position #\: line :from-end t :end last))))
  22. (subseq line first last)))
  23. (defun run-gpg (args &key input)
  24. (with-output-to-string (s)
  25. (sb-ext:run-program *gpg-program*
  26. (append
  27. (list "--homedir" (namestring *gpg-homedir*)
  28. "--status-fd" "1"
  29. "--logger-fd" "2"
  30. "--no-tty")
  31. args)
  32. :input input
  33. :output s
  34. :error nil)))
  35. (defun list-fingerprints ()
  36. (loop-lines (run-gpg '("--with-colons"
  37. "--with-fingerprint"
  38. "--list-keys"))
  39. if (starts-with "fpr:" line)
  40. collect (extract-fingerprint line)))
  41. (defun recv-key (fingerprint)
  42. (loop-lines (run-gpg (list "--keyserver" *gpg-keyserver*
  43. "--recv-keys" fingerprint))
  44. if (starts-with "[GNUPG:] IMPORT_OK" line)
  45. do (return t)))
  46. (defun delete-key (fingerprint)
  47. (not (loop-lines (run-gpg (list "--batch"
  48. "--delete-keys" fingerprint))
  49. if (starts-with "[GNUPG:] DELETE_PROBLEM" line)
  50. do (return t))))
  51. (defun verify (clearsigned)
  52. (with-input-from-string (input clearsigned)
  53. (loop-lines (run-gpg '("--verify") :input input)
  54. if (starts-with "[GNUPG:] VALIDSIG" line)
  55. do (return (values (subseq line (1+ (position #\Space line :from-end t)))
  56. (parse-integer line
  57. :start 70
  58. :end (position #\Space line :start 70)))))))