如何產生有GPG簽章過的Git Commit?

前言

不管是在GitHub或是GitLab網站上,都會看到每個commit資訊,這些commit資訊會顯示「unverified」的時候,像是下列的圖示:

為什麼Commit會顯示「Unverified」呢?原因是該Commit並沒有建立GPG sign簽章而導致該Commit顯示未經過認證,有認證過的Commit有什麼好處?可以讓人有個保證,有簽章過的Commit較為安全,未簽章過的會讓人覺得有偽造的嫌疑。在本文章中,會以GitHub為例,演示該如何針對一個使用者進行設定GPG commit,以及產生GPG金鑰的方法與相關的步驟。

前置條件

首先,要有GPG的指令可以使用,在Windows底下可以安裝Git for Windows進行使;用Linux相關的作業系統則已經有gpg的指令可以使用了。下列是有關於Windows上安裝Git for Windows與Linux作業系統上檢查gpg指令的方法:


# 在Windows上(Git for Windows)

peter@ideapad-peterli MINGW64 ~/Downloads
$ gpg --version
gpg (GnuPG) 2.2.41-unknown
libgcrypt 1.9.4-unknown
Copyright (C) 2022 g10 Code GmbH
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/peter/.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

# 在Linux作業系統上,以Ubuntu發行版本為例

peter@ideapad-peterli:~$ gpg --version
gpg (GnuPG) 2.2.4
libgcrypt 1.8.1
Copyright (C) 2017 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 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: /home/peter/.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 --full-generate-key

gpg (GnuPG) 2.2.4; Copyright (C) 2017 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

gpg: keybox '/home/peter/.gnupg/pubring.kbx' created
Please select what kind of key you want:
(1) RSA and RSA (default)
(2) DSA and Elgamal
(3) DSA (sign only)
(4) RSA (sign only)
Your selection?
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (3072)
Requested keysize is 3072 bits
Please specify how long the key should be valid.
0 = key does not expire
<n> = key expires in n days
<n>w = key expires in n weeks
<n>m = key expires in n months
<n>y = key expires in n years
Key is valid for? (0)
Key does not expire at all
Is this correct? (y/N) y

GnuPG needs to construct a user ID to identify your key.

Real name: peter279k
Email address: peter279k@gmail.com
Comment:
You selected this USER-ID:
"peter279k <peter279k@gmail.com>"

Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
gpg: /home/peter/.gnupg/trustdb.gpg: trustdb created
gpg: key 180E78DA37B1ABDE marked as ultimately trusted
gpg: directory '/home/peter/.gnupg/openpgp-revocs.d' created
gpg: revocation certificate stored as '/home/peter/.gnupg/openpgp-revocs.d/4569E017DF5889475A5959A6180E78DA37B1ABDE.rev'
public and secret key created and signed.

pub rsa3072 2023-11-12 [SC]
4569E017DF5889475A5959A6180E78DA37B1ABDE
uid peter279k <peter279k@gmail.com>
sub rsa3072 2023-11-12 [E]

從上述的執行指令訊息,有幾個重點如下:

  • 選用什麼演算法來產生公私鑰,這邊可以使用預設RSA演算法來進行產生。
  • 產生RSA金鑰長度要多少bits?預設是3072,也可以使用預設值是可以的。
  • 「Key is valid for? (0)」產生的金鑰不會過期。
  • 接下來會問你是否正確,就輸入「y」來進行下一步。
  • 接下來分別輸入「Real name」、「Email address」以及「Comment」,Comment可以是空白。
  • 接下來會問是否設定正確?確定正確訊息之後,則可以輸入「O」來進行下一步。
  • 接著會跳出下列的訊息對話框,提示需要輸入金鑰的passphrase來進行保護,相關圖片如下:

  • 上述的步驟會重複兩次,這邊會建議不設定passphrase是因為,假設儲存在電腦上是安全的,且有可能有忘記passphrase的風險,因此這邊以空白為主,並按下「enter」鍵。

產生完成之後,會顯示相關的訊息出來,以及說明公私鑰儲存在哪裡以及公鑰之內容。

