72

I would like to set up my own OCSP Responder for testing purposes, and this requires me to have a Root certificate with a few certificates generated from it.

I've managed to create a self-signed certificate using openssl, and I want to use it as the Root certificate. The next step would be to create the derived certificates, however, I can't seem to find the documentation on how to do this. Does anyone know where I can find this information?

  • Edit:
    In retrospect, my question is not yet completely answered, and to clarify the problem, I'll represent my certificate chain like this: Root > A > B > C > ...

I am currently able to create the Root and A certificates via the below, but I haven't found how to make a longer chain:

# Root certificate is created like this:
  openssl req -new -newkey rsa:1024 -nodes -out ca.csr -keyout ca.key
  openssl x509 -trustout -signkey ca.key -days 365 -req -in ca.csr -out ca.pem

# Certificate A is created like this:
  openssl genrsa -out client.key 1024
  openssl req -new -key client.key -out client.csr
  openssl ca -in client.csr -out client.cer
  • This command implicitly depends on the root certificate, for which it finds the required info within the OpenSSL configuration file, however, certificate B must only rely on A, which is not registered in the config file, so the previous command won't work here.

What command should I use to create certificates B and beyond?

  • Edit:
    I found the answer in this article: Certificate B (chain A -> B) can be created with these two commands and this approach seems to be working well.:

    # Create a certificate request
    openssl req -new -keyout B.key -out B.request -days 365
    
    # Create and sign the certificate
    openssl ca -policy policy_anything -keyfile A.key -cert A.pem -out B.pem -infiles B.request
    

    I also changed the openssl.cnf file:

    [ usr_cert ]
    basicConstraints=CA:TRUE # prev value was FALSE
    
3
34

You can use OpenSSL directly.

  1. Create a Certificate Authority private key (this is your most important key):

    openssl req -new -newkey rsa:1024 -nodes -out ca.csr -keyout ca.key
    
  2. Create your CA self-signed certificate:

    openssl x509 -trustout -signkey ca.key -days 365 -req -in ca.csr -out ca.pem
    
  3. Issue a client certificate by first generating the key, then request (or use one provided by external system) then sign the certificate using private key of your CA:

    openssl genrsa -out client.key 1024
    openssl req -new -key client.key -out client.csr
    openssl ca -in client.csr -out client.cer
    

(You may need to add some options as I am using these commands together with my openssl.conf file. You may need to setup your own .conf file first.)

5
  • Thanks, you instructions worked after some tweaking of my openssl.conf file. – StackedCrooked Apr 1 '10 at 7:59
  • 3
    @twk: note the question has one more step needed for a complete answer -- how to create another certificate that only depends on the certificate created in step 3, but not the root certificate. – quack quixote Apr 7 '10 at 19:08
  • 6
    Fails at last step with "unable to load CA private key"; I can get partway there by supplying the key and cert with openssl ca -in client.csr -out client.cer -cern ca.pem -keyfile ca.key, but it wants a demoCA directory and various accouterments. – Iiridayn Jun 28 '17 at 20:28
  • 43
    "You may need to add some options..." really removes the utility from this answer. – Zach Feb 8 '18 at 18:52
  • To complete the last step (from the response below) openssl x509 -req -days 365 -in client.csr -CA ca.pem -CAkey ca.key -set_serial 01 -out client.cer – Tadhg Jan 8 at 1:52
24

Once you have created your CA, you can use it to sign certs:

  • Create a key:
    openssl genrsa -out key_A.key  1024
    
  • Create a CSR:
    openssl req -new -key key_A.key -out csr_A.csr
      # You are about to be asked to enter information etc....
    
  • Sign it:
    openssl x509 -req -days 365 -in csr_A.csr -CA CA_certificate_you_created.crt \
    -CAkey CA_key_you_created.key -set_serial 01 -out crt_A.crt
    
    And so on, replacing A with B, CA_certificate_you_created.crt with crt_A.crt, and CA_key_you_created.key with key_A.key

