Skip to content
Closed
Show file tree
Hide file tree
Changes from 2 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
2 changes: 1 addition & 1 deletion doc/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ PyMongo 4.17 brings a number of changes including:
been deprecated and will be removed in PyMongo 5.0. These methods were
deprecated in favor of the standard dictionary containment operator ``in``
and the ``keys()`` and ``values()`` methods, respectively.

- Added the :meth:`~pymongo.asynchronous.client_session.AsyncClientSession.bind` and :meth:`~pymongo.client_session.ClientSession.bind` methods
that allow users to bind a session to all database operations within the scope of a context manager instead of having to explicitly pass the session to each individual operation.
See <PLACEHOLDER> for examples and more information.
- OCSP authentication now uses the more secure SHA-256 hashing algorithm for certificate verification instead of SHA-1.
Comment thread
NoahStapp marked this conversation as resolved.
Outdated

Changes in Version 4.16.0 (2026/01/07)
--------------------------------------
Expand Down
8 changes: 4 additions & 4 deletions pymongo/ocsp_support.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
from cryptography.hazmat.primitives.asymmetric.x25519 import (
X25519PublicKey as _X25519PublicKey,
)
from cryptography.hazmat.primitives.hashes import SHA1 as _SHA1
from cryptography.hazmat.primitives.hashes import SHA256 as _SHA256
from cryptography.hazmat.primitives.hashes import Hash as _Hash
from cryptography.hazmat.primitives.serialization import Encoding as _Encoding
from cryptography.hazmat.primitives.serialization import PublicFormat as _PublicFormat
Expand Down Expand Up @@ -158,7 +158,7 @@ def _get_extension(
def _public_key_hash(cert: Certificate) -> bytes:
public_key = cert.public_key()
# https://tools.ietf.org/html/rfc2560#section-4.2.1
# "KeyHash ::= OCTET STRING -- SHA-1 hash of responder's public key
# "KeyHash ::= OCTET STRING -- SHA-256 hash of responder's public key
# (excluding the tag and length fields)"
# https://stackoverflow.com/a/46309453/600498
if isinstance(public_key, _RSAPublicKey):
Expand All @@ -167,7 +167,7 @@ def _public_key_hash(cert: Certificate) -> bytes:
pbytes = public_key.public_bytes(_Encoding.X962, _PublicFormat.UncompressedPoint)
else:
pbytes = public_key.public_bytes(_Encoding.DER, _PublicFormat.SubjectPublicKeyInfo)
digest = _Hash(_SHA1(), backend=_default_backend()) # noqa: S303
digest = _Hash(_SHA256(), backend=_default_backend())
Comment on lines 166 to +170
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_public_key_hash now computes a SHA-256 digest, but the OCSP ResponderID byKey KeyHash is defined as a SHA-1 hash in RFC2560/RFC6960. response.responder_key_hash from cryptography follows the RFC, so switching this to SHA-256 will prevent _get_certs_by_key_hash from ever finding a matching responder cert (and can cause valid delegated OCSP responses to be rejected). Keep SHA-1 for the responder KeyHash computation (and update the comment accordingly), even if the OCSP CertID/request hashing moves to SHA-256.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@NoahStapp Good catch copilot ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I need to verify more, the robots have given different answers on each ask.

digest.update(pbytes)
return digest.finalize()

Expand Down Expand Up @@ -249,7 +249,7 @@ def _verify_response_signature(issuer: Certificate, response: OCSPResponse) -> i
def _build_ocsp_request(cert: Certificate, issuer: Certificate) -> OCSPRequest:
# https://cryptography.io/en/latest/x509/ocsp/#creating-requests
builder = _OCSPRequestBuilder()
builder = builder.add_certificate(cert, issuer, _SHA1()) # noqa: S303
builder = builder.add_certificate(cert, issuer, _SHA256())
return builder.build()
Comment on lines 249 to 253
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changing the OCSP request CertID hash algorithm to SHA-256 updates response.issuer_key_hash (it is computed using the request's hash algorithm). The response ResponderID responder_key_hash is not derived from the CertID hash algorithm, so the existing responder-is-issuer shortcut (rkey_hash == ikey_hash) can stop working and may incorrectly treat an issuer responder as a delegate, causing verification failures when no responder cert is embedded. Update the issuer-responder detection logic to compare like-for-like (e.g., compare responder_key_hash against a SHA-1 KeyHash of the issuer cert per RFC, or rely on responder_name when present) rather than comparing to issuer_key_hash.

Copilot uses AI. Check for mistakes.


Expand Down
Loading