Creating self-signed SSL certificates with OpenSSL

Overview

Intro

This tutorial will walk through the process of creating your own self-signed certificate. You can use this to secure network communication using the SSL/TLS protocol. For example, to run an HTTPS server. If you don't need self-signed certificates and want trusted signed certificates, check out my LetsEncrypt SSL Tutorial for a walkthrough of how to get free signed certificates.

Self-signed certificates are convenient when developing locally, but I don't recommend them for production environments. If you want to run a public website, getting a trusted signed certificate can be a better option. With a self-signed certificate, users will get a warning on their first visit to your site that is using an untrusted certificate. You can purchase one from somewhere like GoDaddy or you can get a free certificate with Let's Encrypt. If you just need a self-signed cert for personal use or testing, continue and learn how to sign your own certificate.

OpenSSL is the tool used in this tutorial. Learn more about OpenSSL at https://www.openssl.org/.

The two important files you will need when this is all done is the private key file and the signed certificate file. Those two files are required when setting up an SSL/TLS server. The private key should always be kept secret.

Generating a self signed certificate consists of a few steps:

If you already have a private key, you could skip the first step. Next, we will look at the commands to perform each action individually. At the end, we will see one command that can do everything in a single step.

Checking if OpenSSL is already installed

You will need openssl installed to run these commands. To check if it's installed already try this in your command prompt:

openssl version

If you get a version number then you have it installed. If you get an error saying unrecognized command, you will need to install it. Mac computers should already have it installed, but you could use brew to install a newer version.

Installing OpenSSL in Linux

Chances are openssl is already installed in Linux. If not, you can install it using your distributions package manager. For example like this in Debian/Ubuntu based distributions:

sudo apt-get install openssl

You can also download the source from https://www.openssl.org/.

Installing OpenSSL in Windows

For Windows, check out http://gnuwin32.sourceforge.net/packages/openssl.htm to download the GPG binaries. You might need to update your PATH environment variable to point to the new openssl/bin directory, if you get a message about openssl not being a recognized command.

If you get an error regarding the config file when running openssl on Windows like this:

Unable to load config info from /usr/local/ssl/openssl.cnf

Then you will need to set the environment variable OPENSSL_CONF to the path of the default (or your own custom) openssl.cnf file. If you installed openssl to C:\opt\openssl then you would set it like this:

set OPENSSL_CONF=C:\opt\openssl\share\openssl.cnf

Generate a private RSA key

You can generate your private key with or without a passphrase to protect it. You only need to choose one of these options. This will generate a 2048-bit RSA private key.

# Generate 2048 bit RSA private key (no passphrase)
openssl genrsa -out privkey.pem 2048

# To add a passphrase when generating the private key
# include a cipher flag like -aes256 or -des3
openssl genrsa -aes256 -out privkey.pem 2048

Generate certificate signing request (CSR) with the key

Using the private key generated in the previous step, we need to create a certificate signing request. You can generate the certificate signing request with an interactive prompt or by providing the extra certificate information in the command line arguments. You only need to choose one of these options.

# Generate certificate signing request (CSR)
openssl req -new -key privkey.pem -out signreq.csr

# To avoid the interactive prompt and fill out the information in the command, you can add this
openssl req -new -key privkey.pem -out signreq.csr -subj "/C=US/ST=NRW/L=Earth/O=CompanyName/OU=IT/CN=www.example.com/[email protected]"

Sign the certificate signing request with the key

The last step in the process is to sign the request using a private key. In this example we are signing the certificate request with the same key that was used to create it. That's why it earns the name "self-signed".

# Sign the certificate signing request
openssl x509 -req -days 365 -in signreq.csr -signkey privkey.pem -out certificate.pem

View certificate details

To view the details of a certificate and verify the information, you can use the following command:

# Review a certificate
openssl x509 -text -noout -in certificate.pem

Removing a passphrase from a private key

If you have a private key that is protected with a passphrase and you want to create a copy that has no passphrase on it, you can do it like this:

# If a private key has a passphrase, remove it.
# Will be prompted to enter the passphrase
openssl rsa -in server.key -out server-nopassphrase.key

Single command to generate a key and certificate

Earlier we covered the steps involved with creating a self-signed cert: generating a key, creating a certificate signing request, and signing the request with the same key. It is important to understand that process, but there is a more convenient way achieve the same goal in one step without creating the intermediary certificate signing request file.

openssl req -newkey rsa:2048 -nodes -keyout privkey.pem -x509 -days 36500 -out certificate.pem

If you want to passphrase the private key generated in the command above, omit the -nodes (read: "no DES") so it will not ask for a passphrase to encrypt the key.

Just like before, you can add the subject information to the certificate in the command and avoid the interactive prompt.

openssl req -newkey rsa:2048 -nodes -keyout privkey.pem -x509 -days 36500 -out certificate.pem -subj "/C=US/ST=NRW/L=Earth/O=CompanyName/OU=IT/CN=www.example.com/[email protected]"
# Same thing but in different formatting
openssl \
  req \
  -newkey rsa:2048 -nodes \
  -keyout privkey.pem \
  -x509 -days 36500 -out certificate.pem \
  -subj "/C=US/ST=NRW/L=Earth/O=CompanyName/OU=IT/CN=www.example.com/[email protected]"

Python script to run HTTPS server

The code below demonstrates how to run a simple HTTPS server using the key and certificate you just created. Running the script will start up a web server that serves your current directory. Use curl or a web browser to

If you want to learn how to work with cryptography and certificates with Go, check out my book Security with Go. It dedicates an entire chapter to hashing, symettric and asymmetric encryption, certificates, and practical applications. Modify the settings at the top before running.

#!/usr/bin/python
# Sets up an HTTPS server that serves directory contents
import sys
import ssl

# Settings
listen_target = ('localhost', 9999)  # https://localhost:9999/
certificate_file = './certificate.pem'
private_key_file = './privkey.pem'

# Python 3 version
if sys.version_info[0] == 3:
    import http.server
    httpd = http.server.HTTPServer(listen_target, http.server.SimpleHTTPRequestHandler)
# Python 2 version
elif sys.version_info[0] == 2:
    import BaseHTTPServer, SimpleHTTPServer
    httpd = BaseHTTPServer.HTTPServer(listen_target, SimpleHTTPServer.SimpleHTTPRequestHandler)

# Wrap the socket with SSL
httpd.socket = ssl.wrap_socket(httpd.socket,
               certfile=certificate_file, keyfile=private_key_file, server_side=True)

# Start listening
httpd.serve_forever()