• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# This file is dual licensed under the terms of the Apache License, Version
2# 2.0, and the BSD License. See the LICENSE file in the root of this repository
3# for complete details.
4
5from __future__ import absolute_import, division, print_function
6
7import base64
8import itertools
9import os
10import textwrap
11
12import pytest
13
14import six
15
16from cryptography.exceptions import UnsupportedAlgorithm
17from cryptography.hazmat.backends.interfaces import (
18    DERSerializationBackend,
19    DSABackend,
20    EllipticCurveBackend,
21    PEMSerializationBackend,
22    RSABackend,
23)
24from cryptography.hazmat.primitives.asymmetric import (
25    dsa,
26    ec,
27    ed25519,
28    ed448,
29    rsa,
30    x25519,
31    x448,
32)
33from cryptography.hazmat.primitives.serialization import (
34    BestAvailableEncryption,
35    Encoding,
36    NoEncryption,
37    PrivateFormat,
38    PublicFormat,
39    load_der_parameters,
40    load_der_private_key,
41    load_der_public_key,
42    load_pem_parameters,
43    load_pem_private_key,
44    load_pem_public_key,
45    load_ssh_private_key,
46    load_ssh_public_key,
47    ssh,
48)
49
50
51from .test_ec import _skip_curve_unsupported
52from .utils import (
53    _check_dsa_private_numbers,
54    _check_rsa_private_numbers,
55    load_vectors_from_file,
56)
57from ...doubles import DummyKeySerializationEncryption
58
59
60def _skip_fips_format(key_path, password, backend):
61    if backend._fips_enabled:
62        if key_path[0] == "Traditional_OpenSSL_Serialization":
63            pytest.skip("Traditional OpenSSL format blocked in FIPS mode")
64        if key_path[0] == "PEM_Serialization" and password is not None:
65            pytest.skip("Encrypted PEM_Serialization blocked in FIPS mode")
66
67
68class TestBufferProtocolSerialization(object):
69    @pytest.mark.requires_backend_interface(interface=RSABackend)
70    @pytest.mark.parametrize(
71        ("key_path", "password"),
72        [
73            (["DER_Serialization", "enc-rsa-pkcs8.der"], bytearray(b"foobar")),
74            (["DER_Serialization", "enc2-rsa-pkcs8.der"], bytearray(b"baz")),
75            (["DER_Serialization", "unenc-rsa-pkcs8.der"], None),
76            (["DER_Serialization", "testrsa.der"], None),
77        ],
78    )
79    def test_load_der_rsa_private_key(self, key_path, password, backend):
80        data = load_vectors_from_file(
81            os.path.join("asymmetric", *key_path),
82            lambda derfile: derfile.read(),
83            mode="rb",
84        )
85        key = load_der_private_key(bytearray(data), password, backend)
86        assert key
87        assert isinstance(key, rsa.RSAPrivateKey)
88        _check_rsa_private_numbers(key.private_numbers())
89
90    @pytest.mark.requires_backend_interface(interface=RSABackend)
91    @pytest.mark.parametrize(
92        ("key_path", "password"),
93        [
94            (
95                ["PEM_Serialization", "rsa_private_key.pem"],
96                bytearray(b"123456"),
97            ),
98            (["PKCS8", "unenc-rsa-pkcs8.pem"], None),
99            (["PKCS8", "enc-rsa-pkcs8.pem"], bytearray(b"foobar")),
100            (["PKCS8", "enc2-rsa-pkcs8.pem"], bytearray(b"baz")),
101            (
102                ["Traditional_OpenSSL_Serialization", "key1.pem"],
103                bytearray(b"123456"),
104            ),
105        ],
106    )
107    def test_load_pem_rsa_private_key(self, key_path, password, backend):
108        _skip_fips_format(key_path, password, backend)
109        data = load_vectors_from_file(
110            os.path.join("asymmetric", *key_path),
111            lambda pemfile: pemfile.read(),
112            mode="rb",
113        )
114        key = load_pem_private_key(bytearray(data), password, backend)
115        assert key
116        assert isinstance(key, rsa.RSAPrivateKey)
117        _check_rsa_private_numbers(key.private_numbers())
118
119
120@pytest.mark.requires_backend_interface(interface=DERSerializationBackend)
121class TestDERSerialization(object):
122    @pytest.mark.requires_backend_interface(interface=RSABackend)
123    @pytest.mark.parametrize(
124        ("key_path", "password"),
125        [
126            (["DER_Serialization", "enc-rsa-pkcs8.der"], b"foobar"),
127            (["DER_Serialization", "enc2-rsa-pkcs8.der"], b"baz"),
128            (["DER_Serialization", "unenc-rsa-pkcs8.der"], None),
129            (["DER_Serialization", "testrsa.der"], None),
130        ],
131    )
132    def test_load_der_rsa_private_key(self, key_path, password, backend):
133        key = load_vectors_from_file(
134            os.path.join("asymmetric", *key_path),
135            lambda derfile: load_der_private_key(
136                derfile.read(), password, backend
137            ),
138            mode="rb",
139        )
140        assert key
141        assert isinstance(key, rsa.RSAPrivateKey)
142        _check_rsa_private_numbers(key.private_numbers())
143
144    @pytest.mark.requires_backend_interface(interface=DSABackend)
145    @pytest.mark.parametrize(
146        ("key_path", "password"),
147        [
148            (["DER_Serialization", "unenc-dsa-pkcs8.der"], None),
149            (["DER_Serialization", "dsa.1024.der"], None),
150            (["DER_Serialization", "dsa.2048.der"], None),
151            (["DER_Serialization", "dsa.3072.der"], None),
152        ],
153    )
154    def test_load_der_dsa_private_key(self, key_path, password, backend):
155        key = load_vectors_from_file(
156            os.path.join("asymmetric", *key_path),
157            lambda derfile: load_der_private_key(
158                derfile.read(), password, backend
159            ),
160            mode="rb",
161        )
162        assert key
163        assert isinstance(key, dsa.DSAPrivateKey)
164        _check_dsa_private_numbers(key.private_numbers())
165
166    @pytest.mark.parametrize(
167        "key_path", [["DER_Serialization", "enc-rsa-pkcs8.der"]]
168    )
169    @pytest.mark.requires_backend_interface(interface=RSABackend)
170    def test_password_not_bytes(self, key_path, backend):
171        key_file = os.path.join("asymmetric", *key_path)
172        password = u"this password is not bytes"
173
174        with pytest.raises(TypeError):
175            load_vectors_from_file(
176                key_file,
177                lambda derfile: load_der_private_key(
178                    derfile.read(), password, backend
179                ),
180                mode="rb",
181            )
182
183    @pytest.mark.parametrize(
184        ("key_path", "password"),
185        [
186            (["DER_Serialization", "ec_private_key.der"], None),
187            (["DER_Serialization", "ec_private_key_encrypted.der"], b"123456"),
188        ],
189    )
190    @pytest.mark.requires_backend_interface(interface=EllipticCurveBackend)
191    def test_load_der_ec_private_key(self, key_path, password, backend):
192        _skip_curve_unsupported(backend, ec.SECP256R1())
193        key = load_vectors_from_file(
194            os.path.join("asymmetric", *key_path),
195            lambda derfile: load_der_private_key(
196                derfile.read(), password, backend
197            ),
198            mode="rb",
199        )
200
201        assert key
202        assert isinstance(key, ec.EllipticCurvePrivateKey)
203        assert key.curve.name == "secp256r1"
204        assert key.curve.key_size == 256
205
206    @pytest.mark.parametrize(
207        "key_path", [["DER_Serialization", "enc-rsa-pkcs8.der"]]
208    )
209    @pytest.mark.requires_backend_interface(interface=RSABackend)
210    def test_wrong_password(self, key_path, backend):
211        key_file = os.path.join("asymmetric", *key_path)
212        password = b"this password is wrong"
213
214        with pytest.raises(ValueError):
215            load_vectors_from_file(
216                key_file,
217                lambda derfile: load_der_private_key(
218                    derfile.read(), password, backend
219                ),
220                mode="rb",
221            )
222
223    @pytest.mark.parametrize(
224        "key_path", [["DER_Serialization", "unenc-rsa-pkcs8.der"]]
225    )
226    @pytest.mark.requires_backend_interface(interface=RSABackend)
227    def test_unused_password(self, key_path, backend):
228        key_file = os.path.join("asymmetric", *key_path)
229        password = b"this password will not be used"
230
231        with pytest.raises(TypeError):
232            load_vectors_from_file(
233                key_file,
234                lambda derfile: load_der_private_key(
235                    derfile.read(), password, backend
236                ),
237                mode="rb",
238            )
239
240    @pytest.mark.parametrize(
241        ("key_path", "password"),
242        itertools.product(
243            [["DER_Serialization", "enc-rsa-pkcs8.der"]], [b"", None]
244        ),
245    )
246    @pytest.mark.requires_backend_interface(interface=RSABackend)
247    def test_missing_password(self, key_path, password, backend):
248        key_file = os.path.join("asymmetric", *key_path)
249
250        with pytest.raises(TypeError):
251            load_vectors_from_file(
252                key_file,
253                lambda derfile: load_der_private_key(
254                    derfile.read(), password, backend
255                ),
256                mode="rb",
257            )
258
259    def test_wrong_format(self, backend):
260        key_data = b"---- NOT A KEY ----\n"
261
262        with pytest.raises(ValueError):
263            load_der_private_key(key_data, None, backend)
264
265        with pytest.raises(ValueError):
266            load_der_private_key(
267                key_data, b"this password will not be used", backend
268            )
269
270    def test_corrupt_der_pkcs8(self, backend):
271        # unenc-rsa-pkcs8 with a bunch of data missing.
272        key_data = textwrap.dedent(
273            """\
274        MIICdQIBADALBgkqhkiG9w0BAQEEggJhMIICXQIBAAKBgQC7JHoJfg6yNzLMOWet
275        8Z49a4KD0dCspMAYvo2YAMB7/wdEycocujbhJ2n/seONi+5XqTqqFkM5VBl8rmkk
276        FPZk/7x0xmdsTPECSWnHK+HhoaNDFPR3j8jQhVo1laxiqcEhAHegi5cwtFosuJAv
277        FiRC0Cgz+frQPFQEBsAV9RuasyQxqzxrR0Ow0qncBeGBWbYE6WZhqtcLAI895b+i
278        +F4lbB4iD7T9QeIDMU/aIMXA81UO4cns1z4qDAHKeyLLrPQrJ/B4X7XC+egUWm5+
279        hr1qmyAMusyXIBECQQDJWZ8piluf4yrYfsJAn6hF5T4RjTztbqvO0GVG2McHY7Uj
280        NPSffhzHx/ll0fQEQji+OgydCCX8o3HZrgw5YfSJAkEA7e+rqdU5nO5ZG//PSEQb
281        tjLnRiTzBH/elQhtdZ5nF7pcpNTi4k13zutmKcWW4GK75azcRGJUhu1kDM7QYAOd
282        SQJAVNkYcifkvna7GmooL5VYEsQsqLbM4v0NF2TIGNfG3z1MGp75KrC5LhL97MNR
283        we2p/bd2k0HYyCKUGnf2nMPDiQJBAI75pwittSoE240EobUGIDTSz8CJsXIxuDmL
284        z+KOpdpPRR5TQmbEMEspjsFpFymMiuYPgmihQbO2cJl1qScY5OkCQQCJ6m5tcN8l
285        Xxg/SNpjEIv+qAyUD96XVlOJlOIeLHQ8kYE0C6ZA+MsqYIzgAreJk88Yn0lU/X0/
286        mu/UpE/BRZmR
287        """
288        ).encode()
289        bad_der = base64.b64decode(b"".join(key_data.splitlines()))
290
291        with pytest.raises(ValueError):
292            load_der_private_key(bad_der, None, backend)
293
294        with pytest.raises(ValueError):
295            load_der_private_key(
296                bad_der, b"this password will not be used", backend
297            )
298
299    def test_corrupt_traditional_format_der(self, backend):
300        # privkey with a bunch of data missing.
301        key_data = textwrap.dedent(
302            """\
303        MIIBPAIBAAJBAKrbeqkuRk8VcRmWFmtP+LviMB3+6dizWW3DwaffznyHGAFwUJ/I
304        Tv0XtbsCyl3QoyKGhrOAy3RvPK5M38iuXT0CAwEAAQJAZ3cnzaHXM/bxGaR5CR1R
305        rD1qFBAVfoQFiOH9uPJgMaoAuoQEisPHVcZDKcOv4wEg6/TInAIXBnEigtqvRzuy
306        mvcpHZwQJdmdHHkGKAs37Dfxi67HbkUCIQCeZGliHXFa071Fp06ZeWlR2ADonTZz
307        rJBhdTe0v5pCeQIhAIZfkiGgGBX4cIuuckzEm43g9WMUjxP/0GlK39vIyihxAiEA
308        mymehFRT0MvqW5xAKAx7Pgkt8HVKwVhc2LwGKHE0DZM=
309        """
310        ).encode()
311        bad_der = base64.b64decode(b"".join(key_data.splitlines()))
312
313        with pytest.raises(ValueError):
314            load_pem_private_key(bad_der, None, backend)
315
316        with pytest.raises(ValueError):
317            load_pem_private_key(
318                bad_der, b"this password will not be used", backend
319            )
320
321    @pytest.mark.parametrize(
322        "key_file",
323        [
324            os.path.join(
325                "asymmetric", "DER_Serialization", "unenc-rsa-pkcs8.pub.der"
326            ),
327            os.path.join(
328                "asymmetric", "DER_Serialization", "rsa_public_key.der"
329            ),
330            os.path.join("asymmetric", "public", "PKCS1", "rsa.pub.der"),
331        ],
332    )
333    @pytest.mark.requires_backend_interface(interface=RSABackend)
334    def test_load_der_rsa_public_key(self, key_file, backend):
335        key = load_vectors_from_file(
336            key_file,
337            lambda derfile: load_der_public_key(derfile.read(), backend),
338            mode="rb",
339        )
340        assert key
341        assert isinstance(key, rsa.RSAPublicKey)
342        numbers = key.public_numbers()
343        assert numbers.e == 65537
344
345    def test_load_der_invalid_public_key(self, backend):
346        with pytest.raises(ValueError):
347            load_der_public_key(b"invalid data", backend)
348
349    @pytest.mark.parametrize(
350        "key_file",
351        [
352            os.path.join(
353                "asymmetric", "DER_Serialization", "unenc-dsa-pkcs8.pub.der"
354            ),
355            os.path.join(
356                "asymmetric", "DER_Serialization", "dsa_public_key.der"
357            ),
358        ],
359    )
360    @pytest.mark.requires_backend_interface(interface=DSABackend)
361    def test_load_der_dsa_public_key(self, key_file, backend):
362        key = load_vectors_from_file(
363            key_file,
364            lambda derfile: load_der_public_key(derfile.read(), backend),
365            mode="rb",
366        )
367        assert key
368        assert isinstance(key, dsa.DSAPublicKey)
369
370    @pytest.mark.requires_backend_interface(interface=EllipticCurveBackend)
371    def test_load_ec_public_key(self, backend):
372        _skip_curve_unsupported(backend, ec.SECP256R1())
373        key = load_vectors_from_file(
374            os.path.join(
375                "asymmetric", "DER_Serialization", "ec_public_key.der"
376            ),
377            lambda derfile: load_der_public_key(derfile.read(), backend),
378            mode="rb",
379        )
380        assert key
381        assert isinstance(key, ec.EllipticCurvePublicKey)
382        assert key.curve.name == "secp256r1"
383        assert key.curve.key_size == 256
384
385    def test_wrong_parameters_format(self, backend):
386        param_data = b"---- NOT A KEY ----\n"
387
388        with pytest.raises(ValueError):
389            load_der_parameters(param_data, backend)
390
391
392@pytest.mark.requires_backend_interface(interface=PEMSerializationBackend)
393class TestPEMSerialization(object):
394    @pytest.mark.parametrize(
395        ("key_file", "password"),
396        [
397            (["PEM_Serialization", "rsa_private_key.pem"], b"123456"),
398            (["PKCS8", "unenc-rsa-pkcs8.pem"], None),
399            (["PKCS8", "enc-rsa-pkcs8.pem"], b"foobar"),
400            (["PKCS8", "enc2-rsa-pkcs8.pem"], b"baz"),
401            (["PKCS8", "pkcs12_s2k_pem-X_9607.pem"], b"123456"),
402            (["PKCS8", "pkcs12_s2k_pem-X_9671.pem"], b"123456"),
403            (["PKCS8", "pkcs12_s2k_pem-X_9925.pem"], b"123456"),
404            (["PKCS8", "pkcs12_s2k_pem-X_9926.pem"], b"123456"),
405            (["PKCS8", "pkcs12_s2k_pem-X_9927.pem"], b"123456"),
406            (["PKCS8", "pkcs12_s2k_pem-X_9928.pem"], b"123456"),
407            (["PKCS8", "pkcs12_s2k_pem-X_9929.pem"], b"123456"),
408            (["PKCS8", "pkcs12_s2k_pem-X_9930.pem"], b"123456"),
409            (["PKCS8", "pkcs12_s2k_pem-X_9931.pem"], b"123456"),
410            (["PKCS8", "pkcs12_s2k_pem-X_9932.pem"], b"123456"),
411            (["Traditional_OpenSSL_Serialization", "key1.pem"], b"123456"),
412            (["Traditional_OpenSSL_Serialization", "key2.pem"], b"a123456"),
413            (["Traditional_OpenSSL_Serialization", "testrsa.pem"], None),
414            (
415                ["Traditional_OpenSSL_Serialization", "testrsa-encrypted.pem"],
416                b"password",
417            ),
418        ],
419    )
420    def test_load_pem_rsa_private_key(self, key_file, password, backend):
421        _skip_fips_format(key_file, password, backend)
422        key = load_vectors_from_file(
423            os.path.join("asymmetric", *key_file),
424            lambda pemfile: load_pem_private_key(
425                pemfile.read().encode(), password, backend
426            ),
427        )
428
429        assert key
430        assert isinstance(key, rsa.RSAPrivateKey)
431        _check_rsa_private_numbers(key.private_numbers())
432
433    @pytest.mark.parametrize(
434        ("key_path", "password"),
435        [
436            (["Traditional_OpenSSL_Serialization", "dsa.1024.pem"], None),
437            (["Traditional_OpenSSL_Serialization", "dsa.2048.pem"], None),
438            (["Traditional_OpenSSL_Serialization", "dsa.3072.pem"], None),
439            (["PKCS8", "unenc-dsa-pkcs8.pem"], None),
440            (["PEM_Serialization", "dsa_private_key.pem"], b"123456"),
441        ],
442    )
443    def test_load_dsa_private_key(self, key_path, password, backend):
444        _skip_fips_format(key_path, password, backend)
445        key = load_vectors_from_file(
446            os.path.join("asymmetric", *key_path),
447            lambda pemfile: load_pem_private_key(
448                pemfile.read().encode(), password, backend
449            ),
450        )
451        assert key
452        assert isinstance(key, dsa.DSAPrivateKey)
453        _check_dsa_private_numbers(key.private_numbers())
454
455    @pytest.mark.parametrize(
456        ("key_path", "password"),
457        [
458            (["PKCS8", "ec_private_key.pem"], None),
459            (["PKCS8", "ec_private_key_encrypted.pem"], b"123456"),
460            (["PEM_Serialization", "ec_private_key.pem"], None),
461            (["PEM_Serialization", "ec_private_key_encrypted.pem"], b"123456"),
462        ],
463    )
464    @pytest.mark.requires_backend_interface(interface=EllipticCurveBackend)
465    def test_load_pem_ec_private_key(self, key_path, password, backend):
466        _skip_curve_unsupported(backend, ec.SECP256R1())
467        _skip_fips_format(key_path, password, backend)
468        key = load_vectors_from_file(
469            os.path.join("asymmetric", *key_path),
470            lambda pemfile: load_pem_private_key(
471                pemfile.read().encode(), password, backend
472            ),
473        )
474
475        assert key
476        assert isinstance(key, ec.EllipticCurvePrivateKey)
477        assert key.curve.name == "secp256r1"
478        assert key.curve.key_size == 256
479
480    @pytest.mark.parametrize(
481        ("key_file"),
482        [
483            os.path.join("asymmetric", "PKCS8", "unenc-rsa-pkcs8.pub.pem"),
484            os.path.join(
485                "asymmetric", "PEM_Serialization", "rsa_public_key.pem"
486            ),
487            os.path.join("asymmetric", "public", "PKCS1", "rsa.pub.pem"),
488        ],
489    )
490    def test_load_pem_rsa_public_key(self, key_file, backend):
491        key = load_vectors_from_file(
492            key_file,
493            lambda pemfile: load_pem_public_key(
494                pemfile.read().encode(), backend
495            ),
496        )
497        assert key
498        assert isinstance(key, rsa.RSAPublicKey)
499        numbers = key.public_numbers()
500        assert numbers.e == 65537
501
502    @pytest.mark.parametrize(
503        ("key_file"),
504        [
505            os.path.join("asymmetric", "PKCS8", "unenc-dsa-pkcs8.pub.pem"),
506            os.path.join(
507                "asymmetric", "PEM_Serialization", "dsa_public_key.pem"
508            ),
509        ],
510    )
511    def test_load_pem_dsa_public_key(self, key_file, backend):
512        key = load_vectors_from_file(
513            key_file,
514            lambda pemfile: load_pem_public_key(
515                pemfile.read().encode(), backend
516            ),
517        )
518        assert key
519        assert isinstance(key, dsa.DSAPublicKey)
520
521    @pytest.mark.requires_backend_interface(interface=EllipticCurveBackend)
522    def test_load_ec_public_key(self, backend):
523        _skip_curve_unsupported(backend, ec.SECP256R1())
524        key = load_vectors_from_file(
525            os.path.join(
526                "asymmetric", "PEM_Serialization", "ec_public_key.pem"
527            ),
528            lambda pemfile: load_pem_public_key(
529                pemfile.read().encode(), backend
530            ),
531        )
532        assert key
533        assert isinstance(key, ec.EllipticCurvePublicKey)
534        assert key.curve.name == "secp256r1"
535        assert key.curve.key_size == 256
536
537    @pytest.mark.skip_fips(
538        reason="Traditional OpenSSL format blocked in FIPS mode"
539    )
540    def test_rsa_traditional_encrypted_values(self, backend):
541        pkey = load_vectors_from_file(
542            os.path.join(
543                "asymmetric", "Traditional_OpenSSL_Serialization", "key1.pem"
544            ),
545            lambda pemfile: load_pem_private_key(
546                pemfile.read().encode(), b"123456", backend
547            ),
548        )
549        assert pkey
550
551        numbers = pkey.private_numbers()
552        assert numbers.p == int(
553            "fb7d316fc51531b36d93adaefaf52db6ad5beb793d37c4cf9dfc1ddd17cfbafb",
554            16,
555        )
556        assert numbers.q == int(
557            "df98264e646de9a0fbeab094e31caad5bc7adceaaae3c800ca0275dd4bb307f5",
558            16,
559        )
560        assert numbers.d == int(
561            "db4848c36f478dd5d38f35ae519643b6b810d404bcb76c00e44015e56ca1cab0"
562            "7bb7ae91f6b4b43fcfc82a47d7ed55b8c575152116994c2ce5325ec24313b911",
563            16,
564        )
565        assert numbers.dmp1 == int(
566            "ce997f967192c2bcc3853186f1559fd355c190c58ddc15cbf5de9b6df954c727",
567            16,
568        )
569        assert numbers.dmq1 == int(
570            "b018a57ab20ffaa3862435445d863369b852cf70a67c55058213e3fe10e3848d",
571            16,
572        )
573        assert numbers.iqmp == int(
574            "6a8d830616924f5cf2d1bc1973f97fde6b63e052222ac7be06aa2532d10bac76",
575            16,
576        )
577        assert numbers.public_numbers.e == 65537
578        assert numbers.public_numbers.n == int(
579            "dba786074f2f0350ce1d99f5aed5b520cfe0deb5429ec8f2a88563763f566e77"
580            "9814b7c310e5326edae31198eed439b845dd2db99eaa60f5c16a43f4be6bcf37",
581            16,
582        )
583
584    @pytest.mark.parametrize(
585        "key_path",
586        [
587            ["Traditional_OpenSSL_Serialization", "testrsa.pem"],
588            ["PKCS8", "unenc-rsa-pkcs8.pem"],
589        ],
590    )
591    def test_unused_password(self, key_path, backend):
592        key_file = os.path.join("asymmetric", *key_path)
593        password = b"this password will not be used"
594
595        with pytest.raises(TypeError):
596            load_vectors_from_file(
597                key_file,
598                lambda pemfile: load_pem_private_key(
599                    pemfile.read().encode(), password, backend
600                ),
601            )
602
603    def test_invalid_encoding_with_traditional(self, backend):
604        key_file = os.path.join(
605            "asymmetric", "Traditional_OpenSSL_Serialization", "testrsa.pem"
606        )
607        key = load_vectors_from_file(
608            key_file,
609            lambda pemfile: load_pem_private_key(
610                pemfile.read(), None, backend
611            ),
612            mode="rb",
613        )
614
615        for enc in (Encoding.OpenSSH, Encoding.Raw, Encoding.X962):
616            with pytest.raises(ValueError):
617                key.private_bytes(
618                    enc, PrivateFormat.TraditionalOpenSSL, NoEncryption()
619                )
620
621    @pytest.mark.parametrize(
622        "key_path",
623        [
624            ["Traditional_OpenSSL_Serialization", "testrsa-encrypted.pem"],
625            ["PKCS8", "enc-rsa-pkcs8.pem"],
626        ],
627    )
628    def test_password_not_bytes(self, key_path, backend):
629        key_file = os.path.join("asymmetric", *key_path)
630        password = u"this password is not bytes"
631
632        with pytest.raises(TypeError):
633            load_vectors_from_file(
634                key_file,
635                lambda pemfile: load_pem_private_key(
636                    pemfile.read().encode(), password, backend
637                ),
638            )
639
640    @pytest.mark.parametrize(
641        "key_path",
642        [
643            ["Traditional_OpenSSL_Serialization", "testrsa-encrypted.pem"],
644            ["PKCS8", "enc-rsa-pkcs8.pem"],
645        ],
646    )
647    def test_wrong_password(self, key_path, backend):
648        key_file = os.path.join("asymmetric", *key_path)
649        password = b"this password is wrong"
650
651        with pytest.raises(ValueError):
652            load_vectors_from_file(
653                key_file,
654                lambda pemfile: load_pem_private_key(
655                    pemfile.read().encode(), password, backend
656                ),
657            )
658
659    @pytest.mark.parametrize(
660        ("key_path", "password"),
661        itertools.product(
662            [
663                ["Traditional_OpenSSL_Serialization", "testrsa-encrypted.pem"],
664                ["PKCS8", "enc-rsa-pkcs8.pem"],
665            ],
666            [b"", None],
667        ),
668    )
669    def test_missing_password(self, key_path, password, backend):
670        key_file = os.path.join("asymmetric", *key_path)
671
672        with pytest.raises(TypeError):
673            load_vectors_from_file(
674                key_file,
675                lambda pemfile: load_pem_private_key(
676                    pemfile.read().encode(), password, backend
677                ),
678            )
679
680    def test_wrong_private_format(self, backend):
681        key_data = b"---- NOT A KEY ----\n"
682
683        with pytest.raises(ValueError):
684            load_pem_private_key(key_data, None, backend)
685
686        with pytest.raises(ValueError):
687            load_pem_private_key(
688                key_data, b"this password will not be used", backend
689            )
690
691    def test_wrong_public_format(self, backend):
692        key_data = b"---- NOT A KEY ----\n"
693
694        with pytest.raises(ValueError):
695            load_pem_public_key(key_data, backend)
696
697    def test_wrong_parameters_format(self, backend):
698        param_data = b"---- NOT A KEY ----\n"
699
700        with pytest.raises(ValueError):
701            load_pem_parameters(param_data, backend)
702
703    def test_corrupt_traditional_format(self, backend):
704        # privkey.pem with a bunch of data missing.
705        key_data = textwrap.dedent(
706            """\
707        -----BEGIN RSA PRIVATE KEY-----
708        MIIBPAIBAAJBAKrbeqkuRk8VcRmWFmtP+LviMB3+6dizWW3DwaffznyHGAFwUJ/I
709        Tv0XtbsCyl3QoyKGhrOAy3RvPK5M38iuXT0CAwEAAQJAZ3cnzaHXM/bxGaR5CR1R
710        rD1qFBAVfoQFiOH9uPJgMaoAuoQEisPHVcZDKcOv4wEg6/TInAIXBnEigtqvRzuy
711        mvcpHZwQJdmdHHkGKAs37Dfxi67HbkUCIQCeZGliHXFa071Fp06ZeWlR2ADonTZz
712        rJBhdTe0v5pCeQIhAIZfkiGgGBX4cIuuckzEm43g9WMUjxP/0GlK39vIyihxAiEA
713        mymehFRT0MvqW5xAKAx7Pgkt8HVKwVhc2LwGKHE0DZM=
714        -----END RSA PRIVATE KEY-----
715        """
716        ).encode()
717
718        with pytest.raises(ValueError):
719            load_pem_private_key(key_data, None, backend)
720
721        with pytest.raises(ValueError):
722            load_pem_private_key(
723                key_data, b"this password will not be used", backend
724            )
725
726    def test_traditional_encrypted_corrupt_format(self, backend):
727        # privkey.pem with a single bit flipped
728        key_data = textwrap.dedent(
729            """\
730        -----BEGIN RSA PRIVATE KEY-----
731        Proc-Type: <,ENCRYPTED
732        DEK-Info: AES-128-CBC,5E22A2BD85A653FB7A3ED20DE84F54CD
733
734        hAqtb5ZkTMGcs4BBDQ1SKZzdQThWRDzEDxM3qBfjvYa35KxZ54aic013mW/lwj2I
735        v5bbpOjrHYHNAiZYZ7RNb+ztbF6F/g5PA5g7mFwEq+LFBY0InIplYBSv9QtE+lot
736        Dy4AlZa/+NzJwgdKDb+JVfk5SddyD4ywnyeORnMPy4xXKvjXwmW+iLibZVKsjIgw
737        H8hSxcD+FhWyJm9h9uLtmpuqhQo0jTUYpnTezZx2xeVPB53Ev7YCxR9Nsgj5GsVf
738        9Z/hqLB7IFgM3pa0z3PQeUIZF/cEf72fISWIOBwwkzVrPUkXWfbuWeJXQXSs3amE
739        5A295jD9BQp9CY0nNFSsy+qiXWToq2xT3y5zVNEStmN0SCGNaIlUnJzL9IHW+oMI
740        kPmXZMnAYBWeeCF1gf3J3aE5lZInegHNfEI0+J0LazC2aNU5Dg/BNqrmRqKWEIo/
741        -----END RSA PRIVATE KEY-----
742        """
743        ).encode()
744
745        password = b"this password is wrong"
746
747        with pytest.raises(ValueError):
748            load_pem_private_key(key_data, None, backend)
749
750        with pytest.raises(ValueError):
751            load_pem_private_key(key_data, password, backend)
752
753    def test_unsupported_key_encryption(self, backend):
754        key_data = textwrap.dedent(
755            """\
756        -----BEGIN RSA PRIVATE KEY-----
757        Proc-Type: 4,ENCRYPTED
758        DEK-Info: FAKE-123,5E22A2BD85A653FB7A3ED20DE84F54CD
759
760        hAqtb5ZkTMGcs4BBDQ1SKZzdQThWRDzEDxM3qBfjvYa35KxZ54aic013mW/lwj2I
761        v5bbpOjrHYHNAiZYZ7RNb+ztbF6F/g5PA5g7mFwEq+LFBY0InIplYBSv9QtE+lot
762        Dy4AlZa/+NzJwgdKDb+JVfk5SddyD4ywnyeORnMPy4xXKvjXwmW+iLibZVKsjIgw
763        H8hSxcD+FhWyJm9h9uLtmpuqhQo0jTUYpnTezZx2xeVPB53Ev7YCxR9Nsgj5GsVf
764        9Z/hqLB7IFgM3pa0z3PQeUIZF/cEf72fISWIOBwwkzVrPUkXWfbuWeJXQXSs3amE
765        5A295jD9BQp9CY0nNFSsy+qiXWToq2xT3y5zVNEStmN0SCGNaIlUnJzL9IHW+oMI
766        kPmXZMnAYBWeeCF1gf3J3aE5lZInegHNfEI0+J0LazC2aNU5Dg/BNqrmRqKWEIo/
767        -----END RSA PRIVATE KEY-----
768        """
769        ).encode()
770
771        password = b"password"
772
773        with pytest.raises(ValueError):
774            load_pem_private_key(key_data, password, backend)
775
776    def test_corrupt_pkcs8_format(self, backend):
777        # unenc-rsa-pkcs8.pem with a bunch of data missing.
778        key_data = textwrap.dedent(
779            """\
780        -----BEGIN PRIVATE KEY-----
781        MIICdQIBADALBgkqhkiG9w0BAQEEggJhMIICXQIBAAKBgQC7JHoJfg6yNzLMOWet
782        8Z49a4KD0dCspMAYvo2YAMB7/wdEycocujbhJ2n/seONi+5XqTqqFkM5VBl8rmkk
783        FPZk/7x0xmdsTPECSWnHK+HhoaNDFPR3j8jQhVo1laxiqcEhAHegi5cwtFosuJAv
784        FiRC0Cgz+frQPFQEBsAV9RuasyQxqzxrR0Ow0qncBeGBWbYE6WZhqtcLAI895b+i
785        +F4lbB4iD7T9QeIDMU/aIMXA81UO4cns1z4qDAHKeyLLrPQrJ/B4X7XC+egUWm5+
786        hr1qmyAMusyXIBECQQDJWZ8piluf4yrYfsJAn6hF5T4RjTztbqvO0GVG2McHY7Uj
787        NPSffhzHx/ll0fQEQji+OgydCCX8o3HZrgw5YfSJAkEA7e+rqdU5nO5ZG//PSEQb
788        tjLnRiTzBH/elQhtdZ5nF7pcpNTi4k13zutmKcWW4GK75azcRGJUhu1kDM7QYAOd
789        SQJAVNkYcifkvna7GmooL5VYEsQsqLbM4v0NF2TIGNfG3z1MGp75KrC5LhL97MNR
790        we2p/bd2k0HYyCKUGnf2nMPDiQJBAI75pwittSoE240EobUGIDTSz8CJsXIxuDmL
791        z+KOpdpPRR5TQmbEMEspjsFpFymMiuYPgmihQbO2cJl1qScY5OkCQQCJ6m5tcN8l
792        Xxg/SNpjEIv+qAyUD96XVlOJlOIeLHQ8kYE0C6ZA+MsqYIzgAreJk88Yn0lU/X0/
793        mu/UpE/BRZmR
794        -----END PRIVATE KEY-----
795        """
796        ).encode()
797
798        with pytest.raises(ValueError):
799            load_pem_private_key(key_data, None, backend)
800
801        with pytest.raises(ValueError):
802            load_pem_private_key(
803                key_data, b"this password will not be used", backend
804            )
805
806    def test_pks8_encrypted_corrupt_format(self, backend):
807        # enc-rsa-pkcs8.pem with some bits flipped.
808        key_data = textwrap.dedent(
809            """\
810        -----BEGIN ENCRYPTED PRIVATE KEY-----
811        MIICojAcBgoqhkiG9w0BDAEDMA4ECHK0M0+QuEL9AgIBIcSCAoDRq+KRY+0XP0tO
812        lwBTzViiXSXoyNnKAZKt5r5K/fGNntv22g/1s/ZNCetrqsJDC5eMUPPacz06jFq/
813        Ipsep4/OgjQ9UAOzXNrWEoNyrHnWDo7usgD3CW0mKyqER4+wG0adVMbt3N+CJHGB
814        85jzRmQTfkdx1rSWeSx+XyswHn8ER4+hQ+omKWMVm7AFkjjmP/KnhUnLT98J8rhU
815        ArQoFPHz/6HVkypFccNaPPNg6IA4aS2A+TU9vJYOaXSVfFB2yf99hfYYzC+ukmuU
816        5Lun0cysK5s/5uSwDueUmDQKspnaNyiaMGDxvw8hilJc7vg0fGObfnbIpizhxJwq
817        gKBfR7Zt0Hv8OYi1He4MehfMGdbHskztF+yQ40LplBGXQrvAqpU4zShga1BoQ98T
818        0ekbBmqj7hg47VFsppXR7DKhx7G7rpMmdKbFhAZVCjae7rRGpUtD52cpFdPhMyAX
819        huhMkoczwUW8B/rM4272lkHo6Br0yk/TQfTEGkvryflNVu6lniPTV151WV5U1M3o
820        3G3a44eDyt7Ln+WSOpWtbPQMTrpKhur6WXgJvrpa/m02oOGdvOlDsoOCgavgQMWg
821        7xKKL7620pHl7p7f/8tlE8q6vLXVvyNtAOgt/JAr2rgvrHaZSzDE0DwgCjBXEm+7
822        cVMVNkHod7bLQefVanVtWqPzbmr8f7gKeuGwWSG9oew/lN2hxcLEPJHAQlnLgx3P
823        0GdGjK9NvwA0EP2gYIeE4+UtSder7xQ7bVh25VB20R4TTIIs4aXXCVOoQPagnzaT
824        6JLgl8FrvdfjHwIvmSOO1YMNmILBq000Q8WDqyErBDs4hsvtO6VQ4LeqJj6gClX3
825        qeJNaJFu
826        -----END ENCRYPTED PRIVATE KEY-----
827        """
828        ).encode()
829
830        password = b"this password is wrong"
831
832        with pytest.raises(ValueError):
833            load_pem_private_key(key_data, None, backend)
834
835        with pytest.raises(ValueError):
836            load_pem_private_key(key_data, password, backend)
837
838    def test_rsa_pkcs8_encrypted_values(self, backend):
839        pkey = load_vectors_from_file(
840            os.path.join("asymmetric", "PKCS8", "enc-rsa-pkcs8.pem"),
841            lambda pemfile: load_pem_private_key(
842                pemfile.read().encode(), b"foobar", backend
843            ),
844        )
845        assert pkey
846
847        numbers = pkey.private_numbers()
848
849        assert numbers.public_numbers.n == int(
850            "00beec64d6db5760ac2fd4c971145641b9bd7f5c56558ece608795c79807"
851            "376a7fe5b19f95b35ca358ea5c8abd7ae051d49cd2f1e45969a1ae945460"
852            "3c14b278664a0e414ebc8913acb6203626985525e17a600611b028542dd0"
853            "562aad787fb4f1650aa318cdcff751e1b187cbf6785fbe164e9809491b95"
854            "dd68480567c99b1a57",
855            16,
856        )
857
858        assert numbers.public_numbers.e == 65537
859
860        assert numbers.d == int(
861            "0cfe316e9dc6b8817f4fcfd5ae38a0886f68f773b8a6db4c9e6d8703c599"
862            "f3d9785c3a2c09e4c8090909fb3721e19a3009ec21221523a729265707a5"
863            "8f13063671c42a4096cad378ef2510cb59e23071489d8893ac4934dd149f"
864            "34f2d094bea57f1c8027c3a77248ac9b91218737d0c3c3dfa7d7829e6977"
865            "cf7d995688c86c81",
866            16,
867        )
868
869        assert numbers.p == int(
870            "00db122ac857b2c0437d7616daa98e597bb75ca9ad3a47a70bec10c10036"
871            "03328794b225c8e3eee6ffd3fd6d2253d28e071fe27d629ab072faa14377"
872            "ce6118cb67",
873            16,
874        )
875
876        assert numbers.q == int(
877            "00df1b8aa8506fcbbbb9d00257f2975e38b33d2698fd0f37e82d7ef38c56"
878            "f21b6ced63c825383782a7115cfcc093300987dbd2853b518d1c8f26382a"
879            "2d2586d391",
880            16,
881        )
882
883        assert numbers.dmp1 == int(
884            "00be18aca13e60712fdf5daa85421eb10d86d654b269e1255656194fb0c4"
885            "2dd01a1070ea12c19f5c39e09587af02f7b1a1030d016a9ffabf3b36d699"
886            "ceaf38d9bf",
887            16,
888        )
889
890        assert numbers.dmq1 == int(
891            "71aa8978f90a0c050744b77cf1263725b203ac9f730606d8ae1d289dce4a"
892            "28b8d534e9ea347aeb808c73107e583eb80c546d2bddadcdb3c82693a4c1"
893            "3d863451",
894            16,
895        )
896
897        assert numbers.iqmp == int(
898            "136b7b1afac6e6279f71b24217b7083485a5e827d156024609dae39d48a6"
899            "bdb55af2f062cc4a3b077434e6fffad5faa29a2b5dba2bed3e4621e478c0"
900            "97ccfe7f",
901            16,
902        )
903
904    def test_load_pem_dsa_private_key(self, backend):
905        key = load_vectors_from_file(
906            os.path.join("asymmetric", "PKCS8", "unenc-dsa-pkcs8.pem"),
907            lambda pemfile: load_pem_private_key(
908                pemfile.read().encode(), None, backend
909            ),
910        )
911        assert key
912        assert isinstance(key, dsa.DSAPrivateKey)
913
914        params = key.parameters()
915        assert isinstance(params, dsa.DSAParameters)
916
917        num = key.private_numbers()
918        pub = num.public_numbers
919        parameter_numbers = pub.parameter_numbers
920        assert num.x == int("00a535a8e1d0d91beafc8bee1d9b2a3a8de3311203", 16)
921        assert pub.y == int(
922            "2b260ea97dc6a12ae932c640e7df3d8ff04a8a05a0324f8d5f1b23f15fa1"
923            "70ff3f42061124eff2586cb11b49a82dcdc1b90fc6a84fb10109cb67db5d"
924            "2da971aeaf17be5e37284563e4c64d9e5fc8480258b319f0de29d54d8350"
925            "70d9e287914d77df81491f4423b62da984eb3f45eb2a29fcea5dae525ac6"
926            "ab6bcce04bfdf5b6",
927            16,
928        )
929
930        assert parameter_numbers.p == int(
931            "00aa0930cc145825221caffa28ac2894196a27833de5ec21270791689420"
932            "7774a2e7b238b0d36f1b2499a2c2585083eb01432924418d867faa212dd1"
933            "071d4dceb2782794ad393cc08a4d4ada7f68d6e839a5fcd34b4e402d82cb"
934            "8a8cb40fec31911bf9bd360b034caacb4c5e947992573c9e90099c1b0f05"
935            "940cabe5d2de49a167",
936            16,
937        )
938
939        assert parameter_numbers.q == int(
940            "00adc0e869b36f0ac013a681fdf4d4899d69820451", 16
941        )
942
943        assert parameter_numbers.g == int(
944            "008c6b4589afa53a4d1048bfc346d1f386ca75521ccf72ddaa251286880e"
945            "e13201ff48890bbfc33d79bacaec71e7a778507bd5f1a66422e39415be03"
946            "e71141ba324f5b93131929182c88a9fa4062836066cebe74b5c6690c7d10"
947            "1106c240ab7ebd54e4e3301fd086ce6adac922fb2713a2b0887cba13b9bc"
948            "68ce5cfff241cd3246",
949            16,
950        )
951
952    @pytest.mark.parametrize(
953        ("key_file", "password"), [("bad-oid-dsa-key.pem", None)]
954    )
955    def test_load_bad_oid_key(self, key_file, password, backend):
956        with pytest.raises(ValueError):
957            load_vectors_from_file(
958                os.path.join("asymmetric", "PKCS8", key_file),
959                lambda pemfile: load_pem_private_key(
960                    pemfile.read().encode(), password, backend
961                ),
962            )
963
964    @pytest.mark.parametrize(
965        ("key_file", "password"), [("bad-encryption-oid.pem", b"password")]
966    )
967    def test_load_bad_encryption_oid_key(self, key_file, password, backend):
968        with pytest.raises(ValueError):
969            load_vectors_from_file(
970                os.path.join("asymmetric", "PKCS8", key_file),
971                lambda pemfile: load_pem_private_key(
972                    pemfile.read().encode(), password, backend
973                ),
974            )
975
976
977@pytest.mark.requires_backend_interface(interface=RSABackend)
978class TestRSASSHSerialization(object):
979    def test_load_ssh_public_key_unsupported(self, backend):
980        ssh_key = b"ecdsa-sha2-junk AAAAE2VjZHNhLXNoYTItbmlzdHAyNTY="
981
982        with pytest.raises(UnsupportedAlgorithm):
983            load_ssh_public_key(ssh_key, backend)
984
985    def test_load_ssh_public_key_bad_format(self, backend):
986        ssh_key = b"ssh-rsa not-a-real-key"
987
988        with pytest.raises(ValueError):
989            load_ssh_public_key(ssh_key, backend)
990
991    def test_load_ssh_public_key_rsa_too_short(self, backend):
992        ssh_key = b"ssh-rsa"
993
994        with pytest.raises(ValueError):
995            load_ssh_public_key(ssh_key, backend)
996
997    def test_load_ssh_public_key_truncated_int(self, backend):
998        ssh_key = b"ssh-rsa AAAAB3NzaC1yc2EAAAA="
999
1000        with pytest.raises(ValueError):
1001            load_ssh_public_key(ssh_key, backend)
1002
1003        ssh_key = b"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAACKr+IHXo"
1004
1005        with pytest.raises(ValueError):
1006            load_ssh_public_key(ssh_key, backend)
1007
1008    def test_load_ssh_public_key_rsa_comment_with_spaces(self, backend):
1009        ssh_key = (
1010            b"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDDu/XRP1kyK6Cgt36gts9XAk"
1011            b"FiiuJLW6RU0j3KKVZSs1I7Z3UmU9/9aVh/rZV43WQG8jaR6kkcP4stOR0DEtll"
1012            b"PDA7ZRBnrfiHpSQYQ874AZaAoIjgkv7DBfsE6gcDQLub0PFjWyrYQUJhtOLQEK"
1013            b"vY/G0vt2iRL3juawWmCFdTK3W3XvwAdgGk71i6lHt+deOPNEPN2H58E4odrZ2f"
1014            b"sxn/adpDqfb2sM0kPwQs0aWvrrKGvUaustkivQE4XWiSFnB0oJB/lKK/CKVKuy"
1015            b"///ImSCGHQRvhwariN2tvZ6CBNSLh3iQgeB0AkyJlng7MXB2qYq/Ci2FUOryCX"
1016            # Extra section appended
1017            b"2MzHvnbv testkey@localhost extra"
1018        )
1019
1020        load_ssh_public_key(ssh_key, backend)
1021
1022    def test_load_ssh_public_key_rsa_extra_data_after_modulo(self, backend):
1023        ssh_key = (
1024            b"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDDu/XRP1kyK6Cgt36gts9XAk"
1025            b"FiiuJLW6RU0j3KKVZSs1I7Z3UmU9/9aVh/rZV43WQG8jaR6kkcP4stOR0DEtll"
1026            b"PDA7ZRBnrfiHpSQYQ874AZaAoIjgkv7DBfsE6gcDQLub0PFjWyrYQUJhtOLQEK"
1027            b"vY/G0vt2iRL3juawWmCFdTK3W3XvwAdgGk71i6lHt+deOPNEPN2H58E4odrZ2f"
1028            b"sxn/adpDqfb2sM0kPwQs0aWvrrKGvUaustkivQE4XWiSFnB0oJB/lKK/CKVKuy"
1029            b"///ImSCGHQRvhwariN2tvZ6CBNSLh3iQgeB0AkyJlng7MXB2qYq/Ci2FUOryCX"
1030            b"2MzHvnbvAQ== testkey@localhost"
1031        )
1032
1033        with pytest.raises(ValueError):
1034            load_ssh_public_key(ssh_key, backend)
1035
1036    def test_load_ssh_public_key_rsa_different_string(self, backend):
1037        ssh_key = (
1038            # "AAAAB3NzA" the final A is capitalized here to cause the string
1039            # ssh-rsa inside the base64 encoded blob to be incorrect. It should
1040            # be a lower case 'a'.
1041            b"ssh-rsa AAAAB3NzAC1yc2EAAAADAQABAAABAQDDu/XRP1kyK6Cgt36gts9XAk"
1042            b"FiiuJLW6RU0j3KKVZSs1I7Z3UmU9/9aVh/rZV43WQG8jaR6kkcP4stOR0DEtll"
1043            b"PDA7ZRBnrfiHpSQYQ874AZaAoIjgkv7DBfsE6gcDQLub0PFjWyrYQUJhtOLQEK"
1044            b"vY/G0vt2iRL3juawWmCFdTK3W3XvwAdgGk71i6lHt+deOPNEPN2H58E4odrZ2f"
1045            b"sxn/adpDqfb2sM0kPwQs0aWvrrKGvUaustkivQE4XWiSFnB0oJB/lKK/CKVKuy"
1046            b"///ImSCGHQRvhwariN2tvZ6CBNSLh3iQgeB0AkyJlng7MXB2qYq/Ci2FUOryCX"
1047            b"2MzHvnbvAQ== testkey@localhost"
1048        )
1049        with pytest.raises(ValueError):
1050            load_ssh_public_key(ssh_key, backend)
1051
1052    def test_load_ssh_public_key_rsa(self, backend):
1053        ssh_key = (
1054            b"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDDu/XRP1kyK6Cgt36gts9XAk"
1055            b"FiiuJLW6RU0j3KKVZSs1I7Z3UmU9/9aVh/rZV43WQG8jaR6kkcP4stOR0DEtll"
1056            b"PDA7ZRBnrfiHpSQYQ874AZaAoIjgkv7DBfsE6gcDQLub0PFjWyrYQUJhtOLQEK"
1057            b"vY/G0vt2iRL3juawWmCFdTK3W3XvwAdgGk71i6lHt+deOPNEPN2H58E4odrZ2f"
1058            b"sxn/adpDqfb2sM0kPwQs0aWvrrKGvUaustkivQE4XWiSFnB0oJB/lKK/CKVKuy"
1059            b"///ImSCGHQRvhwariN2tvZ6CBNSLh3iQgeB0AkyJlng7MXB2qYq/Ci2FUOryCX"
1060            b"2MzHvnbv testkey@localhost"
1061        )
1062
1063        key = load_ssh_public_key(ssh_key, backend)
1064
1065        assert key is not None
1066        assert isinstance(key, rsa.RSAPublicKey)
1067
1068        numbers = key.public_numbers()
1069
1070        expected_e = 0x10001
1071        expected_n = int(
1072            "00C3BBF5D13F59322BA0A0B77EA0B6CF570241628AE24B5BA454D"
1073            "23DCA295652B3523B67752653DFFD69587FAD9578DD6406F23691"
1074            "EA491C3F8B2D391D0312D9653C303B651067ADF887A5241843CEF"
1075            "8019680A088E092FEC305FB04EA070340BB9BD0F1635B2AD84142"
1076            "61B4E2D010ABD8FC6D2FB768912F78EE6B05A60857532B75B75EF"
1077            "C007601A4EF58BA947B7E75E38F3443CDD87E7C138A1DAD9D9FB3"
1078            "19FF69DA43A9F6F6B0CD243F042CD1A5AFAEB286BD46AEB2D922B"
1079            "D01385D6892167074A0907F94A2BF08A54ABB2FFFFC89920861D0"
1080            "46F8706AB88DDADBD9E8204D48B87789081E074024C8996783B31"
1081            "7076A98ABF0A2D8550EAF2097D8CCC7BE76EF",
1082            16,
1083        )
1084
1085        expected = rsa.RSAPublicNumbers(expected_e, expected_n)
1086
1087        assert numbers == expected
1088
1089
1090@pytest.mark.requires_backend_interface(interface=DSABackend)
1091class TestDSSSSHSerialization(object):
1092    def test_load_ssh_public_key_dss_too_short(self, backend):
1093        ssh_key = b"ssh-dss"
1094
1095        with pytest.raises(ValueError):
1096            load_ssh_public_key(ssh_key, backend)
1097
1098    def test_load_ssh_public_key_dss_comment_with_spaces(self, backend):
1099        ssh_key = (
1100            b"ssh-dss AAAAB3NzaC1kc3MAAACBALmwUtfwdjAUjU2Dixd5DvT0NDcjjr69UD"
1101            b"LqSD/Xt5Al7D3GXr1WOrWGpjO0NE9qzRCvMTU7zykRH6XjuNXB6Hvv48Zfm4vm"
1102            b"nHQHFmmMg2bI75JbnOwdzWnnPZJrVU4rS23dFFPqs5ug+EbhVVrcwzxahjcSjJ"
1103            b"7WEQSkVQWnSPbbAAAAFQDXmpD3DIkGvLSBf1GdUF4PHKtUrQAAAIB/bJFwss+2"
1104            b"fngmfG/Li5OyL7A9iVoGdkUaFaxEUROTp7wkm2z49fXFAir+/U31v50Tu98YLf"
1105            b"WvKlxdHcdgQYV9Ww5LIrhWwwD4UKOwC6w5S3KHVbi3pWUi7vxJFXOWfeu1mC/J"
1106            b"TWqMKR91j+rmOtdppWIZRyIVIqLcMdGO3m+2VgAAAIANFDz5KQH5NvoljpoRQi"
1107            b"RgyPjxWXiE7vjLElKj4v8KrpanAywBzdhIW1y/tzpGuwRwj5ihi8iNTHgSsoTa"
1108            b"j5AG5HPomJf5vJElxpu/2O9pHA52wcNObIQ7j+JA5uWusxNIbl+pF6sSiP8abr"
1109            b"z53N7tPF/IhHTjBHb1Ol7IFu9p9A== testkey@localhost extra"
1110        )
1111
1112        load_ssh_public_key(ssh_key, backend)
1113
1114    def test_load_ssh_public_key_dss_extra_data_after_modulo(self, backend):
1115        ssh_key = (
1116            b"ssh-dss AAAAB3NzaC1kc3MAAACBALmwUtfwdjAUjU2Dixd5DvT0NDcjjr69UD"
1117            b"LqSD/Xt5Al7D3GXr1WOrWGpjO0NE9qzRCvMTU7zykRH6XjuNXB6Hvv48Zfm4vm"
1118            b"nHQHFmmMg2bI75JbnOwdzWnnPZJrVU4rS23dFFPqs5ug+EbhVVrcwzxahjcSjJ"
1119            b"7WEQSkVQWnSPbbAAAAFQDXmpD3DIkGvLSBf1GdUF4PHKtUrQAAAIB/bJFwss+2"
1120            b"fngmfG/Li5OyL7A9iVoGdkUaFaxEUROTp7wkm2z49fXFAir+/U31v50Tu98YLf"
1121            b"WvKlxdHcdgQYV9Ww5LIrhWwwD4UKOwC6w5S3KHVbi3pWUi7vxJFXOWfeu1mC/J"
1122            b"TWqMKR91j+rmOtdppWIZRyIVIqLcMdGO3m+2VgAAAIANFDz5KQH5NvoljpoRQi"
1123            b"RgyPjxWXiE7vjLElKj4v8KrpanAywBzdhIW1y/tzpGuwRwj5ihi8iNTHgSsoTa"
1124            b"j5AG5HPomJf5vJElxpu/2O9pHA52wcNObIQ7j+JA5uWusxNIbl+pF6sSiP8abr"
1125            b"z53N7tPF/IhHTjBHb1Ol7IFu9p9AAwMD== testkey@localhost"
1126        )
1127
1128        with pytest.raises(ValueError):
1129            load_ssh_public_key(ssh_key, backend)
1130
1131    def test_load_ssh_public_key_dss_different_string(self, backend):
1132        ssh_key = (
1133            # "AAAAB3NzA" the final A is capitalized here to cause the string
1134            # ssh-dss inside the base64 encoded blob to be incorrect. It should
1135            # be a lower case 'a'.
1136            b"ssh-dss AAAAB3NzAC1kc3MAAACBALmwUtfwdjAUjU2Dixd5DvT0NDcjjr69UD"
1137            b"LqSD/Xt5Al7D3GXr1WOrWGpjO0NE9qzRCvMTU7zykRH6XjuNXB6Hvv48Zfm4vm"
1138            b"nHQHFmmMg2bI75JbnOwdzWnnPZJrVU4rS23dFFPqs5ug+EbhVVrcwzxahjcSjJ"
1139            b"7WEQSkVQWnSPbbAAAAFQDXmpD3DIkGvLSBf1GdUF4PHKtUrQAAAIB/bJFwss+2"
1140            b"fngmfG/Li5OyL7A9iVoGdkUaFaxEUROTp7wkm2z49fXFAir+/U31v50Tu98YLf"
1141            b"WvKlxdHcdgQYV9Ww5LIrhWwwD4UKOwC6w5S3KHVbi3pWUi7vxJFXOWfeu1mC/J"
1142            b"TWqMKR91j+rmOtdppWIZRyIVIqLcMdGO3m+2VgAAAIANFDz5KQH5NvoljpoRQi"
1143            b"RgyPjxWXiE7vjLElKj4v8KrpanAywBzdhIW1y/tzpGuwRwj5ihi8iNTHgSsoTa"
1144            b"j5AG5HPomJf5vJElxpu/2O9pHA52wcNObIQ7j+JA5uWusxNIbl+pF6sSiP8abr"
1145            b"z53N7tPF/IhHTjBHb1Ol7IFu9p9A== testkey@localhost"
1146        )
1147        with pytest.raises(ValueError):
1148            load_ssh_public_key(ssh_key, backend)
1149
1150    def test_load_ssh_public_key_dss(self, backend):
1151        ssh_key = (
1152            b"ssh-dss AAAAB3NzaC1kc3MAAACBALmwUtfwdjAUjU2Dixd5DvT0NDcjjr69UD"
1153            b"LqSD/Xt5Al7D3GXr1WOrWGpjO0NE9qzRCvMTU7zykRH6XjuNXB6Hvv48Zfm4vm"
1154            b"nHQHFmmMg2bI75JbnOwdzWnnPZJrVU4rS23dFFPqs5ug+EbhVVrcwzxahjcSjJ"
1155            b"7WEQSkVQWnSPbbAAAAFQDXmpD3DIkGvLSBf1GdUF4PHKtUrQAAAIB/bJFwss+2"
1156            b"fngmfG/Li5OyL7A9iVoGdkUaFaxEUROTp7wkm2z49fXFAir+/U31v50Tu98YLf"
1157            b"WvKlxdHcdgQYV9Ww5LIrhWwwD4UKOwC6w5S3KHVbi3pWUi7vxJFXOWfeu1mC/J"
1158            b"TWqMKR91j+rmOtdppWIZRyIVIqLcMdGO3m+2VgAAAIANFDz5KQH5NvoljpoRQi"
1159            b"RgyPjxWXiE7vjLElKj4v8KrpanAywBzdhIW1y/tzpGuwRwj5ihi8iNTHgSsoTa"
1160            b"j5AG5HPomJf5vJElxpu/2O9pHA52wcNObIQ7j+JA5uWusxNIbl+pF6sSiP8abr"
1161            b"z53N7tPF/IhHTjBHb1Ol7IFu9p9A== testkey@localhost"
1162        )
1163
1164        key = load_ssh_public_key(ssh_key, backend)
1165
1166        assert key is not None
1167        assert isinstance(key, dsa.DSAPublicKey)
1168
1169        numbers = key.public_numbers()
1170
1171        expected_y = int(
1172            "d143cf92901f936fa258e9a11422460c8f8f1597884eef8cb1252a3e2ff0aae"
1173            "96a7032c01cdd8485b5cbfb73a46bb04708f98a18bc88d4c7812b284da8f900"
1174            "6e473e89897f9bc9125c69bbfd8ef691c0e76c1c34e6c843b8fe240e6e5aeb3"
1175            "13486e5fa917ab1288ff1a6ebcf9dcdeed3c5fc88474e30476f53a5ec816ef6"
1176            "9f4",
1177            16,
1178        )
1179        expected_p = int(
1180            "b9b052d7f07630148d4d838b17790ef4f43437238ebebd5032ea483fd7b7902"
1181            "5ec3dc65ebd563ab586a633b4344f6acd10af31353bcf29111fa5e3b8d5c1e8"
1182            "7befe3c65f9b8be69c740716698c8366c8ef925b9cec1dcd69e73d926b554e2"
1183            "b4b6ddd1453eab39ba0f846e1555adcc33c5a8637128c9ed61104a45505a748"
1184            "f6db",
1185            16,
1186        )
1187        expected_q = 1230879958723280233885494314531920096931919647917
1188        expected_g = int(
1189            "7f6c9170b2cfb67e78267c6fcb8b93b22fb03d895a0676451a15ac44511393a"
1190            "7bc249b6cf8f5f5c5022afefd4df5bf9d13bbdf182df5af2a5c5d1dc7604185"
1191            "7d5b0e4b22b856c300f850a3b00bac394b728755b8b7a56522eefc491573967"
1192            "debb5982fc94d6a8c291f758feae63ad769a5621947221522a2dc31d18ede6f"
1193            "b656",
1194            16,
1195        )
1196        expected = dsa.DSAPublicNumbers(
1197            expected_y,
1198            dsa.DSAParameterNumbers(expected_p, expected_q, expected_g),
1199        )
1200
1201        assert numbers == expected
1202
1203
1204@pytest.mark.requires_backend_interface(interface=EllipticCurveBackend)
1205class TestECDSASSHSerialization(object):
1206    def test_load_ssh_public_key_ecdsa_nist_p256(self, backend):
1207        _skip_curve_unsupported(backend, ec.SECP256R1())
1208
1209        ssh_key = (
1210            b"ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAy"
1211            b"NTYAAABBBGG2MfkHXp0UkxUyllDzWNBAImsvt5t7pFtTXegZK2WbGxml8zMrgWi5"
1212            b"teIg1TO03/FD9hbpBFgBeix3NrCFPls= root@cloud-server-01"
1213        )
1214        key = load_ssh_public_key(ssh_key, backend)
1215        assert isinstance(key, ec.EllipticCurvePublicKey)
1216
1217        expected_x = int(
1218            "44196257377740326295529888716212621920056478823906609851236662550"
1219            "785814128027",
1220            10,
1221        )
1222        expected_y = int(
1223            "12257763433170736656417248739355923610241609728032203358057767672"
1224            "925775019611",
1225            10,
1226        )
1227
1228        assert key.public_numbers() == ec.EllipticCurvePublicNumbers(
1229            expected_x, expected_y, ec.SECP256R1()
1230        )
1231
1232    def test_load_ssh_public_key_byteslike(self, backend):
1233        _skip_curve_unsupported(backend, ec.SECP256R1())
1234
1235        ssh_key = (
1236            b"ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAy"
1237            b"NTYAAABBBGG2MfkHXp0UkxUyllDzWNBAImsvt5t7pFtTXegZK2WbGxml8zMrgWi5"
1238            b"teIg1TO03/FD9hbpBFgBeix3NrCFPls= root@cloud-server-01"
1239        )
1240        assert load_ssh_public_key(bytearray(ssh_key), backend)
1241        if six.PY3:
1242            assert load_ssh_public_key(memoryview(ssh_key), backend)
1243            assert load_ssh_public_key(memoryview(bytearray(ssh_key)), backend)
1244
1245    def test_load_ssh_public_key_ecdsa_nist_p384(self, backend):
1246        _skip_curve_unsupported(backend, ec.SECP384R1())
1247        ssh_key = (
1248            b"ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAz"
1249            b"ODQAAABhBMzucOm9wbwg4iMr5QL0ya0XNQGXpw4wM5f12E3tWhdcrzyGHyel71t1"
1250            b"4bvF9JZ2/WIuSxUr33XDl8jYo+lMQ5N7Vanc7f7i3AR1YydatL3wQfZStQ1I3rBa"
1251            b"qQtRSEU8Tg== root@cloud-server-01"
1252        )
1253        key = load_ssh_public_key(ssh_key, backend)
1254
1255        expected_x = int(
1256            "31541830871345183397582554827482786756220448716666815789487537666"
1257            "592636882822352575507883817901562613492450642523901",
1258            10,
1259        )
1260        expected_y = int(
1261            "15111413269431823234030344298767984698884955023183354737123929430"
1262            "995703524272335782455051101616329050844273733614670",
1263            10,
1264        )
1265
1266        assert key.public_numbers() == ec.EllipticCurvePublicNumbers(
1267            expected_x, expected_y, ec.SECP384R1()
1268        )
1269
1270    def test_load_ssh_public_key_ecdsa_nist_p521(self, backend):
1271        _skip_curve_unsupported(backend, ec.SECP521R1())
1272        ssh_key = (
1273            b"ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1"
1274            b"MjEAAACFBAGTrRhMSEgF6Ni+PXNz+5fjS4lw3ypUILVVQ0Av+0hQxOx+MyozELon"
1275            b"I8NKbrbBjijEs1GuImsmkTmWsMXS1j2A7wB4Kseh7W9KA9IZJ1+TMrzWUEwvOOXi"
1276            b"wT23pbaWWXG4NaM7vssWfZBnvz3S174TCXnJ+DSccvWBFnKP0KchzLKxbg== "
1277            b"root@cloud-server-01"
1278        )
1279        key = load_ssh_public_key(ssh_key, backend)
1280
1281        expected_x = int(
1282            "54124123120178189598842622575230904027376313369742467279346415219"
1283            "77809037378785192537810367028427387173980786968395921877911964629"
1284            "142163122798974160187785455",
1285            10,
1286        )
1287        expected_y = int(
1288            "16111775122845033200938694062381820957441843014849125660011303579"
1289            "15284560361402515564433711416776946492019498546572162801954089916"
1290            "006665939539407104638103918",
1291            10,
1292        )
1293
1294        assert key.public_numbers() == ec.EllipticCurvePublicNumbers(
1295            expected_x, expected_y, ec.SECP521R1()
1296        )
1297
1298    def test_load_ssh_public_key_ecdsa_nist_p256_trailing_data(self, backend):
1299        ssh_key = (
1300            b"ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAy"
1301            b"NTYAAABBBGG2MfkHXp0UkxUyllDzWNBAImsvt5t7pFtTXegZK2WbGxml8zMrgWi5"
1302            b"teIg1TO03/FD9hbpBFgBeix3NrCFPltB= root@cloud-server-01"
1303        )
1304        with pytest.raises(ValueError):
1305            load_ssh_public_key(ssh_key, backend)
1306
1307    def test_load_ssh_public_key_ecdsa_nist_p256_missing_data(self, backend):
1308        ssh_key = (
1309            b"ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAy"
1310            b"NTYAAABBBGG2MfkHXp0UkxUyllDzWNBAImsvt5t7pFtTXegZK2WbGxml8zMrgWi5"
1311            b"teIg1TO03/FD9hbpBFgBeix3NrCF= root@cloud-server-01"
1312        )
1313        with pytest.raises(ValueError):
1314            load_ssh_public_key(ssh_key, backend)
1315
1316    def test_load_ssh_public_key_ecdsa_nist_p256_compressed(self, backend):
1317        # If we ever implement compressed points, note that this is not a valid
1318        # one, it just has the compressed marker in the right place.
1319        ssh_key = (
1320            b"ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAy"
1321            b"NTYAAABBAWG2MfkHXp0UkxUyllDzWNBAImsvt5t7pFtTXegZK2WbGxml8zMrgWi5"
1322            b"teIg1TO03/FD9hbpBFgBeix3NrCFPls= root@cloud-server-01"
1323        )
1324        with pytest.raises(NotImplementedError):
1325            load_ssh_public_key(ssh_key, backend)
1326
1327    def test_load_ssh_public_key_ecdsa_nist_p256_bad_curve_name(self, backend):
1328        ssh_key = (
1329            # The curve name in here is changed to be "nistp255".
1330            b"ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAy"
1331            b"NTUAAABBBGG2MfkHXp0UkxUyllDzWNBAImsvt5t7pFtTXegZK2WbGxml8zMrgWi5"
1332            b"teIg1TO03/FD9hbpBFgBeix3NrCFPls= root@cloud-server-01"
1333        )
1334        with pytest.raises(ValueError):
1335            load_ssh_public_key(ssh_key, backend)
1336
1337
1338@pytest.mark.supported(
1339    only_if=lambda backend: backend.ed25519_supported(),
1340    skip_message="Requires OpenSSL with Ed25519 support",
1341)
1342class TestEd25519SSHSerialization(object):
1343    def test_load_ssh_public_key(self, backend):
1344        ssh_key = (
1345            b"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIG2fgpmpYO61qeAxGd0wgRaN/E4"
1346            b"GR+xWvBmvxjxrB1vG user@chiron.local"
1347        )
1348        key = load_ssh_public_key(ssh_key, backend)
1349        assert isinstance(key, ed25519.Ed25519PublicKey)
1350        assert key.public_bytes(Encoding.Raw, PublicFormat.Raw) == (
1351            b"m\x9f\x82\x99\xa9`\xee\xb5\xa9\xe01\x19\xdd0\x81\x16\x8d\xfc"
1352            b"N\x06G\xecV\xbc\x19\xaf\xc6<k\x07[\xc6"
1353        )
1354
1355    def test_public_bytes_openssh(self, backend):
1356        ssh_key = (
1357            b"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIG2fgpmpYO61qeAxGd0wgRaN/E4"
1358            b"GR+xWvBmvxjxrB1vG"
1359        )
1360        key = load_ssh_public_key(ssh_key, backend)
1361        assert isinstance(key, ed25519.Ed25519PublicKey)
1362        assert (
1363            key.public_bytes(Encoding.OpenSSH, PublicFormat.OpenSSH) == ssh_key
1364        )
1365
1366    def test_load_ssh_public_key_not_32_bytes(self, backend):
1367        ssh_key = (
1368            b"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI22fgpmpYO61qeAxGd0wgRaN/E4"
1369            b"GR+xWvBmvxjxrB1vGaGVs user@chiron.local"
1370        )
1371        with pytest.raises(ValueError):
1372            load_ssh_public_key(ssh_key, backend)
1373
1374    def test_load_ssh_public_key_trailing_data(self, backend):
1375        ssh_key = (
1376            b"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIG2fgpmpYO61qeAxGd0wgRa"
1377            b"N/E4GR+xWvBmvxjxrB1vGdHJhaWxpbmdkYXRh user@chiron.local"
1378        )
1379        with pytest.raises(ValueError):
1380            load_ssh_public_key(ssh_key, backend)
1381
1382
1383class TestKeySerializationEncryptionTypes(object):
1384    def test_non_bytes_password(self):
1385        with pytest.raises(ValueError):
1386            BestAvailableEncryption(object())
1387
1388    def test_encryption_with_zero_length_password(self):
1389        with pytest.raises(ValueError):
1390            BestAvailableEncryption(b"")
1391
1392
1393@pytest.mark.supported(
1394    only_if=lambda backend: backend.ed25519_supported(),
1395    skip_message="Requires OpenSSL with Ed25519 support",
1396)
1397class TestEd25519Serialization(object):
1398    def test_load_der_private_key(self, backend):
1399        data = load_vectors_from_file(
1400            os.path.join("asymmetric", "Ed25519", "ed25519-pkcs8-enc.der"),
1401            lambda derfile: derfile.read(),
1402            mode="rb",
1403        )
1404        unencrypted = load_vectors_from_file(
1405            os.path.join("asymmetric", "Ed25519", "ed25519-pkcs8.der"),
1406            lambda derfile: derfile.read(),
1407            mode="rb",
1408        )
1409        key = load_der_private_key(data, b"password", backend)
1410        assert (
1411            key.private_bytes(
1412                Encoding.DER, PrivateFormat.PKCS8, NoEncryption()
1413            )
1414            == unencrypted
1415        )
1416
1417    def test_load_pem_private_key(self, backend):
1418        data = load_vectors_from_file(
1419            os.path.join("asymmetric", "Ed25519", "ed25519-pkcs8-enc.pem"),
1420            lambda pemfile: pemfile.read(),
1421            mode="rb",
1422        )
1423        unencrypted = load_vectors_from_file(
1424            os.path.join("asymmetric", "Ed25519", "ed25519-pkcs8.pem"),
1425            lambda pemfile: pemfile.read(),
1426            mode="rb",
1427        )
1428        key = load_pem_private_key(data, b"password", backend)
1429        assert (
1430            key.private_bytes(
1431                Encoding.PEM, PrivateFormat.PKCS8, NoEncryption()
1432            )
1433            == unencrypted
1434        )
1435
1436    @pytest.mark.parametrize(
1437        ("key_path", "encoding", "loader"),
1438        [
1439            (
1440                ["Ed25519", "ed25519-pub.pem"],
1441                Encoding.PEM,
1442                load_pem_public_key,
1443            ),
1444            (
1445                ["Ed25519", "ed25519-pub.der"],
1446                Encoding.DER,
1447                load_der_public_key,
1448            ),
1449        ],
1450    )
1451    def test_load_public_key(self, key_path, encoding, loader, backend):
1452        data = load_vectors_from_file(
1453            os.path.join("asymmetric", *key_path),
1454            lambda pemfile: pemfile.read(),
1455            mode="rb",
1456        )
1457        public_key = loader(data, backend)
1458        assert (
1459            public_key.public_bytes(
1460                encoding, PublicFormat.SubjectPublicKeyInfo
1461            )
1462            == data
1463        )
1464
1465    def test_openssl_serialization_unsupported(self, backend):
1466        key = ed25519.Ed25519PrivateKey.generate()
1467        with pytest.raises(ValueError):
1468            key.private_bytes(
1469                Encoding.PEM,
1470                PrivateFormat.TraditionalOpenSSL,
1471                NoEncryption(),
1472            )
1473        with pytest.raises(ValueError):
1474            key.private_bytes(
1475                Encoding.DER,
1476                PrivateFormat.TraditionalOpenSSL,
1477                NoEncryption(),
1478            )
1479
1480
1481@pytest.mark.supported(
1482    only_if=lambda backend: backend.x448_supported(),
1483    skip_message="Requires OpenSSL with X448 support",
1484)
1485class TestX448Serialization(object):
1486    def test_load_der_private_key(self, backend):
1487        data = load_vectors_from_file(
1488            os.path.join("asymmetric", "X448", "x448-pkcs8-enc.der"),
1489            lambda derfile: derfile.read(),
1490            mode="rb",
1491        )
1492        unencrypted = load_vectors_from_file(
1493            os.path.join("asymmetric", "X448", "x448-pkcs8.der"),
1494            lambda derfile: derfile.read(),
1495            mode="rb",
1496        )
1497        key = load_der_private_key(data, b"password", backend)
1498        assert (
1499            key.private_bytes(
1500                Encoding.DER, PrivateFormat.PKCS8, NoEncryption()
1501            )
1502            == unencrypted
1503        )
1504
1505    def test_load_pem_private_key(self, backend):
1506        data = load_vectors_from_file(
1507            os.path.join("asymmetric", "X448", "x448-pkcs8-enc.pem"),
1508            lambda pemfile: pemfile.read(),
1509            mode="rb",
1510        )
1511        unencrypted = load_vectors_from_file(
1512            os.path.join("asymmetric", "X448", "x448-pkcs8.pem"),
1513            lambda pemfile: pemfile.read(),
1514            mode="rb",
1515        )
1516        key = load_pem_private_key(data, b"password", backend)
1517        assert (
1518            key.private_bytes(
1519                Encoding.PEM, PrivateFormat.PKCS8, NoEncryption()
1520            )
1521            == unencrypted
1522        )
1523
1524    @pytest.mark.parametrize(
1525        ("key_path", "encoding", "loader"),
1526        [
1527            (["X448", "x448-pub.pem"], Encoding.PEM, load_pem_public_key),
1528            (["X448", "x448-pub.der"], Encoding.DER, load_der_public_key),
1529        ],
1530    )
1531    def test_load_public_key(self, key_path, encoding, loader, backend):
1532        data = load_vectors_from_file(
1533            os.path.join("asymmetric", *key_path),
1534            lambda pemfile: pemfile.read(),
1535            mode="rb",
1536        )
1537        public_key = loader(data, backend)
1538        assert (
1539            public_key.public_bytes(
1540                encoding, PublicFormat.SubjectPublicKeyInfo
1541            )
1542            == data
1543        )
1544
1545    def test_openssl_serialization_unsupported(self, backend):
1546        key = x448.X448PrivateKey.generate()
1547        with pytest.raises(ValueError):
1548            key.private_bytes(
1549                Encoding.PEM,
1550                PrivateFormat.TraditionalOpenSSL,
1551                NoEncryption(),
1552            )
1553        with pytest.raises(ValueError):
1554            key.private_bytes(
1555                Encoding.DER,
1556                PrivateFormat.TraditionalOpenSSL,
1557                NoEncryption(),
1558            )
1559
1560    def test_openssh_serialization_unsupported(self, backend):
1561        key = x448.X448PrivateKey.generate()
1562        with pytest.raises(ValueError):
1563            key.public_key().public_bytes(
1564                Encoding.OpenSSH, PublicFormat.OpenSSH
1565            )
1566        with pytest.raises(ValueError):
1567            key.private_bytes(
1568                Encoding.PEM, PrivateFormat.OpenSSH, NoEncryption()
1569            )
1570
1571
1572@pytest.mark.supported(
1573    only_if=lambda backend: backend.x25519_supported(),
1574    skip_message="Requires OpenSSL with X25519 support",
1575)
1576class TestX25519Serialization(object):
1577    def test_load_der_private_key(self, backend):
1578        data = load_vectors_from_file(
1579            os.path.join("asymmetric", "X25519", "x25519-pkcs8-enc.der"),
1580            lambda derfile: derfile.read(),
1581            mode="rb",
1582        )
1583        unencrypted = load_vectors_from_file(
1584            os.path.join("asymmetric", "X25519", "x25519-pkcs8.der"),
1585            lambda derfile: derfile.read(),
1586            mode="rb",
1587        )
1588        key = load_der_private_key(data, b"password", backend)
1589        assert (
1590            key.private_bytes(
1591                Encoding.DER, PrivateFormat.PKCS8, NoEncryption()
1592            )
1593            == unencrypted
1594        )
1595
1596    def test_load_pem_private_key(self, backend):
1597        data = load_vectors_from_file(
1598            os.path.join("asymmetric", "X25519", "x25519-pkcs8-enc.pem"),
1599            lambda pemfile: pemfile.read(),
1600            mode="rb",
1601        )
1602        unencrypted = load_vectors_from_file(
1603            os.path.join("asymmetric", "X25519", "x25519-pkcs8.pem"),
1604            lambda pemfile: pemfile.read(),
1605            mode="rb",
1606        )
1607        key = load_pem_private_key(data, b"password", backend)
1608        assert (
1609            key.private_bytes(
1610                Encoding.PEM, PrivateFormat.PKCS8, NoEncryption()
1611            )
1612            == unencrypted
1613        )
1614
1615    @pytest.mark.parametrize(
1616        ("key_path", "encoding", "loader"),
1617        [
1618            (["X25519", "x25519-pub.pem"], Encoding.PEM, load_pem_public_key),
1619            (["X25519", "x25519-pub.der"], Encoding.DER, load_der_public_key),
1620        ],
1621    )
1622    def test_load_public_key(self, key_path, encoding, loader, backend):
1623        data = load_vectors_from_file(
1624            os.path.join("asymmetric", *key_path),
1625            lambda pemfile: pemfile.read(),
1626            mode="rb",
1627        )
1628        public_key = loader(data, backend)
1629        assert (
1630            public_key.public_bytes(
1631                encoding, PublicFormat.SubjectPublicKeyInfo
1632            )
1633            == data
1634        )
1635
1636    def test_openssl_serialization_unsupported(self, backend):
1637        key = x25519.X25519PrivateKey.generate()
1638        with pytest.raises(ValueError):
1639            key.private_bytes(
1640                Encoding.PEM,
1641                PrivateFormat.TraditionalOpenSSL,
1642                NoEncryption(),
1643            )
1644        with pytest.raises(ValueError):
1645            key.private_bytes(
1646                Encoding.DER,
1647                PrivateFormat.TraditionalOpenSSL,
1648                NoEncryption(),
1649            )
1650
1651    def test_openssh_serialization_unsupported(self, backend):
1652        key = x25519.X25519PrivateKey.generate()
1653        with pytest.raises(ValueError):
1654            key.public_key().public_bytes(
1655                Encoding.OpenSSH, PublicFormat.OpenSSH
1656            )
1657        with pytest.raises(ValueError):
1658            key.private_bytes(
1659                Encoding.PEM, PrivateFormat.OpenSSH, NoEncryption()
1660            )
1661
1662
1663@pytest.mark.supported(
1664    only_if=lambda backend: backend.ed448_supported(),
1665    skip_message="Requires OpenSSL with Ed448 support",
1666)
1667class TestEd448Serialization(object):
1668    def test_load_der_private_key(self, backend):
1669        data = load_vectors_from_file(
1670            os.path.join("asymmetric", "Ed448", "ed448-pkcs8-enc.der"),
1671            lambda derfile: derfile.read(),
1672            mode="rb",
1673        )
1674        unencrypted = load_vectors_from_file(
1675            os.path.join("asymmetric", "Ed448", "ed448-pkcs8.der"),
1676            lambda derfile: derfile.read(),
1677            mode="rb",
1678        )
1679        key = load_der_private_key(data, b"password", backend)
1680        assert (
1681            key.private_bytes(
1682                Encoding.DER, PrivateFormat.PKCS8, NoEncryption()
1683            )
1684            == unencrypted
1685        )
1686
1687    def test_load_pem_private_key(self, backend):
1688        data = load_vectors_from_file(
1689            os.path.join("asymmetric", "Ed448", "ed448-pkcs8-enc.pem"),
1690            lambda pemfile: pemfile.read(),
1691            mode="rb",
1692        )
1693        unencrypted = load_vectors_from_file(
1694            os.path.join("asymmetric", "Ed448", "ed448-pkcs8.pem"),
1695            lambda pemfile: pemfile.read(),
1696            mode="rb",
1697        )
1698        key = load_pem_private_key(data, b"password", backend)
1699        assert (
1700            key.private_bytes(
1701                Encoding.PEM, PrivateFormat.PKCS8, NoEncryption()
1702            )
1703            == unencrypted
1704        )
1705
1706    @pytest.mark.parametrize(
1707        ("key_path", "encoding", "loader"),
1708        [
1709            (["Ed448", "ed448-pub.pem"], Encoding.PEM, load_pem_public_key),
1710            (["Ed448", "ed448-pub.der"], Encoding.DER, load_der_public_key),
1711        ],
1712    )
1713    def test_load_public_key(self, key_path, encoding, loader, backend):
1714        data = load_vectors_from_file(
1715            os.path.join("asymmetric", *key_path),
1716            lambda pemfile: pemfile.read(),
1717            mode="rb",
1718        )
1719        public_key = loader(data, backend)
1720        assert (
1721            public_key.public_bytes(
1722                encoding, PublicFormat.SubjectPublicKeyInfo
1723            )
1724            == data
1725        )
1726
1727    def test_openssl_serialization_unsupported(self, backend):
1728        key = ed448.Ed448PrivateKey.generate()
1729        with pytest.raises(ValueError):
1730            key.private_bytes(
1731                Encoding.PEM,
1732                PrivateFormat.TraditionalOpenSSL,
1733                NoEncryption(),
1734            )
1735        with pytest.raises(ValueError):
1736            key.private_bytes(
1737                Encoding.DER,
1738                PrivateFormat.TraditionalOpenSSL,
1739                NoEncryption(),
1740            )
1741
1742    def test_openssh_serialization_unsupported(self, backend):
1743        key = ed448.Ed448PrivateKey.generate()
1744        with pytest.raises(ValueError):
1745            key.public_key().public_bytes(
1746                Encoding.OpenSSH,
1747                PublicFormat.OpenSSH,
1748            )
1749        with pytest.raises(ValueError):
1750            key.private_bytes(
1751                Encoding.PEM,
1752                PrivateFormat.OpenSSH,
1753                NoEncryption(),
1754            )
1755
1756
1757class TestDHSerialization(object):
1758    """Test all options with least-supported key type."""
1759
1760    @pytest.mark.skip_fips(reason="non-FIPS parameters")
1761    def test_dh_public_key(self, backend):
1762        data = load_vectors_from_file(
1763            os.path.join("asymmetric", "DH", "dhkey.pem"),
1764            lambda pemfile: pemfile.read(),
1765            mode="rb",
1766        )
1767        public_key = load_pem_private_key(data, None, backend).public_key()
1768        for enc in (
1769            Encoding.PEM,
1770            Encoding.DER,
1771            Encoding.OpenSSH,
1772            Encoding.Raw,
1773            Encoding.X962,
1774        ):
1775            for fmt in (
1776                PublicFormat.SubjectPublicKeyInfo,
1777                PublicFormat.PKCS1,
1778                PublicFormat.OpenSSH,
1779                PublicFormat.Raw,
1780                PublicFormat.CompressedPoint,
1781                PublicFormat.UncompressedPoint,
1782            ):
1783                if (
1784                    enc in (Encoding.PEM, Encoding.DER)
1785                    and fmt == PublicFormat.SubjectPublicKeyInfo
1786                ):
1787                    # tested elsewhere
1788                    continue
1789                with pytest.raises(ValueError):
1790                    public_key.public_bytes(enc, fmt)
1791
1792    @pytest.mark.skip_fips(reason="non-FIPS parameters")
1793    def test_dh_private_key(self, backend):
1794        data = load_vectors_from_file(
1795            os.path.join("asymmetric", "DH", "dhkey.pem"),
1796            lambda pemfile: pemfile.read(),
1797            mode="rb",
1798        )
1799        private_key = load_pem_private_key(data, None, backend)
1800        for enc in (
1801            Encoding.PEM,
1802            Encoding.DER,
1803            Encoding.OpenSSH,
1804            Encoding.Raw,
1805            Encoding.X962,
1806        ):
1807            for fmt in (
1808                PrivateFormat.PKCS8,
1809                PrivateFormat.TraditionalOpenSSL,
1810                PrivateFormat.Raw,
1811            ):
1812                if (
1813                    enc in (Encoding.PEM, Encoding.DER)
1814                    and fmt is PrivateFormat.PKCS8
1815                ):
1816                    # tested elsewhere
1817                    continue
1818                with pytest.raises(ValueError):
1819                    private_key.private_bytes(enc, fmt, NoEncryption())
1820
1821
1822@pytest.mark.requires_backend_interface(interface=RSABackend)
1823@pytest.mark.requires_backend_interface(interface=DSABackend)
1824@pytest.mark.requires_backend_interface(interface=EllipticCurveBackend)
1825class TestOpenSSHSerialization(object):
1826    @pytest.mark.parametrize(
1827        ("key_file", "cert_file"),
1828        [
1829            ("rsa-psw.key.pub", None),
1830            ("rsa-nopsw.key.pub", "rsa-nopsw.key-cert.pub"),
1831            ("dsa-psw.key.pub", None),
1832            ("dsa-nopsw.key.pub", "dsa-nopsw.key-cert.pub"),
1833            ("ecdsa-psw.key.pub", None),
1834            ("ecdsa-nopsw.key.pub", "ecdsa-nopsw.key-cert.pub"),
1835            ("ed25519-psw.key.pub", None),
1836            ("ed25519-nopsw.key.pub", "ed25519-nopsw.key-cert.pub"),
1837        ],
1838    )
1839    def test_load_ssh_public_key(self, key_file, cert_file, backend):
1840        if "ed25519" in key_file and not backend.ed25519_supported():
1841            pytest.skip("Requires OpenSSL with Ed25519 support")
1842
1843        # normal public key
1844        pub_data = load_vectors_from_file(
1845            os.path.join("asymmetric", "OpenSSH", key_file),
1846            lambda f: f.read(),
1847            mode="rb",
1848        )
1849        public_key = load_ssh_public_key(pub_data, backend)
1850        nocomment_data = b" ".join(pub_data.split()[:2])
1851        assert (
1852            public_key.public_bytes(Encoding.OpenSSH, PublicFormat.OpenSSH)
1853            == nocomment_data
1854        )
1855
1856        self.run_partial_pubkey(pub_data, backend)
1857
1858        # parse public key with ssh certificate
1859        if cert_file:
1860            cert_data = load_vectors_from_file(
1861                os.path.join("asymmetric", "OpenSSH", cert_file),
1862                lambda f: f.read(),
1863                mode="rb",
1864            )
1865            cert_key = load_ssh_public_key(cert_data, backend)
1866            assert (
1867                cert_key.public_bytes(Encoding.OpenSSH, PublicFormat.OpenSSH)
1868                == nocomment_data
1869            )
1870
1871            # try with more spaces
1872            cert_data = b" \t ".join(cert_data.split())
1873            cert_key = load_ssh_public_key(cert_data, backend)
1874            assert (
1875                cert_key.public_bytes(Encoding.OpenSSH, PublicFormat.OpenSSH)
1876                == nocomment_data
1877            )
1878
1879            self.run_partial_pubkey(cert_data, backend)
1880
1881    def run_partial_pubkey(self, pubdata, backend):
1882        parts = pubdata.split()
1883        raw = base64.b64decode(parts[1])
1884        for i in range(1, len(raw)):
1885            frag = base64.b64encode(raw[:i])
1886            new_pub = b" ".join([parts[0], frag])
1887            with pytest.raises(ValueError):
1888                load_ssh_public_key(new_pub, backend)
1889
1890    @pytest.mark.parametrize(
1891        ("key_file",),
1892        [
1893            ("rsa-nopsw.key",),
1894            ("rsa-psw.key",),
1895            ("dsa-nopsw.key",),
1896            ("dsa-psw.key",),
1897            ("ecdsa-nopsw.key",),
1898            ("ecdsa-psw.key",),
1899            ("ed25519-nopsw.key",),
1900            ("ed25519-psw.key",),
1901        ],
1902    )
1903    def test_load_ssh_private_key(self, key_file, backend):
1904        if "ed25519" in key_file and not backend.ed25519_supported():
1905            pytest.skip("Requires OpenSSL with Ed25519 support")
1906        if "-psw" in key_file and not ssh._bcrypt_supported:
1907            pytest.skip("Requires bcrypt module")
1908
1909        # read public and private key from ssh-keygen
1910        priv_data = load_vectors_from_file(
1911            os.path.join("asymmetric", "OpenSSH", key_file),
1912            lambda f: f.read(),
1913            mode="rb",
1914        )
1915        pub_data = load_vectors_from_file(
1916            os.path.join("asymmetric", "OpenSSH", key_file + ".pub"),
1917            lambda f: f.read(),
1918            mode="rb",
1919        )
1920        nocomment_data = b" ".join(pub_data.split()[:2])
1921
1922        # load and compare
1923        password = None
1924        if "-psw" in key_file:
1925            password = b"password"
1926        private_key = load_ssh_private_key(priv_data, password, backend)
1927        assert (
1928            private_key.public_key().public_bytes(
1929                Encoding.OpenSSH, PublicFormat.OpenSSH
1930            )
1931            == nocomment_data
1932        )
1933
1934        # bytearray
1935        private_key = load_ssh_private_key(
1936            bytearray(priv_data), password, backend
1937        )
1938        assert (
1939            private_key.public_key().public_bytes(
1940                Encoding.OpenSSH, PublicFormat.OpenSSH
1941            )
1942            == nocomment_data
1943        )
1944
1945        if six.PY3:
1946            # memoryview(bytes)
1947            private_key = load_ssh_private_key(
1948                memoryview(priv_data), password, backend
1949            )
1950            assert (
1951                private_key.public_key().public_bytes(
1952                    Encoding.OpenSSH, PublicFormat.OpenSSH
1953                )
1954                == nocomment_data
1955            )
1956
1957            # memoryview(bytearray)
1958            private_key = load_ssh_private_key(
1959                memoryview(bytearray(priv_data)), password, backend
1960            )
1961            assert (
1962                private_key.public_key().public_bytes(
1963                    Encoding.OpenSSH, PublicFormat.OpenSSH
1964                )
1965                == nocomment_data
1966            )
1967
1968        # serialize with own code and reload
1969        encryption = NoEncryption()
1970        if password:
1971            encryption = BestAvailableEncryption(password)
1972        priv_data2 = private_key.private_bytes(
1973            Encoding.PEM,
1974            PrivateFormat.OpenSSH,
1975            encryption,
1976        )
1977        private_key2 = load_ssh_private_key(priv_data2, password, backend)
1978        assert (
1979            private_key2.public_key().public_bytes(
1980                Encoding.OpenSSH, PublicFormat.OpenSSH
1981            )
1982            == nocomment_data
1983        )
1984
1985        # make sure multi-line base64 is used
1986        maxline = max(map(len, priv_data2.split(b"\n")))
1987        assert maxline < 80
1988
1989    @pytest.mark.supported(
1990        only_if=lambda backend: ssh._bcrypt_supported,
1991        skip_message="Requires that bcrypt exists",
1992    )
1993    def test_bcrypt_encryption(self, backend):
1994        private_key = ec.generate_private_key(ec.SECP256R1(), backend)
1995        pub1 = private_key.public_key().public_bytes(
1996            Encoding.OpenSSH, PublicFormat.OpenSSH
1997        )
1998
1999        for psw in (
2000            b"1",
2001            b"1234",
2002            b"1234" * 4,
2003            b"x" * 72,
2004        ):
2005            # BestAvailableEncryption does not handle bytes-like?
2006            best = BestAvailableEncryption(psw)
2007            encdata = private_key.private_bytes(
2008                Encoding.PEM, PrivateFormat.OpenSSH, best
2009            )
2010            decoded_key = load_ssh_private_key(encdata, psw, backend)
2011            pub2 = decoded_key.public_key().public_bytes(
2012                Encoding.OpenSSH, PublicFormat.OpenSSH
2013            )
2014            assert pub1 == pub2
2015
2016            # bytearray
2017            decoded_key2 = load_ssh_private_key(
2018                bytearray(encdata), psw, backend
2019            )
2020            pub2 = decoded_key2.public_key().public_bytes(
2021                Encoding.OpenSSH, PublicFormat.OpenSSH
2022            )
2023            assert pub1 == pub2
2024
2025            if six.PY3:
2026                # memoryview(bytes)
2027                decoded_key2 = load_ssh_private_key(
2028                    memoryview(encdata), psw, backend
2029                )
2030                pub2 = decoded_key2.public_key().public_bytes(
2031                    Encoding.OpenSSH, PublicFormat.OpenSSH
2032                )
2033                assert pub1 == pub2
2034
2035                # memoryview(bytearray)
2036                decoded_key2 = load_ssh_private_key(
2037                    memoryview(bytearray(encdata)), psw, backend
2038                )
2039                pub2 = decoded_key2.public_key().public_bytes(
2040                    Encoding.OpenSSH, PublicFormat.OpenSSH
2041                )
2042                assert pub1 == pub2
2043
2044            with pytest.raises(ValueError):
2045                decoded_key = load_ssh_private_key(encdata, None, backend)
2046            with pytest.raises(ValueError):
2047                decoded_key = load_ssh_private_key(encdata, b"wrong", backend)
2048
2049    @pytest.mark.supported(
2050        only_if=lambda backend: not ssh._bcrypt_supported,
2051        skip_message="Requires that bcrypt is missing",
2052    )
2053    def test_missing_bcrypt(self, backend):
2054        priv_data = load_vectors_from_file(
2055            os.path.join("asymmetric", "OpenSSH", "ecdsa-psw.key"),
2056            lambda f: f.read(),
2057            mode="rb",
2058        )
2059        with pytest.raises(UnsupportedAlgorithm):
2060            load_ssh_private_key(priv_data, b"password", backend)
2061
2062        private_key = ec.generate_private_key(ec.SECP256R1(), backend)
2063        with pytest.raises(UnsupportedAlgorithm):
2064            private_key.private_bytes(
2065                Encoding.PEM,
2066                PrivateFormat.OpenSSH,
2067                BestAvailableEncryption(b"x"),
2068            )
2069
2070    def test_fraglist_corners(self):
2071        f = ssh._FragList()
2072        with pytest.raises(ValueError):
2073            f.put_mpint(-1)
2074        f.put_mpint(0)
2075        f.put_mpint(0x80)
2076        assert f.tobytes() == b"\0\0\0\0" + b"\0\0\0\x02" + b"\0\x80"
2077
2078    def make_file(
2079        self,
2080        magic=b"openssh-key-v1\0",
2081        ciphername=b"none",
2082        kdfname=b"none",
2083        kdfoptions=b"",
2084        nkeys=1,
2085        pub_type=b"ecdsa-sha2-nistp256",
2086        pub_fields=(
2087            b"nistp256",
2088            b"\x04" * 65,
2089        ),
2090        priv_type=None,
2091        priv_fields=(b"nistp256", b"\x04" * 65, b"\x7F" * 32),
2092        comment=b"comment",
2093        checkval1=b"1234",
2094        checkval2=b"1234",
2095        pad=None,
2096        header=b"-----BEGIN OPENSSH PRIVATE KEY-----\n",
2097        footer=b"-----END OPENSSH PRIVATE KEY-----\n",
2098        cut=8192,
2099    ):
2100        """Create private key file"""
2101        if not priv_type:
2102            priv_type = pub_type
2103
2104        pub = ssh._FragList()
2105        for elem in (pub_type,) + pub_fields:
2106            pub.put_sshstr(elem)
2107
2108        secret = ssh._FragList([checkval1, checkval2])
2109        for i in range(nkeys):
2110            for elem in (priv_type,) + priv_fields + (comment,):
2111                secret.put_sshstr(elem)
2112
2113        if pad is None:
2114            pad_len = 8 - (secret.size() % 8)
2115            pad = bytearray(range(1, 1 + pad_len))
2116        secret.put_raw(pad)
2117
2118        main = ssh._FragList([magic])
2119        main.put_sshstr(ciphername)
2120        main.put_sshstr(kdfname)
2121        main.put_sshstr(kdfoptions)
2122        main.put_u32(nkeys)
2123        for i in range(nkeys):
2124            main.put_sshstr(pub)
2125        main.put_sshstr(secret)
2126
2127        res = main.tobytes()
2128        return ssh._ssh_pem_encode(res[:cut], header, footer)
2129
2130    def test_ssh_make_file(self, backend):
2131        # check if works by default
2132        data = self.make_file()
2133        key = load_ssh_private_key(data, None, backend)
2134        assert isinstance(key, ec.EllipticCurvePrivateKey)
2135
2136    def test_load_ssh_private_key_errors(self, backend):
2137        # bad kdf
2138        data = self.make_file(kdfname=b"unknown", ciphername=b"aes256-ctr")
2139        with pytest.raises(UnsupportedAlgorithm):
2140            load_ssh_private_key(data, None, backend)
2141
2142        # bad cipher
2143        data = self.make_file(ciphername=b"unknown", kdfname=b"bcrypt")
2144        with pytest.raises(UnsupportedAlgorithm):
2145            load_ssh_private_key(data, None, backend)
2146
2147        # bad magic
2148        data = self.make_file(magic=b"unknown")
2149        with pytest.raises(ValueError):
2150            load_ssh_private_key(data, None, backend)
2151
2152        # too few keys
2153        data = self.make_file(nkeys=0)
2154        with pytest.raises(ValueError):
2155            load_ssh_private_key(data, None, backend)
2156
2157        # too many keys
2158        data = self.make_file(nkeys=2)
2159        with pytest.raises(ValueError):
2160            load_ssh_private_key(data, None, backend)
2161
2162    def test_ssh_errors_bad_values(self, backend):
2163        # bad curve
2164        data = self.make_file(pub_type=b"ecdsa-sha2-nistp444")
2165        with pytest.raises(UnsupportedAlgorithm):
2166            load_ssh_private_key(data, None, backend)
2167
2168        # curve mismatch
2169        data = self.make_file(priv_type=b"ecdsa-sha2-nistp384")
2170        with pytest.raises(ValueError):
2171            load_ssh_private_key(data, None, backend)
2172
2173        # invalid bigint
2174        data = self.make_file(
2175            priv_fields=(b"nistp256", b"\x04" * 65, b"\x80" * 32)
2176        )
2177        with pytest.raises(ValueError):
2178            load_ssh_private_key(data, None, backend)
2179
2180    def test_ssh_errors_pubpriv_mismatch(self, backend):
2181        # ecdsa public-private mismatch
2182        data = self.make_file(
2183            pub_fields=(
2184                b"nistp256",
2185                b"\x04" + b"\x05" * 64,
2186            )
2187        )
2188        with pytest.raises(ValueError):
2189            load_ssh_private_key(data, None, backend)
2190
2191        # rsa public-private mismatch
2192        data = self.make_file(
2193            pub_type=b"ssh-rsa",
2194            pub_fields=(b"x" * 32,) * 2,
2195            priv_fields=(b"z" * 32,) * 6,
2196        )
2197        with pytest.raises(ValueError):
2198            load_ssh_private_key(data, None, backend)
2199
2200        # dsa public-private mismatch
2201        data = self.make_file(
2202            pub_type=b"ssh-dss",
2203            pub_fields=(b"x" * 32,) * 4,
2204            priv_fields=(b"z" * 32,) * 5,
2205        )
2206        with pytest.raises(ValueError):
2207            load_ssh_private_key(data, None, backend)
2208
2209        # ed25519 public-private mismatch
2210        sk = b"x" * 32
2211        pk1 = b"y" * 32
2212        pk2 = b"z" * 32
2213        data = self.make_file(
2214            pub_type=b"ssh-ed25519",
2215            pub_fields=(pk1,),
2216            priv_fields=(
2217                pk1,
2218                sk + pk2,
2219            ),
2220        )
2221        with pytest.raises(ValueError):
2222            load_ssh_private_key(data, None, backend)
2223        data = self.make_file(
2224            pub_type=b"ssh-ed25519",
2225            pub_fields=(pk1,),
2226            priv_fields=(
2227                pk2,
2228                sk + pk1,
2229            ),
2230        )
2231        with pytest.raises(ValueError):
2232            load_ssh_private_key(data, None, backend)
2233
2234    def test_ssh_errors_bad_wrapper(self, backend):
2235        # wrong header
2236        data = self.make_file(header=b"-----BEGIN RSA PRIVATE KEY-----\n")
2237        with pytest.raises(ValueError):
2238            load_ssh_private_key(data, None, backend)
2239
2240        # wring footer
2241        data = self.make_file(footer=b"-----END RSA PRIVATE KEY-----\n")
2242        with pytest.raises(ValueError):
2243            load_ssh_private_key(data, None, backend)
2244
2245    def test_ssh_no_padding(self, backend):
2246        # no padding must work, if data is on block boundary
2247        data = self.make_file(pad=b"", comment=b"")
2248        key = load_ssh_private_key(data, None, backend)
2249        assert isinstance(key, ec.EllipticCurvePrivateKey)
2250
2251        # no padding with right last byte
2252        data = self.make_file(pad=b"", comment=b"\x08" * 8)
2253        key = load_ssh_private_key(data, None, backend)
2254        assert isinstance(key, ec.EllipticCurvePrivateKey)
2255
2256        # avoid unexpected padding removal
2257        data = self.make_file(pad=b"", comment=b"1234\x01\x02\x03\x04")
2258        key = load_ssh_private_key(data, None, backend)
2259        assert isinstance(key, ec.EllipticCurvePrivateKey)
2260
2261        # bad padding with right size
2262        data = self.make_file(pad=b"\x08" * 8, comment=b"")
2263        with pytest.raises(ValueError):
2264            load_ssh_private_key(data, None, backend)
2265
2266    def test_ssh_errors_bad_secrets(self, backend):
2267        # checkval mismatch
2268        data = self.make_file(checkval2=b"4321")
2269        with pytest.raises(ValueError):
2270            load_ssh_private_key(data, None, backend)
2271
2272        # bad padding, correct=1
2273        data = self.make_file(pad=b"\x01\x02")
2274        with pytest.raises(ValueError):
2275            load_ssh_private_key(data, None, backend)
2276        data = self.make_file(pad=b"")
2277        with pytest.raises(ValueError):
2278            load_ssh_private_key(data, None, backend)
2279
2280    @pytest.mark.supported(
2281        only_if=lambda backend: backend.elliptic_curve_supported(
2282            ec.SECP192R1()
2283        ),
2284        skip_message="Requires backend support for ec.SECP192R1",
2285    )
2286    def test_serialize_ssh_private_key_errors_bad_curve(self, backend):
2287        private_key = ec.generate_private_key(ec.SECP192R1(), backend)
2288        with pytest.raises(ValueError):
2289            private_key.private_bytes(
2290                Encoding.PEM, PrivateFormat.OpenSSH, NoEncryption()
2291            )
2292
2293    def test_serialize_ssh_private_key_errors(self, backend):
2294        # bad encoding
2295        private_key = ec.generate_private_key(ec.SECP256R1(), backend)
2296        with pytest.raises(ValueError):
2297            private_key.private_bytes(
2298                Encoding.DER, PrivateFormat.OpenSSH, NoEncryption()
2299            )
2300
2301        # bad object type
2302        with pytest.raises(ValueError):
2303            ssh.serialize_ssh_private_key(object(), None)
2304
2305        private_key = ec.generate_private_key(ec.SECP256R1(), backend)
2306
2307        # too long password
2308        with pytest.raises(ValueError):
2309            private_key.private_bytes(
2310                Encoding.PEM,
2311                PrivateFormat.OpenSSH,
2312                BestAvailableEncryption(b"p" * 73),
2313            )
2314
2315        # unknown encryption class
2316        with pytest.raises(ValueError):
2317            private_key.private_bytes(
2318                Encoding.PEM,
2319                PrivateFormat.OpenSSH,
2320                DummyKeySerializationEncryption(),
2321            )
2322
2323    @pytest.mark.parametrize(
2324        ("key_path", "supported"),
2325        [
2326            (["Traditional_OpenSSL_Serialization", "dsa.1024.pem"], True),
2327            (["Traditional_OpenSSL_Serialization", "dsa.2048.pem"], False),
2328            (["Traditional_OpenSSL_Serialization", "dsa.3072.pem"], False),
2329        ],
2330    )
2331    def test_dsa_private_key_sizes(self, key_path, supported, backend):
2332        key = load_vectors_from_file(
2333            os.path.join("asymmetric", *key_path),
2334            lambda pemfile: load_pem_private_key(
2335                pemfile.read(), None, backend
2336            ),
2337            mode="rb",
2338        )
2339        assert isinstance(key, dsa.DSAPrivateKey)
2340        if supported:
2341            res = key.private_bytes(
2342                Encoding.PEM, PrivateFormat.OpenSSH, NoEncryption()
2343            )
2344            assert isinstance(res, bytes)
2345        else:
2346            with pytest.raises(ValueError):
2347                key.private_bytes(
2348                    Encoding.PEM, PrivateFormat.OpenSSH, NoEncryption()
2349                )
2350