Skip to content

Commit c00a58c

Browse files
authored
fix: use issubclass instead of isinstance in _set_signature_type (#800)
Replace isinstance(signing_algorithm_info, type(ec.EllipticCurve)) with issubclass(signing_algorithm_info, ec.EllipticCurve) wrapped in try/except TypeError. The old check used isinstance against ABCMeta which was fragile and semantically incorrect for checking class hierarchy. Update tests to use real EC curve classes (ec.SECP256R1, ec.SECP384R1) instead of MagicMock with spec=ec.EllipticCurve, which masked the bug. Based on PR #794.
1 parent 73c7ddb commit c00a58c

4 files changed

Lines changed: 38 additions & 25 deletions

File tree

src/aws_encryption_sdk/internal/crypto/authentication.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,10 @@ def __init__(self, algorithm, key):
3636

3737
def _set_signature_type(self):
3838
"""Ensures that the algorithm signature type is a known type and sets a reference value."""
39-
if not isinstance(self.algorithm.signing_algorithm_info, type(ec.EllipticCurve)):
39+
try:
40+
if not issubclass(self.algorithm.signing_algorithm_info, ec.EllipticCurve):
41+
raise NotSupportedError("Unsupported signing algorithm info")
42+
except TypeError:
4043
raise NotSupportedError("Unsupported signing algorithm info")
4144
return ec.EllipticCurve
4245

test/unit/test_crypto_authentication_signer.py

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"""Unit test suite for ``aws_encryption_sdk.internal.crypto.authentication.Signer``."""
44
import cryptography.hazmat.primitives.serialization
55
import pytest
6+
from cryptography.hazmat.primitives.asymmetric import ec
67
from mock import MagicMock, patch, sentinel
78
from pytest_mock import mocker # noqa pylint: disable=unused-import
89

@@ -73,8 +74,8 @@ def test_GIVEN_no_encoding_WHEN_signer_from_key_bytes_THEN_load_der_private_key(
7374
patch_build_hasher,
7475
patch_ec
7576
):
76-
mock_algorithm_info = MagicMock(return_value=sentinel.algorithm_info, spec=patch_ec.EllipticCurve)
77-
_algorithm = MagicMock(signing_algorithm_info=mock_algorithm_info)
77+
patch_ec.EllipticCurve = ec.EllipticCurve
78+
_algorithm = MagicMock(signing_algorithm_info=ec.SECP256R1)
7879

7980
# Make a new patched serialization module for this test.
8081
# The default patch introduces serialization as `serialization.Encoding.DER`
@@ -106,8 +107,8 @@ def test_GIVEN_PEM_encoding_WHEN_signer_from_key_bytes_THEN_load_pem_private_key
106107
patch_build_hasher,
107108
patch_ec
108109
):
109-
mock_algorithm_info = MagicMock(return_value=sentinel.algorithm_info, spec=patch_ec.EllipticCurve)
110-
_algorithm = MagicMock(signing_algorithm_info=mock_algorithm_info)
110+
patch_ec.EllipticCurve = ec.EllipticCurve
111+
_algorithm = MagicMock(signing_algorithm_info=ec.SECP256R1)
111112

112113
# When: from_key_bytes
113114
signer = Signer.from_key_bytes(
@@ -132,8 +133,8 @@ def test_GIVEN_unrecognized_encoding_WHEN_signer_from_key_bytes_THEN_raise_Value
132133
patch_build_hasher,
133134
patch_ec
134135
):
135-
mock_algorithm_info = MagicMock(return_value=sentinel.algorithm_info, spec=patch_ec.EllipticCurve)
136-
_algorithm = MagicMock(signing_algorithm_info=mock_algorithm_info)
136+
patch_ec.EllipticCurve = ec.EllipticCurve
137+
_algorithm = MagicMock(signing_algorithm_info=ec.SECP256R1)
137138

138139
# Then: Raises ValueError
139140
with pytest.raises(ValueError):
@@ -147,8 +148,8 @@ def test_GIVEN_unrecognized_encoding_WHEN_signer_from_key_bytes_THEN_raise_Value
147148

148149

149150
def test_signer_key_bytes(patch_default_backend, patch_serialization, patch_build_hasher, patch_ec):
150-
mock_algorithm_info = MagicMock(return_value=sentinel.algorithm_info, spec=patch_ec.EllipticCurve)
151-
algorithm = MagicMock(signing_algorithm_info=mock_algorithm_info)
151+
patch_ec.EllipticCurve = ec.EllipticCurve
152+
algorithm = MagicMock(signing_algorithm_info=ec.SECP256R1)
152153
private_key = MagicMock()
153154
signer = Signer(algorithm, key=private_key)
154155

