Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save helios2k6/fca17460de863ad3ef154c365dd932a0 to your computer and use it in GitHub Desktop.
Save helios2k6/fca17460de863ad3ef154c365dd932a0 to your computer and use it in GitHub Desktop.
Self Signed Certificate with Custom Root CA

Create Root CA (Done once)

Create Root Key

Attention: this is the key used to sign the certificate requests, anyone holding this can sign certificates on your behalf. So keep it in a safe place!

openssl ecparam -genkey -name prime256v1 -noout -out <ROOT_CA_KEY>

Create and self sign the Root Certificate

Method A: Interactive

openssl req -x509 -new -nodes -key <ROOT_CA_KEY> -sha256 -days 1024 -out <ROOT_CA_CERT>

Be sure to set the following traits:

  1. Country (C) = US
  2. State (ST) = Illinois
  3. Locality (L) = Chicago
  4. Organization (O) = Circle Quant Inc.
  5. Organizational Unit (OU) = Engineering
  6. Common Name (CN) = circlequant
  7. Email Address = engineering@circlequant.com

Method B: One-Liner

openssl \
    req \
    -x509 \
    -new \
    -nodes \
    -key <ROOT_CA_KEY> \
    -sha256 \
    -days 3652 \
    -subj "/C=<YOUR COUNTRY>/ST=<YOUR STATE>/L=<YOUR CITY>/O=<YOUR COMPANY NAME>/OU=<YOUR TEAM NAME>/CN=<YOUR DOMAIN NAME>" \
    -out <ROOT_CA_CERT>

Here we used our root key to create the root certificate that needs to be distributed in all the computers that have to trust us.

Create a certificate (Done for each server)

This procedure needs to be followed for each server/appliance that needs a trusted certificate from our CA

Create the certificate key

openssl ecparam -name prime256v1 -genkey -noout -out <SERVER_PRIVATE_KEY>

Create the signing (csr)

The certificate signing request is where you specify the details for the certificate you want to generate. This request will be processed by the owner of the Root key (you in this case since you create it earlier) to generate the certificate.

Important: Please mind that while creating the signing request, it is important to specify the Common Name providing the IP address or domain name for the service, otherwise the certificate cannot be verified.

Method A (Interactive)

If you generate the csr in this way, openssl will ask you questions about the certificate to generate like the organization details and the Common Name (CN) that is the web address you are creating the certificate for, e.g mydomain.com.

openssl req -new -key <SERVER_PRIVATE_KEY> -out <SERVER_CERT_REQUEST>

Method B (One Liner)

This method generates the same output as Method A but it's suitable for use in your automation :) .

openssl req \
    -new \
    -sha256 \
    -key <SERVER_PRIVATE_KEY> \
    -subj "/C=<YOUR COUNTRY>/ST=<YOUR STATE>/L=<YOUR CITY>/O=<YOUR COMPANY NAME>/OU=<YOUR TEAM NAME>/CN=<YOUR DOMAIN NAME>" -reqexts SAN -config <(cat /etc/ssl/openssl.cnf <(printf "\n[SAN]\nsubjectAltName=DNS:YOUR_DOMAIN_NAME")) \
    -out <SERVER_CERT_REQUEST>

If you need to pass additional config you can use the -config parameter, here for example I want to add alternative names to my certificate.

openssl req -new -sha256 \
    -key <SERVER_PRIVATE_KEY> \
    -subj "/C=<YOUR COUNTRY>/ST=<YOUR STATE>/L=<YOUR CITY>/O=<YOUR COMPANY NAME>/OU=<YOUR TEAM NAME>/CN=<YOUR DOMAIN NAME>" \
    -reqexts SAN \
    -config <(cat /etc/ssl/openssl.cnf \
        <(printf "\n[SAN]\nsubjectAltName=DNS:<EXAMPLE_DOMAIN_NAME>,DNS:<EXAMPLE_DOMAIN_NAME>")) \
    -out <SERVER_CERT_REQUEST>

Verify the csr's content

openssl req -in <SERVER_CERT_REQUEST> -noout -text

Generate the certificate using the mydomain csr and key along with the CA Root key

openssl x509 \
    -req \
    -extfile <(printf "subjectAltName=DNS:YOUR_DOMAIN_NAME") \
    -in <SERVER_CERT_REQUEST> \
    -CA <ROOT_CA_CERT> \
    -CAkey <ROOT_CA_CERT_KEY> \
    -CAcreateserial \
    -out <SERVER_CERT> \
    -days 500 \
    -sha256

If you want to make the certificate an intermediate certificate authority, use the following command instead:

openssl x509 \
    -req \
    -extfile <(printf "basicConstraints=CA:TRUE\nsubjectAltName=DNS:<YOUR_DOMAIN_NAME>") \
    -in <SERVER_CERT_REQUEST> \
    -CA <ROOT_CA_CERT> \
    -CAkey <ROOT_CA_CERT_KEY> \
    -CAcreateserial \
    -out <SERVER_CERT> \
    -days 500 \
    -sha256

In general, you can look at the different extension options at: https://www.openssl.org/docs/man1.1.1/man5/x509v3_config.html

Verify the certificate's content

openssl x509 -in <SERVER_CERT> -text -noout

Verify Root CA -> Client CA Relationship

openssl verify -CAfile <ROOT_CA_CERT> -purpose sslclient <INTERMEDIATE_CA_CERT>

ref

Convert a PEM Format to PKS-8

PEM format is the default output format for all keys and certs. To convert to the PKS-8 format (which is needed for Postgresql), run the following command:

openssl pkcs8 -topk8 -inform PEM -outform DER -in filename -out filename -nocrypt

ref: https://stackoverflow.com/questions/8290435/convert-pem-traditional-private-key-to-pkcs8-private-key

Convert Old-School EC-Key PEM Format to PKCS8 That is PEM Encoded

openssl pkcs8 -topk8 -inform PEM -in <filename> -out <filename> -nocrypt
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment