OpenSSLでの暗号スイート(Cipher Suite)の取り扱い

# 概要

近年、暗号スイートの管理の重要性が増してきました
計算機の演算能力の向上やサイバーセキュリティにおける脅威やリスク等の増加、既存暗号技術の脆弱性管理などの理由により、単に「暗号化しているかしていないか」だけではなく「どの暗号スイートで通信しているか」が重要になってきています
ネットで検索しても、古い情報をそのまま適用すると脆弱なシステムになってしまう可能性があります
生成AIも、脆弱性を含む回答をするかもしれません
今どの暗号スイートを使っているのかについて把握し制御できる知識や能力に対する需要は今後必要とされるでしょう
ここでは、広く使われているOpenSSLにおける、暗号スイートの取り扱いについて基礎的な事項を扱います

# そのOpenSSLでサポートしている全ての暗号スイートを知る

まずは手元にあるOpenSSLがサポートしているすべての暗号スイートを表示するコマンドを知る方法を出して見ます
この出力内容は対応している暗号スイートを全部出力するものであって、今そのOpenSSLに依存するミドルウェア等が使用しているものとは異なることに留意してください

## 全ての暗号スイートを表示するコマンド

出力される結果については手元の環境によって異なります
`ALL`は全て、という意味ですが、暗号化を行わない暗号スイートを除きます
`NULL`は暗号化を行わない暗号スイートを表示します
`ALL`と`NULL`の組み合わせで、そのopensslが対応する暗号スイートを全て網羅します

```shell-session
$ openssl ciphers -v 'ALL:NULL'
TLS_AES_256_GCM_SHA384  TLSv1.3 Kx=any      Au=any  Enc=AESGCM(256) Mac=AEAD
TLS_CHACHA20_POLY1305_SHA256 TLSv1.3 Kx=any      Au=any  Enc=CHACHA20/POLY1305(256) Mac=AEAD
TLS_AES_128_GCM_SHA256  TLSv1.3 Kx=any      Au=any  Enc=AESGCM(128) Mac=AEAD
ECDHE-ECDSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH     Au=ECDSA Enc=AESGCM(256) Mac=AEAD
ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH     Au=RSA  Enc=AESGCM(256) Mac=AEAD
DHE-DSS-AES256-GCM-SHA384 TLSv1.2 Kx=DH       Au=DSS  Enc=AESGCM(256) Mac=AEAD
DHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=DH       Au=RSA  Enc=AESGCM(256) Mac=AEAD
ECDHE-ECDSA-CHACHA20-POLY1305 TLSv1.2 Kx=ECDH     Au=ECDSA Enc=CHACHA20/POLY1305(256) Mac=AEAD
（以下略）
```

## 表示されるものの意味

出力される内容は、各行ごとに、左から以下の要素となります
1. 暗号スイート名
1. TLS/SSLプロトコルバージョン
1. 鍵交換アルゴリズム
1. 認証アルゴリズム
1. 暗号化アルゴリズムとその強度
1. MACアルゴリズム

## 詳細出力

`-v`スイッチの代わりに`-V`スイッチをコマンドに付与すると以下のようになります
```shell-session
$ openssl ciphers -V 'ALL:NULL'
          0x13,0x02 - TLS_AES_256_GCM_SHA384  TLSv1.3 Kx=any      Au=any  Enc=AESGCM(256) Mac=AEAD
          0x13,0x03 - TLS_CHACHA20_POLY1305_SHA256 TLSv1.3 Kx=any      Au=any  Enc=CHACHA20/POLY1305(256) Mac=AEAD
          0x13,0x01 - TLS_AES_128_GCM_SHA256  TLSv1.3 Kx=any      Au=any  Enc=AESGCM(128) Mac=AEAD
          0xC0,0x2C - ECDHE-ECDSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH     Au=ECDSA Enc=AESGCM(256) Mac=AEAD
          0xC0,0x30 - ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH     Au=RSA  Enc=AESGCM(256) Mac=AEAD
          0x00,0xA3 - DHE-DSS-AES256-GCM-SHA384 TLSv1.2 Kx=DH       Au=DSS  Enc=AESGCM(256) Mac=AEAD
          0x00,0x9F - DHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=DH       Au=RSA  Enc=AESGCM(256) Mac=AEAD
          0xCC,0xA9 - ECDHE-ECDSA-CHACHA20-POLY1305 TLSv1.2 Kx=ECDH     Au=ECDSA Enc=CHACHA20/POLY1305(256) Mac=AEAD
（以下略）
```

## 標準的な暗号スイート名の表示

暗号スイート名称に、OpenSSL方言に加えて標準的なスイート名を出力するには、`-stdname`スイッチを付与します

