GPGキーを使ってGitHubにSSHで疎通確認、その後GPGキーを使った署名付きコミットをするまでのログです。
GnuPG is a complete and free implementation of the OpenPGP standard as defined by RFC4880 (also known as PGP). GnuPG allows you to encrypt and sign your data and communications; it features a versatile key management system, along with access modules for all kinds of public key directories. GnuPG, also known as GPG, is a command line tool with features for easy integration with other applications. A wealth of frontend applications and libraries are available. GnuPG also provides support for S/MIME and Secure Shell (ssh).
ということで、RFC4880で規定されたOpenPGP標準規格を実装した、暗号化・署名を行うフリーソフトウェアです。
GPGは
- gpg
- gpgconf
- gpgme-json
- gpgparsemail
- gpgrt-config
- gpgsm
- gpgsplit
- gpgv
- gpg-agent
- gpg-connect-agent
- gpg-error
- gpg-error-config
- gpg-wks-server
- gpg-zip
など複数のソフトウェアで構成されています。大抵のディストリビューションでは /usr/bin/
にあると思います。
執筆時は2.3系が最新ですが、2.2系がLTSバージョンとなっていて、2024年12月31日までサポートされています。なおgpg 2.2.21と2.2.22、libgcrypt 1.9.1は公式で非推奨となっていますので注意してください。
まずはgpgコマンドが使える状態にしてください。今回の例ではAlmaLinux 8.5/gpg 2.2.20/libgcrypt 1.8.5を使用します。またgpg 2.1以降、pinentryの利用(パスフレーズの入力に使用する)が必須となりましたので、これも使えるようにしておいてください。
# RedHat系
sudo yum install gnupg2 pinentry
次に .bashrc
や .profile
などに以下を追記します。
GNUPGHOME="${HOME}/.gnupg"
export GNUPGHOME
GPG_TTY=$(tty)
export GPG_TTY
追記後 ${SHELL} -l
や source ~/.bashrc
、 . .profile
などで再読み込みします。
${GNUPGHOME}
ディレクトリを作成します。
mkdir -p ${GNUPGHOME}/private-keys-v1.d
chmod 0700 ${GNUPGHOME} && chmod 0700 ${GNUPGHOME}/private-keys-v1.d
最後に、現在gpg-agentが起動されているか確認します。単に gpg-agent
で起動状態がわかります。
gpg-agent[3012123]: gpg-agent running and available
といった表示であれば現在起動中ですので、一度止めておきます。
gpgconf --kill gpg-agent
gpgコマンドに渡すオプションを記載しておくファイルです。 ${GNUPGHOME}/gpg.conf
として配置します。
一例を記載します。 personal-*-preferences
に設定するアルゴリズムのリストは gpg --with-colons --list-config
で得ることができます。gpg 2.2.20ではAEADに関する項目が表示されなかったのでコメントアウトしてあります。
cat > ${GNUPGHOME}/gpg.conf <<'EOF'
# キーIDを16文字で表示する
keyid-format long
# フィンガープリントを表示する
with-fingerprint
# キーグリップを表示する
with-keygrip
# 暗号化アルゴリズムのリスト
personal-cipher-preferences AES256 TWOFISH CAMELLIA256
# 認証付き暗号(Authenticated Encryption with Associated Data)に使用する暗号化アルゴリズムのリスト
#personal-aead-preferences EAX OCB
# メッセージダイジェストに使用するハッシュアルゴリズムのリスト
personal-digest-preferences SHA256 RIPEMD160
# 圧縮アルゴリズムのリスト
personal-compress-preferences ZIP ZLIB BZIP2
# バージョン情報を出力しない
no-emit-version
# パスフレーズ入力を呼び出し元(今回はシェル)にリダイレクトする
# 危険なパスフレーズでも警告なしに登録できてしまうので注意
#pinentry-mode loopback
EOF
gpg.conf
と同じように、gpg-agentコマンドに渡すオプションを記載しておくファイルです。 ${GNUPGHOME}/gpg-agent.conf
として配置します。
こちらも例を載せておきます。
cat > ${GNUPGHOME}/gpg-agent.conf <<'EOF'
# 最後にパスフレーズを入力してからのキャッシュTTL(秒)
default-cache-ttl 300
# ssh鍵に対して最後にパスフレーズを入力してからのキャッシュTTL(秒)
default-cache-ttl-ssh 300
# パスフレーズの最大キャッシュTTL(秒)
max-cache-ttl 3600
# ssh鍵のパスフレーズの最大キャッシュTTL(秒)
max-cache-ttl-ssh 3600
# パスフレーズの最短文字数
min-passphrase-len 8
# パスフレーズに英字以外を含める数
min-passphrase-nonalpha 0
# パスフレーズ入力プログラム指定する
#pinentry-program /usr/bin/pinentry
# ssh-agentの代わりにgpg-agentを使用するときは指定する
enable-ssh-support
EOF
さて、いよいよ鍵の作成です。
今回はマスターキーに認証機能だけを持たせて、サブキーに署名・暗号化・証明機能を割り振ります。
作成方法は設定を逐次入力する対話モードと、事前に設定ファイルを作成するバッチモードがありますが、今回は対話モードで作成します。バッチモードについては別に簡単にまとめておきますので、興味があればそちらを参照してください。
楕円曲線暗号を利用します。またサブキーに必要な能力を割り振るので、マスターキー通常は利用しないかわりに有効期限を無期限とします。
gpg --full-gen-key --expert
コマンド入力後は対話的にキー作成を進めます。
楕円曲線暗号を利用するため11を選択し、能力の有無を自分で選択します。
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)
(7) DSA (set your own capabilities)
(8) RSA (set your own capabilities)
(9) ECC and ECC
(10) ECC (sign only)
(11) ECC (set your own capabilities)
(13) Existing key
(14) Existing key from card
Your selection? 11
署名能力の有無を切り替えて認証能力のみにします。
Possible actions for a ECDSA/EdDSA key: Sign Certify Authenticate
Current allowed actions: Sign Certify
(S) Toggle the sign capability
(A) Toggle the authenticate capability
(Q) Finished
Your selection? s
Possible actions for a ECDSA/EdDSA key: Sign Certify Authenticate
Current allowed actions: Certify
(S) Toggle the sign capability
(A) Toggle the authenticate capability
(Q) Finished
Your selection? q
楕円曲線の種類を選択します。今回はCurve 25519を使用します。
Please select which elliptic curve you want:
(1) Curve 25519
(3) NIST P-256
(4) NIST P-384
(5) NIST P-521
(9) secp256k1
Your selection? 1
有効期限を入力します。無期限にしたいので0です。
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) 0
Key does not expire at all
Is this correct? (y/N) y
GPGキーの持ち主の情報を入力します。適宜内容を変更してください。GitHubで使う場合はGitHubに登録しているメールアドレスである必要があります。
GnuPG needs to construct a user ID to identify your key.
Real name: sample
Email address: sample@example
Comment: 1
確認画面が表示されるので、問題なければO(大文字のオー)を入力します。小文字でも通ります。
You selected this USER-ID:
"sample (1) <sample@example>"
Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? o
パスフレーズを入力します。NISTによれば、
Memorized secrets SHALL be at least 8 characters in length if chosen by the subscriber.
(中略)
If the CSP or verifier disallows a chosen memorized secret based on its appearance on a blacklist of compromised values, the subscriber SHALL be required to choose a different memorized secret.
またGnuPGのメーリングリストでは以下のように言及されています。
I'd suggest:
L = (3N) / (10 * log S)
(中略)
Plugging in the numbers for Diceware and a 256-bit key:
L = (3 * 256) / (10 * log 7776)
L = 768 / (10 * 3.89)
L = 768 / 38.9
L = 19.74Round it up to 20 words and call it done.
以上から8から20文字で危険でない(abcdやpasswordではない)単語の組み合わせがよいでしょう。
パスフレーズの入力が終わるとキーと失効証明書が作成されます。
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/${USER}/.gnupg/trustdb.gpg: trustdb created
gpg: key C781C1D6CC545538 marked as ultimately trusted
gpg: directory '/home/${USER}/gnupg/openpgp-revocs.d' created
gpg: revocation certificate stored as '/home/${USER}/.gnupg/openpgp-revocs.d/81E1FBCEC81AD4F229B6DB5FC781C1D6CC545538.rev'
public and secret key created and signed.
pub ed25519/C781C1D6CC545538 2022-01-07 [C]
Key fingerprint = 81E1 FBCE C81A D4F2 29B6 DB5F C781 C1D6 CC54 5538
Keygrip = 1AD0F0EEA2B592906446A011BED9829142C3F943
uid sample (1) <sample@example.com>
gitコミットの署名使用するだけなら署名能力のあるサブキーだけで問題ありません。サブキーの作成方法はどの用途でも同じです。
マスターキーのキーID(今回は C781C1D6CC545538
)かuid(今回は sample@example.com
)を指定します。
gpg --expert --edit-key C781C1D6CC545538
こちらも対話的に作成します。
キーを追加します。
gpg> addkey
マスターキーの作成時と同じように使用する暗号の種類等を選択します。今回は署名能力だけを持つキーを作りたいので、10を選択します
Please select what kind of key you want:
(3) DSA (sign only)
(4) RSA (sign only)
(5) Elgamal (encrypt only)
(6) RSA (encrypt only)
(7) DSA (set your own capabilities)
(8) RSA (set your own capabilities)
(10) ECC (sign only)
(11) ECC (set your own capabilities)
(12) ECC (encrypt only)
(13) Existing key
(14) Existing key from card
Your selection? 10
楕円曲線の種類を選択します。今回はマスターキーと同じCurve 25519を使用します。
Please select which elliptic curve you want:
(1) Curve 25519
(3) NIST P-256
(4) NIST P-384
(5) NIST P-521
(9) secp256k1
Your selection? 1
有効期限を入力します。
秘密鍵の有効期限とは少し話が変わりますが、Appleは2020年3月3日に「398日を超えるSSL/TLS証明書を信頼しない」という声明を出しました。
TLS server certificates issued on or after September 1, 2020 00:00 GMT/UTC must not have a validity period greater than 398 days.
— About upcoming limits on trusted certificates - Apple Support
その後GoogleやMozillaといった主要なブラウザベンダーがこれに追従したことで、現在はSSL/TLS証明書の有効期限は1年になっていることが多いようです。
今回はこれに倣い、有効期限を1年にしておきます。
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) 1y
Key expires at Sat 07 Jan 2023 11:19:01 AM JST
Is this correct? (y/N) y
Really create? (y/N) y
パスフレーズを入力します。マスターキーに設定したパスフレーズです。
パスフレーズが正しければサブキーが作成されます。
# ...
ssb ed25519/09990DA502D268F0
created: 2022-01-07 expires: 2023-01-07 usage: S
[ultimate] (1). sample (1) <sample@example.com>
署名用サブキーと同様に認証用サブキーを作成します。署名用サブキーと作成手順は同じですので、入力値が異なる部分だけ載せておきます。
gpg> addkey
Please select what kind of key you want:
(3) DSA (sign only)
(4) RSA (sign only)
(5) Elgamal (encrypt only)
(6) RSA (encrypt only)
(7) DSA (set your own capabilities)
(8) RSA (set your own capabilities)
(10) ECC (sign only)
(11) ECC (set your own capabilities)
(12) ECC (encrypt only)
(13) Existing key
(14) Existing key from card
Your selection? 11
Possible actions for a ECDSA/EdDSA key: Sign Authenticate
Current allowed actions: Sign
(S) Toggle the sign capability
(A) Toggle the authenticate capability
(Q) Finished
Your selection? a
Possible actions for a ECDSA/EdDSA key: Sign Authenticate
Current allowed actions: Authenticate
(S) Toggle the sign capability
(A) Toggle the authenticate capability
(Q) Finished
Your selection? s
Possible actions for a ECDSA/EdDSA key: Sign Authenticate
Current allowed actions: Authenticate
(S) Toggle the sign capability
(A) Toggle the authenticate capability
(Q) Finished
Your selection? q
作成されたキーは以下の通りです。
# ...
ssb ed25519/0B515F3FEE8F39C8
created: 2022-01-07 expires: 2023-01-07 usage: A
[ultimate] (1). sample (1) <sample@example.com>
今回は署名用と認証用のサブキーを作って終わりにしますので、ここで終了します。
gpg> save
一部のファイルは存在しないこともありますが、マニュアルによれば以下のファイルをバックアップしておくべきです。
- gpg.conf
- gpg-agent.conf
- openpgp-revocs.d/
- private-keys-v1.d/
- pubring.gpg
- pubring.kbx
- sshcontrol
- trustlist.txt
trustdb.gpgについては、以下のコマンドを使用することが推奨されています。出力先は適宜変更してください。
gpg --export-ownertrust > ${GNUPGHOME}/trustdb
また、GPGキーは以下の方法でもバックアップできます。
# 公開鍵
gpg --armor --export --output ${GNUPGHOME}/public-key.asc <uid>
# 秘密鍵
gpg --pinentry-mode loopback --armor --export-secret-keys --output ${GNUPGHOME}/secret-keys.asc <uid>
バックアップが終わったらマスターキーを削除します。
まずマスターキーのキーIDを確認します。
gpg --list-secret-keys
# /home/${USER}/.gnupg/pubring.kbx
# ----------------------------------
# sec ed25519/C781C1D6CC545538 2022-01-07 [C]
# Key fingerprint = 81E1 FBCE C81A D4F2 29B6 DB5F C781 C1D6 CC54 5538
# Keygrip = 1AD0F0EEA2B592906446A011BED9829142C3F943
# uid [ultimate] sample (1) <sample@example.com>
# ssb ed25519/09990DA502D268F0 2022-01-07 [S] [expires: 2023-01-07]
# Keygrip = 9466E3AFC6A4981ED9D6C422417373D37539D434
# ssb ed25519/0B515F3FEE8F39C8 2022-01-07 [A] [expires: 2023-01-07]
# Keygrip = D614E7980EA94F608EBF2EF1CC9E05FC4D75F537
キーIDの最後にエクスクラメーションマーク !
をつけて削除します。確認画面が出るので、キーIDがあっているか確認してください。
gpg --yes --delete-secret-keys C781C1D6CC545538!
gpg: WARNING: unsafe permissions on homedir '/home/rkitagawa/.gnupg/batch'
gpg (GnuPG) 2.2.20; Copyright (C) 2020 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.
sec ed25519/C781C1D6CC545538 2022-01-07 sample example (sample comment) <sample@example.com>
Note: Only the secret part of the shown primary key will be deleted.
Delete this key from the keyring? (y/N) y
This is a secret key! - really delete? (y/N) y
削除できたか確認を行います。 sec#
のように、 #
がついていれば削除できています。
gpg --list-secret-keys
# /home/${USER}/.gnupg/pubring.kbx
# ----------------------------------
# sec# ed25519/C781C1D6CC545538 2022-01-07 [C]
# Key fingerprint = 81E1 FBCE C81A D4F2 29B6 DB5F C781 C1D6 CC54 5538
# Keygrip = 1AD0F0EEA2B592906446A011BED9829142C3F943
# uid [ultimate] sample (1) <sample@example.com>
# ssb ed25519/09990DA502D268F0 2022-01-07 [S] [expires: 2023-01-07]
# Keygrip = 9466E3AFC6A4981ED9D6C422417373D37539D434
# ssb ed25519/0B515F3FEE8F39C8 2022-01-07 [A] [expires: 2023-01-07]
# Keygrip = D614E7980EA94F608EBF2EF1CC9E05FC4D75F537
以下のようにしてインポートを行えます。
cp -R openpgp-revocs.d ${GNUPGHOME}/openpgp-revocs.d
cp -R private-keys-v1.d ${GNUPGHOME}/private-keys-v1.d
cp pubring.kbx ${GNUPGHOME}/pubring.kbx
gpg --import-ownertrust < trustdb
インポート後に gpg --list-secret-keys
などで確認を行ってください。
また gpg --export --output ...
で秘密鍵/公開鍵をエクスポートした場合は、以下の方法でもインポートすることができます( <
は無くても構いません)。
gpg --import < {public-key}
gpg --import < {secret-keys}