@@ -174,8 +175,8 @@ def test_signer_encoded_public_key(
174175
patch_base64.b64encode.return_value = sentinel.encoded_point
175176
private_key = MagicMock()
176177

177-
mock_algorithm_info = MagicMock(return_value=sentinel.algorithm_info, spec=patch_ec.EllipticCurve)
178-
algorithm = MagicMock(signing_algorithm_info=mock_algorithm_info)
178+
patch_ec.EllipticCurve = ec.EllipticCurve
179+
algorithm = MagicMock(signing_algorithm_info=ec.SECP256R1)
179180

180181
signer = Signer(algorithm, key=private_key)
181182
test_key = signer.encoded_public_key()
@@ -186,8 +187,8 @@ def test_signer_encoded_public_key(
186187

187188

188189
def test_signer_update(patch_default_backend, patch_serialization, patch_build_hasher, patch_ec):
189-
mock_algorithm_info = MagicMock(return_value=sentinel.algorithm_info, spec=patch_ec.EllipticCurve)
190-
algorithm = MagicMock(signing_algorithm_info=mock_algorithm_info)
190+
patch_ec.EllipticCurve = ec.EllipticCurve
191+
algorithm = MagicMock(signing_algorithm_info=ec.SECP256R1)
191192
signer = Signer(algorithm, key=MagicMock())
192193
signer.update(sentinel.data)
193194
patch_build_hasher.return_value.update.assert_called_once_with(sentinel.data)
@@ -196,8 +197,8 @@ def test_signer_update(patch_default_backend, patch_serialization, patch_build_h
196197
def test_signer_finalize(
197198
patch_default_backend, patch_serialization, patch_build_hasher, patch_ecc_static_length_signature, patch_ec
198199
):
199-
mock_algorithm_info = MagicMock(return_value=sentinel.algorithm_info, spec=patch_ec.EllipticCurve)
200-
algorithm = MagicMock(signing_algorithm_info=mock_algorithm_info)
200+
patch_ec.EllipticCurve = ec.EllipticCurve
201+
algorithm = MagicMock(signing_algorithm_info=ec.SECP256R1)
201202
private_key = MagicMock()
202203

203204
signer = Signer(algorithm, key=private_key)

test/unit/test_crypto_authentication_verifier.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
# SPDX-License-Identifier: Apache-2.0
33
"""Unit test suite for ``aws_encryption_sdk.internal.crypto.authentication.Verifier``."""
44
import pytest
5+
from cryptography.hazmat.primitives.asymmetric import ec
56
from mock import MagicMock, sentinel
67
from pytest_mock import mocker # noqa pylint: disable=unused-import
78

@@ -85,23 +86,23 @@ def test_verifier_from_encoded_point(
8586
mock_point_instance.public_key.return_value = sentinel.public_key
8687
patch_ecc_public_numbers_from_compressed_point.return_value = mock_point_instance
8788
patch_base64.b64decode.return_value = sentinel.compressed_point
88-
mock_algorithm_info = MagicMock(return_value=sentinel.algorithm_info, spec=patch_ec.EllipticCurve)
89-
mock_algorithm = MagicMock(signing_algorithm_info=mock_algorithm_info)
89+
mock_algorithm = MagicMock(signing_algorithm_info=ec.SECP256R1)
90+
patch_ec.EllipticCurve = ec.EllipticCurve
9091

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

9394
patch_base64.b64decode.assert_called_once_with(sentinel.encoded_point)
94-
mock_algorithm.signing_algorithm_info.assert_called_once_with()
95-
patch_ecc_public_numbers_from_compressed_point.assert_called_once_with(
96-
curve=mock_algorithm.signing_algorithm_info.return_value, compressed_point=sentinel.compressed_point
97-
)
95+
patch_ecc_public_numbers_from_compressed_point.assert_called_once()
96+
call_kwargs = patch_ecc_public_numbers_from_compressed_point.call_args
97+
assert isinstance(call_kwargs[1]["curve"], ec.SECP256R1)
98+
assert call_kwargs[1]["compressed_point"] is sentinel.compressed_point
9899
mock_point_instance.public_key.assert_called_once_with(patch_default_backend.return_value)
99100
assert isinstance(verifier, Verifier)
100101

101102

102103
def test_verifier_update(patch_default_backend, patch_serialization, patch_build_hasher, patch_ec):
103-
mock_algorithm_info = MagicMock(return_value=sentinel.algorithm_info, spec=patch_ec.EllipticCurve)
104-
mock_algorithm = MagicMock(signing_algorithm_info=mock_algorithm_info)
104+
patch_ec.EllipticCurve = ec.EllipticCurve
105+
mock_algorithm = MagicMock(signing_algorithm_info=ec.SECP256R1)
105106
verifier = Verifier(algorithm=mock_algorithm, key=MagicMock())
106107
verifier.update(sentinel.data)
107108
verifier._hasher.update.assert_called_once_with(sentinel.data)

test/unit/test_crypto_prehashing_authenticator.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
# SPDX-License-Identifier: Apache-2.0
33
"""Unit test suite for ``aws_encryption_sdk.internal.crypto._PrehashingAuthenticater``."""
44
import pytest
5+
from cryptography.hazmat.primitives.asymmetric import ec
56
from mock import MagicMock, sentinel
67
from pytest_mock import mocker # noqa pylint: disable=unused-import
78

@@ -56,13 +57,20 @@ def test_init(patch_set_signature_type, patch_build_hasher):
5657
def test_set_signature_type_elliptic_curve(
5758
patch_build_hasher, patch_cryptography_ec
5859
):
59-
mock_algorithm_info = MagicMock(return_value=sentinel.algorithm_info, spec=patch_cryptography_ec.EllipticCurve)
60-
mock_algorithm = MagicMock(signing_algorithm_info=mock_algorithm_info)
60+
patch_cryptography_ec.EllipticCurve = ec.EllipticCurve
61+
mock_algorithm = MagicMock(signing_algorithm_info=ec.SECP256R1)
6162
test = _PrehashingAuthenticator(algorithm=mock_algorithm, key=sentinel.key)
6263

6364
assert test._signature_type is patch_cryptography_ec.EllipticCurve
6465

6566

67+
def test_set_signature_type_elliptic_curve_known_value(patch_build_hasher):
68+
mock_algorithm = MagicMock(signing_algorithm_info=ec.SECP384R1)
69+
test = _PrehashingAuthenticator(algorithm=mock_algorithm, key=sentinel.key)
70+
71+
assert test._signature_type is ec.EllipticCurve
72+
73+
6674
def test_set_signature_type_unknown(
6775
patch_build_hasher, patch_cryptography_ec
6876
):

0 commit comments

Comments
 (0)