接下來,為了要讓Git指令在使用git commit指令時可以去使用GPG金鑰進行簽章,則需要使用下列的指令來進行設定:


git config --global commit.gpgSign true
git config --global user.signingKey signed_key

從上述執行的指令可以知道,第一行代表的是設定GPG簽章為true,第二行是設定簽章的金鑰是哪一個。

「signed_key」要替換成自己產生的key,輸出自己的Key方式如下:


$ gpg --list-secret-keys --keyid-format=long
gpg: checking the trustdb
gpg: marginals needed: 3 completes needed: 1 trust model: pgp
gpg: depth: 0 valid: 1 signed: 0 trust: 0-, 0q, 0n, 0m, 0f, 1u
/home/peter/.gnupg/pubring.kbx
------------------------------
sec rsa3072/180E78DA37B1ABDE 2023-11-12 [SC]
4569E017DF5889475A5959A6180E78DA37B1ABDE
uid [ultimate] peter279k <peter279k@gmail.com>
ssb rsa3072/9619458E50C86AD1 2023-11-12 [E]

從上述的輸出訊息可以知道,「4569E017DF5889475A5959A6180E78DA37B1ABDE」就是私鑰。

於是執行「git config –global user.signingKey 4569E017DF5889475A5959A6180E78DA37B1ABDE」指令進行設定。

接著要讓GitHub知道這是簽章過的Commit,因此需要將上面產生的GPG公鑰上傳到我們GitHub帳號中,可以透過下列的指令來輸出公鑰的資訊:


gpg --output public.pgp --armor --export peter279k@gmail.com

從上述的指令可以知道,指定上面產生GPG的那個信箱,並把輸出的公鑰資訊儲存到「public.pgp」檔案中,「–armor」參數是產生ASCII格式的公鑰輸出訊息。

我們用cat指令就可以把上述的檔案進行輸出:


$ cat public.pgp
-----BEGIN PGP PUBLIC KEY BLOCK-----

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
lQwJ6FPQa+D5VSc=
=VkgQ
-----END PGP PUBLIC KEY BLOCK-----

輸出的這一段就可以貼到GitHub帳號設定裡面,記得進到帳戶設定選擇「SSH and GPG Keys」並按下「New GPG Keys」,接著就可以設定該公鑰名稱以及公鑰內容了,相關的截圖如下:

在新增之後,會需要對帳號進行二次確認, 對帳號輸入密碼之後,該GPG金鑰就會設定進去了。

設定好之後,在設定GPG金鑰的那台機器上就可以產生出Verified的有經過GPG簽章過的Commit了。

故障排除

若是在git commit的指令時候,出現下列的訊息:


gpg: skipped "peter279k <peter279k@gmail.com>": No secret key
gpg: signing failed: No secret key
error: gpg failed to sign the data
fatal: failed to write commit object

則是代表說「git config –global user.signingKey」指令沒有設定成功,則需要進行正確的設定。

並確定該GPG公鑰有上傳到指定的GitHub帳號中。

 

若是執行指令的環境無法有互動模式的話,則可以使用無互動的方式去執行gpg的指令,相關的指令執行方式如下:

<pre>#!/bin//bash

gpg --full-generate-key --batch <(echo "Key-Type: 1"; \
                             echo "Key-Length: 4096"; \
                             echo "Subkey-Type: 1"; \
                             echo "Subkey-Length: 4096"; \
                             echo "Expire-Date: 0"; \
                             echo "Name-Real: peter279k"; \
                             echo "Name-Email: peter279k@gmail.com"; \
                             echo "%no-protection"; )</pre>

備註

上述的GPG公鑰與私鑰將不會真的拿來設定與使用,在這篇文章完成之後,該GPG金鑰就會從產生的機器上刪除,並透過下列的指令進行刪除:


$ gpg --delete-secret-keys peter279k@gmail.com

$ gpg --delete-keys peter279k@gmail.com

從上述指令得知,就是分別刪除指定信箱的GPG私鑰與公鑰,有順序之分,需要先刪除GPG私鑰再刪除公鑰。

參考資料

Posted in Git