Skip to content
ecdsa.com
Python ssl module (OpenSSL 3)Python cryptography

Error message

[SSL: UNSAFE_LEGACY_RENEGOTIATION_DISABLED] unsafe legacy renegotiation disabled

Appears with Python linked against OpenSSL 3.0 or later (most Python builds since 2022); OpenSSL 1.1.1 still allowed these servers. A source location such as "(_ssl.c:1082)" follows.

Python ssl module (OpenSSL 3) — ssl.SSLError, SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED

What it means

The server negotiated TLS 1.2 or older without the secure renegotiation extension of RFC 5746. OpenSSL 3 clients refuse such servers by default, because legacy renegotiation allowed a man-in-the-middle to splice its own data in front of the client's request (CVE-2009-3555). Python inherits that default, so the connection fails during the handshake.

Why it happens

How to fix it

  1. 1.

    Confirm the server lacks secure renegotiation

    openssl s_client reports "Secure Renegotiation IS NOT supported" for such servers.

    bash
    openssl s_client -connect legacy.example.com:443 -servername legacy.example.com </dev/null 2>/dev/null \
      | grep -i 'secure renegotiation'
    # "Secure Renegotiation IS NOT supported" confirms the server lacks RFC 5746
  2. 2.

    Fix the server

    Updating the server's TLS stack or firmware, or offering TLS 1.3, removes the problem for every client.

    text
    Server / appliance owners: update the TLS stack or firmware to any release
    supporting RFC 5746 (every mainstream TLS library since 2010), or enable TLS 1.3,
    which has no renegotiation at all.
  3. 3.

    Temporary workaround: allow it for one host only

    ssl.OP_LEGACY_SERVER_CONNECT (Python 3.12+) re-enables connections to such servers for this one context. It re-opens the renegotiation splicing risk for that host, so do not set it globally or via the system OpenSSL configuration.

    python
    # Temporary workaround for one legacy host only (Python 3.12+: ssl.OP_LEGACY_SERVER_CONNECT)
    import ssl, urllib.request
    
    ctx = ssl.create_default_context()
    ctx.options |= ssl.OP_LEGACY_SERVER_CONNECT
    urllib.request.urlopen("https://legacy.example.com/", context=ctx)

Related errors

Browse the full signature error database