在批处理模式下使用 gpg --search-keys
我正在开发一个应用程序,最终会绘制出一组预定义电子邮件地址之间的gpg签名连接。我需要它能够自动从密钥服务器收集公钥。我已经有一个可以工作的模型,它会使用gpg的--search-keys选项。不过,当我加上--batch这个标志运行时,出现了一个错误:“gpg: 抱歉,我们处于批处理模式 - 无法获取输入”。如果不加--batch标志,gpg就会要求输入。
我希望能找到一个我可能错过的gpg标志。或者,如果有一个库(最好是python的)可以与密钥服务器互动,那也可以。
5 个回答
我们可以通过指定 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
在hkps服务器的情况下,下面的内容可以使用:
gpg --keyserver hkps://***HKPSDOMAIN*** --recv-keys \
$(curl -s "https://***HKPSDOMAIN***/?op=index&options=mr&search=***SEARCHSTRING***"\
|grep pub|awk -F ":" '{print $2}')
使用 --recv-keys 可以在不需要确认的情况下获取密钥。
使用
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 ..
应该就能正常工作了。
GnuPG在导入非常大规模的信任网络时,表现得并不好,特别是在导入的阶段。
我建议你可以搭建一个本地的密钥服务器,把所有的密钥都放进去(2014年下载的大小不到10GB),然后直接查询你自己的本地密钥服务器。
Hockeypuck的设置相对简单,查询也很方便,因为它把数据存储在一个PostgreSQL数据库里。