OpenSSHの暗号化周りの設定について

昨今、常時SSL化対応などで、SSL/TLS(https)の暗号化設定について各所で話題になっていたりしますが、サーバの運用に使用するSSHの暗号化設定についてはあまり触れられることが少ないように思います。

今回、個人的に運用しているサーバのSSL/TLSの対応に合わせてSSH(OpenSSH)にも通信に利用する暗号化周りの設定（暗号化方式、鍵交換方式、メッセージ認証、公開鍵）を行うために各暗号化方式の調査や検討を行ったので、まとめていきます。

**2020-09-30 更新**

* 設定ファイルの説明にRed Hat/CentOS 8のcrypto-policies導入に関する注記を追加しました。
* OpenSSH 8.3までに新規追加された暗号方式等を反映しました。
* 公開鍵設定まわりの記述を全体的に見直しました。

# OpenSSHの設定ファイル

OpenSSHの設定ファイルは`/etc/ssh`配下にまとめられています。
サーバ機能とクライアント機能の両方がインストールされているサーバであれば、下記の2種類のファイルが存在しています。
(その他、サーバ公開鍵などが同ディレクトリに存在します)

|ファイル名|内容|
|:--|:--|
|ssh_config|SSHクライアントの設定ファイル|
|sshd_config|SSHサーバの設定ファイル|

今回は、SSHのサーバ側に対しての設定を行いたいので、サーバの設定ファイル`sshd_config`に対して設定を行っていきます。
※ Red Hat/CentOSの8.x系では、`crypto-policies`という仕組みが導入され、sshdの起動引数としてシステムで規定された暗号化方式が指定される仕様になりました。
sshdの引数で指定される設定は、設定ファイルよりも優先順位が高いため、OpenSSH設定ファイルの暗号化関連の設定は反映できなくなりました。

# 暗号方式の評価基準

今回は各暗号方式や鍵交換方式などを評価基準としてよく用いられるNIST SP 800-57の評価表で評価を行いました。
評価表を基に、SSHで利用されるアルゴリズムを分類したものが次の表になります。

|Level|暗号方式|鍵交換方式|署名方式|ハッシュ|MAC|
|:--|:--|:--|:--|:--|:--|
|≦80||DH-1024|RSA-1024<br>DSA-1024|MD5<br>SHA1||
|112|3DES|DH-2048|RSA-2048|||
|128|AES-128<br>(Chacha20)|ECDH P-256<br>(ECDH X25519)|RSA-3072<br>ECDSA P-256<br>(Ed25519)|SHA256|HMAC-SHA1|
|128-192||DH-4096|RSA-4096||
|192|AES-192|ECDH P-384|ECDSA P-384||
|192-256||DH-8192|||
|256|AES-256|ECDH P-521|ECDSA P-521|SHA512|HMAC-SHA256|

※ Chacha20, Curve25519(ECDH X25519, EdDSA)については、言及がありませんが、RFC7748で~128-bit security levelとうたわれているため、ここでは128に分類することにします。

上記の表をもとに、下記の4段階の基準で分類していくことにします。

|安全性|基準|
|:-:|:--|
|◎|AES 128bit相当以上のセキュリティレベルを満たす|
|○|AES 112bit以上、128bit未満相当のレベルで2019年現在では実用上十分な安全性がある|
|△|脆弱性がある、もしくはAES 112bit相当未満の強度で解読のおそれは低いものの強度不足|
|×|脆弱性があり、解読等のおそれがある|

# 暗号化方式(Ciphers)

SSHのサーバ・クライアント間で通信する際の暗号化方式です。

|Algorithm|暗号化方式|安全性|備考|
|:--|:--|:-:|:--|
|3des-cbc|3DES(CBC) 168bit|△[^c1]||
|aes128-cbc|AES(CBC) 128bit|△||
|aes192-cbc|AES(CBC) 192bit|△||
|aes256-cbc|AES(CBC) 256bit|△||
|aes128-ctr|AES(CTR) 128bit|◎||
|aes192-ctr|AES(CTR) 192bit|◎||
|aes256-ctr|AES(CTR) 256bit|◎||
|aes128-gcm@openssh.com|AES(GCM) 128bit|◎|OpenSSH 6.2以降|
|aes256-gcm@openssh.com|AES(GCM) 256bit|◎|OpenSSH 6.2以降|
|arcfour|RC4 128bit|×||
|arcfour128|RC4 128bit|×||
|arcfour256|RC4 256bit|×||
|blowfish-cbc|Blowfish(CBC) 128bit|△[^c1]||
|cast128-cbc|CAST(CBC) 128bit|△[^c1]||
|chacha20-poly1305@openssh.com|Chacha20 256bit|◎|OpenSSH 6.5以降|
[^c1]: SWEET32の脆弱性(CVE-2016-2183)あり

