Professionally administering Linux is a very complex matter: it requires advanced skills on the kernel and on a lot of tools and utilities that are often combined in pipelines and scripts.

Professionals having a thorough understanding of the kernel know how to get optimal performance for specific workloads by tuning the right “knobs” and to what degree to do it. In addition to that they know what commands and tools should be used to gather all the information necessary to fix performance issues. This of course requires having a thorough understanding of the kernel scheduler, of memory allocators, of the virtual memory, the Virtual File System and so.

As anybody would expect, skilled professionals thoroughly know the Linux distribution they use – being able to install and remove software packages is absolutely not enough. They should know:

  • the file system standard layout used by the distro – so to honour it when installing custom software
  • how to create custom packages (such as RPM) to ease the installation of custom application and scripts
  • the peculiarities of the initialization process specific of the distribution, in order to sort out boot issues that may arise sooner or later
  • how to perform automated installations
  • how to use filesystems, partitioning and Logical Volume Management utilities to apply changes while keeping online the system

And of course a lot of other stuff.

 

OpenSSL is a full featured tool capable not only to generate keys and certificates, but also to provide every facility a PKI must have, such as indirect CRL and OCSP responders: these features, along with certificate's best practices such as the Certification Practice Statement (CPS), publishing CRL Distribution Points URL, OCSP Responders URL, CA Issuers URL, are the topics of the OpenSSL CA tutorial - A full-featured openssl PKI. 

Right after setting up the Lab PKI, the post shows you also how to mark the issued certificates as Extended Validated, Organization Validated, Individual Validated and Domain Validated.

This post is the hands-on lab of my previous post "X509 Certificates HowTo - A Public Key Infrastructure Tutorial": I strongly suggest you to read it before going further: I won't provide any theoretical notions in this post - it would be pointless, since it's every already explained there.

Mind that OpenSSL CLI and tools have not been developed with performance in mind: if you need something more performing, please consider using OpenXPKI or Cloudlfare's PKI and TLS Toolkit.

The Public Key Infrastructure We Want To implement

We are going to setup the following Lab:

  • Root CA: CARC R100T
  • Intermediate CA: CARCI100T
  • both CA will have their own Validation Authority with dedicated certificate to sign OCSP Responses and Indirect CRL
  • both CA use Elliptic Curves as the key algorithm
This post shows how to set-up a Systemd Unit for the OCSP Responder: since HTTP publishing the CRL file is the same as publishing any kind of file, you can configure your favorite web server for doing this trivial task. Mind only that it is not necessary to use HTTPS: a CRL is a public document - the only important thing is that it is digitally signed by the authoritative entity.

Since we are setting up everything from scratch, and every configuration command needs administrative rights, we directly switch to the root user:

sudo su -

Prerequisites

Add a PKI Service User

The very first and obvious thing to do is creating a dedicated service user::

adduser -r -c "pki Service User" -s /sbin/nologin pki

Setup The PKI Directory Tree

As we saw, a Public Key Infrastructure is very often made of more than just one Certificate Authority: for this reason we create two dedicated directory trees:

the first, where to store each Certificate Authorities' configuration files:

mkdir -m 755 /etc/corporate-pki \
/etc/corporate-pki/ca

the second one is instead used to store data files of each Certificate Authority:

mkdir -m 755 /var/lib/corporate-pki

Automating The Certificate Authority Creation

Manually configuring Certificate Authorities with openssl is a cumbersome, time consuming and error prone task: for this reason I developed the below automation script that automatically generates the directories structures, taking care of properly setting permissions, and deriving OpenSSL configuration files from templates.

The script is intentionally missing the statements necessary to create the keys and certificates: the goal of this post is exactly to explain how to deal with openssl - automating everything is just the opposite of this purpose. If you fancy, you can complete the script yourself by adding the statements we are manually using in this post, ... it is a trivial task.

The CA-Setup Script

Create the "/usr/local/bin/corporate-pki-newca.sh" script with the following contents:

#!/bin/bash
PKI_CONF_PATH="/etc/corporate-pki/ca"
PKI_TEMPLATES_PATH="/etc/corporate-pki/templates"
PKI_LIB_PATH="/var/lib/corporate-pki"
PKI_SERVICE_USER="pki"
ADD_ISSUER=0

CA_NAME_D="CARC I100T"
CA_LABEL_D="carc_i100t"
OCSP_URI_D="http://ocsp.test.carcano.local:8889"
CAISSUERS_URI_D="http://ca.test.carcano.local/carc_r100t.cer"
CRL_URI_D="http://www.test.carcano.local/crl/carc_r100t.crl"
COUNTRY_D="CH"
ORGANIZATION_D="Carcano SA"
ENTERPRISE_OID_D="1234"
CPS_URL_D="http://www.carcano.local/ca/cps.html"
ROOTCA_LABEL_D="CARC I100T"

validate(){
    local missing_options=""
    if [[ -z ${CA_NAME} ]]; then
        missing_options="--ca-name"
    fi
    if [[ -z ${CA_LABEL} ]]; then
        [ -n "${missing_options}" ] && missing_options="${missing_options}, "
        missing_options="${missing_options}--ca-label"
    fi
    if [[ -z ${ORGANIZATION} ]]; then
        [ -n "${missing_options}" ] && missing_options="${missing_options}, "
        missing_options="${missing_options}--organization"
    fi
    if [[ -z ${ENTERPRISE_OID} ]]; then
        [ -n "${missing_options}" ] && missing_options="${missing_options}, "
        missing_options="${missing_options}--enterprise-oid"
    fi
    if [[ -z ${COUNTRY} ]]; then
        [ -n "${missing_options}" ] && missing_options="${missing_options}, "
        missing_options="${missing_options}--country"
    fi
    if [[ -z ${CRL_URI} ]]; then
        [ -n "${missing_options}" ] && missing_options="${missing_options}, "
        missing_options="${missing_options}--crl-url"
    fi
    if [[ -z ${OCSP_URI} ]]; then
        [ -n "${missing_options}" ] && missing_options="${missing_options}, "
        missing_options="${missing_options}--ocsp-url"
    fi
    if [[ -z ${CAISSUERS_URI} ]]; then
        [ -n "${missing_options}" ] && missing_options="${missing_options}, "
        missing_options="${missing_options}--ca-issuers"
    fi
    if [[ -z ${CPS_URL} ]]; then
        [ -n "${missing_options}" ] && missing_options="${missing_options}, "
        missing_options="${missing_options}--cps-url"
    fi
    if [[ -n "${missing_options}" ]]; then
        echo "" >&2
        echo "The following mandatory options are missing:" >&2
        echo "" >&2
        echo "${missing_options}" >&2
        echo "" >&2
        echo "The command line syntax is as follows:" >&2
	usage
        exit 1
    fi
}

usage(){
    echo "" >&2
    echo "Create a new Certificate Authority" >&2
    echo "" >&2
    echo "  USAGE:" >&2
    echo "" >&2
    echo "    ${0##*/} [ OPTIONS ]" >&2
    echo "" >&2
    echo "  OPTIONS:" >&2
    echo "" >&2
    echo "    -n|--ca-name:         Name of the CA to create - for example: \"${CA_NAME_D}\"" >&2
    echo "    -l|--ca-label:        Label of the CA to create - for example: \"${CA_LABEL_D}\"" >&2
    echo "    -g|--organization:    Organization - for example: \"${ORGANIZATION_D}\"" >&2
    echo "    -i|--enterprise-oid:  Enterprise OID - for example: \"${ENTERPRISE_OID_D}\"" >&2
    echo "    -c|--country:         Country - for example: \"${COUNTRY_D}\"" >&2
    echo "    -v|--crl-url:         CRL's URL - for example: \"${CRL_URI_D}\"" >&2
    echo "    -o|--ocsp-url:        OCSP responder's URL - for example: \"${OCSP_URI_D}\"" >&2
    echo "    -u|--ca-issuers:      CA-Issuers URL - for example: \"${CAISSUERS_URI_D}\"" >&2
    echo "    -p|--cps-url:         CPS URL - for example: \"${CPS_URL_D}\"" >&2
    echo "    -r|--root-ca-label:   if creating an INTERMEDIATE level CA," >&2
    echo "                          the label of the ROOT level CA - for example \"${ROOTCA_LABEL_D}\"" >&2
    echo "    -s|--add-issuer:      add CA Issuer name and certificate serial to issued certificates" >&2
    echo "                          WARNING - not compatible with CA's cross-signing and CA's certificate" >&2
    echo "                          re-issuing using the same private key" >&2
    echo "    -h|--help:            print this help message" >&2
    echo "" >&2
}

if [[ -z "${1}" ]]; then
    usage
    exit 1
fi

echo ""
PARAMS=`getopt -o l:i:o:u:v:c:g:n:p:r:h --long ca-label:,enterprise-oid:,ocsp-url:,ca-issuers-url:,crl-url:,country:,organization:,ca-name:,cps-url:,root-ca-label:,help -n "${0##*/}" -- "$@"`
if [[ ${?} -ne 0 ]]; then
    usage
    exit 1
fi

eval set -- "${PARAMS}"
unset PARAMS

CA_LEVEL="intermediate"

while true
do
  case ${1} in
    -l|--ca-label)
      CA_LABEL=${2}
      shift 2
      ;;
    -i|--enterprise-oid)
      ENTERPRISE_OID=${2}
      shift 2
      ;;
    -o|--ocsp-url)
      OCSP_URI=${2}
      shift 2
      ;;
    -u|--ca-issuers-url)
      CAISSUERS_URI=${2}
      shift 2
      ;;
    -v|--crl-url)
      CRL_URI=${2}
      shift 2
      ;;
    -c|--country)
      COUNTRY=${2}
      shift 2
      ;;
    -g|--organization)
      ORGANIZATION=${2}
      shift 2
      ;;
    -n|--ca-name)
      CA_NAME=${2}
      shift 2
      ;;
    -p|--cps-url)
      CPS_URL=${2}
      shift 2
      ;;
    -r|--root-ca-label)
      ROOTCA_LABEL=${2}
      shift 2
      ;;
    -s|--add-issuer)
	    ADD_ISSUER=1
      shift 1
      ;;
    -h|--help)
      usage
      exit
      ;;
    --)
      shift
      break
      ;;
  esac
done

validate

if [[ -z "${ROOTCA_LABEL}" ]]; then
  CA_LEVEL="root"
fi

[ -d "${PKI_CONF_PATH}/${CA_LABEL}" ] || mkdir -m 755 "${PKI_CONF_PATH}/${CA_LABEL}"
[ -d "${PKI_CONF_PATH}/${CA_LABEL}/conf" ] || mkdir -m 755 "${PKI_CONF_PATH}/${CA_LABEL}/conf"
[ -d "${PKI_CONF_PATH}/${CA_LABEL}/keys" ] || mkdir -m 700 "${PKI_CONF_PATH}/${CA_LABEL}/keys"
chown ${PKI_SERVICE_USER}: "${PKI_CONF_PATH}/${CA_LABEL}/keys"
[ -d "${PKI_CONF_PATH}/${CA_LABEL}/certs" ] || mkdir -m 755 "${PKI_CONF_PATH}/${CA_LABEL}/certs"
[ -d "${PKI_LIB_PATH}/${CA_LABEL}" ] || mkdir -m 755 "${PKI_LIB_PATH}/${CA_LABEL}"
[ -d "${PKI_LIB_PATH}/${CA_LABEL}/certs" ] || mkdir -m 755 "${PKI_LIB_PATH}/${CA_LABEL}/certs"
[ -d "${PKI_LIB_PATH}/${CA_LABEL}/db" ] || mkdir -m 755 "${PKI_LIB_PATH}/${CA_LABEL}/db"
[ -d "${PKI_LIB_PATH}/${CA_LABEL}/crl" ] || mkdir -m 755 "${PKI_LIB_PATH}/${CA_LABEL}/crl"
[ -f "${PKI_LIB_PATH}/${CA_LABEL}/db/index.txt" ] || touch "${PKI_LIB_PATH}/${CA_LABEL}/db/index.txt"
[ -f "${PKI_LIB_PATH}/${CA_LABEL}/db/serial" ] || echo "1000" > "${PKI_LIB_PATH}/${CA_LABEL}/db/serial"
cp "${PKI_TEMPLATES_PATH}/openssl-${CA_LEVEL}.conf" "${PKI_CONF_PATH}/${CA_LABEL}/conf/openssl.conf"
sed -i "s/##CA_LABEL##/${CA_LABEL}/g" "${PKI_CONF_PATH}/${CA_LABEL}/conf/openssl.conf"
sed -i "s+##PKI_CONF_PATH##+${PKI_CONF_PATH}+g" "${PKI_CONF_PATH}/${CA_LABEL}/conf/openssl.conf"
sed -i "s+##PKI_LIB_PATH##+${PKI_LIB_PATH}+g" "${PKI_CONF_PATH}/${CA_LABEL}/conf/openssl.conf"
sed -i "s/##ENTERPRISE_OID##/${ENTERPRISE_OID}/g" "${PKI_CONF_PATH}/${CA_LABEL}/conf/openssl.conf"
sed -i "s+##OCSP_URI##+${OCSP_URI}+g" "${PKI_CONF_PATH}/${CA_LABEL}/conf/openssl.conf"
sed -i "s+##CAISSUERS_URI##+${CAISSUERS_URI}+g" "${PKI_CONF_PATH}/${CA_LABEL}/conf/openssl.conf"
sed -i "s+##CRL_URI##+${CRL_URI}+g" "${PKI_CONF_PATH}/${CA_LABEL}/conf/openssl.conf"
sed -i "s/##COUNTRY##/${COUNTRY}/g" "${PKI_CONF_PATH}/${CA_LABEL}/conf/openssl.conf"
sed -i "s/##ORGANIZATION##/${ORGANIZATION}/g" "${PKI_CONF_PATH}/${CA_LABEL}/conf/openssl.conf"
sed -i "s/##CA_NAME##/${CA_NAME}/g" "${PKI_CONF_PATH}/${CA_LABEL}/conf/openssl.conf"
sed -i "s+##CPS_URL##+${CPS_URL}+g" "${PKI_CONF_PATH}/${CA_LABEL}/conf/openssl.conf"
cp "${PKI_TEMPLATES_PATH}/crl.conf" "${PKI_CONF_PATH}/${CA_LABEL}/conf/crl.conf"
sed -i "s/##CA_LABEL##/${CA_LABEL}/g" "${PKI_CONF_PATH}/${CA_LABEL}/conf/crl.conf"
sed -i "s+##PKI_CONF_PATH##+${PKI_CONF_PATH}+g" "${PKI_CONF_PATH}/${CA_LABEL}/conf/crl.conf"
sed -i "s+##PKI_LIB_PATH##+${PKI_LIB_PATH}+g" "${PKI_CONF_PATH}/${CA_LABEL}/conf/crl.conf"
sed -i "s+##CRL_URI##+${CRL_URI}+g" "${PKI_CONF_PATH}/${CA_LABEL}/conf/crl.conf"
if [[ ${ADD_ISSUER} -eq 1 ]]; then
  sed -i "s/##AUTHORITY_KEY_IDENTIFIER##/authorityKeyIdentifier = keyid:always,issuer:always/g" "${PKI_CONF_PATH}/${CA_LABEL}/conf/openssl.conf"
  sed -i "s/##AUTHORITY_KEY_IDENTIFIER##/authorityKeyIdentifier = keyid:always,issuer:always/g" "${PKI_CONF_PATH}/${CA_LABEL}/conf/crl.conf"
