So, first of all, you should absolutely not have the private key! As the name says, it is private and not necessary to establish a connection.
You could have the public key, but even that is not necessary as long as you use standard SSL and you trust the CA that signed the servers certificate.
Are you sure, it is the private key? Does the file begin with -----BEGIN PRIVATE KEY-----? Check with openssl rsa -noout -text -in server.key.
Refer to the wikipedia article and this post for more on asymmetric cryptography.

Further along the way:
With socket.bind() you bind a socket to a port on your local machine. This is not possible, as your machine does not have the address (you provide a server address).
From your code, it looks like you are trying to open the socket as a server. You will need the private key for that, but then you will be accepting connections and not connect to other machines yourself. I have a feeling, that you are mixing up two things here.
Refer to the python documentation of socket.bind() and to this question as this seems to be closely related.
Also check out the python documentation on ssl. I took the example, that does what you are asking for from said documentation:

import socket, ssl, pprint

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# require a certificate from the server
ssl_sock = ssl.wrap_socket(s,
                           ca_certs="/etc/ca_certs_file",
                           cert_reqs=ssl.CERT_REQUIRED)
ssl_sock.connect(('www.verisign.com', 443))

pprint.pprint(ssl_sock.getpeercert())
# note that closing the SSLSocket will also close the underlying socket
ssl_sock.close()

Also have a look on the example on how to open a SSL socket in server mode.

Further thoughts:
Do you really need to do all that TLS stuff yourself? If the server, for example, uses HTTPS (SSL encrypted HTTP), you can just use the http.client library.

Feel free to ask, if you need me to clarify something. I'll update my answer accordingly.

EDIT:
As you indicated, you want to open a port in server mode, I made an example for you (it heavily leans on the python documentation example):

import socket, ssl

context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
context.load_cert_chain(certfile="cert.pem", keyfile="key.pem")

bindsocket = socket.socket()
bindsocket.bind(('127.0.0.1', 10023))
bindsocket.listen(5)

def deal_with_client(connstream):
    data = connstream.recv(1024)
    # empty data means the client is finished with us
    while data:
        print(data)
        data = connstream.recv(1024)

while True:
    newsocket, fromaddr = bindsocket.accept()
    connstream = context.wrap_socket(newsocket, server_side=True)
    try:
        deal_with_client(connstream)
    finally:
        connstream.shutdown(socket.SHUT_RDWR)
        connstream.close()

Running it:

% python3 ssltest.py
b'hello server!\n'
b'this is data\n'

The client side:

% openssl s_client -connect 127.0.0.1:10023
CONNECTED(00000005)
depth=0 C = SE, ST = Some-State, O = Internet Widgits Pty Ltd
verify error:num=18:self signed certificate
verify return:1
depth=0 C = SE, ST = Some-State, O = Internet Widgits Pty Ltd
verify return:1
---
Certificate chain
 0 s:C = SE, ST = Some-State, O = Internet Widgits Pty Ltd
   i:C = SE, ST = Some-State, O = Internet Widgits Pty Ltd
---
Server certificate
-----BEGIN CERTIFICATE-----
 ... certificate ...
-----END CERTIFICATE-----
subject=C = SE, ST = Some-State, O = Internet Widgits Pty Ltd

issuer=C = SE, ST = Some-State, O = Internet Widgits Pty Ltd

---
No client certificate CA names sent
Peer signing digest: SHA256
Peer signature type: RSA-PSS
Server Temp Key: X25519, 253 bits
---
SSL handshake has read 2272 bytes and written 404 bytes
Verification error: self signed certificate
---
New, TLSv1.2, Cipher is ECDHE-RSA-AES256-GCM-SHA384
Server public key is 4096 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
    Protocol  : TLSv1.2
    Cipher    : ECDHE-RSA-AES256-GCM-SHA384
    ... session stuff ...
    Extended master secret: yes
---
hello server!
this is data
^C

If you use some usual protocol like HTTP, you should use a library though. Here is a example with flask:

