🐔

git の signingkey にフィンガープリントを指定する時は末尾に感嘆符が必要

2022/06/16に公開
1

署名のすすめ

唐突だが git でコミット時に gpg の署名を付けているだろうか?
署名を付けておくと GitHub でコミットに って出て何となく箔が付いたように見えるから(気のせい)、みんなも付けるといいんじゃないかと思う。

それ、間違ってますから

で、そのためには git config -global commit.gpgsign true とか git config --global user.signingkey キー とかやる必要があるんだが、どうもこの user.signingkey の指定の仕方が正しく広まっていないように見える。

と言うのは、ここにフィンガープリントを指定する場合、最後に感嘆符(ビックリマーク、エクスクラメーションマーク、要は!)を付ける必要があるんだが、そう言った記載をあまり見かけないからだ。
むしろ誤った記載しか見かけない、とさえ言える。

GitHub のドキュメント

例えば、みんな大好き GitHub のドキュメントTelling Git about your signing keyを見てみると臆面もなく、

$ git config --global user.signingkey 3AA5C34371567BD2

と書いてある。
ダメですから!
これじゃ意味ないですから!
正しくはこう。

$ git config --global user.signingkey 3AA5C34371567BD2!

非常に気づきづらいが、最後に!が付いている。これ重要。

みんな間違ってる理由(?)

で、何でこんな事になってるのかと思ったら、なんと Git の公式サイトが間違ってやがった
GPG Introduction を見ると、

$ git config --global user.signingkey 0A46826A

と書いてある。
ちげーよ!
お前が間違えるなよ!
これ↓が正解。

$ git config --global user.signingkey 0A46826A!

しつこいようだが、最後に!が付いている。これ重要。
さすがに厳しいので一応プルリク出しといた。
⇒[2022/6/21 追記]マージされた(1バイト)、良かった…

なんで感嘆符?

user.signingkeygpg コマンドの --local-user にそのまま指定される、と git のドキュメントにしっかり書いてある。
つまり、指定するのは「ユーザ ID」であって「キー ID」ではない。

で、網羅的に書かれている訳では無いが、gpg のコマンドで「ユーザ ID」を指定する場所では、「キーID」の最後に! を付けたものも指定できることになっている。

つまり、そういうわけだ。(どういうわけだ?)

でも実は大丈夫かも…

これだけ間違った情報が出回ってて何で大丈夫なのかと言えば、間違った指定は単に無視されているから。つまり、指定されていないのと同じなのである。

指定されていないとどうなるかと言えば、署名できるキーが勝手に使われる。つまり署名できるキーさえあれば、ちゃんと署名されるというわけだ。

じゃあいつダメなのかと言えば、署名できるキーが複数あって、かつそれらを使い分けたい場合だけだ。
これは推測になるが、多分そんなヤツはあんまりいないから間違ってても気づいてないんじゃなかろうか。

正しく設定しよう

とは言え、間違った設定を残しておくのは気持ち悪いと思うので、正しく設定することをお勧めする。

そして、今回の教訓は公式サイトでも間違っていることはあるので気をつけよう、と言う事だ。(そうか?)

Discussion

conjLobconjLob

以下 man ページ gpg(1) の「HOW TO SPECIFY A USER ID」項から引用します。

By key Id.
This format is deduced from the length of the string and its content or 0x prefix. The key Id of an X.509 certificate are the low 64 bits of its SHA-1 fingerprint. The use of key Ids is just a shortcut, for all automated processing the fingerprint should be used.

When using gpg an exclamation mark (!) may be appended to force using the specified primary or secondary key and not to try and calculate which primary or secondary key to use.

The last four lines of the example give the key ID in their long form as internally used by the OpenPGP protocol. You can see the long key ID using the option --with-colons.

234567C4
0F34E556E
01347A56A
0xAB123456

234AABBCC34567C4
0F323456784E56EAB
01AB3FED1347A5612
0x234AABBCC34567C4

By fingerprint.
This format is deduced from the length of the string and its content or the 0x prefix. Note, that only the 20 byte version fingerprint is available with gpgsm (i.e. the SHA-1 hash of the certificate).

When using gpg an exclamation mark (!) may be appended to force using the specified primary or secondary key and not to try and calculate which primary or secondary key to use.

The best way to specify a key Id is by using the fingerprint. This avoids any ambiguities in case that there are duplicated key IDs.

1234343434343434C434343434343434
123434343434343C3434343434343734349A3434
0E12343434343434343434EAB3484343434343434
0xE12343434343434343434EAB3484343434343434

「This format is deduced from the length of the string and its content or the 0x prefix.」とあるように、指定されたパラメータがキー ID またはフィンガープリントであるかは、特定の長さの16進数であるか、または明示的にプレフィックス 0x が指定されているかで判定されます。そのため、サフィックス ! は必須ではないかと思われます。

実際、ソースコードを見てみると16進数の長さで条件分岐していました。
0x もほかの & などのプレフィックスとは違い、必須ではないようです。
https://git.gnupg.org/cgi-bin/gitweb.cgi?p=gnupg.git;a=blob;f=common/userids.c;h=00f26b720e04e9a02ba624281ae844ba95bfaa00;hb=refs/heads/STABLE-BRANCH-2-2

また、! を付けない場合は、セカンダリキーを指定してもそれのプライマリキーに紐づく署名可能なキーが自動的に選択されるようです。したがって、単にプライマリキーとセカンダリキーのセット全体を指定したい場合はプライマリキーのフィンガープリントを ! 無しで指定し、特定のセカンダリキーの使用を強制したい場合は ! を付けるのが良さそうです。