```shell-session
$ openssl ciphers -v -stdname 'ALL:NULL' 
TLS_AES_256_GCM_SHA384 - TLS_AES_256_GCM_SHA384  TLSv1.3 Kx=any      Au=any  Enc=AESGCM(256) Mac=AEAD
TLS_CHACHA20_POLY1305_SHA256 - TLS_CHACHA20_POLY1305_SHA256 TLSv1.3 Kx=any      Au=any  Enc=CHACHA20/POLY1305(256) Mac=AEAD
TLS_AES_128_GCM_SHA256 - TLS_AES_128_GCM_SHA256  TLSv1.3 Kx=any      Au=any  Enc=AESGCM(128) Mac=AEAD
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 - ECDHE-ECDSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH     Au=ECDSA Enc=AESGCM(256) Mac=AEAD
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 - ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH     Au=RSA  Enc=AESGCM(256) Mac=AEAD
TLS_DHE_DSS_WITH_AES_256_GCM_SHA384 - DHE-DSS-AES256-GCM-SHA384 TLSv1.2 Kx=DH       Au=DSS  Enc=AESGCM(256) Mac=AEAD
TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 - DHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=DH       Au=RSA  Enc=AESGCM(256) Mac=AEAD
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 - ECDHE-ECDSA-CHACHA20-POLY1305 TLSv1.2 Kx=ECDH     Au=ECDSA Enc=CHACHA20/POLY1305(256) Mac=AEAD
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 - ECDHE-RSA-CHACHA20-POLY1305 TLSv1.2 Kx=ECDH     Au=RSA  Enc=CHACHA20/POLY1305(256) Mac=AEAD
TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 - DHE-RSA-CHACHA20-POLY1305 TLSv1.2 Kx=DH       Au=RSA  Enc=CHACHA20/POLY1305(256) Mac=AEAD
TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 - ECDHE-ECDSA-AES256-CCM8 TLSv1.2 Kx=ECDH     Au=ECDSA Enc=AESCCM8(256) Mac=AEAD
（以下略）
```

# フィルタリング

OpenSSLを使用する際には、対応する全ての暗号スイートを使用するわけではありません
対応する暗号スイートの中には脆弱なもの、将来的に脆弱とみなされるものもあるからです
したがって、実際には対応する暗号スイートの中から使用すべき暗号スイートを絞り込んでゆくことになります

## セキュリティ強度によるフィルタリング

日本国内での公式な暗号スイートガイドラインとしては、CRYPTRECの資料や、IPAのTLS暗号設定ガイドラインがあリます
これらの資料に「セキュリティ強度」もしくは「ビットセキュリティ」という用語が登場します。これは暗号技術の強度を統一的に比較検討するための尺度となります

opensslコマンドで、このセキュリティ強度により暗号スイートをフィルタリングするには`-s`スイッチを使います

```shell-session
$ openssl ciphers -v -s 'ALL @SECLEVEL=4'
TLS_AES_256_GCM_SHA384  TLSv1.3 Kx=any      Au=any  Enc=AESGCM(256) Mac=AEAD
TLS_CHACHA20_POLY1305_SHA256 TLSv1.3 Kx=any      Au=any  Enc=CHACHA20/POLY1305(256) Mac=AEAD
ECDHE-ECDSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH     Au=ECDSA Enc=AESGCM(256) Mac=AEAD
ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH     Au=RSA  Enc=AESGCM(256) Mac=AEAD
DHE-DSS-AES256-GCM-SHA384 TLSv1.2 Kx=DH       Au=DSS  Enc=AESGCM(256) Mac=AEAD
DHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=DH       Au=RSA  Enc=AESGCM(256) Mac=AEAD
ECDHE-ECDSA-CHACHA20-POLY1305 TLSv1.2 Kx=ECDH     Au=ECDSA Enc=CHACHA20/POLY1305(256) Mac=AEAD
（以下略）
```

| セキュリティ強度 | 内容 |
|:-|:-|
| SECLEVEL=0 | 全ての暗号スイートを表示 |
| SECLEVEL=1 | 80ビット以上のセキュリティ強度を表示 |
| SECLEVEL=2 | 112ビット以上のセキュリティ強度を表示 |
| SECLEVEL=3 | 128ビット以上のセキュリティ強度を表示 |
| SECLEVEL=4 | 192ビット以上のセキュリティ強度を表示 |
| SECLEVEL=5 | 256ビット以上のセキュリティ強度を表示 |



## TLSバージョンによるフィルタリング

TLSバージョンによるフィルタリングは最もよく使うことになるかもしれません
TLSバージョンのフィルタリングは`-s`スイッチとともに使います

