Skip to content

refactor: remove verify_interface #471

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions decrypt_oracle/requirements-actual.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# Requirements for actual package
chalice
aws-encryption-sdk~=1.7.1
cryptography>=2.5.0,<3.3.2
10 changes: 5 additions & 5 deletions dev_requirements/linter-requirements.txt
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
bandit==1.7.0
black==21.12b0
bandit==1.7.4
black==22.3.0
doc8==0.10.1
flake8==4.0.1
flake8-bugbear==21.11.29
flake8-bugbear==22.1.11
flake8-docstrings==1.6.0
flake8-print==4.0.0
isort==5.10.1
pyflakes==2.4.0
pylint==2.12.2
readme_renderer==32.0
pylint==2.13.5
readme_renderer==34.0
seed-isort-config==2.2.0
vulture==2.3
sphinx==4.4.0
4 changes: 4 additions & 0 deletions dev_requirements/release-requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
pypi-parker==0.1.2
setuptools==62.0.0
twine==3.8.0
wheel==0.37.1
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
boto3>=1.10.0
cryptography>=2.5.0
cryptography>=2.5.0,<=3.3.2
attrs>=17.4.0
wrapt>=1.10.11
9 changes: 4 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,8 @@
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 aws_encryption_sdk.internal.utils import verify_ec_interface

from ...exceptions import NotSupportedError
from .elliptic_curve import (
Expand Down Expand Up @@ -47,11 +48,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 verify_ec_interface(self.algorithm):
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
10 changes: 5 additions & 5 deletions src/aws_encryption_sdk/internal/crypto/elliptic_curve.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@
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_from_bytes, int_to_bytes, verify_interface
from cryptography.utils import int_from_bytes, int_to_bytes

from aws_encryption_sdk.internal.utils import verify_ec_interface

from ...exceptions import NotSupportedError
from ..str_ops import to_bytes
Expand Down Expand Up @@ -183,8 +185,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 verify_ec_interface(algorithm):
raise NotSupportedError("Unsupported signing algorithm info")
return ec.generate_private_key(curve=algorithm.signing_algorithm_info(), backend=default_backend())
15 changes: 15 additions & 0 deletions src/aws_encryption_sdk/internal/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import os

import six
from cryptography.hazmat.primitives.asymmetric import ec

import aws_encryption_sdk.internal.defaults
from aws_encryption_sdk.exceptions import InvalidDataKeyError, SerializationError, UnknownIdentityError
Expand Down Expand Up @@ -161,3 +162,17 @@ def source_data_key_length_check(source_data_key, algorithm):
actual=len(source_data_key.data_key), required=algorithm.kdf_input_len
)
)


def verify_ec_interface(algorithm):
"""Validates that the provided EllipticCurve Algorithm is correctly implemented by
checking if it implements both of the abstract methods from the EllipticCurve
abstract class.

:param algorithm: Algorithm object which directs which Elliptic Curve will be used
:type algorithm: aws_encryption_sdk.identifiers.Algorithm
"""
for method in ec.EllipticCurve.__abstractmethods__:
if not hasattr(algorithm.signing_algorithm_info(), method):
return False
return True
49 changes: 39 additions & 10 deletions test/unit/test_crypto_authentication_signer.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ def patch_default_backend(mocker):


@pytest.yield_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")
yield aws_encryption_sdk.internal.crypto.authentication.serialization
Expand Down Expand Up @@ -71,8 +77,13 @@ 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):
patch_ec.EllipticCurve.__abstractmethods__ = set()
mock_algorithm_info = MagicMock(return_value=sentinel.algorithm_info, spec=patch_ec.EllipticCurve)
mock_algorithm_info.return_value.name = True
mock_algorithm_info.return_value.key_size = True
_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 +94,12 @@ 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):
patch_ec.EllipticCurve.__abstractmethods__ = set()
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 +112,45 @@ 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)
patch_ec.EllipticCurve.__abstractmethods__ = set()

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):
patch_ec.EllipticCurve.__abstractmethods__ = set()
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()
patch_ec.EllipticCurve.__abstractmethods__ = set()
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
9 changes: 7 additions & 2 deletions test/unit/test_crypto_authentication_verifier.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,17 +89,22 @@ def test_verifier_from_encoded_point(
patch_ecc_public_numbers_from_compressed_point,
patch_base64,
patch_build_hasher,
patch_ec
):
mock_point_instance = MagicMock()
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()

patch_ec.EllipticCurve.__abstractmethods__ = set()
mock_algorithm_info = MagicMock(return_value=sentinel.algorithm_info, spec=patch_ec.EllipticCurve)
mock_algorithm_info.return_value.name = True
mock_algorithm_info.return_value.key_size = True
algorithm = MagicMock(signing_algorithm_info=mock_algorithm_info)

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

patch_base64.b64decode.assert_called_once_with(sentinel.encoded_point)
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
)
Expand Down
24 changes: 11 additions & 13 deletions test/unit/test_crypto_elliptic_curve.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@

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

