Jamie’s Discourse

OpenSSL Certificate Authority


Thanks for the great guide. It is perfect.
Is there a PDF or single file version?

Also, in my system I have added the following extension for code signing:

[ codesign_cert ]
# Extensions for code sign certificates
basicConstraints = CA:FALSE
nsCertType = client, email, objsign
subjectKeyIdentifier = hash
keyUsage = digitalSignature
extendedKeyUsage = codeSigning, msCodeInd, msCodeCom

I think nsCertType could be only “objsign” but I’m not sure.
Has someone more information about this?


I’m also getting this error on macOS 10.12.6 and a fresh build of openssl 1.1.0f.

The only difference is I’m using ~/root instead of /root.

Any help appreciated.

I think you need to specify the absolute path.
eg, dir = /Users/paul_adams/root

Did you have any luck getting this to work without the browser error?

I kept getting NET::ERR_CERT_COMMON_NAME_INVALID in Chrome, because it now requires Subject Alternative Names in the certificate. I patched the intermediate’s openssl.cnf from the Appendix with some help from an article by James Young. Of course, the reader will have to update the alt_names section before requesting/signing.

--- .bak.1.openssl.cnf	2017-09-11 19:03:02.422328200 -0400
+++ openssl.cnf	2017-09-11 19:41:39.324328200 -0400
@@ -67,6 +67,19 @@
 # Extension to add when the -x509 option is used.
 x509_extensions     = v3_ca
+# Need Subject Alternative Name for RFC 2818 / Chrome
+req_extensions = v3_req
+[ v3_req ]
+basicConstraints = CA:FALSE
+keyUsage = nonRepudiation, digitalSignature, keyEncipherment
+subjectAltName = @alt_names
+DNS.1 = server1.example.com
+DNS.2 = server2.example.com
+DNS.3 = server3.example.com
 [ req_distinguished_name ]
 # See <https://en.wikipedia.org/wiki/Certificate_signing_request>.
 countryName                     = Country Name (2 letter code)
@@ -118,6 +131,7 @@
 authorityKeyIdentifier = keyid,issuer:always
 keyUsage = critical, digitalSignature, keyEncipherment
 extendedKeyUsage = serverAuth
+subjectAltName = @alt_names
 [ crl_ext ]
 # Extension for CRLs (`man x509v3_config`).

Excellent article. But I do miss what file to use as certificate authority in Firefox and how to configure Apache if you use mod_gnutls.

After some trail and error found out that the solution is very simple:

cd /root/ca/intermediate/certs
cat intermediate.cert.pem >> yoursecureserver1.cert.pem

This will put the intermediate certificate at the end of your server certificate and gnutls is completely happy with it. You only have to copy yoursecureserver1.cert.pem and yoursercureserver1.key.pem to /etc/httpd (or wherever it is on your system).

And in Apache in your VirtualHost part:

GnuTLSEnable on
GnuTLSPriorities SECURE
GnuTLSCertificateFile /etc/httpd/yoursecureserver1.cert.pem
GnuTLSKeyFile /etc/httpd/yoursecureserver1.key.pem

In Firefox you only have to import the root certificate (from /root/ca/certs).

Fantastic article! Thanks. You mention:

Production ready OCSP responders exist, but those are beyond the scope of this guide

Does anyone know where to find a production-ready OCSP server daemon?

Thank you very much for this tutorial

I hacked a script to automate the process of obtaining certificates for websites, which I would like to share:

#!/usr/bin/env bash


read -p "enter domain name: " DOMAIN;

# Create a key
openssl genrsa -out "$KEYPATH" 2048;
chmod 400 "$KEYPATH";

# Create a certificate signing request
openssl req -config "$IPATH/openssl.cnf" \
      -key "$KEYPATH" \
      -new -sha256 \
      -subj "/CN=$DOMAIN/C=DE" \
      -out "$CSRPATH";

# Create a certificate
openssl ca -config "$IPATH/openssl.cnf" \
      -extensions server_cert -days 375 -notext -md sha256 \
      -in "$CSRPATH" \
      -out "$CRTPATH";
