The CAW driver is our native certificate authority driver. In essence, it is a shell script encompassing ordinary OpenSSL certificate authority. This has many pros:
It also has some cons:
CAW is a shell wrapper above the OpenSSL-based certificate authority (abbreviated: OSSL CA). It allows you to use the OSSL CA in a similar way the EasyRSA does. CAW is primarily created as a CA backend for the CzechIdM Certificate Authority module but it is possible to extend/incorporate it somewhere else. It also provides an user-friendly CA implementation which can be used right away from the command line.
For the list of capabilities and input/output formats, please refer to the CAW shell script. Simply run CAW to get the usage screen where you can find everything you will ever need. :)
./caw Unknown command '' specified. Usage: ./caw command [--param1 value1 --param2 value2 ...] ... COMMAND create-key-and-cert - generates new private key, CSR and signs a certificate OUTPUT Success: Serial number of the issued certificate written onto STDOUT. Return code 0. Error: Error message on STDERR. Return code 1. PARAMETERS --country countryName. Mandatory. --state stateOrProvinceName. Mandatory. --locality localityName. Mandatory. --org organizationName. Mandatory. --ou organizationalUnitName. Mandatory. --cn commonName. Mandatory. --mail emailAddress. Mandatory. --pass private key passphrase. Mandatory. ... and so on ...
In its core, CAW uses a well-known OSSL CA all with its openssl.cnf
file and such. Therefore every configuration which can be specified in openssl.cnf
can be made available in the CAW. CAW makes use of openssl.cnf
as often as possible (i.e. with defaults for the openssl req
command) and very often invokes openssl
using -batch
argument.
But beware, CAW has also its own configuration file caw\_settings.source
. This file contains some options that need to be in sync with options in ca\_openssl.cnf
. So if you are fiddling with ca\_openssl.cnf
, always also check caw\_settings.source
.
Additional information can be found in one of those three places:
./caw
.caw\_settings.source
file./etc/openssl.cnf
, it brings its own ca\_openssl.cnf
along. That means, your CA is completely separated from others.openssl ca …
) must not be invoked in multiple instances at the same time. CAW uses lockdir to prevent that.ca\_openssl.cnf
and caw\_settings.source
(and there is already a template for that).STDOUT
) or an error (on STDERR
).0
, for error it is 1
.policy_match
in heterogenous environments../caw create-crl
. Another user can then publish the CRL into public destination by calling ./caw publish-crl
../caw housekeep
.users
group which encompasses all users.[root@ca ~]# useradd -r -m -s /bin/bash authority1
[root@ca ~]# mv caw.tgz /home/authority1/ [root@ca authority1]# tar xzf caw.tgz [root@ca authority1]# ll total 28 drwxr-xr-x 4 1000 users 4096 Aug 24 14:36 caw -rw-r--r-- 1 root root 24563 Aug 24 15:16 caw.tgz [root@ca authority1]# chown -Rf authority1:authority1 caw/ [root@ca authority1]# chmod 750 caw
caw
script is runnable.[root@ca authority1]# cd caw/ [root@ca caw]# chmod 750 caw
01
but there is a caveat attached to this - OpenSSL then works with 8bit serial mode (this is potentially dangerous). Better way is to create truly random 128bit serial number as the example shows.[root@ca caw]# cd ca/ [root@ca ca]# openssl rand -hex 16 > serial
b1676557ad077ef7144c227d16a55025
. Then we simply edit the starting serial to have our desired prefix (say, aaaccc000
). Total length of the serial number must remain 128b, so our new serial will be aaaccc000d077ef7144c227d16a55025
. Write it into the serial
file. We can, possibly, overflow to the prefix aaaccc001
so be aware of it - our "prefix" is not a real prefix. It is merely a cleverly chosen starting number.ca\_crt.extensions
file. Edit them (and command line parameters in the example below) according to your needs.[root@ca ca]# su - authority1 [authority1@ca ~]$ cd caw/ca/ [authority1@ca ca]$ pwd /home/authority1/caw/ca [authority1@ca ca]$ openssl genrsa -out private/ca.key 2048 [authority1@ca ca]$ chmod 400 private/ca.key [authority1@ca ca]$ openssl req -new -in private/ca.key -out ca.csr -key private/ca.key [authority1@ca ca]$ openssl x509 -req -in ca.csr -signkey private/ca.key -days 1000 -out ca.crt -sha256 -extfile ../ca_crt.extensions [authority1@ca ca]$ rm ca.csr
caw
script for managing the authority. Do not delete them.ca\_openssl.cnf
configuration file and configure your authority. This file is an ordinary openssl.cnf, but is realized in local variant. This enables multiple caw-based CAs to coexist one along the other just by separating their directories. The ca\_openssl.cnf
contains preconfigured CA so only small adjustments should be necessary. Follow the comments in the file itself. The most important things to set up are:default\_days
and default\_crl\_days
and other certificate-related settings.req
stanza - those are used for generating new keys and requests.issued\_cert\_ext
stanza. Do not forget to set up the crlDistributionPoints
correctly.caw\_settings.source
configuration file and configure it accordingly. The tricky part there is that some settings have to have the same values as in ca\_openssl.cnf
. Again, the comments in the file will help you. The most important things to set up are:CA\_OSSL\_ENGINE\_PARAM
if you want to use PKCS11 token. Set it to an empty string if you store the CA's private key in the file.CA\_OSSL\_ROOT\_CHAIN
if your CAW authority is not the root authority.SubjectDN
and CSR
validation prefixes. This also lets you set a basic policy for user's passphrase complexity. Also, set allowed signature algorithms.ca.key
), deconfigure PKCS11 engine template according to this howto.[authority1@ca caw]$ ./caw create-crl
[root@ca ~]# ./caw create-key-and-cert --country CZ --state "Czech Republic" --locality Prague --org BCV --ou TEST --cn user.test.bcv --pass demodemo 0C0774BACDF2CA2A52BEEF68A0F1D411
[root@ca ~]# ./caw prolong-cert --serial 0C0774BACDF2CA2A52BEEF68A0F1D411 0C0774BACDF2CA2A52BEEF68A0F1D412
[root@ca ~]# ./caw get-cert --serial 0C0774BACDF2CA2A52BEEF68A0F1D411 --with-pkey --pass demodemo --with-chain MIIKoQIBAzCCCmcGCSqGSIb3DQEHAaCCClgEggpUMIIKUDCCBQcGCSqGSIb3DQEHBqCCBPgwggT0 ... FbAM6nS5jJYQ4s4VKDElMCMGCSqGSIb3DQEJFTEWBBRGj5/LUBZtcz/k+N96L7RzdleanDAxMCEw CQYFKw4DAhoFAAQUCqImx0Un2qmtSACpEWD4i2ivunMECFJnEuzDIEtHAgIIAA==
[root@ca ~]# ./caw revoke-cert --serial 0C0774BACDF2CA2A52BEEF68A0F1D411 --reason keyCompromise
[root@ca ~]# ./caw create-crl
[root@ca ~]# mkdir /data/volumes/czechidm/cert-authority
[root@ca ~]# unzip caw-master.zip -d /data/volumes/czechidm/cert-authority/ [root@ca ~]# mv /data/volumes/czechidm/cert-authority/caw-master /data/volumes/czechidm/cert-authority/caw
[root@ca ~]# cp customerCa.key /data/volumes/czechidm/cert-authority/caw/ca/private/ca.key [root@ca ~]# cp customerCa.pem /data/volumes/czechidm/cert-authority/caw/ca/ca.pem
[root@ca ~]# cd /data/volumes/czechidm/cert-authority/caw/ca/ [root@ca ca]# openssl rand -hex 16 > serial
[root@ca czechidm]# chown -Rf 999:998 cert-authority/ [root@ca czechidm]# chmod 400 cert-authority/caw/ca/private/ca.key [root@ca czechidm]# chmod 750 cert-authority/ [root@ca czechidm]# cd cert-authority/caw/ [root@ca caw]# chmod 750 caw
- type: bind source: /data/volumes/czechidm/cert-authority target: /opt/cert-authority read_only: false
[Unit] Description=CRL refreshing After=network.target docker.service [Service] Type=simple ExecStart=/usr/bin/docker exec czechidm /opt/cert-authority/caw/caw create-crl
[Unit] Description=CzechIdM refresh CRL After=network.target docker.service [Timer] OnCalendar=*-*-* *:00:00 [Install] WantedBy=multi-user.target
[root@ca czechidm]# systemctl enable iam-crl-refresh.service iam-crl-refresh.timer
- type: bind source: /data/volumes/czechidm/cert-authority/caw/ca/crl/ca.crl target: /etc/nginx/crl/ca.crl read_only: true
- location /crl/ca.crl { root /etc/nginx/; }
Then the crl file is available at URL:https://iam.appliance.tld/crl/ca.crl
By default, CAW comes with a preconfigured template for the PKCS11-enabled crypto engine. In some deployments, this is not necessary and the goal is to have CA's private key and certificate stored on the machine's filesystem. This short howto will show you how to swap preconfigured PKCS11 engine for the more usual setup.
The ca\_openssl.cnf
file has several sections, referred as "stanzas". Stanza starts with [stanza name]
and ends when another stanza starts.
To deconfigure the PKCS11 template:
ca\_openssl.cnf
file.openssl\_conf = openssl\_init
at the top of the file.[openssl\_init]
stanza.[engine\_section]
stanza.[pkcs11\_engine]
stanza.[CA\_default]
stanza, uncomment the private\_key = …
line. Set it to a path to your private key or create private key in the $dir/private/ca.key
path. The key has to have at most 600
(-rw\-\-\-\-\-\-\-
) privileges.caw\_settings.source
file.CA\_OSSL\_ENGINE\_PARAM="…"
to CA\_OSSL\_ENGINE\_PARAM=""
(empty variable).If you modify the example below according to those remarks, then your setup should be secure enough.
[root@ca ~]# openssl genrsa -out ca.key 4096
[root@ca ~]# openssl req -new -key ca.key -out ca.csr -sha512
[root@ca ~]# openssl x509 -req -days 3650 -in ca.csr -signkey ca.key -out ca.crt -sha512 -extfile ca_extensions.txt
-nocrypt
option is a bad idea. But, again, we should be generating private key directly on the token.[root@ca ~]# openssl pkcs8 -in ca.key -topk8 -out ca_pk8.key -nocrypt
[root@ca ~]# softhsm2-util --init-token --slot 0 --label ca --so-pin 123456 --pin 1234 The token has been initialized. [root@ca ~]# softhsm2-util --pin 1234 --so-pin 123456 --import ca_pk8.key --label ca --id A1B2 --no-public-key --slot 0 The key pair has been imported.
[root@ca ~]# openssl engine -t dynamic -pre SO_PATH:/usr/lib64/openssl/engines/pkcs11.so -pre ID:pkcs11 -pre LIST_ADD:1 -pre LOAD -pre MODULE_PATH:/usr/lib64/pkcs11/libsofthsm2.so -pre VERBOSE -pre PIN:1234 (dynamic) Dynamic engine loading support Success: SO_PATH:/usr/lib64/openssl/engines/pkcs11.so Success: ID:pkcs11 Success: LIST_ADD:1 Success: LOAD Success: MODULE_PATH:/usr/lib64/pkcs11/libsofthsm2.so Success: PIN:1234 Loaded: (pkcs11) pkcs11 engine [ available ]
softhsm2-util –show-slots
. Certificate signing should look basically like this (we used openssl shell in this snippet):[root@ca usercert]# openssl OpenSSL> engine -t dynamic -pre SO_PATH:/usr/lib64/openssl/engines/pkcs11.so -pre ID:pkcs11 -pre LIST_ADD:1 -pre LOAD -pre MODULE_PATH:/usr/lib64/pkcs11/libsofthsm2.so -pre VERBOSE -pre PIN:1234 (dynamic) Dynamic engine loading support Success: SO_PATH:/usr/lib64/openssl/engines/pkcs11.so Success: ID:pkcs11 Success: LIST_ADD:1 Success: LOAD Success: MODULE_PATH:/usr/lib64/pkcs11/libsofthsm2.so Success: VERBOSE Success: PIN:1234 Loaded: (pkcs11) pkcs11 engine PKCS#11: Initializing the engine Found 2 slots [ available ] OpenSSL> x509 -req -engine pkcs11 -CAkeyform engine -CAkey slot_0-label_ca -CA ca.crt -days 1000 -set_serial 15 -sha256 -in user.csr -out user.crt PKCS#11: Initializing the engine Found 2 slots engine "pkcs11" set. Signature ok subject=/C=CZ/ST=Czech Republic/L=Prague/O=BCV/OU=TEST/CN=user.test.bcv Getting CA Private Key Loading private key "slot_0-label_ca" Looking in slot 0 for key: label=ca [0] SoftHSM slot 0 login (ca) [1] SoftHSM slot 1 uninitialized, login (no label) Found slot: SoftHSM slot 0 Found token: ca Found 0 certificate: No private keys found. Loading private key "slot_0-label_ca" Looking in slot 0 for key: label=ca [0] SoftHSM slot 0 login (ca) [1] SoftHSM slot 1 uninitialized, login (no label) Found slot: SoftHSM slot 0 Found token: ca Found 0 certificate: Found 1 private key: 1 P id=ffffffa2ffffffb2 label=ca ^C
[root@ca usercert]# openssl verify -CAfile ca.crt user.crt user.crt: OK
[engine]
section in the ca_openssl.cnf
and supply the values you just used on the command line.CA\_OSSL\_ENGINE\_PARAM
variable in the caw\_settings.source
file. There is already template for that, the only value that needs changing should be an identifier of the PKCS11 slot.We are installing SoftHSM on CentOS 7 operating system. Then, we will configure it to run under authority1 OS user.
[root@ca ~]# yum install epel-release [root@ca ~]# yum install softhsm opensc engine_pkcs11
[root@ca ~]# cat /etc/softhsm2.conf # SoftHSM v2 configuration file directories.tokendir = /var/lib/softhsm/tokens/ objectstore.backend = file # ERROR, WARNING, INFO, DEBUG log.level = INFO
authority1
user can access.[root@ca ~]# su - authority1 [authority1@ca ~]$ pwd /home/authority1 [authority1@ca ~]$ mkdir -pv softhsm/tokens mkdir: created directory ‘softhsm’ mkdir: created directory ‘softhsm/tokens’ [authority1@ca ~]$ chmod 750 softhsm [authority1@ca ~]$ vim softhsm/softhsm2.conf [authority1@ca ~]$ cat softhsm/softhsm2.conf directories.tokendir = /home/authority1/softhsm/tokens/ objectstore.backend = file # ERROR, WARNING, INFO, DEBUG log.level = INFO
softhsm2-util
program. This program reads environment variable SOFTHSM2\_CONF
. When the variable is not defined, it uses configuration /etc/softhsm2.conf
. We will export the variable with proper path to config file. If you modified the system-wide config, you can skip this step.[authority1@ca ~]$ export SOFTHSM2_CONF=/home/authority1/softhsm/softhsm2.conf
softhsm2-util
and initialize a new token. Please DO NOT use PINs like 1234 or 123456 in the real world scenarios.[authority1@ca ~]$ softhsm2-util --init-token --slot 0 --label test_slot --pin 1234 --so-pin 123456
[authority1@ca ~]$ find /home/authority1/softhsm/tokens/ -type f /home/authority1/softhsm/tokens/ee48c4b2-b28e-8c2d-7921-59236dda0866/token.lock /home/authority1/softhsm/tokens/ee48c4b2-b28e-8c2d-7921-59236dda0866/generation /home/authority1/softhsm/tokens/ee48c4b2-b28e-8c2d-7921-59236dda0866/token.object
caw\_settings.source
and append the export SOFTHSM2_CONF…
line to it. This will make CAW use the configured store. If you modified the system-wide config, you can skip this step.