paloma blog

NWエンジニアやってます。主に自宅環境のお遊びを書きます。Pythonもちょっと。タイトルは好きなカクテルから。

SSHのセッション確立フローをもう一回勉強する

業務の一環でNW機器のsshdアルゴリズムを調べていたんですが、
そういえばSSHのセッション確立のフローについてちゃんと説明出来ないなと思ったのでおさらいします。

アルゴリズムの中身を書いていくときりがないので、どのタイミングで何をしているのかを整理したいと思います。

仕組み自体もそうですが、アルゴリズムの種類も多いので用語で混乱してしまいますね。

SSHで出てくる用語

アルゴリズム

  • ホストキー
    • SSHサーバを識別する値
  • 共通鍵
    • 暗号化に使われる鍵
  • 公開鍵
  • 秘密鍵
    • それぞれログイン時のユーザ認証に使われる鍵

SSHの動作 コネクション

大まかな流れ

  1. TCPコネクション確立
  2. サーバ使用できるバージョンを応答
  3. サーバの公開ホストキーの提供
    • 公開鍵認証でサーバのFinger printを確認して認証
  4. アルゴリズムネゴシエーション
  5. Diffie Hellman関数で鍵交換
    • ここで暗号化、複合化用の共通鍵が交換される
  6. 共通鍵を使って以後の通信をやりとり
    • 以降のコネクションで使われる共通鍵暗号はバイナリパケットプロトコルと呼ばれる
    • パケットにMACを使ってデータの整合性を保っている

認証

以下のどちらかでユーザを認証する

  • パスワード認証
  • 公開鍵認証
    • 公開鍵、秘密鍵はここで使われる

なぜ説明できなかったのか、勘違いしていたところ

対象鍵暗号、非対称鍵暗号アルゴリズムがごっちゃになっていた

アルゴリズムの用語は覚えていましたが、何の鍵暗号化の紐づけが忘れてしまっていました。

ホストキーと公開鍵がごっちゃになっていた

公開ホストキーと書かれている場合が多いので公開鍵と間違えていました。

  • 公開ホストキーはSSHコネクション時に確認される
    • known_hostsファイルに保存される。情報が無い場合はユーザ認証前に確認される
  • 公開鍵はユーザ認証のみで使う
    • 認証キーペアはクライアント側で作成してサーバに配置する

これですっきり。

ファイル、コマンド系

サーバ側

  • 公開ホストキー

ホストキはssh_host_XXX_key.pubとアルゴリズムごとにありますが、私の経験ではecdsaがよく使われています。

/etc/ssh/ssh_host_ecdsa_key.pub # 接続するとclientのknown_hostsに書かれる
  • ホストキー確認コマンド
ssh-keygen -lv -f /etc/ssh/ssh_host_ecdsa_key.pub

クライアント側

Windowsだとソフトによりけりなので一般的なLinuxで書きます。

  • sshサーバのホストキー
$HOME/.ssh/known_hosts
  • 認証鍵ペア
$HOME/.ssh/id_rsa
$HOME/.ssh/id_rsa.pub # こっちをサーバのauthrized_keyに書く。またはssh-copy-id

残課題 ホストキーについて

  • ホストの認証とは何なのか?どう行っているのか?

SSHコネクションを行う際に公開ホストキーでサーバの識別を行いますが、ecdsaの鍵が使われておりこれも公開鍵認証を行っていそうです。

ユーザではなくサーバ認証用のキーペアがありそうですが、この周りの資料が出てこなかったのでこの分は今回保留とします。

サーバ側でホストキーファイルを確認したら公開鍵と秘密鍵のペアっぽいものがありました。

masashi@PC-ubuntu:~$ ls -l /etc/ssh/ssh_host_*
-rw------- 1 root root  227  817  2019 /etc/ssh/ssh_host_ecdsa_key
-rw-r--r-- 1 root root  176  817  2019 /etc/ssh/ssh_host_ecdsa_key.pub
-rw------- 1 root root  411  817  2019 /etc/ssh/ssh_host_ed25519_key
-rw-r--r-- 1 root root   96  817  2019 /etc/ssh/ssh_host_ed25519_key.pub
-rw------- 1 root root 1675  817  2019 /etc/ssh/ssh_host_rsa_key
-rw-r--r-- 1 root root  396  817  2019 /etc/ssh/ssh_host_rsa_key.pub

公開鍵を確認。

masashi@PC-ubuntu:~$ cat /etc/ssh/ssh_host_ecdsa_key.pub
ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBIYnhbqvzAS0J/yUr7jCGLx88zBL9GqPlrZZLobdBmdkKdLEDIQ2VUCcMdfsZ1IZA0kqStnq61o5s9OGQ0sbzN0= root@PC-ubuntu

クライアント側と比較してみます。
環境の都合でWindowsでの確認ですが、同じですね。
最近のビルドではPowershellsshが付いているので便利です。

PS C:\Users\masashi> cat .\.ssh\known_hosts
192.168.0.10 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBIYnhbqvzAS0J/yUr7jCGLx88zBL9GqPlrZZLobdBmdkKdLEDIQ2VUCcMdfsZ1IZA0kqStnq61o5s9OGQ0sbzN0=

ということはサーバ接続時も公開鍵認証でクライアントがサーバを認証していてアルゴリズムはecdsaを使用しているということになりますね。
で、サーバの公開鍵がクライアントのknown_hostsに書かれると。
パスワード認証の場合でも一回は公開鍵認証をしているということですね。

まとめ

普段使っているSSHですが、意外と説明に困ったので今回まとめてみました。
技術的な説明は何もできていませんが、とりあえずはフローの整理ができたので良しとします。

SSHが詳しく書かれている本って意外と無いんですよね。
O'Reilly本を読むのとRFCを読まないとですね。

参考サイト

Understanding the SSH Encryption and Connection Process | DigitalOcean

RFC 4716 - The Secure Shell (SSH) Public Key File Format

RFC 4253 - The Secure Shell (SSH) Transport Layer Protocol