aboutsummaryrefslogtreecommitdiffstats
path: root/tests/hazmat/primitives/test_ec.py
diff options
context:
space:
mode:
Diffstat (limited to 'tests/hazmat/primitives/test_ec.py')
-rw-r--r--tests/hazmat/primitives/test_ec.py734
1 files changed, 649 insertions, 85 deletions
diff --git a/tests/hazmat/primitives/test_ec.py b/tests/hazmat/primitives/test_ec.py
index cc185145..987c0ff0 100644
--- a/tests/hazmat/primitives/test_ec.py
+++ b/tests/hazmat/primitives/test_ec.py
@@ -4,24 +4,30 @@
from __future__ import absolute_import, division, print_function
+import binascii
import itertools
import os
+from binascii import hexlify
import pytest
-from cryptography import exceptions, utils
+from cryptography import exceptions, utils, x509
from cryptography.hazmat.backends.interfaces import (
EllipticCurveBackend, PEMSerializationBackend
)
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.primitives.asymmetric.utils import (
- encode_rfc6979_signature
+ Prehashed, encode_dss_signature
)
+from cryptography.utils import CryptographyDeprecationWarning
+from .fixtures_ec import EC_KEY_SECP384R1
+from ...doubles import DummyKeySerializationEncryption
from ...utils import (
load_fips_ecdsa_key_pair_vectors, load_fips_ecdsa_signing_vectors,
- load_vectors_from_file, raises_unsupported_algorithm
+ load_kasvs_ecdh_vectors, load_nist_vectors, load_vectors_from_file,
+ raises_unsupported_algorithm
)
_HASH_TYPES = {
@@ -33,25 +39,13 @@ _HASH_TYPES = {
}
-def _skip_if_no_serialization(key, backend):
- if not isinstance(
- key, (
- ec.EllipticCurvePrivateKeyWithSerialization,
- ec.EllipticCurvePublicKeyWithSerialization
- )
- ):
- pytest.skip(
- "{0} does not support EC key serialization".format(backend)
- )
-
-
def _skip_ecdsa_vector(backend, curve_type, hash_type):
if not backend.elliptic_curve_signature_algorithm_supported(
ec.ECDSA(hash_type()),
curve_type()
):
pytest.skip(
- "ECDSA not supported with this hash {0} and curve {1}".format(
+ "ECDSA not supported with this hash {} and curve {}".format(
hash_type().name, curve_type().name
)
)
@@ -60,12 +54,29 @@ def _skip_ecdsa_vector(backend, curve_type, hash_type):
def _skip_curve_unsupported(backend, curve):
if not backend.elliptic_curve_supported(curve):
pytest.skip(
- "Curve {0} is not supported by this backend {1}".format(
+ "Curve {} is not supported by this backend {}".format(
curve.name, backend
)
)
+def _skip_exchange_algorithm_unsupported(backend, algorithm, curve):
+ if not backend.elliptic_curve_exchange_algorithm_supported(
+ algorithm, curve
+ ):
+ pytest.skip(
+ "Exchange with {} curve is not supported by {}".format(
+ curve.name, backend
+ )
+ )
+
+
+def test_get_curve_for_oid():
+ assert ec.get_curve_for_oid(ec.EllipticCurveOID.SECP256R1) == ec.SECP256R1
+ with pytest.raises(LookupError):
+ ec.get_curve_for_oid(x509.ObjectIdentifier("1.1.1.1"))
+
+
@utils.register_interface(ec.EllipticCurve)
class DummyCurve(object):
name = "dummy-curve"
@@ -77,20 +88,51 @@ class DummySignatureAlgorithm(object):
algorithm = None
-@utils.register_interface(serialization.KeySerializationEncryption)
-class DummyKeyEncryption(object):
- pass
-
-
@pytest.mark.requires_backend_interface(interface=EllipticCurveBackend)
def test_skip_curve_unsupported(backend):
with pytest.raises(pytest.skip.Exception):
_skip_curve_unsupported(backend, DummyCurve())
-def test_skip_no_serialization():
+@pytest.mark.requires_backend_interface(interface=EllipticCurveBackend)
+def test_skip_exchange_algorithm_unsupported(backend):
+ with pytest.raises(pytest.skip.Exception):
+ _skip_exchange_algorithm_unsupported(backend, ec.ECDH(), DummyCurve())
+
+
+@pytest.mark.requires_backend_interface(interface=EllipticCurveBackend)
+def test_skip_ecdsa_vector(backend):
with pytest.raises(pytest.skip.Exception):
- _skip_if_no_serialization("fakebackend", "fakekey")
+ _skip_ecdsa_vector(backend, DummyCurve, hashes.SHA256)
+
+
+@pytest.mark.requires_backend_interface(interface=EllipticCurveBackend)
+def test_derive_private_key_success(backend):
+ curve = ec.SECP256K1()
+ _skip_curve_unsupported(backend, curve)
+
+ private_numbers = ec.generate_private_key(curve, backend).private_numbers()
+
+ derived_key = ec.derive_private_key(
+ private_numbers.private_value, curve, backend
+ )
+
+ assert private_numbers == derived_key.private_numbers()
+
+
+@pytest.mark.requires_backend_interface(interface=EllipticCurveBackend)
+def test_derive_private_key_errors(backend):
+ curve = ec.SECP256K1()
+ _skip_curve_unsupported(backend, curve)
+
+ with pytest.raises(TypeError):
+ ec.derive_private_key('one', curve, backend)
+
+ with pytest.raises(TypeError):
+ ec.derive_private_key(10, 'five', backend)
+
+ with pytest.raises(ValueError):
+ ec.derive_private_key(-7, curve, backend)
def test_ec_numbers():
@@ -106,43 +148,135 @@ def test_ec_numbers():
assert numbers.public_numbers.y == 3
assert isinstance(numbers.public_numbers.curve, DummyCurve)
+
+@pytest.mark.parametrize(
+ ("private_value", "x", "y", "curve"),
+ [
+ (None, 2, 3, DummyCurve()),
+ (1, None, 3, DummyCurve()),
+ (1, 2, None, DummyCurve()),
+ (1, 2, 3, None),
+ ]
+)
+def test_invalid_ec_numbers_args(private_value, x, y, curve):
with pytest.raises(TypeError):
ec.EllipticCurvePrivateNumbers(
- None,
- ec.EllipticCurvePublicNumbers(
- 2, 3, DummyCurve()
- )
+ private_value, ec.EllipticCurvePublicNumbers(x, y, curve)
)
+
+def test_invalid_private_numbers_public_numbers():
with pytest.raises(TypeError):
- ec.EllipticCurvePrivateNumbers(
- 1,
- ec.EllipticCurvePublicNumbers(
- None, 3, DummyCurve()
- )
+ ec.EllipticCurvePrivateNumbers(1, None)
+
+
+def test_encode_point():
+ # secp256r1 point
+ x = int(
+ '233ea3b0027127084cd2cd336a13aeef69c598d8af61369a36454a17c6c22aec',
+ 16
+ )
+ y = int(
+ '3ea2c10a84153862be4ec82940f0543f9ba866af9751a6ee79d38460b35f442e',
+ 16
+ )
+ pn = ec.EllipticCurvePublicNumbers(x, y, ec.SECP256R1())
+ with pytest.warns(utils.PersistentlyDeprecated2019):
+ data = pn.encode_point()
+ assert data == binascii.unhexlify(
+ "04233ea3b0027127084cd2cd336a13aeef69c598d8af61369a36454a17c6c22ae"
+ "c3ea2c10a84153862be4ec82940f0543f9ba866af9751a6ee79d38460b35f442e"
+ )
+
+
+def test_from_encoded_point():
+ # secp256r1 point
+ data = binascii.unhexlify(
+ "04233ea3b0027127084cd2cd336a13aeef69c598d8af61369a36454a17c6c22ae"
+ "c3ea2c10a84153862be4ec82940f0543f9ba866af9751a6ee79d38460b35f442e"
+ )
+ with pytest.warns(CryptographyDeprecationWarning):
+ pn = ec.EllipticCurvePublicNumbers.from_encoded_point(
+ ec.SECP256R1(), data
)
+ assert pn.x == int(
+ '233ea3b0027127084cd2cd336a13aeef69c598d8af61369a36454a17c6c22aec',
+ 16
+ )
+ assert pn.y == int(
+ '3ea2c10a84153862be4ec82940f0543f9ba866af9751a6ee79d38460b35f442e',
+ 16
+ )
- with pytest.raises(TypeError):
- ec.EllipticCurvePrivateNumbers(
- 1,
- ec.EllipticCurvePublicNumbers(
- 2, None, DummyCurve()
+
+def test_from_encoded_point_invalid_length():
+ bad_data = binascii.unhexlify(
+ "04233ea3b0027127084cd2cd336a13aeef69c598d8af61369a36454a17c6c22ae"
+ "c3ea2c10a84153862be4ec82940f0543f9ba866af9751a6ee79d38460"
+ )
+ with pytest.raises(ValueError):
+ with pytest.warns(CryptographyDeprecationWarning):
+ ec.EllipticCurvePublicNumbers.from_encoded_point(
+ ec.SECP384R1(), bad_data
)
- )
- with pytest.raises(TypeError):
- ec.EllipticCurvePrivateNumbers(
- 1,
- ec.EllipticCurvePublicNumbers(
- 2, 3, None
+
+def test_from_encoded_point_unsupported_point_no_backend():
+ # set to point type 2.
+ unsupported_type = binascii.unhexlify(
+ "02233ea3b0027127084cd2cd336a13aeef69c598d8af61369a36454a17c6c22a"
+ )
+ with pytest.raises(ValueError):
+ with pytest.warns(CryptographyDeprecationWarning):
+ ec.EllipticCurvePublicNumbers.from_encoded_point(
+ ec.SECP256R1(), unsupported_type
)
- )
+
+def test_from_encoded_point_not_a_curve():
with pytest.raises(TypeError):
- ec.EllipticCurvePrivateNumbers(
- 1,
- None
- )
+ with pytest.warns(CryptographyDeprecationWarning):
+ ec.EllipticCurvePublicNumbers.from_encoded_point(
+ "notacurve", b"\x04data"
+ )
+
+
+def test_ec_public_numbers_repr():
+ pn = ec.EllipticCurvePublicNumbers(2, 3, ec.SECP256R1())
+ assert repr(pn) == "<EllipticCurvePublicNumbers(curve=secp256r1, x=2, y=3>"
+
+
+def test_ec_public_numbers_hash():
+ pn1 = ec.EllipticCurvePublicNumbers(2, 3, ec.SECP256R1())
+ pn2 = ec.EllipticCurvePublicNumbers(2, 3, ec.SECP256R1())
+ pn3 = ec.EllipticCurvePublicNumbers(1, 3, ec.SECP256R1())
+
+ assert hash(pn1) == hash(pn2)
+ assert hash(pn1) != hash(pn3)
+
+
+def test_ec_private_numbers_hash():
+ numbers1 = ec.EllipticCurvePrivateNumbers(
+ 1, ec.EllipticCurvePublicNumbers(2, 3, DummyCurve())
+ )
+ numbers2 = ec.EllipticCurvePrivateNumbers(
+ 1, ec.EllipticCurvePublicNumbers(2, 3, DummyCurve())
+ )
+ numbers3 = ec.EllipticCurvePrivateNumbers(
+ 2, ec.EllipticCurvePublicNumbers(2, 3, DummyCurve())
+ )
+
+ assert hash(numbers1) == hash(numbers2)
+ assert hash(numbers1) != hash(numbers3)
+
+
+@pytest.mark.requires_backend_interface(interface=EllipticCurveBackend)
+def test_ec_key_key_size(backend):
+ curve = ec.SECP256R1()
+ _skip_curve_unsupported(backend, curve)
+ key = ec.generate_private_key(curve, backend)
+ assert key.key_size == 256
+ assert key.public_key().key_size == 256
@pytest.mark.requires_backend_interface(interface=EllipticCurveBackend)
@@ -173,12 +307,11 @@ class TestECWithNumbers(object):
).private_key(backend)
assert key
- if isinstance(key, ec.EllipticCurvePrivateKeyWithSerialization):
- priv_num = key.private_numbers()
- assert priv_num.private_value == vector['d']
- assert priv_num.public_numbers.x == vector['x']
- assert priv_num.public_numbers.y == vector['y']
- assert curve_type().name == priv_num.public_numbers.curve.name
+ priv_num = key.private_numbers()
+ assert priv_num.private_value == vector['d']
+ assert priv_num.public_numbers.x == vector['x']
+ assert priv_num.public_numbers.y == vector['y']
+ assert curve_type().name == priv_num.public_numbers.curve.name
@pytest.mark.requires_backend_interface(interface=EllipticCurveBackend)
@@ -212,11 +345,13 @@ class TestECDSAVectors(object):
pkey = key.public_key()
assert pkey
- signer = key.signer(ec.ECDSA(hash_type()))
+ with pytest.warns(CryptographyDeprecationWarning):
+ signer = key.signer(ec.ECDSA(hash_type()))
signer.update(b"YELLOW SUBMARINE")
signature = signer.finalize()
- verifier = pkey.verifier(signature, ec.ECDSA(hash_type()))
+ with pytest.warns(CryptographyDeprecationWarning):
+ verifier = pkey.verifier(signature, ec.ECDSA(hash_type()))
verifier.update(b"YELLOW SUBMARINE")
verifier.verify()
@@ -254,14 +389,26 @@ class TestECDSAVectors(object):
with raises_unsupported_algorithm(
exceptions._Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM
- ):
+ ), pytest.warns(CryptographyDeprecationWarning):
key.signer(DummySignatureAlgorithm())
with raises_unsupported_algorithm(
exceptions._Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM
):
+ key.sign(b"somedata", DummySignatureAlgorithm())
+
+ with raises_unsupported_algorithm(
+ exceptions._Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM
+ ), pytest.warns(CryptographyDeprecationWarning):
key.public_key().verifier(b"", DummySignatureAlgorithm())
+ with raises_unsupported_algorithm(
+ exceptions._Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM
+ ):
+ key.public_key().verify(
+ b"signature", b"data", DummySignatureAlgorithm()
+ )
+
assert backend.elliptic_curve_signature_algorithm_supported(
DummySignatureAlgorithm(),
ec.SECP192R1()
@@ -303,6 +450,35 @@ class TestECDSAVectors(object):
with pytest.raises(ValueError):
numbers.private_key(backend)
+ def test_load_invalid_public_ec_key_from_numbers(self, backend):
+ _skip_curve_unsupported(backend, ec.SECP521R1())
+
+ # Bad X coordinate
+ numbers = ec.EllipticCurvePublicNumbers(
+ int("000003647356b91f8ace114c7247ecf4f4a622553fc025e04a178f179ef27"
+ "9090c184af678a4c78f635483bdd8aa544851c6ef291c1f0d6a241ebfd145"
+ "77d1d30d9903ce", 16),
+ int("000001499bc7e079322ea0fcfbd6b40103fa6a1536c2257b182db0df4b369"
+ "6ec643adf100eb4f2025d1b873f82e5a475d6e4400ba777090eeb4563a115"
+ "09e4c87319dc26", 16),
+ ec.SECP521R1()
+ )
+ with pytest.raises(ValueError):
+ numbers.public_key(backend)
+
+ # Bad Y coordinate
+ numbers = ec.EllipticCurvePublicNumbers(
+ int("0000019aadc221cc0525118ab6d5aa1f64720603de0be128cbfea0b381ad8"
+ "02a2facc6370bb58cf88b3f0c692bc654ee19d6cad198f10d4b681b396f20"
+ "d2e40603fa945b", 16),
+ int("0000025da392803a320717a08d4cb3dea932039badff363b71bdb8064e726"
+ "6c7f4f4b748d4d425347fc33e3885d34b750fa7fcd5691f4d90c89522ce33"
+ "feff5db10088a5", 16),
+ ec.SECP521R1()
+ )
+ with pytest.raises(ValueError):
+ numbers.public_key(backend)
+
@pytest.mark.parametrize(
"vector",
itertools.chain(
@@ -330,14 +506,13 @@ class TestECDSAVectors(object):
curve_type()
).public_key(backend)
- signature = encode_rfc6979_signature(vector['r'], vector['s'])
+ signature = encode_dss_signature(vector['r'], vector['s'])
- verifier = key.verifier(
+ key.verify(
signature,
+ vector['message'],
ec.ECDSA(hash_type())
)
- verifier.update(vector['message'])
- assert verifier.verify()
@pytest.mark.parametrize(
"vector",
@@ -359,19 +534,107 @@ class TestECDSAVectors(object):
curve_type()
).public_key(backend)
- signature = encode_rfc6979_signature(vector['r'], vector['s'])
-
- verifier = key.verifier(
- signature,
- ec.ECDSA(hash_type())
- )
- verifier.update(vector['message'])
+ signature = encode_dss_signature(vector['r'], vector['s'])
if vector["fail"] is True:
with pytest.raises(exceptions.InvalidSignature):
- verifier.verify()
+ key.verify(
+ signature,
+ vector['message'],
+ ec.ECDSA(hash_type())
+ )
else:
- verifier.verify()
+ key.verify(
+ signature,
+ vector['message'],
+ ec.ECDSA(hash_type())
+ )
+
+ def test_sign(self, backend):
+ _skip_curve_unsupported(backend, ec.SECP256R1())
+ message = b"one little message"
+ algorithm = ec.ECDSA(hashes.SHA1())
+ private_key = ec.generate_private_key(ec.SECP256R1(), backend)
+ signature = private_key.sign(message, algorithm)
+ public_key = private_key.public_key()
+ public_key.verify(signature, message, algorithm)
+
+ def test_sign_prehashed(self, backend):
+ _skip_curve_unsupported(backend, ec.SECP256R1())
+ message = b"one little message"
+ h = hashes.Hash(hashes.SHA1(), backend)
+ h.update(message)
+ data = h.finalize()
+ algorithm = ec.ECDSA(Prehashed(hashes.SHA1()))
+ private_key = ec.generate_private_key(ec.SECP256R1(), backend)
+ signature = private_key.sign(data, algorithm)
+ public_key = private_key.public_key()
+ public_key.verify(signature, message, ec.ECDSA(hashes.SHA1()))
+
+ def test_sign_prehashed_digest_mismatch(self, backend):
+ _skip_curve_unsupported(backend, ec.SECP256R1())
+ message = b"one little message"
+ h = hashes.Hash(hashes.SHA1(), backend)
+ h.update(message)
+ data = h.finalize()
+ algorithm = ec.ECDSA(Prehashed(hashes.SHA256()))
+ private_key = ec.generate_private_key(ec.SECP256R1(), backend)
+ with pytest.raises(ValueError):
+ private_key.sign(data, algorithm)
+
+ def test_verify(self, backend):
+ _skip_curve_unsupported(backend, ec.SECP256R1())
+ message = b"one little message"
+ algorithm = ec.ECDSA(hashes.SHA1())
+ private_key = ec.generate_private_key(ec.SECP256R1(), backend)
+ signature = private_key.sign(message, algorithm)
+ public_key = private_key.public_key()
+ public_key.verify(signature, message, algorithm)
+
+ def test_verify_prehashed(self, backend):
+ _skip_curve_unsupported(backend, ec.SECP256R1())
+ message = b"one little message"
+ algorithm = ec.ECDSA(hashes.SHA1())
+ private_key = ec.generate_private_key(ec.SECP256R1(), backend)
+ signature = private_key.sign(message, algorithm)
+ h = hashes.Hash(hashes.SHA1(), backend)
+ h.update(message)
+ data = h.finalize()
+ public_key = private_key.public_key()
+ public_key.verify(
+ signature, data, ec.ECDSA(Prehashed(hashes.SHA1()))
+ )
+
+ def test_verify_prehashed_digest_mismatch(self, backend):
+ _skip_curve_unsupported(backend, ec.SECP256R1())
+ message = b"one little message"
+ private_key = ec.generate_private_key(ec.SECP256R1(), backend)
+ h = hashes.Hash(hashes.SHA1(), backend)
+ h.update(message)
+ data = h.finalize()
+ public_key = private_key.public_key()
+ with pytest.raises(ValueError):
+ public_key.verify(
+ b"\x00" * 32, data, ec.ECDSA(Prehashed(hashes.SHA256()))
+ )
+
+ def test_prehashed_unsupported_in_signer_ctx(self, backend):
+ _skip_curve_unsupported(backend, ec.SECP256R1())
+ private_key = ec.generate_private_key(ec.SECP256R1(), backend)
+ with pytest.raises(TypeError), \
+ pytest.warns(CryptographyDeprecationWarning):
+ private_key.signer(ec.ECDSA(Prehashed(hashes.SHA1())))
+
+ def test_prehashed_unsupported_in_verifier_ctx(self, backend):
+ _skip_curve_unsupported(backend, ec.SECP256R1())
+ private_key = ec.generate_private_key(ec.SECP256R1(), backend)
+ public_key = private_key.public_key()
+ with pytest.raises(TypeError), \
+ pytest.warns(CryptographyDeprecationWarning):
+ public_key.verifier(
+ b"0" * 64,
+ ec.ECDSA(Prehashed(hashes.SHA1()))
+ )
class TestECNumbersEquality(object):
@@ -437,7 +700,6 @@ class TestECSerialization(object):
lambda pemfile: pemfile.read().encode()
)
key = serialization.load_pem_private_key(key_bytes, None, backend)
- _skip_if_no_serialization(key, backend)
serialized = key.private_bytes(
serialization.Encoding.PEM,
fmt,
@@ -451,6 +713,21 @@ class TestECSerialization(object):
assert loaded_priv_num == priv_num
@pytest.mark.parametrize(
+ ("encoding", "fmt"),
+ [
+ (serialization.Encoding.Raw, serialization.PrivateFormat.PKCS8),
+ (serialization.Encoding.DER, serialization.PrivateFormat.Raw),
+ (serialization.Encoding.Raw, serialization.PrivateFormat.Raw),
+ (serialization.Encoding.X962, serialization.PrivateFormat.PKCS8),
+ ]
+ )
+ def test_private_bytes_rejects_invalid(self, encoding, fmt, backend):
+ _skip_curve_unsupported(backend, ec.SECP256R1())
+ key = ec.generate_private_key(ec.SECP256R1(), backend)
+ with pytest.raises(ValueError):
+ key.private_bytes(encoding, fmt, serialization.NoEncryption())
+
+ @pytest.mark.parametrize(
("fmt", "password"),
[
[serialization.PrivateFormat.PKCS8, b"s"],
@@ -467,7 +744,6 @@ class TestECSerialization(object):
lambda pemfile: pemfile.read().encode()
)
key = serialization.load_pem_private_key(key_bytes, None, backend)
- _skip_if_no_serialization(key, backend)
serialized = key.private_bytes(
serialization.Encoding.DER,
fmt,
@@ -514,7 +790,6 @@ class TestECSerialization(object):
lambda pemfile: pemfile.read().encode()
)
key = serialization.load_pem_private_key(key_bytes, None, backend)
- _skip_if_no_serialization(key, backend)
serialized = key.private_bytes(
encoding, fmt, serialization.NoEncryption()
)
@@ -566,7 +841,6 @@ class TestECSerialization(object):
pemfile.read().encode(), None, backend
)
)
- _skip_if_no_serialization(key, backend)
with pytest.raises(ValueError):
key.private_bytes(
serialization.Encoding.DER,
@@ -583,7 +857,6 @@ class TestECSerialization(object):
pemfile.read().encode(), None, backend
)
)
- _skip_if_no_serialization(key, backend)
with pytest.raises(TypeError):
key.private_bytes(
"notencoding",
@@ -600,7 +873,6 @@ class TestECSerialization(object):
pemfile.read().encode(), None, backend
)
)
- _skip_if_no_serialization(key, backend)
with pytest.raises(TypeError):
key.private_bytes(
serialization.Encoding.PEM,
@@ -617,7 +889,6 @@ class TestECSerialization(object):
pemfile.read().encode(), None, backend
)
)
- _skip_if_no_serialization(key, backend)
with pytest.raises(TypeError):
key.private_bytes(
serialization.Encoding.PEM,
@@ -634,12 +905,11 @@ class TestECSerialization(object):
pemfile.read().encode(), None, backend
)
)
- _skip_if_no_serialization(key, backend)
with pytest.raises(ValueError):
key.private_bytes(
serialization.Encoding.PEM,
serialization.PrivateFormat.TraditionalOpenSSL,
- DummyKeyEncryption()
+ DummyKeySerializationEncryption()
)
def test_public_bytes_from_derived_public_key(self, backend):
@@ -651,7 +921,6 @@ class TestECSerialization(object):
pemfile.read().encode(), None, backend
)
)
- _skip_if_no_serialization(key, backend)
public = key.public_key()
pem = public.public_bytes(
serialization.Encoding.PEM,
@@ -689,12 +958,39 @@ class TestEllipticCurvePEMPublicKeySerialization(object):
key_path, lambda pemfile: pemfile.read(), mode="rb"
)
key = loader_func(key_bytes, backend)
- _skip_if_no_serialization(key, backend)
serialized = key.public_bytes(
encoding, serialization.PublicFormat.SubjectPublicKeyInfo,
)
assert serialized == key_bytes
+ def test_public_bytes_openssh(self, backend):
+ _skip_curve_unsupported(backend, ec.SECP192R1())
+ _skip_curve_unsupported(backend, ec.SECP256R1())
+
+ key_bytes = load_vectors_from_file(
+ os.path.join(
+ "asymmetric", "PEM_Serialization", "ec_public_key.pem"
+ ),
+ lambda pemfile: pemfile.read(), mode="rb"
+ )
+ key = serialization.load_pem_public_key(key_bytes, backend)
+
+ ssh_bytes = key.public_bytes(
+ serialization.Encoding.OpenSSH, serialization.PublicFormat.OpenSSH
+ )
+ assert ssh_bytes == (
+ b"ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAy"
+ b"NTYAAABBBCS8827s9rUZyxZTi/um01+oIlWrwLHOjQxRU9CDAndom00zVAw5BRrI"
+ b"KtHB+SWD4P+sVJTARSq1mHt8kOIWrPc="
+ )
+
+ key = ec.generate_private_key(ec.SECP192R1(), backend).public_key()
+ with pytest.raises(ValueError):
+ key.public_bytes(
+ serialization.Encoding.OpenSSH,
+ serialization.PublicFormat.OpenSSH
+ )
+
def test_public_bytes_invalid_encoding(self, backend):
_skip_curve_unsupported(backend, ec.SECP256R1())
key = load_vectors_from_file(
@@ -705,13 +1001,40 @@ class TestEllipticCurvePEMPublicKeySerialization(object):
pemfile.read().encode(), backend
)
)
- _skip_if_no_serialization(key, backend)
with pytest.raises(TypeError):
key.public_bytes(
"notencoding",
serialization.PublicFormat.SubjectPublicKeyInfo
)
+ @pytest.mark.parametrize(
+ ("encoding", "fmt"),
+ list(itertools.product(
+ [
+ serialization.Encoding.Raw,
+ serialization.Encoding.X962,
+ serialization.Encoding.PEM,
+ serialization.Encoding.DER
+ ],
+ [
+ serialization.PublicFormat.Raw,
+ ]
+ )) + list(itertools.product(
+ [serialization.Encoding.Raw],
+ [
+ serialization.PublicFormat.SubjectPublicKeyInfo,
+ serialization.PublicFormat.PKCS1,
+ serialization.PublicFormat.UncompressedPoint,
+ serialization.PublicFormat.CompressedPoint,
+ ]
+ ))
+ )
+ def test_public_bytes_rejects_invalid(self, encoding, fmt, backend):
+ _skip_curve_unsupported(backend, ec.SECP256R1())
+ key = ec.generate_private_key(ec.SECP256R1(), backend).public_key()
+ with pytest.raises(ValueError):
+ key.public_bytes(encoding, fmt)
+
def test_public_bytes_invalid_format(self, backend):
_skip_curve_unsupported(backend, ec.SECP256R1())
key = load_vectors_from_file(
@@ -722,7 +1045,6 @@ class TestEllipticCurvePEMPublicKeySerialization(object):
pemfile.read().encode(), backend
)
)
- _skip_if_no_serialization(key, backend)
with pytest.raises(TypeError):
key.public_bytes(serialization.Encoding.PEM, "invalidformat")
@@ -736,8 +1058,250 @@ class TestEllipticCurvePEMPublicKeySerialization(object):
pemfile.read().encode(), backend
)
)
- _skip_if_no_serialization(key, backend)
with pytest.raises(ValueError):
key.public_bytes(
serialization.Encoding.PEM, serialization.PublicFormat.PKCS1
)
+
+ @pytest.mark.parametrize(
+ "vector",
+ load_vectors_from_file(
+ os.path.join("asymmetric", "EC", "compressed_points.txt"),
+ load_nist_vectors
+ )
+ )
+ def test_from_encoded_point_compressed(self, vector, backend):
+ curve = {
+ b"SECP256R1": ec.SECP256R1(),
+ b"SECP256K1": ec.SECP256K1(),
+ }[vector["curve"]]
+ _skip_curve_unsupported(backend, curve)
+ point = binascii.unhexlify(vector["point"])
+ pn = ec.EllipticCurvePublicKey.from_encoded_point(curve, point)
+ public_num = pn.public_numbers()
+ assert public_num.x == int(vector["x"], 16)
+ assert public_num.y == int(vector["y"], 16)
+
+ def test_from_encoded_point_notoncurve(self):
+ uncompressed_point = binascii.unhexlify(
+ "047399336a9edf2197c2f8eb3d39aed9c34a66e45d918a07dc7684c42c9b37ac"
+ "686699ececc4f5f0d756d3c450708a0694eb0a07a68b805070b40b058d27271f"
+ "6e"
+ )
+ with pytest.raises(ValueError):
+ ec.EllipticCurvePublicKey.from_encoded_point(
+ ec.SECP256R1(), uncompressed_point
+ )
+
+ def test_from_encoded_point_uncompressed(self):
+ uncompressed_point = binascii.unhexlify(
+ "047399336a9edf2197c2f8eb3d39aed9c34a66e45d918a07dc7684c42c9b37ac"
+ "686699ececc4f5f0d756d3c450708a0694eb0a07a68b805070b40b058d27271f"
+ "6d"
+ )
+ pn = ec.EllipticCurvePublicKey.from_encoded_point(
+ ec.SECP256R1(), uncompressed_point
+ )
+ assert pn.public_numbers().x == int(
+ '7399336a9edf2197c2f8eb3d39aed9c34a66e45d918a07dc7684c42c9b37ac68',
+ 16
+ )
+ assert pn.public_numbers().y == int(
+ '6699ececc4f5f0d756d3c450708a0694eb0a07a68b805070b40b058d27271f6d',
+ 16
+ )
+
+ def test_from_encoded_point_invalid_length(self):
+ bad_data = binascii.unhexlify(
+ "047399336a9edf2197c2f8eb3d39aed9c34a66e45d918a07dc7684c42c9b37ac"
+ "686699ececc4f5f0d756d3c450708a0694eb0a07a68b805070b40b058d27271f"
+ "6d"
+ )
+ with pytest.raises(ValueError):
+ ec.EllipticCurvePublicKey.from_encoded_point(
+ ec.SECP384R1(), bad_data
+ )
+
+ def test_from_encoded_point_empty_byte_string(self):
+ with pytest.raises(ValueError):
+ ec.EllipticCurvePublicKey.from_encoded_point(
+ ec.SECP384R1(), b""
+ )
+
+ def test_from_encoded_point_not_a_curve(self):
+ with pytest.raises(TypeError):
+ ec.EllipticCurvePublicKey.from_encoded_point(
+ "notacurve", b"\x04data"
+ )
+
+ def test_from_encoded_point_unsupported_encoding(self):
+ unsupported_type = binascii.unhexlify(
+ "057399336a9edf2197c2f8eb3d39aed9c34a66e45d918a07dc7684c42c9b37ac6"
+ "8"
+ )
+ with pytest.raises(ValueError):
+ ec.EllipticCurvePublicKey.from_encoded_point(
+ ec.SECP256R1(), unsupported_type
+ )
+
+ @pytest.mark.parametrize(
+ "vector",
+ load_vectors_from_file(
+ os.path.join("asymmetric", "EC", "compressed_points.txt"),
+ load_nist_vectors
+ )
+ )
+ def test_serialize_point(self, vector, backend):
+ curve = {
+ b"SECP256R1": ec.SECP256R1(),
+ b"SECP256K1": ec.SECP256K1(),
+ }[vector["curve"]]
+ _skip_curve_unsupported(backend, curve)
+ point = binascii.unhexlify(vector["point"])
+ key = ec.EllipticCurvePublicKey.from_encoded_point(curve, point)
+ key2 = ec.EllipticCurvePublicKey.from_encoded_point(
+ curve,
+ key.public_bytes(
+ serialization.Encoding.X962,
+ serialization.PublicFormat.UncompressedPoint
+ )
+ )
+ assert key.public_bytes(
+ serialization.Encoding.X962,
+ serialization.PublicFormat.CompressedPoint
+ ) == point
+ assert key2.public_bytes(
+ serialization.Encoding.X962,
+ serialization.PublicFormat.CompressedPoint
+ ) == point
+
+
+@pytest.mark.requires_backend_interface(interface=EllipticCurveBackend)
+class TestECDSAVerification(object):
+ def test_signature_not_bytes(self, backend):
+ _skip_curve_unsupported(backend, ec.SECP256R1())
+ key = ec.generate_private_key(ec.SECP256R1(), backend)
+ public_key = key.public_key()
+ with pytest.raises(TypeError), \
+ pytest.warns(CryptographyDeprecationWarning):
+ public_key.verifier(1234, ec.ECDSA(hashes.SHA256()))
+
+
+@pytest.mark.requires_backend_interface(interface=EllipticCurveBackend)
+class TestECDH(object):
+ @pytest.mark.parametrize(
+ "vector",
+ load_vectors_from_file(
+ os.path.join(
+ "asymmetric", "ECDH",
+ "KASValidityTest_ECCStaticUnified_NOKC_ZZOnly_init.fax"),
+ load_kasvs_ecdh_vectors
+ )
+ )
+ def test_key_exchange_with_vectors(self, backend, vector):
+ _skip_exchange_algorithm_unsupported(
+ backend, ec.ECDH(), ec._CURVE_TYPES[vector['curve']]
+ )
+
+ key_numbers = vector['IUT']
+ private_numbers = ec.EllipticCurvePrivateNumbers(
+ key_numbers['d'],
+ ec.EllipticCurvePublicNumbers(
+ key_numbers['x'],
+ key_numbers['y'],
+ ec._CURVE_TYPES[vector['curve']]()
+ )
+ )
+ # Errno 5-7 indicates a bad public or private key, this doesn't test
+ # the ECDH code at all
+ if vector['fail'] and vector['errno'] in [5, 6, 7]:
+ with pytest.raises(ValueError):
+ private_numbers.private_key(backend)
+ return
+ else:
+ private_key = private_numbers.private_key(backend)
+
+ peer_numbers = vector['CAVS']
+ public_numbers = ec.EllipticCurvePublicNumbers(
+ peer_numbers['x'],
+ peer_numbers['y'],
+ ec._CURVE_TYPES[vector['curve']]()
+ )
+ # Errno 1 and 2 indicates a bad public key, this doesn't test the ECDH
+ # code at all
+ if vector['fail'] and vector['errno'] in [1, 2]:
+ with pytest.raises(ValueError):
+ public_numbers.public_key(backend)
+ return
+ else:
+ peer_pubkey = public_numbers.public_key(backend)
+
+ z = private_key.exchange(ec.ECDH(), peer_pubkey)
+ z = int(hexlify(z).decode('ascii'), 16)
+ # At this point fail indicates that one of the underlying keys was
+ # changed. This results in a non-matching derived key.
+ if vector['fail']:
+ # Errno 8 indicates Z should be changed.
+ assert vector['errno'] == 8
+ assert z != vector['Z']
+ else:
+ assert z == vector['Z']
+
+ @pytest.mark.parametrize(
+ "vector",
+ load_vectors_from_file(
+ os.path.join("asymmetric", "ECDH", "brainpool.txt"),
+ load_nist_vectors
+ )
+ )
+ def test_brainpool_kex(self, backend, vector):
+ curve = ec._CURVE_TYPES[vector['curve'].decode('ascii')]
+ _skip_exchange_algorithm_unsupported(backend, ec.ECDH(), curve)
+ key = ec.EllipticCurvePrivateNumbers(
+ int(vector['da'], 16),
+ ec.EllipticCurvePublicNumbers(
+ int(vector['x_qa'], 16), int(vector['y_qa'], 16), curve()
+ )
+ ).private_key(backend)
+ peer = ec.EllipticCurvePrivateNumbers(
+ int(vector['db'], 16),
+ ec.EllipticCurvePublicNumbers(
+ int(vector['x_qb'], 16), int(vector['y_qb'], 16), curve()
+ )
+ ).private_key(backend)
+ shared_secret = key.exchange(ec.ECDH(), peer.public_key())
+ assert shared_secret == binascii.unhexlify(vector["x_z"])
+ shared_secret_2 = peer.exchange(ec.ECDH(), key.public_key())
+ assert shared_secret_2 == binascii.unhexlify(vector["x_z"])
+
+ def test_exchange_unsupported_algorithm(self, backend):
+ _skip_curve_unsupported(backend, ec.SECP256R1())
+
+ key = load_vectors_from_file(
+ os.path.join(
+ "asymmetric", "PKCS8", "ec_private_key.pem"),
+ lambda pemfile: serialization.load_pem_private_key(
+ pemfile.read().encode(), None, backend
+ )
+ )
+
+ with raises_unsupported_algorithm(
+ exceptions._Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM
+ ):
+ key.exchange(None, key.public_key())
+
+ def test_exchange_non_matching_curve(self, backend):
+ _skip_curve_unsupported(backend, ec.SECP256R1())
+ _skip_curve_unsupported(backend, ec.SECP384R1())
+
+ key = load_vectors_from_file(
+ os.path.join(
+ "asymmetric", "PKCS8", "ec_private_key.pem"),
+ lambda pemfile: serialization.load_pem_private_key(
+ pemfile.read().encode(), None, backend
+ )
+ )
+ public_key = EC_KEY_SECP384R1.public_numbers.public_key(backend)
+
+ with pytest.raises(ValueError):
+ key.exchange(ec.ECDH(), public_key)