Creating Self-Signed Certificates Using OpenSSL

    Background

    Self-signed certificates are useful for testing as well as some limited real-world use-cases. The instructions below cover commands necessary to create self-signed certificates using openssl.

    As as alternative to openssl, there is also the keytool utility included with the JDK that can be used to generate certificates. Refer to these instructions which cover using keytool to generate self-signed certificates instead.

    Terminology

    Whenever cryptography is involved, you can expect to a deluge of terminology about complex concepts. Fully fleshing out these concepts is beyond the scope of this piece, but it would be beneficial to roughly summarize some of the terms as they apply to the operations used further down:

    • Keystore or Truststore – Container file designed to hold cryptographic materials such as keys, certificates, etc.
    • PFX – Effectively an alternate name for PKCS12 files. PFX is usually found within Microsoft contexts as PFX was initially a Microsoft format before it eventually became re-defined by RFC 7292 as PKCS12.
    • Key Pair – A public key and its corresponding private key together are commonly referred to as a “key pair”.
    • Private Key – The secret key of a key pair that should be availble only to the owner or owner programs/processes
    • Public Key – The public key of a key pair that is made available to one or more external parties to encrypt data that can (well…should) only be decrypted by someone with access to the corresponding secret key.
    • Certificate – A file format (typically X.509) that includes a key (commonly a public key) along with other relevant information such as expiration, issuer, etc.

    A Quick Note On Approach

    Several best practices are intentionally not followed in the commands below in order to emphasize the overall mechanics. Things like the keystore password being ‘password’, private key password not being set, and passwords included on the command line should not be followed outside an educational exercise context.

    OpenSSL Instructions

    Here we will create the individual components (the private key and public cert) then package them up after into a PKCS12 file.

    Configure SubjectAltName

    If you create a certificate the way you see on most posts on the Internet, you may find you’ll get warnings from some clients similar to the following from python3:

    SubjectAltNameWarning: Certificate for localhost has no `subjectAltName`, falling back to check for a `commonName` for now. 
    This feature is being removed by major browsers and deprecated by RFC 2818. (See https://github.com/shazow/urllib3/issues/497 for details.)
    

    As the warning indicates there is no subjectAltName field in the certificate. To do so requires either modifying the system openssl.cnf (or a copy of it) for OpenSSL pre-1.1.1 or using additional command line options if using OpenSSL 1.1.1 and onwards. OpenSSL 1.1.1 was just released Sept 11 2018 and hasn’t yet made its way into most distributions. The commands below will show the pre-1.1.1 method using a copy of openssl.cnf which should also continue to work when 1.1.1 becomes more widely available.

    Note: Your system’s openssl.cnf can be in several different places, common places to look:

    • /etc/ssl/openssl.cnf
    • /usr/lib/ssl/openssl.cnf
    • /usr/local/ssl/openssl.cnf
    • /usr/local/etc/openssl.cnf
    • /System/Library/OpenSSL/openssl.cnf (OSX)
    • /etc/pki/tls/openssl.cnf (RHEL)

    Prepare local openssl.cnf

    1. Make a local copy of the system openssl.cnf:
      cp /path/to/openssl.cnf openssl.cnf.tmp
    2. Add subjectAltName entry in copy:
      echo -e "[SAN]\nsubjectAltName=DNS:localhost\n" >> openssl.cnf.tmp

    Create certificate and key

    openssl req \
           -newkey rsa:4096 \
           -sha256 \
           -x509 \
           -days 3650 \
           -nodes \
           -subj "/C=C8/ST=ST/L=L/O=O/OU=OU/CN=localhost/[email protected]" \
           -keyout server.private.key \
           -config openssl.cnf.tmp \
           -extensions SAN \
           -out server.public.crt
    

    If you get the following error:

    problems making Certificate Request
    139634576708864:error:0D07A098:asn1 encoding routines:ASN1_mbstring_ncopy:string too short:../crypto/asn1/a_mbstr.c:102:minsize=2
    

    This indicates that one of the fields in the -subj text is either empty or too short

    Assemble the PKCS12 container

    openssl pkcs12 \
      -export \
      -inkey server.private.key \
      -in server.public.crt \
      -passout pass:password \
      -out server.p12
    

    (Optional) Examine the keystore

    openssl pkcs12 \
      -nokeys \
      -info \
      -in server.p12 \
      -passin pass:password
    

    Testing with OpenSSL

    You can also use openssl to quickly test your new certificate.

    Starting the test server

    The following commands will start the TLS/SSL server bound to TCP port 4430 and instruct it to respond to a simple HTTP GET requests.

    openssl s_server \
      -key server.private.key \
      -cert server.public.crt \
      -accept 4430 \
      -no_dhe \
      -www
    

    Testing client-side with web browser

    Browse to https://localhost:4430 in a browser (you may have to click past warnings). You should see info text provided by test server (ciphers supported, ciphers in common with client, etc)

    Testing client-side on the command line

    1. In a separate teminal window or tab, run: openssl s_client -connect localhost:4430
    2. Followed by: GET / HTTP 1.0
    3. Then the Enter key

    You should see the same HTML used to generate the page for the browser test.