Chienomi

SSHの公開鍵認証に関する誤謬と実際

SSHの公開鍵認証について、「常識」となっている説明がある。

「サーバーが公開鍵によって暗号化したデータを送り、クライアントはこれを復号化して復号化した結果を送信する」 というものだ。

ものすごく当たり前のようにそう言われているし、ウェブでも本でもその説明ばかりであり、私も雑誌でそのように読んだのでそう信じていた。

が、これは事実ではない。

考えてみるとこれは問題があることがわかる。 まず、サーバー側が暗号化に使用する公開鍵を特定する方法がない。 そして、もしもクライアント側から公開鍵を指定し、サーバー側が指定された公開鍵で暗号化するとすれば、サーバーにその鍵が登録されているかどうかを権限によらず知ることができるということになってしまう。

実際

プロトコル

SSHのプロトコルについては基本的に理解しているという前提で進めるが、一応説明しておこう。

SSHはバイナリプロトコルであり、バイナリプロトコルということは「長さ」を特定する方法が必要になる。

SSHパケットは先頭4バイトがパケット長で、次の1バイトがパディング長、それ以降がペイロードになる。 パケット全体の長さは8の倍数バイトになっている。 パディングはランダムな値で、結果8の倍数バイトになるように長さが設定される。

ペイロードの先頭は1バイトのメッセージタイプ(整数)になっている。 それぞれのメッセージタイプの値に対して名前がついている。

SSHサーバーは動的にクライアントに問いかけることはなく、接続を確率するまでは常にクライアントからの問いかけに応答する形である。

認証

クライアントはSSH2_MSG_SERVICE_REQUEST (Type 5)を送信し、サーバーが認証を受け付ける場合、SSH2_MSG_USERAUYTH_ACCEPT (Type 6)を返す。

認証はクライアントがSSH2_MSG_USERAUTH_REQUEST (Type 50)によって認証を行い、それを受け取ったサーバーはSSH2_MSG_USERAUTH_FAILURE (Type 51)またはSSH2_MSG_USERAUTH_SUCCESS (Type 52)を返す。

失敗した場合に失敗した理由は回答されないが、有効な認証メソッドの一覧が返る。 これを先に得ようとする場合、クライアントは認証メソッドがnoneであるSSH_MSG_USERAUTH_REQUESTを送り、SSH2_MSG_USERAUTH_FAILUREを受け取って認証を選択する。

認証を複数突破する必要がある場合、途中の認証に成功した場合もSSH2_MSG_USERAUTH_FAILUREが返る。

公開鍵認証

認証メソッド publickey を使用する場合、クライアントは認証メソッドpublickeyで、認証メソッド名の直後に真偽値があり、この真偽値が偽であるSSH2_MSG_USERAUTH_REQUESTを送信する。 サーバーはこれに対して、publickey認証ができないことを示すSSH2_MSG_USERAUTH_FAILUREか、もしくはpublickey認証が可能であることを示すSSH2_MSG_USERAUTH_PK_OK (Type 60)を返す。 このやりとりは省略できる

次に真偽値が真であるSSH2_MSG_USERAUTH_REQUESTを送信する。 これに続き、

  • 公開鍵暗号アルゴリズム (String)
  • 公開鍵 (String)
  • 署名された値 (String)

が後続する。アルゴリズムについてはDHにおいて交換されているが、これに従う必要はない。

署名された値は、セッションIDの後ろにこのパケットの署名よりも前の部分を結合したもの全体に対する署名である。 DHで交換された経路暗号を担う共通の秘密であるセッションIDを使用していることにより、その値そのものが他者には知りえない共通の秘密になっている。 忘れてはいけない。 SSHの経路暗号は共通鍵暗号である

パケットには公開鍵そのものを含み、署名の検証は付属された公開鍵によって行われる。 それが成功した場合に、その認証に成功した公開鍵が認証済みであるかどうか(authorized_keysに存在するか)を照合するのである。 鍵オプションの適用もこれを経て行われる。

なぜこうなった

おそらく、SSH1時代のRSAAuthenticationというのと混同しているのだうろ。

RSAAuthenticationは、チャレンジレスポンス方式で、よく言われる方式と似ている。 そして、SSH1時代の解説を誰も検証することなくコピペで広め続けたために、それが適合しなくなった現代においても流布されている、ということではないか。

RSAAuthenticationはPublickey Authenticationに置き換わる形でSSH2からは消えている。 今やOpenSSHにおいてはSSH1はサポートされなくなっているので、あまり意味のない知識だ。

Wrote on: 2019-10-30 18:01:00 +09:00