Skip to content

Certificates

letsencrypt 2024

There is another section lower down about letsencrypt and certbot. But this was an install from march 2024 so i just show the basic steps.

You need to install apache2, also i installed ufw to firewall so there are some ufw commands around needed to open up the needed ports.

dns

Note that certbot requests the website that you want to get a certificate for. So the DNS name needs to point to that address and apache2 should be running.

For me it was this rule in transip console. The first was already there :

caiway  A       204.168.204.158
*.hvh   CNAME   caiway

The second works just like the other wildcard CNAME's neat. So rancher.hvh.klopt.org will end up in 204.166.204.158

ufw

If installed this closes all ports by default so apt-get install apache2 won't work at all. You can view the current status :

 ufw status
Status: active

To                         Action      From
--                         ------      ----
22                         ALLOW       Anywhere                  
22 (v6)                    ALLOW       Anywhere (v6)    

So only ssh is open, let's encrypt wants to connect to your server through the domain name, so we need a http(s) port, i just did both

sudo ufw allow 80
Rule added
Rule added (v6)
sudo ufw allow 443
Rule added
Rule added (v6)

rancher

After this there is a section on apache2 that works, but it might be even simpler by issuing this command.

docker run -d --restart=unless-stopped \
  -p 80:80 -p 443:443 \
  --privileged \
  rancher/rancher:latest \
  --acme-domain rancher.hvh.klopt.org

Now this works if you follow the rest of this guide, and then stop apache (because it used our ports) But it may work without apache at all !?! (try out the next time)

The --restart option makes the container restart when docker restart unless you explicitly stopped it yourself. It also start the container when you stop+start docker, so that includes a reboot.

apache2

sudo apt-get install apache2
a2enmod ssl
a2ensite default-ssl
apache2ctl restart

certbot

Now test if you have access to the apache server by browsing to https://rancher.hvh.klopt.org. If that work run certbot, do NOT use the default debian package, install it with snap :

sudo apt-get install snapd
snap install --classic certbot
certbot --apache

Fill in the questions, and remember where the certificate are put :

Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/rancher.hvh.klopt.org/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/rancher.hvh.klopt.org/privkey.pem
This certificate expires on 2024-06-23.

The certificate is not long lasting, maybe there is a way around that. But it is easy to install, so ...

pki

This is the most simple setup, see https://pki-tutorial.readthedocs.org/en/latest/simple/index.html The example is very terse and you won't see what exactly get's done, that's why this is a little more verbose examples.

config file

We need a considerate amount of config file to start. You can get these by getting them from git :

pki sample files
git clone https://bitbucket.org/stefanholek/pki-example-1

But i will display them here as well.

etc
cd pki-example 
ls etc

will show you what files are needed.

create root CA

Our base file is etc.root-ca.conf: Now this is a LOT of fields most of which are standard.

create CA
# Simple Root CA

# The [default] section contains global constants that can be referred to from
# the entire configuration file. It may also hold settings pertaining to more
# than one openssl command.

[ default ]
ca                      = root-ca               # CA name
dir                     = .                     # Top dir

# The next part of the configuration file is used by the openssl req command.
# It defines the CA's key pair, its DN, and the desired extensions for the CA
# certificate.

[ req ]
default_bits            = 2048                  # RSA key size
encrypt_key             = yes                   # Protect private key
default_md              = sha1                  # MD to use
utf8                    = yes                   # Input is UTF-8
string_mask             = utf8only              # Emit UTF-8 strings
prompt                  = no                    # Don't prompt for DN
distinguished_name      = ca_dn                 # DN section
req_extensions          = ca_reqext             # Desired extensions

[ ca_dn ]
0.domainComponent       = "org"
1.domainComponent       = "simple"
organizationName        = "Simple Inc"
organizationalUnitName  = "Simple Root CA"
commonName              = "Simple Root CA"

[ ca_reqext ]
keyUsage                = critical,keyCertSign,cRLSign
basicConstraints        = critical,CA:true
subjectKeyIdentifier    = hash

# The remainder of the configuration file is used by the openssl ca command.
# The CA section defines the locations of CA assets, as well as the policies
# applying to the CA.

[ ca ]
default_ca              = root_ca               # The default CA section

