在批处理模式下使用 gpg --search-keys

1 投票
5 回答
3860 浏览
提问于 2025-04-18 13:53

我正在开发一个应用程序,最终会绘制出一组预定义电子邮件地址之间的gpg签名连接。我需要它能够自动从密钥服务器收集公钥。我已经有一个可以工作的模型,它会使用gpg的--search-keys选项。不过,当我加上--batch这个标志运行时,出现了一个错误:“gpg: 抱歉,我们处于批处理模式 - 无法获取输入”。如果不加--batch标志,gpg就会要求输入。

我希望能找到一个我可能错过的gpg标志。或者,如果有一个库(最好是python的)可以与密钥服务器互动,那也可以。

5 个回答

0

我们可以通过指定 2>&1 来把 gpg --search-keys 命令的标准输出和错误输出存储到变量中,然后对这些变量进行处理。例如,可以获取公钥的ID或者那些带有 *.amazon.com 邮箱地址的公钥:

pubkeyids=$(gpg --batch --keyserver hkp://keyserver.ubuntu.com --search-keys amazon.com 2>&1 | grep -Po '\d+\s*bit\s*\S+\s*key\s*[^,]+' | cut -d' ' -f5)

关于正则表达式的详细解释可以在 regex101.com 找到。我们可以通过解析输出,使用 bash 自动搜索公钥的ID并将它们添加到密钥环中。为了说明这个过程,我创建了一个 GitHub gist 来托管下面的代码。

示例地址列表 example.csv

名字 姓氏 邮箱地址
再见 hi@bye.com
yes@no.com
为什么 why@not.com

然后我们可以把CSV文件的路径传给一个bash脚本,这个脚本会添加所有属于CSV中邮箱地址的公钥:

$ getPubKeysFromCSV.sh ~/example.csv

这里是上述想法的实现,文件名是 getPubKeysFromCSV.sh

# CSV of email address
csv=$1

# Get headers from CSV
headers=$(head -1 $csv)

# Find the column number of the email address
emailCol=$(echo $headers | tr ',' '\n' | grep -n "Email Address" | cut -d':' -f1)

# Content of the CSV at emailCol column, skipping the first line
emailAddrs=$(tail -n +2 $csv | cut -d',' -f$emailCol)
gpgListPatrn='(?<entropy>\d+)\s*bit\s*(?<algo>\S+)\s*key\s*(?<pubkeyid>[^,]+)'
# Loop through the array and get the public keys
for email in "${emailAddrs[@]}"
do
    # Get the public key ids for the email address by matching the regex gpgListPatt
    pubkeyids=$(gpg --batch --keyserver hkp://keyserver.ubuntu.com --search-keys $email 2>&1 | grep -Po $gpgListPatrn | cut -d' ' -f5)
    # For each public key id, get the public key
    for pubkeyid in $pubkeyids
    do
        # Add the public key to the local keyring
        recvr=$(gpg --keyserver hkp://keyserver.ubuntu.com --recv-keys $pubkeyids 2>&1)
        # Check exit code to see if the key was added
        if [ $? -eq 0 ]; then
            # If the public key is added, do some extra work with it
            # [do stuff] 
        fi
    done
done

如果我们想的话,可以通过在循环体内验证文件签名来让 getPubKeysFromCSV.sh 变得更复杂,在成功添加公钥之后。除了CSV路径,我们还会将签名路径和文件路径作为第二和第三个参数传递:

$ getPubKeysFromCSV.sh ~/example.csv ./example.file.sig ./example.file

这里是更新后的脚本差异,使用 diff 显示:

--- original.sh
+++ updated.sh
@@ -1,6 +1,12 @@
 # CSV of email address
 csv=$1
 
+# signature file
+sig=$2
+
+# file to verify
+file=$3
+
 # Get headers from CSV
 headers=$(head -1 $csv)
 
@@ -22,5 +28,17 @@
         recvr=$(gpg --keyserver hkp://keyserver.ubuntu.com --recv-keys $pubkeyids 2>&1)
        # Check exit code to see if the key was added
+       if [ $? -eq 0 ]; then
+           verify=$(gpg --batch --verify $sig $file 2>&1)
+           # If the signature is verified, announce it was verified
+           # else, print error not verified and exit
+           if [[ $verify =~ "^gpg: Good signature from" ]]; then 
+               echo "$file was verified by $email using $pubkeyid" 
+           else 
+               printf '%s\n' "$file was unable to be verified" >&2
+               exit 1
+           fi
+       fi
     done
 done
0

在hkps服务器的情况下,下面的内容可以使用:

gpg --keyserver hkps://***HKPSDOMAIN*** --recv-keys \
$(curl -s "https://***HKPSDOMAIN***/?op=index&options=mr&search=***SEARCHSTRING***"\
|grep pub|awk -F ":" '{print $2}')
0

使用 --recv-keys 可以在不需要确认的情况下获取密钥。

2

使用

gpg --batch --keyserver hkp://pool.sks-keyservers.net --search-keys ...

然后解析输出,以获取关键的ID。

之后

gpg --batch --keyserver hkp://pool.sks-keyservers.net  --recv-keys key-id key-id ..

应该就能正常工作了。

0

GnuPG在导入非常大规模的信任网络时,表现得并不好,特别是在导入的阶段。

我建议你可以搭建一个本地的密钥服务器,把所有的密钥都放进去(2014年下载的大小不到10GB),然后直接查询你自己的本地密钥服务器。

Hockeypuck的设置相对简单,查询也很方便,因为它把数据存储在一个PostgreSQL数据库里。

撰写回答