• 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 binascii
8import itertools
9import os
10from binascii import hexlify
11
12import pytest
13
14from cryptography import exceptions, utils, x509
15from cryptography.hazmat.backends.interfaces import (
16    EllipticCurveBackend,
17    PEMSerializationBackend,
18)
19from cryptography.hazmat.primitives import hashes, serialization
20from cryptography.hazmat.primitives.asymmetric import ec
21from cryptography.hazmat.primitives.asymmetric.utils import (
22    Prehashed,
23    encode_dss_signature,
24)
25from cryptography.utils import CryptographyDeprecationWarning
26
27from .fixtures_ec import EC_KEY_SECP384R1
28from .utils import skip_fips_traditional_openssl
29from ...doubles import DummyKeySerializationEncryption
30from ...utils import (
31    load_fips_ecdsa_key_pair_vectors,
32    load_fips_ecdsa_signing_vectors,
33    load_kasvs_ecdh_vectors,
34    load_nist_vectors,
35    load_vectors_from_file,
36    raises_unsupported_algorithm,
37)
38
39_HASH_TYPES = {
40    "SHA-1": hashes.SHA1,
41    "SHA-224": hashes.SHA224,
42    "SHA-256": hashes.SHA256,
43    "SHA-384": hashes.SHA384,
44    "SHA-512": hashes.SHA512,
45}
46
47
48def _skip_ecdsa_vector(backend, curve_type, hash_type):
49    if not backend.elliptic_curve_signature_algorithm_supported(
50        ec.ECDSA(hash_type()), curve_type()
51    ):
52        pytest.skip(
53            "ECDSA not supported with this hash {} and curve {}.".format(
54                hash_type().name, curve_type().name
55            )
56        )
57
58
59def _skip_curve_unsupported(backend, curve):
60    if not backend.elliptic_curve_supported(curve):
61        pytest.skip(
62            "Curve {} is not supported by this backend {}".format(
63                curve.name, backend
64            )
65        )
66
67
68def _skip_exchange_algorithm_unsupported(backend, algorithm, curve):
69    if not backend.elliptic_curve_exchange_algorithm_supported(
70        algorithm, curve
71    ):
72        pytest.skip(
73            "Exchange with {} curve is not supported by {}".format(
74                curve.name, backend
75            )
76        )
77
78
79def test_get_curve_for_oid():
80    assert ec.get_curve_for_oid(ec.EllipticCurveOID.SECP256R1) == ec.SECP256R1
81    with pytest.raises(LookupError):
82        ec.get_curve_for_oid(x509.ObjectIdentifier("1.1.1.1"))
83
84
85@utils.register_interface(ec.EllipticCurve)
86class DummyCurve(object):
87    name = "dummy-curve"
88    key_size = 1
89
90
91@utils.register_interface(ec.EllipticCurveSignatureAlgorithm)
92class DummySignatureAlgorithm(object):
93    algorithm = None
94
95
96@pytest.mark.requires_backend_interface(interface=EllipticCurveBackend)
97def test_skip_curve_unsupported(backend):
98    with pytest.raises(pytest.skip.Exception):
99        _skip_curve_unsupported(backend, DummyCurve())
100
101
102@pytest.mark.requires_backend_interface(interface=EllipticCurveBackend)
103def test_skip_exchange_algorithm_unsupported(backend):
104    with pytest.raises(pytest.skip.Exception):
105        _skip_exchange_algorithm_unsupported(backend, ec.ECDH(), DummyCurve())
106
107
108@pytest.mark.requires_backend_interface(interface=EllipticCurveBackend)
109def test_skip_ecdsa_vector(backend):
110    with pytest.raises(pytest.skip.Exception):
111        _skip_ecdsa_vector(backend, DummyCurve, hashes.SHA256)
112
113
114@pytest.mark.requires_backend_interface(interface=EllipticCurveBackend)
115def test_derive_private_key_success(backend):
116    curve = ec.SECP256K1()
117    _skip_curve_unsupported(backend, curve)
118
119    private_numbers = ec.generate_private_key(curve, backend).private_numbers()
120
121    derived_key = ec.derive_private_key(
122        private_numbers.private_value, curve, backend
123    )
124
125    assert private_numbers == derived_key.private_numbers()
126
127
128@pytest.mark.requires_backend_interface(interface=EllipticCurveBackend)
129def test_derive_private_key_errors(backend):
130    curve = ec.SECP256K1()
131    _skip_curve_unsupported(backend, curve)
132
133    with pytest.raises(TypeError):
134        ec.derive_private_key("one", curve, backend)
135
136    with pytest.raises(TypeError):
137        ec.derive_private_key(10, "five", backend)
138
139    with pytest.raises(ValueError):
140        ec.derive_private_key(-7, curve, backend)
141
142
143def test_ec_numbers():
144    numbers = ec.EllipticCurvePrivateNumbers(
145        1, ec.EllipticCurvePublicNumbers(2, 3, DummyCurve())
146    )
147
148    assert numbers.private_value == 1
149    assert numbers.public_numbers.x == 2
150    assert numbers.public_numbers.y == 3
151    assert isinstance(numbers.public_numbers.curve, DummyCurve)
152
153
154@pytest.mark.parametrize(
155    ("private_value", "x", "y", "curve"),
156    [
157        (None, 2, 3, DummyCurve()),
158        (1, None, 3, DummyCurve()),
159        (1, 2, None, DummyCurve()),
160        (1, 2, 3, None),
161    ],
162)
163def test_invalid_ec_numbers_args(private_value, x, y, curve):
164    with pytest.raises(TypeError):
165        ec.EllipticCurvePrivateNumbers(
166            private_value, ec.EllipticCurvePublicNumbers(x, y, curve)
167        )
168
169
170def test_invalid_private_numbers_public_numbers():
171    with pytest.raises(TypeError):
172        ec.EllipticCurvePrivateNumbers(1, None)
173
174
175def test_encode_point():
176    # secp256r1 point
177    x = int(
178        "233ea3b0027127084cd2cd336a13aeef69c598d8af61369a36454a17c6c22aec", 16
179    )
180    y = int(
181        "3ea2c10a84153862be4ec82940f0543f9ba866af9751a6ee79d38460b35f442e", 16
182    )
183    pn = ec.EllipticCurvePublicNumbers(x, y, ec.SECP256R1())
184    with pytest.warns(utils.PersistentlyDeprecated2019):
185        data = pn.encode_point()
186    assert data == binascii.unhexlify(
187        "04233ea3b0027127084cd2cd336a13aeef69c598d8af61369a36454a17c6c22ae"
188        "c3ea2c10a84153862be4ec82940f0543f9ba866af9751a6ee79d38460b35f442e"
189    )
190
191
192def test_from_encoded_point():
193    # secp256r1 point
194    data = binascii.unhexlify(
195        "04233ea3b0027127084cd2cd336a13aeef69c598d8af61369a36454a17c6c22ae"
196        "c3ea2c10a84153862be4ec82940f0543f9ba866af9751a6ee79d38460b35f442e"
197    )
198    with pytest.warns(CryptographyDeprecationWarning):
199        pn = ec.EllipticCurvePublicNumbers.from_encoded_point(
200            ec.SECP256R1(), data
201        )
202    assert pn.x == int(
203        "233ea3b0027127084cd2cd336a13aeef69c598d8af61369a36454a17c6c22aec", 16
204    )
205    assert pn.y == int(
206        "3ea2c10a84153862be4ec82940f0543f9ba866af9751a6ee79d38460b35f442e", 16
207    )
208
209
210def test_from_encoded_point_invalid_length():
211    bad_data = binascii.unhexlify(
212        "04233ea3b0027127084cd2cd336a13aeef69c598d8af61369a36454a17c6c22ae"
213        "c3ea2c10a84153862be4ec82940f0543f9ba866af9751a6ee79d38460"
214    )
215    with pytest.raises(ValueError):
216        with pytest.warns(CryptographyDeprecationWarning):
217            ec.EllipticCurvePublicNumbers.from_encoded_point(
218                ec.SECP384R1(), bad_data
219            )
220
221
222def test_from_encoded_point_unsupported_point_no_backend():
223    # set to point type 2.
224    unsupported_type = binascii.unhexlify(
225        "02233ea3b0027127084cd2cd336a13aeef69c598d8af61369a36454a17c6c22a"
226    )
227    with pytest.raises(ValueError):
228        with pytest.warns(CryptographyDeprecationWarning):
229            ec.EllipticCurvePublicNumbers.from_encoded_point(
230                ec.SECP256R1(), unsupported_type
231            )
232
233
234def test_from_encoded_point_not_a_curve():
235    with pytest.raises(TypeError):
236        with pytest.warns(CryptographyDeprecationWarning):
237            ec.EllipticCurvePublicNumbers.from_encoded_point(
238                "notacurve", b"\x04data"
239            )
240
241
242def test_ec_public_numbers_repr():
243    pn = ec.EllipticCurvePublicNumbers(2, 3, ec.SECP256R1())
244    assert repr(pn) == "<EllipticCurvePublicNumbers(curve=secp256r1, x=2, y=3>"
245
246
247def test_ec_public_numbers_hash():
248    pn1 = ec.EllipticCurvePublicNumbers(2, 3, ec.SECP256R1())
249    pn2 = ec.EllipticCurvePublicNumbers(2, 3, ec.SECP256R1())
250    pn3 = ec.EllipticCurvePublicNumbers(1, 3, ec.SECP256R1())
251
252    assert hash(pn1) == hash(pn2)
253    assert hash(pn1) != hash(pn3)
254
255
256def test_ec_private_numbers_hash():
257    numbers1 = ec.EllipticCurvePrivateNumbers(
258        1, ec.EllipticCurvePublicNumbers(2, 3, DummyCurve())
259    )
260    numbers2 = ec.EllipticCurvePrivateNumbers(
261        1, ec.EllipticCurvePublicNumbers(2, 3, DummyCurve())
262    )
263    numbers3 = ec.EllipticCurvePrivateNumbers(
264        2, ec.EllipticCurvePublicNumbers(2, 3, DummyCurve())
265    )
266
267    assert hash(numbers1) == hash(numbers2)
268    assert hash(numbers1) != hash(numbers3)
269
270
271@pytest.mark.requires_backend_interface(interface=EllipticCurveBackend)
272def test_ec_key_key_size(backend):
273    curve = ec.SECP256R1()
274    _skip_curve_unsupported(backend, curve)
275    key = ec.generate_private_key(curve, backend)
276    assert key.key_size == 256
277    assert key.public_key().key_size == 256
278
279
280@pytest.mark.requires_backend_interface(interface=EllipticCurveBackend)
281class TestECWithNumbers(object):
282    @pytest.mark.parametrize(
283        ("vector", "hash_type"),
284        list(
285            itertools.product(
286                load_vectors_from_file(
287                    os.path.join(
288                        "asymmetric", "ECDSA", "FIPS_186-3", "KeyPair.rsp"
289                    ),
290                    load_fips_ecdsa_key_pair_vectors,
291                ),
292                _HASH_TYPES.values(),
293            )
294        ),
295    )
296    def test_with_numbers(self, backend, vector, hash_type):
297        curve_type = ec._CURVE_TYPES[vector["curve"]]
298
299        _skip_ecdsa_vector(backend, curve_type, hash_type)
300
301        key = ec.EllipticCurvePrivateNumbers(
302            vector["d"],
303            ec.EllipticCurvePublicNumbers(
304                vector["x"], vector["y"], curve_type()
305            ),
306        ).private_key(backend)
307        assert key
308
309        priv_num = key.private_numbers()
310        assert priv_num.private_value == vector["d"]
311        assert priv_num.public_numbers.x == vector["x"]
312        assert priv_num.public_numbers.y == vector["y"]
313        assert curve_type().name == priv_num.public_numbers.curve.name
314
315
316@pytest.mark.requires_backend_interface(interface=EllipticCurveBackend)
317class TestECDSAVectors(object):
318    @pytest.mark.parametrize(
319        ("vector", "hash_type"),
320        list(
321            itertools.product(
322                load_vectors_from_file(
323                    os.path.join(
324                        "asymmetric", "ECDSA", "FIPS_186-3", "KeyPair.rsp"
325                    ),
326                    load_fips_ecdsa_key_pair_vectors,
327                ),
328                _HASH_TYPES.values(),
329            )
330        ),
331    )
332    def test_signing_with_example_keys(self, backend, vector, hash_type):
333        curve_type = ec._CURVE_TYPES[vector["curve"]]
334
335        _skip_ecdsa_vector(backend, curve_type, hash_type)
336
337        key = ec.EllipticCurvePrivateNumbers(
338            vector["d"],
339            ec.EllipticCurvePublicNumbers(
340                vector["x"], vector["y"], curve_type()
341            ),
342        ).private_key(backend)
343        assert key
344
345        pkey = key.public_key()
346        assert pkey
347
348        with pytest.warns(CryptographyDeprecationWarning):
349            signer = key.signer(ec.ECDSA(hash_type()))
350        signer.update(b"YELLOW SUBMARINE")
351        signature = signer.finalize()
352
353        with pytest.warns(CryptographyDeprecationWarning):
354            verifier = pkey.verifier(signature, ec.ECDSA(hash_type()))
355        verifier.update(b"YELLOW SUBMARINE")
356        verifier.verify()
357
358    @pytest.mark.parametrize("curve", ec._CURVE_TYPES.values())
359    def test_generate_vector_curves(self, backend, curve):
360        _skip_curve_unsupported(backend, curve())
361
362        key = ec.generate_private_key(curve(), backend)
363        assert key
364        assert isinstance(key.curve, curve)
365        assert key.curve.key_size
366
367        pkey = key.public_key()
368        assert pkey
369        assert isinstance(pkey.curve, curve)
370        assert key.curve.key_size == pkey.curve.key_size
371
372    def test_generate_unknown_curve(self, backend):
373        with raises_unsupported_algorithm(
374            exceptions._Reasons.UNSUPPORTED_ELLIPTIC_CURVE
375        ):
376            ec.generate_private_key(DummyCurve(), backend)
377
378        assert (
379            backend.elliptic_curve_signature_algorithm_supported(
380                ec.ECDSA(hashes.SHA256()), DummyCurve()
381            )
382            is False
383        )
384
385    def test_unknown_signature_algoritm(self, backend):
386        _skip_curve_unsupported(backend, ec.SECP192R1())
387
388        key = ec.generate_private_key(ec.SECP192R1(), backend)
389
390        with raises_unsupported_algorithm(
391            exceptions._Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM
392        ), pytest.warns(CryptographyDeprecationWarning):
393            key.signer(DummySignatureAlgorithm())
394
395        with raises_unsupported_algorithm(
396            exceptions._Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM
397        ):
398            key.sign(b"somedata", DummySignatureAlgorithm())
399
400        with raises_unsupported_algorithm(
401            exceptions._Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM
402        ), pytest.warns(CryptographyDeprecationWarning):
403            key.public_key().verifier(b"", DummySignatureAlgorithm())
404
405        with raises_unsupported_algorithm(
406            exceptions._Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM
407        ):
408            key.public_key().verify(
409                b"signature", b"data", DummySignatureAlgorithm()
410            )
411
412        assert (
413            backend.elliptic_curve_signature_algorithm_supported(
414                DummySignatureAlgorithm(), ec.SECP192R1()
415            )
416            is False
417        )
418
419    def test_load_invalid_ec_key_from_numbers(self, backend):
420        _skip_curve_unsupported(backend, ec.SECP256R1())
421
422        numbers = ec.EllipticCurvePrivateNumbers(
423            357646505660320080863666618182642070958081774038609089496899025506,
424            ec.EllipticCurvePublicNumbers(
425                47250808410327023131573602008345894927686381772325561185532964,
426                1120253292479243545483756778742719537373113335231773536789915,
427                ec.SECP256R1(),
428            ),
429        )
430        with pytest.raises(ValueError):
431            numbers.private_key(backend)
432
433        numbers = ec.EllipticCurvePrivateNumbers(
434            357646505660320080863666618182642070958081774038609089496899025506,
435            ec.EllipticCurvePublicNumbers(
436                -4725080841032702313157360200834589492768638177232556118553296,
437                1120253292479243545483756778742719537373113335231773536789915,
438                ec.SECP256R1(),
439            ),
440        )
441        with pytest.raises(ValueError):
442            numbers.private_key(backend)
443
444        numbers = ec.EllipticCurvePrivateNumbers(
445            357646505660320080863666618182642070958081774038609089496899025506,
446            ec.EllipticCurvePublicNumbers(
447                47250808410327023131573602008345894927686381772325561185532964,
448                -1120253292479243545483756778742719537373113335231773536789915,
449                ec.SECP256R1(),
450            ),
451        )
452        with pytest.raises(ValueError):
453            numbers.private_key(backend)
454
455    def test_load_invalid_public_ec_key_from_numbers(self, backend):
456        _skip_curve_unsupported(backend, ec.SECP521R1())
457
458        # Bad X coordinate
459        numbers = ec.EllipticCurvePublicNumbers(
460            int(
461                "000003647356b91f8ace114c7247ecf4f4a622553fc025e04a178f179ef27"
462                "9090c184af678a4c78f635483bdd8aa544851c6ef291c1f0d6a241ebfd145"
463                "77d1d30d9903ce",
464                16,
465            ),
466            int(
467                "000001499bc7e079322ea0fcfbd6b40103fa6a1536c2257b182db0df4b369"
468                "6ec643adf100eb4f2025d1b873f82e5a475d6e4400ba777090eeb4563a115"
469                "09e4c87319dc26",
470                16,
471            ),
472            ec.SECP521R1(),
473        )
474        with pytest.raises(ValueError):
475            numbers.public_key(backend)
476
477        # Bad Y coordinate
478        numbers = ec.EllipticCurvePublicNumbers(
479            int(
480                "0000019aadc221cc0525118ab6d5aa1f64720603de0be128cbfea0b381ad8"
481                "02a2facc6370bb58cf88b3f0c692bc654ee19d6cad198f10d4b681b396f20"
482                "d2e40603fa945b",
483                16,
484            ),
485            int(
486                "0000025da392803a320717a08d4cb3dea932039badff363b71bdb8064e726"
487                "6c7f4f4b748d4d425347fc33e3885d34b750fa7fcd5691f4d90c89522ce33"
488                "feff5db10088a5",
489                16,
490            ),
491            ec.SECP521R1(),
492        )
493        with pytest.raises(ValueError):
494            numbers.public_key(backend)
495
496    @pytest.mark.parametrize(
497        "vector",
498        itertools.chain(
499            load_vectors_from_file(
500                os.path.join(
501                    "asymmetric", "ECDSA", "FIPS_186-3", "SigGen.txt"
502                ),
503                load_fips_ecdsa_signing_vectors,
504            ),
505            load_vectors_from_file(
506                os.path.join("asymmetric", "ECDSA", "SECP256K1", "SigGen.txt"),
507                load_fips_ecdsa_signing_vectors,
508            ),
509        ),
510    )
511    def test_signatures(self, backend, vector):
512        hash_type = _HASH_TYPES[vector["digest_algorithm"]]
513        curve_type = ec._CURVE_TYPES[vector["curve"]]
514
515        _skip_ecdsa_vector(backend, curve_type, hash_type)
516
517        key = ec.EllipticCurvePublicNumbers(
518            vector["x"], vector["y"], curve_type()
519        ).public_key(backend)
520
521        signature = encode_dss_signature(vector["r"], vector["s"])
522
523        key.verify(signature, vector["message"], ec.ECDSA(hash_type()))
524
525    @pytest.mark.parametrize(
526        "vector",
527        load_vectors_from_file(
528            os.path.join("asymmetric", "ECDSA", "FIPS_186-3", "SigVer.rsp"),
529            load_fips_ecdsa_signing_vectors,
530        ),
531    )
532    def test_signature_failures(self, backend, vector):
533        hash_type = _HASH_TYPES[vector["digest_algorithm"]]
534        curve_type = ec._CURVE_TYPES[vector["curve"]]
535
536        _skip_ecdsa_vector(backend, curve_type, hash_type)
537
538        key = ec.EllipticCurvePublicNumbers(
539            vector["x"], vector["y"], curve_type()
540        ).public_key(backend)
541
542        signature = encode_dss_signature(vector["r"], vector["s"])
543
544        if vector["fail"] is True:
545            with pytest.raises(exceptions.InvalidSignature):
546                key.verify(signature, vector["message"], ec.ECDSA(hash_type()))
547        else:
548            key.verify(signature, vector["message"], ec.ECDSA(hash_type()))
549
550    def test_sign(self, backend):
551        _skip_curve_unsupported(backend, ec.SECP256R1())
552        message = b"one little message"
553        algorithm = ec.ECDSA(hashes.SHA1())
554        private_key = ec.generate_private_key(ec.SECP256R1(), backend)
555        signature = private_key.sign(message, algorithm)
556        public_key = private_key.public_key()
557        public_key.verify(signature, message, algorithm)
558
559    def test_sign_prehashed(self, backend):
560        _skip_curve_unsupported(backend, ec.SECP256R1())
561        message = b"one little message"
562        h = hashes.Hash(hashes.SHA1(), backend)
563        h.update(message)
564        data = h.finalize()
565        algorithm = ec.ECDSA(Prehashed(hashes.SHA1()))
566        private_key = ec.generate_private_key(ec.SECP256R1(), backend)
567        signature = private_key.sign(data, algorithm)
568        public_key = private_key.public_key()
569        public_key.verify(signature, message, ec.ECDSA(hashes.SHA1()))
570
571    def test_sign_prehashed_digest_mismatch(self, backend):
572        _skip_curve_unsupported(backend, ec.SECP256R1())
573        message = b"one little message"
574        h = hashes.Hash(hashes.SHA1(), backend)
575        h.update(message)
576        data = h.finalize()
577        algorithm = ec.ECDSA(Prehashed(hashes.SHA256()))
578        private_key = ec.generate_private_key(ec.SECP256R1(), backend)
579        with pytest.raises(ValueError):
580            private_key.sign(data, algorithm)
581
582    def test_verify(self, backend):
583        _skip_curve_unsupported(backend, ec.SECP256R1())
584        message = b"one little message"
585        algorithm = ec.ECDSA(hashes.SHA1())
586        private_key = ec.generate_private_key(ec.SECP256R1(), backend)
587        signature = private_key.sign(message, algorithm)
588        public_key = private_key.public_key()
589        public_key.verify(signature, message, algorithm)
590
591    def test_verify_prehashed(self, backend):
592        _skip_curve_unsupported(backend, ec.SECP256R1())
593        message = b"one little message"
594        algorithm = ec.ECDSA(hashes.SHA1())
595        private_key = ec.generate_private_key(ec.SECP256R1(), backend)
596        signature = private_key.sign(message, algorithm)
597        h = hashes.Hash(hashes.SHA1(), backend)
598        h.update(message)
599        data = h.finalize()
600        public_key = private_key.public_key()
601        public_key.verify(signature, data, ec.ECDSA(Prehashed(hashes.SHA1())))
602
603    def test_verify_prehashed_digest_mismatch(self, backend):
604        _skip_curve_unsupported(backend, ec.SECP256R1())
605        message = b"one little message"
606        private_key = ec.generate_private_key(ec.SECP256R1(), backend)
607        h = hashes.Hash(hashes.SHA1(), backend)
608        h.update(message)
609        data = h.finalize()
610        public_key = private_key.public_key()
611        with pytest.raises(ValueError):
612            public_key.verify(
613                b"\x00" * 32, data, ec.ECDSA(Prehashed(hashes.SHA256()))
614            )
615
616    def test_prehashed_unsupported_in_signer_ctx(self, backend):
617        _skip_curve_unsupported(backend, ec.SECP256R1())
618        private_key = ec.generate_private_key(ec.SECP256R1(), backend)
619        with pytest.raises(TypeError), pytest.warns(
620            CryptographyDeprecationWarning
621        ):
622            private_key.signer(ec.ECDSA(Prehashed(hashes.SHA1())))
623
624    def test_prehashed_unsupported_in_verifier_ctx(self, backend):
625        _skip_curve_unsupported(backend, ec.SECP256R1())
626        private_key = ec.generate_private_key(ec.SECP256R1(), backend)
627        public_key = private_key.public_key()
628        with pytest.raises(TypeError), pytest.warns(
629            CryptographyDeprecationWarning
630        ):
631            public_key.verifier(b"0" * 64, ec.ECDSA(Prehashed(hashes.SHA1())))
632
633
634class TestECNumbersEquality(object):
635    def test_public_numbers_eq(self):
636        pub = ec.EllipticCurvePublicNumbers(1, 2, ec.SECP192R1())
637        assert pub == ec.EllipticCurvePublicNumbers(1, 2, ec.SECP192R1())
638
639    def test_public_numbers_ne(self):
640        pub = ec.EllipticCurvePublicNumbers(1, 2, ec.SECP192R1())
641        assert pub != ec.EllipticCurvePublicNumbers(1, 2, ec.SECP384R1())
642        assert pub != ec.EllipticCurvePublicNumbers(1, 3, ec.SECP192R1())
643        assert pub != ec.EllipticCurvePublicNumbers(2, 2, ec.SECP192R1())
644        assert pub != object()
645
646    def test_private_numbers_eq(self):
647        pub = ec.EllipticCurvePublicNumbers(1, 2, ec.SECP192R1())
648        priv = ec.EllipticCurvePrivateNumbers(1, pub)
649        assert priv == ec.EllipticCurvePrivateNumbers(
650            1, ec.EllipticCurvePublicNumbers(1, 2, ec.SECP192R1())
651        )
652
653    def test_private_numbers_ne(self):
654        pub = ec.EllipticCurvePublicNumbers(1, 2, ec.SECP192R1())
655        priv = ec.EllipticCurvePrivateNumbers(1, pub)
656        assert priv != ec.EllipticCurvePrivateNumbers(
657            2, ec.EllipticCurvePublicNumbers(1, 2, ec.SECP192R1())
658        )
659        assert priv != ec.EllipticCurvePrivateNumbers(
660            1, ec.EllipticCurvePublicNumbers(2, 2, ec.SECP192R1())
661        )
662        assert priv != ec.EllipticCurvePrivateNumbers(
663            1, ec.EllipticCurvePublicNumbers(1, 3, ec.SECP192R1())
664        )
665        assert priv != ec.EllipticCurvePrivateNumbers(
666            1, ec.EllipticCurvePublicNumbers(1, 2, ec.SECP521R1())
667        )
668        assert priv != object()
669
670
671@pytest.mark.requires_backend_interface(interface=EllipticCurveBackend)
672@pytest.mark.requires_backend_interface(interface=PEMSerializationBackend)
673class TestECSerialization(object):
674    @pytest.mark.parametrize(
675        ("fmt", "password"),
676        itertools.product(
677            [
678                serialization.PrivateFormat.TraditionalOpenSSL,
679                serialization.PrivateFormat.PKCS8,
680            ],
681            [
682                b"s",
683                b"longerpassword",
684                b"!*$&(@#$*&($T@%_somesymbols",
685                b"\x01" * 1000,
686            ],
687        ),
688    )
689    def test_private_bytes_encrypted_pem(self, backend, fmt, password):
690        skip_fips_traditional_openssl(backend, fmt)
691        _skip_curve_unsupported(backend, ec.SECP256R1())
692        key_bytes = load_vectors_from_file(
693            os.path.join("asymmetric", "PKCS8", "ec_private_key.pem"),
694            lambda pemfile: pemfile.read().encode(),
695        )
696        key = serialization.load_pem_private_key(key_bytes, None, backend)
697        serialized = key.private_bytes(
698            serialization.Encoding.PEM,
699            fmt,
700            serialization.BestAvailableEncryption(password),
701        )
702        loaded_key = serialization.load_pem_private_key(
703            serialized, password, backend
704        )
705        loaded_priv_num = loaded_key.private_numbers()
706        priv_num = key.private_numbers()
707        assert loaded_priv_num == priv_num
708
709    @pytest.mark.parametrize(
710        ("encoding", "fmt"),
711        [
712            (serialization.Encoding.Raw, serialization.PrivateFormat.PKCS8),
713            (serialization.Encoding.DER, serialization.PrivateFormat.Raw),
714            (serialization.Encoding.Raw, serialization.PrivateFormat.Raw),
715            (serialization.Encoding.X962, serialization.PrivateFormat.PKCS8),
716        ],
717    )
718    def test_private_bytes_rejects_invalid(self, encoding, fmt, backend):
719        _skip_curve_unsupported(backend, ec.SECP256R1())
720        key = ec.generate_private_key(ec.SECP256R1(), backend)
721        with pytest.raises(ValueError):
722            key.private_bytes(encoding, fmt, serialization.NoEncryption())
723
724    @pytest.mark.parametrize(
725        ("fmt", "password"),
726        [
727            [serialization.PrivateFormat.PKCS8, b"s"],
728            [serialization.PrivateFormat.PKCS8, b"longerpassword"],
729            [serialization.PrivateFormat.PKCS8, b"!*$&(@#$*&($T@%_somesymbol"],
730            [serialization.PrivateFormat.PKCS8, b"\x01" * 1000],
731        ],
732    )
733    def test_private_bytes_encrypted_der(self, backend, fmt, password):
734        _skip_curve_unsupported(backend, ec.SECP256R1())
735        key_bytes = load_vectors_from_file(
736            os.path.join("asymmetric", "PKCS8", "ec_private_key.pem"),
737            lambda pemfile: pemfile.read().encode(),
738        )
739        key = serialization.load_pem_private_key(key_bytes, None, backend)
740        serialized = key.private_bytes(
741            serialization.Encoding.DER,
742            fmt,
743            serialization.BestAvailableEncryption(password),
744        )
745        loaded_key = serialization.load_der_private_key(
746            serialized, password, backend
747        )
748        loaded_priv_num = loaded_key.private_numbers()
749        priv_num = key.private_numbers()
750        assert loaded_priv_num == priv_num
751
752    @pytest.mark.parametrize(
753        ("encoding", "fmt", "loader_func"),
754        [
755            [
756                serialization.Encoding.PEM,
757                serialization.PrivateFormat.TraditionalOpenSSL,
758                serialization.load_pem_private_key,
759            ],
760            [
761                serialization.Encoding.DER,
762                serialization.PrivateFormat.TraditionalOpenSSL,
763                serialization.load_der_private_key,
764            ],
765            [
766                serialization.Encoding.PEM,
767                serialization.PrivateFormat.PKCS8,
768                serialization.load_pem_private_key,
769            ],
770            [
771                serialization.Encoding.DER,
772                serialization.PrivateFormat.PKCS8,
773                serialization.load_der_private_key,
774            ],
775        ],
776    )
777    def test_private_bytes_unencrypted(
778        self, backend, encoding, fmt, loader_func
779    ):
780        _skip_curve_unsupported(backend, ec.SECP256R1())
781        key_bytes = load_vectors_from_file(
782            os.path.join("asymmetric", "PKCS8", "ec_private_key.pem"),
783            lambda pemfile: pemfile.read().encode(),
784        )
785        key = serialization.load_pem_private_key(key_bytes, None, backend)
786        serialized = key.private_bytes(
787            encoding, fmt, serialization.NoEncryption()
788        )
789        loaded_key = loader_func(serialized, None, backend)
790        loaded_priv_num = loaded_key.private_numbers()
791        priv_num = key.private_numbers()
792        assert loaded_priv_num == priv_num
793
794    @pytest.mark.skip_fips(
795        reason="Traditional OpenSSL key format is not supported in FIPS mode."
796    )
797    @pytest.mark.parametrize(
798        ("key_path", "encoding", "loader_func"),
799        [
800            [
801                os.path.join(
802                    "asymmetric", "PEM_Serialization", "ec_private_key.pem"
803                ),
804                serialization.Encoding.PEM,
805                serialization.load_pem_private_key,
806            ],
807            [
808                os.path.join(
809                    "asymmetric", "DER_Serialization", "ec_private_key.der"
810                ),
811                serialization.Encoding.DER,
812                serialization.load_der_private_key,
813            ],
814        ],
815    )
816    def test_private_bytes_traditional_openssl_unencrypted(
817        self, backend, key_path, encoding, loader_func
818    ):
819        _skip_curve_unsupported(backend, ec.SECP256R1())
820        key_bytes = load_vectors_from_file(
821            key_path, lambda pemfile: pemfile.read(), mode="rb"
822        )
823        key = loader_func(key_bytes, None, backend)
824        serialized = key.private_bytes(
825            encoding,
826            serialization.PrivateFormat.TraditionalOpenSSL,
827            serialization.NoEncryption(),
828        )
829        assert serialized == key_bytes
830
831    def test_private_bytes_traditional_der_encrypted_invalid(self, backend):
832        _skip_curve_unsupported(backend, ec.SECP256R1())
833        key = load_vectors_from_file(
834            os.path.join("asymmetric", "PKCS8", "ec_private_key.pem"),
835            lambda pemfile: serialization.load_pem_private_key(
836                pemfile.read().encode(), None, backend
837            ),
838        )
839        with pytest.raises(ValueError):
840            key.private_bytes(
841                serialization.Encoding.DER,
842                serialization.PrivateFormat.TraditionalOpenSSL,
843                serialization.BestAvailableEncryption(b"password"),
844            )
845
846    def test_private_bytes_invalid_encoding(self, backend):
847        _skip_curve_unsupported(backend, ec.SECP256R1())
848        key = load_vectors_from_file(
849            os.path.join("asymmetric", "PKCS8", "ec_private_key.pem"),
850            lambda pemfile: serialization.load_pem_private_key(
851                pemfile.read().encode(), None, backend
852            ),
853        )
854        with pytest.raises(TypeError):
855            key.private_bytes(
856                "notencoding",
857                serialization.PrivateFormat.PKCS8,
858                serialization.NoEncryption(),
859            )
860
861    def test_private_bytes_invalid_format(self, backend):
862        _skip_curve_unsupported(backend, ec.SECP256R1())
863        key = load_vectors_from_file(
864            os.path.join("asymmetric", "PKCS8", "ec_private_key.pem"),
865            lambda pemfile: serialization.load_pem_private_key(
866                pemfile.read().encode(), None, backend
867            ),
868        )
869        with pytest.raises(TypeError):
870            key.private_bytes(
871                serialization.Encoding.PEM,
872                "invalidformat",
873                serialization.NoEncryption(),
874            )
875
876    def test_private_bytes_invalid_encryption_algorithm(self, backend):
877        _skip_curve_unsupported(backend, ec.SECP256R1())
878        key = load_vectors_from_file(
879            os.path.join("asymmetric", "PKCS8", "ec_private_key.pem"),
880            lambda pemfile: serialization.load_pem_private_key(
881                pemfile.read().encode(), None, backend
882            ),
883        )
884        with pytest.raises(TypeError):
885            key.private_bytes(
886                serialization.Encoding.PEM,
887                serialization.PrivateFormat.TraditionalOpenSSL,
888                "notanencalg",
889            )
890
891    def test_private_bytes_unsupported_encryption_type(self, backend):
892        _skip_curve_unsupported(backend, ec.SECP256R1())
893        key = load_vectors_from_file(
894            os.path.join("asymmetric", "PKCS8", "ec_private_key.pem"),
895            lambda pemfile: serialization.load_pem_private_key(
896                pemfile.read().encode(), None, backend
897            ),
898        )
899        with pytest.raises(ValueError):
900            key.private_bytes(
901                serialization.Encoding.PEM,
902                serialization.PrivateFormat.TraditionalOpenSSL,
903                DummyKeySerializationEncryption(),
904            )
905
906    def test_public_bytes_from_derived_public_key(self, backend):
907        _skip_curve_unsupported(backend, ec.SECP256R1())
908        key = load_vectors_from_file(
909            os.path.join("asymmetric", "PKCS8", "ec_private_key.pem"),
910            lambda pemfile: serialization.load_pem_private_key(
911                pemfile.read().encode(), None, backend
912            ),
913        )
914        public = key.public_key()
915        pem = public.public_bytes(
916            serialization.Encoding.PEM,
917            serialization.PublicFormat.SubjectPublicKeyInfo,
918        )
919        parsed_public = serialization.load_pem_public_key(pem, backend)
920        assert parsed_public
921
922
923@pytest.mark.requires_backend_interface(interface=EllipticCurveBackend)
924@pytest.mark.requires_backend_interface(interface=PEMSerializationBackend)
925class TestEllipticCurvePEMPublicKeySerialization(object):
926    @pytest.mark.parametrize(
927        ("key_path", "loader_func", "encoding"),
928        [
929            (
930                os.path.join(
931                    "asymmetric", "PEM_Serialization", "ec_public_key.pem"
932                ),
933                serialization.load_pem_public_key,
934                serialization.Encoding.PEM,
935            ),
936            (
937                os.path.join(
938                    "asymmetric", "DER_Serialization", "ec_public_key.der"
939                ),
940                serialization.load_der_public_key,
941                serialization.Encoding.DER,
942            ),
943        ],
944    )
945    def test_public_bytes_match(
946        self, key_path, loader_func, encoding, backend
947    ):
948        _skip_curve_unsupported(backend, ec.SECP256R1())
949        key_bytes = load_vectors_from_file(
950            key_path, lambda pemfile: pemfile.read(), mode="rb"
951        )
952        key = loader_func(key_bytes, backend)
953        serialized = key.public_bytes(
954            encoding,
955            serialization.PublicFormat.SubjectPublicKeyInfo,
956        )
957        assert serialized == key_bytes
958
959    def test_public_bytes_openssh(self, backend):
960        _skip_curve_unsupported(backend, ec.SECP192R1())
961        _skip_curve_unsupported(backend, ec.SECP256R1())
962
963        key_bytes = load_vectors_from_file(
964            os.path.join(
965                "asymmetric", "PEM_Serialization", "ec_public_key.pem"
966            ),
967            lambda pemfile: pemfile.read(),
968            mode="rb",
969        )
970        key = serialization.load_pem_public_key(key_bytes, backend)
971
972        ssh_bytes = key.public_bytes(
973            serialization.Encoding.OpenSSH, serialization.PublicFormat.OpenSSH
974        )
975        assert ssh_bytes == (
976            b"ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAy"
977            b"NTYAAABBBCS8827s9rUZyxZTi/um01+oIlWrwLHOjQxRU9CDAndom00zVAw5BRrI"
978            b"KtHB+SWD4P+sVJTARSq1mHt8kOIWrPc="
979        )
980
981        key = ec.generate_private_key(ec.SECP192R1(), backend).public_key()
982        with pytest.raises(ValueError):
983            key.public_bytes(
984                serialization.Encoding.OpenSSH,
985                serialization.PublicFormat.OpenSSH,
986            )
987
988    def test_public_bytes_invalid_encoding(self, backend):
989        _skip_curve_unsupported(backend, ec.SECP256R1())
990        key = load_vectors_from_file(
991            os.path.join(
992                "asymmetric", "PEM_Serialization", "ec_public_key.pem"
993            ),
994            lambda pemfile: serialization.load_pem_public_key(
995                pemfile.read().encode(), backend
996            ),
997        )
998        with pytest.raises(TypeError):
999            key.public_bytes(
1000                "notencoding", serialization.PublicFormat.SubjectPublicKeyInfo
1001            )
1002
1003    @pytest.mark.parametrize(
1004        ("encoding", "fmt"),
1005        list(
1006            itertools.product(
1007                [
1008                    serialization.Encoding.Raw,
1009                    serialization.Encoding.X962,
1010                    serialization.Encoding.PEM,
1011                    serialization.Encoding.DER,
1012                ],
1013                [serialization.PublicFormat.Raw],
1014            )
1015        )
1016        + list(
1017            itertools.product(
1018                [serialization.Encoding.Raw],
1019                [
1020                    serialization.PublicFormat.SubjectPublicKeyInfo,
1021                    serialization.PublicFormat.PKCS1,
1022                    serialization.PublicFormat.UncompressedPoint,
1023                    serialization.PublicFormat.CompressedPoint,
1024                ],
1025            )
1026        ),
1027    )
1028    def test_public_bytes_rejects_invalid(self, encoding, fmt, backend):
1029        _skip_curve_unsupported(backend, ec.SECP256R1())
1030        key = ec.generate_private_key(ec.SECP256R1(), backend).public_key()
1031        with pytest.raises(ValueError):
1032            key.public_bytes(encoding, fmt)
1033
1034    def test_public_bytes_invalid_format(self, backend):
1035        _skip_curve_unsupported(backend, ec.SECP256R1())
1036        key = load_vectors_from_file(
1037            os.path.join(
1038                "asymmetric", "PEM_Serialization", "ec_public_key.pem"
1039            ),
1040            lambda pemfile: serialization.load_pem_public_key(
1041                pemfile.read().encode(), backend
1042            ),
1043        )
1044        with pytest.raises(TypeError):
1045            key.public_bytes(serialization.Encoding.PEM, "invalidformat")
1046
1047    def test_public_bytes_pkcs1_unsupported(self, backend):
1048        _skip_curve_unsupported(backend, ec.SECP256R1())
1049        key = load_vectors_from_file(
1050            os.path.join(
1051                "asymmetric", "PEM_Serialization", "ec_public_key.pem"
1052            ),
1053            lambda pemfile: serialization.load_pem_public_key(
1054                pemfile.read().encode(), backend
1055            ),
1056        )
1057        with pytest.raises(ValueError):
1058            key.public_bytes(
1059                serialization.Encoding.PEM, serialization.PublicFormat.PKCS1
1060            )
1061
1062    @pytest.mark.parametrize(
1063        "vector",
1064        load_vectors_from_file(
1065            os.path.join("asymmetric", "EC", "compressed_points.txt"),
1066            load_nist_vectors,
1067        ),
1068    )
1069    def test_from_encoded_point_compressed(self, vector, backend):
1070        curve = {b"SECP256R1": ec.SECP256R1(), b"SECP256K1": ec.SECP256K1()}[
1071            vector["curve"]
1072        ]
1073        _skip_curve_unsupported(backend, curve)
1074        point = binascii.unhexlify(vector["point"])
1075        pn = ec.EllipticCurvePublicKey.from_encoded_point(curve, point)
1076        public_num = pn.public_numbers()
1077        assert public_num.x == int(vector["x"], 16)
1078        assert public_num.y == int(vector["y"], 16)
1079
1080    def test_from_encoded_point_notoncurve(self):
1081        uncompressed_point = binascii.unhexlify(
1082            "047399336a9edf2197c2f8eb3d39aed9c34a66e45d918a07dc7684c42c9b37ac"
1083            "686699ececc4f5f0d756d3c450708a0694eb0a07a68b805070b40b058d27271f"
1084            "6e"
1085        )
1086        with pytest.raises(ValueError):
1087            ec.EllipticCurvePublicKey.from_encoded_point(
1088                ec.SECP256R1(), uncompressed_point
1089            )
1090
1091    def test_from_encoded_point_uncompressed(self):
1092        uncompressed_point = binascii.unhexlify(
1093            "047399336a9edf2197c2f8eb3d39aed9c34a66e45d918a07dc7684c42c9b37ac"
1094            "686699ececc4f5f0d756d3c450708a0694eb0a07a68b805070b40b058d27271f"
1095            "6d"
1096        )
1097        pn = ec.EllipticCurvePublicKey.from_encoded_point(
1098            ec.SECP256R1(), uncompressed_point
1099        )
1100        assert pn.public_numbers().x == int(
1101            "7399336a9edf2197c2f8eb3d39aed9c34a66e45d918a07dc7684c42c9b37ac68",
1102            16,
1103        )
1104        assert pn.public_numbers().y == int(
1105            "6699ececc4f5f0d756d3c450708a0694eb0a07a68b805070b40b058d27271f6d",
1106            16,
1107        )
1108
1109    def test_from_encoded_point_invalid_length(self):
1110        bad_data = binascii.unhexlify(
1111            "047399336a9edf2197c2f8eb3d39aed9c34a66e45d918a07dc7684c42c9b37ac"
1112            "686699ececc4f5f0d756d3c450708a0694eb0a07a68b805070b40b058d27271f"
1113            "6d"
1114        )
1115        with pytest.raises(ValueError):
1116            ec.EllipticCurvePublicKey.from_encoded_point(
1117                ec.SECP384R1(), bad_data
1118            )
1119
1120    def test_from_encoded_point_empty_byte_string(self):
1121        with pytest.raises(ValueError):
1122            ec.EllipticCurvePublicKey.from_encoded_point(ec.SECP384R1(), b"")
1123
1124    def test_from_encoded_point_not_a_curve(self):
1125        with pytest.raises(TypeError):
1126            ec.EllipticCurvePublicKey.from_encoded_point(
1127                "notacurve", b"\x04data"
1128            )
1129
1130    def test_from_encoded_point_unsupported_encoding(self):
1131        unsupported_type = binascii.unhexlify(
1132            "057399336a9edf2197c2f8eb3d39aed9c34a66e45d918a07dc7684c42c9b37ac6"
1133            "8"
1134        )
1135        with pytest.raises(ValueError):
1136            ec.EllipticCurvePublicKey.from_encoded_point(
1137                ec.SECP256R1(), unsupported_type
1138            )
1139
1140    @pytest.mark.parametrize(
1141        "vector",
1142        load_vectors_from_file(
1143            os.path.join("asymmetric", "EC", "compressed_points.txt"),
1144            load_nist_vectors,
1145        ),
1146    )
1147    def test_serialize_point(self, vector, backend):
1148        curve = {b"SECP256R1": ec.SECP256R1(), b"SECP256K1": ec.SECP256K1()}[
1149            vector["curve"]
1150        ]
1151        _skip_curve_unsupported(backend, curve)
1152        point = binascii.unhexlify(vector["point"])
1153        key = ec.EllipticCurvePublicKey.from_encoded_point(curve, point)
1154        key2 = ec.EllipticCurvePublicKey.from_encoded_point(
1155            curve,
1156            key.public_bytes(
1157                serialization.Encoding.X962,
1158                serialization.PublicFormat.UncompressedPoint,
1159            ),
1160        )
1161        assert (
1162            key.public_bytes(
1163                serialization.Encoding.X962,
1164                serialization.PublicFormat.CompressedPoint,
1165            )
1166            == point
1167        )
1168        assert (
1169            key2.public_bytes(
1170                serialization.Encoding.X962,
1171                serialization.PublicFormat.CompressedPoint,
1172            )
1173            == point
1174        )
1175
1176
1177@pytest.mark.requires_backend_interface(interface=EllipticCurveBackend)
1178class TestECDSAVerification(object):
1179    def test_signature_not_bytes(self, backend):
1180        _skip_curve_unsupported(backend, ec.SECP256R1())
1181        key = ec.generate_private_key(ec.SECP256R1(), backend)
1182        public_key = key.public_key()
1183        with pytest.raises(TypeError), pytest.warns(
1184            CryptographyDeprecationWarning
1185        ):
1186            public_key.verifier(1234, ec.ECDSA(hashes.SHA256()))
1187
1188
1189@pytest.mark.requires_backend_interface(interface=EllipticCurveBackend)
1190class TestECDH(object):
1191    @pytest.mark.parametrize(
1192        "vector",
1193        load_vectors_from_file(
1194            os.path.join(
1195                "asymmetric",
1196                "ECDH",
1197                "KASValidityTest_ECCStaticUnified_NOKC_ZZOnly_init.fax",
1198            ),
1199            load_kasvs_ecdh_vectors,
1200        ),
1201    )
1202    def test_key_exchange_with_vectors(self, backend, vector):
1203        _skip_exchange_algorithm_unsupported(
1204            backend, ec.ECDH(), ec._CURVE_TYPES[vector["curve"]]
1205        )
1206
1207        key_numbers = vector["IUT"]
1208        private_numbers = ec.EllipticCurvePrivateNumbers(
1209            key_numbers["d"],
1210            ec.EllipticCurvePublicNumbers(
1211                key_numbers["x"],
1212                key_numbers["y"],
1213                ec._CURVE_TYPES[vector["curve"]](),
1214            ),
1215        )
1216        # Errno 5-7 indicates a bad public or private key, this doesn't test
1217        # the ECDH code at all
1218        if vector["fail"] and vector["errno"] in [5, 6, 7]:
1219            with pytest.raises(ValueError):
1220                private_numbers.private_key(backend)
1221            return
1222        else:
1223            private_key = private_numbers.private_key(backend)
1224
1225        peer_numbers = vector["CAVS"]
1226        public_numbers = ec.EllipticCurvePublicNumbers(
1227            peer_numbers["x"],
1228            peer_numbers["y"],
1229            ec._CURVE_TYPES[vector["curve"]](),
1230        )
1231        # Errno 1 and 2 indicates a bad public key, this doesn't test the ECDH
1232        # code at all
1233        if vector["fail"] and vector["errno"] in [1, 2]:
1234            with pytest.raises(ValueError):
1235                public_numbers.public_key(backend)
1236            return
1237        else:
1238            peer_pubkey = public_numbers.public_key(backend)
1239
1240        z = private_key.exchange(ec.ECDH(), peer_pubkey)
1241        z = int(hexlify(z).decode("ascii"), 16)
1242        # At this point fail indicates that one of the underlying keys was
1243        # changed. This results in a non-matching derived key.
1244        if vector["fail"]:
1245            # Errno 8 indicates Z should be changed.
1246            assert vector["errno"] == 8
1247            assert z != vector["Z"]
1248        else:
1249            assert z == vector["Z"]
1250
1251    @pytest.mark.parametrize(
1252        "vector",
1253        load_vectors_from_file(
1254            os.path.join("asymmetric", "ECDH", "brainpool.txt"),
1255            load_nist_vectors,
1256        ),
1257    )
1258    def test_brainpool_kex(self, backend, vector):
1259        curve = ec._CURVE_TYPES[vector["curve"].decode("ascii")]
1260        _skip_exchange_algorithm_unsupported(backend, ec.ECDH(), curve)
1261        key = ec.EllipticCurvePrivateNumbers(
1262            int(vector["da"], 16),
1263            ec.EllipticCurvePublicNumbers(
1264                int(vector["x_qa"], 16), int(vector["y_qa"], 16), curve()
1265            ),
1266        ).private_key(backend)
1267        peer = ec.EllipticCurvePrivateNumbers(
1268            int(vector["db"], 16),
1269            ec.EllipticCurvePublicNumbers(
1270                int(vector["x_qb"], 16), int(vector["y_qb"], 16), curve()
1271            ),
1272        ).private_key(backend)
1273        shared_secret = key.exchange(ec.ECDH(), peer.public_key())
1274        assert shared_secret == binascii.unhexlify(vector["x_z"])
1275        shared_secret_2 = peer.exchange(ec.ECDH(), key.public_key())
1276        assert shared_secret_2 == binascii.unhexlify(vector["x_z"])
1277
1278    def test_exchange_unsupported_algorithm(self, backend):
1279        _skip_curve_unsupported(backend, ec.SECP256R1())
1280
1281        key = load_vectors_from_file(
1282            os.path.join("asymmetric", "PKCS8", "ec_private_key.pem"),
1283            lambda pemfile: serialization.load_pem_private_key(
1284                pemfile.read().encode(), None, backend
1285            ),
1286        )
1287
1288        with raises_unsupported_algorithm(
1289            exceptions._Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM
1290        ):
1291            key.exchange(None, key.public_key())
1292
1293    def test_exchange_non_matching_curve(self, backend):
1294        _skip_curve_unsupported(backend, ec.SECP256R1())
1295        _skip_curve_unsupported(backend, ec.SECP384R1())
1296
1297        key = load_vectors_from_file(
1298            os.path.join("asymmetric", "PKCS8", "ec_private_key.pem"),
1299            lambda pemfile: serialization.load_pem_private_key(
1300                pemfile.read().encode(), None, backend
1301            ),
1302        )
1303        public_key = EC_KEY_SECP384R1.public_numbers.public_key(backend)
1304
1305        with pytest.raises(ValueError):
1306            key.exchange(ec.ECDH(), public_key)
1307