Changing the below means that the certificates you issue can be used to sign other certificates:

basicConstraints=CA:TRUE  # prev value was FALSE
2
  • 1
    What .crt file? – MickyD Oct 1 '18 at 5:12
  • Starting from OpenSSL 1.1.1 it's possible to use parameter -addext basicConstraints=CA:TRUE - see stackoverflow.com/a/52806736/2164198 Or parameter -extensions v3_ca which refers to a standard extension from openssl.cnf – Ivan Samygin 2 days ago
10

OpenSSL comes with a Perl script CA.pl to help you create a self-signed root CA cert, along with the matching private key, plus a few simple files and directories to help keep track of any future certs you sign (a.k.a. issue) with that root CA. It also helps you generate other key pairs and certificate signing requests (CSRs) and helps you process those CSRs (that is, issue certs for them), and more.

Note that many products require CA certs to contain a certain attribute marking them as CA certs, or they won't be accepted as valid signers/issuers of other certs. If the self-signed cert you created does not contain that attribute, you might have trouble getting other software to treat it like a valid root CA cert.

If I recall correctly, the syntax goes something like this:

CA.pl -newca    # Create a new root CA  

CA.pl -newreq   # Create a new CSR

CA.pl -sign     # Sign a CSR, creating a cert  

CA.pl -pkcs12   # Turn an issued cert, plus its matching private key and trust chain, 
                # into a .p12 file you can install on another machine    
1
  • 4
    This was helpful. On Ubuntu 14.04 I found the file at /usr/lib/ssl/misc/CA.pl – Colin M Jan 25 '17 at 22:00
5

Summary

Summary of the commands used to create a root CA, an intermediate CA, and a leaf certificate:

openssl genrsa -out root.key 2048
openssl req -new -key root.key -out root.csr -config root_req.config
openssl ca -in root.csr -out root.pem -config root.config -selfsign -extfile ca.ext -days 1095

openssl genrsa -out intermediate.key 2048
openssl req -new -key intermediate.key -out intermediate.csr -config intermediate_req.config
openssl ca -in intermediate.csr -out intermediate.pem -config root.config -extfile ca.ext -days 730

openssl genrsa -out leaf.key 2048
openssl req -new -key leaf.key -out leaf.csr -config leaf_req.config
openssl ca -in leaf.csr -out leaf.pem -config intermediate.config -days 365

openssl verify -x509_strict -CAfile root.pem -untrusted intermediate.pem leaf.pem

These commands rely on some setup which I will describe below. They are a bit of an overkill if you just want a few certs in a chain, which can be done with just the x509 command. These commands will also track your certs in a text database and auto-increment a serial number. I would recommend reading the warnings and bugs section of the openssl ca man page before or after reading this answer.

Directory Structure

We will need the following directory structure before starting.

ca.ext              # the extensions required for a CA certificate for signing certs
intermediate.config # configuration for the intermediate CA
root.config         # configuration for the root CA

leaf_req.config         # configuration for the leaf cert's csr
intermediate_req.config # configuration for the intermediate CA's csr
root_req.config         # configuration for the root CA's csr

intermediate_ca/    # state files specific to the intermediate CA
    index           # a text database of issued certificates
    serial          # an auto-incrementing serial number for issued certificates
root_ca/            # state files specific to the root CA
    index           # a text database of issued certificates
    serial          # an auto-incrementing serial number for issued certificates

If this is a more permanent CA, the following changes are probably a good idea:

  1. Moving each CA's configuration file, private key (generated later), and certificate file (generated later) to the CA's directory. This will require changes to the configuration file.
  2. Creating a subdirectory in the CA's directory for issued certificates. This requires changes to the configuration file
  3. Encrypting the private key
  4. Setting a default number of days for issued certificates in the CA configuration files

Starting Directory Structure File Contents

The contents of each of the files in the directory structure are as follows:

ca.ext

