you can use this command to generate a self-signed certificate

openssl req -new -x509 -days 365 -nodes -out cert.pem -keyout cert.pem

the openssl framework will ask you to enter some information, such as your country, city, etc. just follow the instruction, and you will get a cert.pem file. the output file will have both your RSA private key, with which you can generate your public key, and the certificate. the output file looks like this:

-----BEGIN RSA PRIVATE KEY-----
 # your private key
-----END RSA PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
 # your certificate
-----END CERTIFICATE-----

just load it, and the ssl module will handle the rest for you:

context.load_cert_chain(certfile="cert.pem", keyfile="cert.pem")

btw, there is no "SSLContext" in python2. for guys who are using python2, just assign the pem file when wrapping socket:

newsocket, fromaddr = bindsocket.accept()
connstream = ssl.wrap_socket(newsocket,
                             server_side=True,
                             certfile="cert.pem",
                             keyfile="cert.pem",
                             ssl_version=YOUR CHOICE) 

available ssl version: ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv23. if you have no idea, ssl.PROTOCOL_SSLv23 may be your choice as it provides the most compatibility with other versions.

Answer from Brian on Stack Overflow
🌐
Python
docs.python.org › 3 › library › ssl.html
ssl — TLS/SSL wrapper for socket objects — Python 3.14.4 ...
The curve_name parameter should be a string describing a well-known elliptic curve, for example prime256v1 for a widely supported curve. This setting doesn’t apply to client sockets. You can also use the OP_SINGLE_ECDH_USE option to further improve security. This method is not available if HAS_ECDH is False. Added in version 3.3. ... Vincent Bernat. SSLContext.wrap_socket(sock, server_side=False, do_handshake_on_connect=True, suppress_ragged_eofs=True, server_hostname=None, session=None)¶
🌐
GitHub
gist.github.com › oborichkin › d8d0c7823fd6db3abeb25f69352a5299
Simple TLS client and server on python · GitHub
import socket import ssl HOST = "127.0.0.1" PORT = 40000 if __name__ == "__main__": server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) server = ssl.wrap_socket( server, server_side=True, keyfile="path/to/keyfile", certfile="path/to/certfile" ) server.bind((HOST, PORT)) server.listen(0) while True: connection, client_address = server.accept() while True: data = connection.recv(1024) if not data: break print(f"Received: {data.decode('utf-8')}") ... To avoid getting the deprecation warning and update the code SSLContext method must be used and the unwrapped socket closed as specified at https://pythontic.com/ssl/sslcontext/sslcontext :
🌐
Pythontic
pythontic.com › ssl › sslsocket › introduction
The SSLSocket class in Python | Pythontic.com
The server program validates the common Name, time validity of the certificate before sending any information over the secure connection with the client. The client program makes use of the SSLContext instance to load the CA certificate, client certificate and the corresponding private key. The client creates a stream based socket and wraps it around an SSLSocket instance.
🌐
Markusholtermann
markusholtermann.eu › 2016 › 09 › ssl-all-the-things-in-python
Markus Holtermann — SSL All The Things In Python
And finally you connect to the server. import socket, ssl HOST, PORT = 'example.com', 443 def handle(conn): conn.write(b'GET / HTTP/1.1\n') print(conn.recv().decode()) def main(): sock = socket.socket(socket.AF_INET) context = ssl.create_de...
🌐
GitHub
gist.github.com › ndavison › 6a5d97cb8a9091cffa7a
Python socket HTTPS client connection example · GitHub
#!/usr/bin/env python # coding=utf-8 import fire import logging import re import socket import ssl from urllib.parse import urlparse import cchardet as chardet def socket_http(hostname: str, port: int, path: str, http_version: str, method: str): """ Use socket to connect to hostname:port, send GET request, receive response Args: hostname (_type_): _description_ port (_type_): _description_ path (_type_): _description_ """ logging.info( f'Connecting to {hostname}:{port}, send {method} {path} {http_version} request') client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # connect the client
🌐
Paullockaby
paullockaby.com › posts › 2019 › 03 › python-ssl-socket-server
Python SSL Socket Server - Paul Lockaby
In this case our server identifies itself as “dart.s.uw.edu” and only allows clients that are using that same certificate. (Is this a good idea? Probably not. But I don’t have the infrastructure to maintain lots of certificates for just this purpose. This is effective for me.) What does a client look like to all of this? Super simple. import socket import ssl ctx = ssl.create_default_context() ctx.verify_mode = ssl.CERT_REQUIRED ctx.check_hostname = True ctx.load_verify_locations("/usr/local/ssl/certs/ca-uwca.pem") ctx.load_cert_chain("/usr/local/ssl/certs/dart.s.uw.edu.pem") with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: with ctx.wrap_socket(sock, server_hostname="dart.s.uw.edu") as ssl_sock: ssl_sock.connect(("localhost", 3278)) ssl_sock.sendall(bytes("this is a test\n", "utf-8"))
Find elsewhere
🌐
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 - Normally you’d use a server certificate from a Certificate Authority such as Let’s Encrypt, and would setup your own Certificate Authority so you can sign and revoke client certificates. ... Make sure to enter ‘example.com’ for the Common Name. ... The Common Name for the client certificate doesn’t really matter. ... #!/usr/bin/python3 import socket import ssl host_addr = '127.0.0.1' host_port = 8082 server_sni_hostname = 'example.com' server_cert = 'server.crt' client_cert = 'client.crt' client_key = 'client.key' context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH, cafile=server_cert) context.load_cert_chain(certfile=client_cert, keyfile=client_key) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) conn = context.wrap_socket(s, server_side=False, server_hostname=server_sni_hostname) conn.connect((host_addr, host_port)) print("SSL established.
🌐
GitHub
github.com › xliu59 › SSL-TLS_SOCKET
GitHub - xliu59/SSL-TLS_SOCKET: A basic implementation on SSL/TLS socket on both server and client
python server.py --sslv23 --cacert ./ssl/certificate.pem --cipher ECDHE-RSA-AES256-GCM-SHA384 127.0.0.1 8801 index.html · Note: For the purpose of testing only the connection, on the client-side should not specify certificate file path (but DOES NOT mean this parameter won’t work, its effectiveness can be tested in the next part), otherwise will change to the result of certificate-printing (next part).
Starred by 13 users
Forked by 4 users
Languages   Python 99.1% | HTML 0.9% | Python 99.1% | HTML 0.9%
🌐
A Security Site
asecuritysite.com › subjects › chapter107
Client/server with SSL
Bib: @misc{asecuritysite_19014, title = {Client/server with SSL}, year={2026}, organization = {Asecuritysite.com}, author = {Buchanan, William J}, url = {https://asecuritysite.com/subjects/chapter107}, note={Accessed: April 12, 2026}, howpublished={\url{https://asecuritysite.com/subjects/chapter107}} }
🌐
Blogger
bobthegnome.blogspot.com › 2007 › 08 › making-ssl-connection-in-python.html
Bob's development blog: Making an SSL connection in Python
August 3, 2007 - Basically you just wrap a standard socket with an SSL socket: import socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('localhost', 12345)) sslSocket = socket.ssl(s) print repr(sslSocket.server()) print repr(sslSocket.issuer()) sslSocket.write('Hello secure socket\n') ...
🌐
K-state
faculty.salina.k-state.edu › tim › NPstudy_guide › ssl › ssl.html
8. Topic 5 - SSL — Network Programming Study Guide
SSL was re-worked for Python 3 (available in Python 2.6). The improvements add a new module, ssl, that’s built atop the OpenSSL library. This new module provides more control over the protocol negotiated, the X.509 certificates used, and has better support for writing SSL servers (as opposed to just clients). To use the new module, you must first create a TCP connection in the usual way and then pass it to the ssl.wrap_socket() function.
🌐
YouTube
youtube.com › watch
Python Client and Server using sockets with SSL - YouTube
PREREQUISITES:======================================================1. Install OpenSSL2. Create .key, .crt, .pem files 3. Add certificate.crt to the windows ...
Published   March 7, 2022
🌐
Python
docs.python.org › 3.0 › library › ssl.html
ssl — SSL wrapper for socket objects — Python v3.0.1 documentation
In some older versions of OpenSSL (for instance, 0.9.7l on OS X 10.4), an SSLv2 client could not connect to an SSLv23 server. The parameter do_handshake_on_connect specifies whether to do the SSL handshake automatically after doing a socket.connect(), or whether the application program will call it explicitly, by invoking the SSLSocket.do_handshake() method.
Top answer
1 of 2
23

Basically the server need to share with the client his certificate and vice versa (look the ca_certs parameter). The main problem with your code is that the handshake were never executed. Also, the Common Name string position depends on how many field did specified in the certificate. I had been lazy, so my subject has only 4 fiels, and Common Name is the last of them.

Now it works (feel free to ask for further details).

Server

#!/bin/usr/env python
import socket
import ssl
import pprint

#server
if __name__ == '__main__':

    HOST = '127.0.0.1'
    PORT = 1234

    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    server_socket.bind((HOST, PORT))
    server_socket.listen(10)

    client, fromaddr = server_socket.accept()
    secure_sock = ssl.wrap_socket(client, server_side=True, ca_certs = "client.pem", certfile="server.pem", keyfile="server.key", cert_reqs=ssl.CERT_REQUIRED,
                           ssl_version=ssl.PROTOCOL_TLSv1_2)

    print repr(secure_sock.getpeername())
    print secure_sock.cipher()
    print pprint.pformat(secure_sock.getpeercert())
    cert = secure_sock.getpeercert()
    print cert

    # verify client
    if not cert or ('commonName', 'test') not in cert['subject'][3]: raise Exception("ERROR")

    try:
        data = secure_sock.read(1024)
        secure_sock.write(data)
    finally:
        secure_sock.close()
        server_socket.close()

Client

import socket
import ssl

# client
if __name__ == '__main__':

    HOST = '127.0.0.1'
    PORT = 1234

    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.setblocking(1);
    sock.connect((HOST, PORT))

    context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
    context.verify_mode = ssl.CERT_REQUIRED
    context.load_verify_locations('server.pem')
    context.load_cert_chain(certfile="client.pem", keyfile="client.key")

    if ssl.HAS_SNI:
        secure_sock = context.wrap_socket(sock, server_side=False, server_hostname=HOST)
    else:
        secure_sock = context.wrap_socket(sock, server_side=False)

    cert = secure_sock.getpeercert()
    print cert

    # verify server
    if not cert or ('commonName', 'test') not in cert['subject'][3]: raise Exception("ERROR")

    secure_sock.write('hello')
    print secure_sock.read(1024)

    secure_sock.close()
    sock.close()

Take a look:

Ps: I made the client print the server response.

Response to comments

On client's side you never used the context variable I've created. Does it mean it's unnecessary here?

Documentation says:

For more sophisticated applications, the ssl.SSLContext class helps manage settings and certificates, which can then be inherited by SSL sockets created through the SSLContext.wrap_socket() method.

I've updated the code to show you the differences: the server uses ssl.wrap_socket(), the client ssl.SSLContext.wrap_socket().

Second, what's the point in checking if ssl.HAS_SNI when the socket creation looks the same in if and else? With your approach I cant use server_hostname=HOST in socket wrapping method.

You are right, in the updated code I used server_hostname=HOST.

Another thing: you're using ca_certs instead of using load_verify_locations in context I created. Why? Are those 2 methods identical?

My fault, I was using ca_cert as parameter of ssl.wrap_socket(), so I didn't used the context at all. Now I use it.

And another thing: do you really need to call secure_sock.do_handshake() by yourself?

Nope, I forgot to remove it :)

