Git 错误 - gpg 无法签署数据

Git error - gpg failed to sign data

我刚开始使用 git,我通过自制软件安装了 git 和 gpg。 出于某种原因,我在 git commit 时收到此错误 我看了很多关于这个主题的其他 Whosebug 问题,其中 none 对我有用。 我该如何解决这个错误,以便我可以成功上传。

error: gpg failed to sign the data
fatal: failed to write commit object

对于故障排除,首先要尝试两件事:

  • 运行 gpg --version,并确保安装了 GnuPG 版本 2+(而非版本 1)
  • 运行echo "test" | gpg --clearsign,以确保gpg本身正常工作

如果一切正常,请尝试下一件事:

  • 运行 brew install pinentry 以确保您安装了用于输入密码的好工具

如果在安装之后,您重试 git commit 并且仍然收到“failed to sign the data”错误,请执行:

  • 运行 gpgconf --kill gpg-agent 杀死任何可能挂起的 运行ning 代理

否则,一些基本步骤 运行 检查您是否有一个工作的 GnuPG 环境:

  • 运行 gpg -K --keyid-format SHORT,检查您是否至少有一对密钥

如果输出显示您没有可供 GnuPG 使用的密钥,您需要创建一个:

  • 运行 gpg --gen-key,让 GnuPG 引导您完成创建密钥对的步骤

如果您收到一条错误消息 “设备的 ioctl 不合适”,请执行以下操作:

  • 运行 export GPG_TTY=$(tty) and/or 将其添加到您的 ~/.bashrc˜/.bash_profile

不知何故,您的 git 配置为 GPG 签署每个提交。使用 git 提交或推送不需要使用 GPG 签名。可能会出现错误,因为您的 gpg 签名机制尚未配置。

如果您是 git 的新手,请先尝试在没有 GPG 签名的情况下先运行它,然后在您确实需要时添加登录。

您可以验证您的 git 是如何配置 gpg 的:

git config -l | grep gpg

这可能会产生零行或多行,包括:

commit.gpgsign=true

如果 "commit.gpgsign" 为真,则您已启用 gpg 签名。禁用它:

git config --global --unset commit.gpgsign

然后再次尝试 运行 您的提交。它现在应该 运行 没有 gpg 签名。在你得到基本的 git 工作之后,你应该尝试将 gpg 签名重新添加到组合中。

Git 需要知道它用哪个密钥签名。

设置好 GPG、gpg-agent 和 gpg.conf 文件后(参见 this guide),您需要 运行

git config --global user.signingKey EB11C755

显然,将末尾的 public 键替换为您自己的键。如果您希望默认情况下对每个提交进行签名,请使用

git config --global commit.gpgsign true

$ gpg2 -K --keyid-format SHORT          # <-- Shows your keys, e.g.:
/home/<username>/.gnupg/pubring.kbx
-------------------------------
sec   rsa4096/0754B01E 2019-02-02 [SCA]             <--secret key
      C396BF3771782D7691B0641145E11B080754B01E
uid         [ultimate] John Doe <user@domain.com>
ssb   rsa4096/A20AB8EC 2019-02-02 [E]               <--public key

sec   rsa4096/25C504D5 2019-02-02 [SCA] [revoked: 2020-06-01]
      08BFF49B9E07E4B4B0C4946B645B6C1425C504D5
uid         [ revoked] John Doe <user2@domain.com>
uid         [ revoked] [jpeg image of size 2670]

其中 A20AB8EC 是您在此示例中查找的密钥 ID。

我已经为 certify / sign / encrypt 制作了一个 git 密钥,其中包含 3 个单独的密钥并且该密钥显示为将来过期(在工作正常之后几天):

pub   rsa4096/4CD1E9DA 2017-04-26 [C] [expired: 2017-04-28]
      Key fingerprint = 4670 59C1 7592 08B8 7FA5  313B 2A42 B6A6 4CD1 E9DA