else
  sed -i "s/##AUTHORITY_KEY_IDENTIFIER##/authorityKeyIdentifier = keyid:always/g" "${PKI_CONF_PATH}/${CA_LABEL}/conf/openssl.conf"
  sed -i "s/##AUTHORITY_KEY_IDENTIFIER##/authorityKeyIdentifier = keyid:always/g" "${PKI_CONF_PATH}/${CA_LABEL}/conf/crl.conf"
fi
[ -f "${PKI_LIB_PATH}/${CA_LABEL}/db/crl_serial" ] || echo 1000 > "${PKI_LIB_PATH}/${CA_LABEL}/db/crl_serial"

and of course, set it as executable:

chmod 755 /usr/local/bin/corporate-pki-newca.sh

OpenSSL CA configuration File Templates

The automation script generates the Certificate Authority's configuration file from the following template files:

  • openssl-root.conf
  • openssl-intermediate.conf
  • crl.conf

Let's create the directory where to store them:

mkdir -m 755 /etc/corporate-pki/templates

we are now ready to create the template files.

Root Certificate Authorities Configuration Template

Create the "/etc/corporate-pki/templates/openssl-root.conf" file with the following contents:

oid_section     = custom_oids

[ ca ]
default_ca = CA_default

[ CA_default ]
dir               = ##PKI_LIB_PATH##/##CA_LABEL##
certs             = ##PKI_CONF_PATH##/##CA_LABEL##/certs
private_key       = ##PKI_CONF_PATH##/##CA_LABEL##/keys/ca.key
certificate       = ##PKI_CONF_PATH##/##CA_LABEL##/certs/ca.crt
new_certs_dir     = $dir/certs
database          = $dir/db/index.txt
serial            = $dir/db/serial
default_md        = sha256
unique_subject    = no
policy            = policy_short
preserveDN        = no
email_in_dn       = no

[ custom_oids ]
CPS           = 1.3.6.1.4.1.##ENTERPRISE_OID##.1.1
CA-Cert       = 1.3.6.1.4.1.##ENTERPRISE_OID##.1.2
EV-Cert       = 2.23.140.1.1

[ policy_short ]
countryName             = match
organizationName        = match
organizationalUnitName  = optional
commonName              = supplied

[ req ]
distinguished_name = req_distinguished_name

[ req_distinguished_name ]

[ root_ca ]
subjectKeyIdentifier = hash
##AUTHORITY_KEY_IDENTIFIER##
keyUsage = critical,keyCertSign
basicConstraints = critical,CA:TRUE

