Skip to content

Commit

Permalink
check if key used to sign a signing-key.public.asc was revoked/expired
Browse files Browse the repository at this point in the history
- ignore expired in case of --auto-trust true
- ask if user wants to take a closer look if expired and
  --auto-trust false => i.e. if user does not respond within 20 seconds
  we assume it is OK
- ask if user wants to trust signing-key.public.asc if key signing it
  was revoked after the signature was created
- error and ignore the signing-key.public.asc if the key signing it
  was revoked before the signature was created
  • Loading branch information
robstoll committed Oct 24, 2024
1 parent f66075e commit 21ebad4
Show file tree
Hide file tree
Showing 4 changed files with 167 additions and 15 deletions.
1 change: 1 addition & 0 deletions .gt/remotes/tegonal-scripts/pulled.tsv
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,4 @@ v4.0.0 src/releasing/prepare-next-dev-cycle-template.sh ../lib/tegonal-scripts/s
v4.0.0 src/utility/cleanups.sh ../lib/tegonal-scripts/src/utility/cleanups.sh c686d5e932d54ca5cb22531eb67bae9784c569d450c2005beb8960988ab5e7b0c55dac8c41e350abc5414091f37b643e9bf846cec3d754c49a058a43eed467de
v4.0.0 src/ci/install-shellspec.sh ../lib/tegonal-scripts/src/ci/install-shellspec.sh 3d6c88a7984e5d0eb6342050e5bfc789795d25df3b43adc674f607a6b6f8ea6200bc883f4ea9bb98ce6ba8b2f56cc36f718bdb7ac1455c715d087c14abc09fe1
v4.0.0 src/qa/run-shellspec-if-installed.sh ../lib/tegonal-scripts/src/qa/run-shellspec-if-installed.sh 7e540126a38a2d1184903760fca8970f544544e144544a735962ea260039e524e83d6257e648e0358c134187597830c88bbda184175182d83bb0f953954911a4
v4.0.0 src/utility/date-utils.sh ../lib/tegonal-scripts/src/utility/date-utils.sh ebd74294fb217aad3f1f233ffaeb3a66d06c529b6840a6b7c29413b7ad4576bd1f690a5f354bd7cc398c069ba094ff084828bec7713bbe19ca72eb1fef3ec701
59 changes: 59 additions & 0 deletions lib/tegonal-scripts/src/utility/date-utils.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#!/usr/bin/env bash
#
# __ __
# / /____ ___ ____ ___ ___ _/ / This script is provided to you by https://github.com/tegonal/scripts
# / __/ -_) _ `/ _ \/ _ \/ _ `/ / It is licensed under Apache License 2.0
# \__/\__/\_, /\___/_//_/\_,_/_/ Please report bugs and contribute back your improvements
# /___/
# Version: v4.0.0
#
####### Description #############
#
# utility functions for dealing with git
#
####### Usage ###################
#
# #!/usr/bin/env bash
# set -euo pipefail
# shopt -s inherit_errexit
#
# projectDir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]:-$0}")" >/dev/null && pwd 2>/dev/null)/.."
#
# # Assumes tegonal's scripts were fetched with gt - adjust location accordingly
# dir_of_tegonal_scripts="$projectDir/lib/tegonal-scripts/src"
# source "$dir_of_tegonal_scripts/setup.sh" "$dir_of_tegonal_scripts"
#
# sourceOnce "$dir_of_tegonal_scripts/utility/date-utils.sh"
#
# # converts the unix timestamp to a date in format Y-m-dTH:M:S
# timestampToDateTime 1662981524 # outputs 2022-09-12T13:18:44
#
# dateToTimestamp "2024-03-01" # outputs 1709247600
# dateToTimestamp "2022-09-12T13:18:44" # outputs 1662981524
#
###################################
set -euo pipefail
shopt -s inherit_errexit
unset CDPATH

if ! [[ -v dir_of_tegonal_scripts ]]; then
dir_of_tegonal_scripts="$(cd -- "$(dirname -- "${BASH_SOURCE[0]:-$0}")" >/dev/null && pwd 2>/dev/null)/.."
source "$dir_of_tegonal_scripts/setup.sh" "$dir_of_tegonal_scripts"
fi
sourceOnce "$dir_of_tegonal_scripts/utility/parse-fn-args.sh"

function timestampToDateTime() {
local timestamp
# shellcheck disable=SC2034 # is passed by name to parseFnArgs
local -ra params=(timestamp)
parseFnArgs params "$@"
date -d "@$timestamp" +"%Y-%m-%dT%H:%M:%S"
}

function dateToTimestamp() {
local dateAsString
# shellcheck disable=SC2034 # is passed by name to parseFnArgs
local -ra params=(dateAsString)
parseFnArgs params "$@"
date -d "$dateAsString" +%s
}
19 changes: 17 additions & 2 deletions src/gt-pull.sh
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,13 @@ sourceOnce "$dir_of_tegonal_scripts/utility/gpg-utils.sh"
sourceOnce "$dir_of_tegonal_scripts/utility/io.sh"
sourceOnce "$dir_of_tegonal_scripts/utility/parse-args.sh"

function gt_pull_cleanupGpgDir() {
local -r gpgDir=$1
if [[ -d $gpgDir ]]; then
deleteDirChmod777 "$gpgDir" &>/dev/null
fi
}

function gt_pull_cleanupRepo() {
# note, we want to cleanup also for normal exits, so no need to check for $?
local -r repository=$1
Expand Down Expand Up @@ -225,7 +232,7 @@ function gt_pull() {
die "looks like the remote \033[0;36m%s\033[0m is broken there is a file at the gpg dir's location: %s" "$remote" "$gpgDir"
fi

logInfo "gpg directory does not exist at %s\nWe are going to import %s from %s" "$gpgDir" "$signingKeyAsc" "$publicKeysDir"
logInfo "gpg directory does not exist at %s\nWe are going to import %s from %s" "$gpgDir" "$signingKeyAsc" "$publicKeysDir"

if ! [[ -f "$publicKeysDir/$signingKeyAsc" ]]; then
if [[ $unsecure == true ]]; then
Expand All @@ -234,9 +241,15 @@ function gt_pull() {
# we initialiseGpgDir so that we don't try it next time
initialiseGpgDir "$gpgDir"
else
die "\033[0;36m%s\033[0m not defined in %s" "$signingKeyAsc" "$publicKeysDir"
die "\033[0;36m%s\033[0m not defined in %s" "$signingKeyAsc" "$publicKeysDir"
fi
else
# we want to expand $gpgDir here and not when signal happens (as $gpgDir might be out of scope), hence we ignore
# shellcheck disable=SC2064
# we use this trap to delete the gpgDir in case something goes wrong during the import, i.e. to avoid that that
# we keep a gpg store with a non-trusted signing-key (which would then be used during gt pull and the like)
trap "gt_pull_cleanupGpgDir '$gpgDir'" EXIT

initialiseGpgDir "$gpgDir"

local -i numberOfImportedKeys=0
Expand Down Expand Up @@ -267,6 +280,8 @@ function gt_pull() {

# we want to expand $repo here and not when signal happens (as $repo might be out of scope)
# shellcheck disable=SC2064
# note, this replaces the previous EXIT trap gt_pull_cleanupGpgDir which is intentional, we want to keep the gpg dir
# now that it was established
trap "gt_pull_cleanupRepo '$repo'" EXIT

askToDeleteAndReInitialiseGitDirIfRemoteIsBroken "$workingDirAbsolute" "$remote"
Expand Down
103 changes: 90 additions & 13 deletions src/utils.sh
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ if ! [[ -v dir_of_tegonal_scripts ]]; then
dir_of_tegonal_scripts="$dir_of_gt/../lib/tegonal-scripts/src"
source "$dir_of_tegonal_scripts/setup.sh" "$dir_of_tegonal_scripts"
fi
sourceOnce "$dir_of_tegonal_scripts/utility/date-utils.sh"
sourceOnce "$dir_of_tegonal_scripts/utility/gpg-utils.sh"
sourceOnce "$dir_of_tegonal_scripts/utility/io.sh"
sourceOnce "$dir_of_tegonal_scripts/utility/parse-fn-args.sh"

Expand All @@ -35,7 +37,7 @@ function exitBecauseSigningKeyNotImported() {
local -ra params=(remote publicKeysDir gpgDir unsecureParamPatternLong signingKeyAsc)
parseFnArgs params "$@"

logError "%s not imported, you won't be able to pull files from the remote \033[0;36m%s\033[0m without using %s true\n" "$signingKeyAsc" "$remote" "$unsecureParamPatternLong"
logError "%s not imported, you won't be able to pull files from the remote \033[0;36m%s\033[0m without using %s true\n" "$signingKeyAsc" "$remote" "$unsecureParamPatternLong"
printf >&2 "Alternatively, you can:\n- place the %s manually in %s or\n- setup a gpg store yourself at %s\n" "$signingKeyAsc" "$publicKeysDir" "$gpgDir"
deleteDirChmod777 "$gpgDir"
exit 1
Expand Down Expand Up @@ -221,36 +223,106 @@ function validateSigningKeyAndImport() {

exitIfArgIsNotFunction "$validateSigningKeyAndImport_callback" 4

local autoTrustParamPattern signingKeyAsc
local autoTrustParamPatternLong signingKeyAsc
source "$dir_of_gt/common-constants.source.sh" || traceAndDie "could not source common-constants.source.sh"

local -r publicKey="$sourceDir/$signingKeyAsc"
local -r sigExtension="sig"
local -r sigFile="$publicKey.$sigExtension"

logInfo "Verifying if we trust %s\n" "$publicKey"

local confirm
confirm="--confirm=$(invertBool "$autoTrust")"
confirm=$(invertBool "$autoTrust")

local verified=false
local importIt=false

if ! [[ -f "$publicKey.$sigExtension" ]]; then
logWarning "There is no %s.%s next to %s, cannot verify it" "$signingKeyAsc" "$sigExtension" "$publicKey"
if ! [[ -f $sigFile ]]; then
logWarning "There is no %s next to %s, cannot verify it" "$sigFile" "$publicKey"
else
# note we verify the signature of the public key based on the normal gpg dir
# i.e. not based on the gpg dir of the remote but of the user
# which means we trust the public key only if the user trusts the public key which created the sig
if gpg --verify "$publicKey.$sigExtension" "$publicKey"; then
confirm="false"
importIt=true
if gpg --verify "$sigFile" "$publicKey"; then
verified=true
confirm=false
# new line on purpose to separate output of verify
echo ""

# signature is valid but it could be that the gpg key was expired or even revoked by now
local keyData keyId
keyData=$(getSigningGpgKeyData "$sigFile") || die "could not get the key data of %s" "$sigFile"
keyId=$(extractGpgKeyIdFromKeyData "$keyData")
if isGpgKeyInKeyDataExpired "$keyData"; then
local expirationTimestamp
expirationTimestamp=$(extractExpirationTimestampFromKeyData "$keyData") || die "could not extract the expiration timestamp out of the key data:\n%" "$keyData"
expirationDate=$(timestampToDateTime "$expirationTimestamp") || die "was not able to convert the expiration timestamp %s to a date" "$expirationTimestamp"

if [[ $autoTrust == true ]]; then
logInfo "The key %s used to sign %s expired at %s, ignoring it since you specified % true" "$keyId" "$publicKey" "$expirationDate" "$autoTrustParamPatternLong"
importIt=true
else
logInfo "The key %s used to sign %s expired at %s" "$keyId" "$publicKey" "$expirationDate"
if askYesOrNo "The signature as such is OK and thus we assume you still trust it. Or would you like to take a closer look at the key %s?" "$keyId"; then
listSignaturesAndHighlightKey "$keyId"
if askYesOrNo "Do you want to trust %s seeing now more details of the key %s which signed it" "$signingKeyAsc" "$keyId"; then
importIt=true
else
importIt=false
fi
else
importIt=true
fi

if [[ $importIt == true ]]; then
logInfo "trust confirmed for %s -- signature verified (see further above) via expired key %s" "$publicKey" "$keyId"
fi
fi
elif isGpgKeyInKeyDataRevoked "$keyData"; then
# key was revoked, lets see if the signature was created before the revocation,
# if so, then we ask the user if they still trust it
local getSigCreationDate sigCreationTimestamp
getSigCreationDate=$(getSigCreationDate "$sigFile") || die "could not get the creation date of the signature %s" "$sigFile"
sigCreationTimestamp=$(dateToTimestamp "$getSigCreationDate") || die "was not able to convert the signature creation date %s to a timestamp" "$getSigCreationDate"

local revData revCreatedTimestamp revCreate
revData=$(getRevocationData "$keyId" "") || die "could ont get the revocation data for key %s" "$keyId"
revCreatedTimestamp=$(extractCreationTimestampFromRevocationData "$revData") || die "was not able to extract the revocation creation timestamp from the revocation information:\n%" "$revData"
revCreate=$(timestampToDateTime "$revCreatedTimestamp") || die "was not able to convert the revocation creation timestamp %s to a date" "$revCreatedTimestamp"

if ((sigCreationTimestamp < revCreatedTimestamp)); then
logWarning "The key %s used to sign the %s was revoked at %s.\nHowever, the signature was created before at %s. You should take a closer look at the key and the reason why it was revoked to decide if you trust the signature." "$keyId" "$publicKey" "$revCreate" "$getSigCreationDate"

printf "Press enter to see the signatures of %s (will be shown automatically after 20 seconds)\n\n" "$keyId"
read -t 20 -r || true

listSignaturesAndHighlightKey "$keyId"

if askYesOrNo "Do you want to trust the %s although the key %s signing it was revoked?" "$signingKeyAsc" "$keyId"; then
logInfo "trust confirmed for %s -- signature verified (see further above) via revoked key %s" "$publicKey" "$keyId"
importIt=true
else
importIt=false
fi
else
logError "The key %s used to sign the %s was revoked at %s and but the signature was created afterwards at %s -- i.e. we cannot trust it" "$keyId" "$signingKeyAsc" "$revCreate" "$getSigCreationDate"
importIt=false
fi
else
logInfo "trust confirmed for %s -- signature verified" "$publicKey"
importIt=true
fi
else
# new line on purpose to separate output of verify
echo ""
logWarning "gpg verification failed for signing key \033[0;36m%s\033[0m -- if you trust this repo, then import the public key which signed %s into your personal gpg store" "$publicKey" "$signingKeyAsc"
fi
fi

if [[ $importIt != true ]]; then
if [[ $verified != true ]]; then
if [[ $autoTrust == true ]]; then
logInfo "since you specified %s true, we trust it nonetheless. This can be a security risk" "$autoTrustParamPattern"
logInfo "since you specified %s true, we trust it nonetheless. This can be a security risk" "$autoTrustParamPatternLong"
importIt=true
else
logInfo "You can still trust this repository via manual consent.\nIf you do, then the %s of this remote will be stored in the remote's gpg store (not in your personal store) located at:\n%s" "$signingKeyAsc" "$gpgDir"
Expand All @@ -260,12 +332,17 @@ function validateSigningKeyAndImport() {
echo "Decision: do not continue! Skipping this public key accordingly"
fi
fi
fi

local confirmationQuestion
if [[ $confirm == false ]]; then
confirmationQuestion=""
else
logInfo "trust confirmed (verified via public key, see further above)" "$publicKey"
confirmationQuestion="The above key(s) will be used to verify the files you will pull from this remote, do you trust them?"
fi

if [[ $importIt == true ]] && importGpgKey "$gpgDir" "$publicKey" "--confirm=$confirm"; then
"$validateSigningKeyAndImport_callback" "$publicKey" "$publicKey.$sigExtension"
if [[ $importIt == true ]] && echo "" && importGpgKey "$gpgDir" "$publicKey" "$confirmationQuestion"; then
"$validateSigningKeyAndImport_callback" "$publicKey" "$sigFile"
else
logInfo "deleting gpg key file $publicKey for security reasons"
rm "$publicKey" || die "was not able to delete the gpg key file \033[0;36m%s\033[0m, aborting" "$publicKey"
Expand Down

0 comments on commit 21ebad4

Please sign in to comment.