GA になった Amazon Corretto 27 でポスト量子鍵交換を試してみた
はじめに
2026年9月17日、Amazon Corretto 27 が公開されました。
OpenJDK 27 は 2026年9月15日に GA し、2日後の公開です。
本記事では、Corretto 27 の TLS 1.3 で、ポスト量子ハイブリッド鍵交換が選択されることを、ローカル Docker 上の JDK デバッグログで確認しました。
Corretto 27 の主な特徴
同発表では、主な特徴として次が挙げられています。
- すべての環境で G1 をデフォルト GC にする変更(JEP 523)
- TLS 1.3 のポスト量子ハイブリッド鍵交換(JEP 527)
- コンパクトオブジェクトヘッダーのデフォルト有効化(JEP 534)
- JFR のプロセス内データマスキング(JEP 536)
- 拡張パターンマッチング、構造化並行性、遅延定数の継続プレビュー(JEP 532、JEP 533、JEP 531)
- Vector API の継続インキュベータ(JEP 537)
検証環境
検証に使用したホストのアーキテクチャは aarch64 です。JDK と OpenSSL はどちらもコンテナ内に閉じているため、ホストへのインストールは不要です。今回の実測は aarch64 ホストで行いました。
クライアントは、debian:bookworm-slim に Corretto 27 の latest 版をダウンロードして展開したイメージです。取得日(2026年9月17日)時点のバージョンは次のとおりでした。
openjdk version "27" 2026-09-15
OpenJDK Runtime Environment Corretto-27.0.0.35.1 (build 27+35-FR)
OpenJDK 64-Bit Server VM Corretto-27.0.0.35.1 (build 27+35-FR, mixed mode, sharing)
サーバーは debian:trixie-slim の OpenSSL 3.5.7 です。OpenSSL 3.5.0 の公式変更履歴では、X25519MLKEM768 を含む TLS ハイブリッド鍵共有方式が追加されたと記載されています。
検証手順
compose.yml、Dockerfile.server、Dockerfile.client、PqTlsCheck.java を同じディレクトリに置いて実行します(以下この順に掲載します)。
全体構成(compose.yml)
services:
tls-server:
build:
context: .
dockerfile: Dockerfile.server
container_name: pq-tls-server
networks:
- pq-net
logging:
driver: "json-file"
tls-client:
build:
context: .
dockerfile: Dockerfile.client
container_name: pq-tls-client
depends_on:
- tls-server
networks:
- pq-net
# サーバー起動待ち + JDK ハンドシェイクデバッグ付きで実行
entrypoint:
- sh
- -c
- |
sleep 2
# 本番でも有効にしておくことが推奨される設定
exec java \
-Djavax.net.debug=ssl:handshake \
-Dcom.sun.jndi.ldap.object.trustURLCodebase=false \
-cp /app \
PqTlsCheck tls-server 4433
logging:
driver: "json-file"
networks:
pq-net:
driver: bridge
OpenSSL サーバーの起動
サーバー側はイメージのビルド時に自己署名証明書を生成し、openssl s_server を TLS 1.3 のみ・-trace 付きで起動します。
Dockerfile.server
FROM debian:trixie-slim
RUN apt-get update && apt-get install -y --no-install-recommends \
openssl \
ca-certificates \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /certs
# 自己署名サーバー証明書を生成(CA は作らず1枚で完結)
RUN openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:P-256 \
-keyout server.key -out server.crt -days 1 -nodes \
-subj "/CN=tls-server" \
-addext "subjectAltName=DNS:tls-server,IP:127.0.0.1"
EXPOSE 4433
# -trace: ハンドシェイク詳細(named group 含む)を stderr へ出力
CMD ["openssl", "s_server", \
"-key", "/certs/server.key", \
"-cert", "/certs/server.crt", \
"-accept", "4433", \
"-tls1_3", \
"-trace", \
"-www"]
Corretto 27 クライアントの実行
クライアントは Corretto 27 を取得し、ビルド時に javac まで実行したイメージです。
Dockerfile.client
FROM debian:bookworm-slim
RUN apt-get update && apt-get install -y --no-install-recommends \
curl ca-certificates \
&& rm -rf /var/lib/apt/lists/*
# Corretto 27 - アーキテクチャ自動判別
ARG TARGETARCH
RUN case "${TARGETARCH}" in \
amd64) JDK_URL="https://corretto.aws/downloads/latest/amazon-corretto-27-x64-linux-jdk.tar.gz" ;; \
arm64) JDK_URL="https://corretto.aws/downloads/latest/amazon-corretto-27-aarch64-linux-jdk.tar.gz" ;; \
*) echo "Unsupported arch: ${TARGETARCH}" && exit 1 ;; \
esac \
&& curl -fsSL "${JDK_URL}" | tar -xz -C /opt \
&& ln -s /opt/amazon-corretto-27* /opt/java
ENV JAVA_HOME=/opt/java
ENV PATH="${JAVA_HOME}/bin:${PATH}"
WORKDIR /app
COPY PqTlsCheck.java .
RUN javac PqTlsCheck.java
# -Djavax.net.debug=ssl:handshake でハンドシェイクログ全出力
# サーバー証明書検証は無効(自己署名のため)
CMD ["java", \
"-Djavax.net.debug=ssl:handshake", \
"-Dcom.sun.jndi.ldap.object.trustURLCodebase=false", \
"PqTlsCheck", "tls-server", "4433"]
クライアントのアプリケーションは SSLSocket で TLS 1.3 接続を確立し、セッション情報を出力する短いプログラムです。
PqTlsCheck.java
自己署名証明書のための検証用実装です。証明書検証を無効にしているため、本番では使用しないでください。
import javax.net.ssl.*;
import java.io.*;
import java.security.cert.X509Certificate;
/**
* Corretto 27 の PQ TLS ハンドシェイク確認ツール。
* 接続先サーバーと TLS 1.3 ネゴシエーションを行い、
* 選択された cipher suite / named group をログに出力する。
*
* 証明書検証を無効にした TrustManager を使用 (自己署名証明書対応)。
* 本番環境ではこの TrustManager を使わず、JDK 既定の TrustManager(証明書検証あり)とホスト名検証を有効にすること。
*/
public class PqTlsCheck {
public static void main(String[] args) throws Exception {
String host = args.length > 0 ? args[0] : "localhost";
int port = args.length > 1 ? Integer.parseInt(args[1]) : 4433;
System.out.println("=== Corretto 27 PQ TLS Check ===");
System.out.println("Target: " + host + ":" + port);
System.out.println("Java version: " + System.getProperty("java.version"));
System.out.println("Java vendor: " + System.getProperty("java.vendor"));
System.out.println();
// 自己署名証明書を許容する TrustManager(検証用のみ)
TrustManager[] trustAll = new TrustManager[]{
new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] c, String a) {}
public void checkServerTrusted(X509Certificate[] c, String a) {}
public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; }
}
};
SSLContext ctx = SSLContext.getInstance("TLS");
ctx.init(null, trustAll, null);
SSLSocketFactory factory = ctx.getSocketFactory();
try (SSLSocket socket = (SSLSocket) factory.createSocket(host, port)) {
socket.setEnabledProtocols(new String[]{"TLSv1.3"});
// 明示設定していないため null が返る(JDK デフォルトが適用される)
SSLParameters params = socket.getSSLParameters();
String[] namedGroups = params.getNamedGroups();
System.out.println("--- Named Groups (client preference order) ---");
if (namedGroups != null) {
for (int i = 0; i < namedGroups.length; i++) {
System.out.printf(" [%d] %s%n", i, namedGroups[i]);
}
} else {
System.out.println(" (not set explicitly — JDK default applies)");
}
System.out.println();
// ハンドシェイク実行(ssl:handshake デバッグログは JVM が出力)
socket.startHandshake();
SSLSession session = socket.getSession();
System.out.println("--- TLS Session ---");
System.out.println("Protocol: " + session.getProtocol());
System.out.println("CipherSuite: " + session.getCipherSuite());
System.out.println("PeerHost: " + session.getPeerHost());
System.out.println();
System.out.println("SUCCESS: TLS handshake completed.");
}
}
}
サーバーを起動してからクライアントを実行します。
docker compose up -d tls-server && docker compose run --rm tls-client
確認が終わったら、ローカルにビルドされたイメージもあわせて削除します。
docker compose down --rmi local
ハンドシェイクの確認
-Djavax.net.debug=ssl:handshake を付けているため、クライアントの標準エラー出力に ClientHello と ServerHello の内容が出力されます。まず、ClientHello の supported_groups 拡張を確認します。
"supported_groups (10)": {
"named groups": [X25519MLKEM768, x25519, secp256r1, secp384r1, secp521r1, x448, ffdhe2048, ffdhe3072, ffdhe4096]
},
PqTlsCheck.java では named groups を一切設定していないため、これは Corretto 27 のデフォルトの優先順です。JEP 527 に記載されている、X25519MLKEM768 を先頭に置く挙動を、コードを変更せずに確認できました。
続いて ServerHello の key_share です。
"key_share (51)": {
"server_share": {
"named group": X25519MLKEM768
...
OpenSSL 3.5.7 のサーバーが X25519MLKEM768 を選び、ハイブリッド鍵交換でハンドシェイクが成立しました。JDK のデバッグログには TLS 1.3 でのネゴシエーション完了が記録されています。
Negotiated protocol version: TLSv1.3
アプリケーションの標準出力は次のとおりです。
--- TLS Session ---
Protocol: TLSv1.3
CipherSuite: TLS_AES_256_GCM_SHA384
PeerHost: tls-server
SUCCESS: TLS handshake completed.
まとめ
Amazon Corretto 27 の一般提供開始に合わせ、ローカル Docker 環境で TLS 1.3 のポスト量子ハイブリッド鍵交換 X25519MLKEM768 が選択されることを確認しました。
Amazon S3 や Elastic Load Balancing(ALB/NLB)などの主要な AWS サービスでは、2025 年から PQC をサポートするようになりました。
また、2026 年9月にリリースされた Aurora MySQL 8.4.8 も PQC をサポートしました。
量子コンピュータの性能向上により、2030 年代半ばには RSA 暗号や楕円曲線暗号(ECC)など、現在広く使われている公開鍵暗号が解読されるリスクが指摘されています(NISC 中間取りまとめ、2025年11月20日)。
いわゆる「2035年問題」への備えとして、PQC 対応の JDK である Corretto 27 を評価してみてください。
ただし、Corretto 27 は Feature Release 版であり、サポートは 2027年4月までです。将来のアップデートや LTS 版への移行を前提に利用してください。