[ default ]
basicConstraints = critical,CA:true     # recommended to be marked critical. required for a ca
keyUsage         = critical,keyCertSign # required to be marked critical. required for signing certs

intermediate.config

[ ca ]
default_ca      = CA_default

[ CA_default]
dir             = ./intermediate_ca   # helper variable pointing to ca specific files
database        = $dir/index          # database of certs generated by the ca
new_certs_dir   = ./                  # one dir up to make the demo easier
certificate     = ./intermediate.pem  # one dir up to make the demo easier
serial          = $dir/serial         # file with incrementing hex serial number for certs
private_key     = ./intermediate.key

policy          = policy_any
email_in_dn     = no                  # recommended
unique_subject  = no                  # recommended for easier certificate rollover
copy_extensions = none                # don't honor the extensions in the csr
default_md      = sha256

[ policy_any ]
countryName            = optional
stateOrProvinceName    = optional
organizationName       = optional
organizationalUnitName = optional
commonName             = supplied

root.config

[ ca ]
default_ca      = CA_default

[ CA_default]
dir             = ./root_ca      # helper variable pointing to ca specific files
database        = $dir/index     # database of certs generated by the ca
new_certs_dir   = ./             # one dir up to make the demo easier
certificate     = ./root.pem     # one dir up to make the demo easier
serial          = $dir/serial    # file with incrementing hex serial number for certs
private_key     = ./root.key

policy          = policy_any
email_in_dn     = no             # recommended
unique_subject  = no             # recommended for easier certificate rollover
copy_extensions = none           # don't honor the extensions in the csr
default_md      = sha256

[ policy_any ]
countryName            = optional
stateOrProvinceName    = optional
organizationName       = optional
organizationalUnitName = optional
commonName             = supplied

leaf_req.config

[ req ]
distinguished_name = req_distinguished_name
prompt             = no

[ req_distinguished_name ]
countryName = US
commonName  = Test Leaf

intermediate_req.config

[ req ]
distinguished_name = req_distinguished_name
prompt             = no

[ req_distinguished_name ]
countryName = US
commonName  = Test Intermediate CA

root_req.config

[ req ]
distinguished_name = req_distinguished_name
prompt             = no

[ req_distinguished_name ]
countryName = US
commonName  = Test Root CA

intermediate_ca/index (empty file). Database of issued certs. Updates automatically

[empty]

intermediate_ca/serial (a single 0 does not work). This file auto-increments

00

root_ca/index (empty file). Database of issued certs. Updates automatically

[empty]

root_ca/serial (a single 0 does not work). This file auto-increments

00

Detailed commands

Now we can run the commands from the start of this answer:

# create the private key for the root CA
openssl genrsa 
    -out root.key # output file
    2048          # bitcount

# create the csr for the root CA
openssl req 
    -new 
    -key root.key           # private key associated with the csr
    -out root.csr           # output file
    -config root_req.config # contains config for generating the csr such as the distinguished name

# create the root CA cert
openssl ca 
    -in root.csr        # csr file
    -out root.pem       # output certificate file
    -config root.config # CA configuration file
    -selfsign           # create a self-signed certificate
    -extfile ca.ext     # extensions that must be present for CAs that sign certificates
    -days 1095          # 3 years

# create the private key for the intermediate CA
openssl genrsa 
    -out intermediate.key # output file
    2048                  # bitcount

# create the csr for the intermediate CA
openssl req 
    -new 
    -key intermediate.key           # private key associated with the csr
    -out intermediate.csr           # output file
    -config intermediate_req.config # contains config for generating the csr such as the distinguished name

# create the intermediate CA cert
openssl ca 
    -in intermediate.csr  # csr file
    -out intermediate.pem # output certificate file
    -config root.config   # CA configuration file (note: root is still issuing)
    -extfile ca.ext       # extensions that must be present for CAs that sign certificates
    -days 730             # 2 years

# create the private key for the leaf certificate
openssl genrsa 
    -out leaf.key # output file
    2048          # bitcount

