git(GitHub)でGPGを使った署名をおこなう


GPGとは

GNU Privacy Guard (GnuPG, GPG)とは、GPLに基づいた暗号化ソフトのことです。GPGで作成した鍵を使用し、暗号化・復号化をおこなうことができます。
gitやGitHubではGPGを使用した署名に対応しており、コミットやマージ、タグを作成する際に署名することができます。署名することによって、その内容が信頼できるものか判断することができます。
GitHubでは署名付きコミットにバッジが表示されるようです。

GPGのインストール

現在GPGには3つの系列が存在します。stableである2.0系を使うのが良さそうです。

Wikipedia
"stable" (2.0): 現行安定版。一般の使用に適している。初版リリースは2006年11月13日[8]。
"modern" (2.1): 最新の開発系列であり、楕円曲線暗号など新機能を実装している。十分な安定性が確認されたら 2.0 系列に代わり安定版となる。初版リリースは2014年11月6日[7]。
"classic" (1.4): 旧来のスタンドアロン版。古いシステムや組み込み用途に適している。初版リリースは2004年12月16日[9]。

MacOSXの場合、HomeBrewを利用してインストールができます。

% brew install gpg2 gpg-agent pinentry-mac
% gpg --version
gpg (GnuPG) 2.0.30
libgcrypt 1.7.3
Copyright (C) 2015 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://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: ~/.gnupg
Supported algorithms:
Pubkey: RSA, RSA, RSA, ELG, DSA
Cipher: IDEA, 3DES, CAST5, BLOWFISH, AES, AES192, AES256, TWOFISH,
        CAMELLIA128, CAMELLIA192, CAMELLIA256
Hash: MD5, SHA1, RIPEMD160, SHA256, SHA384, SHA512, SHA224
Compression: Uncompressed, ZIP, ZLIB, BZIP2

gpg-agentの設定をおこなう

続いてgpg-agentの設定ファイルを作成します。コマンドラインからGPGのパスフレーズを入力する際、gpg-agentpinentry-macが入っていないとエラーとなってしまいます。

pinentry-macを呼び出せるように~/.gpg/直下に下記のような設定ファイルを配置します。

~/.gnupg/gpg-agent.conf
use-standard-socket
pinentry-program /usr/local/bin/pinentry-mac

GPGで暗号化鍵を作成

公開鍵暗号方式で使うため、秘密鍵と公開鍵のペアを作成します。
今回はRSAの4096bit、2年の有効期限付きで作成します。

$ gpg --gen-key
gpg (GnuPG) 2.0.30; Copyright (C) 2015 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.

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?1
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (2048)4096
Requested keysize is 4096 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) 2y
Key expires at Fri Nov 30 09:07:29 2018 JST
Is this correct? (y/N)y

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

Real name:pontago
Email address: [email protected]
Comment:
You selected this USER-ID:
    "pontago <[email protected]>"

Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O
You need a Passphrase to protect your secret key.

"ここでパスフレーズを聞かれるので入力"

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: /Users/pontago/.gnupg/trustdb.gpg: trustdb created
gpg: key 88E9CD67 marked as ultimately trusted
public and secret key created and signed.

gpg: checking the trustdb
gpg: 3 marginal(s) needed, 1 complete(s) needed, PGP trust model
gpg: depth: 0  valid:   1  signed:   0  trust: 0-, 0q, 0n, 0m, 0f, 1u
gpg: next trustdb check due at 2018-11-30
pub   4096R/88E9CD67 2016-11-30 [expires: 2018-11-30]
      Key fingerprint = 4755 ABE2 9B90 5861 544B  3829 B702 10C3 88E9 CD67
uid       [ultimate] pontago <[email protected]>
sub   4096R/0518C709 2016-11-30 [expires: 2018-11-30]

無事に作成できたか確認してみます。

% gpg --list-keys
/Users/pontago/.gnupg/pubring.gpg
---------------------------------
pub   4096R/88E9CD67 2016-11-30 [expires: 2018-11-30]
uid       [ultimate] pontago <[email protected]>
sub   4096R/0518C709 2016-11-30 [expires: 2018-11-30]

GitHubにGPG公開鍵を登録

試しに作成したGPG鍵をGitHubに登録してみます。下記リンクのページから登録できます。
https://github.com/settings/keys

"New GPG key"ボタンを押して表示される入力ボックスに下記の方法で出力した公開鍵を入力します。

"--armor"オプションはアスキーコードで出力するオプションで、これを指定しないとバイナリで出力されてしまいます。
"--export"オプションに出力対象のキーIDを指定します。

% gpg --armor --export 88E9CD67
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v2

"公開鍵の文字列"
-----END PGP PUBLIC KEY BLOCK-----

gpg --armor --export 88E9CD67 | pbcopy のようすることで、クリップボードにコピーできます。

署名付きコミットをおこなう

さっそく作成したPGP鍵を使用してコミットに署名してみることにします。
GitHubにテストのリポジトリを作成してcloneします。
https://github.com/pontago/pgp-test.git

% git clone https://github.com/pontago/pgp-test.git
Cloning into 'pgp-test'...
remote: Counting objects: 3, done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), done.
Checking connectivity... done.
% cd pgp-test && ls
README.md

使用するGPG鍵を指定します。"--global"オプションを追加すると全体のGitから参照できるようになります。

% git config user.signingkey 88E9CD67
% git config --get user.signingkey
88E9CD67

README.mdに追記してコミットします。通常のコミットに"-S"オプションを追加すると署名付きコミットとなります。

% echo "\n# Signature commit" >> README.md
% git commit -S -am "Signature commit."
% git push

無事に署名付きコミットが成功すると下記のようになります。

署名コミット時にエラーが出た

gpg-agentpinentry-macが入っていない場合にパスフレーズを入力することができず、エラーとなるようです。

% git commit -S -am "Signature commit."
You need a passphrase to unlock the secret key for
user: "pontago <[email protected]>"
4096-bit RSA key, ID 88E9CD67, created 2016-11-30

gpg-agent[57226]: command get_passphrase failed: Inappropriate ioctl for device
gpg: problem with the agent: Inappropriate ioctl for device
gpg: skipped "88E9CD67": Operation cancelled
gpg: signing failed: Operation cancelled
error: gpg failed to sign the data
fatal: failed to write commit object

GitHubでUnverifiedとなった

GPG鍵作成時に入力したメールアドレスと一致しないためのようです。下記の方法で適切なメールアドレスを設定します。(必要であれば"--global"オプションを追加)

% git config user.email [email protected]

参考

Git - 作業内容への署名
GPG鍵を作って運用し、Git(hub)やMercurialで自分が書いたコードに署名をする
macOS Sierra で GitHub にGPG署名付きでコミットできるようにする