chmod 444 "$CRTPATH";

# Verify the certificate
openssl x509 -noout -text -in "$CRTPATH";

openssl verify -CAfile "$IPATH/certs/ca-chain.cert.pem" "$CRTPATH";

Great post!
I had only trouble displaying latin chars on organizationName field, and I fixed it adding -utf8 when I was creating the private key:

openssl req -config intermediate/openssl.cnf -key intermediate/private/$sitio.key.pem -new -utf8 -sha256 -out intermediate/csr/$sitio.csr.pem

Indeed a great guide! When I modified this for my purposes, I found that the server and user certs were signed by the root cert, not the intermediate. Has anyone else seen the same or is it just me messing things up? I resolved it by creating a separate openssl.cnf for those.


Great documentation, many thanks for that!
For the purpose of a local tool, I had to set a full ssl chain from scratch, and I was only finding little fragments of information with very few explanations, that were so confusing when finally put all together.
Until I found your post, and everything suddenly became extra clear!
Maybe you should just add a little section about how to trust the newly created root certificate. Because at first I was a little confused when I saw the ssl error telling me that there was a self-signed certificate in my chain. Even if I quickly understood why…
Many thanks again for this work!

Great Docs about CA creation. Thanks a lot.

Any chance to have this document also exported to PDF?
Or to put the Source of the docs which are used for sphinx online into a git repo? So any updates or hardening could be added with Pull Requests?

This guide’s comprehensive up to the Deploy the Certificate section, but “You can now either deploy your new certificate to a server, or distribute the certificate to a client. When deploying to a server application (eg, Apache), you need to make the following files available” leaves no clear idea what to do to actually deploy it. Where should those files be avail, etc? Pointers to further resources would be helpful here,

Hello, I need to create Indirect CRL, could you pleas help us by providing the steps to do so.

Great writeup!!! Thanks.

Something caught my eye. In the intermediate configuration file in the appendix you have

[ req ]

x509_extensions = v3_ca

when I expected to see

[ req ]

x509_extensions = v3_intermediate_ca

because of the pathlen:0 attribute only in the latter:


basicContraints = …, pathlen:0

Awesome works, Thanks a lot !

Thank you for great documentation.

I would suggest adding “copy_extensions = copy” to [ CA_default ] at intermediate/openssl.cnf to pass subjectAltName to signed certificate along with CRL.

Adding my thanks and appreciation!

For several years, I maintained a registry of assigned names and numbers for a software development organization: mostly OID’s and SNMP MIB’s. At one point, I prototyped an internal CA and published certificates as well. The registry structure followed Maven/Ivy conventions so that build/integration systems could download these artifacts. I followed this tutorial to set up the CA.

Jamie’s tutorial covers certificate generation but not so much about publication. Similarly, the aspects of provisioning servers and clients are not covered so much. I ran into the sort of problems you find in the comments such as how to bundle up a certificate chain and key for a given server.

I’ve published two GitHub projects covering:

  1. A prototype web site and registry to make certificates generated by a CA publicly available: ranger6/xanna

  2. A set of tools (mostly bash scripts) to standardize and simplify the publication of certificates, generate certificate bundles, etc.: ranger6/ca. This project includes an example workflow of setting up the CA with signing certificates, generating server certificates, publishing to a registry, and fetching certificates/bundles to provision servers. A good part of the workflow (the upstream part) is simply following Jamie’s tutorial.

Advise on all the provisioning gotcha’s are not covered. I mostly played around with Caddy (caddyserver.com).

Everything is free for the taking (MIT License). Comments and pull requests accepted!

First of all this is great article.

When I check certification path from browser, it is showing only intermediate certificate -> server certificate… why it is missing rootca… in certification path… I am expecting to show certification path as rootca-> intermediateca -> server.

A PDF version of https://jamielinux.com/docs/openssl-certificate-authority/index.html would be really handy to be stored together with produced files.