>>> from flask import Flask
>>> app = Flask(__name__)
>>> 
>>> @app.route("/")
... def hello():
...     return "Hello World!"
... 
>>> if __name__ == "__main__":
...     app.run(ssl_context=('cert.pem', 'key.pem'))
... 
 * Serving Flask app "__main__" (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: off
 * Running on https://127.0.0.1:5000/ (Press CTRL+C to quit)
127.0.0.1 - - [06/Aug/2020 11:45:50] "GET / HTTP/1.1" 200 -
Answer from toydarian on Stack Overflow
๐ŸŒ
PyPI
pypi.org โ€บ project โ€บ tls-client
tls-client ยท PyPI
Advanced Python HTTP Client. ... Python-TLS-Client is an advanced HTTP library based on requests and tls-client.
      ยป pip install tls-client
    
Published ย  Feb 02, 2024
Version ย  1.0.1
๐ŸŒ
GitHub
github.com โ€บ iamtorsten โ€บ tls-client
GitHub - iamtorsten/tls-client: Advanced HTTP Library ยท GitHub
Python-TLS-Client is an advanced HTTP library based on requests and tls-client.
Starred by 33 users
Forked by 11 users
Languages ย  Python 99.9% | Batchfile 0.1%
๐ŸŒ
Python
docs.python.org โ€บ 3 โ€บ library โ€บ ssl.html
ssl โ€” TLS/SSL wrapper for socket objects โ€” Python 3.14.4 ...
Deprecated since version 3.7: All OP_NO_SSL* and OP_NO_TLS* options have been deprecated since Python 3.7. Use SSLContext.minimum_version and SSLContext.maximum_version instead. ... Enable TLS 1.3 post-handshake client authentication. Post-handshake auth is disabled by default and a server can only request a TLS client certificate during the initial handshake.
๐ŸŒ
Medium
medium.com โ€บ @dimakynal โ€บ exploring-python-libraries-tls-client-vs-curl-cffi-for-web-requests-129b7888e1f6
Exploring Python Libraries: tls_client vs curl_cffi for Web Requests | by Dima Kynal | Medium
January 24, 2025 - The `tls_client` library in Python is a specialized tool designed for making HTTP requests with a strong focus on bypassing bot protection mechanisms. It achieves this by: - **TLS Fingerprinting**: The library can mimic the TLS fingerprint of ...
๐ŸŒ
GitHub
github.com โ€บ thewebscraping โ€บ tls-requests
GitHub - thewebscraping/tls-requests: TLS Requests is a powerful Python library for secure HTTP requests, offering browser-like TLS client, fingerprinting, anti-bot page bypass, and high performance. ยท GitHub
TLS Requests is a cutting-edge HTTP client for Python, offering a feature-rich, highly configurable alternative to the popular requests library.
Starred by 146 users
Forked by 10 users
Languages ย  Python
Top answer
1 of 1
15

So, first of all, you should absolutely not have the private key! As the name says, it is private and not necessary to establish a connection.
You could have the public key, but even that is not necessary as long as you use standard SSL and you trust the CA that signed the servers certificate.
Are you sure, it is the private key? Does the file begin with -----BEGIN PRIVATE KEY-----? Check with openssl rsa -noout -text -in server.key.
Refer to the wikipedia article and this post for more on asymmetric cryptography.

Further along the way:
With socket.bind() you bind a socket to a port on your local machine. This is not possible, as your machine does not have the address (you provide a server address).
From your code, it looks like you are trying to open the socket as a server. You will need the private key for that, but then you will be accepting connections and not connect to other machines yourself. I have a feeling, that you are mixing up two things here.
Refer to the python documentation of socket.bind() and to this question as this seems to be closely related.
Also check out the python documentation on ssl. I took the example, that does what you are asking for from said documentation:

import socket, ssl, pprint

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# require a certificate from the server
ssl_sock = ssl.wrap_socket(s,
                           ca_certs="/etc/ca_certs_file",
                           cert_reqs=ssl.CERT_REQUIRED)
ssl_sock.connect(('www.verisign.com', 443))

pprint.pprint(ssl_sock.getpeercert())
# note that closing the SSLSocket will also close the underlying socket
ssl_sock.close()

Also have a look on the example on how to open a SSL socket in server mode.

Further thoughts:
Do you really need to do all that TLS stuff yourself? If the server, for example, uses HTTPS (SSL encrypted HTTP), you can just use the http.client library.

Feel free to ask, if you need me to clarify something. I'll update my answer accordingly.

EDIT:
As you indicated, you want to open a port in server mode, I made an example for you (it heavily leans on the python documentation example):

import socket, ssl

context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
context.load_cert_chain(certfile="cert.pem", keyfile="key.pem")

bindsocket = socket.socket()
bindsocket.bind(('127.0.0.1', 10023))
bindsocket.listen(5)

def deal_with_client(connstream):
    data = connstream.recv(1024)
    # empty data means the client is finished with us
    while data:
        print(data)
        data = connstream.recv(1024)

while True:
    newsocket, fromaddr = bindsocket.accept()
    connstream = context.wrap_socket(newsocket, server_side=True)
    try:
        deal_with_client(connstream)
    finally:
        connstream.shutdown(socket.SHUT_RDWR)
        connstream.close()

Running it:

% python3 ssltest.py
b'hello server!\n'
b'this is data\n'

The client side:

% openssl s_client -connect 127.0.0.1:10023
CONNECTED(00000005)
depth=0 C = SE, ST = Some-State, O = Internet Widgits Pty Ltd
verify error:num=18:self signed certificate
verify return:1
depth=0 C = SE, ST = Some-State, O = Internet Widgits Pty Ltd
verify return:1
---
Certificate chain
 0 s:C = SE, ST = Some-State, O = Internet Widgits Pty Ltd
   i:C = SE, ST = Some-State, O = Internet Widgits Pty Ltd
---
Server certificate
-----BEGIN CERTIFICATE-----
 ... certificate ...
-----END CERTIFICATE-----
subject=C = SE, ST = Some-State, O = Internet Widgits Pty Ltd

issuer=C = SE, ST = Some-State, O = Internet Widgits Pty Ltd

---
No client certificate CA names sent
Peer signing digest: SHA256
Peer signature type: RSA-PSS
Server Temp Key: X25519, 253 bits
---
SSL handshake has read 2272 bytes and written 404 bytes
Verification error: self signed certificate
---
New, TLSv1.2, Cipher is ECDHE-RSA-AES256-GCM-SHA384
Server public key is 4096 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
    Protocol  : TLSv1.2
    Cipher    : ECDHE-RSA-AES256-GCM-SHA384
    ... session stuff ...
    Extended master secret: yes
---
hello server!
this is data
^C

If you use some usual protocol like HTTP, you should use a library though. Here is a example with flask:

>>> from flask import Flask
>>> app = Flask(__name__)
>>> 
>>> @app.route("/")
... def hello():
...     return "Hello World!"
... 
>>> if __name__ == "__main__":
...     app.run(ssl_context=('cert.pem', 'key.pem'))
... 
 * Serving Flask app "__main__" (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: off
 * Running on https://127.0.0.1:5000/ (Press CTRL+C to quit)
127.0.0.1 - - [06/Aug/2020 11:45:50] "GET / HTTP/1.1" 200 -
๐ŸŒ
GitHub
gist.github.com โ€บ oborichkin โ€บ d8d0c7823fd6db3abeb25f69352a5299
Simple TLS client and server on python ยท GitHub
Giving the code, if a client disconnected, the server side will exit. I do not want the server side pgm ended abnormally. ... Quite concerning that this gist is so popular for some reason. It's remarkably bad. from tls_server import HOST as SERVER_HOST from tls_server import PORT as SERVER_PORT
๐ŸŒ
PyPI
pypi.org โ€บ project โ€บ async-tls-client
Python-TLS-Client-Async
Asyncio-first TLS client for Python with advanced fingerprinting capabilities.
      ยป pip install async-tls-client
    
Published ย  Mar 23, 2026
Version ย  2.2.0
Find elsewhere
๐ŸŒ
Docker
docker-py.readthedocs.io โ€บ en โ€บ stable โ€บ tls.html
Using TLS โ€” Docker SDK for Python 7.1.0 documentation
tls_config = docker.tls.TLSConfig(ca_cert='/path/to/ca.pem', verify=True) client = docker.DockerClient(base_url='<https_url>', tls=tls_config)
๐ŸŒ
GitHub
github.com โ€บ florianregaz โ€บ python-tls-client
GitHub - FlorianREGAZ/Python-Tls-Client: Advanced HTTP Library
Python-TLS-Client is an advanced HTTP library based on requests and tls-client.
Starred by 785 users
Forked by 161 users
Languages ย  Python 99.9% | Batchfile 0.1% | Python 99.9% | Batchfile 0.1%
๐ŸŒ
GitHub
github.com โ€บ arthurazs โ€บ python-tls
GitHub - arthurazs/python-tls: Simple TLS connection example ยท GitHub
user@pc:~$ cd python-tls user@pc:~/python-tls$ openssl req -new -x509 -days 365 -nodes -out cert.pem -keyout key.pem -subj "/C=BR/ST=Rio de Janeiro/L=Niteroi/O=UFF/OU=Midiacom/CN=example.org/emailAddress=arthurazs@midiacom.uff.br" The first command changes the directory to the downloaded repository, the second command generates the certificate and private key. ... Warning If you change the CN value, you have to change the hostname under client.py to reflect the new hostname.
Starred by 14 users
Forked by 14 users
Languages ย  Python
๐ŸŒ
Thewebscraping
thewebscraping.github.io โ€บ tls-requests
Wrapper TLS Requests
A powerful and lightweight Python library for making secure and reliable HTTP/TLS fingerprint requests.
๐ŸŒ
Python
peps.python.org โ€บ pep-0748
PEP 748 โ€“ A Unified TLS API for Python | peps.python.org
June 27, 2024 - For the sake of simplicity, this PEP proposes to remove interfaces (3) and (4), and replace them by a simpler interface that returns a socket which ensures that all communication through the socket is protected by TLS. In other words, this interface treats concepts such as socket initialization, the TLS handshake, Server Name Indication (SNI), etc., as an atomic part of creating a client or server connection.
๐ŸŒ
Snyk
snyk.io โ€บ blog โ€บ implementing-tls-ssl-python
Implementing TLS/SSL in Python | Snyk
October 16, 2022 - We use the Python SSL library to provide TLS encryption in socket-based communication between Python clients and servers. It uses cryptography and message digests to secure data and detect alteration attempts in the network.
๐ŸŒ
Electricmonk
electricmonk.nl โ€บ log โ€บ 2018 โ€บ 06 โ€บ 02 โ€บ ssl-tls-client-certificate-verification-with-python-v3-4-sslcontext
SSL/TLS client certificate verification with Python v3.4+ SSLContext | Electricmonk.nl weblog
June 2, 2018 - # Client ssl.wrap_socket(s, ca_certs="ssl/server.crt", cert_reqs=ssl.CERT_REQUIRED, certfile="ssl/client.crt", keyfile="ssl/client.key") # Server ssl.wrap_socket(connection, server_side=True, certfile="ssl/server.crt", keyfile="ssl/server.key", ca_certs="ssl/client.crt") Since Python v3.4, the more secure, and thus preferred method of wrapping a socket in the SSL/TLS layer is to create an SSLContext instance and call SSLContext.wrap_socket().
๐ŸŒ
Python
peps.python.org โ€บ pep-0543
PEP 543 โ€“ A Unified TLS API for Python | peps.python.org
The ``callback`` function will be called with three arguments: the first will be the ``TLSBufferObject`` for the connection; the second will be a string that represents the server name that the client is intending to communicate (or ``None`` if the TLS Client Hello does not contain a server name); and the third argument will be the original ``TLSConfiguration`` that configured the connection.
๐ŸŒ
A Security Site
asecuritysite.com โ€บ subjects โ€บ chapter107
Client/server with SSL
Next we will create a server which will listen on Port 443, and support two cipher suites ('AES256+ECDH:AES256+EDH'): ยท Now we will create the client to connect on Port 443. As we have a self-signed certificate, we will disable the checking of the host and certificate (remember to change the ...
๐ŸŒ
Faircom
docs.faircom.com โ€บ docs โ€บ en โ€บ UUID-cb67a0f7-170b-352a-39eb-3307a423b7d4.html
TLS in Python for MQTT
mqtts_client = mqtt.Client( client_id = "MQTTS Client ID" ) Enable TLS by calling tls_set() on the newly created client using the following code:
๐ŸŒ
Readthedocs
tls.readthedocs.io โ€บ en โ€บ latest โ€บ tls-api.html
Python TLS API โ€” TLS 0.0 documentation
Get the server chain to send to the client when the client is using Server Name Indication (SNI). Implement this method to invoke the certificate_chain_callback with a collection of certificates with ONE leaf certificate that MUST have a private key. None may be passed to the certificate_chain_callback in case no certificates can be found, in which case a TLS Alert will be sent.
๐ŸŒ
Faircom
docs.faircom.com โ€บ docs โ€บ en โ€บ UUID-86e5166d-4c7b-d89c-a516-956a4c27e8d1.html
TLS in Python for JSON DB API - FairCom Documentation
A tuple should be passed to this parameter, where the first element is the client certificate and the second is the client private key file. If you do not already have a JSON DB API project, establish a TLS connection by making the following update to this code.