#!/bin/sh

set -eu

ORGANIZATION="CAcert Inc."
COUNTRY_CODE="AU"
. ./.env

if [ ! -d testca/ ]; then
  mkdir -p testca/
  cd testca
  mkdir -p root/newcerts class3/newcerts root/private class3/private certs
  touch root/index.txt class3/index.txt
else
  cd testca
fi

cat >ca.cnf <<EOF
[ca]
default_ca             = class3_ca

[root_ca]
dir                    = ./root
certs                  = \$dir/certs
crl_dir                = \$dir/crl
database               = \$dir/index.txt
serial                 = \$dir/serial
new_certs_dir          = \$dir/newcerts

crl                    = \$dir/crl.pem
certificate            = \$dir/ca.crt.pem
private_key            = \$dir/private/ca.key.pem
RANDFILE               = \$dir/private/.rand

policy                 = policy_any
unique_subject         = no
email_in_dn            = no
copy_extensions        = none

default_md             = sha256
default_days           = 1825
default_crl_days       = 30

extensions             = intermediary_extensions

[class3_ca]
dir                    = ./class3
certs                  = \$dir/certs
crl_dir                = \$dir/crl
database               = \$dir/index.txt
serial                 = \$dir/serial
new_certs_dir          = \$dir/newcerts

crl                    = \$dir/crl.pem
certificate            = \$dir/ca.crt.pem
private_key            = \$dir/private/ca.key.pem
RANDFILE               = \$dir/private/.rand

policy                 = policy_any
unique_subject         = no
email_in_dn            = no
copy_extensions        = copy

default_md             = sha256
default_days           = 365
default_crl_days       = 30

extensions             = class3_extensions

[policy_any]
countryName            = optional
stateOrProvinceName    = optional
organizationName       = optional
organizationalUnitName = optional
commonName             = supplied
emailAddress           = optional

[req]
default_bits           = 3072
prompt                 = no
utf8                   = yes
distinguished_name     = req_distinguished_name

[req_distinguished_name]
countryName            = AU
organizationName       = CAcert Inc.
organizationalUnitName = Software Testing

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

[class3_extensions]
basicConstraints       = critical,CA:true,pathlen:0
keyUsage               = critical,keyCertSign,cRLSign
extendedKeyUsage       = serverAuth,clientAuth
subjectKeyIdentifier   = hash
authorityKeyIdentifier = keyid:always
authorityInfoAccess    = 1.3.6.1.5.5.7.48.2;URI:http://test.cacert.localhost/ca/root/ca.crt,OCSP;URI:http://ocsp.test.cacert.localhost/
crlDistributionPoints  = URI:http://crl.test.cacert.localhost/class3.crl
certificatePolicies    = @policy_class3_ca

[client_ext]
basicConstraints       = critical,CA:false
keyUsage               = digitalSignature,keyEncipherment
extendedKeyUsage       = clientAuth
subjectKeyIdentifier   = hash
authorityKeyIdentifier = keyid:always
authorityInfoAccess    = 1.3.6.1.5.5.7.48.2;URI:http://test.cacert.localhost/ca/class3/ca.crt,OCSP;URI:http://ocsp.test.cacert.localhost/
crlDistributionPoints  = URI:http://crl.test.cacert.localhost/class3.crl
certificatePolicies    = @policy_class3_ca

[server_ext]
basicConstraints       = critical,CA:false
keyUsage               = digitalSignature,keyEncipherment
extendedKeyUsage       = serverAuth
subjectKeyIdentifier   = hash
authorityKeyIdentifier = keyid:always
authorityInfoAccess    = 1.3.6.1.5.5.7.48.2;URI:http://test.cacert.localhost/ca/class3/ca.crt,OCSP;URI:http://ocsp.test.cacert.localhost/
crlDistributionPoints  = URI:http://crl.test.cacert.localhost/class3.crl
certificatePolicies    = @policy_class3_ca

[policy_class3_ca]
policyIdentifier       = 1.3.6.1.5.5.7.2.1
CPS                    = http://test.cacert.localhost/ca/class3/cps.html
EOF

if [ ! -f root/ca.crt.pem ]; then
  openssl req -new -x509 -config ca.cnf \
    -keyout root/private/ca.key.pem \
    -nodes \
    -subj "/CN=Test Root/C=${COUNTRY_CODE}/O=${ORGANIZATION}" \
    -days 3650 \
    -extensions root_extensions \
    -out root/ca.crt.pem
