gnupg.scm 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. ;;; GNU Guix --- Functional package management for GNU
  2. ;;; Copyright © 2023 Ludovic Courtès <ludo@gnu.org>
  3. ;;; Copyright © 2023 Efraim Flashner <efraim@flashner.co.il>
  4. ;;;
  5. ;;; This file is part of GNU Guix.
  6. ;;;
  7. ;;; GNU Guix is free software; you can redistribute it and/or modify it
  8. ;;; under the terms of the GNU General Public License as published by
  9. ;;; the Free Software Foundation; either version 3 of the License, or (at
  10. ;;; your option) any later version.
  11. ;;;
  12. ;;; GNU Guix is distributed in the hope that it will be useful, but
  13. ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
  14. ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. ;;; GNU General Public License for more details.
  16. ;;;
  17. ;;; You should have received a copy of the GNU General Public License
  18. ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
  19. (define-module (gnu home services gnupg)
  20. #:use-module (guix gexp)
  21. #:use-module ((guix records) #:select (match-record))
  22. #:use-module (gnu services)
  23. #:use-module (gnu services configuration)
  24. #:use-module (gnu home services)
  25. #:use-module (gnu home services shepherd)
  26. #:autoload (gnu packages gnupg) (gnupg pinentry parcimonie)
  27. #:export (home-gpg-agent-configuration
  28. home-gpg-agent-configuration?
  29. home-gpg-agent-configuration-gnupg
  30. home-gpg-agent-configuration-pinentry-program
  31. home-gpg-agent-configuration-ssh-support?
  32. home-gpg-agent-configuration-default-cache-ttl
  33. home-gpg-agent-configuration-max-cache-ttl
  34. home-gpg-agent-configuration-max-cache-ttl-ssh
  35. home-gpg-agent-configuration-extra-content
  36. home-gpg-agent-service-type
  37. home-parcimonie-configuration
  38. home-parcimonie-configuration?
  39. home-parcimonie-configuration-parcimonie
  40. home-parcimonie-configuration-gnupg-already-torified?
  41. home-parcimonie-configuration-refresh-guix-keyrings?
  42. home-parcimonie-configuration-extra-content
  43. home-parcimonie-service-type))
  44. (define raw-configuration-string? string?)
  45. ;; Configuration of 'gpg-agent'.
  46. (define-configuration/no-serialization home-gpg-agent-configuration
  47. (gnupg
  48. (file-like gnupg)
  49. "The GnuPG package to use.")
  50. (pinentry-program
  51. (file-like (file-append pinentry "/bin/pinentry-curses"))
  52. "Pinentry program to use. Pinentry is a small user interface that
  53. @command{gpg-agent} delegates to anytime it needs user input for a passphrase
  54. or @acronym{PIN, personal identification number} (@pxref{Top,,, pinentry,
  55. Using the PIN-Entry}).")
  56. (ssh-support?
  57. (boolean #f)
  58. "Whether to enable @acronym{SSH, secure shell} support. When true,
  59. @command{gpg-agent} acts as a drop-in replacement for OpenSSH's
  60. @command{ssh-agent} program, taking care of OpenSSH secret keys and directing
  61. passphrase requests to the chosen Pinentry program.")
  62. (default-cache-ttl
  63. (integer 600)
  64. "Time a cache entry is valid, in seconds.")
  65. (max-cache-ttl
  66. (integer 7200)
  67. "Maximum time a cache entry is valid, in seconds. After this time a cache
  68. entry will be expired even if it has been accessed recently.")
  69. (default-cache-ttl-ssh
  70. (integer 1800)
  71. "Time a cache entry for SSH keys is valid, in seconds.")
  72. (max-cache-ttl-ssh
  73. (integer 7200)
  74. "Maximum time a cache entry for SSH keys is valid, in seconds.")
  75. (extra-content
  76. (raw-configuration-string "")
  77. "Raw content to add to the end of @file{~/.gnupg/gpg-agent.conf}."))
  78. (define (home-gpg-agent-configuration-file config)
  79. "Return the @file{gpg-agent.conf} file for @var{config}."
  80. (match-record config <home-gpg-agent-configuration>
  81. (pinentry-program default-cache-ttl max-cache-ttl
  82. default-cache-ttl-ssh max-cache-ttl-ssh
  83. extra-content)
  84. (mixed-text-file "gpg-agent.conf"
  85. "pinentry-program " pinentry-program "\n"
  86. "default-cache-ttl "
  87. (number->string default-cache-ttl) "\n"
  88. "max-cache-ttl "
  89. (number->string max-cache-ttl) "\n"
  90. "default-cache-ttl-ssh "
  91. (number->string default-cache-ttl-ssh) "\n"
  92. "max-cache-ttl-ssh "
  93. (number->string max-cache-ttl-ssh) "\n"
  94. extra-content)))
  95. (define (home-gpg-agent-shepherd-services config)
  96. "Return the possibly-empty list of Shepherd services for @var{config}."
  97. (match-record config <home-gpg-agent-configuration>
  98. (gnupg ssh-support?)
  99. ;; 'gpg-agent' is started on demand by GnuPG's programs, but it has to be
  100. ;; started explicitly when OpenSSH support is enabled (info "(gnupg) Agent
  101. ;; Options").
  102. (if ssh-support?
  103. (let ((endpoint (lambda (name socket)
  104. #~(endpoint
  105. (make-socket-address
  106. AF_UNIX
  107. (string-append %user-runtime-dir
  108. "/gnupg/" #$socket))
  109. #:name #$name
  110. #:socket-directory-permissions #o700))))
  111. (list (shepherd-service
  112. (provision '(gpg-agent ssh-agent))
  113. (modules '((shepherd support))) ;for '%user-runtime-dir'
  114. (start #~(make-systemd-constructor
  115. (list #$(file-append gnupg "/bin/gpg-agent")
  116. "--supervised" "--enable-ssh-support")
  117. (list #$(endpoint "ssh" "S.gpg-agent.ssh")
  118. #$(endpoint "browser" "S.gpg-agent.browser")
  119. #$(endpoint "extra" "S.gpg-agent.extra")
  120. ;; #$(endpoint "scdaemon" "S.scdaemon")
  121. #$(endpoint "std" "S.gpg-agent"))))
  122. (stop #~(make-systemd-destructor))
  123. (documentation "Start 'gpg-agent', the GnuPG passphrase
  124. agent, with support for handling OpenSSH material."))))
  125. '())))
  126. (define (home-gpg-agent-files config)
  127. `((".gnupg/gpg-agent.conf" ,(home-gpg-agent-configuration-file config))))
  128. (define (home-gpg-agent-environment-variables config)
  129. "Return GnuPG environment variables needed for @var{config}."
  130. (if (home-gpg-agent-configuration-ssh-support? config)
  131. `(("SSH_AUTH_SOCK"
  132. . "$XDG_RUNTIME_DIR/gnupg/S.gpg-agent.ssh"))
  133. '()))
  134. (define home-gpg-agent-service-type
  135. (service-type
  136. (name 'home-gpg-agent)
  137. (extensions
  138. (list (service-extension home-files-service-type
  139. home-gpg-agent-files)
  140. (service-extension home-shepherd-service-type
  141. home-gpg-agent-shepherd-services)
  142. (service-extension home-environment-variables-service-type
  143. home-gpg-agent-environment-variables)))
  144. (default-value (home-gpg-agent-configuration))
  145. (description
  146. "Configure GnuPG's agent, @command{gpg-agent}, which is responsible for
  147. managing OpenPGP and optionally SSH private keys. When SSH support is
  148. enabled, @command{gpg-agent} acts as a drop-in replacement for OpenSSH's
  149. @command{ssh-agent}.")))
  150. (define-configuration/no-serialization home-parcimonie-configuration
  151. (parcimonie
  152. (file-like parcimonie)
  153. "The parcimonie package to use.")
  154. (verbose?
  155. (boolean #f)
  156. "Provide extra output to the log file.")
  157. (gnupg-aleady-torified?
  158. (boolean #f)
  159. "GnuPG is already configured to use tor and parcimonie won't attempt to use
  160. tor directly.")
  161. (refresh-guix-keyrings?
  162. (boolean #f)
  163. "Also refresh any Guix keyrings found in the XDG_CONFIG_DIR.")
  164. (extra-content
  165. (raw-configuration-string "")
  166. "Raw content to add to the parcimonie service."))
  167. (define (home-parcimonie-shepherd-service config)
  168. "Return a user service to run parcimonie."
  169. (match-record config <home-parcimonie-configuration>
  170. (parcimonie verbose? gnupg-aleady-torified?
  171. refresh-guix-keyrings? extra-content)
  172. (let ((log-file #~(string-append %user-log-dir "/parcimonie.log")))
  173. (list (shepherd-service
  174. (provision '(parcimonie))
  175. (modules '((shepherd support) ;for '%user-log-dir'
  176. (guix build utils)
  177. (srfi srfi-1)))
  178. (start #~(make-forkexec-constructor
  179. (cons*
  180. #$(file-append parcimonie "/bin/parcimonie")
  181. #$@(if verbose?
  182. '("--verbose")
  183. '())
  184. #$@(if gnupg-aleady-torified?
  185. '("--gnupg_already_torified")
  186. '())
  187. #$@(if (not (string=? extra-content ""))
  188. (list extra-content)
  189. '())
  190. #$@(if refresh-guix-keyrings?
  191. '((append-map
  192. (lambda (item)
  193. (list (string-append "--gnupg_extra_args="
  194. "--keyring=" item)))
  195. (find-files
  196. (string-append (getenv "XDG_CONFIG_HOME") "/guix")
  197. "^trustedkeys\\.kbx$")))
  198. '((list))))
  199. #:log-file #$log-file))
  200. (stop #~(make-kill-destructor))
  201. (respawn? #t)
  202. (documentation "Incrementally refresh gnupg keyring over Tor"))))))
  203. (define home-parcimonie-service-type
  204. (service-type
  205. (name 'home-parcimonie)
  206. (extensions
  207. (list (service-extension home-shepherd-service-type
  208. home-parcimonie-shepherd-service)))
  209. (default-value (home-parcimonie-configuration))
  210. (description
  211. "Incrementally refresh GnuPG keyrings over Tor.")))