The output is exactly the same.

2 of 2
4

ilario-pierbattista Answer but in python 3:

  • Check print function
  • Check secure_sock.write(b'hello') in bytes
  • Check function argument (config)
def start_client_side(config):
    HOST = config['host']
    PORT = config['port']
    pemServer = config['serverpem']
    keyClient = config['clientkey']
    pemClient = config['clientpem']

    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.setblocking(1);
    sock.connect((HOST, PORT))

    context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
    context.verify_mode = ssl.CERT_REQUIRED
    context.load_verify_locations(pemServer)
    context.load_cert_chain(certfile=pemClient, keyfile=keyClient)

    if ssl.HAS_SNI:
        secure_sock = context.wrap_socket(sock, server_side=False, server_hostname=HOST)
    else:
        secure_sock = context.wrap_socket(sock, server_side=False)

    cert = secure_sock.getpeercert()
    print(pprint.pformat(cert))

    # verify server
    if not cert or ('commonName', 'server.utester.local') not in itertools.chain(*cert['subject']): raise Exception("ERROR")

    secure_sock.write(b'hello')
    print(secure_sock.read(1024))

    secure_sock.close()
    sock.close()

def start_server_side(config):
    HOST = config['host']
    PORT = config['port']
    pemServer = config['serverpem']
    keyServer = config['serverkey']
    pemClient = config['clientpem']

    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    server_socket.bind((HOST, PORT))
    server_socket.listen(10)

    client, fromaddr = server_socket.accept()
    secure_sock = ssl.wrap_socket(client, server_side=True, ca_certs=pemClient, certfile=pemServer,
                                  keyfile=keyServer, cert_reqs=ssl.CERT_REQUIRED,
                                  ssl_version=ssl.PROTOCOL_TLSv1_2)

    print(repr(secure_sock.getpeername()))
    print(secure_sock.cipher())
    cert = secure_sock.getpeercert()
    print(pprint.pformat(cert))

    # verify client
    if not cert or ('commonName', 'client.utester.local') not in itertools.chain(*cert['subject']): raise Exception("ERROR")

    try:
        data = secure_sock.read(1024)
        secure_sock.write(data)
    finally:
        secure_sock.close()
        server_socket.close()