CBC系の暗号化方式はSSHプロトコルの仕様上に問題があるため、基本的に使用せず、Chacha20やAES-GCM、AES-CTRを利用するようにします。

AES-CTR系の方式は古くから使用できるため、古いSSHクライアントなどの互換性を考えても（3DESやAES-CBCしかサポートしない特殊なクライアントがなければ）最低限AES-CTRがあれば問題はないでしょう。

### 設定
暗号化方式を設定する際には、`Ciphers`ディレクティブを追加して設定を行います。

```apache
# Chacha20, AES-CTR, AES-GCM系を設定する例
Ciphers  chacha20-poly1305@openssh.com,aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com
```


# 鍵交換方式(KexAlgorithms)

暗号通信を始める前に、暗号化に使用する鍵をサーバ・クライアント間で共有するために使用するアルゴリズムです。
SSL/TLSでは、サーバ証明書の公開鍵を使って暗号化する方式(RSA系)とDiffie-Hellman系がありますが、SSHではDiffie-Hellman系のみとなります。

|Algorithm|鍵交換方式|ハッシュ|安全性|備考|
|:--|:--|:--|:-:|:--|
|curve25519-sha256|ECDH X25519|SHA-2 256bit|◎|OpenSSH 7.4以降|
|curve25519-sha256@libssh.org|ECDH X25519|SHA-2 256bit|◎|OpenSSH 6.7以降[^2]|
|diffie-hellman-group1-sha1|DH 1024bit|SHA-1 160bit|△||
|diffie-hellman-group14-sha1|DH 2048bit|SHA-1 160bit|○||
|diffie-hellman-group14-sha256|DH 2048bit|SHA-2 256bit|○|OpenSSH 7.3以降|
|diffie-hellman-group16-sha512|DH 4096bit|SHA-2 512bit|◎|OpenSSH 7.3以降|
|diffie-hellman-group18-sha512|DH 8192bit|SHA-2 512bit|◎|OpenSSH 7.3以降|
|diffie-hellman-group-exchange-sha1|DH **** bit [^1]|SHA-1 160bit|△/○/◎||
|diffie-hellman-group-exchange-sha256|DH **** bit [^1]|SHA-2 256bit|△/○/◎|OpenSSH 4.4以降|
|ecdh-sha2-nistp256|ECDH P-256|SHA-2 256bit|◎|OpenSSH 5.7以降|
|ecdh-sha2-nistp384|ECDH P-384|SHA-2 256bit|◎|OpenSSH 5.7以降|
|ecdh-sha2-nistp521|ECDH P-521|SHA-2 256bit|◎|OpenSSH 5.7以降|
|sntrup4591761x25519-sha512@tinyssh.org [^3]|NTRU|SHA-2 512bit|?|OpenSSH 8.0以降|

[^1]: 鍵長は可変となり、一般的に1024～8192bitの中から選択されます。昨今ではLogjam脆弱性などの影響で十分な安全性を確保するために2048bitが必要とされることから、最近の実装では範囲が2048～8192bitとなっているようです。(`/etc/ssh/moduli`を手動で生成することにより範囲の制御も可能)
[^2]: OpenSSHとしては6.5からサポートしているが、バグにより無効化されている
[^3]: 量子コンピュータ対応に対応した暗号方式(試験段階)。OpenSSH 8.3時点ではデフォルトで無効。

diffie-hellmanのgroup16やgroup18は十分な強度がありますが、bit数の増大による影響で他のアルゴリズムと比べて**処理が非常に重い**ので積極的に使える選択肢とは言い難い。

そのため、安全性と処理が軽いECDH系を基本として、ECDHをサポートしない古いSSHクライアントがある場合は、古くから利用できて互換性が高く安全性・速度もそこそこのgroup14やgroup-exchangeを追加することを検討します。
※ group-exchangeはサーバにより鍵長が可変値となるため、必要に応じて十分な強度があるか確認が必要。

### 設定
設定する際には、`KexAlgorithms`ディレクティブを追加して設定を行います。
`KexAlgorithms`はOpenSSH 5.7から追加された機能となりますので、それ以前のバージョンでは設定による制御はできません。

```apache
# ECDH系と、Diffie-Hellman(group-exchange, group14)を設定する例
KexAlgorithms    curve25519-sha256,curve25519-sha256@libssh.org,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group14-sha1
```



# メッセージ認証符号(MACs)
サーバ・クライアント間でやりとりされる暗号化されたメッセージが改竄や破損していないか確認する際に使用するアルゴリズムです。

