1*1877e1bcSjsing#!/bin/ksh 2*1877e1bcSjsing 3*1877e1bcSjsing# 4*1877e1bcSjsing# Copyright (c) 2020, 2021 Joel Sing <jsing@openbsd.org> 5*1877e1bcSjsing# 6*1877e1bcSjsing# Permission to use, copy, modify, and distribute this software for any 7*1877e1bcSjsing# purpose with or without fee is hereby granted, provided that the above 8*1877e1bcSjsing# copyright notice and this permission notice appear in all copies. 9*1877e1bcSjsing# 10*1877e1bcSjsing# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11*1877e1bcSjsing# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12*1877e1bcSjsing# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13*1877e1bcSjsing# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14*1877e1bcSjsing# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15*1877e1bcSjsing# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16*1877e1bcSjsing# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17*1877e1bcSjsing# 18*1877e1bcSjsing 19*1877e1bcSjsingset -e 20*1877e1bcSjsingset -u 21*1877e1bcSjsingset -x 22*1877e1bcSjsing 23*1877e1bcSjsingreadonly SUBJECT="/CN=LibreSSL Test" 24*1877e1bcSjsing 25*1877e1bcSjsingreadonly TMPDIR=$(mktemp -d) 26*1877e1bcSjsing 27*1877e1bcSjsingcleanup() { 28*1877e1bcSjsing rm -rf "${TMPDIR}" 29*1877e1bcSjsing} 30*1877e1bcSjsing 31*1877e1bcSjsingtrap cleanup EXIT INT 32*1877e1bcSjsing 33*1877e1bcSjsingreset() { 34*1877e1bcSjsing echo '100001' > ${TMPDIR}/certserial 35*1877e1bcSjsing cat /dev/null > ${TMPDIR}/certindex 36*1877e1bcSjsing} 37*1877e1bcSjsing 38*1877e1bcSjsingsetup() { 39*1877e1bcSjsing reset 40*1877e1bcSjsing 41*1877e1bcSjsing cat > ${TMPDIR}/openssl.cnf <<EOF 42*1877e1bcSjsing[ca] 43*1877e1bcSjsingdefault_ca = test_ca 44*1877e1bcSjsing 45*1877e1bcSjsing[test_ca] 46*1877e1bcSjsingnew_certs_dir = ${TMPDIR}/ 47*1877e1bcSjsingdatabase = ${TMPDIR}/certindex 48*1877e1bcSjsingdefault_days = 365 49*1877e1bcSjsingdefault_md = sha256 50*1877e1bcSjsingpolicy = test_policy 51*1877e1bcSjsingserial = ${TMPDIR}/certserial 52*1877e1bcSjsing 53*1877e1bcSjsing[test_policy] 54*1877e1bcSjsingcountryName = optional 55*1877e1bcSjsingstateOrProvinceName = optional 56*1877e1bcSjsinglocalityName = optional 57*1877e1bcSjsingorganizationName = optional 58*1877e1bcSjsingorganizationalUnitName = optional 59*1877e1bcSjsingcommonName = supplied 60*1877e1bcSjsingemailAddress = optional 61*1877e1bcSjsing 62*1877e1bcSjsing[v3_ca_root] 63*1877e1bcSjsingsubjectKeyIdentifier = hash 64*1877e1bcSjsingauthorityKeyIdentifier = keyid:always,issuer 65*1877e1bcSjsingbasicConstraints = critical, CA:true 66*1877e1bcSjsingkeyUsage = critical, cRLSign, keyCertSign 67*1877e1bcSjsing 68*1877e1bcSjsing[v3_ca_int] 69*1877e1bcSjsingsubjectKeyIdentifier = hash 70*1877e1bcSjsingauthorityKeyIdentifier = keyid:always,issuer 71*1877e1bcSjsingbasicConstraints = critical, CA:true 72*1877e1bcSjsingkeyUsage = critical, cRLSign, keyCertSign 73*1877e1bcSjsing 74*1877e1bcSjsing[v3_other] 75*1877e1bcSjsingsubjectKeyIdentifier = hash 76*1877e1bcSjsingauthorityKeyIdentifier = keyid:always,issuer 77*1877e1bcSjsingbasicConstraints = critical, CA:false 78*1877e1bcSjsingkeyUsage = critical, digitalSignature 79*1877e1bcSjsing 80*1877e1bcSjsing[req] 81*1877e1bcSjsingdistinguished_name = req_distinguished_name 82*1877e1bcSjsing 83*1877e1bcSjsing[ req_distinguished_name ] 84*1877e1bcSjsingEOF 85*1877e1bcSjsing} 86*1877e1bcSjsing 87*1877e1bcSjsingkey_type_to_args() { 88*1877e1bcSjsing local key_type=$1 89*1877e1bcSjsing 90*1877e1bcSjsing alg=${key_type%:*} 91*1877e1bcSjsing param=${key_type#*:} 92*1877e1bcSjsing 93*1877e1bcSjsing if [[ "${alg}" == "rsa" ]]; then 94*1877e1bcSjsing echo "-newkey ${key_type}"; 95*1877e1bcSjsing elif [[ "${alg}" == "ec" ]]; then 96*1877e1bcSjsing echo "-newkey $alg -pkeyopt ec_paramgen_curve:${param}" 97*1877e1bcSjsing else 98*1877e1bcSjsing echo "Unknown key type ${key_type}" >&2 99*1877e1bcSjsing exit 1 100*1877e1bcSjsing fi 101*1877e1bcSjsing} 102*1877e1bcSjsing 103*1877e1bcSjsingcreate_root() { 104*1877e1bcSjsing local name=$1 file=$2 key_type=$3 105*1877e1bcSjsing 106*1877e1bcSjsing key_args=$(key_type_to_args "${key_type}") 107*1877e1bcSjsing 108*1877e1bcSjsing openssl req -new -days 3650 -nodes ${key_args} -sha256 -x509 \ 109*1877e1bcSjsing -subj "${SUBJECT} ${name}" -keyout "${TMPDIR}/${file}.key" \ 110*1877e1bcSjsing -config ${TMPDIR}/openssl.cnf -extensions v3_ca_root \ 111*1877e1bcSjsing -out "${TMPDIR}/${file}.crt" 112*1877e1bcSjsing} 113*1877e1bcSjsing 114*1877e1bcSjsingcreate_intermediate() { 115*1877e1bcSjsing local name=$1 file=$2 issuer_file=$3 key_type=$4 116*1877e1bcSjsing 117*1877e1bcSjsing key_args=$(key_type_to_args "${key_type}") 118*1877e1bcSjsing 119*1877e1bcSjsing openssl req -new -days 3650 -nodes ${key_args} -sha256 \ 120*1877e1bcSjsing -subj "${SUBJECT} ${name}" -keyout "${TMPDIR}/${file}.key" \ 121*1877e1bcSjsing -out "${TMPDIR}/${file}.csr" 122*1877e1bcSjsing openssl x509 -req -days 3650 -CA "${TMPDIR}/${issuer_file}.crt" \ 123*1877e1bcSjsing -CAkey "${TMPDIR}/${issuer_file}.key" -CAcreateserial \ 124*1877e1bcSjsing -extfile ${TMPDIR}/openssl.cnf -extensions v3_ca_int \ 125*1877e1bcSjsing -in "${TMPDIR}/${file}.csr" -out "${TMPDIR}/${file}.crt" 126*1877e1bcSjsing} 127*1877e1bcSjsing 128*1877e1bcSjsingcreate_leaf() { 129*1877e1bcSjsing local name=$1 file=$2 issuer_file=$3 key_type=$4 130*1877e1bcSjsing 131*1877e1bcSjsing key_args=$(key_type_to_args "${key_type}") 132*1877e1bcSjsing 133*1877e1bcSjsing openssl req -new -days 3650 -nodes ${key_args} -sha256 \ 134*1877e1bcSjsing -subj "${SUBJECT} ${name}" -keyout "${TMPDIR}/${file}.key" \ 135*1877e1bcSjsing -out "${TMPDIR}/${file}.csr" 136*1877e1bcSjsing openssl x509 -req -days 3650 -CA "${TMPDIR}/${issuer_file}.crt" \ 137*1877e1bcSjsing -CAkey "${TMPDIR}/${issuer_file}.key" -CAcreateserial -sha256 \ 138*1877e1bcSjsing -extfile ${TMPDIR}/openssl.cnf -extensions v3_other \ 139*1877e1bcSjsing -in "${TMPDIR}/${file}.csr" -out "${TMPDIR}/${file}.crt" 140*1877e1bcSjsing} 141*1877e1bcSjsing 142*1877e1bcSjsingcreate_expired_leaf() { 143*1877e1bcSjsing local name=$1 file=$2 issuer_file=$3 key_type=$4 144*1877e1bcSjsing 145*1877e1bcSjsing key_args=$(key_type_to_args "${key_type}") 146*1877e1bcSjsing 147*1877e1bcSjsing openssl req -new -days 3650 -nodes ${key_args} -sha256 \ 148*1877e1bcSjsing -subj "${SUBJECT} ${name}" -keyout "${TMPDIR}/${file}.key" \ 149*1877e1bcSjsing -out "${TMPDIR}/${file}.csr" 150*1877e1bcSjsing openssl ca -batch -notext -cert "${TMPDIR}/${issuer_file}.crt" \ 151*1877e1bcSjsing -keyfile "${TMPDIR}/${issuer_file}.key" \ 152*1877e1bcSjsing -config ${TMPDIR}/openssl.cnf -extensions v3_other \ 153*1877e1bcSjsing -startdate 20100101000000Z -enddate 20200101000000Z \ 154*1877e1bcSjsing -in "${TMPDIR}/${file}.csr" -out "${TMPDIR}/${file}.crt" 155*1877e1bcSjsing} 156*1877e1bcSjsing 157*1877e1bcSjsingcreate_revoked_leaf() { 158*1877e1bcSjsing local name=$1 file=$2 issuer_file=$3 key_type=$4 159*1877e1bcSjsing 160*1877e1bcSjsing key_args=$(key_type_to_args "${key_type}") 161*1877e1bcSjsing 162*1877e1bcSjsing openssl req -new -days 3650 -nodes ${key_args} -sha256 \ 163*1877e1bcSjsing -subj "${SUBJECT} ${name}" -keyout "${TMPDIR}/${file}.key" \ 164*1877e1bcSjsing -out "${TMPDIR}/${file}.csr" 165*1877e1bcSjsing openssl x509 -req -days 3650 -CA "${TMPDIR}/${issuer_file}.crt" \ 166*1877e1bcSjsing -CAkey "${TMPDIR}/${issuer_file}.key" -CAcreateserial \ 167*1877e1bcSjsing -extfile ${TMPDIR}/openssl.cnf -extensions v3_other \ 168*1877e1bcSjsing -in "${TMPDIR}/${file}.csr" -out "${TMPDIR}/${file}.crt" 169*1877e1bcSjsing openssl ca -cert "${TMPDIR}/${issuer_file}.crt" \ 170*1877e1bcSjsing -keyfile "${TMPDIR}/${issuer_file}.key" \ 171*1877e1bcSjsing -config "${TMPDIR}/openssl.cnf" -extensions v3_other \ 172*1877e1bcSjsing -revoke "${TMPDIR}/${file}.crt" 173*1877e1bcSjsing openssl ca -gencrl -cert "${TMPDIR}/${issuer_file}.crt" \ 174*1877e1bcSjsing -keyfile "${TMPDIR}/${issuer_file}.key" \ 175*1877e1bcSjsing -config "${TMPDIR}/openssl.cnf" -extensions v3_other \ 176*1877e1bcSjsing -crldays 30 -out "${TMPDIR}/${issuer_file}.crl" 177*1877e1bcSjsing} 178*1877e1bcSjsing 179*1877e1bcSjsingcreate_bundle() { 180*1877e1bcSjsing local bundle_file=$1 181*1877e1bcSjsing shift 182*1877e1bcSjsing 183*1877e1bcSjsing mkdir -p $(dirname ${bundle_file}) 184*1877e1bcSjsing cat /dev/null > ${bundle_file} 185*1877e1bcSjsing 186*1877e1bcSjsing for _cert_file in $@; do 187*1877e1bcSjsing openssl x509 -nameopt oneline -subject -issuer \ 188*1877e1bcSjsing -in "${TMPDIR}/${_cert_file}.crt" >> ${bundle_file} 189*1877e1bcSjsing done 190*1877e1bcSjsing} 191*1877e1bcSjsing 192*1877e1bcSjsingcreate_bundle_with_key() { 193*1877e1bcSjsing local bundle_file=$1 194*1877e1bcSjsing shift 195*1877e1bcSjsing 196*1877e1bcSjsing mkdir -p $(dirname ${bundle_file}) 197*1877e1bcSjsing cat /dev/null > ${bundle_file} 198*1877e1bcSjsing 199*1877e1bcSjsing for _cert_file in $@; do 200*1877e1bcSjsing openssl x509 -nameopt oneline -subject -issuer -noout \ 201*1877e1bcSjsing -in "${TMPDIR}/${_cert_file}.crt" >> ${bundle_file} 202*1877e1bcSjsing done 203*1877e1bcSjsing for _cert_file in $@; do 204*1877e1bcSjsing cat "${TMPDIR}/${_cert_file}.crt" >> ${bundle_file} 205*1877e1bcSjsing done 206*1877e1bcSjsing for _key_file in $@; do 207*1877e1bcSjsing cat "${TMPDIR}/${_key_file}.key" >> ${bundle_file} 208*1877e1bcSjsing done 209*1877e1bcSjsing} 210*1877e1bcSjsing 211*1877e1bcSjsingsetup 212*1877e1bcSjsing 213*1877e1bcSjsingreset 214*1877e1bcSjsingcreate_root "Root CA RSA" "ca-root-rsa" "rsa:2048" 215*1877e1bcSjsingcreate_intermediate "Intermediate CA RSA" "ca-int-rsa" "ca-root-rsa" "rsa:2048" 216*1877e1bcSjsingcreate_leaf "Server 1 RSA" "server-1-rsa" "ca-int-rsa" "rsa:2048" 217*1877e1bcSjsingcreate_expired_leaf "Server 2 RSA" "server-2-rsa" "ca-int-rsa" "rsa:2048" 218*1877e1bcSjsingcreate_revoked_leaf "Server 3 RSA" "server-3-rsa" "ca-int-rsa" "rsa:2048" 219*1877e1bcSjsingcreate_leaf "Client 1 RSA" "client-1-rsa" "ca-int-rsa" "rsa:2048" 220*1877e1bcSjsingcreate_expired_leaf "Client 2 RSA" "client-2-rsa" "ca-int-rsa" "rsa:2048" 221*1877e1bcSjsingcreate_revoked_leaf "Client 3 RSA" "client-3-rsa" "ca-int-rsa" "rsa:2048" 222*1877e1bcSjsing 223*1877e1bcSjsingcreate_bundle "./ca-root-rsa.pem" "ca-root-rsa" 224*1877e1bcSjsingcreate_bundle "./ca-int-rsa.pem" "ca-int-rsa" 225*1877e1bcSjsingcp "${TMPDIR}/ca-int-rsa.crl" "./ca-int-rsa.crl" 226*1877e1bcSjsingcreate_bundle_with_key "./server1-rsa.pem" "server-1-rsa" 227*1877e1bcSjsingcreate_bundle "./server1-rsa-chain.pem" "server-1-rsa" "ca-int-rsa" 228*1877e1bcSjsingcreate_bundle_with_key "./server2-rsa.pem" "server-2-rsa" 229*1877e1bcSjsingcreate_bundle "./server2-rsa-chain.pem" "server-2-rsa" "ca-int-rsa" 230*1877e1bcSjsingcreate_bundle_with_key "./server3-rsa.pem" "server-3-rsa" 231*1877e1bcSjsingcreate_bundle "./server3-rsa-chain.pem" "server-3-rsa" "ca-int-rsa" 232*1877e1bcSjsingcreate_bundle_with_key "./client1-rsa.pem" "client-1-rsa" 233*1877e1bcSjsingcreate_bundle "./client1-rsa-chain.pem" "client-1-rsa" "ca-int-rsa" 234*1877e1bcSjsingcreate_bundle_with_key "./client2-rsa.pem" "client-2-rsa" 235*1877e1bcSjsingcreate_bundle "./client2-rsa-chain.pem" "client-2-rsa" "ca-int-rsa" 236*1877e1bcSjsingcreate_bundle_with_key "./client3-rsa.pem" "client-3-rsa" 237*1877e1bcSjsingcreate_bundle "./client3-rsa-chain.pem" "client-3-rsa" "ca-int-rsa" 238*1877e1bcSjsing 239*1877e1bcSjsingreset 240*1877e1bcSjsingcreate_root "Root CA ECDSA" "ca-root-ecdsa" "ec:prime256v1" 241*1877e1bcSjsingcreate_intermediate "Intermediate CA ECDSA" "ca-int-ecdsa" "ca-root-ecdsa" "ec:prime256v1" 242*1877e1bcSjsingcreate_leaf "Server 1 ECDSA" "server-1-ecdsa" "ca-int-ecdsa" "ec:prime256v1" 243*1877e1bcSjsingcreate_expired_leaf "Server 2 ECDSA" "server-2-ecdsa" "ca-int-ecdsa" "ec:prime256v1" 244*1877e1bcSjsingcreate_revoked_leaf "Server 3 ECDSA" "server-3-ecdsa" "ca-int-ecdsa" "ec:prime256v1" 245*1877e1bcSjsingcreate_leaf "Client 1 ECDSA" "client-1-ecdsa" "ca-int-ecdsa" "ec:prime256v1" 246*1877e1bcSjsingcreate_expired_leaf "Client 2 ECDSA" "client-2-ecdsa" "ca-int-ecdsa" "ec:prime256v1" 247*1877e1bcSjsingcreate_revoked_leaf "Client 3 ECDSA" "client-3-ecdsa" "ca-int-ecdsa" "ec:prime256v1" 248*1877e1bcSjsing 249*1877e1bcSjsingcreate_bundle "./ca-root-ecdsa.pem" "ca-root-ecdsa" 250*1877e1bcSjsingcreate_bundle "./ca-int-ecdsa.pem" "ca-int-ecdsa" 251*1877e1bcSjsingcp "${TMPDIR}/ca-int-ecdsa.crl" "./ca-int-ecdsa.crl" 252*1877e1bcSjsingcreate_bundle_with_key "./server1-ecdsa.pem" "server-1-ecdsa" 253*1877e1bcSjsingcreate_bundle "./server1-ecdsa-chain.pem" "server-1-ecdsa" "ca-int-ecdsa" 254*1877e1bcSjsingcreate_bundle_with_key "./server2-ecdsa.pem" "server-2-ecdsa" 255*1877e1bcSjsingcreate_bundle "./server2-ecdsa-chain.pem" "server-2-ecdsa" "ca-int-ecdsa" 256*1877e1bcSjsingcreate_bundle_with_key "./server3-ecdsa.pem" "server-3-ecdsa" 257*1877e1bcSjsingcreate_bundle "./server3-ecdsa-chain.pem" "server-3-ecdsa" "ca-int-ecdsa" 258*1877e1bcSjsingcreate_bundle_with_key "./client1-ecdsa.pem" "client-1-ecdsa" 259*1877e1bcSjsingcreate_bundle "./client1-ecdsa-chain.pem" "client-1-ecdsa" "ca-int-ecdsa" 260*1877e1bcSjsingcreate_bundle_with_key "./client2-ecdsa.pem" "client-2-ecdsa" 261*1877e1bcSjsingcreate_bundle "./client2-ecdsa-chain.pem" "client-2-ecdsa" "ca-int-ecdsa" 262*1877e1bcSjsingcreate_bundle_with_key "./client3-ecdsa.pem" "client-3-ecdsa" 263*1877e1bcSjsingcreate_bundle "./client3-ecdsa-chain.pem" "client-3-ecdsa" "ca-int-ecdsa" 264