|
#!/usr/bin/env bash |
|
|
|
|
|
#/** |
|
# * A bash script to automate the commands from the article |
|
# * "EC CA redux: now with more Nitrokey", available at |
|
# * https://medium.com/where-the-flamingcow-roams/ec-ca-redux-now-with-more-nitrokey-729061e1b7c9 |
|
# * (accessed 2018-01-29) |
|
# * |
|
# * Copyright (c) 2016-2018 Christian Prior |
|
# * Licensed under the MIT License. See LICENSE file in the project root for full license information. |
|
# * |
|
# */ |
|
|
|
clear |
|
echo "This script contains the commands from" |
|
echo -e "https://medium.com/where-the-flamingcow-roams/ec-ca-redux-now-with-more-nitrokey-729061e1b7c9\n\n" |
|
echo "It asks for the User PIN of the Nitrokey first," |
|
echo "then deletes private & public key and certificate for labels" |
|
echo -e "- rsaca_root\n- rsaca_intermediate\n" |
|
echo "Use with caution." |
|
read -n 1 -s -r -p "Press any key to continue, or Ctrl-C to abort!"; echo -e "\n\n" |
|
|
|
|
|
nitrokeyUserPin="" |
|
read -s -p "The User PIN of the Nitrokey:" nitrokeyUserPin && echo -e "\n\n" |
|
|
|
openscpkcs11_path="/usr/lib" |
|
pkcs15tool_path="/usr/bin" |
|
pkcs11tool_path="/usr/bin" |
|
openssl_path=$(dirname $(which openssl)) |
|
localpath="./tmp/ca" |
|
|
|
label_root="rsaca_root" |
|
label_intermediate="rsaca_intermediate" |
|
|
|
myorg="PRDV" |
|
mysubjwithoutCN="/C=DE/ST=Hessen/O=${myorg}.de/OU=${myorg} Certificate Authority" |
|
|
|
if [ -d "${localpath}" ]; then |
|
printf '%*s\rDeleting~subfolder ./tmp/ca\n' "${COLUMNS:-$(tput cols)}" '' | tr ' ' - | tr '~' ' ' |
|
read -n 1 -s -r -p "Press any key to continue, or Ctrl-C to abort!"; echo -e "\n" |
|
rm -rf "${localpath}"; |
|
fi |
|
mkdir -p "${localpath}" |
|
cd "${localpath}" |
|
mkdir -p {root,intermediate}/{certs,crl,csr,newcerts} |
|
mkdir -p {client,server}/{certs,csr,pfx,private} |
|
touch {root,intermediate}/database |
|
echo 1000 | tee {root,intermediate}/{serial,crlnumber} > /dev/null |
|
chmod 700 {client,server}/private |
|
|
|
function removePIN { |
|
sed -i 's/^PIN.*$/#PIN=**********/g' openssl.cnf |
|
} |
|
trap removePIN EXIT |
|
|
|
printf '\n\n%*s\rDeleting~from~the~Nitrokey~if~existing.\n' "${COLUMNS:-$(tput cols)}" '' | tr ' ' - | tr '~' ' ' |
|
read -n 1 -s -r -p "Press any key to continue, or Ctrl-C to abort!"; |
|
echo "" |
|
${pkcs11tool_path}/pkcs11-tool --module ${openscpkcs11_path}/opensc-pkcs11.so --login \ |
|
--delete-object --type privkey --label "${label_root}" --pin $nitrokeyUserPin |
|
#${pkcs11tool_path}/pkcs11-tool --module ${openscpkcs11_path}/opensc-pkcs11.so --login \ |
|
# --delete-object --type cert --label "${label_root}" --pin $nitrokeyUserPin |
|
${pkcs11tool_path}/pkcs11-tool --module ${openscpkcs11_path}/opensc-pkcs11.so --login \ |
|
--delete-object --type privkey --label "${label_intermediate}" --pin $nitrokeyUserPin |
|
#${pkcs11tool_path}/pkcs11-tool --module ${openscpkcs11_path}/opensc-pkcs11.so --login \ |
|
# --delete-object --type cert --label "${label_intermediate}" --pin $nitrokeyUserPin |
|
|
|
${pkcs15tool_path}/pkcs15-tool -D |
|
|
|
|
|
|
|
printf '\n\n%*s\rGoing~to~write~the~openssl.cnf~config~file.\n' "${COLUMNS:-$(tput cols)}" '' | tr ' ' - | tr '~' ' ' |
|
read -n 1 -s -r -p "Press any key to continue, or Ctrl-C to abort!"; echo -e "\n" |
|
|
|
cat > openssl.cnf <<'END' |
|
openssl_conf = openssl_init |
|
[ openssl_init ] |
|
engines = engines |
|
|
|
[ ca ] |
|
default_ca = ca_intermediate |
|
|
|
[ ca_root ] |
|
dir = root |
|
certs = $dir/certs |
|
crl_dir = $dir/crl |
|
new_certs_dir = $dir/newcerts |
|
database = $dir/database |
|
serial = $dir/serial |
|
crlnumber = $dir/crlnumber |
|
END |
|
cat >> openssl.cnf <<END |
|
private_key = label_${label_root} |
|
END |
|
cat >> openssl.cnf <<'END' |
|
certificate = $dir/certs/root.cert.pem |
|
crl = $dir/crl/root.crl.pem |
|
crl_extensions = ext_crl |
|
default_md = sha256 |
|
name_opt = ca_default |
|
cert_opt = ca_default |
|
default_crl_days = 30 |
|
default_days = 3650 |
|
preserve = no |
|
policy = policy_strict |
|
|
|
[ ca_intermediate ] |
|
dir = intermediate |
|
certs = $dir/certs |
|
crl_dir = $dir/crl |
|
new_certs_dir = $dir/newcerts |
|
database = $dir/database |
|
serial = $dir/serial |
|
crlnumber = $dir/crlnumber |
|
END |
|
cat >> openssl.cnf <<END |
|
private_key = label_${label_intermediate} |
|
END |
|
cat >> openssl.cnf <<'END' |
|
certificate = $dir/certs/intermediate.cert.pem |
|
crl = $dir/crl/intermediate.crl.pem |
|
crl_extensions = ext_crl |
|
default_md = sha256 |
|
name_opt = ca_default |
|
cert_opt = ca_default |
|
default_crl_days = 30 |
|
default_days = 375 |
|
preserve = no |
|
policy = policy_loose |
|
|
|
[ policy_strict ] |
|
countryName = match |
|
stateOrProvinceName = match |
|
organizationName = match |
|
organizationalUnitName = optional |
|
commonName = supplied |
|
emailAddress = optional |
|
|
|
[ policy_loose ] |
|
countryName = optional |
|
stateOrProvinceName = optional |
|
localityName = optional |
|
organizationName = optional |
|
organizationalUnitName = optional |
|
commonName = supplied |
|
emailAddress = optional |
|
|
|
[ req ] |
|
default_bits = 2048 |
|
string_mask = utf8only |
|
default_md = sha256 |
|
distinguished_name = req_distinguished_name |
|
|
|
[ req_distinguished_name ] |
|
countryName = Country Name (2 letter code) |
|
stateOrProvinceName = State or Province Name |
|
localityName = Locality Name |
|
0.organizationName = Organization Name |
|
organizationalUnitName = Organizational Unit Name |
|
commonName = Common Name |
|
emailAddress = Email Address |
|
countryName_default = DE |
|
stateOrProvinceName_default = Hessen |
|
localityName_default = Rittershausen |
|
0.organizationName_default = PRDV |
|
organizationalUnitName_default = IT |
|
#commonName_default = ${CN} |
|
emailAddress_default = cprior@gmail.com |
|
|
|
[ ext_root ] |
|
subjectKeyIdentifier = hash |
|
authorityKeyIdentifier = keyid:always, issuer |
|
basicConstraints = critical, CA:true |
|
keyUsage = critical, digitalSignature, cRLSign, keyCertSign |
|
|
|
[ ext_intermediate ] |
|
subjectKeyIdentifier = hash |
|
authorityKeyIdentifier = keyid:always, issuer |
|
basicConstraints = critical, CA:true, pathlen:0 |
|
keyUsage = critical, digitalSignature, cRLSign, keyCertSign |
|
|
|
[ ext_client ] |
|
basicConstraints = CA:FALSE |
|
nsCertType = client, email |
|
nsComment = "OpenSSL Generated Client Certificate" |
|
subjectKeyIdentifier = hash |
|
authorityKeyIdentifier = keyid, issuer |
|
keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment |
|
extendedKeyUsage = clientAuth, emailProtection |
|
subjectAltName = @alt_names |
|
|
|
[ ext_server ] |
|
basicConstraints = CA:FALSE |
|
nsCertType = server |
|
nsComment = "OpenSSL Generated Server Certificate" |
|
subjectKeyIdentifier = hash |
|
authorityKeyIdentifier = keyid, issuer:always |
|
keyUsage = critical, digitalSignature, keyEncipherment |
|
extendedKeyUsage = serverAuth |
|
crlDistributionPoints = URI:http://pki.archam.de/intermediate.crl.pem |
|
subjectAltName = @alt_names |
|
|
|
[ ext_server_client ] |
|
basicConstraints = CA:FALSE |
|
nsCertType = server, client |
|
nsComment = "OpenSSL Generated Server Certificate" |
|
subjectKeyIdentifier = hash |
|
authorityKeyIdentifier = keyid, issuer:always |
|
keyUsage = critical, digitalSignature, keyEncipherment |
|
extendedKeyUsage = serverAuth, clientAuth |
|
crlDistributionPoints = URI:http://pki.archam.de/intermediate.crl.pem |
|
subjectAltName = @alt_names |
|
|
|
[alt_names] |
|
|
|
# sample syntax |
|
# [alt_names_localhost] # for ssh -L 4443:localhost:443 ... |
|
# DNS.0 = localhost |
|
# IP.0 = 127.0.0.1 |
|
|
|
[ ext_crl ] |
|
authorityKeyIdentifier = keyid:always |
|
|
|
[ ext_ocsp ] |
|
basicConstraints = CA:FALSE |
|
subjectKeyIdentifier = hash |
|
authorityKeyIdentifier = keyid, issuer |
|
keyUsage = critical, digitalSignature |
|
extendedKeyUsage = critical, OCSPSigning |
|
|
|
[ engines ] |
|
pkcs11 = engine_pkcs11 |
|
|
|
END |
|
cat >> openssl.cnf <<END |
|
[ engine_pkcs11 ] |
|
engine_id = pkcs11 |
|
dynamic_path = ${openscpkcs11_path}/x86_64-linux-gnu/openssl-1.0.0/engines/pkcs11.so |
|
MODULE_PATH = ${openscpkcs11_path}/opensc-pkcs11.so |
|
init = 0 |
|
PIN = ${nitrokeyUserPin} |
|
END |
|
#echo "PIN = ${nitrokeyUserPin}" >> openssl.cnf |
|
|
|
|
|
|
|
printf '\n\n%*s\rGenerating~the~root~CA.\n' "${COLUMNS:-$(tput cols)}" '' | tr ' ' - | tr '~' ' ' |
|
read -n 1 -s -r -p "Press any key to continue, or Ctrl-C to abort!"#; echo -e "\n\n" |
|
|
|
#export OPENSSL_CONF=openssl.cnf |
|
printf '\n\n%*s\rGenerate~root~key.\n' "${COLUMNS:-$(tput cols)}" '' | tr ' ' - | tr '~' ' ' |
|
${pkcs11tool_path}/pkcs11-tool --module ${openscpkcs11_path}/opensc-pkcs11.so \ |
|
--login --keypairgen --key-type RSA:2048 \ |
|
--label "${label_root}" --pin $nitrokeyUserPin |
|
|
|
printf '\n\n%*s\rGenerate~root~cert.\n' "${COLUMNS:-$(tput cols)}" '' | tr ' ' - | tr '~' ' ' |
|
day=$(date +'%0d'); month=$(date +'%0m'); year=$(date +'%y'); # futureyear=$(( $year + 20 )); |
|
days=$(( ($(date --date="20421016" +%s) - $(date --date="${year}${month}${day}" +%s) )/(60*60*24) )) |
|
OPENSSL_CONF=openssl.cnf ${openssl_path}/openssl req \ |
|
-engine pkcs11 -keyform engine -key "label_${label_root}" \ |
|
-new -extensions ext_root -x509 \ |
|
-days ${days} \ |
|
-subj "${mysubjwithoutCN}/CN=${myorg} Root CA" \ |
|
-out root/certs/root.cert.pem |
|
|
|
chmod 544 root/certs/root.cert.pem |
|
|
|
printf '\n\n%*s\rVerify~root~cert.\n' "${COLUMNS:-$(tput cols)}" '' | tr ' ' - | tr '~' ' ' |
|
OPENSSL_CONF=openssl.cnf ${openssl_path}/openssl x509 -noout -text -in root/certs/root.cert.pem |
|
|
|
printf '\n\n%*s\rConvert~to~DER\n' "${COLUMNS:-$(tput cols)}" '' | tr ' ' - | tr '~' ' ' |
|
OPENSSL_CONF=openssl.cnf ${openssl_path}/openssl x509 -outform der \ |
|
-in root/certs/root.cert.pem \ |
|
-out root/certs/root.cert.der |
|
|
|
${pkcs11tool_path}/pkcs11-tool --module ${openscpkcs11_path}/opensc-pkcs11.so \ |
|
--login --write-object root/certs/root.cert.der \ |
|
--type cert --label "${label_root}" --pin $nitrokeyUserPin |
|
|
|
|
|
|
|
printf '\n\n%*s\rGenerating~the~intermediate~CA.\n' "${COLUMNS:-$(tput cols)}" '' | tr ' ' - | tr '~' ' ' |
|
read -n 1 -s -r -p "Press any key to continue, or Ctrl-C to abort!" |
|
echo "" |
|
|
|
printf '\n\n%*s\rGenerate~intermediate~key.\n' "${COLUMNS:-$(tput cols)}" '' | tr ' ' - | tr '~' ' ' |
|
${pkcs11tool_path}/pkcs11-tool --module ${openscpkcs11_path}/opensc-pkcs11.so \ |
|
--login --keypairgen --key-type RSA:2048 \ |
|
--label "${label_intermediate}" --pin $nitrokeyUserPin |
|
|
|
printf '\n\n%*s\rCreate~intermediate~CSR~certificate~signing~request.\n' "${COLUMNS:-$(tput cols)}" '' | tr ' ' - | tr '~' ' ' |
|
OPENSSL_CONF=openssl.cnf ${openssl_path}/openssl req \ |
|
-engine pkcs11 -keyform engine -key "label_${label_intermediate}" \ |
|
-out intermediate/csr/intermediate.csr.pem \ |
|
-new -sha256 \ |
|
-subj "${mysubjwithoutCN}/CN=${myorg} Intermediate CA" |
|
|
|
printf '\n\n%*s\rGenerate~intermediate~cert.\n' "${COLUMNS:-$(tput cols)}" '' | tr ' ' - | tr '~' ' ' |
|
day=$(date +'%0d'); month=$(date +'%0m'); year=$(date +'%y'); futureyear=$(( $year + 10 )); |
|
days=$(( ($(date --date="${futureyear}${month}${day}" +%s) - $(date --date="${year}${month}${day}" +%s) )/(60*60*24) )) |
|
OPENSSL_CONF=openssl.cnf ${openssl_path}/openssl ca \ |
|
-batch -engine pkcs11 -keyform engine -name ca_root \ |
|
-extensions ext_intermediate -notext \ |
|
-md sha256 \ |
|
-create_serial \ |
|
-startdate "${year}0101000000Z" -days ${days} \ |
|
-in intermediate/csr/intermediate.csr.pem \ |
|
-out intermediate/certs/intermediate.cert.pem |
|
|
|
chmod 544 intermediate/certs/intermediate.cert.pem |
|
|
|
printf '\n\n%*s\rVerify~intermediate~cert.\n' "${COLUMNS:-$(tput cols)}" '' | tr ' ' - | tr '~' ' ' |
|
OPENSSL_CONF=openssl.cnf ${openssl_path}/openssl x509 \ |
|
-noout -text -in intermediate/certs/intermediate.cert.pem |
|
|
|
OPENSSL_CONF=openssl.cnf ${openssl_path}/openssl verify \ |
|
-CAfile root/certs/root.cert.pem intermediate/certs/intermediate.cert.pem |
|
|
|
printf '\n\n%*s\rConvert~to~DER\n' "${COLUMNS:-$(tput cols)}" '' | tr ' ' - | tr '~' ' ' |
|
OPENSSL_CONF=openssl.cnf ${openssl_path}/openssl x509 -outform der \ |
|
-in intermediate/certs/intermediate.cert.pem \ |
|
-out intermediate/certs/intermediate.cert.der |
|
|
|
printf '\n\n%*s\rStoring~the~intermediate~certificate~on~the~Nitrokey.\n' "${COLUMNS:-$(tput cols)}" '' | tr ' ' - | tr '~' ' ' |
|
${pkcs11tool_path}/pkcs11-tool --module ${openscpkcs11_path}/opensc-pkcs11.so \ |
|
--login --write-object intermediate/certs/intermediate.cert.der \ |
|
--type cert --label "${label_intermediate}" --pin $nitrokeyUserPin |
|
|
|
${pkcs15tool_path}/pkcs15-tool -D |
|
|
|
|
|
|
|
printf '\n\n%*s\rGenerating~the~certificate~chain.\n' "${COLUMNS:-$(tput cols)}" '' | tr ' ' - | tr '~' ' ' |
|
|
|
cat intermediate/certs/intermediate.cert.pem root/certs/root.cert.pem > intermediate/certs/chain.cert.pem |
|
|
|
chmod 544 intermediate/certs/chain.cert.pem |
|
|
|
|
|
|
|
printf '\n\n%*s\rGenerating~a~client~certificate.\n' "${COLUMNS:-$(tput cols)}" '' | tr ' ' - | tr '~' ' ' |
|
read -n 1 -s -r -p "Press any key to continue, or Ctrl-C to abort!" |
|
|
|
#OPENSSL_CONF=openssl.cnf ${openssl_path}/openssl ecparam \ |
|
# -name secp384r1 -genkey | openssl ec -aes-256-cbc -out client/private/test1.key.pem |
|
OPENSSL_CONF=openssl.cnf ${openssl_path}/openssl genrsa \ |
|
-out client/private/test1.key.pem 2048 |
|
chmod 500 client/private/test1.key.pem |
|
|
|
${openssl_path}/openssl req \ |
|
-new -sha256 -key client/private/test1.key.pem \ |
|
-reqexts SAN -extensions SAN \ |
|
-config <(cat "./openssl.cnf" \ |
|
<(printf "\n\n[SAN]\nsubjectAltName=DNS:test1,DNS:test1.prdv.de")) \ |
|
-subj "${mysubjwithoutCN}/CN=${myorg} Test 1" \ |
|
-out client/csr/test1.csr.pem \ |
|
#"Test 1" is used later for grepping the serial number that is then going to be revoked |
|
|
|
day=$(date +'%0d'); month=$(date +'%0m'); year=$(date +'%y'); futureyear=$(( $year + 10 )); |
|
days=$(( ($(date --date="${futureyear}${month}${day}" +%s) - $(date --date="${year}${month}${day}" +%s) )/(60*60*24) )) |
|
OPENSSL_CONF=openssl.cnf ${openssl_path}/openssl ca \ |
|
-batch -engine pkcs11 -keyform engine \ |
|
-extensions ext_server_client -notext \ |
|
-config <(cat "./openssl.cnf" \ |
|
<(printf "\n\n[alt_names]\nIP.0 = 127.0.0.1\nDNS.0 = localhost\nDNS.1 = test1\nDNS.2 = test1.prdv.de")) \ |
|
-startdate "${year}0101000000Z" -days ${days} \ |
|
-in client/csr/test1.csr.pem \ |
|
-out client/certs/test1.cert.pem |
|
|
|
chmod 544 client/certs/test1.cert.pem |
|
|
|
printf '\n\n%*s\rConvert~to~DER\n' "${COLUMNS:-$(tput cols)}" '' | tr ' ' - | tr '~' ' ' |
|
OPENSSL_CONF=openssl.cnf ${openssl_path}/openssl x509 -outform der \ |
|
-in client/certs/test1.cert.pem \ |
|
-out client/certs/test1.cert.der |
|
|
|
OPENSSL_CONF=openssl.cnf ${openssl_path}/openssl x509 \ |
|
-noout -text -in client/certs/test1.cert.pem |
|
|
|
OPENSSL_CONF=openssl.cnf ${openssl_path}/openssl verify \ |
|
-CAfile intermediate/certs/chain.cert.pem client/certs/test1.cert.pem |
|
|
|
OPENSSL_CONF=openssl.cnf ${openssl_path}/openssl pkcs12 \ |
|
-export -passout pass: \ |
|
-certfile intermediate/certs/chain.cert.pem \ |
|
-inkey client/private/test1.key.pem \ |
|
-in client/certs/test1.cert.pem \ |
|
-out client/pfx/test1.pfx |
|
# Enter both the client key password, and a new password for the export; you'll need to give the latter to the client |
|
|
|
|
|
|
|
printf '\n\n%*s\rGenerating~a~CRL~certificate~revocation~list.\n' "${COLUMNS:-$(tput cols)}" '' | tr ' ' - | tr '~' ' ' |
|
read -n 1 -s -r -p "Press any key to continue, or Ctrl-C to abort!" |
|
|
|
OPENSSL_CONF=openssl.cnf ${openssl_path}/openssl ca \ |
|
-engine pkcs11 -keyform engine -gencrl -out intermediate/crl/intermediate.crl.pem |
|
|
|
OPENSSL_CONF=openssl.cnf ${openssl_path}/openssl crl \ |
|
-in intermediate/crl/intermediate.crl.pem -noout -text |
|
|
|
OPENSSL_CONF=openssl.cnf ${openssl_path}/openssl crl \ |
|
-inform pem -text -noout -in intermediate/crl/intermediate.crl.pem |
|
|
|
|
|
|
|
printf '\n\n%*s\rRevoking~the~client~certificate.\n' "${COLUMNS:-$(tput cols)}" '' | tr ' ' - | tr '~' ' ' |
|
read -n 1 -s -r -p "Press any key to continue, or Ctrl-C to abort!" |
|
|
|
cert_serial=$(grep "Test 1" intermediate/database | cut -f4 -d$'\t') |
|
OPENSSL_CONF=openssl.cnf ${openssl_path}/openssl ca \ |
|
-engine pkcs11 -keyform engine -revoke intermediate/newcerts/${cert_serial}.pem |
|
|
|
OPENSSL_CONF=openssl.cnf ${openssl_path}/openssl ca \ |
|
-engine pkcs11 -keyform engine -gencrl -out intermediate/crl/intermediate.crl.pem |
|
|
|
OPENSSL_CONF=openssl.cnf ${openssl_path}/openssl crl \ |
|
-in intermediate/crl/intermediate.crl.pem -noout -text |
|
|
|
|
|
|
|
printf '\n\n%*s\rDeleting the Nitrokey User PIN from openssl.cnf.\n' "${COLUMNS:-$(tput cols)}" '' | tr ' ' - | tr '~' ' ' |
|
|
|
#sed -i 's/^PIN.*$/**********/g' openssl.cnf |
|
grep PIN openssl.cnf |
|
|
|
exit 0 |
|
|