AWS Private CA で量子耐性証明書を発行してみた
はじめに
AWS Private CA で CA を作成するとき、キーアルゴリズムの指定が求められます。
現在提供されているアルゴリズム (RSA 2048 以上、ECDSA P256 以上) は現時点で安全ですが、「暗号の2030年問題」への対応が必要です。2030年問題とは、NIST が RSA 2048 の使用期限を2030年までとしていることに加え、2030年頃に量子コンピュータによる暗号解読の可能性が指摘されている問題です。
CA の秘密鍵が漏洩または将来解読された場合、偽造証明書による中間者攻撃などの重大なインシデントに繋がる可能性があります。
CA を長期運用する場合はキーアルゴリズムについても考慮が必要となってくるのです。
キーアルゴリズムとビットセキュリティ
暗号の安全性を測る指標として用いられているのがビットセキュリティです。2031年以降は 128 ビットセキュリティ以上の利用が推奨されています。
以下は、Private CA 作成時に選択できるキーアルゴリズムとビットセキュリティになります。
| キーアルゴリズム | ビットセキュリティ |
|---|---|
| RSA 2048 | 112 |
| RSA 3072 | 128 |
| RSA 4096 | 152 |
| ECDSA P256 | 128 |
| ECDSA P384 | 192 |
| ECDSA P521 | 256 |
今から作成する場合は、128ビットセキュリティ以上の強度を持つキーアルゴリズムを選択するのが良さそうです。
ポスト量子暗号
というのがこれまでの意思決定フローだったのですが、先日、ポスト量子暗号がサポートされるようになりました。
ポスト量子暗号については、ワークショップがあったり、
CloudFront でサポートされていたり、
と、ホットなワードだったりもします。
AWS Private CA で利用可能なキーアルゴリズムは以下の通りです。
- ML-DSA-44
- ML-DSA-65
- ML-DSA-87
早速試してみましょう。
準備
今回は ML-DSA-44 を選択してみました。

次にエンドエンティティ証明書を発行するために CSR と秘密鍵を作成します。秘密鍵のアルゴリズムも ML-DSA-44 にしてみましょう。証明書チェーン全体が量子耐性のある構成にしてみます。
$ openssl req -out csr.pem -new -newkey ml-dsa-44 -nodes -keyout private-key.pem
-----
Country Name (2 letter code) [AU]:US
State or Province Name (full name) [Some-State]:WA
Locality Name (eg, city) []:Seattle
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Example Corp
Organizational Unit Name (eg, section) []:Sales
Common Name (e.g. server FQDN or YOUR name) []:private.example.com
続いて、証明書を発行します。署名アルゴリズムは同じく ML-DSA-44 です。
aws acm-pca issue-certificate \
--certificate-authority-arn arn:aws:acm-pca:ap-northeast-1:222222222222:certificate-authority/hoge \
--csr fileb://csr.pem \
--signing-algorithm "ML_DSA_44" \
--validity Value=10,Type="YEARS"
取得は aws acm-pca get-certificate コマンドで。
検証
前回記事と同様のサーバを構築しておきます。
リクエストですが、私のデフォルト curl (厳密には LibreSSL) では ML-DSA-44 が実装されていないようでした。
試しに、ML-DSA-44 で鍵を生成しようとすると、
$ /usr/bin/openssl version && /usr/bin/openssl genpkey -algorithm ML-DSA-44 2>&1 | head -1
LibreSSL 3.3.6
Algorithm ML-DSA-44 not found
というように、そんなアルゴリズムは知らないよ、と怒られてしまいます。
なので、今回は brew でインストールした OpenSSL 版の curl を利用します。
% /opt/homebrew/bin/openssl version && openssl genpkey -algorithm ml-dsa-44 2>&1 | head -1
OpenSSL 3.6.0 1 Oct 2025 (Library: OpenSSL 3.6.0 1 Oct 2025)
-----BEGIN PRIVATE KEY-----
良い感じです!
早速リクエストしてみましょう。
$ /opt/homebrew/Cellar/curl/8.17.0/bin/curl -V | grep OpenSSL
curl 8.17.0 (aarch64-apple-darwin24.4.0) libcurl/8.17.0 OpenSSL/3.6.0 zlib/1.2.12 brotli/1.2.0 zstd/1.5.7 AppleIDN libssh2/1.11.1 nghttp2/1.68.0 ngtcp2/1.18.0 nghttp3/1.13.1 librtmp/2.3 mit-krb5/1.7-prerelease
$ /opt/homebrew/Cellar/curl/8.17.0/bin/curl -Iv --cacert ca.crt --resolve private.example.com:8443:127.0.0.1 https://private.example.com:8443
* Added private.example.com:8443:127.0.0.1 to DNS cache
* Hostname private.example.com was found in DNS cache
* Trying 127.0.0.1:8443...
* ALPN: curl offers h2,http/1.1
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* SSL Trust Anchors:
* CAfile: ca.crt
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384 / X25519MLKEM768 / id-ml-dsa-44
* ALPN: server did not agree on a protocol. Uses default.
* Server certificate:
* subject: C=US; ST=WA; L=Seattle; O=Example Corp; OU=Sales; CN=private.example.com
* start date: Nov 25 02:52:51 2025 GMT
* expire date: Nov 25 03:52:51 2035 GMT
* issuer: C=US; O=Example Corp; OU=Sales; ST=WA; CN=root.example.com; L=Seattle
* Certificate level 0: Public key type ML-DSA-44 (10496/128 Bits/secBits), signed using ML-DSA-44
* Certificate level 1: Public key type ML-DSA-44 (10496/128 Bits/secBits), signed using ML-DSA-44
* common name: private.example.com (matched)
* SSL certificate verified via OpenSSL.
* Established connection to private.example.com (127.0.0.1 port 8443) from 127.0.0.1 port 61096
* using HTTP/1.x
> HEAD / HTTP/1.1
> Host: private.example.com:8443
> User-Agent: curl/8.17.0
> Accept: */*
>
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* Request completely sent off
* HTTP 1.0, assume close after body
< HTTP/1.0 200 OK
HTTP/1.0 200 OK
< Server: SimpleHTTP/0.6 Python/3.12.7
Server: SimpleHTTP/0.6 Python/3.12.7
< Date: Wed, 26 Nov 2025 00:33:39 GMT
Date: Wed, 26 Nov 2025 00:33:39 GMT
< Content-type: text/html; charset=utf-8
Content-type: text/html; charset=utf-8
< Content-Length: 406
Content-Length: 406
<
* shutting down connection #0
バッチリですね!
まとめ
これからは全てポスト量子暗号アルゴリズムを使えば良いのか、と思ってしまいそうですがそうでもありません。
というのも、現状においては一般的なブラウザが対応していないので、Web サイトで利用するのはかなりハードルが高いのです。
M2M などの限られた環境にのみ使うもの、という理解で良いと思います。
2030年問題はもちろん、量子コンピュータの登場ももうまもなくという感じです。改めて、キーアルゴリズムについて見直すのも良いでしょう。






