最近我在逛别人的 GitHub 仓库的时候,发现有些提交右侧有一个独特的绿色标识写着 verified,查了下资料才知道,这是使用 GPG 签名验证过的提交,因此会显示已验证的标志。这篇文章就分享如何使用 GPG 给 Git commit 签名。
GPG 的功能
GPG,全称 GNU Privacy Guard,顾名思义就是用来保护隐私数据的。其原理是非对称加密,分有公钥和私钥,公钥加密私钥才能解密,私钥加密公钥才能解密。通过这个原理,GPG 实现了四个功能:
- [C] Certificating: 认证其他密钥、签名其他证书。
- [S] Signing: 签名。
- [A] Authenticating: 身份验证、鉴权。
- [E] Encrypting: 加密。
我们给 Git commit 签名就用到了第二个功能,它可以验证这个 commit 是不是你本人提交的,是否被别人冒名顶替,如此保证了开源软件的安全性。
使用 GPG 给提交签名
检查 GPG 安装
如果你在阅读这篇文章,肯定是安装了而且会使用 Git 的。GPG 在 GitBash 中自带,因此我们理论上不需要额外安装。打开 GitBash,使用 gpg --version
命令即可查看当前 GPG 版本信息如下:
$ gpg --version gpg (GnuPG) 2.2.29-unknown libgcrypt 1.9.3-unknown Copyright (C) 2021 Free Software Foundation, Inc. License GNU GPL-3.0-or-later <https://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Home: /c/Users/<UserName>/.gnupg Supported algorithms: Pubkey: RSA, ELG, DSA, ECDH, ECDSA, EDDSA Cipher: IDEA, 3DES, CAST5, BLOWFISH, AES, AES192, AES256, TWOFISH, CAMELLIA128, CAMELLIA192, CAMELLIA256 Hash: SHA1, RIPEMD160, SHA256, SHA384, SHA512, SHA224 Compression: Uncompressed, ZIP, ZLIB, BZIP2
生成 GPG 密钥
第一次使用 GPG,我们先要给自己生成一个 GPG 密钥。使用 gpg --full-generate-key
指令生成自定义密钥。
生成密钥有一些选项,首先是密钥类型和密钥长度,默认即可。然后是密钥有效期,没有特殊需求的话选择不失效会比较方便。
然后进入密钥信息的填写,首先是姓名,接下来邮箱比较重要,需要和你的代码托管平台例如 GitHub 的邮箱保持一致,否则将无法导入你的公钥。备注不是很重要,可以空着。
然后弹出 Pinentry 窗口,设置你的密钥的密码。以后使用密钥需要输入该密码。
gpg: revocation certificate stored as '/c/Users/<UserName>/.gnupg/openpgp-revocs.d/<ID>.rev' public and secret key created and signed. pub rsa3072 2022-05-28 [SC] <ID> uid <Name> <E-mail> sub rsa3072 2022-05-28 [E]
这样就成功生成了你的密钥。今后也可使用 gpg --list-keys
列出当前设备上的公钥。
使用 GPG 给提交签名
首先设置 Git 使用的密钥:(<ID> 就是生成密钥后显示的那一行字符)
git config --global user.signingkey <ID>
此时就已经可以使用 GPG 签名提交了,只需在每次提交时加上 -S 参数,如:
git commit -S -m "Commit Message"
如果默认每次提交都要使用 GPG 签名,可以设置:
git config --global commit.gpgsign true
设置后加不加 -S 都会使用 GPG 签名提交。
之后提交时,均会弹出 Pinentry 窗口,需要输入对应密钥的密码才可以提交代码。
GitHub 导入 GPG 公钥
我们需要将自己的公钥导入 GitHub,这样 GitHub 才能验证我们的提交是否是本人。
首先导出我们的公钥,使用 gpg --armor --export <ID>
导出 ASCII 编码后的公钥(要不然就是二进制数据了),将公钥内容完整复制下来。
在 Settings 中找到 SSH and GPG keys 页面,点击 New GPG Keys,粘贴公钥保存即可。
这样操作之后,我们的提交在 GitHub 上均会标有 verified 标识。
一些其他操作
导入并信任 GitHub 的公钥
由于有时候我们会直接在 GitHub 上提交,此时这个提交是使用 GitHub 的密钥签名的,在我们本地就会显示无法验证的签名,并且被标红了。使用 git log --show-signature
就可以发现这个现象如下:
commit b30d6a82b62e49665aa7d6964f528381c1ba72c4 gpg: Signature made 2022年05月16日 23:52:13 gpg: using RSA key 4AEE18F83AFDEB23 gpg: Can't check signature: No public key Author: Haotian Zou <49368462+ChrisKimZHT@users.noreply.github.com> Date: Mon May 16 23:52:13 2022 +0800
这样很碍眼,因此我们得导入并信任 GitHub 的公钥,这样我们本地的 Git 就能验证该提交。
首先是导入:curl https://github.com/web-flow.gpg | gpg --import
然后是信任:gpg --sign-key 4AEE18F83AFDEB23
输入自己密钥的密码,使用自己的密钥为它签名验证。这样提交变成蓝色的已验证的了:
commit b30d6a82b62e49665aa7d6964f528381c1ba72c4 gpg: Signature made 2022年05月16日 23:52:13 gpg: using RSA key 4AEE18F83AFDEB23 gpg: Good signature from "GitHub (web-flow commit signing) <noreply@github.com>" [full] Author: Haotian Zou <49368462+ChrisKimZHT@users.noreply.github.com> Date: Mon May 16 23:52:13 2022 +0800
导出自己的私钥
如果我们想在不同设备共有一个密钥,就需要导出自己的私钥,例如我想在本机的 wsl2 中使用相同的密钥。通常,这种操作不太安全,不建议进行导出。
gpg --output <Name>.pgp --armor --export-secret-key <ID>
导出时需要输入密码。导出后获得一个密钥文件,将其移动到对应设备,切记保管好私钥文件,重新导入后删除销毁。
导入并信任私钥
在对应设备运行指令:gpg --import <KeyFile>
即可导入公/私钥,私钥导入需要输入密码。
如果仅导入私钥,那么该密钥会在列表中显示为 [ unknown ],它本该为 [ ultimate ],我们需要信任该密钥。
运行指令:gpg --edit-key
,然后再输入 <E-mail>
trust
,选择“绝对信任”选项,再输入 save
保存即可。整个过程如下:
gpg --edit-key user@useremail.com gpg> trust Please decide how far you trust this user to correctly verify other users' keys (by looking at passports, checking fingerprints from different sources, etc.) 1 = I don't know or won't say 2 = I do NOT trust 3 = I trust marginally 4 = I trust fully 5 = I trust ultimately m = back to the main menu Your decision? 5
在 WSL2 中使用 GPG
如果我们按以上步骤配置好了 WSL2 的 GPG 密钥和 Git,想要提交时结果发现:
error: gpg failed to sign the data fatal: failed to write commit object
原因是 WSL2 没法弹出 Pinentry 窗口,也就是我们没法输入密钥的密码,因此将无法提交。解决方法是让 WSL2 使用 Windows 主机上的 pinentry-basic.exe 来接受密码。
似乎 Git 自带的 GPG 没法实现这个操作,因此我们需要额外安装一个 GPG4Win,安装后 pinentry-basic.exe 的目录不出意外应该为:”C:\Program Files (x86)\GnuPG\bin\pinentry-basic.exe”
然后我们编写(不存在则创建)WSL2 中的文件 ~/.gnupg/gpg-agent.conf
,在里面添加
pinentry-program "/mnt/c/Program Files (x86)/GnuPG/bin/pinentry-basic.exe"
这样在 WSL2 中提交,就会在 Windows 主机上弹出窗口接受密钥的密码。至此就可以在 WSL2 中顺利提交了。
发表回复