春山征吾のWiki - ssh/SSHプロトコル概要/バージョン文字列の交換

サンプルプログラムでの実装


バージョン文字列の交換部分の実装は以下の通りです.

https://github.com/haruyama/ssh_client_sample/blob...

  private def sendVersionString(out: OutputStream, clientVersion: String) {
    out.write((clientVersion+ "\r\n").getBytes)
  }

  private def recvVersionString(in:InputStream): String = {
    val reader = new BufferedReader(new InputStreamReader(in))
    var serverString = ""
    //"SSH-" で開始しない文字列は無視する
    do {
      serverString = reader.readLine
    } while (!serverString.startsWith("SSH-"))
    serverString
  }

  private def exchangeVersion(in: InputStream, out: OutputStream, clientVersion: String) = {
    //バージョン文字列の交換
    //CR LF 区切りの文字列でやりとりする

    //クライアントからバージョン文字列を送る
    sendVersionString(out, clientVersion)

    //サーバからバージョン文字列を受け取る
    val serverVersion = recvVersionString(in)

    //version のすり合わせは省略している

    //クライアントとサーバのバージョン文字列は鍵の生成で利用するので
    //サーバのバージョン文字列を返す
    serverVersion
  }

解説

バージョン文字列を交換


sendVersionString() と recvVersionString() によって, バージョン文字列を交換しています.

SSHのパケットは利用せず, CR LF 区切りの文字列をやりとりします.
このため, サーバのバージョン文字列は, SSHサーバにtelnetすることで確認できます.

% telnet localhost 22     (git)-[master] 
Trying ::1...
Connected to localhost.
Escape character is '^]'.
SSH-2.0-OpenSSH_5.8p1 Debian-4

バージョンのすりあわせ


実用的な実装では相手のバージョン文字列に応じて, SSH の古いバージョン(1.5 や 1.3)に対応したり, 既知のバグを避けるワークアラウンドの準備をします.

このサンプルでは, なにもせず, 相手が SSH 2 プロトコル だと仮定して先に進みます.

サーバのバージョン文字列の返却


クライアントとサーバのバージョン文字列は, 暗号化やMACの鍵の生成に利用します.クライアントのバージョン文字列は既知ですので, サーバのバージョン文字列を返しています.