jump to content
Snippets and tips
  1. Home
  2. Holiday
  3. Posts
  4. Tools
  5. Tags
  6. Categories

One's own certification authority

Create self signed X.509 certificates for https and similar

The post gives an overview how to create and use X.509 certificates for use in HTTPS and other TLS encrypted endpoints.

One can create root certificates, which then have to be imported into the system. Those root certificates can be used to sign purpose specific certificates. The following post presents all necessary commands to accomplish this.

Basics #

There is symmetric and asymmetric encryption. Symmetric encryption requires the exchange of a common secret – which presents a challenge. Asymmetric encryption employs a public key and a private key – the latter has to be kept a secret. If two parties meet without prior contact, one has to be sure that the other party really is who they claim. This identity verification is the reason for the certificate chain, the public key is signed by someone else, who’s public key again is signed by another– until the root certificate, which needs to be one of the trusted.

In essence, there is a set of trusted root CA. Their certificates are bundled with operating systems and browsers. If one uses a certificate that can be traced back to one of those, then the certificate is accepted.

The certificate mafia #

There are many recommendations how to secure traffic using X.509 certificates, with recipes how to accomplish that. Trying to do that, one quickly realizes that getting certain certificates come with hefty fees, while other more general purpose certificates are impossible to obtain.

In general, being a root certificate authority carries a huge responsiblity, since all certificates down the chain will be trusted. Identity verification and maintenance of the infrastructure is costly. It has become a business for some companies.

Purpose #

Let’s Encrypt offers free certificates that convince users that the used certificate is indeed related to the served domain. But it requires the server to be somewhat reachable from the internet and only offers TLS certificates.

Simple approach - no openssl ca #

The tool openssl offers many routines, among others ca which stands for Certificate Authority.

One needs to do the following:

  1. create a private/public key pair for the root certificate
  2. create the root certificate
  3. create a certificate request for the web certifictate
  4. let the root certificate sign the request
  5. create text versions of all requests and certificates

The following makefile does it all (all indented lines start with a tab character!):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
%.key:
	openssl genpkey -verbose -algorithm rsa -pkeyopt bits:4096 -out $@
%.crt.txt: %.crt
	openssl x509 -in $< -text -out $@
%.csr.txt: %.csr
	openssl req -in $< -text -out $@
root-ca.crt: root-ca.key  root-ca.openssl.cnf
	openssl req -x509 -key root-ca.key -out $@ -days 1826 -sha256 \
	-config root-ca.openssl.cnf
web.csr: web.key web.openssl.cnf
	openssl req -new -key web.key -out $@ -config web.openssl.cnf
web.crt: web.csr root-ca.crt makefile
	openssl x509 -req -in web.csr -CA root-ca.crt -CAkey root-ca.key -CAcreateserial \
	-sha256 -out web.crt -copy_extensions copyall -days 1826 
	cat root-ca.crt >> web.crt

all: web.crt web.crt.txt web.csr.txt root-ca.crt.txt

While it is possible to use ed25519 keys, browsers might not accept it. RSA with 4096 bits is a safe option. Line 9 and 11 reference config files, which have to be supplied.

root-ca.openssl.cnf

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
[req]
default_keyfile     = root-ca.key
distinguished_name  = root_ca
x509_extensions     = v3_ca
prompt              = no
utf8 = yes

[root_ca]
CN = Root Certificate Authority
O  = Private
C  = NO
emailAddress = root-ca@my-domain.dev

[v3_ca]
basicConstraints       = critical, CA:TRUE
keyUsage               = critical, digitalSignature, keyCertSign, cRLSign
subjectKeyIdentifier   = hash
authorityKeyIdentifier = keyid:always,issuer

This config file does not need many edits. The CN value should contain something more identifyable, since this is the displayed name in the overview over certificates. The root address should also be adjusted.

web.openssl.cnf

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
[req]
default_keyfile     = web.key
distinguished_name  = web
req_extensions      = v3_ext
prompt              = no
utf8                = yes

[web]
CN = Web page
O  = Private
C  = NO
emailAddress = web@my-domain.dev

[v3_ext]
extendedKeyUsage     = serverAuth
basicConstraints     = CA:FALSE
subjectAltName       = @web_ext
subjectKeyIdentifier = hash

[web_ext]
DNS.1 = *.my-domain.dev
DNS.2 = localhost
IP.1  = 192.168.0.10

The config for the web-certificate should be customized:

Field Suggestion
CN the DNS name for the web server
O the responsible organization
C Country - 2 letter abbreviation
emailAddress the responsible developer
DNS.1 dns name of the web server
IP.1 IP-address in case DNS does not work

Proper CA approach #

There is a tool openssl ca, which takes care of more CA related tasks. (maybe later)