|
| 1 | +#!/bin/sh |
| 2 | + |
| 3 | +# This uses the public/private keys on a PIV device, like a CAC or Yubikey. |
| 4 | +# It uses a PIN stored in a file. |
| 5 | +# It uses OpenSSL with PKCS11 enabled via OpenSC. |
| 6 | + |
| 7 | +[ "$#" -ne 1 ] && echo "cluster_key_command usage: $0 \"%d\"" 1>&2 && exit 1 |
| 8 | +# Supports environment variable PIV_PIN_FILE |
| 9 | +# No need for %R or -R since we are not prompting for a PIN |
| 10 | + |
| 11 | +DIR="$1" |
| 12 | +[ ! -e "$DIR" ] && echo "$DIR does not exist" 1>&2 && exit 1 |
| 13 | +[ ! -d "$DIR" ] && echo "$DIR is not a directory" 1>&2 && exit 1 |
| 14 | + |
| 15 | +# Set these here or pass in as environment variables. |
| 16 | +# File that stores the PIN to unlock the PIV |
| 17 | +#PIV_PIN_FILE='' |
| 18 | +# PIV slot 3 is the "Key Management" slot, so we use '0:3' |
| 19 | +PIV_SLOT='0:3' |
| 20 | + |
| 21 | +# File containing the cluster key encrypted with the PIV_SLOT's public key |
| 22 | +KEY_FILE="$DIR/pivpass.key" |
| 23 | + |
| 24 | + |
| 25 | +# ---------------------------------------------------------------------- |
| 26 | + |
| 27 | +[ ! "$PIV_PIN_FILE" ] && echo 'PIV_PIN_FILE undefined' 1>&2 && exit 1 |
| 28 | +[ ! -e "$PIV_PIN_FILE" ] && echo "$PIV_PIN_FILE does not exist" 1>&2 && exit 1 |
| 29 | +[ -d "$PIV_PIN_FILE" ] && echo "$PIV_PIN_FILE is a directory" 1>&2 && exit 1 |
| 30 | + |
| 31 | +[ ! "$KEY_FILE" ] && echo 'KEY_FILE undefined' 1>&2 && exit 1 |
| 32 | +[ -d "$KEY_FILE" ] && echo "$KEY_FILE is a directory" 1>&2 && exit 1 |
| 33 | + |
| 34 | +# Create a cluster key encrypted with the PIV_SLOT's public key? |
| 35 | +if [ ! -e "$KEY_FILE" ] |
| 36 | +then # The 'postgres' operating system user must have permission to |
| 37 | + # access the PIV device. |
| 38 | + |
| 39 | + openssl rand -hex 32 | |
| 40 | + if ! openssl rsautl -engine pkcs11 -keyform engine -encrypt \ |
| 41 | + -inkey "$PIV_SLOT" -passin file:"$PIV_PIN_FILE" -out "$KEY_FILE" |
| 42 | + then echo 'cluster key generation failed' 1>&2 |
| 43 | + exit 1 |
| 44 | + fi |
| 45 | + |
| 46 | + # Warn the user to save the cluster key in a safe place |
| 47 | + cat 1>&2 <<END |
| 48 | +
|
| 49 | +WARNING: The PIV device can be locked and require a reset if too many PIN |
| 50 | +attempts fail. It is recommended to run this command manually and save |
| 51 | +the cluster key in a secure location for possible recovery. |
| 52 | +END |
| 53 | + |
| 54 | +fi |
| 55 | + |
| 56 | +# Decrypt the cluster key encrypted with the PIV_SLOT's public key |
| 57 | +if ! openssl rsautl -engine pkcs11 -keyform engine -decrypt \ |
| 58 | + -inkey "$PIV_SLOT" -passin file:"$PIV_PIN_FILE" -in "$KEY_FILE" |
| 59 | +then echo 'cluster key decryption failed' 1>&2 |
| 60 | + exit 1 |
| 61 | +fi |
| 62 | + |
| 63 | +exit 0 |
0 commit comments