uid         [ expired] Stuart Cardall (GIT Development Keys) <xxxxxx>
sub   rsa4096/5195E715 2017-04-26 [E] [expired: 2019-04-26]
sub   rsa4096/DB74C297 2017-04-26 [S] [expired: 2019-04-26]
sub   rsa2048/A3913A3C 2017-04-28 [] [expired: never     ]

创建一个新密钥而不添加单独的子密钥来解决问题。

检查您的密钥是否已过期。确定到期日期后(除非您愿意,否则无需创建新密钥),git 将照常工作。

修复过期密钥的一种方法:

(注:$表示命令行提示符,在提示符后键入命令;每条命令后按回车键)

$ gpg2 --list-keys 找到合适的密钥 ID(pub\ 之后的字符)

$ gpg2 --edit-key <key id> - 这将打开 gpg shell,提示更改为 gpg>

gpg> expire - 按照说明为主键设置新的到期日期

接下来,如果有过期的子项(sub 显示在行上),也重置它们的过期日期:

gpg> key 1 - 选择第一个子项
gpg> expire - 按照说明为子密钥设置新的到期日期

根据需要对每个后续子项重复。

当您的 GPG 密钥已过期时,也会发生此错误。生成新密钥并将其添加到 Git 应该可以解决此问题。

参考@sideshowbarker和@Xavier Ho的解决方案,我通过以下步骤解决了我的问题。

假设 gpg2 由 brew 安装,

git config --global gpg.program gpg2
brew install pinentry
gpgconf --kill gpg-agent
gpg2 -K --keyid-format SHORT
// no key found then generate new one
gpg2 --gen-key

gpg2 -K --keyid-format SHORT 

           

.../.gnupg/pubring.gpg

sec rsa2048/0A61C6FC 2017-06-29 [SC] [expires: 2019-06-29]

git config --global user.signingkey 0A61C6FC

同事提醒,需要追加

export GPG_TTY=$(tty)

如果使用 zsh,则添加到 ~/.zshrc,否则附加到 ~/.bash_profile


对于macOS,

gpg2 在 brew 中与 gpg 结合,因此 gpg 命令指向 gpg2

brew install gpg2

brew info gpg

gnupg: stable 2.2.6 (bottled)

git config --global gpg.program gpg
gpg -K --keyid-format SHORT 

并且有 pinentry-mac 用于密码输入

brew install pinentry-mac
vim ~/.gnupg/gpg-agent.conf

添加行

pinentry-program /usr/local/bin/pinentry-mac

同事提醒,需要追加

export GPG_TTY=$(tty)

如果使用 zsh,则添加到 ~/.zshrc,否则附加到 ~/.bash_profile

可能是您的 Git 配置已设置 gpgsign = true。如果您不想分配您的提交,请尝试将其设置为 false。转到您的存储库文件夹并更改文件

nano .git/config

由此...

[core]
    repositoryformatversion = 0
    filemode = true
    bare = false
    logallrefupdates = true
