1307 lines
47 KiB
Python
1307 lines
47 KiB
Python
# 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 itertools
|
|
import os
|
|
from binascii import hexlify
|
|
|
|
import pytest
|
|
|
|
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 (
|
|
Prehashed,
|
|
encode_dss_signature,
|
|
)
|
|
from cryptography.utils import CryptographyDeprecationWarning
|
|
|
|
from .fixtures_ec import EC_KEY_SECP384R1
|
|
from .utils import skip_fips_traditional_openssl
|
|
from ...doubles import DummyKeySerializationEncryption
|
|
from ...utils import (
|
|
load_fips_ecdsa_key_pair_vectors,
|
|
load_fips_ecdsa_signing_vectors,
|
|
load_kasvs_ecdh_vectors,
|
|
load_nist_vectors,
|
|
load_vectors_from_file,
|
|
raises_unsupported_algorithm,
|
|
)
|
|
|
|
_HASH_TYPES = {
|
|
"SHA-1": hashes.SHA1,
|
|
"SHA-224": hashes.SHA224,
|
|
"SHA-256": hashes.SHA256,
|
|
"SHA-384": hashes.SHA384,
|
|
"SHA-512": hashes.SHA512,
|
|
}
|
|
|
|
|
|
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 {} and curve {}.".format(
|
|
hash_type().name, curve_type().name
|
|
)
|
|
)
|
|
|
|
|
|
def _skip_curve_unsupported(backend, curve):
|
|
if not backend.elliptic_curve_supported(curve):
|
|
pytest.skip(
|
|
"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"
|
|
key_size = 1
|
|
|
|
|
|
@utils.register_interface(ec.EllipticCurveSignatureAlgorithm)
|
|
class DummySignatureAlgorithm(object):
|
|
algorithm = None
|
|
|
|
|
|
@pytest.mark.requires_backend_interface(interface=EllipticCurveBackend)
|
|
def test_skip_curve_unsupported(backend):
|
|
with pytest.raises(pytest.skip.Exception):
|
|
_skip_curve_unsupported(backend, DummyCurve())
|
|
|
|
|
|
@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_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():
|
|
numbers = ec.EllipticCurvePrivateNumbers(
|
|
1, ec.EllipticCurvePublicNumbers(2, 3, DummyCurve())
|
|
)
|
|
|
|
assert numbers.private_value == 1
|
|
assert numbers.public_numbers.x == 2
|
|
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(
|
|
private_value, ec.EllipticCurvePublicNumbers(x, y, curve)
|
|
)
|
|
|
|
|
|
def test_invalid_private_numbers_public_numbers():
|
|
with pytest.raises(TypeError):
|
|
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
|
|
)
|
|
|
|
|
|
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
|
|
)
|
|
|
|
|
|
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):
|
|
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)
|
|
class TestECWithNumbers(object):
|
|
@pytest.mark.parametrize(
|
|
("vector", "hash_type"),
|
|
list(
|
|
itertools.product(
|
|
load_vectors_from_file(
|
|
os.path.join(
|
|
"asymmetric", "ECDSA", "FIPS_186-3", "KeyPair.rsp"
|
|
),
|
|
load_fips_ecdsa_key_pair_vectors,
|
|
),
|
|
_HASH_TYPES.values(),
|
|
)
|
|
),
|
|
)
|
|
def test_with_numbers(self, backend, vector, hash_type):
|
|
curve_type = ec._CURVE_TYPES[vector["curve"]]
|
|
|
|
_skip_ecdsa_vector(backend, curve_type, hash_type)
|
|
|
|
key = ec.EllipticCurvePrivateNumbers(
|
|
vector["d"],
|
|
ec.EllipticCurvePublicNumbers(
|
|
vector["x"], vector["y"], curve_type()
|
|
),
|
|
).private_key(backend)
|
|
assert key
|
|
|
|
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)
|
|
class TestECDSAVectors(object):
|
|
@pytest.mark.parametrize(
|
|
("vector", "hash_type"),
|
|
list(
|
|
itertools.product(
|
|
load_vectors_from_file(
|
|
os.path.join(
|
|
"asymmetric", "ECDSA", "FIPS_186-3", "KeyPair.rsp"
|
|
),
|
|
load_fips_ecdsa_key_pair_vectors,
|
|
),
|
|
_HASH_TYPES.values(),
|
|
)
|
|
),
|
|
)
|
|
def test_signing_with_example_keys(self, backend, vector, hash_type):
|
|
curve_type = ec._CURVE_TYPES[vector["curve"]]
|
|
|
|
_skip_ecdsa_vector(backend, curve_type, hash_type)
|
|
|
|
key = ec.EllipticCurvePrivateNumbers(
|
|
vector["d"],
|
|
ec.EllipticCurvePublicNumbers(
|
|
vector["x"], vector["y"], curve_type()
|
|
),
|
|
).private_key(backend)
|
|
assert key
|
|
|
|
pkey = key.public_key()
|
|
assert pkey
|
|
|
|
with pytest.warns(CryptographyDeprecationWarning):
|
|
signer = key.signer(ec.ECDSA(hash_type()))
|
|
signer.update(b"YELLOW SUBMARINE")
|
|
signature = signer.finalize()
|
|
|
|
with pytest.warns(CryptographyDeprecationWarning):
|
|
verifier = pkey.verifier(signature, ec.ECDSA(hash_type()))
|
|
verifier.update(b"YELLOW SUBMARINE")
|
|
verifier.verify()
|
|
|
|
@pytest.mark.parametrize("curve", ec._CURVE_TYPES.values())
|
|
def test_generate_vector_curves(self, backend, curve):
|
|
_skip_curve_unsupported(backend, curve())
|
|
|
|
key = ec.generate_private_key(curve(), backend)
|
|
assert key
|
|
assert isinstance(key.curve, curve)
|
|
assert key.curve.key_size
|
|
|
|
pkey = key.public_key()
|
|
assert pkey
|
|
assert isinstance(pkey.curve, curve)
|
|
assert key.curve.key_size == pkey.curve.key_size
|
|
|
|
def test_generate_unknown_curve(self, backend):
|
|
with raises_unsupported_algorithm(
|
|
exceptions._Reasons.UNSUPPORTED_ELLIPTIC_CURVE
|
|
):
|
|
ec.generate_private_key(DummyCurve(), backend)
|
|
|
|
assert (
|
|
backend.elliptic_curve_signature_algorithm_supported(
|
|
ec.ECDSA(hashes.SHA256()), DummyCurve()
|
|
)
|
|
is False
|
|
)
|
|
|
|
def test_unknown_signature_algoritm(self, backend):
|
|
_skip_curve_unsupported(backend, ec.SECP192R1())
|
|
|
|
key = ec.generate_private_key(ec.SECP192R1(), backend)
|
|
|
|
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()
|
|
)
|
|
is False
|
|
)
|
|
|
|
def test_load_invalid_ec_key_from_numbers(self, backend):
|
|
_skip_curve_unsupported(backend, ec.SECP256R1())
|
|
|
|
numbers = ec.EllipticCurvePrivateNumbers(
|
|
357646505660320080863666618182642070958081774038609089496899025506,
|
|
ec.EllipticCurvePublicNumbers(
|
|
47250808410327023131573602008345894927686381772325561185532964,
|
|
1120253292479243545483756778742719537373113335231773536789915,
|
|
ec.SECP256R1(),
|
|
),
|
|
)
|
|
with pytest.raises(ValueError):
|
|
numbers.private_key(backend)
|
|
|
|
numbers = ec.EllipticCurvePrivateNumbers(
|
|
357646505660320080863666618182642070958081774038609089496899025506,
|
|
ec.EllipticCurvePublicNumbers(
|
|
-4725080841032702313157360200834589492768638177232556118553296,
|
|
1120253292479243545483756778742719537373113335231773536789915,
|
|
ec.SECP256R1(),
|
|
),
|
|
)
|
|
with pytest.raises(ValueError):
|
|
numbers.private_key(backend)
|
|
|
|
numbers = ec.EllipticCurvePrivateNumbers(
|
|
357646505660320080863666618182642070958081774038609089496899025506,
|
|
ec.EllipticCurvePublicNumbers(
|
|
47250808410327023131573602008345894927686381772325561185532964,
|
|
-1120253292479243545483756778742719537373113335231773536789915,
|
|
ec.SECP256R1(),
|
|
),
|
|
)
|
|
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(
|
|
load_vectors_from_file(
|
|
os.path.join(
|
|
"asymmetric", "ECDSA", "FIPS_186-3", "SigGen.txt"
|
|
),
|
|
load_fips_ecdsa_signing_vectors,
|
|
),
|
|
load_vectors_from_file(
|
|
os.path.join("asymmetric", "ECDSA", "SECP256K1", "SigGen.txt"),
|
|
load_fips_ecdsa_signing_vectors,
|
|
),
|
|
),
|
|
)
|
|
def test_signatures(self, backend, vector):
|
|
hash_type = _HASH_TYPES[vector["digest_algorithm"]]
|
|
curve_type = ec._CURVE_TYPES[vector["curve"]]
|
|
|
|
_skip_ecdsa_vector(backend, curve_type, hash_type)
|
|
|
|
key = ec.EllipticCurvePublicNumbers(
|
|
vector["x"], vector["y"], curve_type()
|
|
).public_key(backend)
|
|
|
|
signature = encode_dss_signature(vector["r"], vector["s"])
|
|
|
|
key.verify(signature, vector["message"], ec.ECDSA(hash_type()))
|
|
|
|
@pytest.mark.parametrize(
|
|
"vector",
|
|
load_vectors_from_file(
|
|
os.path.join("asymmetric", "ECDSA", "FIPS_186-3", "SigVer.rsp"),
|
|
load_fips_ecdsa_signing_vectors,
|
|
),
|
|
)
|
|
def test_signature_failures(self, backend, vector):
|
|
hash_type = _HASH_TYPES[vector["digest_algorithm"]]
|
|
curve_type = ec._CURVE_TYPES[vector["curve"]]
|
|
|
|
_skip_ecdsa_vector(backend, curve_type, hash_type)
|
|
|
|
key = ec.EllipticCurvePublicNumbers(
|
|
vector["x"], vector["y"], curve_type()
|
|
).public_key(backend)
|
|
|
|
signature = encode_dss_signature(vector["r"], vector["s"])
|
|
|
|
if vector["fail"] is True:
|
|
with pytest.raises(exceptions.InvalidSignature):
|
|
key.verify(signature, vector["message"], ec.ECDSA(hash_type()))
|
|
else:
|
|
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):
|
|
def test_public_numbers_eq(self):
|
|
pub = ec.EllipticCurvePublicNumbers(1, 2, ec.SECP192R1())
|
|
assert pub == ec.EllipticCurvePublicNumbers(1, 2, ec.SECP192R1())
|
|
|
|
def test_public_numbers_ne(self):
|
|
pub = ec.EllipticCurvePublicNumbers(1, 2, ec.SECP192R1())
|
|
assert pub != ec.EllipticCurvePublicNumbers(1, 2, ec.SECP384R1())
|
|
assert pub != ec.EllipticCurvePublicNumbers(1, 3, ec.SECP192R1())
|
|
assert pub != ec.EllipticCurvePublicNumbers(2, 2, ec.SECP192R1())
|
|
assert pub != object()
|
|
|
|
def test_private_numbers_eq(self):
|
|
pub = ec.EllipticCurvePublicNumbers(1, 2, ec.SECP192R1())
|
|
priv = ec.EllipticCurvePrivateNumbers(1, pub)
|
|
assert priv == ec.EllipticCurvePrivateNumbers(
|
|
1, ec.EllipticCurvePublicNumbers(1, 2, ec.SECP192R1())
|
|
)
|
|
|
|
def test_private_numbers_ne(self):
|
|
pub = ec.EllipticCurvePublicNumbers(1, 2, ec.SECP192R1())
|
|
priv = ec.EllipticCurvePrivateNumbers(1, pub)
|
|
assert priv != ec.EllipticCurvePrivateNumbers(
|
|
2, ec.EllipticCurvePublicNumbers(1, 2, ec.SECP192R1())
|
|
)
|
|
assert priv != ec.EllipticCurvePrivateNumbers(
|
|
1, ec.EllipticCurvePublicNumbers(2, 2, ec.SECP192R1())
|
|
)
|
|
assert priv != ec.EllipticCurvePrivateNumbers(
|
|
1, ec.EllipticCurvePublicNumbers(1, 3, ec.SECP192R1())
|
|
)
|
|
assert priv != ec.EllipticCurvePrivateNumbers(
|
|
1, ec.EllipticCurvePublicNumbers(1, 2, ec.SECP521R1())
|
|
)
|
|
assert priv != object()
|
|
|
|
|
|
@pytest.mark.requires_backend_interface(interface=EllipticCurveBackend)
|
|
@pytest.mark.requires_backend_interface(interface=PEMSerializationBackend)
|
|
class TestECSerialization(object):
|
|
@pytest.mark.parametrize(
|
|
("fmt", "password"),
|
|
itertools.product(
|
|
[
|
|
serialization.PrivateFormat.TraditionalOpenSSL,
|
|
serialization.PrivateFormat.PKCS8,
|
|
],
|
|
[
|
|
b"s",
|
|
b"longerpassword",
|
|
b"!*$&(@#$*&($T@%_somesymbols",
|
|
b"\x01" * 1000,
|
|
],
|
|
),
|
|
)
|
|
def test_private_bytes_encrypted_pem(self, backend, fmt, password):
|
|
skip_fips_traditional_openssl(backend, fmt)
|
|
_skip_curve_unsupported(backend, ec.SECP256R1())
|
|
key_bytes = load_vectors_from_file(
|
|
os.path.join("asymmetric", "PKCS8", "ec_private_key.pem"),
|
|
lambda pemfile: pemfile.read().encode(),
|
|
)
|
|
key = serialization.load_pem_private_key(key_bytes, None, backend)
|
|
serialized = key.private_bytes(
|
|
serialization.Encoding.PEM,
|
|
fmt,
|
|
serialization.BestAvailableEncryption(password),
|
|
)
|
|
loaded_key = serialization.load_pem_private_key(
|
|
serialized, password, backend
|
|
)
|
|
loaded_priv_num = loaded_key.private_numbers()
|
|
priv_num = key.private_numbers()
|
|
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"],
|
|
[serialization.PrivateFormat.PKCS8, b"longerpassword"],
|
|
[serialization.PrivateFormat.PKCS8, b"!*$&(@#$*&($T@%_somesymbol"],
|
|
[serialization.PrivateFormat.PKCS8, b"\x01" * 1000],
|
|
],
|
|
)
|
|
def test_private_bytes_encrypted_der(self, backend, fmt, password):
|
|
_skip_curve_unsupported(backend, ec.SECP256R1())
|
|
key_bytes = load_vectors_from_file(
|
|
os.path.join("asymmetric", "PKCS8", "ec_private_key.pem"),
|
|
lambda pemfile: pemfile.read().encode(),
|
|
)
|
|
key = serialization.load_pem_private_key(key_bytes, None, backend)
|
|
serialized = key.private_bytes(
|
|
serialization.Encoding.DER,
|
|
fmt,
|
|
serialization.BestAvailableEncryption(password),
|
|
)
|
|
loaded_key = serialization.load_der_private_key(
|
|
serialized, password, backend
|
|
)
|
|
loaded_priv_num = loaded_key.private_numbers()
|
|
priv_num = key.private_numbers()
|
|
assert loaded_priv_num == priv_num
|
|
|
|
@pytest.mark.parametrize(
|
|
("encoding", "fmt", "loader_func"),
|
|
[
|
|
[
|
|
serialization.Encoding.PEM,
|
|
serialization.PrivateFormat.TraditionalOpenSSL,
|
|
serialization.load_pem_private_key,
|
|
],
|
|
[
|
|
serialization.Encoding.DER,
|
|
serialization.PrivateFormat.TraditionalOpenSSL,
|
|
serialization.load_der_private_key,
|
|
],
|
|
[
|
|
serialization.Encoding.PEM,
|
|
serialization.PrivateFormat.PKCS8,
|
|
serialization.load_pem_private_key,
|
|
],
|
|
[
|
|
serialization.Encoding.DER,
|
|
serialization.PrivateFormat.PKCS8,
|
|
serialization.load_der_private_key,
|
|
],
|
|
],
|
|
)
|
|
def test_private_bytes_unencrypted(
|
|
self, backend, encoding, fmt, loader_func
|
|
):
|
|
_skip_curve_unsupported(backend, ec.SECP256R1())
|
|
key_bytes = load_vectors_from_file(
|
|
os.path.join("asymmetric", "PKCS8", "ec_private_key.pem"),
|
|
lambda pemfile: pemfile.read().encode(),
|
|
)
|
|
key = serialization.load_pem_private_key(key_bytes, None, backend)
|
|
serialized = key.private_bytes(
|
|
encoding, fmt, serialization.NoEncryption()
|
|
)
|
|
loaded_key = loader_func(serialized, None, backend)
|
|
loaded_priv_num = loaded_key.private_numbers()
|
|
priv_num = key.private_numbers()
|
|
assert loaded_priv_num == priv_num
|
|
|
|
@pytest.mark.skip_fips(
|
|
reason="Traditional OpenSSL key format is not supported in FIPS mode."
|
|
)
|
|
@pytest.mark.parametrize(
|
|
("key_path", "encoding", "loader_func"),
|
|
[
|
|
[
|
|
os.path.join(
|
|
"asymmetric", "PEM_Serialization", "ec_private_key.pem"
|
|
),
|
|
serialization.Encoding.PEM,
|
|
serialization.load_pem_private_key,
|
|
],
|
|
[
|
|
os.path.join(
|
|
"asymmetric", "DER_Serialization", "ec_private_key.der"
|
|
),
|
|
serialization.Encoding.DER,
|
|
serialization.load_der_private_key,
|
|
],
|
|
],
|
|
)
|
|
def test_private_bytes_traditional_openssl_unencrypted(
|
|
self, backend, key_path, encoding, loader_func
|
|
):
|
|
_skip_curve_unsupported(backend, ec.SECP256R1())
|
|
key_bytes = load_vectors_from_file(
|
|
key_path, lambda pemfile: pemfile.read(), mode="rb"
|
|
)
|
|
key = loader_func(key_bytes, None, backend)
|
|
serialized = key.private_bytes(
|
|
encoding,
|
|
serialization.PrivateFormat.TraditionalOpenSSL,
|
|
serialization.NoEncryption(),
|
|
)
|
|
assert serialized == key_bytes
|
|
|
|
def test_private_bytes_traditional_der_encrypted_invalid(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 pytest.raises(ValueError):
|
|
key.private_bytes(
|
|
serialization.Encoding.DER,
|
|
serialization.PrivateFormat.TraditionalOpenSSL,
|
|
serialization.BestAvailableEncryption(b"password"),
|
|
)
|
|
|
|
def test_private_bytes_invalid_encoding(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 pytest.raises(TypeError):
|
|
key.private_bytes(
|
|
"notencoding",
|
|
serialization.PrivateFormat.PKCS8,
|
|
serialization.NoEncryption(),
|
|
)
|
|
|
|
def test_private_bytes_invalid_format(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 pytest.raises(TypeError):
|
|
key.private_bytes(
|
|
serialization.Encoding.PEM,
|
|
"invalidformat",
|
|
serialization.NoEncryption(),
|
|
)
|
|
|
|
def test_private_bytes_invalid_encryption_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 pytest.raises(TypeError):
|
|
key.private_bytes(
|
|
serialization.Encoding.PEM,
|
|
serialization.PrivateFormat.TraditionalOpenSSL,
|
|
"notanencalg",
|
|
)
|
|
|
|
def test_private_bytes_unsupported_encryption_type(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 pytest.raises(ValueError):
|
|
key.private_bytes(
|
|
serialization.Encoding.PEM,
|
|
serialization.PrivateFormat.TraditionalOpenSSL,
|
|
DummyKeySerializationEncryption(),
|
|
)
|
|
|
|
def test_public_bytes_from_derived_public_key(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
|
|
),
|
|
)
|
|
public = key.public_key()
|
|
pem = public.public_bytes(
|
|
serialization.Encoding.PEM,
|
|
serialization.PublicFormat.SubjectPublicKeyInfo,
|
|
)
|
|
parsed_public = serialization.load_pem_public_key(pem, backend)
|
|
assert parsed_public
|
|
|
|
|
|
@pytest.mark.requires_backend_interface(interface=EllipticCurveBackend)
|
|
@pytest.mark.requires_backend_interface(interface=PEMSerializationBackend)
|
|
class TestEllipticCurvePEMPublicKeySerialization(object):
|
|
@pytest.mark.parametrize(
|
|
("key_path", "loader_func", "encoding"),
|
|
[
|
|
(
|
|
os.path.join(
|
|
"asymmetric", "PEM_Serialization", "ec_public_key.pem"
|
|
),
|
|
serialization.load_pem_public_key,
|
|
serialization.Encoding.PEM,
|
|
),
|
|
(
|
|
os.path.join(
|
|
"asymmetric", "DER_Serialization", "ec_public_key.der"
|
|
),
|
|
serialization.load_der_public_key,
|
|
serialization.Encoding.DER,
|
|
),
|
|
],
|
|
)
|
|
def test_public_bytes_match(
|
|
self, key_path, loader_func, encoding, backend
|
|
):
|
|
_skip_curve_unsupported(backend, ec.SECP256R1())
|
|
key_bytes = load_vectors_from_file(
|
|
key_path, lambda pemfile: pemfile.read(), mode="rb"
|
|
)
|
|
key = loader_func(key_bytes, 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(
|
|
os.path.join(
|
|
"asymmetric", "PEM_Serialization", "ec_public_key.pem"
|
|
),
|
|
lambda pemfile: serialization.load_pem_public_key(
|
|
pemfile.read().encode(), 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(
|
|
os.path.join(
|
|
"asymmetric", "PEM_Serialization", "ec_public_key.pem"
|
|
),
|
|
lambda pemfile: serialization.load_pem_public_key(
|
|
pemfile.read().encode(), backend
|
|
),
|
|
)
|
|
with pytest.raises(TypeError):
|
|
key.public_bytes(serialization.Encoding.PEM, "invalidformat")
|
|
|
|
def test_public_bytes_pkcs1_unsupported(self, backend):
|
|
_skip_curve_unsupported(backend, ec.SECP256R1())
|
|
key = load_vectors_from_file(
|
|
os.path.join(
|
|
"asymmetric", "PEM_Serialization", "ec_public_key.pem"
|
|
),
|
|
lambda pemfile: serialization.load_pem_public_key(
|
|
pemfile.read().encode(), 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)
|