Coverage for tests/__init__.py: 100.000%
58 statements
« prev ^ index » next coverage.py v7.6.0, created at 2024-07-14 11:39 +0200
« prev ^ index » next coverage.py v7.6.0, created at 2024-07-14 11:39 +0200
1# SPDX-FileCopyrightText: 2024 Marco Ricci <m@the13thletter.info>
2#
3# SPDX-License-Identifier: MIT
5from __future__ import annotations
7import base64
8from collections.abc import Iterator, Mapping
9import contextlib
10import json
11import os
12from typing import TYPE_CHECKING
13from typing_extensions import Any, TypedDict
15import click.testing
16import derivepassphrase
17import derivepassphrase.cli
18import derivepassphrase.types
19import pytest
20import ssh_agent_client
21import ssh_agent_client.types
23__all__ = ()
25if TYPE_CHECKING:
26 class SSHTestKey(TypedDict):
27 private_key: bytes
28 public_key: bytes | str
29 public_key_data: bytes
30 expected_signature: bytes | None
31 derived_passphrase: bytes | str | None
33SUPPORTED_KEYS: Mapping[str, SSHTestKey] = {
34 'ed25519': {
35 'private_key': rb'''-----BEGIN OPENSSH PRIVATE KEY-----
36b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
37QyNTUxOQAAACCBeIFoJtYCSF8P/zJIb+TBMIncHGpFBgnpCQ/7whJpdgAAAKDweO7H8Hju
38xwAAAAtzc2gtZWQyNTUxOQAAACCBeIFoJtYCSF8P/zJIb+TBMIncHGpFBgnpCQ/7whJpdg
39AAAEAbM/A869nkWZbe2tp3Dm/L6gitvmpH/aRZt8sBII3ExYF4gWgm1gJIXw//Mkhv5MEw
40idwcakUGCekJD/vCEml2AAAAG3Rlc3Qga2V5IHdpdGhvdXQgcGFzc3BocmFzZQEC
41-----END OPENSSH PRIVATE KEY-----
42''',
43 'public_key': rb'''ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIF4gWgm1gJIXw//Mkhv5MEwidwcakUGCekJD/vCEml2 test key without passphrase
44''',
45 'public_key_data': bytes.fromhex('''
46 00 00 00 0b 73 73 68 2d 65 64 32 35 35 31 39
47 00 00 00 20
48 81 78 81 68 26 d6 02 48 5f 0f ff 32 48 6f e4 c1
49 30 89 dc 1c 6a 45 06 09 e9 09 0f fb c2 12 69 76
50'''),
51 'expected_signature': bytes.fromhex('''
52 00 00 00 0b 73 73 68 2d 65 64 32 35 35 31 39
53 00 00 00 40
54 f0 98 19 80 6c 1a 97 d5 26 03 6e cc e3 65 8f 86
55 66 07 13 19 13 09 21 33 33 f9 e4 36 53 1d af fd
56 0d 08 1f ec f8 73 9b 8c 5f 55 39 16 7c 53 54 2c
57 1e 52 bb 30 ed 7f 89 e2 2f 69 51 55 d8 9e a6 02
58 '''),
59 'derived_passphrase': rb'8JgZgGwal9UmA27M42WPhmYHExkTCSEzM/nkNlMdr/0NCB/s+HObjF9VORZ8U1QsHlK7MO1/ieIvaVFV2J6mAg==',
60 },
61 # Currently only supported by PuTTY (which is deficient in other
62 # niceties of the SSH agent and the agent's client).
63 'ed448': {
64 'private_key': rb'''-----BEGIN OPENSSH PRIVATE KEY-----
65b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAASgAAAAlz
66c2gtZWQ0NDgAAAA54vZy009Wu8wExjvEb3hqtLz1GO/+d5vmGUbErWQ4AUO9mYLT
67zHJHc2m4s+yWzP29Cc3EcxizLG8AAAAA8BdhfCcXYXwnAAAACXNzaC1lZDQ0OAAA
68ADni9nLTT1a7zATGO8RveGq0vPUY7/53m+YZRsStZDgBQ72ZgtPMckdzabiz7JbM
69/b0JzcRzGLMsbwAAAAByM7GIMRvWJB3YD6SIpAF2uudX4ozZe0X917wPwiBrs373
709TM1n94Nib6hrxGNmCk2iBQDe2KALPgA4vZy009Wu8wExjvEb3hqtLz1GO/+d5vm
71GUbErWQ4AUO9mYLTzHJHc2m4s+yWzP29Cc3EcxizLG8AAAAAG3Rlc3Qga2V5IHdp
72dGhvdXQgcGFzc3BocmFzZQECAwQFBgcICQ==
73-----END OPENSSH PRIVATE KEY-----
74''',
75 'public_key': rb'''ssh-ed448 AAAACXNzaC1lZDQ0OAAAADni9nLTT1a7zATGO8RveGq0vPUY7/53m+YZRsStZDgBQ72ZgtPMckdzabiz7JbM/b0JzcRzGLMsbwA= test key without passphrase
76''',
77 'public_key_data': bytes.fromhex('''
78 00 00 00 09 73 73 68 2d 65 64 34 34 38
79 00 00 00 39
80 e2 f6 72 d3 4f 56 bb cc 04 c6 3b c4 6f 78 6a b4
81 bc f5 18 ef fe 77 9b e6 19 46 c4 ad 64 38 01 43
82 bd 99 82 d3 cc 72 47 73 69 b8 b3 ec 96 cc fd bd
83 09 cd c4 73 18 b3 2c 6f 00
84 '''),
86 'expected_signature': bytes.fromhex('''
87 00 00 00 09 73 73 68 2d 65 64 34 34 38
88 00 00 00 72 06 86
89 f4 64 a4 a6 ba d9 c3 22 c4 93 49 99 fc 11 de 67
90 97 08 f2 d8 b7 3c 2c 13 e7 c5 1c 1e 92 a6 0e d8
91 2f 6d 81 03 82 00 e3 72 e4 32 6d 72 d2 6d 32 84
92 3f cc a9 1e 57 2c 00 9a b3 99 de 45 da ce 2e d1
93 db e5 89 f3 35 be 24 58 90 c6 ca 04 f0 db 88 80
94 db bd 77 7c 80 20 7f 3a 48 61 f6 1f ae a9 5e 53
95 7b e0 9d 93 1e ea dc eb b5 cd 56 4c ea 8f 08 00
96 '''),
97 'derived_passphrase': rb'Bob0ZKSmutnDIsSTSZn8Ed5nlwjy2Lc8LBPnxRwekqYO2C9tgQOCAONy5DJtctJtMoQ/zKkeVywAmrOZ3kXazi7R2+WJ8zW+JFiQxsoE8NuIgNu9d3yAIH86SGH2H66pXlN74J2THurc67XNVkzqjwgA',
98 },
99 'rsa': {
100 'private_key': rb'''-----BEGIN OPENSSH PRIVATE KEY-----
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
137-----END OPENSSH PRIVATE KEY-----
138''',
139 'public_key': rb'''ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCxoe7pezhxWy4NI0mUwKqg9WCYOAS+IjxN9eYcqpfcmQiojcuy9XsiN/xYJ1O94SrsKS5mEia2xHnYA4RUChTyYNcM2v6cnnBQ/N/VQhpGMN7SVxdbhKUXTWFCwbjBgO6rGyHB6WtoH8vd7TOEPt+NgcXwhsWyoaUUdYTA62V+GF9vEmxMaC4ubgDz+B0QkPnauSoNxmkhcIe0lsLNb1pClZyz88PDnKXCX/d0HuN/HJ+sbPg7dCvOyqFYSyKn3uY6bCXqoIdurxXzH3O7z0P8f5sbmKOrGGKNuNxVRbeVl/D/3uDL0nqsbfUc1qvkfwbJwtMXC4IV6kOZMSk2BAsqh7x48gQ+rhYeEVSi8F3CWs4HJQoqrGt7K9a3mCSlMBHP70u3w6ME7eumoryxlUofewTd17ZEkzdX08l2ZlKzZvwQUrc+xQZ2Uw8z2mfW6Ti4gi0pYGaig7Ke4PwuXpo/C5YAWfeXycsvJZ2uaYRjMdZeJGNAnHLUGLkBscw5aI8= test key without passphrase
140''',
141 'public_key_data': bytes.fromhex('''
142 00 00 00 07 73 73 68 2d 72 73 61
143 00 00 00 03 01 00 01
144 00 00 01 81 00
145 b1 a1 ee e9 7b 38 71 5b 2e 0d 23 49 94 c0 aa a0
146 f5 60 98 38 04 be 22 3c 4d f5 e6 1c aa 97 dc 99
147 08 a8 8d cb b2 f5 7b 22 37 fc 58 27 53 bd e1 2a
148 ec 29 2e 66 12 26 b6 c4 79 d8 03 84 54 0a 14 f2
149 60 d7 0c da fe 9c 9e 70 50 fc df d5 42 1a 46 30
150 de d2 57 17 5b 84 a5 17 4d 61 42 c1 b8 c1 80 ee
151 ab 1b 21 c1 e9 6b 68 1f cb dd ed 33 84 3e df 8d
152 81 c5 f0 86 c5 b2 a1 a5 14 75 84 c0 eb 65 7e 18
153 5f 6f 12 6c 4c 68 2e 2e 6e 00 f3 f8 1d 10 90 f9
154 da b9 2a 0d c6 69 21 70 87 b4 96 c2 cd 6f 5a 42
155 95 9c b3 f3 c3 c3 9c a5 c2 5f f7 74 1e e3 7f 1c
156 9f ac 6c f8 3b 74 2b ce ca a1 58 4b 22 a7 de e6
157 3a 6c 25 ea a0 87 6e af 15 f3 1f 73 bb cf 43 fc
158 7f 9b 1b 98 a3 ab 18 62 8d b8 dc 55 45 b7 95 97
159 f0 ff de e0 cb d2 7a ac 6d f5 1c d6 ab e4 7f 06
160 c9 c2 d3 17 0b 82 15 ea 43 99 31 29 36 04 0b 2a
161 87 bc 78 f2 04 3e ae 16 1e 11 54 a2 f0 5d c2 5a
162 ce 07 25 0a 2a ac 6b 7b 2b d6 b7 98 24 a5 30 11
163 cf ef 4b b7 c3 a3 04 ed eb a6 a2 bc b1 95 4a 1f
164 7b 04 dd d7 b6 44 93 37 57 d3 c9 76 66 52 b3 66
165 fc 10 52 b7 3e c5 06 76 53 0f 33 da 67 d6 e9 38
166 b8 82 2d 29 60 66 a2 83 b2 9e e0 fc 2e 5e 9a 3f
167 0b 96 00 59 f7 97 c9 cb 2f 25 9d ae 69 84 63 31
168 d6 5e 24 63 40 9c 72 d4 18 b9 01 b1 cc 39 68 8f
169'''),
170 'expected_signature': bytes.fromhex('''
171 00 00 00 07 73 73 68 2d 72 73 61
172 00 00 01 80
173 a2 10 7c 2e f6 bb 53 a8 74 2a a1 19 99 ad 81 be
174 79 9c ed d6 9d 09 4e 6e c5 18 48 33 90 77 99 68
175 f7 9e 03 5a cd 4e 18 eb 89 7d 85 a2 ee ae 4a 92
176 f6 6f ce b9 fe 86 7f 2a 6b 31 da 6e 1a fe a2 a5
177 88 b8 44 7f a1 76 73 b3 ec 75 b5 d0 a6 b9 15 97
178 65 09 13 7d 94 21 d1 fb 5d 0f 8b 23 04 77 c2 c3
179 55 22 b1 a0 09 8a f5 38 2a d6 7f 1b 87 29 a0 25
180 d3 25 6f cb 64 61 07 98 dc 14 c5 84 f8 92 24 5e
181 50 11 6b 49 e5 f0 cc 29 cb 29 a9 19 d8 a7 71 1f
182 91 0b 05 b1 01 4b c2 5f 00 a5 b6 21 bf f8 2c 9d
183 67 9b 47 3b 0a 49 6b 79 2d fc 1d ec 0c b0 e5 27
184 22 d5 a9 f8 d3 c3 f9 df 48 68 e9 fb ef 3c dc 26
185 bf cf ea 29 43 01 a6 e3 c5 51 95 f4 66 6d 8a 55
186 e2 47 ec e8 30 45 4c ae 47 e7 c9 a4 21 8b 64 ba
187 b6 88 f6 21 f8 73 b9 cb 11 a1 78 75 92 c6 5a e5
188 64 fe ed 42 d9 95 99 e6 2b 6f 3c 16 3c 28 74 a4
189 72 2f 0d 3f 2c 33 67 aa 35 19 8e e7 b5 11 2f b3
190 f7 6a c5 02 e2 6f a3 42 e3 62 19 99 03 ea a5 20
191 e7 a1 e3 bc c8 06 a3 b5 7c d6 76 5d df 6f 60 46
192 83 2a 08 00 d6 d3 d9 a4 c1 41 8c f8 60 56 45 81
193 da 3b a2 16 1f 9e 4e 75 83 17 da c3 53 c3 3e 19
194 a4 1b bc d2 29 b8 78 61 2b 78 e6 b1 52 b0 d5 ec
195 de 69 2c 48 62 d9 fd d1 9b 6b b0 49 db d3 ff 38
196 e7 10 d9 2d ce 9f 0d 5e 09 7b 37 d2 7b c3 bf ce
197'''),
198 'derived_passphrase': rb'ohB8Lva7U6h0KqEZma2Bvnmc7dadCU5uxRhIM5B3mWj3ngNazU4Y64l9haLurkqS9m/Ouf6GfyprMdpuGv6ipYi4RH+hdnOz7HW10Ka5FZdlCRN9lCHR+10PiyMEd8LDVSKxoAmK9Tgq1n8bhymgJdMlb8tkYQeY3BTFhPiSJF5QEWtJ5fDMKcspqRnYp3EfkQsFsQFLwl8ApbYhv/gsnWebRzsKSWt5Lfwd7Ayw5Sci1an408P530ho6fvvPNwmv8/qKUMBpuPFUZX0Zm2KVeJH7OgwRUyuR+fJpCGLZLq2iPYh+HO5yxGheHWSxlrlZP7tQtmVmeYrbzwWPCh0pHIvDT8sM2eqNRmO57URL7P3asUC4m+jQuNiGZkD6qUg56HjvMgGo7V81nZd329gRoMqCADW09mkwUGM+GBWRYHaO6IWH55OdYMX2sNTwz4ZpBu80im4eGEreOaxUrDV7N5pLEhi2f3Rm2uwSdvT/zjnENktzp8NXgl7N9J7w7/O',
199 },
200}
202UNSUITABLE_KEYS: Mapping[str, SSHTestKey] = {
203 'dsa1024': {
204 'private_key': rb'''-----BEGIN OPENSSH PRIVATE KEY-----
205b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABsQAAAAdzc2gtZH
206NzAAAAgQC7KAZXqBGNVLBQPrcMYAoNW54BhD8aIhe7BDWYzJcsaMt72VKSkguZ8+XR7nRa
2070C/ZsBi+uJp0dpxy9ZMTOWX4u5YPMeQcXEdGExZIfimGqSOAsy6fCld2IfJZJZExcCmhe9
208Ssjsd3YSAPJRluOXFQc95MZoR5hMwlIDD8QzrE7QAAABUA99nOZOgd7aHMVGoXpUEBcn7H
209ossAAACALr2Ag3hxM3rKdxzVUw8fX0VVPXO+3+Kr8hGe0Kc/7NwVaBVL1GQ8fenBuWynpA
210UbH0wo3h1wkB/8hX6p+S8cnu5rIBlUuVNwLw/bIYohK98LfqTYK/V+g6KD+8m34wvEiXZm
211qywY54n2bksch1Nqvj/tNpLzExSx/XS0kSM1aigAAACAbQNRPcVEuGDrEcf+xg5tgAejPX
212BPXr/Jss+Chk64km3mirMYjAWyWYtVcgT+7hOYxtYRin8LyMLqKRmqa0Q5UrvDfChgLhvs
213G9YSb/Mpw5qm8PiHSafwhkaz/te3+8hKogqoe7sd+tCF06IpJr5k70ACiNtRGqssNF8Elr
214l1efYAAAH4swlfVrMJX1YAAAAHc3NoLWRzcwAAAIEAuygGV6gRjVSwUD63DGAKDVueAYQ/
215GiIXuwQ1mMyXLGjLe9lSkpILmfPl0e50WtAv2bAYvriadHaccvWTEzll+LuWDzHkHFxHRh
216MWSH4phqkjgLMunwpXdiHyWSWRMXApoXvUrI7Hd2EgDyUZbjlxUHPeTGaEeYTMJSAw/EM6
217xO0AAAAVAPfZzmToHe2hzFRqF6VBAXJ+x6LLAAAAgC69gIN4cTN6yncc1VMPH19FVT1zvt
218/iq/IRntCnP+zcFWgVS9RkPH3pwblsp6QFGx9MKN4dcJAf/IV+qfkvHJ7uayAZVLlTcC8P
2192yGKISvfC36k2Cv1foOig/vJt+MLxIl2ZqssGOeJ9m5LHIdTar4/7TaS8xMUsf10tJEjNW
220ooAAAAgG0DUT3FRLhg6xHH/sYObYAHoz1wT16/ybLPgoZOuJJt5oqzGIwFslmLVXIE/u4T
221mMbWEYp/C8jC6ikZqmtEOVK7w3woYC4b7BvWEm/zKcOapvD4h0mn8IZGs/7Xt/vISqIKqH
222u7HfrQhdOiKSa+ZO9AAojbURqrLDRfBJa5dXn2AAAAFQDJHfenj4EJ9WkehpdJatPBlqCW
2230gAAABt0ZXN0IGtleSB3aXRob3V0IHBhc3NwaHJhc2UBAgMEBQYH
224-----END OPENSSH PRIVATE KEY-----
225''',
226 'public_key': rb'''ssh-dss AAAAB3NzaC1kc3MAAACBALsoBleoEY1UsFA+twxgCg1bngGEPxoiF7sENZjMlyxoy3vZUpKSC5nz5dHudFrQL9mwGL64mnR2nHL1kxM5Zfi7lg8x5BxcR0YTFkh+KYapI4CzLp8KV3Yh8lklkTFwKaF71KyOx3dhIA8lGW45cVBz3kxmhHmEzCUgMPxDOsTtAAAAFQD32c5k6B3tocxUahelQQFyfseiywAAAIAuvYCDeHEzesp3HNVTDx9fRVU9c77f4qvyEZ7Qpz/s3BVoFUvUZDx96cG5bKekBRsfTCjeHXCQH/yFfqn5Lxye7msgGVS5U3AvD9shiiEr3wt+pNgr9X6DooP7ybfjC8SJdmarLBjnifZuSxyHU2q+P+02kvMTFLH9dLSRIzVqKAAAAIBtA1E9xUS4YOsRx/7GDm2AB6M9cE9ev8myz4KGTriSbeaKsxiMBbJZi1VyBP7uE5jG1hGKfwvIwuopGaprRDlSu8N8KGAuG+wb1hJv8ynDmqbw+IdJp/CGRrP+17f7yEqiCqh7ux360IXToikmvmTvQAKI21Eaqyw0XwSWuXV59g== test key without passphrase
227''',
228 'public_key_data': bytes.fromhex('''
229 00 00 00 07 73 73 68 2d 64 73 73
230 00 00 00 81 00
231 bb 28 06 57 a8 11 8d 54 b0 50 3e b7 0c 60 0a 0d
232 5b 9e 01 84 3f 1a 22 17 bb 04 35 98 cc 97 2c 68
233 cb 7b d9 52 92 92 0b 99 f3 e5 d1 ee 74 5a d0 2f
234 d9 b0 18 be b8 9a 74 76 9c 72 f5 93 13 39 65 f8
235 bb 96 0f 31 e4 1c 5c 47 46 13 16 48 7e 29 86 a9
236 23 80 b3 2e 9f 0a 57 76 21 f2 59 25 91 31 70 29
237 a1 7b d4 ac 8e c7 77 61 20 0f 25 19 6e 39 71 50
238 73 de 4c 66 84 79 84 cc 25 20 30 fc 43 3a c4 ed
239 00 00 00 15 00 f7 d9 ce 64
240 e8 1d ed a1 cc 54 6a 17 a5 41 01 72 7e c7 a2 cb
241 00 00 00 80
242 2e bd 80 83 78 71 33 7a ca 77 1c d5 53 0f 1f 5f
243 45 55 3d 73 be df e2 ab f2 11 9e d0 a7 3f ec dc
244 15 68 15 4b d4 64 3c 7d e9 c1 b9 6c a7 a4 05 1b
245 1f 4c 28 de 1d 70 90 1f fc 85 7e a9 f9 2f 1c 9e
246 ee 6b 20 19 54 b9 53 70 2f 0f db 21 8a 21 2b df
247 0b 7e a4 d8 2b f5 7e 83 a2 83 fb c9 b7 e3 0b c4
248 89 76 66 ab 2c 18 e7 89 f6 6e 4b 1c 87 53 6a be
249 3f ed 36 92 f3 13 14 b1 fd 74 b4 91 23 35 6a 28
250 00 00 00 80
251 6d 03 51 3d c5 44 b8 60 eb 11 c7 fe c6 0e 6d 80
252 07 a3 3d 70 4f 5e bf c9 b2 cf 82 86 4e b8 92 6d
253 e6 8a b3 18 8c 05 b2 59 8b 55 72 04 fe ee 13 98
254 c6 d6 11 8a 7f 0b c8 c2 ea 29 19 aa 6b 44 39 52
255 bb c3 7c 28 60 2e 1b ec 1b d6 12 6f f3 29 c3 9a
256 a6 f0 f8 87 49 a7 f0 86 46 b3 fe d7 b7 fb c8 4a
257 a2 0a a8 7b bb 1d fa d0 85 d3 a2 29 26 be 64 ef
258 40 02 88 db 51 1a ab 2c 34 5f 04 96 b9 75 79 f6
259'''),
260 'expected_signature': None,
261 'derived_passphrase': None,
262 },
263 'ecdsa256': {
264 'private_key': rb'''-----BEGIN OPENSSH PRIVATE KEY-----
265b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAaAAAABNlY2RzYS
2661zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQTLbU0zDwsk2Dvp+VYIrsNVf5gWwz2S
2673SZ8TbxiQRkpnGSVqyIoHJOJc+NQItAa7xlJ/8Z6gfz57Z3apUkaMJm6AAAAuKeY+YinmP
268mIAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBMttTTMPCyTYO+n5
269Vgiuw1V/mBbDPZLdJnxNvGJBGSmcZJWrIigck4lz41Ai0BrvGUn/xnqB/PntndqlSRowmb
270oAAAAhAKIl/3n0pKVIxpZkXTGtii782Qr4yIcvHdpxjO/QsIqKAAAAG3Rlc3Qga2V5IHdp
271dGhvdXQgcGFzc3BocmFzZQECAwQ=
272-----END OPENSSH PRIVATE KEY-----
273''',
274 'public_key': rb'''ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBMttTTMPCyTYO+n5Vgiuw1V/mBbDPZLdJnxNvGJBGSmcZJWrIigck4lz41Ai0BrvGUn/xnqB/PntndqlSRowmbo= test key without passphrase
275''',
276 'public_key_data': bytes.fromhex('''
277 00 00 00 13 65 63 64 73 61 2d 73 68 61 32 2d 6e
278 69 73 74 70 32 35 36
279 00 00 00 08 6e 69 73 74 70 32 35 36
280 00 00 00 41 04
281 cb 6d 4d 33 0f 0b 24 d8 3b e9 f9 56 08 ae c3 55
282 7f 98 16 c3 3d 92 dd 26 7c 4d bc 62 41 19 29 9c
283 64 95 ab 22 28 1c 93 89 73 e3 50 22 d0 1a ef 19
284 49 ff c6 7a 81 fc f9 ed 9d da a5 49 1a 30 99 ba
285'''),
286 'expected_signature': None,
287 'derived_passphrase': None,
288 },
289 'ecdsa384': {
290 'private_key': rb'''-----BEGIN OPENSSH PRIVATE KEY-----
291b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAiAAAABNlY2RzYS
2921zaGEyLW5pc3RwMzg0AAAACG5pc3RwMzg0AAAAYQSgkOjkAvq7v5vHuj3KBL4/EAWcn5hZ
293DyKcbyV0eBMGFq7hKXQlZqIahLVqeMR0QqmkxNJ2rly2VHcXneq3vZ+9fIsWCOdYk5WP3N
294ZPzv911Xn7wbEkC7QndD5zKlm4pBUAAADomhj+IZoY/iEAAAATZWNkc2Etc2hhMi1uaXN0
295cDM4NAAAAAhuaXN0cDM4NAAAAGEEoJDo5AL6u7+bx7o9ygS+PxAFnJ+YWQ8inG8ldHgTBh
296au4Sl0JWaiGoS1anjEdEKppMTSdq5ctlR3F53qt72fvXyLFgjnWJOVj9zWT87/ddV5+8Gx
297JAu0J3Q+cypZuKQVAAAAMQD5sTy8p+B1cn/DhOmXquui1BcxvASqzzevkBlbQoBa73y04B
2982OdqVOVRkwZWRROz0AAAAbdGVzdCBrZXkgd2l0aG91dCBwYXNzcGhyYXNlAQIDBA==
299-----END OPENSSH PRIVATE KEY-----
300''',
301 'public_key': rb'''ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBKCQ6OQC+ru/m8e6PcoEvj8QBZyfmFkPIpxvJXR4EwYWruEpdCVmohqEtWp4xHRCqaTE0nauXLZUdxed6re9n718ixYI51iTlY/c1k/O/3XVefvBsSQLtCd0PnMqWbikFQ== test key without passphrase
302''',
303 'public_key_data': bytes.fromhex('''
304 00 00 00 13
305 65 63 64 73 61 2d 73 68 61 32 2d 6e 69 73 74 70
306 33 38 34
307 00 00 00 08 6e 69 73 74 70 33 38 34
308 00 00 00 61 04
309 a0 90 e8 e4 02 fa bb bf 9b c7 ba 3d ca 04 be 3f
310 10 05 9c 9f 98 59 0f 22 9c 6f 25 74 78 13 06 16
311 ae e1 29 74 25 66 a2 1a 84 b5 6a 78 c4 74 42 a9
312 a4 c4 d2 76 ae 5c b6 54 77 17 9d ea b7 bd 9f bd
313 7c 8b 16 08 e7 58 93 95 8f dc d6 4f ce ff 75 d5
314 79 fb c1 b1 24 0b b4 27 74 3e 73 2a 59 b8 a4 15
315'''),
316 'expected_signature': None,
317 'derived_passphrase': None,
318 },
319}
321DUMMY_SERVICE = 'service1'
322DUMMY_PASSPHRASE = b'my secret passphrase\n'
323DUMMY_KEY1 = SUPPORTED_KEYS['ed25519']['public_key_data']
324DUMMY_KEY1_B64 = base64.standard_b64encode(DUMMY_KEY1).decode('ASCII')
325DUMMY_KEY2 = SUPPORTED_KEYS['rsa']['public_key_data']
326DUMMY_KEY2_B64 = base64.standard_b64encode(DUMMY_KEY2).decode('ASCII')
327DUMMY_CONFIG_SETTINGS = {"length": 10, "upper": 1, "lower": 1, "repeat": 5,
328 "number": 1, "space": 1, "dash": 1, "symbol": 1}
329DUMMY_RESULT_PASSPHRASE = b'.2V_QJkd o'
330DUMMY_RESULT_KEY1 = b'E<b<{ -7iG'
331DUMMY_PHRASE_FROM_KEY1_RAW = (
332 b'\x00\x00\x00\x0bssh-ed25519'
333 b'\x00\x00\x00@\xf0\x98\x19\x80l\x1a\x97\xd5&\x03n'
334 b'\xcc\xe3e\x8f\x86f\x07\x13\x19\x13\t!33\xf9\xe46S'
335 b'\x1d\xaf\xfd\r\x08\x1f\xec\xf8s\x9b\x8c_U9\x16|ST,'
336 b'\x1eR\xbb0\xed\x7f\x89\xe2/iQU\xd8\x9e\xa6\x02'
337)
338DUMMY_PHRASE_FROM_KEY1 = b'8JgZgGwal9UmA27M42WPhmYHExkTCSEzM/nkNlMdr/0NCB/s+HObjF9VORZ8U1QsHlK7MO1/ieIvaVFV2J6mAg=='
340skip_if_no_agent = pytest.mark.skipif(
341 not os.environ.get('SSH_AUTH_SOCK'), reason='running SSH agent required')
343def list_keys(
344 self: Any = None,
345) -> list[ssh_agent_client.types.KeyCommentPair]:
346 Pair = ssh_agent_client.types.KeyCommentPair
347 list1 = [Pair(value['public_key_data'], f'{key} test key'.encode('ASCII'))
348 for key, value in SUPPORTED_KEYS.items()]
349 list2 = [Pair(value['public_key_data'], f'{key} test key'.encode('ASCII'))
350 for key, value in UNSUITABLE_KEYS.items()]
351 return list1 + list2
353def list_keys_singleton(
354 self: Any = None,
355) -> list[ssh_agent_client.types.KeyCommentPair]:
356 Pair = ssh_agent_client.types.KeyCommentPair
357 list1 = [Pair(value['public_key_data'], f'{key} test key'.encode('ASCII'))
358 for key, value in SUPPORTED_KEYS.items()]
359 return list1[:1]
361def suitable_ssh_keys(
362 conn: Any
363) -> Iterator[ssh_agent_client.types.KeyCommentPair]:
364 yield from [
365 ssh_agent_client.types.KeyCommentPair(DUMMY_KEY1, b'no comment'),
366 ssh_agent_client.types.KeyCommentPair(DUMMY_KEY2, b'a comment'),
367 ]
369def phrase_from_key(key: bytes) -> bytes:
370 if key == DUMMY_KEY1: # pragma: no branch
371 return DUMMY_PHRASE_FROM_KEY1
372 raise KeyError(key) # pragma: no cover
374@contextlib.contextmanager
375def isolated_config(
376 monkeypatch: Any, runner: click.testing.CliRunner, config: Any,
377):
378 prog_name = derivepassphrase.cli.prog_name
379 env_name = prog_name.replace(' ', '_').upper() + '_PATH'
380 with runner.isolated_filesystem():
381 monkeypatch.setenv('HOME', os.getcwd())
382 monkeypatch.setenv('USERPROFILE', os.getcwd())
383 monkeypatch.delenv(env_name, raising=False)
384 os.makedirs(os.path.dirname(derivepassphrase.cli._config_filename()),
385 exist_ok=True)
386 with open(derivepassphrase.cli._config_filename(), 'wt') as outfile:
387 json.dump(config, outfile)
388 yield
390def auto_prompt(*args: Any, **kwargs: Any) -> str:
391 return DUMMY_PASSPHRASE.decode('UTF-8')