```shell-session:
 openssl ciphers -v -s -tls1_2 'ALL @SECLEVEL=4'
ECDHE-ECDSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH     Au=ECDSA Enc=AESGCM(256) Mac=AEAD
ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH     Au=RSA  Enc=AESGCM(256) Mac=AEAD
DHE-DSS-AES256-GCM-SHA384 TLSv1.2 Kx=DH       Au=DSS  Enc=AESGCM(256) Mac=AEAD
DHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=DH       Au=RSA  Enc=AESGCM(256) Mac=AEAD
ECDHE-ECDSA-CHACHA20-POLY1305 TLSv1.2 Kx=ECDH     Au=ECDSA Enc=CHACHA20/POLY1305(256) Mac=AEAD
ECDHE-RSA-CHACHA20-POLY1305 TLSv1.2 Kx=ECDH     Au=RSA  Enc=CHACHA20/POLY1305(256) Mac=AEAD
（以下略）
```

```shell-session:
$ openssl ciphers -v -s -tls1_3 'ALL @SECLEVEL=4'
TLS_AES_256_GCM_SHA384  TLSv1.3 Kx=any      Au=any  Enc=AESGCM(256) Mac=AEAD
TLS_CHACHA20_POLY1305_SHA256 TLSv1.3 Kx=any      Au=any  Enc=CHACHA20/POLY1305(256) Mac=AEAD
```

| スイッチ | TLSバージョン |
|:-|:-|
| -tls1 | TLS 1.0 |
| -tls1_1 | TLS 1.1 |
| -tls1_2 | TLS 1.2 |
| -tls1_3 | TLS 1.3 |

# OpenSSLの暗号スイート設定

ここまではopensslコマンドを使ってフィルタリングしていましたが
OpenSSLで実際に使用されるのは設定されたものです

## 設定ファイルの場所

OpenSSLの設定ファイルの場所はディストリビューションによって異なりますが、以下のコマンドで知ることができます
設定ファイル名は`openssl.cnf`です

```shell-session
$ openssl version -d
OPENSSLDIR: "/etc/pki/tls"
```

## 暗号スイートの設定

暗号スイートに関する設定の一例です
設定ファイルのうち暗号スイートに関係のない部分は省いています

```ini:openssl.cnf
openssl_conf = openssl_init

[openssl_init]
ssl_conf = ssl_module

[ ssl_module ]
system_default = crypto_policy

[ crypto_policy ]
TLS.MinProtocol = TLSv1.2
TLS.MaxProtocol = TLSv1.3
DTLS.MinProtocol = DTLSv1.2
DTLS.MaxProtocol = DTLSv1.2
CipherString = @SECLEVEL=4:DEFAULT
Ciphersuites = TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256
SignatureAlgorithms = ECDSA+SHA256:ECDSA+SHA384:ECDSA+SHA512:ed25519:ed448:rsa_pss_pss_sha256:rsa_pss_pss_sha384:rsa_pss_pss_sha512:rsa_pss_rsae_sha256:rsa_pss_rsae_sha384:rsa_pss_rsae_sha512:RSA+SHA256:RSA+SHA384:RSA+SHA512:ECDSA+SHA224:RSA+SHA224
Groups = x25519:prime256v1:x448:secp521r1:secp384r1:ffdhe2048:ffdhe3072
```

`CipherString`に、TLS 1.2以前の暗号スイート設定を書きます
`Ciphersuites`に、TLS 1.3の暗号スイート設定を書きます


# ミドルウェアやアプリケーションにおける暗号スイート設定

ところで、OpenSSLの設定をしても、各々のミドルウェアやアプリケーションでは個別に設定を行う場合があります
例えばnginxやApache httpdのようなものでは、個別に設定をします

## nginxの場合

nginxの暗号スイート設定の一例です
設定ファイルのうち暗号スイートに関係のない部分は省いています

```:nginx.conf
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers @SECLEVEL=4:DEFAULT;
ssl_conf_command Ciphersuites TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256;
```

`ssl_ciphers`に、TLS 1.2以前の暗号スイート設定を書きます
`ssl_conf_command Ciphersuites`に、TLS 1.3の暗号スイート設定を書きます

## 個別の設定

上記のように、結局のところソフトウェアごとに個別に設定することがありますが、それぞれのソフトウェアのマニュアルを調べて設定します
しかしながら、基本はこの文書の最初の方で扱ったopensslコマンドの暗号スイートのフィルタリングに沿って記述することになるはずです

# より簡易に暗号スイートを管理したい

このように、暗号スイートを管理するには、個別のソフトウェアごとにあちらこちらで同じような設定をすることになり煩雑になりがちです
RHEL系ディストリビューションなどの最近のバージョンでは、crypto-policiesというツールによる一括管理ができるようになっています

crypto-policiesについては、下記の拙記事やネット検索などで使い方を調べることができます

https://qiita.com/exit0/items/9f0d37e5dde36052ca45

おしまい

## 以下、PR

## 仲間を募集しています！

ARIではエンジニア・ITコンサルタント・PM職全方位で仲間を募集しております。
カジュアル面談、随時受付中です！
ご興味ある方はこちらをご覧ください。

https://note.com/ari_hr/n/n4aed9ba75421