macOS Mojave で GnuPG の鍵を SSH の鍵として使う

## 環境

- macOS Mojave
- Homebrew

## 準備

macOS 向けの GPG Suite というものをインストールする．
GUI アプリケーションと GnuPG のバイナリがインストールされる．

```shell-session
$ brew cask install gpg-suite
```

あとは，適切な鍵を作ってそれを SSH で使えるようにしていく．

## Alice さんの場合

今回は，Alice が新たに GPG 鍵を作ることを考える．
Alice は，自身を `Alice <alice@example.com>` として世界中に認識してもらいたい．
Alice は，Git のコミットへの署名や SSH の公開鍵認証などの用途で GPG 鍵を使いたいと考えている．

### GPG 鍵の新規作成

今回作成する鍵は，今後，長期間に渡って使用するものである．
したがって，暗号アルゴリズムはより強力なものが望ましい．
ここでは，楕円曲線暗号を使うために暗号アルゴリズムとして `future-default` を指定している．
また，秘密鍵が流出した際に悪用され続けないために，鍵には有効期限を設定することが望ましい．
有効期限は 2 年程度が適切だと言われている．
Alice は鍵の有効期限の更新を忘れないように，2 年後の自分の誕生日である 2020 年 1 月 1 日を有効期限として鍵を作成することにした．

```shell-session
$ gpg --quick-generate-key "Alice <alice@example.com>" future-default - 2020-01-01
```