import aws_encryption_sdk.internal.crypto.elliptic_curve
import aws_encryption_sdk.internal.defaults
from aws_encryption_sdk.exceptions import NotSupportedError
from aws_encryption_sdk.internal.crypto.elliptic_curve import (
_ECC_CURVE_PARAMETERS,
Expand Down Expand Up @@ -72,12 +72,6 @@ def patch_ecc_decode_compressed_point(mocker):
yield aws_encryption_sdk.internal.crypto.elliptic_curve._ecc_decode_compressed_point


@pytest.yield_fixture
def patch_verify_interface(mocker):
mocker.patch.object(aws_encryption_sdk.internal.crypto.elliptic_curve, "verify_interface")
yield aws_encryption_sdk.internal.crypto.elliptic_curve.verify_interface


@pytest.yield_fixture
def patch_ecc_curve_parameters(mocker):
mocker.patch.object(aws_encryption_sdk.internal.crypto.elliptic_curve, "_ECC_CURVE_PARAMETERS")
Expand Down Expand Up @@ -374,23 +368,27 @@ 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)
patch_ec.EllipticCurve.__abstractmethods__ = {"key_size", "name"}
mock_algorithm_info = MagicMock(return_value=sentinel.algorithm_info, spec=patch_ec.EllipticCurve)
mock_algorithm_info.return_value.name = MagicMock(return_value=True)
mock_algorithm_info.return_value.key_size = MagicMock(return_value=True)
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
mock_algorithm_info = MagicMock(return_value=sentinel.algorithm_info)
def test_generate_ecc_signing_key_unsupported(patch_default_backend, patch_ec):
patch_ec.generate_private_key.return_value = sentinel.raw_signing_key
mock_algorithm_info = MagicMock(return_value=sentinel.invalid_algorithm_info, spec=patch_ec.EllipticCurve)
mock_algorithm_info.return_value.not_name = MagicMock(return_value=True)
mock_algorithm_info.return_value.not_key_size = MagicMock(return_value=True)
mock_algorithm = MagicMock(signing_algorithm_info=mock_algorithm_info)

with pytest.raises(NotSupportedError) as excinfo:
Expand Down
28 changes: 13 additions & 15 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.yield_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.yield_fixture
def patch_cryptography_ec(mocker):
mocker.patch.object(aws_encryption_sdk.internal.crypto.authentication, "ec")
Expand Down Expand Up @@ -71,23 +64,28 @@ 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()
patch_cryptography_ec.generate_private_key.return_value = sentinel.raw_signing_key
patch_cryptography_ec.EllipticCurve.__abstractmethods__ = set()
mock_algorithm_info = MagicMock(return_value=sentinel.algorithm_info, spec=patch_cryptography_ec.EllipticCurve)
mock_algorithm_info.return_value.name = MagicMock(return_value=True)
mock_algorithm_info.return_value.key_size = MagicMock(return_value=True)
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
mock_algorithm_info = MagicMock(return_value=sentinel.not_algorithm_info, spec=patch_cryptography_ec.EllipticCurve)
mock_algorithm_info.return_value.not_name = MagicMock(return_value=True)
mock_algorithm_info.return_value.not_key_size = MagicMock(return_value=True)
mock_algorithm = MagicMock(signing_algorithm_info=mock_algorithm_info)
with pytest.raises(NotSupportedError) as excinfo:
_PrehashingAuthenticator(algorithm=MagicMock(), key=sentinel.key)
_PrehashingAuthenticator(algorithm=mock_algorithm, key=sentinel.key)

excinfo.match(r"Unsupported signing algorithm info")

Expand Down
19 changes: 19 additions & 0 deletions test/unit/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import aws_encryption_sdk.internal.utils
from aws_encryption_sdk.exceptions import InvalidDataKeyError, SerializationError, UnknownIdentityError
from aws_encryption_sdk.internal.defaults import MAX_FRAME_SIZE, MESSAGE_ID_LENGTH
from aws_encryption_sdk.internal.utils import verify_ec_interface
from aws_encryption_sdk.structures import DataKey, EncryptedDataKey, MasterKeyInfo, RawDataKey

from .test_values import VALUES
Expand All @@ -29,12 +30,30 @@
pytestmark = [pytest.mark.unit, pytest.mark.local]


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


def test_prep_stream_data_passthrough():
test = aws_encryption_sdk.internal.utils.prep_stream_data(io.BytesIO(b"some data"))

assert_prepped_stream_identity(test, io.BytesIO)


def test_verify_ec_interface(patch_ec):
patch_ec.EllipticCurve.__abstractmethods__ = set(("key_size", "name"))
mock_algorithm_info = MagicMock(return_value=sentinel.algorithm_info, spec=patch_ec.EllipticCurve)
mock_algorithm_info.return_value.name = True
mock_algorithm_info.return_value.key_size = True
_algorithm = MagicMock(signing_algorithm_info=mock_algorithm_info)

implemented = verify_ec_interface(algorithm=_algorithm)

assert implemented is True


@pytest.mark.parametrize("source", (u"some unicode data ловие", b"\x00\x01\x02"))
def test_prep_stream_data_wrap(source):
test = aws_encryption_sdk.internal.utils.prep_stream_data(source)
Expand Down
Loading