Skip to content

Instantly share code, notes, and snippets.

@marshalhayes
Last active July 3, 2024 12:33
Show Gist options
  • Save marshalhayes/ca9508f97d673b6fb73ba64a67b76ce8 to your computer and use it in GitHub Desktop.
Save marshalhayes/ca9508f97d673b6fb73ba64a67b76ce8 to your computer and use it in GitHub Desktop.
TLS encryption of Python sockets using the "SSL" module

README.md

Follow these steps before trying to run any code.

  1. First, generate a Certificate Authority (CA).

openssl genrsa -out rootCA.key 2048

  1. Second, self-sign it.

openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 365 -out rootCA.pem

  1. Next, install that CA on the system(s) you want to use it on. You'll have to find out how/where to install it for your system.
  2. After that, create a certificate for each device you want to use it for.

openssl genrsa -out device.key 2048

Then, generate a certificate signing request.

openssl req -new -key device.key -out device.csr

Pay careful attention the "Common Name" field. It must be the same as the common name for the CA, even if it's an IP address.

  1. Then, sign the CSR using the root-CA.

openssl x509 -req -in device.csr -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out device.crt -days 364 -sha256

  1. Finally, install the key and the certificate in your device(s).

References

import ssl
import socket
if __name__ == "__main__":
# Create a context, just like as for the server
context = ssl.create_default_context()
# Load the server's CA
context.load_verify_locations("/Users/marshalhayes/Projects/BlockchainPKI/rootCA.pem")
# Wrap the socket, just as like in the server.
conn = context.wrap_socket(socket.socket(socket.AF_INET, socket.SOCK_STREAM), server_hostname="localhost")
# Connect and send data! Standard python socket stuff can go here.
conn.connect(("localhost", 1234))
conn.sendall(b"Hello, server! This was encrypted.")
import ssl
import socket
BUFF_SIZE = 1024
if __name__ == "__main__":
# First, create a context. The default settings are probably the best here.
context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
# Load the CA (self-signed, in this case) and the corresponding private key (also self-signed, in this case)
context.load_cert_chain(certfile="/Users/marshalhayes/Projects/BlockchainPKI/rootCA.pem",
keyfile="/Users/marshalhayes/Projects/BlockchainPKI/rootCA.key")
# Create a standard TCP socket, bind it to an address, and listen for connections
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(("localhost", 1234))
s.listen()
# Start accepting incoming connections
accepting = True
try:
while accepting:
# conn is a standard python socket, addr is where it originated
conn, addr = s.accept()
# wrap the standard socket with the SSLContext, now it is a secure connection
with context.wrap_socket(conn, server_side=True) as secure_conn:
# data can be read/sent just like as in standard sockets
data = secure_conn.recv(BUFF_SIZE)
except socket.timeout:
pass
@tanjuntao
Copy link

Great, thanks for your sharing.

@jfh92
Copy link

jfh92 commented Jul 3, 2024

Hi,
Thank you for sharing this information.
I am not clear about the common name field. I populated it with 127.0.0.1 in both the root certificate and the device certificate. Both certificates or in the same folder as the python codes for the server and the client. The keys are also in the same folder. I run this code in Windows but the common name I selected does not seem to work. Any information as to what I did wrong would be appreciated.
Thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment