Skip to content

Commit

Permalink
refactor: replace verify_interface with isinstance (#467)
Browse files Browse the repository at this point in the history
* refactor: change verify_interface to isinstance

* chore: update test_vector_handlers tox file
  • Loading branch information
josecorella committed Jun 3, 2022
1 parent cb63b56 commit d3c7638
Show file tree
Hide file tree
Showing 8 changed files with 72 additions and 88 deletions.
7 changes: 2 additions & 5 deletions src/aws_encryption_sdk/internal/crypto/authentication.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.primitives.asymmetric.utils import Prehashed
from cryptography.utils import InterfaceNotImplemented, verify_interface

from ...exceptions import NotSupportedError
from .elliptic_curve import (
Expand Down Expand Up @@ -47,11 +46,9 @@ def __init__(self, algorithm, key):

def _set_signature_type(self):
"""Ensures that the algorithm signature type is a known type and sets a reference value."""
try:
verify_interface(ec.EllipticCurve, self.algorithm.signing_algorithm_info)
return ec.EllipticCurve
except InterfaceNotImplemented:
if not isinstance(self.algorithm.signing_algorithm_info, type(ec.EllipticCurve)):
raise NotSupportedError("Unsupported signing algorithm info")
return ec.EllipticCurve

def _build_hasher(self):
"""Builds the hasher instance which will calculate the digest of all passed data.
Expand Down
17 changes: 7 additions & 10 deletions src/aws_encryption_sdk/internal/crypto/elliptic_curve.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,13 @@
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.primitives.asymmetric.utils import Prehashed, decode_dss_signature, encode_dss_signature
from cryptography.utils import InterfaceNotImplemented, int_to_bytes, verify_interface
from cryptography.utils import int_to_bytes

from ...exceptions import NotSupportedError
from ..str_ops import to_bytes

_LOGGER = logging.getLogger(__name__)


# Curve parameter values are included strictly as a temporary measure
# until they can be rolled into the cryptography.io library.
# Expanded values from http://www.secg.org/sec2-v2.pdf
Expand All @@ -44,10 +43,10 @@
order=0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973,
),
"secp521r1": _ECCCurveParameters(
p=0x01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF, # noqa pylint: disable=line-too-long
a=0x01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC, # noqa pylint: disable=line-too-long
b=0x0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00, # noqa pylint: disable=line-too-long
order=0x01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409, # noqa pylint: disable=line-too-long
p=0x01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF, # noqa pylint: disable=line-too-long
a=0x01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC, # noqa pylint: disable=line-too-long
b=0x0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00, # noqa pylint: disable=line-too-long
order=0x01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409, # noqa pylint: disable=line-too-long
),
}

Expand Down Expand Up @@ -182,8 +181,6 @@ def generate_ecc_signing_key(algorithm):
:returns: Generated signing key
:raises NotSupportedError: if signing algorithm is not supported on this platform
"""
try:
verify_interface(ec.EllipticCurve, algorithm.signing_algorithm_info)
return ec.generate_private_key(curve=algorithm.signing_algorithm_info(), backend=default_backend())
except InterfaceNotImplemented:
if not isinstance(algorithm.signing_algorithm_info, type(ec.EllipticCurve)):
raise NotSupportedError("Unsupported signing algorithm info")
return ec.generate_private_key(curve=algorithm.signing_algorithm_info(), backend=default_backend())
41 changes: 31 additions & 10 deletions test/unit/test_crypto_authentication_signer.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ def patch_default_backend(mocker):
yield aws_encryption_sdk.internal.crypto.authentication.default_backend


@pytest.fixture
def patch_ec(mocker):
mocker.patch.object(aws_encryption_sdk.internal.crypto.authentication, "ec")
yield aws_encryption_sdk.internal.crypto.authentication.ec


@pytest.fixture
def patch_serialization(mocker):
mocker.patch.object(aws_encryption_sdk.internal.crypto.authentication, "serialization")
Expand Down Expand Up @@ -71,8 +77,10 @@ def test_f_signer_key_bytes():
assert test.key_bytes() == VALUES["ecc_private_key_prime_private_bytes"]


def test_signer_from_key_bytes(patch_default_backend, patch_serialization, patch_build_hasher):
_algorithm = MagicMock()
def test_signer_from_key_bytes(patch_default_backend, patch_serialization, patch_build_hasher, patch_ec):
mock_algorithm_info = MagicMock(return_value=sentinel.algorithm_info, spec=patch_ec.EllipticCurve)
_algorithm = MagicMock(signing_algorithm_info=mock_algorithm_info)

signer = Signer.from_key_bytes(algorithm=_algorithm, key_bytes=sentinel.key_bytes)

patch_serialization.load_der_private_key.assert_called_once_with(
Expand All @@ -83,9 +91,11 @@ def test_signer_from_key_bytes(patch_default_backend, patch_serialization, patch
assert signer.key is patch_serialization.load_der_private_key.return_value


def test_signer_key_bytes(patch_default_backend, patch_serialization, patch_build_hasher):
def test_signer_key_bytes(patch_default_backend, patch_serialization, patch_build_hasher, patch_ec):
mock_algorithm_info = MagicMock(return_value=sentinel.algorithm_info, spec=patch_ec.EllipticCurve)
algorithm = MagicMock(signing_algorithm_info=mock_algorithm_info)
private_key = MagicMock()
signer = Signer(MagicMock(), key=private_key)
signer = Signer(algorithm, key=private_key)

test = signer.key_bytes()

Expand All @@ -98,30 +108,41 @@ def test_signer_key_bytes(patch_default_backend, patch_serialization, patch_buil


def test_signer_encoded_public_key(
patch_default_backend, patch_serialization, patch_build_hasher, patch_ecc_encode_compressed_point, patch_base64
patch_default_backend,
patch_serialization,
patch_build_hasher,
patch_ecc_encode_compressed_point,
patch_base64,
patch_ec
):
patch_ecc_encode_compressed_point.return_value = sentinel.compressed_point
patch_base64.b64encode.return_value = sentinel.encoded_point
private_key = MagicMock()

signer = Signer(MagicMock(), key=private_key)
mock_algorithm_info = MagicMock(return_value=sentinel.algorithm_info, spec=patch_ec.EllipticCurve)
algorithm = MagicMock(signing_algorithm_info=mock_algorithm_info)

signer = Signer(algorithm, key=private_key)
test_key = signer.encoded_public_key()

patch_ecc_encode_compressed_point.assert_called_once_with(private_key)
patch_base64.b64encode.assert_called_once_with(sentinel.compressed_point)
assert test_key == sentinel.encoded_point


def test_signer_update(patch_default_backend, patch_serialization, patch_build_hasher):
signer = Signer(MagicMock(), key=MagicMock())
def test_signer_update(patch_default_backend, patch_serialization, patch_build_hasher, patch_ec):
mock_algorithm_info = MagicMock(return_value=sentinel.algorithm_info, spec=patch_ec.EllipticCurve)
algorithm = MagicMock(signing_algorithm_info=mock_algorithm_info)
signer = Signer(algorithm, key=MagicMock())
signer.update(sentinel.data)
patch_build_hasher.return_value.update.assert_called_once_with(sentinel.data)


def test_signer_finalize(
patch_default_backend, patch_serialization, patch_build_hasher, patch_ecc_static_length_signature
patch_default_backend, patch_serialization, patch_build_hasher, patch_ecc_static_length_signature, patch_ec
):
algorithm = MagicMock()
mock_algorithm_info = MagicMock(return_value=sentinel.algorithm_info, spec=patch_ec.EllipticCurve)
algorithm = MagicMock(signing_algorithm_info=mock_algorithm_info)
private_key = MagicMock()

signer = Signer(algorithm, key=private_key)
Expand Down
16 changes: 10 additions & 6 deletions test/unit/test_crypto_authentication_verifier.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ def test_f_verifier_key_bytes():
def test_verifier_from_encoded_point(
patch_default_backend,
patch_serialization,
patch_ec,
patch_ecc_public_numbers_from_compressed_point,
patch_base64,
patch_build_hasher,
Expand All @@ -94,21 +95,24 @@ def test_verifier_from_encoded_point(
mock_point_instance.public_key.return_value = sentinel.public_key
patch_ecc_public_numbers_from_compressed_point.return_value = mock_point_instance
patch_base64.b64decode.return_value = sentinel.compressed_point
algorithm = MagicMock()
mock_algorithm_info = MagicMock(return_value=sentinel.algorithm_info, spec=patch_ec.EllipticCurve)
mock_algorithm = MagicMock(signing_algorithm_info=mock_algorithm_info)

verifier = Verifier.from_encoded_point(algorithm=algorithm, encoded_point=sentinel.encoded_point)
verifier = Verifier.from_encoded_point(algorithm=mock_algorithm, encoded_point=sentinel.encoded_point)

patch_base64.b64decode.assert_called_once_with(sentinel.encoded_point)
algorithm.signing_algorithm_info.assert_called_once_with()
mock_algorithm.signing_algorithm_info.assert_called_once_with()
patch_ecc_public_numbers_from_compressed_point.assert_called_once_with(
curve=algorithm.signing_algorithm_info.return_value, compressed_point=sentinel.compressed_point
curve=mock_algorithm.signing_algorithm_info.return_value, compressed_point=sentinel.compressed_point
)
mock_point_instance.public_key.assert_called_once_with(patch_default_backend.return_value)
assert isinstance(verifier, Verifier)


def test_verifier_update(patch_default_backend, patch_serialization, patch_build_hasher):
verifier = Verifier(algorithm=MagicMock(), key=MagicMock())
def test_verifier_update(patch_default_backend, patch_serialization, patch_build_hasher, patch_ec):
mock_algorithm_info = MagicMock(return_value=sentinel.algorithm_info, spec=patch_ec.EllipticCurve)
mock_algorithm = MagicMock(signing_algorithm_info=mock_algorithm_info)
verifier = Verifier(algorithm=mock_algorithm, key=MagicMock())
verifier.update(sentinel.data)
verifier._hasher.update.assert_called_once_with(sentinel.data)

Expand Down
9 changes: 3 additions & 6 deletions test/unit/test_crypto_elliptic_curve.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@

import pytest
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.utils import InterfaceNotImplemented
from mock import MagicMock, sentinel
from pytest_mock import mocker # noqa pylint: disable=unused-import

Expand Down Expand Up @@ -374,22 +373,20 @@ def test_ecc_public_numbers_from_compressed_point(patch_ec, patch_ecc_decode_com
assert test == sentinel.public_numbers_instance


def test_generate_ecc_signing_key_supported(patch_default_backend, patch_ec, patch_verify_interface):
def test_generate_ecc_signing_key_supported(patch_default_backend, patch_ec):
patch_ec.generate_private_key.return_value = sentinel.raw_signing_key
mock_algorithm_info = MagicMock(return_value=sentinel.algorithm_info)
mock_algorithm_info = MagicMock(return_value=sentinel.algorithm_info, spec=patch_ec.EllipticCurve)
mock_algorithm = MagicMock(signing_algorithm_info=mock_algorithm_info)

test_signing_key = generate_ecc_signing_key(algorithm=mock_algorithm)

patch_verify_interface.assert_called_once_with(patch_ec.EllipticCurve, mock_algorithm_info)
patch_ec.generate_private_key.assert_called_once_with(
curve=sentinel.algorithm_info, backend=patch_default_backend.return_value
)
assert test_signing_key is sentinel.raw_signing_key


def test_generate_ecc_signing_key_unsupported(patch_default_backend, patch_ec, patch_verify_interface):
patch_verify_interface.side_effect = InterfaceNotImplemented
def test_generate_ecc_signing_key_unsupported(patch_default_backend, patch_ec):
mock_algorithm_info = MagicMock(return_value=sentinel.algorithm_info)
mock_algorithm = MagicMock(signing_algorithm_info=mock_algorithm_info)

Expand Down
18 changes: 4 additions & 14 deletions test/unit/test_crypto_prehashing_authenticator.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
# language governing permissions and limitations under the License.
"""Unit test suite for ``aws_encryption_sdk.internal.crypto._PrehashingAuthenticater``."""
import pytest
from cryptography.utils import InterfaceNotImplemented
from mock import MagicMock, sentinel
from pytest_mock import mocker # noqa pylint: disable=unused-import

Expand All @@ -35,12 +34,6 @@ def patch_build_hasher(mocker):
yield _PrehashingAuthenticator._build_hasher


@pytest.fixture
def patch_cryptography_utils_verify_interface(mocker):
mocker.patch.object(aws_encryption_sdk.internal.crypto.authentication, "verify_interface")
yield aws_encryption_sdk.internal.crypto.authentication.verify_interface


@pytest.fixture
def patch_cryptography_ec(mocker):
mocker.patch.object(aws_encryption_sdk.internal.crypto.authentication, "ec")
Expand Down Expand Up @@ -71,21 +64,18 @@ def test_init(patch_set_signature_type, patch_build_hasher):


def test_set_signature_type_elliptic_curve(
patch_build_hasher, patch_cryptography_utils_verify_interface, patch_cryptography_ec
patch_build_hasher, patch_cryptography_ec
):
mock_algorithm = MagicMock()
mock_algorithm_info = MagicMock(return_value=sentinel.algorithm_info, spec=patch_cryptography_ec.EllipticCurve)
mock_algorithm = MagicMock(signing_algorithm_info=mock_algorithm_info)
test = _PrehashingAuthenticator(algorithm=mock_algorithm, key=sentinel.key)

patch_cryptography_utils_verify_interface.assert_called_once_with(
patch_cryptography_ec.EllipticCurve, mock_algorithm.signing_algorithm_info
)
assert test._signature_type is patch_cryptography_ec.EllipticCurve


def test_set_signature_type_unknown(
patch_build_hasher, patch_cryptography_utils_verify_interface, patch_cryptography_ec
patch_build_hasher, patch_cryptography_ec
):
patch_cryptography_utils_verify_interface.side_effect = InterfaceNotImplemented
with pytest.raises(NotSupportedError) as excinfo:
_PrehashingAuthenticator(algorithm=MagicMock(), key=sentinel.key)

Expand Down
2 changes: 1 addition & 1 deletion test_vector_handlers/src/pylintrc
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[MESSAGES CONTROL]
[MESSAGE CONTROL]
# Disabling messages that we either don't care about for tests or are necessary to break for tests.
disable =
bad-continuation, # we let black handle this
Expand Down

0 comments on commit d3c7638

Please sign in to comment.