🌐
Carlo-hamalainen
carlo-hamalainen.net › 2013 › 01 › 24 › python-ssl-socket-echo-test-with-self-signed-certificate
Python SSL socket echo test with self-signed certificate · Carlo Hämäläinen
January 24, 2013 - import socket, ssl bindsocket = socket.socket() bindsocket.bind(('', 10023)) bindsocket.listen(5) def do_something(connstream, data): print "do_something:", data return False def deal_with_client(connstream): data = connstream.read() while data: if not do_something(connstream, data): break data = connstream.read() while True: newsocket, fromaddr = bindsocket.accept() connstream = ssl.wrap_socket(newsocket, server_side=True, certfile="server.crt", keyfile="server.key") try: deal_with_client(connstream) finally: connstream.shutdown(socket.SHUT_RDWR) connstream.close() Note: if you try to use the
🌐
Linux Hint
linuxhint.com › python-ssl-example
Python SSL Example
Linux Hint LLC, [email protected] 1210 Kelly Park Circle, Morgan Hill, CA 95037 Privacy Policy and Terms of Use
🌐
Python.org
discuss.python.org › python help
Handshake ( Server Hello ) - Python Help - Discussions on Python.org
May 25, 2023 - If I can help, below is an example: import socket import ssl # Create a TCP/IP socket sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # Bind the socket to port 443 sock.bind(("localhost", 443)) # Listen for connections sock.listen(1) ...
🌐
Python
docs.python.org › 3.9 › library › ssl.html
ssl — TLS/SSL wrapper for socket objects — Python 3.9.24 documentation
The curve_name parameter should be a string describing a well-known elliptic curve, for example prime256v1 for a widely supported curve. This setting doesn’t apply to client sockets. You can also use the OP_SINGLE_ECDH_USE option to further improve security. This method is not available if HAS_ECDH is False. New in version 3.3. ... Vincent Bernat. SSLContext.wrap_socket(sock, server_side=False, do_handshake_on_connect=True, suppress_ragged_eofs=True, server_hostname=None, session=None)¶