[remote "origin"]
    url = git@bitbucket.org:yourrepo/project.git
    fetch = +refs/heads/*:refs/remotes/origin/*
[branch "master"]
    remote = origin
    merge = refs/heads/master
[user]
    signingkey = <GPG-KEY>
[commit]
    gpgsign = true

为此...

[core]
    repositoryformatversion = 0
    filemode = true
    bare = false
    logallrefupdates = true
[remote "origin"]
    url = git@bitbucket.org:yourrepo/project.git
    fetch = +refs/heads/*:refs/remotes/origin/*
[branch "master"]
    remote = origin
    merge = refs/heads/master
[user]
    signingkey = <GPG-KEY>
[commit]
    gpgsign = false

升级到 gnupg 后我遇到了这个问题 2.x。它会看到 gpg2 以不同方式引用密钥:我的 ~/.gitconfig 中仍然有 signingkey = ABC98F11(gpg v1 设置)。 gpg2 的密钥标识符更长。使用 gpg --list-secret-keys

查找它们

对我来说,当我从 pinentry-gnome3 切换到 pinentry-curses(使用 update-alternatives --config pinentry)以便更容易时,Debian GNU/Linux 上的 git tag -s 开始出现此错误远程访问。它只发生在 git tag -s,而不是 gpg(例如 gpg --clearsign)本身。

在这种情况下让它再次工作所需的唯一更改是将 export GPG_TTY=$(tty) 添加到我的 shell 启动文件。

虽然我没有收到“Inappropriate ioctl for device”错误消息,但在这个问题的另一个答案中作为此修复的指标被提及。

注意:由于出现此错误的原因与之前在该问题的其他答案中建议 export GPG_TTY=$(tty)(通常作为附带提示)的人完全不同,我决定这个问题需要另一个答案,其中提到 export GPG_TTY=$(tty) 在某些情况下可能是主要修复和唯一必要的东西。

我解决了安装 brew install gpg2 然后执行 git config --global gpg.program gpg2

的问题

这将帮助您摆脱它

git config commit.gpgsign false

我正在使用它。它支持 zsh 并在 Windows 子系统上工作 Linux:

export GPG_TTY=$(tty)

其他用户已确认上述是 MacOS(例如 Catalina 10.15.7)所需的唯一更改。对于 Mac,将上面的内容添加到 ~/.zshrc.

证明在 Windows 的 Linux 容器中也可以使用 WSL2。

这对我有用 ubuntu 18.04

检查您的 gpg 密钥

gpg -K --keyid-format LONG

如果收到空白响应,生成一个 GPG 密钥

gpg --generate-key

重新运行第一个命令,您应该得到如下输出:

sec   rsa3072/95A854E0593B3214 2019-05-06 [SC] [expires: 2021-05-05]
      AF2F7514568DC26B0EB97B9595A854E0593B74D8
uid                 [ultimate] yourname<your_email>
ssb   rsa3072/EFD326E6C611117C 2019-05-06 [E] [expires: 2021-05-05]

设置git签名密钥

git config --global user.signingkey 95A854E0593B3214

那你就可以开始了! (--global 是可选的)

或者,如果您不介意使用 ssh 密钥签名

git config commit.gpgsign false

请注意,根据这个问题 and

,由于安全问题,不推荐这样做

我必须将 gpg.program 修复为 gpg 的绝对路径:

git config --global gpg.program "C:\Program Files (x86)\GnuPG\bin\gpg.exe"

我正在使用 Windows 和 cygwin。

为我解决的问题是确保密钥的名称与我的 git 用户名匹配。我假设电子邮件也必须匹配。这可能与我在 Mac 上使用 GPG KeyChain 有关。不确定。

我以为我填写这个的时候是在命名密钥,但我猜它是在问我的名字(git 用户名)。

当您的 git 配置中的密钥过期时,也会导致同样的错误。

请检查 cat .git/config 的内容并查找 signingkey 值并检查它是否已过期。如果是,用新的更新它。

如果您使用 smart card/yubikey 存储您的 GPG 密钥,并且您通过存储的密钥设置 git 配置的 signkey在卡片中(上面的所有答案似乎都无法解决您的问题),您被阻止的卡片 PIN 可能是此问题的根本原因。

检查被阻止的 PIN:

gpg --card-status

如果计数器类似于

Reader ...........: Yubico YubiKey
PIN retry counter : 3 0 3

然后您的 PIN 被阻止(在 3 次尝试失败后)。

解锁 PIN:

gpg --card-edit
gpg/card> admin
Admin commands are allowed

gpg/card> passwd
gpg: OpenPGP card no. … detected

1 - change PIN
2 - unblock PIN
3 - change Admin PIN
4 - set the Reset Code
Q - quit

Your selection? 2
PIN unblocked and new PIN set.

1 - change PIN
2 - unblock PIN
3 - change Admin PIN
4 - set the Reset Code
Q - quit

Your selection? q

我在 macos 上遇到了这个错误 - 尝试进行故障排除并且使用 git config --global user.signingkey.

在我的配置中设置了正确的密钥

在我执行了 运行 those 命令之后,我突然能够毫无问题地再次进行签名提交。我没有更改我的配置文件或密钥——我什至没有创建一个新的终端实例。似乎 gpg2 在我的 mac.

上处于某种奇怪的状态

解决方案:

Issue: Disabled loopback pinentry mode

To solve the problem, you need to enable loopback pinentry mode in ~/.gnupg/gpg.conf:

cat <<'EOF' >> ~/.gnupg/gpg.conf

use-agent 
pinentry-mode loopback

EOF

And also in ~/.gnupg/gpg-agent.conf (create the file if it doesn't already exist):

cat <<'EOF' >> ~/.gnupg/gpg-agent.conf

allow-loopback-pinentry

EOF

Then restart the agent with echo RELOADAGENT | gpg-connect-agent and you should be good to go!

Source

对我来说,一个简单的 brew unintstall gnupg && brew cask reinstall gpg-suite 就解决了这个问题。

它卸载(在我的例子中)手动安装的 gpg 并重新安装整个 GPG 套件。

就我而言,我在此处的提交签名文档中混合了 gpg 配置和 smimesign 配置:https://help.github.com/en/github/authenticating-to-github/telling-git-about-your-signing-key

经过几个小时的努力,我发现纠正它的最佳方法是取消设置与 gpg 相关的所有内容,然后重新配置 gpg。

如@Jason Thrasher 的回答中所述,使用以下方法找到与 gpg 相关的所有 git 配置:

git config -l | grep gpg

然后在本地和本地取消所有设置:

git config --global --unset <config_name>
git config --local --unset <config_name>

然后按照上面给出的官方文档重新配置。 希望这有帮助。

如果您之前设置了 pinentry 和 gpg,但突然停止工作:

检查您的 gpg 是否有效:

echo "test" | gpg --clearsign

如果显示gpg: signing failed: No pinentry, 只需重新启动 gpg 守护程序客户端,它会不时卡住:

gpgconf --kill gpg-agent

现在它应该可以工作了:

echo "test" | gpg --clearsign

在我的例子中,这个错误发生在 运行 git commit 上一个小的 tmux window 上,它无法满足密码提示。

$ echo "test" | gpg --clearsign
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

test
gpg: signing failed: Screen or window too small
gpg: [stdin]: clear-sign failed: Screen or window too small

在我的例子中,我必须将 GitHub 设置中存储的名称与密钥的名称和注释相匹配。

所以如果 gpg --list-keys returns uid [ultimate] Joe Blogs (fancy comment) <email@example.com> 你在 .gitconfig 中的名字应该是 Joe Blogs (fancy comment).

最初,我将我的名字设置为 Joe Blogs,GPG 找不到我的密钥并在 strace 中显示“无密钥”错误。不幸的是,没有 strace 就不会出现该错误,并且会得到通用的

error: gpg failed to sign the data
fatal: failed to write commit object

刚刚 VSCode 更新时我遇到了这个问题。我认为 GPG 代理已挂起,因为该命令花了好几秒钟 运行 才出错。 运行 gpgconf --kill gpg-agent 重置并为我修复它。

对于我的带有 GUI 和 gpg 2.2.19 的 Linux 系统,杀死 gpg-agent(它会再次启动)、取消设置 $DISPLAY 或设置 $GPG_TTY 对我都没有用因为它试图使用 pinentry-gnome 从控制台请求密码。而且我的密钥还没有过期。

根据 SuperUser 对类似问题的回答,How to force GPG to use console-mode pinentry to prompt for passwords?,如果您的系统具有 GNOME 等 GUI,并且您的包管理器配置为使用 GUI pinentry 程序,也可能会出现该问题,即它挂起的原因。

我不得不切换到 pinentry-tty 让 GPG 再次签署消息。在 Ubuntu 上,这可以使用 link 中的步骤完成,我将在此处引用:

sudo apt install pinentry-tty
sudo update-alternatives --config pinentry

第二个命令将向您显示一个 pinentry 程序列表,并要求您键入一个数字到 select 一个,因此键入与 pinentry-tty 对应的那个,然后无需任何额外的努力,签署消息(和 git 提交)应该再次工作。

我在两个 linux/windows 平台上都遇到了这个问题,就我而言,我只需要更加仔细地注意输出。这令人难以置信,因为我可以使用相同的设置在其他回购协议中签署提交。

git commit -m "test signing"
gpg: skipped "***63231079***": No secret key
gpg: signing failed: No secret key
error: gpg failed to sign the data
fatal: failed to write commit object

我强调了“跳过”的那一行。请注意,有时当您克隆一个回购协议时,他们会分配一个密钥:这个问题让我感到困惑,以至于我核对了我有权访问的分叉回购协议并在 github 上重新分叉。然后因为我在考虑“全局配置”,所以我从没想过要查看本地回购配置,当我这样做时,我注意到了这一点:

[user]
    signingkey = 63231079

好吧,nimrod 当然不行,git 默认首先使用本地设置,所以这就是为什么您的密钥从未被提取的原因。我通过 git config 设置指针,从那以后它一直有效。

如果它曾经工作并且只是说失败,请终止代理并重试:

gpgconf --kill gpg-agent

检查代理是否再次启动:

echo "test" | gpg --clearsign

什么是 gpg:GNU 隐私卫士

用法:

GPG is an excellent method to ensure secure communication between two parties. It allows sensitive information to be easily shared across an insecure network.

简单的解决方案:

第一步:检查密钥是否过期

gpg -K --keyid-format SHORT

第二步:如果没有过期

git config --global user.signingkey

使用GIT_TRACE=1查看Git失败的地方,然后检查Git使用的所有自定义配置以及它们的定义位置根据您的需要覆盖:

GIT_TRACE=1 git commit -S -m "this will tell you wich intern git command failed"

git config --list --show-scope --show-origin

我有 error: gpg failed to sign the datafatal: failed to write commit object 因为 Git 使用 smimesign 由于某种原因默认情况下,即使我取消设置 gpg.x509.program 键,并且 smimesign couldn't find my key.

所以我不得不明确地告诉 Git 使用 gpg :

git config --local gpg.x509.program gpg

经过大量搜索,我发现 gpg 密钥是我的问题所在。

如果您的 GPG 密钥正确,您可以尝试 运行 gpg --status-fd=2 -bsau <your GPG key>

要更新正确的密钥,请执行以下操作: 检查密钥使用:gpg --list-secret-keys --keyid-format=long

它应该有以下输出:

/Users/hubot/.gnupg/secring.gpg
------------------------------------
sec   4096R/3AA5C34371567BD2 2016-03-10 [expires: 2017-03-10]
uid                          Hubot 
ssb   4096R/42B317FD4BA89E7A 2016-03-10

然后使用以下方式更新密钥:

git config --global user.signingkey 3AA5C34371567BD2

现在再次检查提交,如果密钥是问题的话应该会成功。您需要设置密码来更新密钥,您可以使用 GitHub docs.

更多详情位于:https://gist.github.com/paolocarrasco/18ca8fe6e63490ae1be23e84a7039374

Fail-safe 对我有用的选项:重新启动我的机器。

它太粗暴了,它最终可能无法阻止问题再次出现。但是我遇到了同样的问题,尝试了几乎所有答案的解决方案,没有运气。

在此处添加它是希望它能解除对我情况的其他人的封锁:)