用`gpg –recv-key`下载密钥,同时检查脚本中的指纹

如何通过gpg --recv-key导入gpg --recv-key并自动检查它的指纹? 理想情况下,我会直接使用gpg --recv-key $fingerprint ,但是gpg最近才添加了一个检查 ,即接收到的密钥实际上有正确的指纹,而不是盲目地信任密钥服务器,并且修复没有着落我关心的所有发行版(例如,Docker Ubuntu Image仍然有一个旧的gpg版本)。

我想和apt-key一起使用它来将一个PPA添加到一个docker容器中。

解:

 #!/bin/bash set -e tempName=$(mktemp) gpg --status-fd 1 --keyserver keyserver.ubuntu.com --recv-keys $fingerprint 1> $tempName 2>/dev/null grep "^\[GNUPG\:\] IMPORT_OK "[[:digit:]]*" "$fingerprint"$" $tempName grep "^\[GNUPG\:\] IMPORT_RES 1" $tempName 

如果密钥无法下载,或者密钥服务器返回恶意密钥,则此脚本将返回非零退出代码。 注意:恶意的密钥仍然在gpg密钥环中,所以如果你在Dockerfile之外使用恶意密钥,你可能会想要恢复原来的密钥环。 在Dockerfile中使用的命令(例如添加防锈PPA):

 RUN echo "deb http://ppa.launchpad.net/hansjorg/rust/ubuntu trusty main" >> /etc/apt/sources.list RUN echo "deb-src http://ppa.launchpad.net/hansjorg/rust/ubuntu trusty main" >> /etc/apt/sources.list RUN bash -c 'set -e;tempName=$(mktemp);apt-key adv --status-fd 1 --keyserver keyserver.ubuntu.com --recv-keys C03264CD6CADC10BFD6E708B37FD5E80BD6B6386 1> $tempName 2>/dev/null;grep "^\[GNUPG\:\] IMPORT_OK [[:digit:]]* C03264CD6CADC10BFD6E708B37FD5E80BD6B6386$" $tempName;grep "^\[GNUPG\:\] IMPORT_RES 1" $tempName' 

说明:

要考虑的第一个构build块是GnuPGs --status-fd选项。 它告诉gpg将机器可读输出写入给定的文件描述符。 文件描述符1总是引用stdout,所以我们将使用它。 那么我们将不得不找出--status-fd的输出结果。 文档不在手册页中,而是在doc/DETAILS 。 示例输出如下所示:

 # gpg --status-fd 1 --keyserver keyserver.ubuntu.com --recv-keys BD6B6386 2>/dev/null [GNUPG:] IMPORTED 37FD5E80BD6B6386 Launchpad PPA for Hans Jørgen Hoel [GNUPG:] IMPORT_OK 1 C03264CD6CADC10BFD6E708B37FD5E80BD6B6386 [GNUPG:] IMPORT_RES 1 0 1 1 0 0 0 0 0 0 0 0 0 0 

所以我们正在寻找IMPORT_OKIMPORT_RES行。 IMPORT_OK之后的第二个参数是导入密钥的实际指纹。 IMPORT_RES之后的第一个参数是导入的密钥数量。

在输出中, gpg转义换行符 ,因此可以匹配以[GNUPG:]开头的行来断言我们不匹配由攻击者控制的string(例如,密钥中的名称字段可能包含\n[GNUPG:] IMPORT_OK 1 C03264CD6CADC10BFD6E708B37FD5E80BD6B6386]并通过创build匹配来欺骗我们)。

对于grep,我们可以通过grep "^\[GNUPG\:\]"匹配以[GNUPG] sometext开始的行,对于grep "^\[GNUPG\:\] sometext$"的整行grep "^\[GNUPG\:\] sometext$"^$表示一行的开始和结束)。 根据文件, IMPORT_OK以下的任何数字对我们来说都可以,所以我们匹配"[[:digit:]]*" 。 因此,作为正则expression式,我们得到"^\[GNUPG\:\] IMPORT_OK "[[:digit:]]*" "$fingerprint"$""^\[GNUPG\:\] IMPORT_RES 1"

由于我们想要匹配输出两次,我们将其安全地保存到一个临时文件中(通过使用mktemp创build一个空的临时文件并重新路由该文件中的输出)。 如果grep不匹配任何行,则返回一个非零的错误代码。 我们可以通过set -e来指示bash中止任何错误。 总的来说,我们最终得到:

 set -e tempName=$(mktemp) gpg --status-fd 1 --keyserver keyserver.ubuntu.com --recv-keys $fingerprint 1> $tempName 2>/dev/null grep "^\[GNUPG\:\] IMPORT_OK "[[:digit:]]*" "$fingerprint"$" $tempName grep "^\[GNUPG\:\] IMPORT_RES 1" $tempName 

如何使用apt来添加存储库密钥: apt-key具有adv命令将命令行参数直接交给gpg(运行上述命令,不输出重新路由以查看由apt-key生成的实际gpg命令)。 因此,我们可以简单地使用apt-key adv来交换gpg来操作存储库密钥环。