snowflakedb / snowflakedb/snowflake-connector-python

SNOW-4108603: Vendored urllib3 triggers pyOpenSSL X509.get_subject DeprecationWarning

Open
#3,034 1 comment 0 reactions 1 assignee View on GitHub

@sfc-gh-snow-drivers-warsaw-dl is already working on this.

Since Sep 14, 2026.

bug status-triage_done
Dominant language
Python
Stars
730
Forks
574
Avg merge
5h 45m
Merged PRs (30d)
16

Description

Python version

Python 3.14.7 (main, Aug 14 2026, 15:24:10) [Clang 22.1.3 ]

Operating system and processor architecture

macOS-26.6.2-arm64-arm-64bit-Mach-O

Installed packages
certifi==2026.5.20
cffi==2.0.0
cryptography==50.0.1
pyopenssl==26.4.0
requests==2.33.1
snowflake-connector-python==4.7.1
snowflake-sqlalchemy==1.11.0
urllib3==2.7.0
What did you do?
Any successful TLS connection to Snowflake now emits a `DeprecationWarning`.


# python -W error::DeprecationWarning repro.py
import snowflake.connector

snowflake.connector.connect(
    account="<account>",
    user="<user>",
    private_key_file="<path>",
)


Offline reproduction that exercises the exact code path without credentials:


import datetime
from types import SimpleNamespace

from cryptography import x509
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.x509.oid import NameOID
from OpenSSL import crypto
from snowflake.connector.vendored.urllib3.contrib import pyopenssl

key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
name = x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, "example.snowflakecomputing.com")])
now = datetime.datetime.now(datetime.UTC)
cert = (
    x509.CertificateBuilder()
    .subject_name(name)
    .issuer_name(name)
    .public_key(key.public_key())
    .serial_number(x509.random_serial_number())
    .not_valid_before(now)
    .not_valid_after(now + datetime.timedelta(days=1))
    .sign(key, hashes.SHA256())
)
fake_socket = SimpleNamespace(
    connection=SimpleNamespace(get_peer_certificate=lambda: crypto.X509.from_cryptography(cert)),
)

pyopenssl.WrappedSocket.getpeercert(fake_socket, binary_form=False)



$ python -W error::DeprecationWarning repro_offline.py
  File ".../snowflake/connector/vendored/urllib3/contrib/pyopenssl.py", line 397, in getpeercert
    "subject": ((("commonName", x509.get_subject().CN),),),
DeprecationWarning: X509.get_subject is deprecated. You should use cryptography's X.509 APIs instead.
What did you expect to see?

Connecting should not emit deprecation warnings from code the connector vendors.

What happens instead: since 4.6.0, ssl_wrap_socket.py runs _verify_hostname_after_handshake(), which calls wrapped_socket.getpeercert() on the vendored urllib3.contrib.pyopenssl.WrappedSocket. That method builds the subject entry with x509.get_subject().CN. pyOpenSSL 26.x deprecates X509.get_subject and X509Name, so every connection now warns. Under -W error the connection raises:

conftest.py:151: in setup_snowflake_test_db
    with target_engine.begin() as target_conn:
...
snowflake/connector/connection.py:1219: in connect
    self.__open_connection()
snowflake/connector/connection.py:1660: in __open_connection
    self.authenticate_with_retry(self.auth_class)
...
snowflake/connector/network.py:1121: in _request_exec
    raw_ret = session.request(
...
snowflake/connector/vendored/urllib3/connection.py:984: in _ssl_wrap_socket_and_match_hostname
    ssl_sock = ssl_wrap_socket(
snowflake/connector/ssl_wrap_socket.py:315: in ssl_wrap_socket_with_cert_revocation_checks
    _verify_hostname_after_handshake(ret, server_hostname, params.get("ssl_context"))
snowflake/connector/ssl_wrap_socket.py:270: in _verify_hostname_after_handshake
    cert = wrapped_socket.getpeercert()
snowflake/connector/vendored/urllib3/contrib/pyopenssl.py:397: in getpeercert
    "subject": ((("commonName", x509.get_subject().CN),),),  # type: ignore[dict-item]
E   DeprecationWarning: X509.get_subject is deprecated. You should use cryptography's X.509 APIs instead.

4.5.0 did not call getpeercert() on this path, so the deprecated API was never reached even with pyOpenSSL 26.4.0 installed.

urllib3 already fixed this on main (unreleased as of 2.7.0): getpeercert now uses a _get_common_name(x509) helper based on x509.to_cryptography().subject.get_attributes_for_oid(NameOID.COMMON_NAME). See https://github.com/urllib3/urllib3/blob/5f2a6a843d0100d1351c3f94d58581ca98d17267/src/urllib3/contrib/pyopenssl.py#L417. Suggested fix: backport that change into the vendored copy (or read the common name via to_cryptography() in _verify_hostname_after_handshake), so the connector stays clean once X509Name is removed from pyOpenSSL.

Can you set logging to DEBUG and collect the logs?
not necessary

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.