### 標準版(Encrypt-and-MAC(E&M)方式)
|Algorithm|方式|安全性|備考|
|:--|:--|:-:|:--|
|hmac-md5|MD5 128bit|×||
|hmac-md5-96|MD5 96bit|×||
|hmac-ripemd160|RIPEMD 160bit|○？|安全性不明|
|hmac-sha1|SHA-1 160bit|◎||
|hmac-sha1-96|SHA-1 96bit|△||
|hmac-sha2-256|SHA-2 256bit|◎|OpenSSH 5.9以降|
|hmac-sha2-512|SHA-2 512bit|◎|OpenSSH 5.9以降|
|umac-64@openssh.com|UMAC 64bit|△？|OpenSSH 4.7以降, 安全性不明|
|umac-128@openssh.com|UMAC 128bit|○？|OpenSSH 6.2以降, 安全性不明|

### Encrypt-then-MAC(EtM)方式
OpenSSH 6.2以降では、標準版のEncrypt-and-MAC方式に加え、Encrypt-then-MAC(EtM)方式という選択肢が増えています。
標準版に比べて処理方法が改良され、安全性が強化されているようですが、根本的な安全性は元のアルゴリズムに依存するため、評価としては同等としています。
これら(EtM)が使用可能な場合は、標準版(E&M)と同様に必要なアルゴリズムを追加します。

|Algorithm|方式|安全性|備考|
|:--|:--|:-:|:--|
|hmac-md5-etm@openssh.com|MD5 128bit|×|OpenSSH 6.2以降|
|hmac-md5-96-etm@openssh.com|MD5 96bit|×|OpenSSH 6.2以降|
|hmac-ripemd160-etm@openssh.com|RIPEMD 160bit|○？|OpenSSH 6.2以降, 安全性不明|
|hmac-sha1-etm@openssh.com|SHA-1 160bit|◎|OpenSSH 6.2以降|
|hmac-sha1-96-etm@openssh.com|SHA-1 96bit|△|OpenSSH 6.2以降|
|hmac-sha2-256-etm@openssh.com|SHA-2 256bit|◎|OpenSSH 6.2以降|
|hmac-sha2-512-etm@openssh.com|SHA-2 512bit|◎|OpenSSH 6.2以降|
|umac-64-etm@openssh.com|UMAC 64bit|△？|OpenSSH 6.2以降, 安全性不明|
|umac-128-etm@openssh.com|UMAC 128bit|○？|OpenSSH 6.2以降, 安全性不明|

メッセージ認証符号は、SHA-2系を基本として、必要に応じて古いSSHクライアントとも互換性の高いSHA-1系の`hmac-sha1`の追加を検討します。

UMAC系は最新のOpenSSH 8.3でもデフォルト有効となっているため、脆弱なアルゴリズムではないと思われますが、特に指標がなく安全性が不明なため、必要がなければ無効化しておくと良いでしょう。
(一般的なSSHクライアントであれば、SHA-2かSHA-1の何れかがあれば接続可能)

EtMとE&Mが双方使用可能な場合は、セキュリティの高いEtM系を先に設定し、その後にE&M系を指定するのがよさそうです。

### 設定

設定する際には、`MACs`ディレクティブを追加して設定を行います。

```apache
# SHA-2系とSHA-1で、EtM, E&M双方を設定する例
MACs    hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha1-etm@openssh.com,hmac-sha2-256,hmac-sha2-512,hmac-sha1
```



# 公開鍵関連(PubkeyAcceptedKeyTypes/HostKeyAlgorithms)

公開鍵関連の設定で指定できる設定には、サーバ証明書に相当する「ホスト公開鍵」の種類を設定する`HostKeyAlgorithms`と、クライアントのログイン時の公開鍵認証に使用する`PubkeyAcceptedKeyTypes`があります。

## 鍵の種類と用途
### クライアント公開鍵(PubkeyAcceptedKeyTypes)
SSHのログイン認証時に、接続元クライアントの認証に利用できる公開鍵の種類です。
秘密鍵はクライアント側端末に、公開鍵は一般的にサーバ側の`${HOME}/.ssh/authorized_keys`に設定されているものです。

### ホスト公開鍵(HostKeyAlgorithms)
SSHの接続時に、接続先サーバの認証に利用するホスト公開鍵の種類です。
秘密鍵、公開鍵とも`/etc/ssh/`配下に保管されているものです。

## 設定値/方法

### 通常版

`ssh-keygen`コマンド等を用いて単体で生成する鍵を使用する一般的な方法です。
OpenSSH 8.2以降は、FIDO対応の外部認証器などによる2要素認証を利用した鍵を利用できるようになりました。

