From 0095a3b74f278dddc6cafda599d280c83368ce7d Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Tue, 17 Jul 2018 20:08:49 +0000 Subject: [PATCH 1/5] Refs #3331 -- integrated wycheproof ECDH tests --- tests/utils.py | 4 ++ tests/wycheproof/test_ecdh.py | 77 +++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+) create mode 100644 tests/wycheproof/test_ecdh.py diff --git a/tests/utils.py b/tests/utils.py index ccc3b7c1bbea..b950f8bd9996 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -906,6 +906,10 @@ def valid(self): def acceptable(self): return self.testcase["result"] == "acceptable" + @property + def invalid(self): + return self.testcase["result"] == "invalid" + def has_flag(self, flag): return flag in self.testcase["flags"] diff --git a/tests/wycheproof/test_ecdh.py b/tests/wycheproof/test_ecdh.py new file mode 100644 index 000000000000..784be1c53d4f --- /dev/null +++ b/tests/wycheproof/test_ecdh.py @@ -0,0 +1,77 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import binascii + +import pytest + +from cryptography import utils +from cryptography.exceptions import UnsupportedAlgorithm +from cryptography.hazmat.backends.interfaces import EllipticCurveBackend +from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives.asymmetric import ec + + +_CURVES = { + "secp224r1": ec.SECP224R1(), + "secp256r1": ec.SECP256R1(), + "secp384r1": ec.SECP384R1(), + "secp521r1": ec.SECP521R1(), + "secp256k1": ec.SECP256K1(), + "brainpoolP224r1": None, + "brainpoolP256r1": ec.BrainpoolP256R1(), + "brainpoolP320r1": None, + "brainpoolP384r1": ec.BrainpoolP384R1(), + "brainpoolP512r1": ec.BrainpoolP512R1(), + "brainpoolP224t1": None, + "brainpoolP256t1": None, + "brainpoolP320t1": None, + "brainpoolP384t1": None, + "brainpoolP512t1": None, +} + +@pytest.mark.requires_backend_interface(interface=EllipticCurveBackend) +@pytest.mark.wycheproof_tests( + "ecdh_test.json", + "ecdh_brainpoolP224r1_test.json", + "ecdh_brainpoolP256r1_test.json", + "ecdh_brainpoolP320r1_test.json", + "ecdh_brainpoolP384r1_test.json", + "ecdh_brainpoolP512r1_test.json", + "ecdh_secp224r1_test.json", + "ecdh_secp256k1_test.json", + "ecdh_secp256r1_test.json", + "ecdh_secp384r1_test.json", + "ecdh_secp521r1_test.json", +) +def test_ecdh(backend, wycheproof): + curve = _CURVES[wycheproof.testcase["curve"]] + if curve is None: + pytest.skip( + "Unsupport curve ({})".format(wycheproof.testcase["curve"]) + ) + private_key = ec.derive_private_key( + int(wycheproof.testcase["private"], 16), curve, backend + ) + + try: + public_key = serialization.load_der_public_key( + binascii.unhexlify(wycheproof.testcase["public"]), backend + ) + except NotImplementedError: + assert wycheproof.has_flag("UnnamedCurve") + return + except ValueError: + assert wycheproof.invalid or wycheproof.acceptable + return + except UnsupportedAlgorithm: + return + + if wycheproof.valid or wycheproof.acceptable: + computed_shared = private_key.exchange(ec.ECDH(), public_key) + else: + with pytest.raises(ValueError): + private_key.exchange(ec.ECDH(), public_key) From e4dad263c593fbb6b874b72fff8023f1cb342462 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Tue, 17 Jul 2018 20:19:26 +0000 Subject: [PATCH 2/5] flake8 + missing assert --- tests/wycheproof/test_ecdh.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/wycheproof/test_ecdh.py b/tests/wycheproof/test_ecdh.py index 784be1c53d4f..d2b96c05a62d 100644 --- a/tests/wycheproof/test_ecdh.py +++ b/tests/wycheproof/test_ecdh.py @@ -8,7 +8,6 @@ import pytest -from cryptography import utils from cryptography.exceptions import UnsupportedAlgorithm from cryptography.hazmat.backends.interfaces import EllipticCurveBackend from cryptography.hazmat.primitives import serialization @@ -33,6 +32,7 @@ "brainpoolP512t1": None, } + @pytest.mark.requires_backend_interface(interface=EllipticCurveBackend) @pytest.mark.wycheproof_tests( "ecdh_test.json", @@ -51,7 +51,7 @@ def test_ecdh(backend, wycheproof): curve = _CURVES[wycheproof.testcase["curve"]] if curve is None: pytest.skip( - "Unsupport curve ({})".format(wycheproof.testcase["curve"]) + "Unsupport curve ({})".format(wycheproof.testcase["curve"]) ) private_key = ec.derive_private_key( int(wycheproof.testcase["private"], 16), curve, backend @@ -72,6 +72,8 @@ def test_ecdh(backend, wycheproof): if wycheproof.valid or wycheproof.acceptable: computed_shared = private_key.exchange(ec.ECDH(), public_key) + expected_shared = binascii.unhexlify(wycheproof.testcase["shared"]) + assert computed_shared == expected_shared else: with pytest.raises(ValueError): private_key.exchange(ec.ECDH(), public_key) From 06d7a3ae2fcdb387f3ff8ef0afff1f63d43b43b1 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Tue, 17 Jul 2018 20:41:17 +0000 Subject: [PATCH 3/5] Handle this error case --- tests/wycheproof/test_ecdh.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/tests/wycheproof/test_ecdh.py b/tests/wycheproof/test_ecdh.py index d2b96c05a62d..eb15e785ea57 100644 --- a/tests/wycheproof/test_ecdh.py +++ b/tests/wycheproof/test_ecdh.py @@ -53,9 +53,13 @@ def test_ecdh(backend, wycheproof): pytest.skip( "Unsupport curve ({})".format(wycheproof.testcase["curve"]) ) - private_key = ec.derive_private_key( - int(wycheproof.testcase["private"], 16), curve, backend - ) + + try: + private_key = ec.derive_private_key( + int(wycheproof.testcase["private"], 16), curve, backend + ) + except UnsupportedAlgorithm: + return try: public_key = serialization.load_der_public_key( From 0d6b47de42e2354fba9788d2ea50c94310c65c34 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Wed, 18 Jul 2018 12:12:13 +0800 Subject: [PATCH 4/5] skip on unsupported --- tests/wycheproof/test_ecdh.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/wycheproof/test_ecdh.py b/tests/wycheproof/test_ecdh.py index eb15e785ea57..e9c5cb34de4b 100644 --- a/tests/wycheproof/test_ecdh.py +++ b/tests/wycheproof/test_ecdh.py @@ -13,6 +13,8 @@ from cryptography.hazmat.primitives import serialization from cryptography.hazmat.primitives.asymmetric import ec +from ..hazmat.primitives.test_ec import _skip_exchange_algorithm_unsupported + _CURVES = { "secp224r1": ec.SECP224R1(), @@ -51,8 +53,9 @@ def test_ecdh(backend, wycheproof): curve = _CURVES[wycheproof.testcase["curve"]] if curve is None: pytest.skip( - "Unsupport curve ({})".format(wycheproof.testcase["curve"]) + "Unsupported curve ({})".format(wycheproof.testcase["curve"]) ) + _skip_exchange_algorithm_unsupported(backend, ec.ECDH(), curve) try: private_key = ec.derive_private_key( From 501a4c553dd6b8fd59bfdd2b3e959b0ecdfe7329 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Wed, 18 Jul 2018 15:45:57 +0800 Subject: [PATCH 5/5] shouldn't need to try here any more --- tests/wycheproof/test_ecdh.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/tests/wycheproof/test_ecdh.py b/tests/wycheproof/test_ecdh.py index e9c5cb34de4b..0850b627ddbd 100644 --- a/tests/wycheproof/test_ecdh.py +++ b/tests/wycheproof/test_ecdh.py @@ -57,12 +57,9 @@ def test_ecdh(backend, wycheproof): ) _skip_exchange_algorithm_unsupported(backend, ec.ECDH(), curve) - try: - private_key = ec.derive_private_key( - int(wycheproof.testcase["private"], 16), curve, backend - ) - except UnsupportedAlgorithm: - return + private_key = ec.derive_private_key( + int(wycheproof.testcase["private"], 16), curve, backend + ) try: public_key = serialization.load_der_public_key(