Skip to content

Instantly share code, notes, and snippets.

@MarkLeMerise
Last active December 23, 2019 03:08
Show Gist options
  • Save MarkLeMerise/d92c600e149bd35bf7d52f246c12de26 to your computer and use it in GitHub Desktop.
Save MarkLeMerise/d92c600e149bd35bf7d52f246c12de26 to your computer and use it in GitHub Desktop.
Generate Self-Signed TLS Certificate for Local Development

The following steps should (theoretically) only need to be once every few years (until the root CA certificate expires):

  1. Run generate-certificate-authority.sh to generate a root Certificate Authority (CA) certificate. All future app-specific certs can "chain" from this.
  2. This script will prompt you to create a pass phrase for your root CA certificate. Make sure to note this down (maybe in a nearby file; it's okay as plaintext since these are just development certificates) as you'll need it for future app-specific certificate generation.
  3. Tell your OS/browser that it can trust this root CA. For example, on macOS, these certificate has to be added to the system keychain: sudo security add-trusted-cert -d -r trustRoot -k "/Library/Keychains/System.keychain" ca.pem.

Anytime you want to generate an app-specific certificate, run the following steps:

  1. Tweak server.csr.cnf to use your particular domain, even if it's just localhost. Most importantly, the DNS.1 entry in v3.ext must match the CN value in server.csr.cnf.
  2. Run generate-self-signed-certificate.sh to generate a TLS certificate, which will be consumed by your application server.
  3. Update your server's configuration to consume the generated server.crt and server.key file. These can be renamed to your liking.

💡 The v3.ext file will help ensure Chrome recongizes the certificate as valid, specifically because the subjectAltName must be populated.

[req]
default_bits = 2048
prompt = no
default_md = sha256
distinguished_name = dn
[dn]
C=US
ST=California
L=San Francisco
O=Your Fake Cert Authority
OU=Computer Department
emailAddress=me@fake.cert
CN=fake.cert
#!/usr/bin/env bash
openssl genrsa \
-des3 \
-out ./ca.key \
2048
openssl req \
-x509 \
-new \
-nodes \
-key ./ca.key \
-sha256 \
-days 1024 \
-out ./ca.pem \
-config ./ca.cnf
#!/usr/bin/env bash
# Cleanup existing certs if they're hanging around
if [ -f ./server.csr ]; then
sudo rm server.csr
fi
if [ -f ./server.crt ]; then
sudo rm server.crt
fi
if [ -f ./server.key ]; then
sudo rm server.key
fi
sudo openssl \
req -new \
-sha256 \
-nodes \
-out server.csr \
-newkey rsa:2048 \
-keyout server.key \
-config ./server.csr.cnf
# Chrome claims that it won't accept certificates valid longer than 39 months
# But who knows how that's actually counted so be conservative with the -days flag.
sudo openssl x509 \
-req \
-in server.csr \
-CA ./ca.pem \
-CAkey ./ca.key \
-CAcreateserial \
-out server.crt \
-days 500 \
-sha256 \
-extfile ./v3.ext
sudo rm server.csr
[req]
default_bits = 2048
prompt = no
default_md = sha256
distinguished_name = dn
[dn]
C=US
ST=Illinois
L=Chicago
O=Your Company
OU=App Developer
emailAddress=me@app.local
CN=app.local
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName = @alt_names
[alt_names]
DNS.1 = app.local
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment