#!/bin/bash # # LTC Certification Authority # Shell script client for Linux and Windows Git Bash # # Copyright 2018 LTC Sp. z o.o. # All rights reserved. # # curl http://www.finn.pl/ltc-root-ca/ltc-root-ca-2-client -O; chmod u+x ltc-root-ca-2-client PROGNAME=$(basename $0) CAID=ltc-root-ca-2 CAOID=1.3.6.1.4.1.10853.1 WEB_NAME="LTC Root CA" WEB_URL=http://www.finn.pl/ltc-root-ca WEB_CAREPO_URL=http://www.finn.pl/ltc-root-ca OPENVPN_HOSTNAME= cnf_content () { if [ "$1" == "" ]; then SANLINE="" else SANLINE="subjectAltName=$1" fi cat << __CNF__ [ req ] default_bits = 2048 default_md = sha256 distinguished_name = req_distinguished_name attributes = req_attributes string_mask = utf8only [ req_distinguished_name ] [ req_attributes ] ### Certificate Profile ### [ v3_req_personal ] basicConstraints=critical,CA:FALSE keyUsage=critical,nonRepudiation,digitalSignature,keyEncipherment certificatePolicies=@cert_policy_cps,@cert_policy_personal subjectKeyIdentifier=hash $SANLINE [ v3_req_ssl ] basicConstraints=critical,CA:FALSE keyUsage=critical,digitalSignature,keyEncipherment extendedKeyUsage=clientAuth,serverAuth certificatePolicies=@cert_policy_cps,@cert_policy_ssl subjectKeyIdentifier=hash $SANLINE [ v3_req_ipsec ] basicConstraints=critical,CA:FALSE keyUsage=critical,digitalSignature,keyEncipherment extendedKeyUsage=clientAuth,serverAuth,1.3.6.1.5.5.8.2.2 certificatePolicies=@cert_policy_cps,@cert_policy_ipsec subjectKeyIdentifier=hash $SANLINE [ v3_req_code ] basicConstraints=critical,CA:FALSE keyUsage=critical,digitalSignature extendedKeyUsage=critical,codeSigning certificatePolicies=@cert_policy_cps,@cert_policy_code subjectKeyIdentifier=hash $SANLINE ### Certificate Policies ### [ cert_policy_cps ] policyIdentifier=$CAOID.1.1 CPS.1=$WEB_URL/ltc-root-ca-cps.pdf userNotice=@cert_policy_cps_notice [ cert_policy_cps_notice ] explicitText="Certificate Practice Statement / Kodeks Postepowania Certyfikacyjnego" [ cert_policy_ocsp ] policyIdentifier=$CAOID.2.1 userNotice=@cert_policy_ocsp_notice [ cert_policy_ocsp_notice ] explicitText="OCSP certificate / Certyfikat OCSP" [ cert_policy_personal ] policyIdentifier=$CAOID.2.2 userNotice=@cert_policy_personal_notice [ cert_policy_personal_notice ] explicitText="Personal certificate / Certyfikat osobowy" [ cert_policy_code ] policyIdentifier=$CAOID.2.3 userNotice=@cert_policy_code_notice [ cert_policy_code_notice ] explicitText="Code signing certificate / Certyfikat podpisywanie kodu" [ cert_policy_ipsec ] policyIdentifier=$CAOID.2.4 userNotice=@cert_policy_ipsec_notice [ cert_policy_ipsec_notice ] explicitText="IPsec certificate / Certyfikat IPsec" [ cert_policy_ssl ] policyIdentifier=$CAOID.2.5 userNotice=@cert_policy_ssl_notice [ cert_policy_ssl_notice ] explicitText="SSL certificate / Certyfikat SSL" __CNF__ } _contains() { _str="$1" _sub="$2" echo "$_str" | grep -- "$_sub" >/dev/null 2>&1 } genpasswd() { if [ ! -f "$1" ]; then openssl rand -base64 16 | tr -cd 'ABCDEFGHJKLMNOPQRTUVWXYZabcdefghijkmnopqrstuvwxyz23456789!#$+ \n' > "$1" || return fi if [ ! -f "$1" ]; then >&2 echo "No $1 file with password!" return 1 fi } usage() { echo "Usage: $PROGNAME req|req-nodes personal|code|ipsec|ssl \"subject\" [altSubName] [name]" echo " $PROGNAME p12 " echo " $PROGNAME ovpn " echo " $PROGNAME keystore (deprecated old Java format)" echo "" echo "Examples:" echo "$PROGNAME req personal \"/C=PL/ST=łódzkie/L=Łódź/O=Example Ltd./OU=ICT Department/GN=Jan/SN=Kowalski/CN=Jan Kowalski/emailAddress=jkowalski@example.com/telephoneNumber=+48509990066\"" echo "$PROGNAME req personal \"/C=PL/GN=Jan/SN=Kowalski/CN=Jan Kowalski/emailAddress=jkowalski@example.com\"" echo "$PROGNAME req ssl \"/C=PL/ST=łódzkie/L=Łódź/O=Example Ltd./CN=example.com\" DNS:example.com,DNS:*.example.com" echo "$PROGNAME req-nodes ssl \"/C=PL/CN=edi.example.com\" DNS:edi.example.com,IP:1.2.3.4" echo "$PROGNAME req code \"/C=PL/ST=łódzkie/L=Łódź/O=Example Ltd./OU=ICT Department/CN=Example Software\"" echo "$PROGNAME req ipsec \"/C=PL/ST=łódzkie/L=Łódź/O=Example Ltd./OU=VPN/CN=fw.example.com\" DNS:fw.example.com,IP:1.2.3.4" exit 1 } if ! command -v openssl > /dev/null; then >&2 echo "openssl program not found!" exit 1 fi ACTION="$1" if [[ "$ACTION" =~ ^req ]] && [ "$2" != "" ] && [ "$3" != "" ]; then REQMODE=${ACTION#req} CERTPOLICY=$2 SUBJECT=$3 SAN=$4 CN=`echo $SUBJECT | sed '/CN=/!d; s|.*CN=\([^/]*\).*|\1|'` EMAIL=`echo $SUBJECT | sed '/emailAddress=/!d; s|.*emailAddress=\([^/]*\).*|\1|'` TELEPHONE=`echo $SUBJECT | sed '/telephoneNumber=/!d; s|.*telephoneNumber=\([^/]*\).*|\1|'` if [ "$5" == "" ]; then BASENAME=$CN if [ "$CERTPOLICY" == "personal" ] && [ "$EMAIL" != "" ]; then BASENAME=$EMAIL fi else BASENAME="$5" fi if [ "$SAN" == "" ] && [ "$CERTPOLICY" == "personal" ] && [ "$EMAIL" != "" ]; then SAN="email:copy" fi if [ -f "$BASENAME.csr" ]; then >&2 echo "Request file $BASENAME.csr already exists!" echo "" else if [ -f "$BASENAME.key" ]; then >&2 echo "Private key file $BASENAME.key already exists. Reusing old key." KEYCMD="-key" if [ -f "$BASENAME.passwd" ]; then PASSCMD=" -passin file:$BASENAME.passwd" fi else KEYCMD="-keyout" if [[ ! "$REQMODE" =~ -nodes ]] && [ ! -f "$BASENAME.passwd" ]; then genpasswd "$BASENAME.passwd" || exit 1 fi if [ -f "$BASENAME.passwd" ]; then if [[ "$REQMODE" =~ -nodes ]] ; then >&2 echo "Password file $BASENAME.passwd already exists. Key will be encrypted." fi PASSCMD=" -passout file:$BASENAME.passwd" else PASSCMD=" -nodes" fi fi if _contains "$(uname -a)" "MINGW"; then OPENSSL_CNF=$(mktemp $CAID-openssl-XXXXXXXX.cnf) trap "{ rm -f $OPENSSL_CNF; }" EXIT cnf_content $SAN > $OPENSSL_CNF MINGSUBJECT="//$(echo "${SUBJECT:1}" | tr '/' '\\')" openssl req -utf8 -config $OPENSSL_CNF -reqexts v3_req_$CERTPOLICY $PASSCMD -new -subj "$MINGSUBJECT" -text $KEYCMD "$BASENAME.key" -out "$BASENAME.csr" || exit 1 else openssl req -utf8 -config <(cnf_content $SAN) -reqexts v3_req_$CERTPOLICY $PASSCMD -new -subj "$SUBJECT" -text $KEYCMD "$BASENAME.key" -out "$BASENAME.csr" || exit 1 fi if [ "$KEYCMD" == "-keyout" ]; then echo "Generated for $WEB_NAME ($CAID) at $(date --rfc-3339=seconds) using:" >> $BASENAME.key echo "$PROGNAME $*" >> $BASENAME.key echo "Private key has been written to $BASENAME.key" fi echo "Certificate request has been written to $BASENAME.csr" echo "" fi if [[ "$REQMODE" =~ -sign ]] ; then CA=$(which CA 2>/dev/null) if [ "$CA" == "" ]; then >&2 echo "CA command is not available!" exit 1 fi $CA -I "$BASENAME.csr" -o "$BASENAME.crt" || exit 1 else echo "Request for $WEB_NAME ($CAID):" openssl req -utf8 -in "$BASENAME.csr" -subject || exit 1 fi echo "" echo "Generate PKCS#12 file using: $PROGNAME p12 $BASENAME" exit 0 fi if [ "$ACTION" == "p12" ] && [ "$2" != "" ]; then NAME=$2 if [ ! -s "$NAME.key" ]; then >&2 echo "No $NAME.key file!" exit 1 fi if [ ! -s "$NAME.crt" ]; then >&2 echo "No $NAME.crt file!" exit 1 fi if [ -s "$NAME.p12" ]; then >&2 echo "Target file $NAME.p12 already exists." exit 1 fi genpasswd "$NAME.p12.passwd" || exit 1 if [ ! -s "$CAID-pem.crt" ]; then curl -s "$WEB_CAREPO_URL/$CAID-pem.crt" -o "$CAID-pem.crt" || exit 1 fi openssl pkcs12 -password "file:$NAME.p12.passwd" -export -in "$NAME.crt" -inkey "$NAME.key" -certfile $CAID-pem.crt -name "$NAME" -out "$NAME.p12" || exit 1 echo "Target file \"$NAME.p12\" has been generated and secured using password $(<"$NAME.p12.passwd")" echo "Deprecated: Generate Java Keystore (JKS) file using: $PROGNAME keystore $BASENAME" exit 0 fi if [ "$ACTION" == "keystore" ] && [ "$2" != "" ]; then NAME=$2 if [ ! -s "$NAME.p12" ]; then >&2 echo "No $NAME.p12 file!" exit 1 fi if [ -s "$NAME.keystore" ]; then >&2 echo "Target file $NAME.keystore already exists." exit 1 fi KEYTOOL_OPT="" if [ -f "$NAME.p12.passwd" ]; then KEYTOOL_OPT="$KEYTOOL_OPT -srcstorepass $(cat $NAME.p12.passwd)" fi genpasswd "$NAME.keystore.passwd" || exit 1 keytool -importkeystore -destkeystore $NAME.keystore -deststoretype JKS -deststorepass $(<"$NAME.keystore.passwd") -destkeypass $(<"$NAME.keystore.passwd") -srckeystore $NAME.p12 -srcstoretype PKCS12 $KEYTOOL_OPT -alias "$NAME" || exit 1 echo "Target file \"$NAME.keystore\" has been generated and secured using password $(<"$NAME.keystore.passwd")" exit 0 fi if [ "$ACTION" == "ovpn" ] && [ "$2" != "" ]; then NAME=$2 if [ ! -s "$NAME.key" ]; then >&2 echo "No $NAME.key file!" exit 1 fi if [ ! -s "$NAME.crt" ]; then >&2 echo "No $NAME.crt file!" exit 1 fi if [ -s "$NAME.ovpn" ]; then >&2 echo "Target file $NAME.ovpn already exists." exit 1 fi cat << __OVPN_END__ > $NAME.ovpn client dev tun remote ${OPENVPN_HOSTNAME:-vpn.example.com} 1194 nobind persist-key persist-tun cipher AES-256-CBC remote-cert-tls server verb 1 auth-nocache # $WEB_CAREPO_URL/$CAID-pem.crt $(curl -s "$WEB_CAREPO_URL/$CAID-pem.crt") # Klucz prywatny i certyfikat w magazynie certyfikatow Windows (CryptoAPI) #cryptoapicert "THUMB:$(openssl x509 -in $NAME.crt -fingerprint -noout| sed -r 's|^SHA1 Fingerprint=||')" # Klucz prywatny i certyfikat w treści pliku konfiguracyjnego .OVPN $(cat $NAME.crt) $(cat $NAME.key) __OVPN_END__ echo "Target file \"$NAME.ovpn\" has been generated. Import it to your OpenVPN client." exit 0 fi usage exit 1