fi
if [ ! -f class3/ca.crt.pem ]; then
  openssl req -new -config ca.cnf \
    -keyout class3/private/ca.key.pem \
    -nodes \
    -subj "/CN=Class 3 Test CA/C=${COUNTRY_CODE}/O=${ORGANIZATION}" \
    -out class3/ca.csr.pem
  openssl ca -config ca.cnf \
    -name root_ca \
    -in class3/ca.csr.pem -out class3/ca.crt.pem \
    -rand_serial \
    -extensions class3_extensions \
    -batch
fi

if [ ! -f certs/cachain.crt.pem ]; then
  (
    openssl x509 -in class3/ca.crt.pem
    openssl x509 -in root/ca.crt.pem
  ) >certs/cachain.crt.pem
fi

if [ ! -f certs/cats.cacert.localhost.crt.pem ]; then
  openssl req -new -keyout certs/cats.cacert.localhost.key.pem -nodes \
    -out certs/cats.cacert.localhost.csr.pem -subj "/CN=cats.cacert.localhost" \
    -addext "subjectAltName=DNS:cats.cacert.localhost,DNS:www.cats.cacert.localhost"
  openssl ca -config ca.cnf \
    -name class3_ca \
    -in certs/cats.cacert.localhost.csr.pem \
    -out certs/cats.cacert.localhost.crt.pem \
    -rand_serial \
    -extensions server_ext \
    -batch
fi
if [ ! -f certs/cats-client.cacert.localhost.crt.pem ]; then
  openssl req -new -keyout certs/cats-client.cacert.localhost.key.pem -nodes \
    -out certs/cats-client.cacert.localhost.csr.pem -subj "/CN=cats.cacert.localhost" \
    -addext "subjectAltName=DNS:cats.cacert.localhost"
  openssl ca -config ca.cnf \
    -name class3_ca \
    -in certs/cats-client.cacert.localhost.csr.pem \
    -out certs/cats-client.cacert.localhost.crt.pem \
    -rand_serial \
    -extensions client_ext \
    -batch
fi
if [ ! -f certs/mgr.cacert.localhost.crt.pem ]; then
  openssl req -new -keyout certs/mgr.cacert.localhost.key.pem -nodes \
    -out certs/mgr.cacert.localhost.csr.pem -subj "/CN=mgr.cacert.localhost" \
    -addext "subjectAltName=DNS:mgr.cacert.localhost,DNS:www.mgr.cacert.localhost"
  openssl ca -config ca.cnf \
    -name class3_ca \
    -in certs/mgr.cacert.localhost.csr.pem \
    -out certs/mgr.cacert.localhost.crt.pem \
    -rand_serial \
    -extensions server_ext \
    -batch
fi
if [ ! -f certs/secure.test.cacert.localhost.crt.pem ]; then
  openssl req -new -keyout certs/secure.test.cacert.localhost.key.pem -nodes \
    -out certs/secure.test.cacert.localhost.csr.pem -subj "/CN=secure.test.cacert.localhost" \
    -addext "subjectAltName=DNS:secure.test.cacert.localhost"
  openssl ca -config ca.cnf \
    -name class3_ca \
    -in certs/secure.test.cacert.localhost.csr.pem \
    -out certs/secure.test.cacert.localhost.crt.pem \
    -rand_serial \
    -extensions server_ext \
    -batch
fi
if [ ! -f certs/test.cacert.localhost.crt.pem ]; then
  openssl req -new -keyout certs/test.cacert.localhost.key.pem -nodes \
    -out certs/test.cacert.localhost.csr.pem -subj "/CN=test.cacert.localhost" \
    -addext "subjectAltName=DNS:test.cacert.localhost,DNS:www.test.cacert.localhost"
  openssl ca -config ca.cnf \
    -name class3_ca \
    -in certs/test.cacert.localhost.csr.pem \
    -out certs/test.cacert.localhost.crt.pem \
    -rand_serial \
    -extensions server_ext \
    -batch
fi

if [ ! -f certs/testclient.p12 ]; then
  openssl req -new -keyout certs/testclient.key.pem -nodes \
    -out certs/testclient.csr.pem -subj "/CN=${CLIENT_CERT_USERNAME}" \
    -addext "subjectAltName=email:${CLIENT_CERT_EMAIL}"
  openssl ca -config ca.cnf \
    -name class3_ca \
    -in certs/testclient.csr.pem \
    -out certs/testclient.crt.pem \
    -rand_serial \
    -extensions client_ext \
    -batch
  openssl pkcs12 -export -out certs/testclient.p12 \
    -passout "pass:${CLIENT_CERT_PASSWORD}" \
    -chain -CAfile certs/cachain.crt.pem \
    -inkey certs/testclient.key.pem \
    -in certs/testclient.crt.pem \
    -name "${CLIENT_CERT_USERNAME}"
fi