パスフレーズを入力する画面が表示される．
Alice は，十分に安全なパスフレーズを [このページ](https://lists.gnupg.org/pipermail/gnupg-users/2014-April/049307.html) を参考にしながら決めた．

```shell-session
$ gpg --quick-generate-key "Alice <alice@example.com>" future-default - 2020-01-01
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.
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: key XXXXXXXXXXXXXXXX marked as ultimately trusted
gpg: directory '/Users/alice/.gnupg/openpgp-revocs.d' created
gpg: revocation certificate stored as '/Users/alice/.gnupg/openpgp-revocs.d/8EF0B7FA95F80BA3731817EE8CC444C1C014F686.rev'
public and secret key created and signed.

pub   ed25519 2018-11-29 [SC] [expires: 2020-01-01]
      XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
uid                      Alice <alice@example.com>
sub   cv25519 2018-11-29 [E]
```

### SSH 用の鍵の作成

Alice は，SSH 用の鍵を PGP で管理したいと考えている．
先ほどの手順では，

```shell-session
$ gpg --list-keys alice@example.com
pub   ed25519 2018-11-29 [SC] [expires: 2020-01-01]
      XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
uid           [ultimate] Alice <alice@example.com>
sub   cv25519 2018-11-29 [E]
```

プライマリキーの他に，暗号化 (Encryption) 用のサブキーが作成されている．
SSH の認証 (Authenticate) に使える鍵は持っていないので，新たにサブキーを作る．

```shell-session
$ gpg --expert --edit-key alice@example.com
gpg (GnuPG/MacGPG2) 2.2.10; Copyright (C) 2018 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.

Secret key is available.

sec  ed25519/AAAAAAAAAAAAAAAA
     created: 2018-11-29  expires: 2020-01-01  usage: SC  
     trust: ultimate      validity: ultimate
ssb  cv25519/BBBBBBBBBBBBBBBB
     created: 2018-11-29  expires: never       usage: E   
[ultimate] (1). Alice <alice@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
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? S

Possible actions for a ECDSA/EdDSA key: Sign Authenticate 
Current allowed actions: 

   (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? Q
Please select which elliptic curve you want:
   (1) Curve 25519
   (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
Your selection? 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) 0
Key does not expire at all
Is this correct? (y/N) y
Really create? (y/N) y
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.

sec  ed25519/AAAAAAAAAAAAAAAA
     created: 2018-11-29  expires: 2020-01-01  usage: SC  
     trust: ultimate      validity: ultimate
ssb  cv25519/BBBBBBBBBBBBBBBB
     created: 2018-11-29  expires: never       usage: E   
ssb  ed25519/CCCCCCCCCCCCCCCC
     created: 2018-11-29  expires: never       usage: A   
[ultimate] (1). Alice <alice@example.com>

gpg> save
```

これで SSH の認証に使えるサブキーを作成することができた．
今回作ったのは，楕円曲線暗号のサブキーである．
古いサーバーだと RSA 暗号にしか対応していない可能性があるため，RSA 暗号のサブキーも作っておく．

```shell-session
$ gpg --expert --edit-key alice@example.com
gpg (GnuPG/MacGPG2) 2.2.10; Copyright (C) 2018 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.

Secret key is available.

sec  ed25519/AAAAAAAAAAAAAAAA
     created: 2018-11-29  expires: 2020-01-01  usage: SC  
     trust: ultimate      validity: ultimate
ssb  cv25519/BBBBBBBBBBBBBBBB
     created: 2018-11-29  expires: never       usage: E   
ssb  ed25519/CCCCCCCCCCCCCCCC
     created: 2018-11-29  expires: never       usage: A   
[ultimate] (1). Alice <alice@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
Your selection? 8

Possible actions for a RSA key: Sign Encrypt Authenticate 
Current allowed actions: Sign Encrypt 

   (S) Toggle the sign capability
   (E) Toggle the encrypt capability
   (A) Toggle the authenticate capability
   (Q) Finished

Your selection? S

Possible actions for a RSA key: Sign Encrypt Authenticate 
Current allowed actions: Encrypt 

   (S) Toggle the sign capability
   (E) Toggle the encrypt capability
   (A) Toggle the authenticate capability
   (Q) Finished

Your selection? E

Possible actions for a RSA key: Sign Encrypt Authenticate 
Current allowed actions: 

   (S) Toggle the sign capability
   (E) Toggle the encrypt capability
   (A) Toggle the authenticate capability
   (Q) Finished

Your selection? A

Possible actions for a RSA key: Sign Encrypt Authenticate 
Current allowed actions: Authenticate 

   (S) Toggle the sign capability
   (E) Toggle the encrypt capability
   (A) Toggle the authenticate capability
   (Q) Finished

Your selection? Q
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) 0
Key does not expire at all
Is this correct? (y/N) y
Really create? (y/N) y
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.

sec  ed25519/AAAAAAAAAAAAAAAA
     created: 2018-11-29  expires: 2020-01-01  usage: SC  
     trust: ultimate      validity: ultimate
ssb  cv25519/BBBBBBBBBBBBBBBB
     created: 2018-11-29  expires: never       usage: E   
ssb  ed25519/CCCCCCCCCCCCCCCC
     created: 2018-11-29  expires: never       usage: A   
ssb  rsa4096/DDDDDDDDDDDDDDDD
     created: 2018-11-29  expires: never       usage: A   
[ultimate] (1). Alice <alice@example.com>

gpg> save
```

終わり．

### サブキーを SSH で使う

PGP で管理しているサブキーを SSH で使うには，`gpg-agent` を `ssh-agent` として利用する．
`.bashrc` に次のように記載する．

```bash:.bashrc
gpgconf --launch gpg-agent
export SSH_AUTH_SOCK=$(gpgconf --list-dirs agent-ssh-socket)
```

変更を読み込む．

```shell-session
$ source ~/.bashrc
```

SSH 鍵として使うサブキーを `gpg-agent` に伝える．
まずは，キーグリップを確認する．

```shell-session
$ gpg --list-keys --with-keygrip alice@example.com
pub   ed25519 2018-11-29 [SC] [expires: 2020-01-01]
      XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
      Keygrip = SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS
uid           [ultimate] Alice <alice@example.com>
sub   cv25519 2018-11-29 [E]
      Keygrip = TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT
sub   ed25519 2018-11-29 [A]
      Keygrip = UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU
sub   rsa4096 2018-11-29 [A]
      Keygrip = VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
```

SSH 鍵として使うサブキーのキーグリップは，

- `UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU`
- `VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV`

である．

これを `gpg-agent` に伝える．

```shell-session
$ echo UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU >> ~/.gnupg/sshcontrol 
$ echo VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV >> ~/.gnupg/sshcontrol
```

SSH で利用可能になったかを確認してみる．

```shell-session
$ ssh-add -L
ssh-ed25519 (snip) (none)
ssh-rsa (snip) (none)
```

OK．

公開鍵は，`ssh-copy-id` や `gpg --export-ssh-key` を使ってログイン先に書き込んでおきましょう．