[ crl_issuer ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always
keyUsage = critical,cRLSign,nonRepudiation,digitalSignature,keyEncipherment
basicConstraints = critical,CA:FALSE
extendedKeyUsage = OCSPSigning

[ aia ]
OCSP;URI.1=##OCSP_URI##
caIssuers;URI.2=##CAISSUERS_URI##

[ intermediate_ca ]
subjectKeyIdentifier = hash
##AUTHORITY_KEY_IDENTIFIER##
basicConstraints = critical,CA:TRUE
keyUsage = critical, keyCertSign, cRLSign
crlDistributionPoints = crl_dp
authorityInfoAccess = @aia
certificatePolicies = ia5org,@CPS,@CA_policy,@EV_policy

[ crl_dp ]
fullname = URI:##CRL_URI##
CRLissuer = dirName:crl_issuer_dn

[ crl_issuer_dn ]
C=##COUNTRY##
O=##ORGANIZATION##
CN=##CA_NAME##

[ CPS ]
policyIdentifier = CPS
CPS.1            = "##CPS_URL##"
userNotice.1     = @CPS_Notice

[ CPS_Notice ]
explicitText  = "##CA_NAME## Certification Practice Statement"

[ CA_policy ]
policyIdentifier = CA-Cert
userNotice.2     = @CA_Notice

[ CA_Notice ]
explicitText  = "CA Certificate Policy"

[ EV_policy ]
policyIdentifier = EV-Cert
userNotice.6     = @EV_Notice

[ EV_Notice ]
explicitText  = "Certificate issued in compliance with the Extended Validation Guidelines"

Specifying "issuer" as value of the authorityKeyIdentifier x509v3 extension causes the issuer's certificate Dir name and Certificate serial to be added to every issued certificate. This deeply affects the validation procedure: since the signer's certificate serial is included, when renewing, it is no more possible to re-issue the Certificate Authority's certificate using the same private key, since the resulting certificate will have a serial that differs from the one that was copied in every issued certificate. If you want to be able to renew CA's certificate by using the same private key,  you must not include "issuer" in the authorityKeyIdentifier x509v3 extension. The script allow you to work both ways: by default it does not add "issuer", but if you fancy you can configure it the strict way by supplying the --add-issuer command line switch - the ##AUTHORITY_KEY_IDENTIFIER## is automatically replaced with the proper settings.

Intermediate Certificate Authorities Configuration Template

Create the "/etc/corporate-pki/templates/openssl-intermediate.conf" file with the following contents:

oid_section     = custom_oids

[ ca ]
default_ca = CA_default

[ CA_default ]
dir               = ##PKI_LIB_PATH##/##CA_LABEL##
certs             = ##PKI_CONF_PATH##/##CA_LABEL##/certs
private_key       = ##PKI_CONF_PATH##/##CA_LABEL##/keys/ca.key
certificate       = ##PKI_CONF_PATH##/##CA_LABEL##/certs/ca.crt
new_certs_dir     = $dir/certs
database          = $dir/db/index.txt
serial            = $dir/db/serial
default_md        = sha256
unique_subject    = no
policy            = policy_short
preserveDN        = no
email_in_dn       = no

[ custom_oids ]
CPS           = 1.3.6.1.4.1.##ENTERPRISE_OID##.1.1
CA-Cert       = 1.3.6.1.4.1.##ENTERPRISE_OID##.1.2
DV-Cert       = 2.23.140.1.2.1
OV-Cert       = 2.23.140.1.2.2
IV-Cert       = 2.23.140.1.2.3
EV-Cert       = 2.23.140.1.1

[ policy_short ]
countryName             = match
organizationName        = match
organizationalUnitName  = optional
commonName              = supplied

[ req ]
distinguished_name = req_distinguished_name

[ req_distinguished_name ]

[ crl_issuer ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always
keyUsage = critical,cRLSign,nonRepudiation,digitalSignature,keyEncipherment
basicConstraints = critical,CA:FALSE
extendedKeyUsage = OCSPSigning

[ aia ]
OCSP;URI.1=##OCSP_URI##
caIssuers;URI.2=##CAISSUERS_URI##

[ intermediate_ca ]
subjectKeyIdentifier = hash
##AUTHORITY_KEY_IDENTIFIER##
basicConstraints = critical,CA:TRUE
keyUsage = critical, keyCertSign, cRLSign
crlDistributionPoints = crl_dp
authorityInfoAccess = @aia
certificatePolicies = ia5org,@CPS,@CA_policy,@EV_policy

[ dv ]
subjectKeyIdentifier = hash
##AUTHORITY_KEY_IDENTIFIER##
basicConstraints = critical,CA:FALSE
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = critical, serverAuth
crlDistributionPoints = crl_dp
authorityInfoAccess = @aia
certificatePolicies = ia5org,@CPS,@DV_policy

[ iv ]
subjectKeyIdentifier = hash
##AUTHORITY_KEY_IDENTIFIER##
basicConstraints = critical,CA:FALSE
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = critical, serverAuth
crlDistributionPoints = crl_dp
authorityInfoAccess = @aia
certificatePolicies = ia5org,@CPS,@IV_policy

[ ov ]
subjectKeyIdentifier = hash
##AUTHORITY_KEY_IDENTIFIER##
basicConstraints = critical,CA:FALSE
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = critical, serverAuth
crlDistributionPoints = crl_dp
authorityInfoAccess = @aia
certificatePolicies = ia5org,@CPS,@OV_policy

[ ev ]
subjectKeyIdentifier = hash
##AUTHORITY_KEY_IDENTIFIER##
basicConstraints = critical,CA:FALSE
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = critical, serverAuth
crlDistributionPoints = crl_dp
authorityInfoAccess = @aia
certificatePolicies = ia5org,@CPS,@EV_policy

[ crl_dp ]
fullname = URI:##CRL_URI##
CRLissuer = dirName:crl_issuer_dn

[ crl_issuer_dn ]
C=##COUNTRY##
O=##ORGANIZATION##
CN=##CA_NAME##

[ CPS ]
policyIdentifier = CPS
CPS.1            = "##CPS_URL##"
userNotice.1     = @CPS_Notice

[ CPS_Notice ]
explicitText  = "##CA_NAME## Certification Practice Statement"

[ CA_policy ]
policyIdentifier = CA-Cert
userNotice.2     = @CA_Notice

[ CA_Notice ]
explicitText  = "CA Certificate Policy"

[ DV_policy ]
policyIdentifier = DV-Cert
userNotice.3     = @DV_Notice

[ DV_Notice ]
explicitText  = "Compliant with Baseline Requirements – No entity identity asserted"

[ IV_policy ]
policyIdentifier = IV-Cert
userNotice.4     = @IV_Notice

[ IV_Notice ]
explicitText  = "Compliant with Baseline Requirements – Individual identity asserted"

[ OV_policy ]
policyIdentifier = OV-Cert
userNotice.5     = @OV_Notice

[ OV_Notice ]
explicitText  = "Compliant with Baseline Requirements – Individual identity asserted"

[ EV_policy ]
policyIdentifier = EV-Cert
userNotice.6     = @EV_Notice

[ EV_Notice ]
explicitText  = "Certificate issued in compliance with the Extended Validation Guidelines"
As you should expect, the Intermediate CAs' template differs from the Root CAs' template: the CA's have different purposes - for example the Intermediate CA must be able to issue Extended Validated (EV), Organization Validated (OV), Individual Validated (IV) and Domain Validated (DV) entity certificates.

Validation Authorities Configuration Template

The Validation Authorities need to have their own OpenSSL configuration file, so we create the "/etc/corporate-pki/templates/crl.conf" template file with the following contents:

[ ca ]
default_ca = CA_default

[ CA_default ]
dir               = ##PKI_LIB_PATH##/##CA_LABEL##
private_key       = ##PKI_CONF_PATH##/##CA_LABEL##/keys/va.key
certificate       = ##PKI_CONF_PATH##/##CA_LABEL##/certs/va.crt
database          = $dir/db/index.txt
default_md        = sha256
crlnumber         = $dir/db/crl_serial
default_crl_days  = 30
crl_dir           = ##PKI_LIB_PATH##/##CA_LABEL##/crl
crl               = ##PKI_LIB_PATH##/##CA_LABEL##/crl/##CA_LABEL##

[ crl_extensions ]
##AUTHORITY_KEY_IDENTIFIER##
issuingDistributionPoint = @crl_issuing_dp

[ crl_issuing_dp ]
fullname = URI:##CRL_URI##
indirectCRL=TRUE

Setup The Root CA

We finally have all the necessary automation to quickly set up Certificate Authorities: let's start from setting up the "CARC R100T" ROOT level Certificate Authority with the following settings:

  • Name: CARC R100T
  • Label: carc-r100t
  • Enterprise OID: 1234
  • Organization: Carcano SA
  • Country: CH
  • CA issuers URL: http://ca.test.carcano.local/carc_r100t.cer
  • Certificate Practice Statement URL: http://www.carcano.local/ca/cps.html
  • CRL Endpoint URL: http://www.test.carcano.local/crl/carc_r100t.crl
  • OCSP Responder URL: http://ocsp.test.carcano.local:8889
Since this is a Lab, we can use any value as Enterprise OID, but in real life you MUST ask IANA for assigning you a dedicated one. If you really need an Enterprise OID - don't use this for experiments - the form is here.

Let's create the directory tree and configuration files using the automation script we developed:

/usr/local/bin/corporate-pki-newca.sh --ca-name "CARC R100T" \
--ca-label carc_r100t --enterprise-oid 1234 --organization "Carcano SA" --country CH \
--crl-url "http://www.test.carcano.local/crl/carc_r100t.crl" \
--ocsp-url "http://ocsp.test.carcano.local:8889" \
--ca-issuers "http://ca.test.carcano.local/carc_r100t.cer" \
--cps-url "http://www.carcano.local/ca/cps.html"

If you don't know the meaning of some of the above parameters, refer to my previous post “X509 Certificates HowTo - A Public Key Infrastructure Tutorial”: since I already thoroughly explained everything, I won't go too much into details in this post, also because otherwise it would become too long.

Generate The Self-Signed ROOT CA Certificate

The very first certificate to generate is the Certificate Authority's self-signed certificate.

First, we generate the key as an empty file and immediately restrict access to it:

CA_LABEL="carc_r100t"
PKI_CONF_PATH="/etc/corporate-pki/ca/${CA_LABEL}"
touch ${PKI_CONF_PATH}/keys/ca.key
chmod 400 ${PKI_CONF_PATH}/keys/ca.key
chown pki: ${PKI_CONF_PATH}/keys/ca.key

then generate the private key overwriting the empty file:

openssl ecparam -name secp521r1 -genkey | \
openssl ec -out ${PKI_CONF_PATH}/keys/ca.key -aes256

of course we are asked for the password we want to use to encrypt the private key.

In this example we created an Elliptic Curve private key using the secp521r curve: if you need more information on this topic, please refer to "Symmetric And Asymmetric Cryptography".

Create the Certificate Signing Request (CSR) with the following data:

  • Certificate Lifetime: 3652 days (10 years)
  • Country: CH
  • Organization: Carcano SA
  • Common Name: CARC R100T
openssl req -new -key ${PKI_CONF_PATH}/keys/ca.key \
-out ${PKI_CONF_PATH}/certs/ca.csr \
-subj "/C=CH/O=Carcano SA/CN=CARC R100T"

Then, we generate the CA Certificate from the CSR, signing it with the same key used for the CSR:

openssl x509 -req -extfile ${PKI_CONF_PATH}/conf/openssl.conf \
-extensions root_ca -days 3652 \
-key ${PKI_CONF_PATH}/keys/ca.key \
-in ${PKI_CONF_PATH}/certs/ca.csr \
-out ${PKI_CONF_PATH}/certs/ca.crt

The outcome is a PEM encoded file containing the certificate data.

Let's have a look to its first two lines and last two lines:

head -n 2 ${PKI_CONF_PATH}/certs/ca.crt; echo ...; tail -n 2 ${PKI_CONF_PATH}/certs/ca.crt

the output looks like the following snippet:

-----BEGIN CERTIFICATE-----
MIICGzCCAaGgAwIBAgIUOQTx2cnp7mGK4Dumzly6I5Bp7PowCgYIKoZIzj0EAwQw
...
wBKX/Z/uE5Y3ZB/gABw3
-----END CERTIFICATE-----

We can of course decode the PEM formatted certificate and print it in human-readable format.

Type the following statement:

openssl x509 -noout -text -in ${PKI_CONF_PATH}/certs/ca.crt

the output is as follows:

Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            70:97:97:61:e9:ce:c4:31:16:5b:63:a7:c8:2e:58:8f:bf:64:d2:7a
        Signature Algorithm: ecdsa-with-SHA256
        Issuer: C = CH, O = Carcano SA, CN = CARC R100T
        Validity
            Not Before: Jun  1 15:02:58 2023 GMT
            Not After : May 31 15:02:58 2033 GMT
        Subject: C = CH, O = Carcano SA, CN = CARC R100T
        Subject Public Key Info:
            Public Key Algorithm: id-ecPublicKey
                Public-Key: (521 bit)
                pub:
                    04:00:10:30:b5:2c:03:09:5d:9f:d2:a6:c4:43:e0:
                    89:5c:10:47:c1:ea:54:b7:08:f0:1c:ec:39:c9:8b:
                    ca:92:59:dd:14:20:01:c5:4e:74:0e:9f:14:ec:02:
                    21:b5:3a:f6:cb:34:49:5b:d7:e1:a5:9b:06:61:b2:
                    db:48:6c:03:b5:8f:50:01:23:76:ff:3d:b2:ce:ba:
                    ae:0a:d5:c9:24:74:00:27:0a:63:b1:0d:21:c1:f7:
                    4b:40:0f:78:e9:cd:88:50:fa:25:29:e8:e3:57:47:
                    42:c5:dc:24:66:7d:f0:46:9a:25:78:69:be:11:ca:
                    28:a6:c0:86:28:c4:1f:a0:c6:64:13:e3:4b
                ASN1 OID: secp521r1
                NIST CURVE: P-521
        X509v3 extensions:
            X509v3 Subject Key Identifier: 
                B5:26:F1:34:F7:C6:51:A7:F3:01:73:9F:28:16:8B:F3:A0:E8:9F:65
            X509v3 Authority Key Identifier: 
                B5:26:F1:34:F7:C6:51:A7:F3:01:73:9F:28:16:8B:F3:A0:E8:9F:65
            X509v3 Key Usage: critical
                Certificate Sign
            X509v3 Basic Constraints: critical
                CA:TRUE
    Signature Algorithm: ecdsa-with-SHA256
    Signature Value:
        30:81:87:02:41:59:eb:46:77:cd:b3:0e:f1:b5:cd:19:7e:c6:
        66:b0:a1:64:65:38:24:a3:fa:a1:06:48:98:af:b5:fc:9b:56:
        26:c5:0c:cb:03:0f:94:23:ff:85:57:e3:d4:6b:27:c2:09:b9:
        55:db:1a:ef:f6:69:18:51:b4:21:45:96:c9:95:89:c1:02:42:
        01:25:a8:1c:1f:80:90:c9:c6:67:8e:a6:3b:18:ec:97:4d:28:
        7d:ff:50:66:02:4c:9a:4e:fa:1b:c1:1e:3d:e8:c3:79:a0:d2:
        b1:19:1a:1b:81:a1:65:54:74:67:7f:6f:ea:49:d4:27:a7:4f:
        a2:4f:40:f5:4f:db:5d:16:b0:22:6f:f0

In this post I really want to show you a complex scenario, so that you can derive your own setups tailored to your needs. If you look at the above output, you see the key usage is only "Certificate Sign '': since it is missing the “CRL Sign” usage, this certificate can of course be used to sign other certificates, but not to sign CRLs. This advanced setup, called "Indirect CRL'', enables you to remove the CA's private key to securely store it offline right after having signed the intermediate CA's certificate: you will use the delegated private key to sign CRLs. The downside is that not every SSL implementation is compatible with this advanced setup, so you have to make sure the technology stack in your environment supports it.

Generate the CA's bundle certificate file with the trust-chain for the CA's certificate:

cp ${PKI_CONF_PATH}/certs/ca.crt ${PKI_CONF_PATH}/certs/bundle.crt

Validation Authority

As we saw, without a Validation Authority it is not possible to verify if certificates have been revoked before their expiration date. Let's set-up the "CARC R100T" validation authority so that it provides both Indirect CRL and OCSP.

Indirect CRL Certificate

Let's generate the private key of the certificate we want to delegate for signing Certificate Revocation Lists (CRLs) - as we did before, generate and restrict access to the private key file:

touch ${PKI_CONF_PATH}/keys/va.key
chmod 400 ${PKI_CONF_PATH}/keys/va.key
chown pki: ${PKI_CONF_PATH}/keys/va.key

then generate the private key overwriting the empty file:

openssl ecparam -name secp521r1 -genkey | \
openssl ec -out ${PKI_CONF_PATH}/keys/va.key -aes256

we are ready to generate the Certificate Signing Request (CSR) to submit to the "CARC R100T" for generating the certificate: the validation rules for CRL signed by an Indirect Certificate are very strict, so, in the CSR for the Indirect Certificate, you must:

  • set the value of the DN of the delegating CA as subject DN
  • make sure that the "crlissuer" attribute in the openssl.conf file matches the same DN

In this example, the delegating CA's subject DN is:

  • Country: CH
  • Organization: Carcano SA
  • Common Name: CARC R100T

so the subject DN in the CSR must be exactly the same:

openssl req -new -key ${PKI_CONF_PATH}/keys/va.key \
-out ${PKI_CONF_PATH}/certs/va.csr \
-subj "/C=CH/O=Carcano SA/CN=CARC R100T"

We can now submit the CSR to the "CARC R100T" CA and generate the certificate:

openssl ca -batch --notext -config ${PKI_CONF_PATH}/conf/openssl.conf \
-extensions crl_issuer -days 3652 -in ${PKI_CONF_PATH}/certs/va.csr \
-out ${PKI_CONF_PATH}/certs/va.crt

it obviously asks for the password to unlock the CA's private key:

Enter pass phrase for /etc/corporate-pki/carc_r100t/keys/ca.key:

then it shows a report with the most interesting information in the issued certificate.

Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
countryName           :PRINTABLE:'CH'
organizationName      :ASN.1 12:'Carcano SA'
commonName            :ASN.1 12:'CARC R100T'
Certificate is to be certified until May 31 15:05:49 2033 GMT (3652 days)

Write out database with 1 new entries
Data Base Updated

let's have a look to this Indirect CRL certificate:

openssl x509 -in ${PKI_CONF_PATH}/certs/va.crt -noout -text

the output is as follows:

Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 4096 (0x1000)
        Signature Algorithm: ecdsa-with-SHA256
        Issuer: C = CH, O = Carcano SA, CN = CARC R100T
        Validity
            Not Before: Jun  1 15:05:49 2023 GMT
            Not After : May 31 15:05:49 2033 GMT
        Subject: C = CH, O = Carcano SA, CN = CARC R100T
        Subject Public Key Info:
            Public Key Algorithm: id-ecPublicKey
                Public-Key: (521 bit)
                pub:
                    04:01:3d:a5:be:b4:a7:fe:65:2e:b8:f3:df:38:9b:
                    84:55:1c:a8:58:24:52:cb:13:79:6c:1c:d3:b6:58:
                    5e:ba:9a:a0:36:7a:c9:f7:fc:6a:ab:70:80:65:dc:
                    9c:8e:24:a6:be:7b:4d:c5:ce:2a:b9:d7:38:b3:bd:
                    02:cb:73:82:ef:69:09:00:ec:2f:df:24:7d:42:2f:
                    20:55:6f:a3:a7:40:66:01:81:d5:9b:b5:8a:62:71:
                    4c:ef:85:ca:63:9d:ac:9c:ac:84:6a:3e:25:db:e4:
                    f9:ae:5b:bc:8c:e3:51:33:b6:9a:0e:73:27:d6:3b:
                    00:6b:72:96:53:c3:28:10:53:2a:db:36:eb
                ASN1 OID: secp521r1
                NIST CURVE: P-521
        X509v3 extensions:
            X509v3 Subject Key Identifier: 
                5D:A0:6D:8A:F5:D0:5D:6D:CF:B0:1D:30:8B:EA:4F:43:15:46:9A:FA
            X509v3 Authority Key Identifier: 
                B5:26:F1:34:F7:C6:51:A7:F3:01:73:9F:28:16:8B:F3:A0:E8:9F:65
            X509v3 Key Usage: critical
                Digital Signature, Non Repudiation, Key Encipherment, CRL Sign
            X509v3 Basic Constraints: critical
                CA:FALSE
            X509v3 Extended Key Usage: 
                OCSP Signing
    Signature Algorithm: ecdsa-with-SHA256
    Signature Value:
        30:81:88:02:42:00:e1:9e:cf:17:a5:93:ef:b5:76:f2:a6:03:
        29:dd:25:2a:b4:ba:65:58:d8:2a:8e:78:e6:09:d0:af:ca:c6:
        68:3b:f0:cd:6c:ab:a1:32:77:93:d1:ef:29:94:d7:22:86:ed:
        9e:d1:de:ac:3a:50:63:8b:6c:b4:00:d5:97:fb:d3:d5:a1:02:
        42:01:5d:54:33:9f:05:5f:9d:31:13:21:d8:08:f0:fc:10:74:
        17:94:f9:1c:fd:02:33:1d:32:85:b1:61:15:d2:e0:a8:d8:34:
        2b:aa:1e:ce:eb:4f:7f:c1:d9:94:64:59:5e:d9:24:0c:36:09:
        91:93:cf:7e:e2:1a:48:79:26:3e:c1:fc:ab

OCSP Responder

As we saw, OCSP is a more modern and better performing way of providing information about certificates revocations.

The OpenSSL OCSP has not been designed to handle large Certificate Authorities' workloads - The openssl-ocsp man page says "The text index file format of revocation is also inefficient for large quantities of revocation data". What is shown here can be used to set up quite small corporate Certificate Authorities to be used as Labs to experiment with certificates and PKI. If you need something more reliable, consider using OpenXPKI or Cloudlfare's PKI and TLS Toolkit.

To implement an OCSP responder for the "CARC R100T CA", proceed as follows:

Create the directory where to store the OCSP responder log files:

mkdir -m 750 /var/log/corporate-pki
chown pki: /var/log/corporate-pki

set up the "ocsp" Systemd service unit template - create the "/etc/systemd/system/ocsp@.service" wit the following contents

[Unit]
Description=%i OCSP responder
After=syslog.target network-online.target

[Service]
Type=simple
User=pki
Group=pki
EnvironmentFile=/etc/sysconfig/ocsp-%i
ExecStart=/bin/openssl ocsp -text -port ${PORT} -index ${INDEX} -CA ${BUNDLE} -rkey ${KEY} -rsigner ${CERT} -out ${LOG}

[Install]
WantedBy=multi-user.target

reload Systemd to publish the new Systemd unit template:

systemctl daemon-reload

configure the "/etc/sysconfig/ocsp-carc_r100t" containing settings specific to the "CARC R100T" CA:

PORT=8889
INDEX=/var/lib/corporate-pki/carc_r100t/db/index.txt
BUNDLE=/etc/corporate-pki/ca/carc_r100t/certs/bundle.crt
KEY=/etc/corporate-pki/ca/carc_r100t/keys/va.key
CERT=/etc/corporate-pki/ca/carc_r100t/certs/va.crt
LOG=/var/log/corporate-pki/ocsp-carc_r100t.log

we can finally enable to start at boot the "CARC R100T"'s OCSP responder, starting it immediately too:

systemctl enable --now ocsp@carc_r100t

Setup The Intermediate CA

As we saw in the previous post “X509 Certificates HowTo - A Public Key Infrastructure Tutorial”, a Root Certificate Authority, besides issuing infrastructural certificates such as the ones used to sign CRLs and OCSP responses, is supposed to issue only Intermediate CA's certificates.

In this example we are creating the "CARC I100T" Intermediate Certificate Authority as follows:

  • Name: CARC I100T
  • Label: carc-i100t
  • Enterprise OID: 1234
  • Organization: Carcano SA
  • Country: CH
  • CA issuers URL: http://ca.test.carcano.local/carc_i100t.cer
  • Certificate Practice Statement URL: http://www.carcano.local/ca/cps.html
  • CRL Endpoint URL: http://www.test.carcano.local/crl/carc_i100t.crl
  • OCSP Responder URL: http://ocsp.test.carcano.local:8890

As we did with the Root CA, let's create its directory trees structures and configuration files by using the automation script we developed:

/usr/local/bin/corporate-pki-newca.sh --ca-name "CARC I100T" \
--ca-label carc_i100t --enterprise-oid 1234 --organization "Carcano SA" --country CH \
--crl-url "http://www.test.carcano.local/crl/carc_i100t.crl" \
--ocsp-url "http://ocsp.test.carcano.local:8890" \
--ca-issuers "http://ca.test.carcano.local/carc_i100t.cer" \
--cps-url "http://www.carcano.local/ca/cps.html" \
--root-ca-label carc_r100t

note how this time we also supplied the "--root-ca-label" to have the script generating an OpenSSL configuration file suitable for an Intermediate Certificate Authority.

The value of the "--root-ca-label" parameter is not actually used in this version of the script: I made it like so to ease the improvement of the script adding the capability of generating key and certificates, ... a feature I couldn't add in this post because with a full automation there wouldn't have been statements to explain and so I wouldn't have anything to explain about the process.

Sign The Intermediate CA Certificate

As we did for the Root CA's certificate, we need to generate a private key - as we did before, create  the key file and restrict access permissions:

CA_LABEL="carc_i100t"
PKI_CONF_PATH="/etc/corporate-pki/ca/${CA_LABEL}"
touch ${PKI_CONF_PATH}/keys/ca.key
chmod 400 ${PKI_CONF_PATH}/keys/ca.key
chown pki: ${PKI_CONF_PATH}/keys/ca.key

then generate the private key, overwriting the secured key file:

openssl ecparam -name secp521r1 -genkey | \
openssl ec -out ${PKI_CONF_PATH}/keys/ca.key -aes256

of course we are asked for the password we want to use to encrypt the private key.

Conversely from the Root CA's certificate, the Intermediate CA's certificate must be signed by another Certificate Authority.

For this reason we need to generate a Certificate Signing Request to submit to the "CARC R100T" Root CA.

The subject DN for this Intermediate CA is:

  • Country: CH
  • Organization: Carcano SA
  • Common Name: CARC I100T

To generate the CSR, type the following statement:

openssl req -new -key ${PKI_CONF_PATH}/keys/ca.key \
-out ${PKI_CONF_PATH}/certs/ca.csr \
-subj "/C=CH/O=Carcano SA/CN=CARC I100T"

Now, let's submit the CSR to the "CARC R100T" Root CA:

ISSUING_CA="/etc/corporate-pki/ca/carc_r100t"
openssl ca -batch --notext -config ${ISSUING_CA}/conf/openssl.conf \
-extensions intermediate_ca -days 1826 \
-in ${PKI_CONF_PATH}/certs/ca.csr \
-out ${PKI_CONF_PATH}/certs/ca.crt

let's have a look to the issued certificate:

openssl x509 -noout -text -in ${PKI_CONF_PATH}/certs/ca.crt

the output is as follows:

Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 4097 (0x1001)
        Signature Algorithm: ecdsa-with-SHA256
        Issuer: C = CH, O = Carcano SA, CN = CARC R100T
        Validity
            Not Before: Jun  1 15:10:46 2023 GMT
            Not After : May 31 15:10:46 2028 GMT
        Subject: C = CH, O = Carcano SA, CN = CARC I100T
        Subject Public Key Info:
            Public Key Algorithm: id-ecPublicKey
                Public-Key: (521 bit)
                pub:
                    04:01:fb:76:05:1a:41:41:e9:90:f9:a3:d0:01:bd:
                    8f:9c:3a:02:90:7a:80:ee:99:cd:7e:26:e1:a3:e7:
                    6f:c3:9f:fc:ea:d6:bf:38:6c:c7:5a:41:0c:bd:ec:
                    32:ee:6b:93:02:d7:b4:3b:4f:5b:9c:b9:d7:38:7e:
                    b3:9e:6c:f2:4f:ef:20:00:f6:c1:f6:07:e6:9b:38:
                    30:97:e2:ce:b5:e6:9d:f4:71:75:4a:70:44:86:36:
                    fc:82:a5:8a:5d:be:61:a1:1d:66:b2:f6:94:27:98:
                    48:9c:29:05:1e:a5:a6:31:4e:e6:78:81:4d:ea:49:
                    7f:fa:77:7a:a2:be:29:18:1e:c0:b8:8d:4f
                ASN1 OID: secp521r1
                NIST CURVE: P-521
        X509v3 extensions:
            X509v3 Subject Key Identifier: 
                86:9C:25:A8:77:A2:7B:B7:18:5D:1F:A9:9E:4E:AC:E6:76:17:60:DB
            X509v3 Authority Key Identifier: 
                B5:26:F1:34:F7:C6:51:A7:F3:01:73:9F:28:16:8B:F3:A0:E8:9F:65
            X509v3 Basic Constraints: critical
                CA:TRUE
            X509v3 Key Usage: critical
                Certificate Sign, CRL Sign
            X509v3 CRL Distribution Points: 
                Full Name:
                  URI:http://www.test.carcano.local/crl/carc_r100t.crl                CRL Issuer:
                  DirName:C = CH, O = Carcano SA, CN = CARC R100T
            Authority Information Access: 
                OCSP - URI:http://ocsp.test.carcano.local:8889
                CA Issuers - URI:http://ca.test.carcano.local/carc_r100t.cer
            X509v3 Certificate Policies: 
                Policy: 1.3.6.1.4.1.1234.1.1
                  CPS: http://www.carcano.local/ca/cps.html
                  User Notice:
                    Explicit Text: CARC R100T Certification Practice Statement
                Policy: 1.3.6.1.4.1.1234.1.2
                  User Notice:
                    Explicit Text: CA Certificate Policy
                Policy: 2.23.140.1.1
                  User Notice:
                    Explicit Text: Certificate issued in compliance with the Extended Validation Guidelines
    Signature Algorithm: ecdsa-with-SHA256
    Signature Value:
        30:81:88:02:42:01:d9:51:72:92:a5:c0:3f:03:5e:1c:74:2c:
        db:f2:66:6c:68:82:89:c1:e7:d3:11:e2:83:c2:a2:97:29:7c:
        05:2d:65:24:d8:aa:4e:cb:93:51:e0:f1:ce:d1:72:07:2c:8f:
        fb:fa:34:d8:6f:f7:36:22:bf:3e:63:76:ce:b2:77:b9:a7:02:
        42:00:94:cb:c5:e7:26:d9:e9:dd:8c:b9:88:4e:62:7a:0b:a5:
        a9:42:2e:2d:1f:17:52:3e:20:20:bb:ed:5b:f2:81:5e:c4:88:
        9c:71:c9:b4:76:4a:06:d3:15:e7:f8:20:2f:63:81:3e:24:bf:
        b7:1f:75:b4:95:c6:83:38:ff:dc:4e:21:31
We have just generated an intermediate CA certificate: the best practice is to securely off-line storing the Root CA private key  now and bring it back online only when it comes to sign new intermediate CA certificates or renew already issued certificates. Offline storing means copying the private key to a secure offline storage (such as a PKCS#11 hardware token) and store it in a secure remote location such as a safety deposit box in a bank. As for the private key on the file system, just deleting it is not enough: you must shred it.

Generate the CA's bundle certificate file with the trust-chain for the CA's certificate:

cp ${ISSUING_CA}/certs/ca.crt ${PKI_CONF_PATH}/certs/bundle.crt
cat ${PKI_CONF_PATH}/certs/ca.crt >> ${PKI_CONF_PATH}/certs/bundle.crt

Validation Authority

It's now time to se up the CARC I100T  Validation Authority.

Indirect CRL Certificate

Let's generate the private key of the certificate we want to delegate for signing Certificate Revocation Lists (CRLs) - as we did before, generate and restrict access to the private key file:

touch ${PKI_CONF_PATH}/keys/va.key
chmod 400 ${PKI_CONF_PATH}/keys/va.key
chown pki: ${PKI_CONF_PATH}/keys/va.key

then generate the private key overwriting the empty file:

openssl ecparam -name secp521r1 -genkey | \
openssl ec -out ${PKI_CONF_PATH}/keys/va.key -aes256

we are ready to generate the Certificate Signing Request (CSR) to submit to the "CARC I100T" for generating the certificate.

The attributes are:

  • Country: CH
  • Organization: Carcano SA
  • Common Name: CARC I100T
openssl req -new -key ${PKI_CONF_PATH}/keys/va.key \
-out ${PKI_CONF_PATH}/certs/va.csr \
-subj "/C=CH/O=Carcano SA/CN=CARC I100T"

We can now submit the CSR to the CARC I100T CA and generate the certificate:

openssl ca -batch --notext -config ${PKI_CONF_PATH}/conf/openssl.conf \
-extensions crl_issuer -days 1826 \
-in ${PKI_CONF_PATH}/certs/va.csr -out ${PKI_CONF_PATH}/certs/va.crt

it obviously asks us for the password to unlock CARC I100T's private key:

Enter pass phrase for /etc/corporate-pki/carc_i100t/keys/ca.key:

then it shows a report with the most interesting information in the issued certificate.

OCSP Responder

As we saw, OCSP is a more modern and better performing way of providing information about certificates revocations.

It is enough to configure a new instance of the "ocsp" systemd unit:

Configure the "/etc/sysconfig/ocsp-carc_i100t" containing settings specific to the "CARC I100T" CA

PORT=8890
INDEX=/var/lib/corporate-pki/carc_i100t/db/index.txt
BUNDLE=/etc/corporate-pki/ca/carc_i100t/certs/bundle.crt
KEY=/etc/corporate-pki/ca/carc_i100t/keys/va.key
CERT=/etc/corporate-pki/ca/carc_i100t/certs/va.crt
LOG=/var/log/corporate-pki/ocsp-carc_i100t.log

we can finally enable to start at boot the "CARC I100T"'s OCSP responder, starting it immediately too:

systemctl enable --now ocsp@carc_i100t

Entity Certificates

We are finally ready to request the issuing of entity certificates - we are going to request an Extended Validated Certificate

Generate the private key:

openssl ecparam -name secp384r1 -genkey \
| openssl ec -out /tmp/foo.key -aes256

then, generate the CSR - in this example we are requesting the issuing a certificate with the following attributes:

  • Country: CH
  • Organization: Carcano SA
  • Common Name: foor.org
  • Subject Alternatives Names:
    • foo.org
    • www.foo.org
    • mail.foo.org
    • 10.21.34.52
openssl req -new -key /tmp/foo.key -out /tmp/foo.csr \
-subj "/C=CH/O=Carcano SA/CN=foo.org" \
-addext "subjectAltName = DNS:foo.org, DNS:www.foo.org, DNS:mail.foo.org, IP:10.21.34.52"

submit the CSR to the CARC I100T CA to get the signed certificate - in this example it is valid for 397 days:

openssl ca -batch --notext -config ${PKI_CONF_PATH}/conf/openssl.conf \
-extensions ev -days 397 -in /tmp/foo.csr -out /tmp/foo.crt

let's have a closer look to it:

openssl x509 -noout -text -in /tmp/foo.crt 

it must look like as follows:

Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 4097 (0x1001)
        Signature Algorithm: ecdsa-with-SHA256
        Issuer: C = CH, O = Carcano SA, CN = CARC I100T
        Validity
            Not Before: Jun  1 15:14:22 2023 GMT
            Not After : Jul  2 15:14:22 2024 GMT
        Subject: C = CH, O = Carcano SA, CN = foo.org
        Subject Public Key Info:
            Public Key Algorithm: id-ecPublicKey
                Public-Key: (384 bit)
                pub:
                    04:be:7e:32:4e:40:9f:13:9a:45:17:cc:62:b3:ca:
                    01:c2:24:d6:0e:08:1a:6f:14:2a:a2:73:97:50:6e:
                    f3:7a:a0:af:57:76:63:17:16:2d:7c:b7:9d:07:88:
                    6d:34:bb:96:b8:ee:2d:0c:2e:76:05:d4:5e:b7:a6:
                    87:1d:5d:d4:60:48:63:79:83:eb:b4:c7:13:6a:b0:
                    ed:95:ad:38:9c:cd:41:49:ba:f0:4f:21:64:a2:30:
                    0f:96:8c:f3:58:13:30
                ASN1 OID: secp384r1
                NIST CURVE: P-384
        X509v3 extensions:
            X509v3 Subject Key Identifier: 
                75:15:D7:14:DC:06:98:E2:1F:12:92:8D:F0:0C:EB:7F:D2:61:56:37
            X509v3 Authority Key Identifier: 
                86:9C:25:A8:77:A2:7B:B7:18:5D:1F:A9:9E:4E:AC:E6:76:17:60:DB
            X509v3 Basic Constraints: critical
                CA:FALSE
            X509v3 Key Usage: critical
                Digital Signature, Key Encipherment
            X509v3 Extended Key Usage: critical
                TLS Web Server Authentication
            X509v3 CRL Distribution Points: 
                Full Name:
                  URI:http://www.test.carcano.local/crl/carc_i100t.crl                CRL Issuer:
                  DirName:C = CH, O = Carcano SA, CN = CARC I100T
            Authority Information Access: 
                OCSP - URI:http://ocsp.test.carcano.local:8890
                CA Issuers - URI:http://ca.test.carcano.local/carc_i100t.cer
            X509v3 Certificate Policies: 
                Policy: 1.3.6.1.4.1.1234.1.1
                  CPS: http://www.carcano.local/ca/cps.html
                  User Notice:
                    Explicit Text: CARC I100T Certification Practice Statement
                Policy: 2.23.140.1.1
                  User Notice:
                    Explicit Text: Certificate issued in compliance with the Extended Validation Guidelines
    Signature Algorithm: ecdsa-with-SHA256
    Signature Value:
        30:81:88:02:42:01:fd:9e:91:fb:42:67:6a:68:1e:c2:c9:67:
        2e:99:6b:aa:b0:9e:8b:10:91:fd:1f:d5:aa:8a:22:22:c8:ac:
        ab:51:91:55:d7:da:45:42:d1:e3:1c:a7:53:8c:cd:aa:39:64:
        9f:e8:38:05:55:3b:c5:57:fa:f3:d2:ef:28:9a:9e:07:88:02:
        42:01:b8:75:f8:18:d3:d9:34:a1:76:4a:a6:02:d4:e8:18:fa:
        8c:2e:58:25:fd:ea:03:99:3c:a8:dd:ba:15:57:d4:40:16:91:
        0b:13:1e:46:95:ed:e1:8a:c2:7f:8b:75:9f:6f:e8:e9:ee:ff:
        e5:3d:02:09:c4:aa:d2:c6:17:49:96:4d:bc

Renewing The Certificate Authority's Certificate

Renewing the Certificate Authorities' certificates is a very delicate task: in the ideal world, you must avoid issuing entity certificates that expires after the expiration date of the CA's certificate itself: in such scenario everything is simple - you simply create the new CA's certificates and deliver them to the trust-stores of your systems.

In the real world, ... often things are not tidy at all - as every IT professionals know, very often you have to administer infrastructures designed and maintained by who was here before, ... that maybe had the very bad habit of designing and delivering quick and dirty (quick and dirty is good only during emergency fixes, otherwise you are just accumulating technical debts), or that improvise on everything claiming they are doing thing the Agile way - by the way, have a look to my post on Agile, SCRUM and Lean the proper way.

Reissuing Existing CA's Certificates

Reissuing the exiting CA's certificate's is necessary when you have leaf certificates that expires after the expiration date of the CA's certificate.

Root CA

You must issue a new certificate that matches the current one, but with a new expiration date.

This means that you need to:

  • use the same private key,
  • specify the same subject string
  • add the same X509v3 extensions

Let's start by renaming the current certificate so that we can easily rollback if necessary.

CA_LABEL="carc_r100t"
PKI_CONF_PATH="/etc/corporate-pki/ca/${CA_LABEL}"
mv ${PKI_CONF_PATH}/certs/ca.crt ${PKI_CONF_PATH}/certs/ca.crt.bak

If you don't have the Certificate Signing Request (CSR) you used to create the current certificate, re-create it as follows, otherwise skip this step.

openssl req -new -key ${PKI_CONF_PATH}/keys/ca.key \
-out ${PKI_CONF_PATH}/certs/ca.csr \
-subj "/C=CH/O=Carcano SA/CN=CARC R100T"

Mind to specify the same subject string of the current certificate - an alternate way is to run the following statement:

openssl x509 -x509toreq -in ${PKI_CONF_PATH}/certs/ca.crt.bak \
-signkey ${PKI_CONF_PATH}/keys/ca.key \
-out ${PKI_CONF_PATH}/certs/ca.csr

Generate the new certificate as follows:

openssl x509 -req -extfile ${PKI_CONF_PATH}/conf/openssl.conf \
-extensions root_ca -days 3652 \
-key ${PKI_CONF_PATH}/keys/ca.key \
-in ${PKI_CONF_PATH}/certs/ca.csr \
-out ${PKI_CONF_PATH}/certs/ca.crt

generate the CA bundle with the Root CA's certificate:

cp ${PKI_CONF_PATH}/certs/ca.crt ${PKI_CONF_PATH}/certs/bundle.crt

It is critical to verify that the new certificate can be used to validate a certificate that was signed using the old one - here we verify that the new certificate can be used to validate the "CARC I100T" intermediate CA's certificate:

openssl verify -CAfile ${PKI_CONF_PATH}/certs/bundle.crt /etc/corporate-pki/ca/carc_i100t/certs/ca.crt

if everything is properly working, you must get the following message:

/etc/corporate-pki/ca/carc_i100t/certs/ca.crt: OK

otherwise, if you get the following message:

C = CH, O = Carcano SA, CN = CARC I100T
error 31 at 0 depth lookup: authority and issuer serial number mismatch
error /etc/corporate-pki/ca/carc_i100t/certs/ca.crt: verification failed

you are very out of luck: it means that the certificate you want to verify in the Authority Key Identifier x509v3 extension has a serial number that does not match with the one of the CA's new certificate (this happens when it is specified "issuer" among the values of the authorityKeyIdentifier x509v3 extension).

In such a scenario, ... you have no other way out of re-do everything from scratch, reissuing all the intermediate and entity certificates, and of course delivering them to their consumer.

Intermediate CA

When it comes to re-issue intermediate CA's certificates, you can exploit cross-signing: simply put, you re-issue the current intermediate certificate submitting it to another trusted Certificate Authority that expires later than the entity certificates already issued by the intermediate CA's current certificate.

If you don't have such a Root CA to exploit for this, you just have to create a new one and deliver its certificate to the TrustStore of your systems, along with the newly issued intermediate CA's certificate.

In this example, we create the following new Root CA:

  • Name: CARC R101T
  • Label: carc-r101t
  • Enterprise OID: 1234
  • Organization: Carcano SA
  • Country: CH
  • CA issuers URL: http://ca.test.carcano.local/carc_r101t.cer
  • Certificate Practice Statement URL: http://www.carcano.local/ca/cps.html
  • CRL Endpoint URL: http://www.test.carcano.local/crl/carc_r101t.crl
  • OCSP Responder URL: http://ocsp.test.carcano.local:8888

Let's create its directory tree and configuration files using the automation script we developed:

/usr/local/bin/corporate-pki-newca.sh --ca-name "CARC R101T" \
--ca-label carc_r101t --enterprise-oid 1234 --organization "Carcano SA" --country CH \
--crl-url "http://www.test.carcano.local/crl/carc_r101t.crl" \
--ocsp-url "http://ocsp.test.carcano.local:8888" \
--ca-issuers "http://ca.test.carcano.local/carc_r101t.cer" \
--cps-url "http://www.carcano.local/ca/cps.html"

As we already did, we generate the key as an empty file and immediately restrict access to it:

CA_LABEL="carc_r101t"
PKI_CONF_PATH="/etc/corporate-pki/ca/${CA_LABEL}"
touch ${PKI_CONF_PATH}/keys/ca.key
chmod 400 ${PKI_CONF_PATH}/keys/ca.key
chown pki: ${PKI_CONF_PATH}/keys/ca.key

then generate the private key overwriting the empty file:

openssl ecparam -name secp521r1 -genkey | \
openssl ec -out ${PKI_CONF_PATH}/keys/ca.key -aes256

as usual we are asked for the password we want to use to encrypt the private key.

Create the Certificate Signing Request (CSR) with the following data:

  • Certificate Lifetime: 3652 days (10 years)
  • Country: CH
  • Organization: Carcano SA
  • Common Name: CARC R101T
openssl req -new -key ${PKI_CONF_PATH}/keys/ca.key \
-out ${PKI_CONF_PATH}/certs/ca.csr \
-subj "/C=CH/O=Carcano SA/CN=CARC R101T"

Then, we generate the CA Certificate from the CSR, signing it with the same key used for the CSR:

openssl x509 -req -extfile ${PKI_CONF_PATH}/conf/openssl.conf \
-extensions root_ca -days 3652 \
-key ${PKI_CONF_PATH}/keys/ca.key \
-in ${PKI_CONF_PATH}/certs/ca.csr \
-out ${PKI_CONF_PATH}/certs/ca.crt
Complete the task creating the Validation Authority with the CRL and OCSP Responder - I won't explicitly the steps here since we have thoroughly explained this topic previously.

we are finally ready to re-issue the current "CARC I100T" intermediate CA's certificate.

As a safety measure, we make a backup copy of the current certificate:.

CA_LABEL="carc_i100t"
PKI_CONF_PATH="/etc/corporate-pki/ca/${CA_LABEL}"
mv ${PKI_CONF_PATH}/certs/ca.crt ${PKI_CONF_PATH}/certs/ca.crt.bak
mv ${PKI_CONF_PATH}/certs/bundle.crt ${PKI_CONF_PATH}/certs/bundle.crt.bak

Then, if you don't already have it, re-generate the CSR with the following statement:

openssl x509 -x509toreq -in ${PKI_CONF_PATH}/certs/ca.crt.bak -signkey ${PKI_CONF_PATH}/keys/ca.key \ -out ${PKI_CONF_PATH}/certs/ca.csr

Then, submit the CSR to the "CARC R101T" Root CA:

ISSUING_CA="/etc/corporate-pki/ca/carc_r101t"
openssl ca --notext -batch -config ${ISSUING_CA}/conf/openssl.conf \
-extensions intermediate_ca -days 1826 \
-in ${PKI_CONF_PATH}/certs/ca.csr \
-out ${PKI_CONF_PATH}/certs/ca.crt

generate a new CA bundle with the Root CA's and the new Intermediate CA's certificates:

cp ${PKI_CONF_PATH}/certs/ca.crt ${PKI_CONF_PATH}/certs/bundle.crt
cat ${ISSUING_CA}/certs/ca.crt >> ${PKI_CONF_PATH}/certs/bundle.crt

Again, it is critical to verify that the new certificate can be used to validate a certificate that was signed using the old one - here we verify that the new intermediate certificate can be used to validate the certificate we issued before for "foo.org":

openssl verify -CAfile ${PKI_CONF_PATH}/certs/bundle.crt /tmp/foo.crt

if everything is properly working, you must get the following message:

/tmp/foo.crt: OK
I saw a lot of tutorials claiming that is is best to bundle servers' certificates along with the issuing CA's certificate, and then configure the application to use it for the TLS endpoint - This is not true: it is necessary to bundle them only if for any reason the intermediate certificate can not distributed to every client accessing that service. Anyway, the tradeoff is that this kind of setup prevents cross-signing. For example, a web server providing not only the server's certificate, but also the Intermediate CA's certificate that signed it, is actually forcing a trust-path to the Root CA Certificate: this causes any new cross-signed Intermediate CA's certificate to be considered untrusted, and so not valid.

Footnotes

Here it ends this post dedicated to how to set-up a full-featured Public Key Infrastructure with OpenSSL: we made a complex Lab following the best practices for PKI and certificates, setting up indirect CRLs and OCSP responders. In the next post we will see how to generate the CRL and validate the certificate's revocation status using the CRL and the OCSP responders.

Writing a post like this takes a lot of hours. I'm doing it for the only pleasure of sharing knowledge and thoughts, but all of this does not come for free: it is a time consuming volunteering task. This blog is not affiliated to anybody, does not show advertisements nor sells data of visitors. The only goal of this blog is to make ideas flow. So please, if you liked this post, spend a little of your time to share it on Linkedin or Twitter using the buttons below: seeing that posts are actually read is the only way I have to understand if I'm really sharing thoughts or if I'm just wasting time and I'd better give up

As we saw in our post on Symmetric And Asymmetric Cryptography, asymmetric key pairs can be used to encrypt and digitally sign documents, but have a huge shortcoming: since they are just keys, they don't provide the metadata necessary to enable people to securely identify their owner. As we saw in the post on GNU Pretty-Good Privacy, GPG addresses this shortcoming by wrapping the key into a container object (the GPG key) that also embeds some metadata about the owner of the key. Of course also the IETF addressed this problem, defining the standard for X.509 certificates (currently X.509v3). X509 Certificates Howto & Public Key Infrastructure Tutorial explores X.509 certificates and how they are trusted by the means of a Public Key Infrastructure.

X.509 Certificates

The X.509 is the part of the X.500 standard (the old fashioned DAP) that deals with authentication - that part of the standard has been taken outside its initial scope to be used to create documents that provide an identity string.
A certificate however contains a lot of metadata: when using openssl, you can easily print the contents of an X.509 certificate into human readable format by using the "x509" subcommand with the "-text" option.

For example, to print the contents of the "/tmp/foo.crt" certificate, type:

openssl x509 -noout -text -in /tmp/foo.crt

an example output is as follows:

Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 4098 (0x1002)
        Signature Algorithm: ecdsa-with-SHA256
        Issuer: C = CH, ST = Tessin, O = Carcano SA, CN = CARC I100T
        Validity
            Not Before: May  2 05:00:31 2023 GMT
            Not After : May  1 05:00:31 2024 GMT
        Subject: C = CH, ST = Tessin, O = Carcano SA, CN = www.baz.org
        Subject Public Key Info:
            Public Key Algorithm: id-ecPublicKey
                Public-Key: (256 bit)
                pub:
                    04:73:df:7c:ec:a7:00:52:ea:43:f2:f1:c4:9f:7f:
                    08:d3:04:d3:70:2b:2b:0c:75:43:eb:12:b4:35:ca:
                    24:91:09:0a:d7:9a:5f:b2:f9:4f:57:7c:62:75:ce:
                    b9:1c:c0:a2:55:15:0e:d4:09:9f:15:cb:40:00:48:
                    2c:8a:cf:33:55
                ASN1 OID: prime256v1
                NIST CURVE: P-256
        X509v3 extensions:
            X509v3 Subject Key Identifier: 
                89:5D:31:70:B7:26:4B:5F:D4:F0:83:FF:F6:52:A0:51:77:70:D5:78
            X509v3 Subject Alternative Name: 
                DNS:www.baz.org, DNS: baz.org
            X509v3 Authority Key Identifier: 
                keyid:0B:E7:E4:44:B4:9D:C6:FF:65:96:36:8E:CE:63:4D:D7:43:BF:26:77
                DirName:/C=CH/ST=Tessin/O=Carcano SA/CN=CARC R100T
                serial:10:01
            X509v3 Basic Constraints: critical
                CA:FALSE
            X509v3 Key Usage: critical
                Digital Signature, Key Encipherment
            X509v3 Extended Key Usage: critical
                TLS Web Server Authentication
            X509v3 CRL Distribution Points: 
                Full Name:
                  URI:http://www.test.carcano.local/crl/carc_i100t.crl                CRL Issuer:
                  DirName:C = CH, ST = Tessin, O = Carcano SA, CN = CARC I100T
            Authority Information Access: 
                OCSP - URI:http://ocsp.test.carcano.local:8889
                CA Issuers - URI:http://ca.test.carcano.local/carc_r100t.cer
            X509v3 Certificate Policies: 
                Policy: 1.3.6.1.4.1.1234.1.1
                  CPS: http://www.carcano.local/ca/cps.html
                  User Notice:
                    Explicit Text: Carcano SA Certification Practice Statement
                Policy: 2.23.140.1.1
                  User Notice:
                    Explicit Text: Extended Validated
    Signature Algorithm: ecdsa-with-SHA256
    Signature Value:
        30:81:88:02:42:01:1f:d0:b4:d8:ed:f3:4f:ba:eb:77:d3:b6:
        02:ac:b0:75:e7:30:5d:66:65:78:5f:f3:84:19:0a:f5:5e:17:
        4a:6d:53:85:ff:8a:2f:15:22:75:92:bc:1e:8f:7b:97:6e:77:
        9e:9f:f5:8e:cb:74:6b:13:2d:3e:0e:14:cf:f1:4b:1f:e1:02:
        42:00:83:ae:e0:75:f5:37:eb:f7:ff:cc:86:c0:cb:32:b3:8b:
        9e:76:e1:52:96:0e:4d:2d:69:98:16:74:ee:08:ea:33:18:7a:
        41:73:6c:c3:16:2a:5d:b0:b3:28:a1:c7:1f:63:13:39:cc:c6:
        35:21:da:cc:c2:e6:6d:c0:d9:e9:cd:6f:91

The above one is a private certificate issued by a private Certificate Authority: it is a very nicely structured certificate, since it contains the very most of the x509v3 extensions you may find on certificates when working. For this reason, we will refer to its contents along all this post.

The Subject

The subject is the string that provides the identity inside the certificate. Since it is derived from the X.500, the tokens in the subject string strongly recall the names of some LDAP attributes:

  • C: Country
  • S: State
  • L: Location
  • O: Organization
  • OU: Organisational Unit
  • Common Name: the actual identity of the X.509 object

For the same reason, the format relies on ASN.1 syntax.

The Subject is printed among the textual information of the certificate.

In our example certificate, it is:

        Subject: C = CH, ST = Tessin, O = Carcano SA, CN = www.baz.org

Some special certificates such as Extended Validation certificates or Organization Validated certificates, may provide additional attributes that help to better identify the subject, such as:

  • jurisdictionOfIncorporationCountryName (OID: 1.3.6.1.4.1.311.60.2.1.3)
  • jurisdictionOfIncorporationStateOrProvinceName (OID: 1.3.6.1.4.1.311.60.2.1.2)
  • jurisdictionOfIncorporationLocalityName (OID: 1.3.6.1.4.1.311.60.2.1.1)
  • businessCategory (OID: 2.5.4.15)
  • serialNumber (OID: 2.5.4.5)
  • streetAddress (OID: 2.5.4.9)
  • postalCode (OID: 2.5.4.17)
The Object IDentifier (OID) is an unambiguous, long-term name for any type of object or entity: it finds application in diverse scenarios, particularly in security, and is endorsed by the International Telecommunication Union (ITU), the Internet Engineering Task Force (IETF), and ISO. When applied to digital certificates, it is possible to use custom OID to extend the range of attributes that can be put inside the certificate.

The Public Key

A certificate contains the public key of an asymmetric key-pair: since this key is a public object, it is perfectly safe to add it to the certificate: the public key attached to the certificate is then exploited to perform cryptographic tasks such as encipherment and verification of digital signatures.

The Public Key is printed among the textual information of the certificate. In the example certificate it is as follows:
        Subject Public Key Info:
            Public Key Algorithm: id-ecPublicKey
                Public-Key: (256 bit)
                pub:
                    04:73:df:7c:ec:a7:00:52:ea:43:f2:f1:c4:9f:7f:
                    08:d3:04:d3:70:2b:2b:0c:75:43:eb:12:b4:35:ca:
                    24:91:09:0a:d7:9a:5f:b2:f9:4f:57:7c:62:75:ce:
                    b9:1c:c0:a2:55:15:0e:d4:09:9f:15:cb:40:00:48:
                    2c:8a:cf:33:55
                ASN1 OID: prime256v1
                NIST CURVE: P-256

The Signature (Signed or Self-Signed Certificates)

Digital Certificates are pretty similar to real life certificates:

  • as in real life, the certificate must be signed
  • as in real life, you can self sign a certificate

As in real life, self signed certificates are issued by the subject itself, whereas third party certificates are issued by Authorities: when talking about digital certificates, the authority is called Certificate Authority - CA for short.

The certificate signature is printed among the textual information of the certificate. In the example certificate it is as follows:
    Signature Algorithm: ecdsa-with-SHA256
    Signature Value:
        30:81:88:02:42:01:1f:d0:b4:d8:ed:f3:4f:ba:eb:77:d3:b6:
        02:ac:b0:75:e7:30:5d:66:65:78:5f:f3:84:19:0a:f5:5e:17:
        4a:6d:53:85:ff:8a:2f:15:22:75:92:bc:1e:8f:7b:97:6e:77:
        9e:9f:f5:8e:cb:74:6b:13:2d:3e:0e:14:cf:f1:4b:1f:e1:02:
        42:00:83:ae:e0:75:f5:37:eb:f7:ff:cc:86:c0:cb:32:b3:8b:
        9e:76:e1:52:96:0e:4d:2d:69:98:16:74:ee:08:ea:33:18:7a:
        41:73:6c:c3:16:2a:5d:b0:b3:28:a1:c7:1f:63:13:39:cc:c6:
        35:21:da:cc:c2:e6:6d:c0:d9:e9:cd:6f:91
If you want more information on symmetric and asymmetric keys and how to operate and manage them, please read "Cryptography Quick Guide - Understanding Symmetric And Asymmetric Cryptography And How To Use It With Openssl".

The Issuer

As we said, the certificate can be issued either by the subject itself - it is a self-signed certificate in this case - or by a third part subject.

The certificate issuer is printed among the textual information of the certificate. In the example certificate it is as follows:
        Issuer: C = CH, ST = Tessin, O = Carcano SA, CN = CARC I100T

The Life Time

Same way as in real life, an X.509 is valid from the date it is signed for the requested amount of time, ... typically days or years - this is actually the lifetime of the certificate: when expired, the certificate is no longer valid.

The certificate lifetime is printed among the textual information of the certificate. In the example certificate it is as follows:
        Validity
            Not Before: May  2 05:00:31 2023 GMT
            Not After : May  1 05:00:31 2024 GMT

It is straightforward that it is needed to have a way to invalidate a certificate before its expiration is reached if necessary: an example use case is if the certificate and its private key get stolen.

For this reason, two revocation status have been designed:

  • Revoked, when the revocation is permanent
  • Hold, when the revocation is temporary

If someone steals a private key, it is of course wise to revoke the certificate, but if the key is simply lost (for example for accidental deletion) it is reasonable to set it on hold for some time to see if the key gets somehow recovered for example from a backup. If the key is definitively lost, then the certificate must be marked as "revoked".

There are two different ways to verify if a certificate has been put on hold or revoked: the Client can download the Certificate Revocation List (CRL) from the CRL Distribution Point of the Certificate Authority that signed it, or it can query the online OCSP responder endpoint, directly asking the status of the certificate without having to download the whole CRL - we will see both of them in details shortly.

POlicy Constraints

The certificate explicitly claims the constraints that must be enforced when validating its extensions.

There are only two constraints:

Critical

the CA's Policy claims the condition as mandatorily required

Non Critical

the CA's Policy advise the condition as nice to be met, but not mandatory

Extensions

X.509v3 provides several extensions: here we list only the ones you are more likely to find on certificates.

Basic Constraints

Basic constraints are used to specify if the certificate is used by a Certificate Authority to sign the issued certificates, and optionally the maximum allowed distance for considering the certificate valid when validating its trust chain - we will discuss in more details the trust chain later on, when talking about the Public Key Infrastructures.

There are only two basic constraints:

  • CA: can be either "true" or "false"
  • Path-Length: it specifies how long can be the trust chain - it if it longer than specified, the certificate is marked as invalid

Of course, also Basic Constraints can be marked either Critical or Non Critical, and of course the best choice is "Critical".

The Basic Constraints extension is printed among the textual information of the certificate. In the example certificate it is as follows:
        X509v3 extensions:
            X509v3 Basic Constraints: critical
                CA:FALSE

Subject Key Identifier (SKID)

This is simply the hash of the public key attached to the certificate: it is used to be available in the certificate to easily uniquely identify the key the certificate is bound to.

The Subject Key Identifier extension is printed among the textual information of the certificate. In the example certificate it is as follows:
        X509v3 extensions:
            X509v3 Subject Key Identifier: 
                89:5D:31:70:B7:26:4B:5F:D4:F0:83:FF:F6:52:A0:51:77:70:D5:78

Authority Key Identifier (AKID)

This is used to identify the private key of the CA used to sign the certificate - a Certificate Authority can have more than just one key and certificate indeed: for example, when renewing the CA's certificate, it is both possible to re-use the same key or generate a new one.

The contained values can be any or both of the following:

  • an explicit key identifier, set in the keyIdentifier field - this is the value of the  subjectKeyIdentifier of the signer certificate, so when validating a trust chain the keyIdentifier of the certificate must match the subjectKeyIdentifier of the certificate used to sign it.
  • an issuer (set in the authorityCertIssuer field) along with the serial number identifying the signer certificate (set in the authorityCertSerialNumber field).
Mind the value of the issuer field always contains the subject of the ROOT certificate of the trust chain.
The contents of the Authority Key Identifier extension are printed among the textual information of the certificate. In the example certificate it is as follows:
        X509v3 extensions:
            X509v3 Authority Key Identifier: 
                keyid:0B:E7:E4:44:B4:9D:C6:FF:65:96:36:8E:CE:63:4D:D7:43:BF:26:77
                DirName:/C=CH/ST=Tessin/O=Carcano SA/CN=CARC R100T
                serial:10:01

Key Usage

The certificate explicitly specifies a set of purposes the key is subjected to: for example, a certificate used by a web server needs the "Digital Signature" and "Key  Encipherment".

Valid purposes are as follows:

Digital Signature

generate digital signature for entity authentication and data origin authentication with integrity

Non-Repudiation

verify digital signatures to provide a non-repudiation service

Key Encipherment

encryption of keys: used by protocols such as  SSL and S/MIME to exchange symmetric keys

Data Encipherment

encryption of data - in contrast to the previously described encryption of keys

Key Agreement

necessary when dealing with exchanging public keys to derive ephemeral keys (for example Diffie-Hellman)

Certificate Signing

the subject's public key is used to verify the signature on certificates. This extension can be used only in CA certificates

CRL Signing

the subject's public key is used to verify a signature on revocation information, such as a Certificate Revocation List (CRL)

Encipher only

the public key can be used only for enciphering data while performing key agreement - requires the Key Agreement usage to be set along with it

Decipher only

the public key can be used only for deciphering data while performing key agreement - requires the Key Agreement usage to be set along with it

Mind the specified constraint applies to the list as a whole: this means that you cannot set  a specific constraint for each single listed key usage.

The Key Usage extension is printed among the textual information of the certificate. In the example certificate it is as follows:
        X509v3 extensions:
            X509v3 Key Usage: critical
                Digital Signature, Key Encipherment

Extended Key Usage

To overcome the limitation of specifying a single constraint that affects the whole list of key usages, to better refine the key usages, they added the "Extended Key Usages" extension. This extension can. be specified multiple times, and so enables you to specify a constraint for each single occurrence.

Valid usages are as follows:

TLS Web server authentication

an alias for Digital Signature, Key Encipherment or Key Agreement 

TLS Web client authentication

an alias for Digital Signature and/or Key Agreement

Sign (downloadable) executable code

an alias for Digital Signature

Email protection

an alias for Digital Signature, Non-Repudiation, and/or Key Encipherment or Key Agreement 

IPSEC End System (host or router)

an alias for Digital Signature and/or Key Encipherment or Key Agreement

IPSEC Tunnel

an alias for Digital Signature and/or Key Encipherment or Key Agreement

IPSEC User

an alias for Digital Signature and/or Key Encipherment or Key Agreement 

Timestamping

an alias for Digital Signature, Non-Repudiation.

During validation, if a certificate contains both a critical key usage field and a critical extended key usage field, both fields must be processed independently, and the certificate be used only for a purpose consistent with both fields. If there is no purpose consistent with both fields, the certificate must not be used for any purpose.

The contents of the Extended key Usage extension is printed among the textual information of the certificate. In the example certificate it is as follows:
        X509v3 extensions:
            X509v3 Extended Key Usage: critical
                TLS Web Server Authentication
If you want more information on symmetric and asymmetric keys and how to operate and manage them, please read "Cryptography Quick Guide - Understanding Symmetric And Asymmetric Cryptography And How To Use It With Openssl".

Subject Alternate Names (SANs)

It provides a way to specify one or more alternative (non-X.500) names. It can be used in addition to the certificate's subject name.

Here you can list:

  • Internet electronic mail address (SMTP)
  • DNS name
  • IP address  (both IPv4 and IPv6)
  • uniform resource identifier (URI)

Despite the old RFC-5280 states the SubjectAlternateName is an optional add-on, and so both the CN and SubjectAlternateName were checked, the more recent RFC 6125, published in 2011, says that if the SANs is present, then the validator must check SAN first and skip validating the CN.

The consequence is that you must alway put the value in the CN inside the list of SubjetAlternateNames.

If the certificate's subject field is empty, then this extension must be marked critical.

The contents of the Subject Alternative Names extension is printed among the textual information of the certificate. In the example certificate it is as follows:
        X509v3 extensions:
            X509v3 Subject Alternative Name: 
                DNS:www.baz.org, DNS: baz.org

Other Extensions

There are of course other extensions, but I postpone explaining them when talking about the Public Key Infrastructure (PKI), since they are used by it and so it is easier to understand their purpose after explaining how a PKI is structured.

The Encodings

The certificate can be either encoded using;

  • Distinguished Encoding Rule - DER:  (the raw binary format)
  • Privacy Enhanced Mail - PEM (a base-64 encoded format derived from the raw DER - the advantages brought by the base-64 encoding is being printable).

The Formats

X509 certificates and kes can be stored in several formats

PKCS#1

It is the traditional and default format used by OpenSSL for keys.

It has the following header and footer:

-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-256-CBC,9AA41915E12E28466900B2BC60801ACA
iCuAcJLGrCiD0nYNIu8R+N82epcaZRat0uUqLBUIYpLAKO7xPqqYBBZZ4IMyRSdy
...
nYVRrEhvW0M44ddNxU/vL/7wx+qN17vCuYBLqj+ducrVGvavMSAWBFUwFO9WQNZI
-----END RSA PUBLIC KEY-----

The type of the key is specified after the BEGIN keyword, for example RSA, DSA, ECC.

It is a very common practice to bundle PKCS#1 key, the PEM encoded linked certificate and one or more PEM encoded certificates within the same file.

PKCS#8

It is a format for keys that provides a stronger encryption.

It has the following header and footer:

-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDJmQE5X3J4ESMi
...
L3I3+g8AvaydlMr/4omJvqnz8M5SFmAEOBXPEu7p1XKs/+QiTQ1I2+/wNWXlCABw
-----END PRIVATE KEY-----

PKCS#7

It can be used to store one or more certificates within the same file - since it does not support storing the private keys of the certificates, this format is convenient only to create trust store files, that is files containing a chain of certificates to be used when validating leaf certificates.

PKCS#12

It provides a password-protected container suitable to store one or more certificates along with their private key.

Mind openssl supports only one certificate and private key per PKCS#12 file!

If you want more information on symmetric and asymmetric keys and how to operate and manage them, please read "Cryptography Quick Guide - Understanding Symmetric And Asymmetric Cryptography And How To Use It With Openssl".

Components Of A Public Key Infrastructure (PKI)

The actual trust of the certificates is inherited from the certificate they have been signed, going up one level at time, until the root of the chain is reached. This happens when a self-signed certificate is found.

The management of this trust chain is operated through a Public Key Infrastructure (PKI) built using the following components.

Asymmetric Key Pair

A pair made of a private key and a public key mathematically related to one another. They can be used to cipher, decipher and to digitally sign documents. If you are interested in a thorough explanation on cryptographic keys, don't miss the "Cryptography quick guide – Understand Symmetric And Asymmetric Cryptography And How To Use It With OpenSSL" post.

X.509 Certificate

As we saw, it is a digitally signed document with a defined lifetime, containing metadata and a public key of the entity contained in the subject of the certificate. The signature can belong to the private key linked to another certificate or to the one linked to the certificate itself (self-signed certificate).

Secure Storage

A secure facility (typically cryptographic algorithms, but also hardware tokens if necessary) used to securely store the private keys - a stolen key and certificate are very harmful - the abuse is not limited to hijacking a service or Man-in-the-Middle attacks: it the stolen key belongs to a Certificate Authority it can be used also to sign rogue certificates.

Registration Authorities (RA)

An entity that receives Certificate Signing Requests (CSR), validates them in compliance with the Certification Practice Statement (CPS): if the request is valid, then the Registration Authority forwards the CSR to the Certificate Authority to generate the signed certificate. The last step is  sending back to the requestor the requested signed certificate.

Certification Practice Statement (CPS)

Among the information that can be published into an X.509 certificate there is the Certificate Practice Statement: this is a statement of the practices the Certification Authority employed when issuing it, as well as the ones that will be used when suspending revoking and renewing, in accordance with specific requirements (i.e., requirements specified in this Certificate Policy, or requirements specified in a contract for services).

Some elements of a CPS may include are documenting practices of:

  • issuance
  • publication
  • archiving
  • revocation
  • renewal

As an example, you can have a look at the RIPE's CPS.

CPS are broadly used by global Authorities, enabling the end user to know how strong was the validation process the certificate's owner had to undergo to get the certificate.

The Certificate Policies extension is printed among the textual information of the certificate. In the example certificate it is as follows:
        X509v3 extensions:
            X509v3 Certificate Policies: 
                Policy: 1.3.6.1.4.1.1234.1.1
                  CPS: http://www.carcano.local/ca/cps.html
                  User Notice:
                    Explicit Text: Carcano SA Certification Practice Statement

Certificate Authorities

Entities owner of a private key and a Certificate that can be used to generate certificates from Certificate Signing Requests, signing the certificates with the Certificate Authority's private key. As we saw, a CA certificate must have the "CA" basic constraint marked as "critical".

When dealing with private Certificate Authorities, the Registration Authority is often fully automated, providing an authenticated endpoint (such as a REST service) where the submitted CSR is immediately forwarded to the Certificate Authority that instantly signs the certificate. This of course enables the Registration Authority to immediately send back the certificate.

The most used certificate enrolment protocols are:

Simple Certificate Enrollment Protocol - SCEP

originally developed by Cisco, now  RFC 8894, it is probably the most popular of these protocols: it enables automatic enrolling by submitting the request to a shared secret protected endpoint.

Enrolment over Secure Transport (EST)

described in the RFC 7030, it is very similar to SCEP, but it relies on mutual TLS authentication, a feature that is gradually raising its reputation over SCEP

Automated Certificate Management Environment (ACME)

described in RFC 8555, it is very similar to SCEP, it also installs a certificate management tool, which generates a key pairing used to validate both the CA and the organization. After being validated, the management tool will generate and sign CSRs and submit them to the CA.

WS-Trust X.509v3 Token Enrolment Extensions Protocol (WSTEP)

Microsoft proprietary, used for auto-enrolling Active Directory Managed Devices with certificates

It is worth mentioning that also the Cloudflare's PKI Toolkit provides an automated enrolment facility through a REST endpoint - it can be used to sign both PEM encoded CSRs as well as Cloudflare's JSON formatted CSRs.

Validation Authorities (VA)

A Validation Authority is an entity providing the technical facilities (such as web services endpoints) necessary to make sure a certificate has not been revoked.

Certificate Revocation Lists (CRL) X.509 extension

This extension provides the URL of the CRL endpoint(s): this is the most legacy facility, indeed it is no longer mandatory to provide them, despite many Certificate Authorities still do.

This facility is a service, such as an HTTP server, that provides a file containing the list of the certificates revoked along with the revocation reason.

This service has two major weakness:

  • the client must download the file containing the full list: on big Certificate Authorities, after some time this file can become quite heavy, so impacting on the overall performance of the SSL handshaking
  • since they contain only revoked certificates, if an issuing CA gets compromised, they do not protect against rogue certificates, since it is not possible to know if a certificate has actually been issued by the "real" one or a rogue one that is using a stolen private key and certificate.

Mind by the way that certificate Revocation Lists do not contain expired certificates: they are already invalid, so there is no reason to list them.

The CRL file must be digitally signed by the Certificate Authority, or by a special delegated certificate that has been signed by the Certificate Authority (indirect CRL). Since signing is a computational intensive task, to minimize response latency, CRLs are pre-generated so that when the CRL endpoint is queried it just has to serve the pre-computed reply. For this reason, the file contains also the scheduled date for the next time the list will be generated again.

The CRL Distribution Points extension is printed among the textual information of the certificate - it is of course possible to list more than just one endpoint from which to download the list. In the example certificate it is as follows:
        X509v3 extensions:
            X509v3 CRL Distribution Points: 
                Full Name:
                  URI:http://www.test.carcano.local/crl/carc_i100t.crl                CRL Issuer:
                  DirName:C = CH, ST = Tessin, O = Carcano SA, CN = CARC I100T

OCSP Responders

It is an online facility that can be queried to directly check the status of a certificate. This addresses both the weakness of  the CRL we saw: the size of the reply is very small compared to the size of a whole CRL, and if the certificate has not been issued by the CA the query clearly reports that the certificate is unknown to that Certificate Authority. The OCSP reply must be digitally signed by the Certificate Authority, or by a special delegated certificate that has been signed by the Certificate Authority. Since signing is a computational intensive task, to minimize response latency, CRLs are pre-generated so that when the CRL endpoint is queried it just has to serve the pre-computed reply.

OCSP Responders are listed in the "Authority Information Access" extension of the X.509 certificate: it is of course possible to list more than just one endpoint to query. IN the example certificate it is as follows:
        X509v3 extensions:
            Authority Information Access: 
                OCSP - URI:http://ocsp.test.carcano.local:8889

OCSP Stapling

The OCSP alone anyway has still some problems: since it is queried by the client, it must be always available to serve requests.

Anyway this ideal requisite hits with the real life world::

  • OCSP is a plain text protocol, and some public hotspots and captive portals forbid unencrypted traffic
  • OCSP responses can be intentionally blocked during malicious attacks

With these premises, it is clear that a "hard" validation process that marks the certificate as invalid if no OCSP response is received is not a viable option. Even worse, a "soft" validation, that fails only if you receive an OCSP response that claims the certificate has been revoked, works only with honest people, which is like honey for bad guys.

OCSP stapling has been specifically designed to overcome this problem: it enables the server itself to provide the current OCSP reply for its own certificate: this way the client has all it needs to perform a quick and reliable verification of the server certificate.

Implementing OCSP stapling requires the server to support this feature. The most broadly used web servers, such as Apache and NGINX have of course OCSP stapling support.

The server can either:

  • fetch OCSP response on the fly when a client negotiate a specific certificate
  • periodically pre-fetched the responses all the certificates used by the endpoints it provides - this last option is far more performing

responses are cached until they expire, so to avoid continuously querying the OCSP responder.

There is still one problem: since clients have a preference for "soft" fail, an attacker that has been able to steal a certificate and its key may configure a rogue server that does not provide OCSP stapling, and also block OCSP responses from the OCSP responders.

To address this, a certificate can be marked as "must staple": this is a hint to the client to say that the server always provides OCSP staple for that certificate, and so not to trust it if they do not receive OCSP responses.

Automation Protocols

It is certainly worth to mention it do exists automation protocols such as Certificate Management Protocol (CMP) - (described in RFC 4210) and Certificate Management over CMS (CMC) - (RFC 5273) that operate throughout all the lifecycle of the certificate: conversely from protocol such as SCEP, they manage also certificate revocation.

Authority Information Access X.509 extension

The Authority Information Access (AIA) is an X.509 v3 certificate extension that can provide two types of information:

  • the URL of the endpoint from where the client can get a copy of the issuer certificate, that is the certificate of the signing Certificate Authority. This is useful when the client does not have this certificate in its trust store, and the server provides only the leaf certificate without a copy of the signing certificate. Mind anyway that applications leveraging on old libraries may not have the capability of automatically retrieving the certificate 
  • the URL of the OCSP responders that can be queried to get the current revocation status of the certificate
As we already saw, the information provided by the Authority Information Access are as follows.
            Authority Information Access: 
                OCSP - URI:http://ocsp.test.carcano.local:8889
                CA Issuers - URI:http://ca.test.carcano.local/carc_i100t.cer

The Trust Model

The trust model used to validate digital Certificates is very similar to the one used to validate real life certificates:

  • as in real life, certificates signed by a trusted third party are trusted
  • as in real life, self signed certificates are trusted as an exception

So all the above claims apply to digital certificates too: the trust of a certificate relies on the trust assigned to the certificate that signed it. The obvious consequence is that the ROOT certificate of this chain must be self-signed, and so must be explicitly marked as trusted.

Certificate Hierarchy

So basically by the hierarchical perspective there are three kind of certificates:

  • ROOT - as the name suggests, they are the root of the chain, they are self-signed by design and they belong to Certificate Authorities.
  • INTERMEDIATE - as the name suggests, they stay in the middle, so they have both an ancestor and children certificates - so also these certificates belong to Certificate Authorities.
  • ENTITY - even here the name is meaningful: certificates of this kind are used to identify entities, such as users, hosts and so on - the very most of the entity certificates are signed by a Certificate Authority, but it is possible to generate self-signed entity certificates.
  • PROXY - these special certificates can be issued by ENTITY certificates, for example for delegating purposes. They can be easily identified because they have the special Proxy Certificate Information (PCI) extension and they are signed by the ENTITY certificate. The standard allows placing in the PCI any type of policy statement expressed in any language (such as eXtensible Access Control Markup Language) .

Proxy certificates are essential in Grid Security Infrastructure (GSI), but the framework is weak when it comes to revoking them: since they are not issued by a Certificate Authority, they don't have the validation facilities that enable them to revoke them before they expire. For this reason it is wise to issue proxy certificates with the lifetime as short as possible, lasting only the necessary amount of time to complete the task they have been created for.

ROOT and INTERMEDIATE certificates must have the "CA" Basic Constraint set to "true".
ENTITY certificates and PROXY certificates must have the "CA" Basic Constraint set to "false".

TrustStore

A trust-store is a repository of trusted certificates: the intended use is to store only ROOT certificates that are trusted, but technically it is possible to store any kind of certificate inside them.

System-wide Trust-Store

Typically there is a system-wide trust-store, delivered and kept current by the Linux distribution, and it is used as the initial trust point to validate the certificate chain of TLS enabled services or user certificates.

On a Red Hat (and derivatives) Linux system it is possible to add custom CA certificates to the system-wide trust-store by using the "update-ca-trust" command line utility: simply copy the PEM encoded certificate file to the "/etc/pki/ca-trust/source/anchors" directory and type:

sudo update-ca-trust enable
sudo update-ca-trust extract

After running those two statements, the certificate is added to the system-wide trust-store, and also to the other trust-stores extracted (synchronized) from it.

You can then easily verify that the certificate is trusted using the openssl command line utility with the "verify" verb. 

For example, if you added the "/tmp/FooCA.crt" certificate to the system-wide trust-store, simply type:

openssl verify /tmp/FooCA.crt

the output must be as follows:

/tmp/FooCA.crt: OK
Since Java leverages on the isolation of a virtual machine, it uses its own trust-store (before Java 9 the default format was JKS, after it is PKCS12): the default path to this file is "$JAVA_HOME/jre/lib/security/cacerts". The "update-ca-trust" command line utility also generates trust-stores in multiple formats. The path to the synchronized JKS trust-store is "/etc/pki/java/cacerts": this means that you can easily have Java applications use the system-wide trust-store by supplying the "javax.net.ssl.trustStore=/etc/pki/java/cacerts" and "javax.net.ssl.trustStoreType=JKS" options when running them.

Dedicated Trust-Store

Unfortunately, there have been several episodes of Certificate Authorities issuing rogue certificates by mistake, because they have been cheated by scammers. For this reason, when dealing with use cases demanding a very strong security, you may need to avoid trusting even the very most (or even all) the public Certificate Authorities: this can be achieved by creating custom trust-stores containing only the minimal set of ROOT certificates you can trust, and configure specific applications to use that trust store instead of the system-wide one.

A pitfall of dedicated trust-store are certainly stateful SSL proxies: when connecting through them they replace the original certificate of the accessed service with a rogue one, so as to be able to inspect the traffic. This means that you must add the certificate of the SSL proxy server to the trust-store, so that the rogue certificates issued by it are valid - adding it to the system-wide trust-store won't be effective, since the application is not using it. If your application is installed on mobile systems, there's a very high risk to have them connected to a network with a stateful SSL proxy sooner or later, so you must provide to the user an easy way to add the certificate of that SSL proxy to the dedicated truststore.

The Trust-Chain

While validating a certificate, it is attempted to build a chain of trust from the certificate that is validated iterating from the certificate to the issuing one checking if the signer certificate is trusted.

As we saw, a certificate in the Authority Key Identifier x509v3 extension provides the Subject Key Identifier of the certificate used to sign it and optionally the name of the ROOT Certificate Authority that marks the beginning of the chain.

Reissuing Certificates Using The Same Private Key

Since the Subject Key Identifier is computed from the key, it is technically possible to re-use the same CSR to issue the same certificate multiple times: the outcome is actually the same certificate (same subject and the same Subject Key Identifier), but with a new expiration time.

Anyway, mind that this is not a safe choice from the security perspective: the expiration date on certificates is used to promote rotating private keys, since keeping the same key for too long increases the chance of having the key broken by bad guys.

Cross-Signing

Being able to reuse the same CSR means also being able to generate multiple copies of the same certificate for example to have the certificate not only self-signed, but also signed by another Certificate Authority. 

This practice is called "cross-signing" and can be exploited to address some use cases.

For example, you can create a brand new ROOT Certificate Authority with its own self-signed certificate and send the same Certificate Signing Request used to generate the self-signed certificate to an already existent and trusted Certificate Authority. The outcome is another copy of the same certificate, this time already trusted by systems since it is signed by an already trusted Certificate Authority.

You can then immediately start generating and delivering certificates using the self-signed certificate, and take your time for a relaxed delivery of it to the trust-store of your systems: since both the name and the Subject Key Identifier of both certificates match, these systems are already able to build a trust path that initially leads to the already trusted CA. Later, when the self-signed certificate is delivered to the system's trust-store, the trust path will stop at the self-signed certificate.

Let's Encrypt Certificate Authority exploited Cross-Signing to become immediately operative, avoiding waiting the necessary time for the application as a public CA to be fulfilled - a task that usually takes even 3-4 years.

Another typical use case of cross-signing is keeping valid the certificates issued by an intermediate certificate after the expiration of the root certificate that signed it: you create a new ROOT CA, submit the already existing CSR of the intermediate CA to the new CA to get a cross-signed intermediate certificate. Then you deliver both certificates: the ROOT certificates to the system-wide trust-stores of your systems and reconfigure your services adding the cross-signed intermediate certificate the the certificate bundle (leaf certificate + intermediate certificate).

Caveats And Pitfalls Of The Trust Model

Certificate Authorities just issue certificates to requestors, but unless they have a special policy that requires them to do accurate enquiries on the requestor, they just issue the certificate without special validation checks.

The broadly used basic condition to be met for having a certificate issued is just to be the owner of the domain the certificate is valid for.

This means that it is perfectly right for Certificate Authorities to issue a certificate requested by an entity for a domain with a name very close to the ones of a financial company, if the requestor actually owns it. It is straightforward how this can be exploited to attempt various kinds of fraud and scam.

These kind of misunderstandings deeply impacts on both service providers as well as end users:

  • service providers may have to deal with fraudulent sites they don't even know to exist, and so they won't cope. This can of course severely damage their reputation, and so their business
  • end users risk to trust malicious websites only because they are using a valid certificate and because they have a name very close to the one of the service they are thinking to use

What can be stolen with this kind of trick spans from credit cards, online banking credentials and so on. 

There are a few mitigations that have been attempted to cope with this.

Certificate Practice Statement And Entity Validation Baselines

The first and most obvious mitigation is standardising the Certification Practice: this way Certificate Authorities must follow at least the same baseline when issuing a specific kind of certificate.

CabForum specifically designed a few documents with baselines the CA must comply with.

Standard Practices Of Validation Of The Entities Contained In The Certificate

Another mitigation is standardising a few practices of validating the entities that the requestor put in the CSR, and that are so copied into the issued certificates.

Domain Validated (DV), Individual Validated (OV), Organization Validated (OV) And Extended Validated (EV) Certificates

Cab Forum's designed baselines with the following four validation policies:

Domain Validated (DV)

the CA's Policy just requires to ensure the requestor owns the domain of the requested certificate - it is of course the most basic kind of validation available.

This validation is accomplished by using one or more Domain Control Validation (DCV) methods - they varies from Certificate Authorities, but the most common ones are adding a TXT record with a specific value or sending an email with a validation code to the administrative email of that domain (usually either admin@ administrator@ postmaster@ webmaster@ hostmaster@ ). Some CA can require you to put a specific file on the web server of that domain.

DV certificates must cleanly publish the CA's CPS used for it, as well as the Cab Forum's OID "2.23.140.1.2.1" (Compliant with "Baseline Requirements – No entity identity asserted")

Individual Validated (IV)

the CA's policy requires to make sure the name of the requestor is actually the claimed one: this means that the certificate must provide the "surname" and the "givenName" attributes, along with a minimum set of attributes necessary to locate him.

IV certificates must cleanly publish the CA's CPS used for it, as well as the Cab Forum's OID "2.23.140.1.2.3" (Compliant with "Baseline Requirements – Individual identity asserted")

Organization Validated (OV)

the CA's policy requires to make sure the name of the requestor organization is actually the claimed one: this means that the certificate must provide the "organization" attribute, along with a minimum set of attributes necessary to locate it.

OV certificates must cleanly publish the CA's CPS used for it, as well as the Cab Forum's OID "2.23.140.1.2.2" (Compliant with "Baseline Requirements – Organization identity asserted")

Extended Validated (EV)

this kind of validation use a dedicated baseline called "Certificate issued in compliance with the Extended Validation Guidelines":

An EV certificate must provide the following (validated) attributes:

  • organizationName
  • businessCategory
  • for any of the attribute Country, State or Locality the related jurisdiction attribute
  • the Subject Registration Number - this means that the CA is required to make sure the entity actually exists in the public trade registry

EV certificates must cleanly publish the CA's CPS used for it, as well as the Cab Forum's OID "2.23.140.1.1"

The validation policy used when issuing the certificate is then put into the certificate and it is printed among the  Certificate Policies extension.

For example:

The validation policy used when issuing the certificate is added to the Certificate Policies extension - it is of course possible to add as many policies as needed. In the example certificate it is as follows:
        X509v3 extensions:
            X509v3 Certificate Policies:
                Policy: 2.23.140.1.1
                  User Notice:
                    Explicit Text: Extended Validated

For some years web browsers turned the address bar into green when the supplied certificate was an Extended Validated one. They stopped after realising that it was misleading : people were mixed up and thought that they could definitely trust that entity because of the "green" certificate. They didn't understand the concept - that green only meant that the Certificate Authority thoroughly checked the accuracy of the information supplied in the certificate: these checks anyway have not anything to deal with the fact that the business of the "ACME Philanthropists Inc." that requested the certificate consisting in stealing or doing the worst possible things.

Despite all the attention Certificate Authority use when validating the data written in the certificates, it happened that some of them have been cheated and released rogue certificates, or even worse, released certificates to a requester that was not the individual stored in the certificate data - yes, this is what is called "identity fraud".

Don't think that the risk of having rogue certificates issued belong only to small companies: in December, 2013, Google announced they noticed unauthorised digital certificates issued for several Google domains by an intermediate CA linking back to a French Certificate Authority.

That authority said the incident was caused by human error, but it is worth mentioning that CA has been reported to work with French intelligence. Are you worried now? You should. It depends on your needs, but for some use cases it may be better to rely on GPG and its web of trust - if interested in this topic, please read "A Quick, Easy Yet Comprehensive GPG Tutorial". By the way, they are more social, since they periodically have signing parties.

Certificate Pinning And Key Pinning

The most straightforward solution to the problem of rogue certificates accidentally issued by public Certificate Authorities is pinning one or more certificates or public keys in the chain.

Pinning indeed mitigates the following risks:

  1. Certificate Authority compromise
  2. Certificate mis-issuance
  3. SSL Stripping

There are several libraries that can be used to implement pinning: on iOS you can use Alamofire or NSURLSession, whereas on Android you can use Network Security Configuration or OKHTTP and CertificatePinner.

You can of course configure these libraries to ignore pinning when dealing with certificates issued by locally imported Certificate Authorities: this way they  do not block the connection when stageful inspection HTTPS proxies are used.

The pinned set, advertised into headers along with a max-age attribute, is enforced during validation until the max-age is reached.

The maximum security level is achieved by pinning the leaf certificate (or its public key), but you can of course pin the intermediate and the root or even only the root. As you can easily guess, the most secure setup is also the most cumbersome and error prone by the maintenance perspective.

Mind that despite pinning public keys (actually it is their SHA256 being pinned) is more easy to maintain compared to pinning certificates, it is however a very cumbersome and error-prone technique.

In addition to that, it has the shortcomings of being unable to change key until max-age is expired: the client enforces the cached pinning information until max-age expires indeed, so replacing a certificate, either because it is expiring or because a revocation is almost impossible.

HTTP Public Key Pinning

This is a deprecated attempt of creating a protocol to implement key pinning on HTTP traffic. It was adopted by some sites and browsers for a few years, until they hit against how hard and cumbersome it is maintaining it: even a small mistake can make a site completely inaccessible indeed. In addition to that, despite this hasn’t been observed yet, if somehow somebody would be able to obtain a valid certificate for the domain, it is theoretically possible for him to set up an intentionally hostile pinning to take the site hostage. For this reason the browsers gradually deprecated this protocol.

CAA DNS Record

Another way to prevent the risk of rogue certificates issued by public CA by mistake is adding a CAA record to the DNS of your domains: the CAA record is used to advertise which Certificate Authorities are allowed to issue certificates containing that domain name. It was standardised in 2013 by the RFC 6844 .

You can inspect the CAA record of a domain even by using the old fashioned "dig" command line utility.

As an example, let's see what they did at Google:

dig google.com CAA +short

the outcome is as follows:

0 issue "pki.goog"

Certificate Transparency (CT)

The capability of actively blocking non compliant SSL sets was of course the strength of HTTP Public Key Pinning, but it was also the cause of being so sensitive and dangerous if not properly managed. Probably for this reason they moved from an active approach to a passive one, based on tracking on public logs Certificate Authorities' activity: if anything weird would be in this log, this time the necessary actions are taken by humans: this passive approach is certainly slower, but it prevents service outages.

This tracking is called Certificate Transparency (CT): it was proposed by Google, but it quickly became an IETF open standard for monitoring and auditing digital certificates.

The auditing relies on public logs where the global available CA submits each issued certificate. They must publish into at least two public Certificate Transparency logs: by  monitoring these logs Companies can easily and quickly identify mistakenly or maliciously issued certificates.

Here are some of the most popular interfaces to CT logs in the web:

Public logs are ... public: this obviously means that anybody has free access to them. This means that special care must be taken when registering certificates: if for example a corporate want to request a certificate for a brand, and don't want people to know that brand belongs to them, it must use a different corporate name if they have, or request someone else such as a trustee to do it for them.

Footnotes

Here it ends this post dedicated to x509 Certificates and Public Key Infrastructures - I know, this is different from my usual posts, since it is completely theoretical, but I swear I will write another post with hands-on labs with OpenSSL to show the above things in action. Honestly this is one of the hardest posts I wrote so far, since there are really a lot of concepts that are necessary to know, and it was really difficult to figure out a way to condense everything within a single post.

Writing a post like this takes a lot of hours. I'm doing it for the only pleasure of sharing knowledge and thoughts, but all of this does not come for free: it is a time consuming volunteering task. This blog is not affiliated to anybody, does not show advertisements nor sells data of visitors. The only goal of this blog is to make ideas flow. So please, if you liked this post, spend a little of your time to share it on Linkedin or Twitter using the buttons below: seeing that posts are actually read is the only way I have to understand if I'm really sharing thoughts or if I'm just wasting time and I'd better give up.

Every system administrator daily use SSH to connect to remote systems and perform they daily tasks: the very most of the time these consist into typing statements on the terminal or copying files from and to the remote system, or again running remote commands, but SSH is much more than this: it not only provides additional facilities such as agent  or forwarding, port forwarding and X11 forwarding, but it has also a subsystem that can be exploited to provide SSH secured services such as SFTP.

The goal of the "OpenSSH Tutorial - The Ultimate SSH Guide To Understand It" post is to tell you what historically drove us to SSH, describe the protocol suite in detail and provide a thorough tutorial on using all of these facilities.

SSH is a huge topic: thoroughly explaining both server and client side would require much more than a single post - actually even just explaining server side would deserve several posts. For this reason this post shows only the minimum required settings that are required server side to enable the features that are instead thoroughly described client side. In addition to that, some parts of this post are a little bit redundant, but it was the only way I found to clearly explain how things work from the client perspective and from the server perspective.

This post is based on Red Hat Enterprise Linux 9, but the same concepts apply to the very most of the Linux distributions.

Read more >

Every time you interact with a computer, either using a command line or graphically, you are using a console. Despite its ease of use, a console must address and solve a lot of compatibility problems, for example properly interpreting control characters that may differ from terminal to terminal.

Being able to customize settings such as locale and keyboard layout is the basis, but it is not enough: , having at least a basic understanding of how a console works under the hood is certainly a valuable skill that lets you quickly and easily address some uncomfortable situations that sometimes arise, especially when connecting to old systems that, in the face of security best practices, for various reasons after decades are still there without being updated, maybe because very are running obsolete services that are not compatibles with up to date operating systems.

The "Linux Console Essential Virtual Terminals Terminal Emulation and configuring locale" post is meant to provide you everything it is necessary to know to solve the most common problems that may arise concerning the Linux console and locale.

Read more >

It is almost impossible not having heard about or not having used LVM: it is one of the pillars of every Linux distribution from decades ago. Almost everyone using Linux has used it to create or modify the basic storage structures of its Linux system. The trouble is that very often people are focused on the specific task they are onto, and neglect the time to investigate its amazing features. The goal of LVM Tutorial - A thorough howto on the Logical Volume Manager is to provide an easy yet comprehensive explanation on the most interesting features of LVM that it is very likely you will need to use sooner or later.

Read more >

Managing Red Hat Network Satellite clients with Ansible roles and playbooks is a very powerful feature of Red Hat Network Satellite Server 6, as well as of its upstream project Katello. Conversely from Puppet, that requires the client host to install its agent package and to be registered to the Puppet master running on the Satellite or Capsule, Ansible does not require installing anything, since it relies on SSH or, to tell it in Red Hat Network Satellite 6 terms, it relies on remote execution with SSH.

This post shows you how to manage client hosts using Ansible, either executing the Ansible roles assigned to the host group the client host belongs to, or running Ansible playbooks using Job Templates.

The Linux distribution used in the examples is CentOS 7, but you can of course easily adapt it to any other Red Hat and derived Linux distribution.

Read more >