Windowsでも楕円曲線DSAでgitのタグに署名したい

(2017-11-26) @spiegel-im-spiegel さんのコメントを受けて内容修正。
(2018-04-17) KleopatraのバージョンアップでEd25519鍵が作成可能になったので追記。
(2020-05-02) 各コミットに署名を付与する方法を追記

gitのタグに署名がしたかった
=========================

Windowsな環境でgitをTortoiseGitから使っていたので, TortoiseGitから署名付きのタグが打てたら便利だなぁ, と思っていましたが, 実際にやってみるとなかなか上手くいきませんでした。
そんな折, 2017/09/19にリリースされた[Gpg4win][] v3.0.0が楕円曲線暗号に対応したGnuPG2.2系列を搭載するようになったので, 署名が出来るようになるまできちんとやってみました。

![TortoiseGit](https://qiita-image-store.s3.amazonaws.com/0/152916/f87828e5-b135-e33f-fefb-bb1a1798b53f.png)


署名が出来るようになるまで
========================

ここでは[Git for Windows][]及び[TortoiseGit][]はインストール済みであるとします。

[Gpg4win][]のインストール
------------------------

gitのコミットやタグに対して署名を行うためには[OpenPGP][]形式の公開鍵/秘密鍵ペアが必要になります。
また実際の署名は, OpenPGP形式の鍵を扱うソフトウェアの中でも恐らく最も広く使われているオープンソース実装の[Gnu Privacy Guard (**GnuPG**)][GnuPG]を利用することで行われています。

Windowsの場合は**[Gpg4win][]**がWindows用にビルドされたGnuPGを含んだツールセットになっていて, GnuPGに加えて鍵/証明書マネージャの**Kleopatra**, Outlook用のメール暗号化プラグイン**GpgOL**, GnuPGをシェルに統合する**GnuEX**をまとめてインストール出来ます。<font color="Gainsboro">Kleopatraはアイコンもうちょっと何とかなりませんかね・・・・</font>

基本的には[公式サイト][Gpg4win]からインストーラをダウンロードして実行してインストールすればよいです。
[Chocolatey][]を利用しているのであれば`PS> choco install gpg4win -y`でインストールすることも出来ます。
普通にインストールすればGnuPGへのパスも自動的に追加されると思います。


鍵の作成
--------

Kleopatra(インストール後にはタスクトレイに常駐していると思います)のウィンドウの左上, **ファイル**から**New Key Pair**を選択し, **個人用のOpenPGP鍵ペアを作成**を行います。

![Kleopatra](https://qiita-image-store.s3.amazonaws.com/0/152916/3c68eefa-6849-9c99-116e-f3e1c085669e.png)

![作成する鍵の選択 - Kleopatra](https://qiita-image-store.s3.amazonaws.com/0/152916/f1b03dd5-9a2e-62ca-d1cc-8a9fb06f4c9d.png)

今回は楕円曲線DSAで署名したいので, **詳細設定**から**ECDSA**を選択し, 使用する楕円曲線を選択します(<font color="#999">2017/11/26現在, Ed25519曲線は選択出来ない模様</font> **Ed25519鍵が選べるようになりました(ed25519 + cv25519)**)。
RSAで署名したい場合には同様にRSAを選択し, 楕円曲線を選ぶかわりに鍵長を選択します。
この際, 適宜鍵の有効期限を設定しておくことをお勧めします。

![詳細設定 - Kleopatra](https://qiita-image-store.s3.amazonaws.com/0/152916/da2b722d-97d0-c200-e3c3-e20dead6a0f6.png)

詳細設定を完了し, 名前とメールアドレスを入力して鍵の生成を行おうとすると鍵に設定するパスフレーズを尋ねられるので, 入力して設定することを推奨します。

作成した鍵は自動的にKleopatraに追加され, 管理されます。


gitで使用する鍵の指定
--------------------

要するに`$ git config --global --set user.signingkey "[key ID]"`を実行すればよいわけですが, 折角なのでTortoiseGitから設定してみます。

TortoiseGitの設定から**[Git]**メニューを選択し, ローカルリポジトリに対する設定ならローカルの, グローバルな設定ならグローバルのユーザ情報の**署名鍵ID**にKleopatraで作成した鍵の**Key-ID**カラムの文字列を入力します。

![Key ID - Kleopatra](https://qiita-image-store.s3.amazonaws.com/0/152916/91a4be97-1448-3810-2fd8-febe0e1f868d.png)

![署名鍵ID - TortoiseGit](https://qiita-image-store.s3.amazonaws.com/0/152916/dfad61d9-e205-18cd-201b-413945200259.png)


~~Git for Windowsのgpg.exeを無効にする~~ gitで使用するgpg.exeを指定する
-------------------------------------------------------------------

さて, ここまでGpg4winをインストールするなどやってきたわけですが, **実はGit for WindowsにはGnuPGが含まれます**。
が, Git-Bashなどからgpgコマンドを実行してみれば分かるのですが, **バージョンが非常に古い**(git 2.15.0.windows.1と同時にインストールされるのがgpg 1.4.22)ものになっています。

````
$ git --version
git version 2.15.0.windows.1

$ gpg --version
gpg (GnuPG) 1.4.22
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-E, RSA-S, ELG-E, 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
````

楕円曲線が利用可能になるのはGnuPGのver2.1からなので, このバージョンでは利用することが出来ません。
また, Gpg4winでインストールしたGnuPGは`%AppData%\Roaming\GnuPG`以下にキーリングが保存されますが, Git for WindowsにバンドルされたGnuPGは`%USERPROFILE%\.gnupg`以下に保存します。
このバージョンの差とデフォルトの参照場所の違いから, Kleopatra管理下の鍵はgitバンドルのGnuPGからは見えず, たとえ`%USERPROFILE%\.gnupg`以下のファイルを`%AppData%\Roaming\GnuPG`以下のファイルへのシンボリックリンクにしてもメジャーバージョンが違っているため読み込むことが出来ません。

通常, gitはバンドルされたGnuPGを使用するため, このままではKleopatra管理下の鍵を使うことが出来ません。
~~そこで, gitがバンドルされたGnuPGを使えないようにするため, `{Git for Windowsインストールディレクトリ}\usr\bin\`にある`gpg.exe`を`gp~.exe`などにリネームするか, 或いは削除してしまいましょう。~~
~~こうすることでパスの通った場所に存在する`gpg.exe`が代わりに使用され, 通常は上記でインストールしたGpg4winに含まれるGnuPGの`gpg.exe`が使用されることになります。~~


~~尚, この`gpg.exe`を無効にする作業は**Git for Windowsのバージョンアップの度に行う必要があります**。~~

**gitが使用するgpg.exeのパスをgit configで`gpg.program`に指定しましょう。** (thanks @spiegel-im-spiegel さん)

````
PS > git config --global gpg.program /path/to/GnuPG/bin/gpg.exe
````

先に書いていた方法より遥かにベターです。
Git for Windows更新の際にももちろん再設定は必要ありません。

~~<font color="#999">Git for WindowsにGnuPG ver2.2以降をバンドルしてくれればいいんですが。</font>~~ どうやら現在のGnuPGで使用されているpinentryがX11に依存しているため, MSYS2上では使えない, というのが理由のようです([Alexpux/MSYS2-packages#986](https://github.com/Alexpux/MSYS2-packages/issues/986))



タグに署名する
------------

ここまで設定出来ればあとは簡単です。
TortoiseGitからタグを打つ際に, **署名**のチェックボックスをチェックすれば署名付きタグが作成されます。
このとき鍵のパスフレーズを尋ねられますので, タグを打つ際に毎回入力してあげましょう。

~~現状, TortoiseGitで`$ git commit -S`相当のことを行う方法はちょっと分かりませんが, まぁ全てのコミットに署名する人は少ないでしょうからタグに署名が出来れば十分じゃないかと思います(偏見)。~~


コミットに署名する
----------------

コミットに署名する場合, TortoiseGitのコミットウィンドウから`$ git commit -S`のようにコミット毎に署名を行うかどうかを切り替えることは出来ないと思われます(ご存知の方がいたらご教示ください)。
全てのコミットに署名を行う場合, gitの設定の`commit.gpgsign`を`true`に設定すればTortoiseGitからコミットを行っても署名が行えます:

```bash
git config --global commit.gpgsign true  # 全てのリポジトリについて行う場合
git config --local commit.gpgsign true   # 現在のリポジトリについて行う場合
```

署名に関する設定を削除する場合には下記コマンドを実行します:

```bash
git config --global --unset commit.gpgsign  # 全てのリポジトリについて行う場合
git config --local --unset commit.gpgsign   # 現在のリポジトリについて行う場合
```

(追記) Ed25519鍵を作成する
---------------------------

**KleopatraからEd25519鍵を作成出来るようになりました！**
下記の文章は残しますが, GUIから鍵を作成可能となったため, 積極的に適用する理由はなくなりました。

~~残念ながらKleopatraからはEd25519鍵を作ることは出来ません~~が, コマンド操作を行うことで作成可能です。
また作成以外の管理についてはKleopatraで行うことが出来ます。

単純に`gpg --gen-key`や`gpg --full-gen-key`としても楕円曲線は選択出来ませんが, `--expert`オプションを付加して`--full-gen-key`を実行することで楕円曲線DSA/暗号を選ぶことが出来るようになります。
この場合は候補の楕円曲線リストにEd25519が普通に表示されるので, 後はプロンプトに従って鍵生成を行えばよいです。

````
PS > gpg --expert --full-gen-key
gpg (GnuPG) 2.2.3; 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.

ご希望の鍵の種類を選択してください:
   (1) RSA と RSA (デフォルト)
   (2) DSA と Elgamal
   (3) DSA (署名のみ)
   (4) RSA (署名のみ)
   (7) DSA (機能をあなた自身で設定)
   (8) RSA (機能をあなた自身で設定)
   (9) ECC と ECC                    <- 楕円曲線DSAで署名し楕円曲線暗号で暗号化する鍵
  (10) ECC (署名のみ)
  (11) ECC (機能をあなた自身で設定)
  (13) 既存の鍵
あなたの選択は? 9
ご希望の楕円曲線を選択してください:
   (1) Curve 25519                   <- Ed25519曲線
   (3) NIST P-256
   (4) NIST P-384
   (5) NIST P-521
   (6) Brainpool P-256
   (7) Brainpool P-384
   (8) Brainpool P-512
   (9) secp256k1
あなたの選択は? 1
鍵の有効期限を指定してください。
         0 = 鍵は無期限
      <n>  = 鍵は n 日間で期限切れ
      <n>w = 鍵は n 週間で期限切れ
      <n>m = 鍵は n か月間で期限切れ
      <n>y = 鍵は n 年間で期限切れ
鍵の有効期間は? (0)5y
鍵は11/25/22 15:00:54 東京 (標準時)で期限切れとなります
これで正しいですか? (y/N) y

GnuPGはあなたの鍵を識別するためにユーザIDを構成する必要があります。

本名: [name]
電子メール・アドレス: example@example.com
コメント: <comment>
次のユーザIDを選択しました:
    "[name] (<comment>) <example@example.com>"

名前(N)、コメント(C)、電子メール(E)の変更、またはOK(O)か終了(Q)? O
たくさんのランダム・バイトの生成が必要です。キーボードを打つ、マウスを動か
す、ディスクにアクセスするなどの他の操作を素数生成の間に行うことで、乱数生
成器に十分なエントロピーを供給する機会を与えることができます。
たくさんのランダム・バイトの生成が必要です。キーボードを打つ、マウスを動か
す、ディスクにアクセスするなどの他の操作を素数生成の間に行うことで、乱数生
成器に十分なエントロピーを供給する機会を与えることができます。
gpg: 鍵0000000000000000を究極的に信用するよう記録しました
gpg: 鍵0000000000000001を究極的に信用するよう記録しました
gpg: 失効証明書を '%AppData%/gnupg/openpgp-revocs.d\0000000000000000000000000000000000000000.rev' に保管しました。
公開鍵と秘密鍵を作成し、署名しました。

pub   ed25519 2017-11-26 [SC] [有効期限: 2022-11-25]
      0000000000000000000000000000000000000000
uid                      [name] (<comment>) <example@example.com>
sub   cv25519 2017-11-26 [E] [有効期限: 2022-11-25]
````

尚, この方法で生成した鍵についても自動的にKleopatra管理下に入りますので, 鍵生成以外についてはコマンドを使う必要はありません。



[OpenPGP]:http://openpgp.org/
[Gpg4win]:https://www.gpg4win.org/
[Git for Windows]:https://git-for-windows.github.io/
[TortoiseGit]:https://tortoisegit.org/
[GnuPG]:https://www.gnupg.org/
[Chocolatey]:https://chocolatey.org/