TLS / SSL HANDSHAKE SCRIPTS

Secures a TLSv2 connection using self-signed certificates, has support for client validation. Pretty useful for CTFs involving servers and certificate debugging.

To generate a key and certificate:


openssl req -x509 -newkey -nodes rsa:2048 rootca.key -days 20000 -out rootca.crt
                        

Make sure to specify a valid common name when filling the form, it must match the hostname specified in the client's SNI.

Server:


#!/usr/bin/python3

import socket
import ssl


# To generate self-signed certificates:
# openssl req -x509 -newkey -nodes rsa:2048 rootca.key -days 20000 -out rootca.crt
# Make sure to give the server's certificate a valid common name (must be the same
# value the client specifies as the SNI).

LISTEN_ADDR = "localhost"
LISTEN_PORT = 7777
SERVER_CERT = "crt/localhost.crt"
SERVER_KEY = "crt/localhost.key"
CLIENT_CERT = "crt/user.crt"

# Specify that we want to validate the client's cert
# context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)

# Uncomment to require clients to provide a certificate as well
# context.verify_mode = ssl.CERT_REQUIRED
# context.load_verify_locations(cafile=CLIENT_CERT)

context.load_cert_chain(certfile=SERVER_CERT, keyfile=SERVER_KEY)

bindsocket = socket.socket()
bindsocket.bind((LISTEN_ADDR, LISTEN_PORT))
bindsocket.listen(5)

print("Server started, listening on {}:{} ".format(LISTEN_ADDR, LISTEN_PORT))

if __name__ == "__main__":
    while True:
        clientSocket, addr = bindsocket.accept()
        print("Client {}:{} connected ".format(addr[0], addr[1]))
        connection = context.wrap_socket(clientSocket, server_side=True)

        print("Secure connection established. Cert: {}".format(
            connection.getpeercert()))

        recvBuffer = (b"")

        try:
            while True:
                recvData = connection.recv(4094)
                if recvData:
                    recvBuffer += recvData
                else:
                    print("Received: {}".format(recvBuffer))
                    break
        finally:
            print("Closing connection")
            connection.shutdown(socket.SHUT_RDWR)
            connection.close()
                        

Client:


#!/usr/bin/python3

import socket
import ssl

SERVER_PORT = 7777
SERVER_ADDR = "localhost"
SERVER_SNI = "localhost"
SERVER_CERT = "crt/localhost.crt"
CLIENT_CERT = "crt/user.crt"
CLIENT_KEY = "crt/user.key"

# Create an openssl context with safe defaults
context = ssl.create_default_context(
    ssl.Purpose.SERVER_AUTH, cafile=SERVER_CERT)

# Uncomment to provide the server with a certificate as well
# context.load_cert_chain(certfile=CLIENT_CERT, keyfile=CLIENT_KEY)

socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# Wrap the generic TCP_IP socket in a valid SSL
connection = context.wrap_socket(
    socket, server_side=False, server_hostname=SERVER_SNI)
connection.connect((SERVER_ADDR, SERVER_PORT))

print("SSL Connection established. Cert: {}".format(connection.getpeercert()))
connection.send(b"test")

connection.close()

                        
Example usage, note that the client works on any tls configured server.
Wireshark packet capture shows the handshake process in detail

Do note that the client can decode the certificate of any SSL server, not just the provided example.