#!/usr/bin/env zsh # zeasypki -- easy PKI # Copyright (C) 2022 Sergey Matveev set -e CERTTOOL=${CERTTOOL:-certtool} GPG=${GPG:-gpg} KEY_ENCRYPT_RECIPIENT=${KEY_ENCRYPT_RECIPIENT:-CF60E89A59231E76E2636422AE1A8109E49857EF} COUNTRY=${COUNTRY:-RU} goston() { path=(~/local/stow/py310/bin ~/work/pygost/pygost/asn1schemas $path) export -TU PYTHONPATH pythonpath pythonpath=(~/work/pygost ~/work/pyderasn) } key_encrypt() { ${=GPG} --encrypt --recipient $KEY_ENCRYPT_RECIPIENT } key_decrypt() { ${=GPG} --decrypt } # ------------------------ >8 ------------------------ usage() { >&2 < $tmpl < $key ${=CERTTOOL} \ --generate-self-signed \ --load-privkey $key \ --template $tmpl \ --outfile $cert reply=(${mapfile[$key]} ${mapfile[$cert]}) } ee_key_new_ecdsa() { certtool_genkey 256 } ee_key_new_gost() { goston cert-selfsigned-example.py --cn does-not-matter --ai 256A --only-key } ee_renew_ecdsa() { local ca=$1 local domain=$2 local cakey=`mktemp` local key=`mktemp` local tmpl=`mktemp` local cert=`mktemp` trap "rm -f $cakey $key $tmpl $cert" HUP PIPE INT QUIT TERM EXIT key_get ca/ecdsa/$ca mapfile[$cakey]=$REPLY key_get ee/ecdsa/$ca/$domain mapfile[$key]=$REPLY > $tmpl <> $cakey < ca/gost/$ca/cer.pem key_get ee/gost/$ca/$domain mapfile[$key]=$REPLY cert-selfsigned-example.py \ --issue-with $cakey \ --reuse-key $key \ --cn $domain --country $COUNTRY --ai 256A } ca_new_gost() { local domain=$1 goston local key=`mktemp` local cert=`mktemp` trap "rm -f $key $cert" HUP PIPE INT QUIT TERM EXIT cert-selfsigned-example.py \ --ca \ --cn $domain \ --country $COUNTRY \ --serial 1 \ --ai 512C \ --out-key $key \ --out-cert $cert reply=(${mapfile[$key]} ${mapfile[$cert]}) } dane_ecdsa() { ${=CERTTOOL} --key-id --hash=sha256 } dane_gost() { goston cert-dane-hash.py } case $1 in (ca) [[ $# -eq 3 ]] || usage local algo=$2 local domain=$3 local dst=ca/$algo/$domain zf_mkdir -p $dst [[ -s $dst/key.pem ]] && { print $dst/key.pem already exists >&2 exit 1 } ca_new_${algo} $domain local _umask=`umask` umask 077 mapfile[${dst}/key.pem]=${reply[1]} umask $_umask mapfile[${dst}/cer.pem]=${reply[2]} print $dst ;; (encrypt) [[ $# -eq 2 ]] || usage local key=$2/key.pem [[ -s $key ]] || { print no $key found >&2 exit 1 } umask 077 key_encrypt < $key > $key.enc rm $key ;; (new) [[ $# -eq 2 ]] || usage local cols=(${(s:/:)2}) local algo=${cols[2]} local ca=${cols[3]} local domain=${cols[4]} local dst=ee/$algo/$ca/$domain [[ $dst = $2 ]] zf_mkdir -p $dst [[ -s $dst/key.pem ]] && { print $dst/key.pem already exists >&2 exit 1 } local _umask=`umask` umask 077 ee_key_new_${algo} > $dst/key.pem umask $_umask ee_renew_${algo} $ca $domain > $dst/cer.pem ;; (renew) [[ $# -eq 2 ]] || usage local cols=(${(s:/:)2}) local algo=${cols[2]} local ca=${cols[3]} local domain=${cols[4]} ee_renew_${algo} $ca $domain > ee/$algo/$ca/$domain/cer.pem ;; (dane) [[ $# -eq 2 ]] || usage dane_${${(s:/:)2}[2]} < $2/cer.pem ;; (keypair) [[ $# -eq 2 ]] || usage key_get $2 print -- "$REPLY" cat $2/cer.pem ;; (rem) setopt GLOB_STAR_SHORT export LC_ALL=C for cer (**/cer.pem) { date_bad_format=`certtool -i < $cer | perl -ne '/Not After: \w+ (\w+ \d+ \d+:\d+):\d+ UTC (\d+)/ && print "$1 $2"'` date_good_format=`date -j -f "%b %d %H:%M %Y" "$date_bad_format" +"%Y-%m-%d"` print REM $date_good_format +30 MSG $cer } ;; (list) print -C1 ee/*/*/*(/on) ;; (list-ca) print -C1 ca/*/*(/on) ;; (*) usage ;; esac