# create the csr for the leaf certificate
openssl req 
    -new 
    -key leaf.key           # private key associated with the csr
    -out leaf.csr           # output file
    -config leaf_req.config # contains config for generating the csr such as the distinguished name

# create the leaf certificate (note: no ca.ext. this certificate is not a CA)
openssl ca 
    -in leaf.csr                # csr file
    -out leaf.pem               # output certificate file
    -config intermediate.config # CA configuration file (note: intermediate is issuing)
    -days 365                   # 1 year

# verify the certificate chain
openssl verify 
    -x509_strict                # strict adherence to rules
    -CAfile root.pem            # root certificate
    -untrusted intermediate.pem # file with all intermediates
    leaf.pem                    # leaf certificate to verify

Final thoughts

If you're looking to use a CA in production, please read the warnings and bugs sections of the openssl ca man page (or just the whole man page).

2
  • 2
    I may write another answer for openssl x509. The configuration files are shorter and there aren't any database / serial files, so it's easier for one-off certificate chain creations – Millie Smith Oct 3 '20 at 21:03
  • Fantastic answer, very detailed and helpful! Thank you – mbrig Oct 5 '20 at 22:12
1

Here's the simplest solution I found.

cert=crt.pem
certPk=pk.pem
ca=ca.crt.pem
caPk=ca.pk.pem

host=example.com
certValidityDays=30

cd "$(mktemp -d)"

# Create CA
openssl req -newkey rsa:4096 -keyout "${caPk}" -x509 -new -nodes -out "${ca}" \
  -subj "/OU=Unknown/O=Unknown/L=Unknown/ST=unknown/C=AU" -days "${certValidityDays}"

# Create Cert Signing Request
openssl req -new -newkey rsa:4096 -nodes -keyout "${certPk}" -out csr.pem \
       -subj "/CN=${host}/OU=Unknown/O=Unknown/L=Unknown/ST=unknown/C=AU" 

# Sign Cert
openssl x509 -req -in csr.pem -CA "${ca}" -CAkey "${caPk}" -CAcreateserial -out "${cert}" \
       -days "${certValidityDays}"
  • Essentially only three commands.
  • I introduced some variables to make the commands easier to understand.
  • What you will need on your webserver are: cert, certPk and ca.
  • caPk is only needed if you want to sign more certs.
  • runs without interaction, so it can be used in batch process.
  • If you want interaction, just leave out the -subj parts.

Some more hints

  • You could run those steps within a standardized debian environment like so:
docker run --rm -it debian:buster-20200327-slim bash
apt update && apt install openssl #=1.1.1d-0+deb10u2
# Run steps above, then `exit` - the certs are stored in a subfolder in your current directory
1

Based on various answers from this question (and related questions and articles) I found a set of commands that allowed me to create a root ca, intermediate ca and test certificate for testing purposes using default openssl config. So I want to post it for myself and for others who's interested in quick solution suitable for testing purposes:

Prerequisite: OpenSSL 1.1.1

  1. Generate CA
openssl req -new -newkey rsa:2048 -nodes -out ca.csr -keyout ca.key -extensions v3_ca
openssl x509 -signkey ca.key -days 365 -req -in ca.csr -set_serial 01 -out ca.crt
  1. Generate Intermediate CA
openssl req -new -newkey rsa:2048 -nodes -out inter.csr -keyout inter.key -addext basicConstraints=CA:TRUE
openssl x509 -CA ca.crt -CAkey ca.key -days 365 -req -in inter.csr -set_serial 02 -out inter.crt
  1. Generate request for target certificate.
openssl req -new -newkey rsa:2048 -nodes -out test.csr -keyout test.key
  1. Sign the request for target certificate using intermediate CA
openssl x509 -CA inter.crt -CAkey inter.key -days 365 -req -in test.csr -set_serial 03 -out test.crt
  1. Export test certificate with private key and the chain certificates to PFX
openssl pkcs12 -export -out test.pfx -inkey test.key -in test.crt -certfile inter.crt -certfile ca.crt
New contributor
Ivan Samygin is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.
0

