Skip to content
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
19 changes: 19 additions & 0 deletions pymongo/ocsp_support.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@
from cryptography.hazmat.primitives.asymmetric.ec import (
EllipticCurvePublicKey as _EllipticCurvePublicKey,
)
from cryptography.hazmat.primitives.asymmetric.mlkem import (
MLKEM768PublicKey as _MLKEM768PublicKey,
)
from cryptography.hazmat.primitives.asymmetric.mlkem import (
MLKEM1024PublicKey as _MLKEM1024PublicKey,
)
from cryptography.hazmat.primitives.asymmetric.padding import PKCS1v15 as _PKCS1v15
from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicKey as _RSAPublicKey
from cryptography.hazmat.primitives.asymmetric.x448 import (
Expand Down Expand Up @@ -68,6 +74,7 @@
ed448,
ed25519,
mldsa,
mlkem,
rsa,
x448,
x25519,
Expand All @@ -82,6 +89,9 @@
from pymongo.ocsp_cache import _OCSPCache
from pymongo.pyopenssl_context import _CallbackData

# Must stay in step with cryptography's CertificatePublicKeyTypes, the
# return type of Certificate.public_key(). cryptography does not export a
# public alias for it, so it is spelled out here.
CertificateIssuerPublicKeyTypes = Union[
dsa.DSAPublicKey,
rsa.RSAPublicKey,
Expand All @@ -91,6 +101,8 @@
mldsa.MLDSA44PublicKey,
mldsa.MLDSA65PublicKey,
mldsa.MLDSA87PublicKey,
mlkem.MLKEM768PublicKey,
mlkem.MLKEM1024PublicKey,
x25519.X25519PublicKey,
x448.X448PublicKey,
]
Expand Down Expand Up @@ -145,6 +157,13 @@ def _verify_signature(
key, (_X25519PublicKey, _X448PublicKey)
): # Curve25519 and Curve448 keys do not require verification
return 1
elif isinstance(key, (_MLKEM768PublicKey, _MLKEM1024PublicKey)):
# ML-KEM is a key encapsulation mechanism, not a signature
# algorithm, so such a key cannot have produced this signature and
# has no verify(). Certificate.public_key() can still return one,
# so fail closed rather than raise AttributeError.
_LOGGER.debug("%s cannot verify signatures", type(key).__name__)
return 0
else:
key.verify(signature, data)
except _InvalidSignature:
Expand Down
15 changes: 15 additions & 0 deletions test/test_ocsp_support.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ def test_tls(self):
from cryptography.exceptions import InvalidSignature
from cryptography.hazmat.primitives.asymmetric.dsa import DSAPublicKey
from cryptography.hazmat.primitives.asymmetric.ec import EllipticCurvePublicKey
from cryptography.hazmat.primitives.asymmetric.mlkem import (
MLKEM768PrivateKey,
MLKEM1024PrivateKey,
)
from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicKey
from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat
from cryptography.x509 import (
Expand Down Expand Up @@ -182,6 +186,17 @@ class FakeX448:
self.assertEqual(_verify_signature(key, b"sig", Mock(), b"data"), 1) # type: ignore[arg-type]
key.verify.assert_not_called()

def test_mlkem768_fails_closed(self):
# ML-KEM is a key encapsulation mechanism, so an ML-KEM public key has
# no verify(). Certificate.public_key() can return one, which used to
# reach the generic branch and raise AttributeError.
key = MLKEM768PrivateKey.generate().public_key()
self.assertEqual(_verify_signature(key, b"sig", Mock(), b"data"), 0)

def test_mlkem1024_fails_closed(self):
key = MLKEM1024PrivateKey.generate().public_key()
self.assertEqual(_verify_signature(key, b"sig", Mock(), b"data"), 0)

def test_other_key_valid(self):
key = Mock()
self.assertEqual(_verify_signature(key, b"sig", Mock(), b"data"), 1) # type: ignore[arg-type]
Expand Down
Loading
Loading