Git のコミットに署名がほしい

macOS Catalina で [Git のコミットに署名](https://git-scm.com/book/ja/v2/Git-%E3%81%AE%E3%81%95%E3%81%BE%E3%81%96%E3%81%BE%E3%81%AA%E3%83%84%E3%83%BC%E3%83%AB-%E4%BD%9C%E6%A5%AD%E5%86%85%E5%AE%B9%E3%81%B8%E3%81%AE%E7%BD%B2%E5%90%8D)を付けたお話。署名には OpenPGP の実装である [GnuPG](https://wiki.archlinux.jp/index.php/GnuPG) を使う。

# 想像図
![2020-06-06 00.36.17 github.com 747e16c355c1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/10931/3d3d1478-ea77-0eae-c300-258875119309.png)

# 用意するもの
## homebrew package
- gnupg
- pinentry
- pinentry-mac

## homebrew cask
- gpg-suite

# 鍵を作る
一般的な秘密鍵の暗号化方式は [ed25519](https://ja.wikipedia.org/wiki/%E3%82%A8%E3%83%89%E3%83%AF%E3%83%BC%E3%82%BA%E6%9B%B2%E7%B7%9A%E3%83%87%E3%82%B8%E3%82%BF%E3%83%AB%E7%BD%B2%E5%90%8D%E3%82%A2%E3%83%AB%E3%82%B4%E3%83%AA%E3%82%BA%E3%83%A0) だが、`--expert` オプションがなければ使えない。

```sh
% gpg --full-gen-key --expert
```

細かい説明は [gpg のはなし](https://gist.github.com/hatsusato/1d5f0267bc9d02bb24c60bd7acc5a59a)を読んでほしいが、目的に合わせて subkey を作ることができる。今回は署名と認証用にふたつ用意する。

## Git に署名する
`commit.gpgsign` オプションがあるので有効にしておく。`user.signingkey` オプションで署名に使う Key ID を指定する。鍵の ID は `--list-keys` (または `--list-secret-keys`) オプションで出力できる[^1]。

```sh
% cat ~/.gitconfig
───────┬────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
       │ File: /Users/unlovingly/.gitconfig
───────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
   1   │ [commit]
   2   │   gpgsign = true
   3   │ [user]
   4   │   signingkey = B933F6FE0FC19F4F
───────┴────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
```

```sh
% gpg --list-keys --keyid-format long email@example.com
pub   ed25519/5E4449CA75763271 2020-06-05 [C]
      9FACEB719D03D05FF61045485E4449CA75763271
uid                 [ultimate] unlovingly <email@example.com>
sub   ed25519/B933F6FE0FC19F4F 2020-06-05 [S] [expires: 2021-06-05]
sub   ed25519/48AA4D1E17FF6BA9 2020-06-05 [A] [expires: 2021-06-05]
```

コミットするとき pinentry が秘密鍵のパス フレーズを訊ねてくる。Keychain Access.app に覚えさせることもできる (画像は pinentry-curses)。

![pinentry.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/10931/c83e7e62-7ad4-babf-c080-ddbb4bc33b13.png)

あとは GitHub に鍵を登録すれば、冒頭の Verified バッジを得られる。

### GitHub に鍵を登録する
[GitHub アカウントへの新しい GPG キーの追加 - GitHub ヘルプ](https://help.github.com/ja/github/authenticating-to-github/adding-a-new-gpg-key-to-your-github-account)

## SSH 接続で使う
`Authenticate` 用に subkey  `48AA4D1E17FF6BA9` を用意した。

ところで GnuPG で公開鍵認証やるなら ssh-agent(1) ではなく gpg-agent(1) を使う。

> [gpg-agent には OpenSSH エージェントのエミュレーション機能が存在します。](https://wiki.archlinux.jp/index.php/GnuPG#SSH_.E3.82.A8.E3.83.BC.E3.82.B8.E3.82.A7.E3.83.B3.E3.83.88)

```sh
% cat ~/.gnupg/gpg-agent.conf
───────┬────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
       │ File: /Users/unlovingly/.gnupg/gpg-agent.conf
───────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
   1   │ default-cache-ttl 86400
   2   │ max-cache-ttl 86400
   3   │ pinentry-program /usr/local/bin/pinentry-mac
───────┴────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

```

gpg-agent には認証する鍵のキーグリップを教える。

```sh
% gpg --list-secret-keys --with-keygrip email@example.com
sec   ed25519 2020-06-05 [C]
      9FACEB719D03D05FF61045485E4449CA75763271
      Keygrip = 84500D69B6BAAF559687F31981319E74BF5B0386
uid           [ultimate] unlovingly <email@example.com>
ssb   ed25519 2020-06-05 [S] [expires: 2021-06-05]
      Keygrip = 6ADFDE069EC89D029B34AA3B2409EAC3B5854709
ssb   ed25519 2020-06-05 [A] [expires: 2021-06-05]
      Keygrip = F304C7E7D0A5715E550FDAAE2237B0A44CADF5CC
```

```sh
% echo F304C7E7D0A5715E550FDAAE2237B0A44CADF5CC >> ~/.gnupg/sshcontrol
```

また、公開鍵を生成してリモート ホストに設定しておくこと。生成には `--export-ssh-key` オプションを使う。引数は key ID を取る。suffix `!` があると Authentication capability を確認しなくなる。

```sh
% gpg --export-ssh-key 48AA4D1E17FF6BA9
```

gpg-agent を起動しておく。

```sh
% gpgconf --launch gpg-agent
```

```sh
% cat ~/.ssh/config
───────┬────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
       │ File: /Users/unlovingly/.ssh/config
───────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
   1   │ Host *
   2   │     ForwardAgent yes
───────┴────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
% ssh example.com
```

# 参考
- [gpg のはなし](https://gist.github.com/hatsusato/1d5f0267bc9d02bb24c60bd7acc5a59a)
- [そろそろ GnuPG でも ECC を標準で使うのがいいんじゃないかな — OpenPGP の実装 | text.Baldanders.info](https://text.baldanders.info/openpgp/using-ecc-with-gnupg/)
- [GnuPG - ArchWiki](https://wiki.archlinux.jp/index.php/GnuPG)
- [GitHub アカウントへの新しい GPG キーの追加 - GitHub ヘルプ](https://help.github.com/ja/github/authenticating-to-github/adding-a-new-gpg-key-to-your-github-account)
- [gnupg - Are GPG and SSH keys interchangable? - Super User](https://superuser.com/a/1286352)
- [Git署名のウソホント - あまねけ！](https://ama.ne.jp/post/git-signing/)

[^1]: この記事を書くとき鍵を作ったので冒頭の画像とは ID が違う