I found this post on Stack Overflow and it's for Node.JS, but the script in this GitHub repo uses openssl commands to create a root CA and Domain cert.

Run using:

  • example.com: bash make-root-ca-and-certificates.sh 'example.com'
  • localhost: bash make-root-ca-and-certificates.sh 'localhost'

make-root-ca-and-certificates.sh

#!/bin/bash
FQDN=$1

# make directories to work from
mkdir -p certs/{server,client,ca,tmp}

# Create your very own Root Certificate Authority
openssl genrsa \
  -out certs/ca/my-root-ca.key.pem \
  2048

# Self-sign your Root Certificate Authority
# Since this is private, the details can be as bogus as you like
openssl req \
  -x509 \
  -new \
  -nodes \
  -key certs/ca/my-root-ca.key.pem \
  -days 1024 \
  -out certs/ca/my-root-ca.crt.pem \
  -subj "/C=US/ST=Utah/L=Provo/O=ACME Signing Authority Inc/CN=example.com"

# Create a Device Certificate for each domain,
# such as example.com, *.example.com, awesome.example.com
# NOTE: You MUST match CN to the domain name or ip address you want to use
openssl genrsa \
  -out certs/server/privkey.pem \
  2048

# Create a request from your Device, which your Root CA will sign
openssl req -new \
  -key certs/server/privkey.pem \
  -out certs/tmp/csr.pem \
  -subj "/C=US/ST=Utah/L=Provo/O=ACME Tech Inc/CN=${FQDN}"

# Sign the request from Device with your Root CA
# -CAserial certs/ca/my-root-ca.srl
openssl x509 \
  -req -in certs/tmp/csr.pem \
  -CA certs/ca/my-root-ca.crt.pem \
  -CAkey certs/ca/my-root-ca.key.pem \
  -CAcreateserial \
  -out certs/server/cert.pem \
  -days 500

# Create a public key, for funzies
# see https://gist.github.com/coolaj86/f6f36efce2821dfb046d
openssl rsa \
  -in certs/server/privkey.pem \
  -pubout -out certs/client/pubkey.pem

# Put things in their proper place
rsync -a certs/ca/my-root-ca.crt.pem certs/server/chain.pem
rsync -a certs/ca/my-root-ca.crt.pem certs/client/chain.pem
cat certs/server/cert.pem certs/server/chain.pem > certs/server/fullchain.pem
0

The best answer can be found here - https://www.youtube.com/watch?v=KXi3-3dEb8k

I have modified it to suit needs by making the intermediate certificate's CA basic constraint True:

MyOpenssl.conf:

[ req ]
distinguished_name       = distinguished_name
extensions               = int_ca
req_extensions           = int_ca

[ int_ca ]
basicConstraints         = CA:TRUE

[ distinguished_name ]

#create Root CA
openssl genrsa -out RootCA.key 4096
openssl req -new -x509 -days 1826 -key RootCA.key -out RootCA.pem -subj "/C=US/O=xzy/OU=abc/CN=ROOT-CN"

#create Intermediate CA
openssl genrsa -out IntermediateCA.key 4096
openssl req -new -sha256 -key IntermediateCA.key -nodes -out IntermediateCA.csr -subj "/C=US/O=xyz/OU=abc/CN=INTERIM-CN"
openssl x509 -req -days 1000 -extfile MyOpenssl.conf -extensions int_ca -in IntermediateCA.csr -CA RootCA.pem -CAkey RootCA.key -CAcreateserial -out IntermediateCA.pem

#create EndUser certificates
openssl genrsa -out my_server.key 2048
openssl req -new -key my_server.key -out my_server.csr -subj "/C=US/O=xyz/OU=abc/CN=USER-CN"
openssl x509 -req -in my_server.csr -CA IntermediateCA.pem -CAkey IntermediateCA.key -set_serial 01 -out my_server.pem -days 500 -sha1

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.