From aac16ab2cbd31d783f98a1ffe814a363886f74f4 Mon Sep 17 00:00:00 2001 From: Silvio Rhatto Date: Fri, 19 Aug 2022 11:17:15 -0300 Subject: Fix re-encryption when the secret hass NULL bytes --- ChangeLog | 4 +++ lib/keyringer/actions/recrypt | 59 +++++++++++++++++++++++++++++++++++-------- 2 files changed, 52 insertions(+), 11 deletions(-) diff --git a/ChangeLog b/ChangeLog index 7b6fae2..0c39eb4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2022-08-19 - unreleased - Silvio Rhatto + + Fix re-encryption when the secret hass NULL bytes + 2022-06-07 - 0.5.7 - Silvio Rhatto New upstream URLs diff --git a/lib/keyringer/actions/recrypt b/lib/keyringer/actions/recrypt index 0e2f6a0..5542bfc 100755 --- a/lib/keyringer/actions/recrypt +++ b/lib/keyringer/actions/recrypt @@ -9,33 +9,66 @@ source "$LIB" readwrite $* || exit 1 # Recrypt a single secret function keyringer_recrypt { - # Get file keyringer_get_file "$1" # Set recipients file keyringer_set_recipients "$FILE" - # Decrypt - decrypted="$($GPG --use-agent -d "$KEYDIR/$FILE")" + # Verbosity + echo "Processing $FILE..." - if [ "$?" != "0" ]; then - echo "Decryption error on $1." - exit 1 - fi + # Recrypt in stages. This approach will fail for secrets that have NULL bytes, since + # bash can't hold those as variables. + # + # In that case, it would lead to the following warning: + # + # lib/keyringer/actions/recrypt: line 20: warning: command substitution: ignored null byte in input + # + # See https://stackoverflow.com/a/42493691 + # + ## Decrypt + #decrypted="$($GPG --use-agent -d "$KEYDIR/$FILE")" + + #if [ "$?" != "0" ]; then + # echo "Decryption error on $1." + # exit 1 + #fi + + ## Recrypt + #recrypted="`echo "$decrypted" | $GPG --use-agent --armor -e -s $(keyringer_recipients "$RECIPIENTS_FILE")`" + + #if [ "$?" != "0" ]; then + # echo "Recryption error on $1." + # exit 1 + #fi - # Recrypt - recrypted="`echo "$decrypted" | $GPG --use-agent --armor -e -s $(keyringer_recipients "$RECIPIENTS_FILE")`" + #unset decrypted + #echo "$recrypted" > "$KEYDIR/$FILE" + + # As we can't use variables as the secret material can contain NULL bytes, we + # use a temporary file instead + set -o pipefail + mkdir -p -m 700 "$TMPWORK/`dirname $FILE`" + $GPG --use-agent -d "$KEYDIR/$FILE" | $GPG --use-agent --armor -e -s $(keyringer_recipients "$RECIPIENTS_FILE") -o "$TMPWORK/$FILE.recrypted" if [ "$?" != "0" ]; then echo "Recryption error on $1." + + if [ -e "$TMPWORK/$FILE.recrypted" ]; then + keyringer_shred "$TMPWORK/$FILE.recrypted" + fi + exit 1 fi - unset decrypted - echo "$recrypted" > "$KEYDIR/$FILE" + # Move the re-encrypted secret only if there was no error + mv "$TMPWORK/$FILE.recrypted" "$KEYDIR/$FILE" } +# Set a tmp file +keyringer_set_tmpfile recrypt -d + # Syntax check and dispatcher if [ ! -z "$2" ]; then keyringer_recrypt $2 @@ -46,3 +79,7 @@ else fi done fi + +# Cleanup +rm -rf "$TMPWORK" +trap - EXIT -- cgit v1.2.3