[ root_ca ]
certificate             = $dir/ca/$ca.crt       # The CA cert
private_key             = $dir/ca/$ca/private/$ca.key # CA private key
new_certs_dir           = $dir/ca/$ca           # Certificate archive
serial                  = $dir/ca/$ca/db/$ca.crt.srl # Serial number file
crlnumber               = $dir/ca/$ca/db/$ca.crl.srl # CRL number file
database                = $dir/ca/$ca/db/$ca.db # Index file
unique_subject          = no                    # Require unique subject
default_days            = 3652                  # How long to certify for
default_md              = sha1                  # MD to use
policy                  = match_pol             # Default naming policy
email_in_dn             = no                    # Add email to cert DN
preserve                = no                    # Keep passed DN ordering
name_opt                = ca_default            # Subject DN display options
cert_opt                = ca_default            # Certificate display options
copy_extensions         = none                  # Copy extensions from CSR
x509_extensions         = signing_ca_ext        # Default cert extensions
default_crl_days        = 365                   # How long before next CRL
crl_extensions          = crl_ext               # CRL extensions

# Naming policies control which parts of a DN end up in the certificate and
# under what circumstances certification should be denied.

[ match_pol ]
domainComponent         = match                 # Must match 'simple.org'
organizationName        = match                 # Must match 'Simple Inc'
organizationalUnitName  = optional              # Included if present
commonName              = supplied              # Must be present

[ any_pol ]
domainComponent         = optional
countryName             = optional
stateOrProvinceName     = optional
localityName            = optional
organizationName        = optional
organizationalUnitName  = optional
commonName              = optional
emailAddress            = optional

# Certificate extensions define what types of certificates the CA is able to
# create.

[ root_ca_ext ]
keyUsage                = critical,keyCertSign,cRLSign
basicConstraints        = critical,CA:true
subjectKeyIdentifier    = hash
authorityKeyIdentifier  = keyid:always

[ signing_ca_ext ]
keyUsage                = critical,keyCertSign,cRLSign
basicConstraints        = critical,CA:true,pathlen:0
subjectKeyIdentifier    = hash
authorityKeyIdentifier  = keyid:always

# CRL extensions exist solely to point to the CA certificate that has issued
# the CRL.

[ crl_ext ]
authorityKeyIdentifier  = keyid:always

Ok, that's a lot. Just view it, and note that it is for simple.org and it's a root-ca.

Create the directory structure as lined out in the root_ca section, and make the private directory very private. mkdir -p ca/root-ca/private ca/root-ca/db crl certs chmod 700 ca/root-ca/private The ca directory holds CA resources, the crl directory holds CRLs, and the certs directory holds user certificates.

Now the database has to be there, and contains some values :

create files
1
2
3
4
cp /dev/null ca/root-ca/db/root-ca.db
cp /dev/null ca/root-ca/db/root-ca.db.attr
echo 01 > ca/root-ca/db/root-ca.crt.srl
echo 01 > ca/root-ca/db/root-ca.crl.srl

one liner certificate

A one-shot line to generate a self signed certificate and key, without any questions :

one shot
openssl req -subj '/CN=test.local/O=Stichting RINIS/C=NL' -new -newkey rsa:2048 -days 365 -nodes -x509 -keyout server.key -out server.crt
list truststore certificates
list keystore
keytool -list -keystore truststore.jks
input
Enter keystore password: ****
Keystore type: JKS
Keystore provider: SUN

Your keystore contains 3 entries

vecozo_root_test, Jun 17, 2015, trustedCertEntry,
Certificate fingerprint (MD5): DB:BB:36:1F:7A:35:E3:82:08:79:31:99:3F:FA:11:AB
vecozo_31_test, Jun 17, 2015, trustedCertEntry,
Certificate fingerprint (MD5): 3C:23:72:6E:42:4D:7B:47:AC:1B:C1:83:75:3B:52:A8
vecozo_server_test, Jun 17, 2015, trustedCertEntry,
Certificate fingerprint (MD5): 8E:97:8E:11:37:CD:88:27:9A:8D:5F:FF:19:F6:C5:B8

This lists tomcat truststores, using the -v option even lists much more, maybe too much ? You could filter on Issuer or Owner :

list
keytool -list -keystore  truststore.jks | grep Owner

Truststore vs KeyStore

The main difference is not as in apache, where you have an entry for the KeyFile, the CertFile and the CA file. These are all serverside certificates. The keystore contains all these three and is meant for serverside. The truststore only contains CA certificates and is use when you connect as a client.

keystore

  • Keystore is meant to provide credentials
  • So this is mainly meant serverside, (or as client when the server requires client authentication)
  • In java this is handled by the KeyManager class
  • In principle you should use keystore.jks
  • This is private key, certificate AND ca-trust in apache

truststore

  • Truststore is meant to verify credentials
  • So this mainly meant to be used client side
  • In java this is handled by the TrustManager class
  • You should use truststore.jks
  • This is the ca certificates installed in your browser.

No one prevents you from putting all keys and chains in one file and using :

truststore
-Djavax.net.ssl.keyStore=keystore.jks -Djavax.net.ssl.keyStorePassword=x -Djavax.net.ssl.trustStore=keystore.jks -Djavax.net.ssl.trustStorePassword=x

listing multiple certificates

There is no way to list multiple certificates in for instance ca-trust files, it will just list the first one if you use

list
openssl x509 -in ca-trust.crt -text

So you will have to cut and paste each one into a separate file and run the command on that. Or you can use this next perl script to list them all.

perl script
#!/usr/bin/perl
# script for splitting multi-cert input into individual certs
# Artistic Licence
#
# v0.0.1         Nick Burch <nick@tirian.magd.ox.ac.uk>
# v0.0.2         Tom Yates <tyates@gatekeeper.ltd.uk>
#

$filename = shift;
unless($filename) {
  die("You must specify a cert file.n");
}
open INP, "<$filename" or die("Unable to load "$filename"n");

$thisfile = "";

while(<INP>) {
   $thisfile .= $_;
   if($_ =~ /^-+END(sw+)?sCERTIFICATE-+$/) {
      print "Found a complete certificate:n";
      print `echo "$thisfile" | openssl x509 -noout -text`;
      $thisfile = "";
   }
}
close INP;

ssl cache

It seems that ctrl-shift-n clears the certificate cache.

My example, was :

  • a failing website at https://https.acc.rinis.eu
  • than added the certificate needed : https_acc_rinis.eu
  • Works !!
  • but now delete it again
  • refresh.. and it still works , not what i need because i'm debugging
  • now hit ctrl-shift-n
  • now it fails again, as in point 1

checking certificate key match

The private key contains a series of numbers. Two of those numbers form the "public key", the others are part of your "private key". The "public key" bits are also embedded in your Certificate (we get them from your CSR). To check that the public key in your cert matches the public portion of your private key, you need to view the cert and the key and compare the numbers. To view the Certificate and the key run the commands:

check key
openssl x509 -noout -text -in server.crt
openssl rsa -noout -text -in server.key

The modulus and the public exponent portions in the key and the Certificate must match. But since the public exponent is usually 65537 and it's bothering comparing long modulus you can use the following approach

check md5 key
openssl x509 -noout -modulus -in server.crt | openssl md5
openssl rsa -noout -modulus -in server.key | openssl md5

If the same, there is undoubtedly a match.

letsencrypt

This is a free CA, so at least interesting. Before jumping to these certificates first take not of these important facts :

Letsencrypt certificates do not check the domain name holder. You could use an anonymous email address and get a certificate. You DO have to own the domain !!

Letsencrypt certificates expire after 90 days !! Though you could automate the extension with tools like certbot.

Two facts to regard these certificates as rather unusable for a production site. It probably won't be accepted by some companies and we have to reinstall 4 times a year (or automate it with certbot).

Still i will try these on codewell.nl just to try out for a while.

certbot

See : https://certbot.eff.org/instructions

Certbot is a tool that uses letsencrypt to automate certificate requests. In kubernetes this tool does not seem to be used, there they have their own cert-manager (see kubernetes)

ACME protocol

This is the protocol that letsencrypt is based on. The objective of Let's Encrypt and the ACME protocol is to make it possible to set up an HTTPS server and have it automatically obtain a browser-trusted certificate, without any human intervention. This is accomplished by running a certificate management agent on the web server.

Here is the gist : https://letsencrypt.org/how-it-works/

In short :

  • The web server has an agent running that handles the ACME protocol
  • The agent requests a certificate from letsencrypt CA
  • CA issues a challenge that the agent can do automatically that proves it has control over the domain. For instance : provide a file on a certain url on that domain.
  • CA Also send a nonce (once used bitstring or number) that the agent must sign with the private key to show that it controls the key-pair for that site
  • The CA verifies if the nonce was signed correctly and if the file was found at the url (only the holder of the certificate could complete these challenges)
  • After that the CA authorizes messages signed by the private key to do operations like CSR or prolongation, revocation etc..
  • Browsers having letsencrypt CA as trusted CA will then accept the issued certificates.