Writing a web application in Python is easily frustrating, but what’s more troublesome is requiring a self-signed certificate for HTTPS. If you’re only using it for yourself then its easy, but if you want to allow anyone on the Internet (or clients) to deploy it, it causes a bit more of a troublesome stir. While it doesn’t take a long time to generate one, not even I really feel like creating a self-signed certificate for an application I have to deploy and test. So, lets make it possible to do it in Python! Required Python 2.7 is used for this. Beyond that, PyOpenSSL (Python’s bindings to the OpenSSL library) is required as well, which installing is out of the scope of this guide (note: use pip install pyopenssl). Some knowledge and/or experience with Python or similar would be nice as I’m not going to explain every aspect of the code, but besides that you should be set! I tested this on Ubuntu 13.04 and had no issues. Code Since I’ve never done an article like this before, going to try something out. I’ll be explaining the Python code that’s necessary to do this. If this isn’t very effective (or if it is for that matter) please leave a post in the comments to let me know. Code: from OpenSSL import crypto, SSL from socket import gethostname from pprint import pprint from time import gmtime, mktime from os.path import exists, join We want to include only specific parts of Python’s various libraries (OpenSSL = PyOpenSSL), which saves us on overhead since Python is an interpreted language. Code: CN = raw_input("Input the hostname of the website the certificate is for: ") CERT_FILE = "%s.crt" % CN KEY_FILE = "%s.key" % CN Since the CN is to match the hostname of the HTTP header, this is part of the dynamic aspect of creating our self-signed certificate. The key and certificate files will also be <CN>.crt/.key. Code: def create_self_signed_cert(cert_dir=”.”): C_F = join(cert_dir, CERT_FILE) K_F = join(cert_dir, KEY_FILE) if not exists(C_F) or not exists(K_F): The start of our method for creating a self-signed certificate. We pass it the directory we want to store our certificate and key (defaults to current directory), and then we specify the full path of the certificate and key file (C_F & K_F), and check if both exists. If one or the other (or both) don’t, then we continue on. Rest of the code will be inside the if block. Code: # create a key pair k = crypto.PKey() k.generate_key(crypto.TYPE_RSA, 1024) Create an instance of generating a key-pair with PyOpenSSL and tell it we want a 1024-bit RSA key pair. Code: # create a self-signed cert cert = crypto.X509() SSL certificates are X-509, so we need a reference to load the appropriate data, which we will manipulate next! Code: cert.get_subject().C = raw_input("Country: ") cert.get_subject().ST = raw_input("State: ") cert.get_subject().L = raw_input("City: ") cert.get_subject().O = raw_input("Organization: ") cert.get_subject().OU = raw_input("Organizational Unit: ") cert.get_subject().CN = CN Similar to using the openssl command to generate a self-signed certificate. Unfortunately there doesn’t seem to be a way (according to documents) on how to parse the OpenSSL configuration file (/etc/ssl/openssl.cnf). So, for now, we have to prompt the user. Code: cert.set_serial_number(1000) Sets the serial number of the certificate. Should be incremented each time the certificate is renewed. Code: cert.gmtime_adj_notBefore(0) States that the certificate is not valid before present time (basically once the certificate is made it shouldn’t be valid prior to that point in time). Code: cert.gmtime_adj_notAfter(315360000) This amounts to 3,650 days and says that the certificate is not valid after 3,650 days after its created. Code: cert.set_issuer(cert.get_subject()) States that the information provided above (where you’re prompted for location information) is the issuer of the certificate. In a self-signed certificate this would state that the person you bought the certificate from is the issuer, but since we made it ourselves we’re the issuer! Code: cert.set_pubkey(k) Remember creating the 1024-bit RSA key? This is how we establish how to encrypt the data. You can pass the key file (.key) for anything that needs to validate a connection to the server, but the certificate (.crt) must remain private. Code: cert.sign(k, 'sha1') Sign the key with the public key using SHA-1 hash. Code: open(C_F, "wt").write( crypto.dump_certificate(crypto.FILETYPE_PEM, cert)) open(K_F, "wt").write( crypto.dump_privatekey(crypto.FILETYPE_PEM, k)) These two lines open up the certificate and key files for writing text to and then we tell OpenSSL to dump the certificate and key information. Getting the Public Key In order to let others authenticate with the self-signed certificate you need to give the public key. But how do we do that? Run this command in the console (assuming same directory where the key file is): Code: openssl rsa -in some.key -pubout -out pubkey.key Replace "some.key" with the name of the key file and give away the pubkey.key file. This way people can authenticate SSL sessions!