#!/bin/bash
set -e
BASEDIR="$(cd "`dirname $0`"; pwd)"
. "${BASEDIR}/colors-inc.sh"

BASEDIR=`pwd`

TARGET=/tmp/csr-$$
mkdir -p $TARGET
CONF=$TARGET/csr.conf

_cleanUp() {
  rm -f "${CONF}"
  rmdir "${TARGET}"
}
trap _cleanUp EXIT

usage() {
  echo "${RED}Usage $0 [-ca CA directory] [-pwd] CN[,subjectAltNames,subjectAltIPs]\* [Country State Localization Organization] OrgUnit${ENDCOLOR}"
  echo "${RED} e.g. $(basename \"${0}\") wolle.dev DE Hesse Kassel 'Elektrowolle' 'sample cert'${ENDCOLOR}"
}

CA_DIR=""
EXP_PWD="changeit"

EXT_TO_USE="v3_req"

while true; do
  case $1 in
    -ca)
      shift
      CA_DIR="$1"
      shift
      ;;
    -tsa)
      shift
      EXT_TO_USE="my_tsa"
      ;;
    -pwd)
      shift
      EXP_PWD="$(dd if=/dev/random bs=1 count=24  2>/dev/null | base64 | tr -cd '0-9A-Za-z')"
      ;;
    -*)
      echo "${RED}Unknown option $1!${ENDCOLOR}"
      usage
      exit 1
      ;;
    *)
      break;
      ;;
  esac
done

