Marco Ricci commited on 2024-06-22 21:19:30
Zeige 2 geänderte Dateien mit 22 Einfügungen und 10 Löschungen.
In vault(1), the passphrase derived from an SSH key signature is *not* just the (framed, binary) SSH signature of the vault UUID. Instead, the payload part of the signature, in binary, is converted to base64, yielding the passphrase. Rewrite the `Vault.phrase_from_signature` method to match vault's behavior, and rename it to `phrase_from_key` to better match the *actual* interface (which takes an SSH key, not a signature). (This design – emitting an SSH signature as payload only, in base64 – is hard-coded into the SSH agent client library used by vault, and likely not a conscious design by vault's primary author.)
... | ... |
@@ -232,7 +232,7 @@ class Vault: |
232 | 232 |
target lengths. |
233 | 233 |
|
234 | 234 |
Examples: |
235 |
- >>> # See also Vault.phrase_from_signature examples. |
|
235 |
+ >>> # See also Vault.phrase_from_key examples. |
|
236 | 236 |
>>> phrase = bytes.fromhex(''' |
237 | 237 |
... 00 00 00 0b 73 73 68 2d 65 64 32 35 35 31 39 |
238 | 238 |
... 00 00 00 40 |
... | ... |
@@ -345,9 +345,9 @@ class Vault: |
345 | 345 |
return any(v(key) for v in deterministic_signature_types.values()) |
346 | 346 |
|
347 | 347 |
@classmethod |
348 |
- def phrase_from_signature( |
|
348 |
+ def phrase_from_key( |
|
349 | 349 |
cls, key: bytes | bytearray, / |
350 |
- ) -> bytes | bytearray: |
|
350 |
+ ) -> bytes: |
|
351 | 351 |
"""Obtain the master passphrase from a configured SSH key. |
352 | 352 |
|
353 | 353 |
vault allows the usage of certain SSH keys to derive a master |
... | ... |
@@ -358,7 +358,8 @@ class Vault: |
358 | 358 |
key: The (public) SSH key to use for signing. |
359 | 359 |
|
360 | 360 |
Returns: |
361 |
- The signature of the vault UUID under this key. |
|
361 |
+ The signature of the vault UUID under this key, unframed but |
|
362 |
+ encoded in base64. |
|
362 | 363 |
|
363 | 364 |
Raises: |
364 | 365 |
ValueError: |
... | ... |
@@ -367,14 +368,15 @@ class Vault: |
367 | 368 |
deterministic. |
368 | 369 |
|
369 | 370 |
Examples: |
370 |
- >>> # Actual test public key. |
|
371 |
+ >>> import base64 |
|
372 |
+ >>> # Actual Ed25519 test public key. |
|
371 | 373 |
>>> public_key = bytes.fromhex(''' |
372 | 374 |
... 00 00 00 0b 73 73 68 2d 65 64 32 35 35 31 39 |
373 | 375 |
... 00 00 00 20 |
374 | 376 |
... 81 78 81 68 26 d6 02 48 5f 0f ff 32 48 6f e4 c1 |
375 | 377 |
... 30 89 dc 1c 6a 45 06 09 e9 09 0f fb c2 12 69 76 |
376 | 378 |
... ''') |
377 |
- >>> expected_sig = bytes.fromhex(''' |
|
379 |
+ >>> expected_sig_raw = bytes.fromhex(''' |
|
378 | 380 |
... 00 00 00 0b 73 73 68 2d 65 64 32 35 35 31 39 |
379 | 381 |
... 00 00 00 40 |
380 | 382 |
... f0 98 19 80 6c 1a 97 d5 26 03 6e cc e3 65 8f 86 |
... | ... |
@@ -382,7 +384,10 @@ class Vault: |
382 | 384 |
... 0d 08 1f ec f8 73 9b 8c 5f 55 39 16 7c 53 54 2c |
383 | 385 |
... 1e 52 bb 30 ed 7f 89 e2 2f 69 51 55 d8 9e a6 02 |
384 | 386 |
... ''') |
385 |
- >>> Vault.phrase_from_signature(public_key) == expected_sig # doctest:+SKIP |
|
387 |
+ >>> # Raw Ed25519 signatures are 64 bytes long. |
|
388 |
+ >>> signature_blob = expected_sig_raw[-64:] |
|
389 |
+ >>> phrase = base64.standard_b64encode(signature_blob) |
|
390 |
+ >>> Vault.phrase_from_key(phrase) == expected # doctest:+SKIP |
|
386 | 391 |
True |
387 | 392 |
|
388 | 393 |
""" |
... | ... |
@@ -390,8 +395,10 @@ class Vault: |
390 | 395 |
raise ValueError( |
391 | 396 |
'unsuitable SSH key: bad key, or signature not deterministic') |
392 | 397 |
with ssh_agent_client.SSHAgentClient() as client: |
393 |
- ret = client.sign(key, cls._UUID) |
|
394 |
- return ret |
|
398 |
+ raw_sig = client.sign(key, cls._UUID) |
|
399 |
+ keytype, trailer = client.unstring_prefix(raw_sig) |
|
400 |
+ signature_blob = client.unstring(trailer) |
|
401 |
+ return bytes(base64.standard_b64encode(signature_blob)) |
|
395 | 402 |
|
396 | 403 |
@staticmethod |
397 | 404 |
def _subtract( |
... | ... |
@@ -40,6 +40,7 @@ idwcakUGCekJD/vCEml2AAAAG3Rlc3Qga2V5IHdpdGhvdXQgcGFzc3BocmFzZQEC |
40 | 40 |
0d 08 1f ec f8 73 9b 8c 5f 55 39 16 7c 53 54 2c |
41 | 41 |
1e 52 bb 30 ed 7f 89 e2 2f 69 51 55 d8 9e a6 02 |
42 | 42 |
'''), |
43 |
+ 'derived_passphrase': rb'8JgZgGwal9UmA27M42WPhmYHExkTCSEzM/nkNlMdr/0NCB/s+HObjF9VORZ8U1QsHlK7MO1/ieIvaVFV2J6mAg==', |
|
43 | 44 |
}, |
44 | 45 |
# Currently only supported by PuTTY (which is deficient in other |
45 | 46 |
# niceties of the SSH agent and the agent's client). |
... | ... |
@@ -77,7 +78,7 @@ dGhvdXQgcGFzc3BocmFzZQECAwQFBgcICQ== |
77 | 78 |
db bd 77 7c 80 20 7f 3a 48 61 f6 1f ae a9 5e 53 |
78 | 79 |
7b e0 9d 93 1e ea dc eb b5 cd 56 4c ea 8f 08 00 |
79 | 80 |
'''), |
80 |
- |
|
81 |
+ 'derived_passphrase': rb'Bob0ZKSmutnDIsSTSZn8Ed5nlwjy2Lc8LBPnxRwekqYO2C9tgQOCAONy5DJtctJtMoQ/zKkeVywAmrOZ3kXazi7R2+WJ8zW+JFiQxsoE8NuIgNu9d3yAIH86SGH2H66pXlN74J2THurc67XNVkzqjwgA', |
|
81 | 82 |
}, |
82 | 83 |
'rsa': { |
83 | 84 |
'private_key': rb'''-----BEGIN OPENSSH PRIVATE KEY----- |
... | ... |
@@ -178,6 +179,7 @@ Bgp6142WnSCQAAABt0ZXN0IGtleSB3aXRob3V0IHBhc3NwaHJhc2UB |
178 | 179 |
de 69 2c 48 62 d9 fd d1 9b 6b b0 49 db d3 ff 38 |
179 | 180 |
e7 10 d9 2d ce 9f 0d 5e 09 7b 37 d2 7b c3 bf ce |
180 | 181 |
'''), |
182 |
+ 'derived_passphrase': rb'ohB8Lva7U6h0KqEZma2Bvnmc7dadCU5uxRhIM5B3mWj3ngNazU4Y64l9haLurkqS9m/Ouf6GfyprMdpuGv6ipYi4RH+hdnOz7HW10Ka5FZdlCRN9lCHR+10PiyMEd8LDVSKxoAmK9Tgq1n8bhymgJdMlb8tkYQeY3BTFhPiSJF5QEWtJ5fDMKcspqRnYp3EfkQsFsQFLwl8ApbYhv/gsnWebRzsKSWt5Lfwd7Ayw5Sci1an408P530ho6fvvPNwmv8/qKUMBpuPFUZX0Zm2KVeJH7OgwRUyuR+fJpCGLZLq2iPYh+HO5yxGheHWSxlrlZP7tQtmVmeYrbzwWPCh0pHIvDT8sM2eqNRmO57URL7P3asUC4m+jQuNiGZkD6qUg56HjvMgGo7V81nZd329gRoMqCADW09mkwUGM+GBWRYHaO6IWH55OdYMX2sNTwz4ZpBu80im4eGEreOaxUrDV7N5pLEhi2f3Rm2uwSdvT/zjnENktzp8NXgl7N9J7w7/O', |
|
181 | 183 |
}, |
182 | 184 |
} |
183 | 185 |
|
... | ... |
@@ -240,6 +242,7 @@ u7HfrQhdOiKSa+ZO9AAojbURqrLDRfBJa5dXn2AAAAFQDJHfenj4EJ9WkehpdJatPBlqCW |
240 | 242 |
40 02 88 db 51 1a ab 2c 34 5f 04 96 b9 75 79 f6 |
241 | 243 |
'''), |
242 | 244 |
'expected_signature': None, |
245 |
+ 'derived_passphrase': None, |
|
243 | 246 |
}, |
244 | 247 |
'ecdsa256': { |
245 | 248 |
'private_key': rb'''-----BEGIN OPENSSH PRIVATE KEY----- |
... | ... |
@@ -265,6 +268,7 @@ dGhvdXQgcGFzc3BocmFzZQECAwQ= |
265 | 268 |
49 ff c6 7a 81 fc f9 ed 9d da a5 49 1a 30 99 ba |
266 | 269 |
'''), |
267 | 270 |
'expected_signature': None, |
271 |
+ 'derived_passphrase': None, |
|
268 | 272 |
}, |
269 | 273 |
'ecdsa384': { |
270 | 274 |
'private_key': rb'''-----BEGIN OPENSSH PRIVATE KEY----- |
... | ... |
@@ -294,6 +298,7 @@ JAu0J3Q+cypZuKQVAAAAMQD5sTy8p+B1cn/DhOmXquui1BcxvASqzzevkBlbQoBa73y04B |
294 | 298 |
79 fb c1 b1 24 0b b4 27 74 3e 73 2a 59 b8 a4 15 |
295 | 299 |
'''), |
296 | 300 |
'expected_signature': None, |
301 |
+ 'derived_passphrase': None, |
|
297 | 302 |
}, |
298 | 303 |
} |
299 | 304 |
|
300 | 305 |