Marco Ricci commited on 2025-08-02 14:27:29
Zeige 3 geänderte Dateien mit 91 Einfügungen und 11 Löschungen.
Document the SSH agent socket providers in the API reference documentation. Additionally, update the user-facing, checklist-style reference documentation on the state of SSH agent support for The Annoying Operating System: still unsupported, but basic infrastructure is being built. Also go into more detail on GnuPG's `gpg-agent` -- how it still is unsupported on The Annoying Operating System, how to connect to it on other systems, and how to prepare OpenPGP keys of the right type for use with SSH. Finally -- though the information will likely still relevant for quite some time -- date the SSH key type recommendations explicitly, and update the explanation of the `--version` output of `derivepassphrase vault` to mention that SSH agent construction might still fail at runtime, even if support is indicated.
... | ... |
@@ -55,11 +55,45 @@ canonical SSH agent implementation. |
55 | 55 |
default, contrary to other SSH agents, so it must be manually |
56 | 56 |
advertised: |
57 | 57 |
|
58 |
+ === "UNIX" |
|
59 |
+ |
|
58 | 60 |
~~~~ console |
59 | 61 |
$ SSH_AUTH_SOCK="$(gpgconf --list-dirs agent-ssh-socket)" |
60 | 62 |
$ export SSH_AUTH_SOCK |
61 | 63 |
~~~~ |
62 | 64 |
|
65 |
+ === "Windows (`libassuan` socket)" |
|
66 |
+ |
|
67 |
+ `gpg-agent` on Windows contains a native emulation of |
|
68 |
+ UNIX domain sockets by the `assuan` library, which GnuPG |
|
69 |
+ internally uses for network connectivity and |
|
70 |
+ inter-process communication. No specific configuration |
|
71 |
+ is necessary, and the agent address can be directly |
|
72 |
+ obtained with `gpgconf`: |
|
73 |
+ |
|
74 |
+ ~~~~ console |
|
75 |
+ $ gpgconf --list-dirs agent-ssh-socket |
|
76 |
+ ~~~~ |
|
77 |
+ |
|
78 |
+ This mode, sadly, is not currently supported. The |
|
79 |
+ system is specific to GnuPG/`libassuan`, and unlikely to |
|
80 |
+ be deployed widely enough to make implementing this |
|
81 |
+ a priority for us… at least, relative to the other, more |
|
82 |
+ common interprocess communication channels for SSH |
|
83 |
+ agents on Windows. |
|
84 |
+ |
|
85 |
+ === "Windows (OpenSSH emulation)" |
|
86 |
+ |
|
87 |
+ From v2.4 onwards, `gpg-agent` supports masquerading as |
|
88 |
+ OpenSSH's `ssh-agent` on Windows, by starting the agent |
|
89 |
+ with the `--enable-win32-openssh-support` command-line |
|
90 |
+ argument. (Usually, this would be added to the |
|
91 |
+ `gpg-agent` configuration file instead of being manually |
|
92 |
+ supplied on the command-line.) |
|
93 |
+ |
|
94 |
+ [This mode, sadly, is not currently |
|
95 |
+ supported.](#python-support) |
|
96 |
+ |
|
63 | 97 |
</section> |
64 | 98 |
|
65 | 99 |
### A Python installation that can talk to the SSH agent { #python-support } |
... | ... |
@@ -74,10 +108,12 @@ canonical SSH agent implementation. |
74 | 108 |
does not inherently support named pipes. Since no comprehensive |
75 | 109 |
third-party Python modules to interface with named pipes appear to |
76 | 110 |
exist, teaching `derivepassphrase` to use Windows named pipes |
77 |
- will require us developers to write a custom low-level C module |
|
78 |
- specific to this application---an unrealistic task if we lack both |
|
79 |
- technical know-how for the named pipe API as well as Windows |
|
80 |
- hardware to test any potential implementation on. |
|
111 |
+ requires us developers to write the code to interface the Windows |
|
112 |
+ system libraries ourselves. Development on this started after the |
|
113 |
+ release of version 0.5, but since this is not our area of expertise, |
|
114 |
+ and because the pre-0.5 design hard-codes the UNIX style of looking |
|
115 |
+ up and connecting to an SSH agent, development progress on this |
|
116 |
+ front has been much slower than usual. |
|
81 | 117 |
|
82 | 118 |
On non-Windows operating systems, the SSH agent is expected to advertise |
83 | 119 |
its communication socket via the `SSH_AUTH_SOCK` environment variable, |
... | ... |
@@ -85,7 +121,13 @@ which is common procedure. Therefore, [your Python installation must |
85 | 121 |
support UNIX domain sockets][socket.AF_UNIX]. |
86 | 122 |
|
87 | 123 |
`derivepassphrase vault --version` will report on supported and on |
88 |
-unavailable features, including "master SSH key": |
|
124 |
+unavailable features, including "master SSH key":[^1] |
|
125 |
+ |
|
126 |
+[^1]: This indicates support in principle, on this |
|
127 |
+ hardware/software/system combination, for interfacing with an SSH |
|
128 |
+ agent. At runtime, this could still fail, e.g. because the SSH |
|
129 |
+ agent isn't actually running, because `derivepassphrase` is trying |
|
130 |
+ to connect to the wrong address, etc. |
|
89 | 131 |
|
90 | 132 |
=== "supported" |
91 | 133 |
|
... | ... |
@@ -114,8 +156,8 @@ unavailable features, including "master SSH key": |
114 | 156 |
For an SSH key to be usable by `derivepassphrase`, the SSH agent must |
115 | 157 |
always generate the same signature for the same input, i.e. the |
116 | 158 |
signature must be deterministic for this key type. Commonly used SSH |
117 |
-key types include [RSA][], [DSA][], [ECDSA][], [Ed25519][] and |
|
118 |
-[Ed448][]. |
|
159 |
+key types (as of August 2025) include [ECDSA][], [Ed25519][], [RSA][], |
|
160 |
+and, somewhat less commonly, [Ed448][] and [DSA][]. |
|
119 | 161 |
|
120 | 162 |
[RSA]: https://en.wikipedia.org/wiki/RSA_(cryptosystem) |
121 | 163 |
[DSA]: https://en.wikipedia.org/wiki/Digital_Signature_Algorithm |
... | ... |
@@ -168,7 +210,7 @@ key types include [RSA][], [DSA][], [ECDSA][], [Ed25519][] and |
168 | 210 |
If you do not yet have a (supported) SSH key, we recommend Ed25519 for |
169 | 211 |
maximum speed and reasonable availability, otherwise RSA for maximum |
170 | 212 |
availability. We do not in general recommend Ed448 because it is not |
171 |
-widely implemented. |
|
213 |
+widely implemented (as of August 2025). |
|
172 | 214 |
|
173 | 215 |
??? example "Generating new SSH keys for `derivepassphrase`" |
174 | 216 |
|
... | ... |
@@ -220,11 +262,42 @@ widely implemented. |
220 | 262 |
|
221 | 263 |
=== "GnuPG" |
222 | 264 |
|
223 |
- Not supported natively. An alternative SSH client distribution |
|
224 |
- such as OpenSSH or PuTTY is necessary. |
|
265 |
+ Not supported natively. A different SSH client distribution |
|
266 |
+ such as OpenSSH or PuTTY is necessary to create SSH keys |
|
267 |
+ specifically. |
|
225 | 268 |
|
226 | 269 |
Alternatively, GnuPG supports reusing keys in its native OpenPGP |
227 | 270 |
format for SSH as long as the underlying key type is compatible. |
271 |
+ First, obtain GnuPG's internal identifier (the "keygrip") for |
|
272 |
+ the correct key you may want to use. (Warning: OpenPGP subkeys |
|
273 |
+ have a different keygrip, so be sure to use the correct one.) |
|
274 |
+ |
|
275 |
+ ~~~~ console |
|
276 |
+ $ gpg --list-keys --with-keygrip sample-key@example.com |
|
277 |
+ pub rsa4096 2025-07-27 [SC] [expires: 2025-08-01] |
|
278 |
+ 675F056879A81925E3E0DE60370C2A7D2E40FF4C |
|
279 |
+ Keygrip = C71CB33DC50C9972EF9C135B0FB70D87B1491923 |
|
280 |
+ uid [ultimate] Sample Key <sample-key@example.com> |
|
281 |
+ sub rsa4096 2025-07-27 [E] [expires: 2025-08-01] |
|
282 |
+ Keygrip = 84129D49C9A0654BDFAE2DACBC7A9D8C563FF884 |
|
283 |
+ ~~~~ |
|
284 |
+ |
|
285 |
+ === "before v2.3.7" |
|
286 |
+ |
|
287 |
+ Add the keygrip (on a line of its own) to the `sshcontrol` |
|
288 |
+ file in the GnuPG configuration directory. |
|
289 |
+ |
|
290 |
+ ~~~~ console |
|
291 |
+ $ echo C71CB33DC50C9972EF9C135B0FB70D87B1491923 >> ~/.gnupg/sshcontrol |
|
292 |
+ ~~~~ |
|
293 |
+ |
|
294 |
+ === "v2.3.7 and later" |
|
295 |
+ |
|
296 |
+ Set a key attribute to permit this key's use in SSH: |
|
297 |
+ |
|
298 |
+ ~~~~ console |
|
299 |
+ $ gpg-connect-agent 'keyattr C71CB33DC50C9972EF9C135B0FB70D87B1491923 Use-for-ssh: true' /bye |
|
300 |
+ ~~~~ |
|
228 | 301 |
|
229 | 302 |
--- |
230 | 303 |
|
... | ... |
@@ -80,7 +80,10 @@ class SSHAgentClient: |
80 | 80 |
""" |
81 | 81 |
|
82 | 82 |
_connection: _types.SSHAgentSocket |
83 |
- SOCKET_PROVIDERS: ClassVar = ['native'] |
|
83 |
+ SOCKET_PROVIDERS: ClassVar = ('native',) |
|
84 |
+ """ |
|
85 |
+ The default list of SSH agent socket providers. |
|
86 |
+ """ |
|
84 | 87 |
|
85 | 88 |
def __init__( # noqa: C901, PLR0912 |
86 | 89 |
self, |
87 | 90 |