|Algorithm|署名方式|安全性|備考|
|:--|:--|:-:|:--|
|ssh-ed25519|Ed25519|◎||
|sk-ssh-ed25519@openssh.com|Ed25519|◎|OpenSSH 8.2以降, 2要素認証付き|
|ssh-rsa|RSA ****bit[^hk1]|△||
|ssh-dss|DSA 1024bit|△||
|rsa-sha2-256|RSA ***bit[^hk1]|△/○/◎|OpenSSH 7.2以降|
|rsa-sha2-512|RSA ***bit[^hk1]|△/○/◎|OpenSSH 7.2以降|
|ecdsa-sha2-nistp256|ECDSA P-256|◎||
|ecdsa-sha2-nistp384|ECDSA P-384|◎||
|ecdsa-sha2-nistp521|ECDSA P-521|◎||
|sk-ecdsa-sha2-nistp256@openssh.com|ECDSA P-256|◎|OpenSSH 8.2以降, 2要素認証付き|

### CA署名版

SSHのサーバ公開鍵もSSL/TLSのサーバ証明書のようにルート鍵を別に生成し、その鍵で署名されたサーバ公開鍵を作成することができ、下記がその際に使用する方式になります。

|Algorithm|署名方式|安全性|備考|
|:--|:--|:-:|:--|
|ssh-ed25519-cert-v01@openssh.com|Ed25519|◎||
|sk-ssh-ed25519-cert-v01@openssh.com|Ed25519|◎|OpenSSH 8.2以降, 2要素認証付き|
|ssh-rsa-cert-v01@openssh.com|RSA ****bit[^hk1]|△||
|ssh-dss-cert-v01@openssh.com|DSA 1024bit|△||
|rsa-sha2-256-cert-v01@openssh.com|RSA ****bit[^hk1]|△/○/◎|OpenSSH 7.2以降|
|rsa-sha2-512-cert-v01@openssh.com|RSA ****bit[^hk1]|△/○/◎|OpenSSH 7.2以降|
|ecdsa-sha2-nistp256-cert-v01@openssh.com|ECDSA P-256|◎||
|ecdsa-sha2-nistp384-cert-v01@openssh.com|ECDSA P-384|◎||
|ecdsa-sha2-nistp521-cert-v01@openssh.com|ECDSA P-521|◎||
|sk-ecdsa-sha2-nistp256-cert-v01@openssh.com|ECDSA P-256|◎|OpenSSH 8.2以降, 2要素認証付き|

[^hk1]: RSA公開鍵の鍵長は鍵ペア作成時の設定により異なる。

RSAのホスト公開鍵`/etc/ssh/ssh_host_rsa_key`の鍵長は2048bitで生成されていることが多いですが、`ssh-keygen`コマンドを利用して任意の長さで生成できるので、必要に応じて再生成します。

現状、設定値はデフォルトでDSA系以外が使用される設定になっていますので、あえて`HostKeyAlgorithms`を手動で設定する意味は薄いです。

### 設定

設定する際には、必要に応じて`PubkeyAcceptedKeyTypes`もしくは、`HostKeyAlgorithms`ディレクティブを追加して設定を行います。
`HostKeyAlgoritms`はOpenSSH 7.0で追加された機能となりますので、それ以前のバージョンでは設定による制御はできません。

```apache
# DSA系以外を設定する例
PubkeyAcceptedKeyTypes ssh-ed25519-cert-v01@openssh.com,ecdsa-sha2-nistp256-cert-v01@openssh.com,ecdsa-sha2-nistp384-cert-v01@openssh.com,ecdsa-sha2-nistp521-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com,ssh-rsa-cert-v01@openssh.com,ssh-ed25519,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,rsa-sha2-256,rsa-sha2-512,ssh-rsa
HostKeyAlgorithms      ssh-ed25519-cert-v01@openssh.com,ecdsa-sha2-nistp256-cert-v01@openssh.com,ecdsa-sha2-nistp384-cert-v01@openssh.com,ecdsa-sha2-nistp521-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com,ssh-rsa-cert-v01@openssh.com,ssh-ed25519,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,rsa-sha2-256,rsa-sha2-512,ssh-rsa
```

# 設定反映
`sshd_config`に変更した設定値を反映するためには、一度sshdデーモンを再起動する必要があります。

`sshd -t`コマンドを使用すると、`sshd_config`の設定ファイルの検証が行えますので、デーモン再起動の際は設定に構文エラーがないことを確認してから再起動を行いましょう。

# 参考

NIST SP 800-57 Part 1 Rev.4 (鍵管理における推奨事項) pp.50-51
https://www.ipa.go.jp/security/publications/nist/index.html

RFC4253 / The Secure Shell (SSH) Transport Layer Protocol
https://tools.ietf.org/html/rfc4253

RFC5656 / Elliptic Curve Algorithm Integration in the Secure Shell Transport Layer
https://tools.ietf.org/html/rfc5656

RFC7748 / Elliptic Curves for Security
https://tools.ietf.org/html/rfc7748

Secure Secure Shell
https://stribika.github.io/2015/01/04/secure-secure-shell.html