| #!/bin/sh |
| |
| # This uses the public/private keys on a PIV device, like a CAC or Yubikey. |
| # It requires a user-entered PIN. |
| # It uses OpenSSL with PKCS11 enabled via OpenSC. |
| # This stores the cluster encryption key encrypted with the PIV public |
| # key in $DIR. This is technically a three-level encryption |
| # architecture, with the third level requiring the PIV and PIN. |
| # Do not create any fie with extension "wkey" in $DIR; these are |
| # reserved for wrapped data key files. |
| |
| [ "$#" -lt 2 ] && echo "cluster_key_command usage: $0 \"%d\" %R [\"%p\"]" 1>&2 && exit 1 |
| # Supports environment variable PROMPT |
| |
| DIR="$1" |
| [ ! -e "$DIR" ] && echo "$DIR does not exist" 1>&2 && exit 1 |
| [ ! -d "$DIR" ] && echo "$DIR is not a directory" 1>&2 && exit 1 |
| |
| FD="$2" |
| [ ! -t "$FD" ] && echo "file descriptor $FD does not refer to a terminal" 1>&2 && exit 1 |
| |
| [ "$3" ] && PROMPT="$3" |
| |
| # PIV slot 3 is the "Key Management" slot, so we use '0:3' |
| PIV_SLOT='0:3' |
| |
| # File containing the cluster key encrypted with the PIV_SLOT's public key |
| KEY_FILE="$DIR/pivpass.key" |
| |
| |
| # ---------------------------------------------------------------------- |
| |
| [ ! "$PROMPT" ] && PROMPT='Enter PIV PIN: ' |
| |
| stty -echo <&"$FD" |
| |
| # Create a cluster key encrypted with the PIV_SLOT's public key? |
| if [ ! -e "$KEY_FILE" ] |
| then echo 1>&"$FD" |
| echo -n "$PROMPT" 1>&"$FD" |
| |
| # The 'postgres' operating system user must have permission to |
| # access the PIV device. |
| |
| openssl rand -hex 32 | |
| # 'engine "pkcs11" set.' message confuses prompting |
| if ! openssl rsautl -engine pkcs11 -keyform engine -encrypt \ |
| -inkey "$PIV_SLOT" -passin fd:"$FD" -out "$KEY_FILE" 2>&1 |
| then stty echo <&"$FD" |
| echo 'cluster key generation failed' 1>&2 |
| exit 1 |
| fi | grep -v 'engine "pkcs11" set\.' |
| |
| echo 1>&"$FD" |
| |
| # Warn the user to save the cluster key in a safe place |
| cat 1>&"$FD" <<END |
| |
| WARNING: The PIV can be locked and require a reset if too many PIN |
| attempts fail. It is recommended to run this command manually and save |
| the cluster key in a secure location for possible recovery. |
| END |
| |
| fi |
| |
| echo 1>&"$FD" |
| echo -n "$PROMPT" 1>&"$FD" |
| |
| # Decrypt the cluster key encrypted with the PIV_SLOT's public key |
| if ! openssl rsautl -engine pkcs11 -keyform engine -decrypt \ |
| -inkey "$PIV_SLOT" -passin fd:"$FD" -in "$KEY_FILE" 2>&1 |
| then stty echo <&"$FD" |
| echo 'cluster key retrieval failed' 1>&2 |
| exit 1 |
| fi | grep -v 'engine "pkcs11" set\.' |
| |
| echo 1>&"$FD" |
| |
| stty echo <&"$FD" |
| |
| exit 0 |