Created
November 10, 2021 15:15
-
-
Save leophys/350ee2b24170035bfd54acd9e4bb7f06 to your computer and use it in GitHub Desktop.
Use your tpm2 module to generate an ssh key (archlinux only)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
# | |
# DISCLAIMER: I am not sure this script won't nuke the content of your tpm module, so please, | |
# accept this risk before continuing. | |
# | |
# This script condensates the receipt found at https://incenp.org/notes/2020/tpm-based-ssh-key.html | |
# for an archlinux system. Running it will eventually install the dependencies, initialize the | |
# tpm2_pkcs11 store and generate a token and a key. From the key, an ssh public key will be generated. | |
# You can customize the some setting with env variables: KEY_PATH overrides the default path where the | |
# key is stored (~/.ssh/tpm2.key); with KEY_ALGO you can override the algorithm used to generate the key | |
# (issue tpm2_ptool addkey --help to list the supported algorithms). | |
# | |
# When the key has been generated, you can use it specifying | |
# | |
# $ ssh -I /usr/local/lib/pkcs11/libtpm2_pkcs11.so myserver.example | |
# | |
# or putting this in the ssh config | |
# | |
# Host myserver.example | |
# PKCS11Provider /usr/lib/pkcs11/libtpm2_pkcs11.so | |
# IdentityAgent none | |
set -o pipefail | |
if [ "z${DEBUG}" != "z" ] | |
then | |
set -x | |
fi | |
_PINENTRY=${PINENTRY:-"pinentry-gnome3"} | |
_KEY_PATH=${KEY_PATH:-"${HOME}/.ssh/tpm2.key"} | |
export TPM2_PKCS11_TCTI=tabrmd: | |
function get_pin() { | |
PROMPT1=$(cat <<EOP | |
SETPROMPT Please enter the ${1}: | |
GETPIN | |
EOP | |
) | |
PROMPT2=$(cat <<EOP | |
SETPROMPT Please enter the ${1} again to confirm: | |
GETPIN | |
EOP | |
) | |
PIN1=$(echo "${PROMPT1}" | \ | |
${_PINENTRY} | \ | |
sed -nr '0,/^D (.+)/s//\1/p') | |
PIN2=$(echo "${PROMPT2}" | \ | |
${_PINENTRY} | \ | |
sed -nr '0,/^D (.+)/s//\1/p') | |
if [ "${PIN1}" != "${PIN2}" ]; then | |
return 1 | |
else | |
PIN=${PIN1} | |
fi | |
return 0 | |
} | |
function get_sopin() { | |
while ! get_pin "sopin" | |
do | |
echo "Insert sopin" | |
done | |
SOPIN=$PIN | |
} | |
function get_userpin() { | |
while ! get_pin "userpin" | |
do | |
echo "Insert userpin" | |
done | |
USERPIN=$PIN | |
} | |
function check_dep_arch() { | |
IS_INSTALLED=$(pacman -Q ${1} 2>/dev/null|wc -l) | |
if [ ${IS_INSTALLED} -eq 0 ] | |
then | |
return 1 | |
fi | |
return 0 | |
} | |
function check_deps_arch() { | |
DEPS=$(cat <<EOD | |
openssh | |
tpm2-tss | |
tpm2-abrmd | |
tpm2-pkcs11 | |
tpm2-tools | |
yq | |
EOD | |
) | |
TO_BE_INSTALLED=$(echo "${DEPS}" |\ | |
while IFS=$'\n' read dep | |
do | |
if ! check_dep_arch "${dep}" | |
then | |
echo -n " ${dep}" | |
fi | |
done) | |
if [ "z${TO_BE_INSTALLED}" != "z" ] | |
then | |
ask_to_install "${TO_BE_INSTALLED}" | |
fi | |
} | |
function ask_to_install() { | |
echo "These packages are missing:${1}" | |
read -p "Do you want me to install them? [y/n]" -n 1 -r | |
echo | |
if [ "${REPLY}" != "y" ] && [ "${REPLY}" != "Y" ] | |
then | |
echo "Manually install the dependencies and re-run this script" | |
exit 1 | |
fi | |
sudo pacman -Sy ${1} | |
} | |
function maybe_init_ptool() { | |
if ! [ -d ${HOME}/.tpm2_pkcs11 ] | |
then | |
echo "Initing. This could take a while. Do not terminate." | |
mkdir ${HOME}/.tpm2_pkcs11 | |
tpm2_ptool init | |
fi | |
} | |
function check_token() { | |
ID=$(tpm2_ptool listprimaries|yq '.[] | .id') | |
ID_LEN=$(echo "${ID}"|wc -l) | |
if [ ${ID_LEN} -eq 0 ] | |
then | |
echo "No primary detected. Exiting" | |
exit -1 | |
elif ! [ ${ID_LEN} -eq 1 ] | |
then | |
select id in "${ID}" | |
do | |
ID="${id}" | |
break | |
done | |
fi | |
TOKENS=$(tpm2_ptool listtokens --pid=${ID}|yq '.[] | .id') | |
TOKENS_LEN=$(echo -n "${TOKENS}"|wc -l) | |
if [ ${TOKENS_LEN} -eq 0 ] | |
then | |
generate_token ${ID} | |
else | |
select token_id in "${TOKENS}" | |
do | |
TOKEN_ID=${token_id} | |
TOKEN_LABEL=$(tpm2_ptool listtokens --pid=${ID}|yq ".[] | select(.id == ${token_id}) | .label") | |
break | |
done | |
fi | |
} | |
function generate_token() { | |
tpm2_ptool addtoken \ | |
--pid=${1} \ | |
--label=${TOKEN_LABEL:-"ssh_token"} \ | |
--sopin=${SOPIN} \ | |
--userpin=${USERPIN} | |
} | |
function generate_key() { | |
export TSS2_LOG=fapi+NONE | |
tpm2_ptool addkey \ | |
--label=${TOKEN_LABEL:-"ssh_token"} \ | |
--userpin=${USERPIN} \ | |
--algorithm=${KEY_ALGO:-"ecc256"} && \ | |
ssh-keygen -D /usr/lib/pkcs11/libtpm2_pkcs11.so > ${_KEY_PATH} | |
} | |
function check_key() { | |
if [ -f ${_KEY_PATH} ] | |
then | |
echo "The key yet exists at ${_KEY_PATH}. Aborting." | |
exit 2 | |
fi | |
} | |
check_key | |
check_deps_arch | |
get_userpin | |
get_sopin | |
maybe_init_ptool | |
check_token | |
generate_key |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment