如何 return 不在 bash 中退出的 gpg 命令的退出值来验证错误的密码?

How to return an exit value for gpg command that does not exit in bash to validate wrong passphrase?

在 GPG 中,没有关于如何通过 bash 代码检查有效密码的适当文档,因此,这是一个 hack。基于以下示例代码,用于检查缓存在 gpg-agent 中的 GPG 密码是否有效:

#!/bin/bash
KEY_ID=YOUR_KEY_ID
echo "1234" | gpg -q --batch --status-fd 1 --sign --local-user $KEY_ID --passphrase-fd 0 --output /dev/null
return_code=$?
if [ "$return_code" = 0 ]; then
 echo "Valid passphrase has been set in gpg-agent"
   else
 echo "Invalid passphrase or no passphrase is set in gpg-agent"
fi

如果设置了有效的密码,当我运行这个bash脚本时,return值为0。这是正确的

但是

如果没有设置密码或设置无效密码,我可以看到该命令正在等待一些未知的输入或进程并且它不会退出(闪烁的光标直到我用 CTRL+C 终止)。但这是一个很好的信号,表明提供了无效的密码。

我的问题是,如果提供了无效的密码,我该如何强制命令退出并获得 return 值 1,以便我可以正确使用 if else 条件?

从代码中重现问题的注意事项和信息(这不是问题):

设置gpg密码有两种方式:

  1. gpg --export-secret-keys -a <KEY_ID>(这可以验证密码)或
  2. bash 中没有提示:/usr/libexec/gpg-preset-passphrase -c $KEY_GRIP <<< $PASSPHRASE(这不会验证密码)。我需要为 cron 使用命令。为什么?阅读下文。

清除密码我这样做: echo RELOADAGENT | gpg-connect-agent

KEY_ID - 你在第一次创建证书时得到

KEY_GRIP - 可以用这个命令获得:gpg --with-keygrip --list-secret-keys $KEY_ID.

PASSPHRASE - 是您的证书在 gpg-agent 中缓存的密码。

请注意,如果您使用此方法在 gpg-agent 中缓存密码:/usr/libexec/gpg-preset-passphrase -c $KEY_GRIP <<< $PASSPHRASE,它不会验证密码,因为错误的密码也可以缓存在 gpg-agent 中。此方法是在 运行 作为 cron 时跳过交互式输入的唯一方法,以防止脚本错误,因为没有用户输入。这就是我使用黑客代码的原因。

您可以尝试类似的方法:

echo "1234" | gpg -q --batch --status-fd 1 --sign --local-user <KEY_ID> --passphrase-fd 0 --output /dev/null ||
{
    echo "Invalid passphrase or no passphrase is set in gpg-agent"
    exit
}
echo "Valid passphrase has been set in gpg-agent"

我不确定这是否可以处理看起来等待输入的内容。

如果可以的话, 您可以启动另一个脚本来计算该脚本的执行时间。如果实际脚本退出然后更正密码,否则,如果设置的时间到达,你杀死脚本的 PID 并且脚本结束。

我找到了这个问题的答案。由于错误,return 代码未正确输出。我只需要修改代码,使其不会使用默认 pin-entry 密码提示。使用 pin-entry 密码可能会导致 return 代码基于此相关错误 (https://dev.gnupg.org/T5076) 随机卡住。所以简而言之,return 代码随机卡住,但这可以使用此选项解决:

--pinentry-mode=loopback

所以,上面的选项是禁用 pin-entry 提示输入密码,我们可以使用 gpg-preset-passphrase 实用程序来代替在终端中设置密码。所以,使用这种方法我可以获得正确的 return 代码。

我发现这个线程讨论如何在 gpg-agent 中禁用 pin 输入,例如:here

所以这是验证密码时使用正确 return 代码的工作代码:

#!/bin/bash
gpg-agent --daemon
KEY_ID=ABC12321SS
GPG_PRESET_PASS="/usr/libexec/gpg-preset-passphrase" # This utility came with gpg
KEY_GRIP=$(gpg --with-keygrip --list-secret-keys "$KEY_ID" | grep -Pom1 '^ *Keygrip += +\K.*') # Get they key grip
# Ask passphrase
read -s -p "Enter a passphrase to cache into a running gpg-agent: " PASSPHRASE; echo
# Cache RAW passphrase here. RAW passphrase means un-validated passphrase. Passphrase can be valid or invalid cached in gpg-agent.
$GPG_PRESET_PASS -c $KEY_GRIP <<< $PASSPHRASE 
# AND NOW WE check if a RAW passphrase is cached:
RET_VAL=$?
if [ $RET_VAL = 0 ]; then
        echo "Un-validated (RAW) passphrase is cached"
        # This is the part that I must use --pinentry-mode=loopback, so I will get correct return code
        echo "Now validating a RAW cached passphrase from gpg-agent ..."
        test=$(echo "1234" | gpg -q --pinentry-mode=loopback --status-fd 1 --sign --local-user "$KEY_ID" --passphrase-fd 0 > /dev/null)
        RET_VAL=$?
        if [ $RET_VAL = 0 ]; then
                echo "Passphrase is valid"
        else
                echo "Passphrase is invalid"
                # Can clear the passphrase and ask again for RAW passphrase
        fi

else
        echo "Error when trying to cache RAW passphrase"
        exit 1
        # Run again the script to cache RAW passphrase
fi