OpenSSHの公開鍵認証時の正常異常ログ比較 続編

[OpenSSHの公開鍵認証時の正常異常ログ比較](https://qiita.com/szly/items/cf0bd4348ed5f3fb3a2a)の続編です。

前の記事では、SSHクライアントには秘密鍵"id_rsa_test"のみを配置して動作を確認しました。今回は、秘密鍵"id_rsa_test"と同フォルダに公開鍵"id_rsa_test.pub"を配置した状態で動作を確認してみます。

この記事には、以下の"会社で聞かれて答えたこと"のエッセンスが含まれています。

* 関連会社から送ってもらった鍵ファイルの、拡張子とファイル形式が合っていないようなので見てほしい
* どの形式のファイルを、どのアプリケーションが使えるのか

# 公開鍵ファイルがある場合とない場合の動作の違い

"秘密鍵ファイルだけを使った場合"と"秘密鍵ファイルと公開鍵ファイルの両方を使った場合"のログの、違いのある部分を抜粋します。大まかな違いを確認するため、デバッグレベル1で比較しています。

認証失敗パターンを使うと、違いが分かりやすいです。ここで試した認証失敗パターンは、サーバーの"authorized_keys"が読み込みできない状態＆パスワード認証不可となっています。

ログの中で行頭に■を付けてある行が、差異のある行です。

## "秘密鍵ファイルだけを使った場合"のログ

```
C:\Tmp>ssh -v -p 10022 -i id_rsa_test linuser@127.0.0.1 echo OK
    :
debug1: Connecting to 127.0.0.1 [127.0.0.1] port 10022.
debug1: Connection established.
■ debug1: key_load_public: No such file or directory
■ debug1: identity file id_rsa_test type -1
debug1: key_load_public: No such file or directory
debug1: identity file id_rsa_test-cert type -1
    :
debug1: Authentications that can continue: publickey
debug1: Next authentication method: publickey
■ debug1: Trying private key: id_rsa_test
■ debug1: read_passphrase: can't open /dev/tty: No such file or directory
■ Enter passphrase for key 'id_rsa_test':
debug1: Authentications that can continue: publickey
debug1: No more authentication methods to try.
linuser@127.0.0.1: Permission denied (publickey).
    :
C:\Tmp>
```

## "秘密鍵ファイルと公開鍵ファイルの両方を使った場合"のログ

```
C:\Tmp>ssh -v -v -p 10022 -i id_rsa_test linuser@127.0.0.1 echo OK
    :
debug1: Connecting to 127.0.0.1 [127.0.0.1] port 10022.
debug1: Connection established.
■ debug1: identity file id_rsa_test type 0
debug1: key_load_public: No such file or directory
debug1: identity file id_rsa_test-cert type -1
    :
debug1: Authentications that can continue: publickey
debug1: Next authentication method: publickey
■ debug1: Offering public key: RSA SHA256:shv7i4Upls8ekTl1bGFiZ/1o9P0zHRSKDgMvQznCxSU id_rsa_test
debug1: Authentications that can continue: publickey
debug1: No more authentication methods to try.
linuser@127.0.0.1: Permission denied (publickey).
    :
C:\Tmp>
```

## ログの違いの解説

前者のログに"Enter passphrase for key 'id_rsa_test':"と表示されていることに気が付くでしょう。これはパスフレーズの入力です。そして、後者ではパスフレーズの入力がありません。これが一番大きな違いです。

このタイミングで何が起こっているのでしょうか。

公開鍵認証の大まかな仕組みは、[過去の記事](https://qiita.com/szly/items/54885a0594f29985d0c5)で紹介した[UnixUserの過去記事](http://www.unixuser.org/%7Eeuske/doc/openssh/book/chap3.html#what-is-pubkey-authentication)に記されています。公開鍵認証部分を抜粋すると、以下のような仕組みになっています。

* クライアントは、公開鍵を指定し、"指定した公開鍵に対応する秘密鍵"を持っていることをサーバーに通知する。
* サーバーは、指定された公開鍵を持っているかどうかを確認する。
 * 持っていない場合は、指定された公開鍵を持っていないことをクライアントに通知する。
 * この場合、クライアントはこの鍵ペアに対する処理を終了する。
* サーバーは、"指定された公開鍵に対応する秘密鍵を持っていることを証明して"とクライアントに促す。
 * これが"チャレンジ"と呼ばれるもの
* クライアントは、"秘密鍵を持っていること"を証明するための情報を送る。
 * これが"レスポンス"と呼ばれるもの
* サーバーは、クライアントからのレスポンスが正しいかどうかを判定する。
 * レスポンスが正しい場合、"クライアントは正しい秘密鍵を持っている"と判断して、ログイン許可をクライアントに通知する。
 * レスポンスが正しくない場合、ログイン許可できないことをクライアントに通知する。
  * この場合、クライアントはこの鍵ペアに対する処理を終了する。

このうち、最初の処理でクライアントが準備すべきものは公開鍵です。

秘密鍵ファイル"id_rsa_test"に対する公開鍵ファイル"id_rsa_test.pub"が同じフォルダに置いてある場合、その公開鍵ファイル"id_rsa_test.pub"をそのまま公開鍵として使うことができます。

秘密鍵ファイル"id_rsa_test"に対する公開鍵ファイル"id_rsa_test.pub"が同じフォルダに置いてない場合、公開鍵を秘密鍵ファイル"id_rsa_test"から取り出す必要があります。この秘密鍵はパスフレーズ付きです。そのため、秘密鍵から公開鍵を取り出すためにはパスフレーズ入力が必要です。

公開鍵ファイル"id_rsa_test.pub"がある場合は、パスフレーズを入力しなくとも公開鍵を使用できます。対して、公開鍵ファイル"id_rsa_test.pub"がない場合は、パスフレーズを入力しないと公開鍵を使用できません。これがパスフレーズ入力有無の違いとなって表れているわけです。

# 鍵ファイルの形式

上の動きに密接に関連しているのが、[前の記事](https://qiita.com/szly/items/cf0bd4348ed5f3fb3a2a)でいただいたコメントで紹介されている記事["PuTTYの秘密鍵が独自形式な理由"](https://srad.jp/~doda/journal/596047/)およびそこから紹介されている["PuTTY wish key-formats-natively"](https://www.chiark.greenend.org.uk/~sgtatham/putty/wishlist/key-formats-natively.html)です。

[前の記事](https://qiita.com/szly/items/cf0bd4348ed5f3fb3a2a)と紹介記事["PuTTYの秘密鍵が独自形式な理由"](https://srad.jp/~doda/journal/596047/)に記されている鍵ファイルのうち、よく見かけるファイル形式を列記してみます。

ファイル形式を見分けるための情報を先に記載します。その後、個々の形式を少しだけ掘り下げて説明します。

## ファイル形式の見分け方

* OpenSSH秘密鍵ファイル(旧型式)：OpenSSL-PEM形式
 * 拡張子はなし
 * ファイル冒頭に"BEGIN RSA PRIVATE KEY"と書かれた秘密鍵ファイル
* OpenSSH秘密鍵ファイル(新形式)
 * 拡張子はなし
 * ファイルの冒頭に"BEGIN OPENSSH PRIVATE KEY"と書かれた秘密鍵ファイル
* OpenSSH公開鍵ファイル
 * 拡張子は".pub"
 * "ssh-～"で始まる1行形式の公開鍵ファイル
* Putty秘密鍵ファイル：PPK形式
 * 拡張子は".ppk"
 * ファイル冒頭に"PuTTY-User-Key-File"と書かれた秘密鍵および公開鍵の鍵ペアファイル

訂正：ここに記載されていた"RFC4716形式"という記載は除去しました。
訂正：ここに記載されていた"Putty公開鍵ファイル"は除去しました。それに伴い、サブ節も除去しました。

## Putty秘密鍵ファイル

Puttyの秘密鍵ファイルは、実際は"秘密鍵"と"公開鍵"がまとまっているファイルです。上のテストで使用したファイルをPPK形式に変換したものは、以下のようになっています。

```
C:\Tmp>type id_rsa_test.ppk
PuTTY-User-Key-File-2: ssh-rsa
Encryption: aes256-cbc
Comment: imported-openssh-key
Public-Lines: 6
AAAAB3NzaC1yc2EAAAADAQABAAABAQDQCWJn07n7TzKAoRcJvZ+QnV99Pc5NVbcB
    :
4/iLYgX4GPq9LSjKuM0NgFCUK7kGS3XuGOJNSwLQcxvfoKTOtoIJ
Private-Lines: 14
fm7UYN2IWHW/pgKAa8hse9iyx9is8T9/60fPGcdQ0PqYMl/rXfvA7J4E+nIULxwL
    :
woTdftnHEkLDqZUHktHMBJcjHnXn+p7l8dZdJyTdqfEJDRRO6fzoEVbLnkjkiFZG
Private-MAC: 59d4a5873be28c86b015f5a59f32326a6ead7ef8

C:\Tmp>
```

"Public-Lines:"で始まる部分が公開鍵、"Private-Lines:"で始まる秘密鍵、これらが同じファイルにまとまっています。そのため、パスフレーズ付きの鍵であっても公開鍵をパスフレーズ入力なしに取り出すことができます。試してみましょう。

[Putty-GDI](https://ice.hotmint.com/putty/)を使って接続したときのログは、以下のようになっています。

```
2020-04-24 10:08:37	Connecting to 127.0.0.1 port 10022
2020-04-24 10:08:37	We claim version: SSH-2.0-PuTTY_Unidentified_Local_Build
2020-04-24 10:08:37	Server version: SSH-2.0-OpenSSH_7.9p1 Debian-10+deb10u2
2020-04-24 10:08:37	Using SSH protocol version 2
2020-04-24 10:08:37	Doing ECDH key exchange with curve Curve25519 and hash SHA-256
2020-04-24 10:08:38	Server also has ecdsa-sha2-nistp256/ssh-rsa host keys, but we don't know any of them
2020-04-24 10:08:38	Host key fingerprint is:
2020-04-24 10:08:38	ssh-ed25519 256 21:20:26:6e:01:58:31:06:87:63:c9:8e:21:e1:17:25
2020-04-24 10:08:38	Initialised AES-256 SDCTR client->server encryption
2020-04-24 10:08:38	Initialised HMAC-SHA-256 client->server MAC algorithm
2020-04-24 10:08:38	Initialised AES-256 SDCTR server->client encryption
2020-04-24 10:08:38	Initialised HMAC-SHA-256 server->client MAC algorithm
2020-04-24 10:08:38	Reading key file "D:\Tmp\id_rsa_test.ppk"
2020-04-24 10:08:38	Offered public key
2020-04-24 10:08:38	Server refused our key
2020-04-24 10:08:38	Disconnected: No supported authentication methods available (server sent: publickey)
```

秘密鍵ファイルの"D:\Tmp\id_rsa_test.ppk"を読み込んだ後、公開鍵を送信したことを表すログ"Offered public key"が表示されています。このとき、パスフレーズを入力していません。

この動きが、紹介記事["PuTTYの秘密鍵が独自形式な理由"](https://srad.jp/~doda/journal/596047/)にある"Puttyの秘密鍵の優位性"の一つです。

## OpenSSH秘密鍵ファイル

OpenSSHの7.6以前の形式は"OpenSSL-PEM形式"(以下単にPEM形式)、OpenSSHの7.7以降は別の独自形式となっています。

[前回の記事](https://qiita.com/szly/items/cf0bd4348ed5f3fb3a2a)で使用していた形式は"PEM形式"でした。CentOS 7.7を使用していたためです。CentOS 7に"yum install"されるOpenSSHは7.4です。そのため、旧型式の秘密鍵となっています。

この鍵を新形式に変換してみます。

```
[linuser@localhost tmp] $docker run -itd --name tmp centos:8
f1390bf25a3ff9e12a7218afc67c7dc1c234e90ff53d2edf5d7d2358f2a55ff9
[linuser@localhost tmp] $docker exec tmp yum -y install openssh-clients > /dev/null 2>&1
[linuser@localhost tmp] $docker exec tmp ssh -V
OpenSSH_8.0p1, OpenSSL 1.1.1c FIPS  28 May 2019
[linuser@localhost tmp] $cat id_rsa_test
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-128-CBC,824850D9B060D4CD6FB1A9AB0AC7ABB0

DzmmOEGVleY76yfLLbbx1gEG7EHabHWxoVWipPVpbJOpOAAlqw1PgRi3DCJJNuIE
    :
H8twA2qLWzeneSmqSrHBheV/o1aMHwxmyksBau5qPfDXEio2U8Tni3AQhUxMRbks
-----END RSA PRIVATE KEY-----
[linuser@localhost tmp] $docker cp id_rsa_test tmp:/tmp/id_rsa_test
[linuser@localhost tmp] $docker exec -it tmp ssh-keygen -p -f /tmp/id_rsa_test -N ABCDEFG
Enter old passphrase:
Your identification has been saved with the new passphrase.
[linuser@localhost tmp] $docker cp tmp:/tmp/id_rsa_test id_rsa_test_new
[linuser@localhost tmp] $cat id_rsa_test_new
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABAji9Pn5q
    :
iCkeiisg==
-----END OPENSSH PRIVATE KEY-----
[linuser@localhost tmp] $docker stop tmp
tmp
[linuser@localhost tmp] $docker rm tmp
tmp
[linuser@localhost tmp] $
```

鍵ファイルの冒頭に"BEGIN OPENSSH PRIVATE KEY"と書かれています。これで新形式となりました。

但し、新形式でも同じフォルダに公開鍵ファイル"id_rsa_new.pub"ファイルがない場合の動きは、旧型式の場合と同じです。実験結果は全く同じなので省略します。

## アプリケーションの対応

秘密鍵ファイルの、アプリケーションの対応状況を記します。

|アプリケーション|OpenSSH旧型式|OpenSSH新形式|Putty形式|備考|
|:--|:--:|:--:|:--:|:--|
|OpenSSH-7.6以前|○|○|-|但し新形式への対応は6.5以降|
|OpenSSH-7.7以降|○|○|-||
|Putty-GDI-20191001|-|-|○|PuTTYgenの対応状況ではない|
|WinSCP-5.7.2|-|-|○||
|RLogin-2.25.0|○|○|○||

あまりに古いアプリケーションは、OpenSSH新形式には対応していないと考えていいでしょう。ED25519などへの対応も同様です。もっとも、セキュリティ関連のアプリケーションを古いまま使うこと自体がどうなのかという話はあります。

# まとめ

今回は、以下のことを説明しました。

* "ssh -i"で秘密鍵を読み込むとき、同じフォルダに公開鍵があるかどうかで、どのように動作が変わるか
* Puttyだとどのように動作するのか
* OpenSSHとPuttyで秘密鍵はどのように違うのか、なぜPuttyはOpenSSHと異なる形式を用いているのか
* アプリケーションの秘密鍵形式への対応