## Must have all params to generate DN
if [ $# != 6 ] && [ $# != 2 ]; then
  echo "arg count wrong $#"
  usage
  exit 1
fi

# Split args to local vars
IFS=',' read -r -a SUBJ_ALT_NAMES <<< "$1"
X509_CN="${SUBJ_ALT_NAMES[0]}"

if [ $# == 2 ]; then
  X509_C="DE"
  X509_ST="Hesse"
  X509_L="Kassel"
  X509_O="Elektrowolle"
  X509_OU="$2"
else
  X509_C="$2"
  X509_ST="$3"
  X509_L="$4"
  X509_O="$5"
  X509_OU="$6"
fi

# generate openssl config file
egrep -v '^OU =\s+$' >$CONF <<EOF
oid_section                     = ts_oids

[ts_oids]
tsa_policy1                     = 1.2.3.4.1
tsa_policy2                     = 1.2.3.4.5.6
tsa_policy3                     = 1.2.3.4.5.7

[req]
distinguished_name = req_distinguished_name
default_ca      = CA_default            # The default ca section
req_extensions = v3_req
prompt = no

[ ca ]
default_ca      = CA_default            # The default ca section

[ CA_default ]
dir            = ${CA_DIR}              # top dir
database       = \$dir/index.txt        # index file.
new_certs_dir  = \$dir/newcerts         # new certs dir

certificate    = \$dir/selfSignCA.crt   # The CA cert
# serial         = \$dir/selfSignCA.srl   # serial no file
private_key    = \$dir/selfSignCA.key   # CA private key
RANDFILE       = \$dir/.rand            # random number file

default_days   = 10000                  # how long to certify for
default_crl_days= 30                    # how long before next CRL
default_md     = sha256                 # md to use

policy         = policy_any            # default policy
email_in_dn    = no                    # Don't add the email into cert DN

name_opt       = ca_default            # Subject name display option
cert_opt       = ca_default            # Certificate display option
copy_extensions = none                 # Don't copy extensions from request
unique_subject = no

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

[req_distinguished_name]
C = ${X509_C}
ST = ${X509_ST}
L = ${X509_L}
O = ${X509_O}
OU = ${X509_OU}
CN = ${X509_CN}

[ tsa ]
default_tsa = default_tsa

[ default_tsa ]
default_policy          = tsa_policy1
serial                  = tsaserial.srl
signer_digest           = sha256                # digest to use for signing (optional)
#other_policies         = tsa_policy2,tsa_policy3 # other policies (optional)
digests                 = sha256,sha384,sha512    # acceptable digests (mandatory)
accuracy                = secs:1,millisecs:500,microsecs:100 # accuracy optional
ordering                = yes                   # is ordering defined? (optional, default: no)
tsa_name                = yes                   # must tsa name be included in reply? (opt., default: no)
ess_cert_id_chain       = yes                   # must ess cert id change be incl? (opt., default: no)
ess_cert_id_alg         = sha256                # alg to compute cert. id (optional, default: sha1)

[my_tsa]
#authorityKeyIdentifier = keyid:always
basicConstraints = critical,CA:false
extendedKeyUsage = critical,timeStamping
keyUsage = critical,nonRepudiation
subjectKeyIdentifier = hash

[v3_req]
keyUsage = critical, keyEncipherment, dataEncipherment, digitalSignature
extendedKeyUsage = critical, serverAuth,clientAuth
basicConstraints = critical, CA:FALSE
subjectAltName = @alt_names

[alt_names]
EOF

cnt=1
# Add the subjAltNames
for index in "${!SUBJ_ALT_NAMES[@]}"
do
  if echo "${SUBJ_ALT_NAMES[index]}" | egrep -q -v '^([0-9\.]+)|(.*@.*)$'; then
    echo "DNS.${cnt} = ${SUBJ_ALT_NAMES[index]}" >> "${CONF}"
    cnt=$(expr 1 + "${cnt}")
  fi
done

cnt=1
# Add the subjAltIPs
for index in "${!SUBJ_ALT_NAMES[@]}"
do
  if echo "${SUBJ_ALT_NAMES[index]}" | egrep -q '^[0-9\.]+$'; then
    echo "IP.${cnt} = ${SUBJ_ALT_NAMES[index]}" >> "${CONF}"
    cnt=$(expr 1 + "${cnt}")
  fi
done

cnt=1
# Add the subjAltMails
for index in "${!SUBJ_ALT_NAMES[@]}"
do
  if echo "${SUBJ_ALT_NAMES[index]}" | egrep -q '@'; then
    echo "email.${cnt} = ${SUBJ_ALT_NAMES[index]}" >> "${CONF}"
    cnt=$(expr 1 + "${cnt}")
  fi
done

# Ready to do our work
echo "${YELLOW}Using config for ${X509_CN}:${ENDCOLOR}"
echo
cat "${CONF}"
echo
if [ -f "${X509_CN}.key" ]; then
  echo "${YELLOW}The ${X509_CN}.key file is already present, won't create new key file${ENDCOLOR}"
else
  echo "${GREEN}Generate KEY${ENDCOLOR}"
  openssl genrsa -out "${X509_CN}.key" 4096
fi
echo "${GREEN}Generate CSR${ENDCOLOR}"
openssl req -new -utf8 -sha256 -key "${X509_CN}.key" -out "${X509_CN}.csr" -config "${CONF}"
openssl req -in "${X509_CN}.csr"

if [ -d "${CA_DIR}" ] && [ -f "${CA_DIR}/selfSignCA.crt" ] && [ -f "${CA_DIR}/selfSignCA.key" ]; then
  echo "${GREEN}Generate CA-signed cert ${CA_DIR}${ENDCOLOR}"
  openssl x509 -req -sha256 -in "${X509_CN}.csr" -CA "${CA_DIR}/selfSignCA.crt" -CAkey "${CA_DIR}/selfSignCA.key" -CAcreateserial -CAserial "${CA_DIR}/selfSignCA.srl" -out "${X509_CN}.crt" -days 10000 -extfile "${CONF}" -extensions ${EXT_TO_USE}
  echo "${GREEN}pkcs#12 export password: ${EXP_PWD}${ENDCOLOR}"
  openssl pkcs12 -passout "pass:${EXP_PWD}" -export -chain -CAfile ${CA_DIR}/selfSignCA.crt -inkey "${X509_CN}.key" -in "${X509_CN}.crt" -out "${X509_CN}.p12"
else
  echo "${GREEN}Generate short living self-signed cert for tests${ENDCOLOR}"
  openssl x509 -req -sha256 -days 7000 -in "${X509_CN}.csr" -signkey "${X509_CN}.key" -out "${X509_CN}.crt" -extfile "${CONF}" -extensions ${EXT_TO_USE}
  echo "${GREEN}pkcs#12 export password: ${EXP_PWD}${ENDCOLOR}"
  openssl pkcs12 -passout "pass:${EXP_PWD}" -export -inkey "${X509_CN}.key" -in "${X509_CN}.crt" -out "${X509_CN}.p12"
fi
openssl x509 -text -in "${X509_CN}.crt"

echo "${GREEN}Done!${ENDCOLOR}"

