RHEL10なら簡単にPQCハイブリッド鍵交換(X25519MLKEM768)対応のWebサーバーを構築できる

# 概要

- RHEL 10がリリースされたことにより、特にソースコードからのビルドを必要とすることなく、容易にWebサーバーのTLSをPQCハイブリッド鍵交換対応させることができるようになりました
- ここではRocky Linux 10を使って、nginxおよびApache httpdを、PQCハイブリッド鍵交換対応してみます

# 前置きは省略して実行してみたい人のための目次
- [RHEL10の設定（crypto-policies）](#rhel10%E3%81%A7pqc%E3%83%8F%E3%82%A4%E3%83%96%E3%83%AA%E3%83%83%E3%83%89%E9%8D%B5%E4%BA%A4%E6%8F%9Bx25519mlkem768%E5%AF%BE%E5%BF%9C%E7%92%B0%E5%A2%83%E3%82%92%E6%A7%8B%E7%AF%89)
- [nginxの構築](#nginx%E3%82%92pqc%E3%83%8F%E3%82%A4%E3%83%96%E3%83%AA%E3%83%83%E3%83%89%E9%8D%B5%E4%BA%A4%E6%8F%9Bx25519mlkem768%E3%81%AB%E5%AF%BE%E5%BF%9C%E3%81%95%E3%81%9B%E3%82%8B)
- [Apache httpd 2.4の構築](#apache-httpd%E3%82%92pqc%E3%83%8F%E3%82%A4%E3%83%96%E3%83%AA%E3%83%83%E3%83%89%E9%8D%B5%E4%BA%A4%E6%8F%9Bx25519mlkem768%E3%81%AB%E5%AF%BE%E5%BF%9C%E3%81%95%E3%81%9B%E3%82%8B)


# PQCハイブリッド鍵交換の必要性について

ここから前置きです

## 量子コンピューターによる従来暗号解読のリスク

- 近年、量子コンピューターの研究開発の進展により、従来の暗号技術の安全性が脅かされつつあるとされています
- とりわけ、ShorのアルゴリズムによりRSAや楕円曲線暗号などの非対称鍵暗号が解読されてしまうリスクが懸念されています
- Shorのアルゴリズムによる既存の非対称鍵暗号の解読を現実的に可能な能力を有する量子コンピューターの出現は、諸説ありますが、米国のNISTでは2035年頃を目安とし、米連邦政府もその前提で対策を進めています

## 量子耐性暗号(PQC)の標準化策定

- 米国のNISTでは、2016年頃より量子コンピューターと従来型コンピューターの両方で解読困難で安全に使用できる非対称鍵暗号技術について、標準化策定を進めてきました
- 2024年にML-KEM、ML-DSA、SLH-DSAが策定され、それぞれECDH、ECDSA、デジタル署名を置き換えるものになります
- 現在も追加の暗号について標準化を進めています

## HNDL攻撃について

- 既存暗号が解読されてしまうのが2035年なら、それまでPQCは使わなくても大丈夫でしょうか
- HNDL攻撃というものがあり、PQC導入は急ぐ領域があるとされています
- HNDL攻撃とは、「Harvest now, decrypt later(今収集しておき、後で解読する)」という攻撃手法です。つまり、現在は解読できないけれども暗号化されたまま重要と思われる通信を傍受・収集しておき、解読可能になってから解読するという攻撃手法です

::: note info
### HNDL攻撃が脅威となる機密データは何でしょうか
- 2025年現在、例えば半年後に新製品として公開する予定のビジネス資料の多くは半年後には公開データとなりますから、そういったものはHNDL攻撃の対象ではないでしょう
- 現在の機密データのうち、10年後もその機密性を保持する必要があるデータはHNDL攻撃が脅威となるものです
- 例えば、今日のあなたの体重、病院で処方された薬のリスト、といったヘルスデータ、今日どこからどこへ移動したという位置データ、などは2035年でも機密性が保証されなければならない可能性が高いでしょう。そしてそれらは私たちがそれぞれの心の中にだけあるのではなく、マイナポータルで確認できたり、携帯電話通信サービス事業会社が保有していたりするものです
- このような個人的なプライバシーデータ以外でも、ビジネスやプライベートの場面で2035年以降も機密性を保証されなければならないデータは多く存在するはずです
:::

### TLS(HTTPS)におけるPQC導入

- NISTによる標準化は行われ、今度は実際に導入する段階にあります
- PQCは、先端研究の領域から、コモディティ技術者が知らなければならない段階に移行しつつあります
- ところで、TLS、とりわけHTTPSにおいてどのようにすれば良いのでしょうか
- TLS証明書（SSL証明書とかサーバー証明書と言ったりします）は、HNDL攻撃の範囲外ですので、今急ぐものではないです。ただしPKI基盤は時間をかけて移行するものなので、CA/PKI基盤の事業者は準備している途中でしょう
- サーバー・インフラ技術者が気にしなければならないのは、鍵交換です。ここはShorのアルゴリズムの影響を受ける場所であり、ここを解読されると、AESやChaCha20の秘密鍵が漏えいしてしまいます
- [NIST IR 8547 (Initial Public Draft)](https://csrc.nist.gov/pubs/ir/8547/ipd)では、この鍵交換について既存暗号技術とのハイブリッドを提唱しています。つまりML-KEMは実績が浅く弱点があるかもしれないリスクがあるので、既存暗号技術とのハイブリッドにすることにより、既存暗号技術とML-KEMの両方を解読できなければならないようにするということです。これがハイブリッド鍵交換(X25519MLKEM768)です
- Google ChromeやMicrosoft Edgeといったブラウザでは既にこれにデフォルトで対応済みです
- Google検索やGmailなどのGoogleのサービスはハイブリッド鍵交換に対応済みです
- あなたのサーバーがハイブリッド鍵交換(X25519MLKEM768)に対応しているかどうか、あなたは知っていますか？そしてその答えはどうですか
- あるいは質問を変えると、あなたが働いている企業・組織において、2035年以降も機密を維持する必要があるデータはどこにどれだけ存在しているか、通信されているか、把握していますか？

以上が前置きです
以下が実際に行動する内容です。機密データの洗い出しは除きますが


# RHEL10で、PQCハイブリッド鍵交換(X25519MLKEM768)対応環境を構築

### RHEL 10.0 およびRocky LinuxなどにおけるPQC実装について

RHEL 10.0以前、例えばRHEL9やRHEL8、それからRHEL系統ではないディストリビューションにおいても、PQCへの対応は可能です
それは下記の拙記事において方法を書いていますし、インターネット上のあちらこちらにもあります

https://qiita.com/exit0/items/11c756f974e14ba11d80

ですが、この手法はソースコードからのビルドが必要なので、人によっては、技術者によっては困難かもしれません
RHEL 10.0では、テクノロジープレビューと断りつつ、PQCに対応しています。

::: note warn
RHEL10では、PQCはテクノロジープレビューとして提供されており、通常のRHELの品質ではないことに留意してください

テクノロジープレビューについては下記ページを参照
https://access.redhat.com/support/offerings/techpreview

:::

RHEL 10では、`crypto-policies`を使用することで、ソースコードからのビルドを必要とせず、容易にPQC対応できます


## 1. `crypto-policies-pq-preview`をインストール

まず、追加のパッケージとして、`crypto-policies-pq-preview`をインストールします

:::note info
RHEL10では、`crypto-policies`の仕組みによってPQCに対応できます
`crypto-policies`については、下記の拙記事や、RHELの公式サイトなどを参照してください
:::

https://docs.redhat.com/ja/documentation/red_hat_enterprise_linux/10/html/securing_networks/post-quantum-cryptography-algorithms-in-openssl

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

```shell-session:crypto-policies-pq-previewインストール
$ sudo dnf -y install crypto-policies-pq-preview
Last metadata expiration check: 0:25:40 ago on Sat Jun 14 17:05:39 2025.
Dependencies resolved.
================================================================================
 Package                    Arch    Version                     Repo       Size
================================================================================
Installing:
 crypto-policies-pq-preview noarch  20250214-1.gitfd9b9b9.el10  appstream  17 k
Installing dependencies:
 liboqs                     aarch64 0.12.0-2.el10               appstream  76 k
 openssl                    aarch64 1:3.2.2-16.el10             baseos    1.1 M
 oqsprovider                aarch64 0.8.0-5.el10                appstream 164 k

Transaction Summary
================================================================================
Install  4 Packages
（中略）
Installed:
  crypto-policies-pq-preview-20250214-1.gitfd9b9b9.el10.noarch
  liboqs-0.12.0-2.el10.aarch64
  openssl-1:3.2.2-16.el10.aarch64
  oqsprovider-0.8.0-5.el10.aarch64

Complete!
```

::: note info
`crypto-policies-pq-preview`はファイル1つのみのパッケージです
このファイルは、crypto-policiesにオプションとして追加できるサブポリシーです

```shell-session:
$ rpm -ql crypto-policies-pq-preview
/usr/share/crypto-policies/policies/modules/TEST-PQ.pmod
```
:::

## 2. crypto-policiesポリシーの設定

### 2-1. サブポリシーTEST-PQを組み込む

インストールしたサブポリシーを、試しに設定してみます

::: note warn
実験的な実装だから将来的な互換性は保証しない旨のメッセージが出てきます
:::

```shell-session:サブポリシーTEST-PQを組み込む
$ update-crypto-policies --show
DEFAULT
$ sudo update-crypto-policies --set DEFAULT:TEST-PQ
ExperimentalValueWarning: `group` value `P384-MLKEM1024` is experimental and might go away in the future
ExperimentalValueWarning: `group` value `P521-MLKEM1024` is experimental and might go away in the future
ExperimentalValueWarning: `group` value `MLKEM1024` is experimental and might go away in the future
ExperimentalValueWarning: `group` value `P256-MLKEM768` is experimental and might go away in the future
ExperimentalValueWarning: `group` value `X25519-MLKEM768` is experimental and might go away in the future
ExperimentalValueWarning: `group` value `MLKEM768-X25519` is experimental and might go away in the future
ExperimentalValueWarning: `group` value `X448-MLKEM768` is experimental and might go away in the future
ExperimentalValueWarning: `group` value `P384-MLKEM768` is experimental and might go away in the future
ExperimentalValueWarning: `group` value `MLKEM768` is experimental and might go away in the future
ExperimentalValueWarning: `group` value `X25519-MLKEM512` is experimental and might go away in the future
ExperimentalValueWarning: `group` value `P256-MLKEM512` is experimental and might go away in the future
ExperimentalValueWarning: `group` value `MLKEM512` is experimental and might go away in the future
ExperimentalValueWarning: `sign` value `MLDSA87-ED448` is experimental and might go away in the future
ExperimentalValueWarning: `sign` value `MLDSA87-P384` is experimental and might go away in the future
ExperimentalValueWarning: `sign` value `P521-MLDSA87` is experimental and might go away in the future
ExperimentalValueWarning: `sign` value `MLDSA87` is experimental and might go away in the future
ExperimentalValueWarning: `sign` value `MLDSA65-ED25519` is experimental and might go away in the future
ExperimentalValueWarning: `sign` value `MLDSA65-P256` is experimental and might go away in the future
ExperimentalValueWarning: `sign` value `MLDSA65-RSA3072` is experimental and might go away in the future
ExperimentalValueWarning: `sign` value `MLDSA65-PSS3072` is experimental and might go away in the future
ExperimentalValueWarning: `sign` value `P384-MLDSA65` is experimental and might go away in the future
ExperimentalValueWarning: `sign` value `MLDSA65` is experimental and might go away in the future
ExperimentalValueWarning: `sign` value `MLDSA44-P256` is experimental and might go away in the future
ExperimentalValueWarning: `sign` value `MLDSA44-ED25519` is experimental and might go away in the future
ExperimentalValueWarning: `sign` value `MLDSA44-RSA2048` is experimental and might go away in the future
ExperimentalValueWarning: `sign` value `MLDSA44-PSS2048` is experimental and might go away in the future
ExperimentalValueWarning: `sign` value `RSA3072-MLDSA44` is experimental and might go away in the future
ExperimentalValueWarning: `sign` value `P256-MLDSA44` is experimental and might go away in the future
ExperimentalValueWarning: `sign` value `MLDSA44` is experimental and might go away in the future
ExperimentalValueWarning: `key_exchange` value `KEM-ECDH` is experimental and might go away in the future
Setting system policy to DEFAULT:TEST-PQ
Note: System-wide crypto policies are applied on application start-up.
It is recommended to restart the system for the change of policies
to fully take place.
$ update-crypto-policies --show
DEFAULT:TEST-PQ
```

### 2-2. サブポリシーTEST-PQの不具合

::: note warn
Rocky Linuxの場合、サブポリシーTEST-PQには、以下のように、RPMパッケージのインストールに不具合があります。RHELやAlmaLinuxなどでも同様なのかについては確認していません

```shell-session:サブポリシーTEST-PQの不具合の例
$ sudo dnf -y install ed
Last metadata expiration check: 0:11:12 ago on Sat Jun 14 18:07:57 2025.
Dependencies resolved.
================================================================================
 Package      Architecture      Version                  Repository        Size
================================================================================
Installing:
 ed           aarch64           1.20-5.el10              baseos            81 k

Transaction Summary
================================================================================
Install  1 Package

Total download size: 81 k
Installed size: 154 k
Downloading Packages:
                         [===                 ] ---  B/s |   0  B     --:-- ETA
The downloaded packages were saved in cache until the next successful transaction.
You can remove cached packages by executing 'dnf clean packages'.
Error: Error downloading packages:
  Curl error (35): SSL connect error for https://mirrors.rockylinux.org/mirrorlist?arch=aarch64&repo=BaseOS-10 [OpenSSL/3.2.2: error:0A0000F4:SSL routines::unexpected message]
```
:::

### 2-3. サブポリシーTEST-PQを解除

パッケージをインストールできなくても構わないならこれでも良いかもしれませんが、ここではいったんサブポリシーTEST-PQを解除して元に戻します

```shell-session:サブポリシーTEST-PQを解除
$ update-crypto-policies --show
DEFAULT:TEST-PQ
$ sudo update-crypto-policies --set DEFAULT
Setting system policy to DEFAULT
Note: System-wide crypto policies are applied on application start-up.
It is recommended to restart the system for the change of policies
to fully take place.
$ update-crypto-policies --show
DEFAULT
```

### 2-4. カスタムサブポリシーを作成

RPMパッケージインストールに関する不具合が出ないように、RPM関連の操作時にはPQCが適用されないようなカスタムポリシーを作成します
ここでは、カスタムポリシーのファイル名を`MYPQ.pmod`としていますので、カスタムポリシー名は`MYPQ`となりますが、任意の名称にして良いです

```shell-session:カスタムサブポリシー作成
$ cd /etc/crypto-policies/policies/modules/
$ sudo vi MYPQ.pmod
$ cat MYPQ.pmod
group = +X25519-MLKEM768
group = +MLKEM768-X25519
group = +MLKEM768

key_exchange = +KEM-ECDH
```


### 2-5. カスタムサブポリシーを適用させる

作成したカスタムサブポリシー`MYPQ`を適用します

```shell-session:カスタムポリシーを適用
$ update-crypto-policies --show
DEFAULT
$ sudo update-crypto-policies --set DEFAULT:MYPQ
（中略）
$ update-crypto-policies --show
DEFAULT:MYPQ
```

::: note info
試しに、手頃なパッケージをインストールして不具合が発生しないことを確認します

```shell-session:インストールによる不具合が発生しないことを確認
$ sudo dnf -y install ed
Last metadata expiration check: 0:49:43 ago on Sat Jun 14 18:07:57 2025.
Dependencies resolved.
================================================================================
 Package      Architecture      Version                  Repository        Size
================================================================================
Installing:
 ed           aarch64           1.20-5.el10              baseos            81 k

（中略）

Installed:
  ed-1.20-5.el10.aarch64

Complete!
```
:::

これで、WebサーバーをPQCハイブリッド鍵交換対応させるための下地ができました

# nginxを、PQCハイブリッド鍵交換(X25519MLKEM768)に対応させる

## 1. nginxをインストール

nginxをインストールします

```shell-session:nginxのインストール
$ sudo dnf -y install nginx
```

## 2. nginxの設定

nginx.confを編集して、末尾の方のTLS(ssl)部分のコメントを解除します

```shell-session:nginx設定
$ sudo vi /etc/nginx/nginx.conf
```

設定の内容は以下のとおりです

```nginx:/etc/nginx/nginx.conf
#（中略）
# Settings for a TLS enabled server.
#
    server {
        listen       443 ssl;
        listen       [::]:443 ssl;
        http2        on;
        server_name  _;
        root         /usr/share/nginx/html;

        ssl_certificate "/etc/pki/nginx/server.crt";
        ssl_certificate_key "/etc/pki/nginx/private/server.key";
        ssl_session_cache shared:SSL:1m;
        ssl_session_timeout  10m;
        ssl_ciphers PROFILE=SYSTEM;
        ssl_prefer_server_ciphers on;

        # Load configuration files for the default server block.
        include /etc/nginx/default.d/*.conf;
    }

}

```

## 3. TLS証明書等の作成

TLS証明書とそれに紐づく秘密鍵を生成します
それぞれのファイルの場所は、前述のnginx.confに記載しているとおりです

| ファイル | ファイルの場所 |
|:-:|:-|
| 秘密鍵 | /etc/pki/nginx/private/server.key |
| 証明書 | /etc/pki/nginx/server.crt |

秘密鍵と証明書の生成方法は、ネット上にいくらでもあります
例えば、下記の拙記事にも記載しています

https://qiita.com/exit0/items/0391173bd69b1e2219ff

### 3-1. 秘密鍵と証明書の作成

```shell-session:秘密鍵と証明書の作成
KEY=/etc/pki/nginx/private/server.key
CERT=/etc/pki/nginx/server.crt
$ sudo mkdir -p /etc/pki/nginx/private/
$ sudo openssl genpkey -out "${KEY}" \
> -algorithm EC \
> -pkeyopt ec_paramgen_curve:P-256
$ sudo openssl req -new -x509 -days 365 \
> -key "${KEY}" -out "${CERT}" \
> -subj "/C=JP/L=Tokyo/O=Example Ltd/CN=www.example.com" \
> -addext "subjectAltName = DNS:www.example.com, DNS:example.com"
```

## 4. nginxを起動

### 4-1. nginx起動

nginxを起動させます

```shell-session:nginx起動
$ sudo systemctl start nginx
$ systemctl status nginx
```

### 4-2. TCP 443ポートの穴あけ

firewalldで443/tcpへの外部からのアクセスを許可します

```shell-session:firewalld設定
$ sudo firewall-cmd --add-port=443/tcp --zone=public --permanent
success
$ sudo firewall-cmd --reload
success
```

### 4-3. コンテンツファイルを設置

適当なファイルを設置します

```shell-session:nginx.html
$ sudo ex /usr/share/nginx/html/nginx.html
Entering Ex mode.  Type "visual" to go to Normal mode.
:a
nginx
.
:wq
```

## 5. nginxへのアクセスと、鍵交換の確認

Google Chrome または Microsoft Edge など、検証できるブラウザでアクセスします

デベロッパーツールで、「Privacy and security」を確認し、「Key exchange」が「X25519MLKEM768」となっていればOKです

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3813346/c58ec70d-956e-4480-954d-cb49046b14b6.png)


# Apache httpdを、PQCハイブリッド鍵交換(X25519MLKEM768)に対応させる

## 1. Apache httpdをインストール

Apache httpdとTLS用のモジュールをインストールします

```shell-session:Apache httpdのインストール
$ sudo dnf -y install httpd mod_ssl
```

## 2. Apache httpdの設定

ssl.confを編集します

```shell-session:ssl.conf設定
$ sudo sed -i -e 's/^#ServerName /ServerName /' /etc/httpd/conf.d/ssl.conf
```

ssl.conf設定の主要な内容は以下のとおりです

```apache:/etc/httpd/conf.d/ssl.conf
Listen 443 https

<VirtualHost _default_:443>

ServerName www.example.com:443

SSLEngine on

SSLCipherSuite PROFILE=SYSTEM
SSLProxyCipherSuite PROFILE=SYSTEM

SSLCertificateFile /etc/pki/tls/certs/localhost.crt
SSLCertificateKeyFile /etc/pki/tls/private/localhost.key

</VirtualHost>
```


## 3. TLS証明書等の作成

TLS証明書とそれに紐づく秘密鍵を生成します
それぞれのファイルの場所は、前述のnginx.confに記載しているとおりです

| ファイル | ファイルの場所 |
|:-:|:-|
| 秘密鍵 | /etc/pki/tls/private/localhost.key |
| 証明書 | /etc/pki/tls/certs/localhost.crt |

秘密鍵と証明書の生成方法は、ネット上にいくらでもあります
例えば、下記の拙記事にも記載しています

https://qiita.com/exit0/items/0391173bd69b1e2219ff

### 3-1. 秘密鍵と証明書の作成

```shell-session:秘密鍵と証明書の作成
KEY=/etc/pki/tls/private/localhost.key
CERT=/etc/pki/tls/certs/localhost.crt
$ sudo mkdir -p /etc/pki/tls/private
$ sudo mkdir -p /etc/pki/tls/certs
$ sudo openssl genpkey -out "${KEY}" \
> -algorithm EC \
> -pkeyopt ec_paramgen_curve:P-256
$ sudo openssl req -new -x509 -days 365 \
> -key "${KEY}" -out "${CERT}" \
> -subj "/C=JP/L=Tokyo/O=Example Ltd/CN=www.example.com" \
> -addext "subjectAltName = DNS:www.example.com, DNS:example.com"
```

## 4. Apache httpdを起動

### 4-1. httpd起動

httpdを起動させます

```shell-session:httpd起動
$ sudo systemctl start httpd
$ systemctl status httpd
```

### 4-2. TCP 443ポートの穴あけ

firewalldで443/tcpへの外部からのアクセスを許可します

```shell-session:firewalld設定
$ sudo firewall-cmd --add-port=443/tcp --zone=public --permanent
success
$ sudo firewall-cmd --reload
success
```

### 4-3. コンテンツファイルを設置

適当なファイルを設置します

```shell-session:nginx.html
$ sudo ex /var/www/html/httpd.html
Entering Ex mode.  Type "visual" to go to Normal mode.
:a
Apache httpd
.
:wq
```

## 5. Apache httpdへのアクセスと、鍵交換の確認

Google Chrome または Microsoft Edge など、検証できるブラウザでアクセスします

デベロッパーツールで、「Privacy and security」を確認し、「Key exchange」が「X25519MLKEM768」となっていればOKです

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3813346/03c5c08b-9b75-49c4-9351-f1922b785f8c.png)

# おしまい

# フッター

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

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

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