#!/usr/bin/env zsh # zeasypki -- easy PKI # Copyright (C) 2022-2024 Sergey Matveev setopt ERR_EXIT PIPE_FAIL COUNTRY=${COUNTRY:-RU} path=( ~/work/gogost/cmd/cer-selfsigned-example ~/work/gogost/cmd/cer-dane-hash $path ) key_encrypt() { age -R ~/.age/general.pub } key_decrypt() { age -d -i ~/.age/general.age } # ------------------------ >8 ------------------------ usage() { cat >&2 < $tmpl < $key certtool \ --generate-self-signed \ --load-privkey $key \ --template $tmpl \ --outfile $cert reply=(${mapfile[$key]} ${mapfile[$cert]}) } ca_new_ecdsa() { ca_new_xdsa "--key-type=ecdsa --bits 512" $1 } ee_key_new_ecdsa() { certtool_genkey "--key-type=ecdsa --bits 256" } ca_new_eddsa() { ca_new_xdsa "--key-type=ed25519" $1 } ee_key_new_eddsa() { certtool_genkey "--key-type=ed25519" } ee_key_new_gost() { cer-selfsigned-example -cn does-not-matter -ai 256A -only-key } ee_renew_xdsa() { local algo=$1 local ca=$2 local domain=$3 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/$algo/$ca mapfile[$cakey]=$REPLY key_get ee/$algo/$ca/$domain mapfile[$key]=$REPLY cat > $tmpl <> $cakey cat >> $cakey < ca/gost/$ca/cer.pem key_get ee/gost/$ca/$domain mapfile[$key]=$REPLY cer-selfsigned-example \ -issue-with $cakey \ -reuse-key $key \ -cn $domain -country $COUNTRY -ai 256A } ca_new_gost() { local domain=$1 local key=`mktemp` local cert=`mktemp` trap "rm -f $key $cert" HUP PIPE INT QUIT TERM EXIT cer-selfsigned-example \ -ca \ -cn $domain \ -country $COUNTRY \ -ai 512C \ -out-key $key \ -out-cert $cert reply=(${mapfile[$key]} ${mapfile[$cert]}) } dane_ecdsa() { certtool --key-id --hash=sha256 } dane_eddsa() { dane_ecdsa } dane_gost() { cer-dane-hash } case $1 in (ca) [[ $# -eq 3 ]] || usage algo=$2 domain=$3 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 _umask=`umask` umask 077 mapfile[${dst}/key.pem]=${reply[1]} umask $_umask mapfile[${dst}/cer.pem]=${reply[2]} print $dst ;; (encrypt) [[ $# -eq 2 ]] || usage 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 cols=(${(s:/:)2}) algo=${cols[2]} ca=${cols[3]} domain=${cols[4]} dst=ee/$algo/$ca/$domain [[ $dst = $2 ]] zf_mkdir -p $dst [[ ! -s $dst/key.pem ]] || { print $dst/key.pem already exists >&2 exit 1 } _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 cols=(${(s:/:)2}) algo=${cols[2]} ca=${cols[3]} 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) zmodload -F zsh/datetime b:strftime export LC_ALL=C for cer (**/cer.pem) { certtool --certificate-info < $cer | while read line ; do [[ ! $line =~ "^Not After: .*" ]] || break done [[ $MATCH ]] # Not After: Sat Jul 02 10:02:29 UTC 2022 cols=(${=MATCH}) strftime -s ts_ugly -r "%b %d %H:%M:%S UTC %Y" ${(j: :)cols[4,-1]} strftime -s ts_good %F $ts_ugly print REM $ts_good +30 MSG $cer } ;; (list) print -C1 ee/*/*/*(/on) ;; (list-ca) print -C1 ca/*/*(/on) ;; (*) usage ;; esac