これは、なにをしたくて書いたもの?
使用しているJava環境でサポートしているSSL/TLSプロトコルや、暗号スイートを確認したいなと思いまして。
特にこれを書こうと思ったきっかけはSSLSocketFactory#getSupportedCipherSuites
とSSLSocketFactory#getDefaultCipherSuites
の
違いがよくわからなかったからです。
JSSEでのプロトコルや暗号スイートの設定に関するドキュメントを見る
この話で見るべきドキュメントはJSSE(Java Secure Socket Extension)のものでしょうね。
Java Secure Socket Extension (JSSE)リファレンス・ガイド
ドキュメント上は、以下のプロトコルをサポートしていることになっています。
- DTLSv1.0、1.2
- TLSv1.0、1.1、1.2、1.3
- SSLv3.0
Java Secure Socket Extension (JSSE)リファレンス・ガイド / JSSEの概要
とはいえ、実際にはjava.security
ファイルのjdk.tls.disabledAlgorithms
セキュリティプロパティーで無効にされているプロトコルがあります。
Java Secure Socket Extension (JSSE)リファレンス・ガイド / JSSEクラスとインタフェース / サポート・クラスとインタフェース
また、SSL/TLS通信時に利用できる暗号スイートはJSSEプロバイダーによって決まっていますが、さらにシステムプロパティや
アプリケーション内でカスタマイズできます。
デフォルトで有効な暗号化方式群は、アプリケーション内で、またはシステム・プロパティjdk.tls.client.cipherSuitesとjdk.tls.server.cipherSuitesを使用して指定できます。
Java Secure Socket Extension (JSSE)リファレンス・ガイド / JSSEのカスタマイズ / デフォルトで有効な暗号化方式群の指定
優先順位は以下のようです。
デフォルトで有効化する暗号化方式群のセットは、この優先度順に従い、次のいずれかの方法で決定されます。
- アプリケーションによる明示的な設定
- システム・プロパティによる指定
- JSSEプロバイダのデフォルトによる指定
たとえば、デフォルトで有効な暗号化方式群をアプリケーション内で明示的に設定すると、これにより、jdk.tls.client.cipherSuitesまたはjdk.tls.server.cipherSuitesおよびJSSEプロバイダのデフォルトで指定された設定がオーバーライドされます。
アプリケーションでの明示的な指定は、以下を指しています。
SSLSocket#setEnabledCipherSuites
SSLEngine#setEnabledCipherSuites
SSLServerSocket#setEnabledCipherSuites
SSLParameters
のコンストラクターによる指定HttpsURLConnection
のhttps.cipherSuites
システム・プロパティ
システムプロパティーでもいろいろカスタマイズできるんですね。
設定できるセキュリティプロパティーおよびシステムプロパティーの一覧は以下に記載されています。
Java Secure Socket Extension (JSSE)リファレンス・ガイド / JSSEのカスタマイズ
SSLContext、SSLSocketFactoryのSupported〜とDefault〜の違い
ところで、SSLContext
にはgetSupportedSSLParameters
とgetDefaultSSLParameters
、SSLSocketFactory
とSSLServerSocketFactory
には
それぞれgetSupportedCipherSuites
とgetDefaultCipherSuites
と似たような名前のメソッドがあります。
※SSLContext#getSupportedSSLParameters
またはSSLContext
getDefaultSSLParametersから取得できる
SSLParameters`からプロトコルの情報を取得できます
SSLContext (Java SE 21 & JDK 21)
SSLSocketFactory (Java SE 21 & JDK 21)
SSLServerSocketFactory (Java SE 21 & JDK 21)
この違いはなんだろうと思っていたのですが、SSLSocketFactory
のJavadocを見ると意味がわかります。
getSupportedCipherSuites
SSL接続で使用可能にできる暗号化方式群の名前を返します。 通常は、その一部のみがデフォルトで使用可能になります。デフォルトのサービス品質要件を満たしていない暗号化方式群は、使用不可になります。 それらの暗号化方式群は、特殊なアプリケーションで使用します。getDefaultCipherSuites
デフォルトで使用可能になっている暗号化方式群のリストを返します。 別のリストが使用可能になっていないかぎり、SSL接続のハンドシェークではこの暗号化方式群のいずれかが使用されます。 デフォルトの暗号化方式群を使用するとき、最小限のサービス品質を保証するには、機密性保護とサーバー認証が必要です(つまり、匿名の暗号化方式群は使用できない)。
なので、プロバイダーでサポートしている範囲がgetSupported〜
で表現され、実際に使えるものがgetDefault〜
で返されるようです。
つまり、getSupported〜
よりもgetDefault〜
の方が少なくなることがあるということです。
実行環境で実際に使える情報を見たい場合は、getDefault〜
の方を使った方がよさそうですね。
SSLSocketFactory
やSSLServerSocketFactory
の実装を見ると、getDefault〜
の方はクライアント用途なのかサーバー用途なのかといった
ロールに合わせたフィルタリングをしていることも確認できます。
/** * Returns the subset of the supported cipher suites which are * enabled by default. These cipher suites all provide a minimum * quality of service whereby the server authenticates itself * (preventing person-in-the-middle attacks) and where traffic * is encrypted to provide confidentiality. */ @Override public String[] getDefaultCipherSuites() { return CipherSuite.namesOf(context.getDefaultCipherSuites(false)); } /** * Returns the names of the cipher suites which could be enabled for use * on an SSL connection. Normally, only a subset of these will actually * be enabled by default, since this list may include cipher suites which * do not support the mutual authentication of servers and clients, or * which do not protect data confidentiality. Servers may also need * certain kinds of certificates to use certain cipher suites. */ @Override public String[] getSupportedCipherSuites() { return CipherSuite.namesOf(context.getSupportedCipherSuites()); }
/** * Returns the subset of the supported cipher suites which are * enabled by default. These cipher suites all provide a minimum * quality of service whereby the server authenticates itself * (preventing person-in-the-middle attacks) and where traffic * is encrypted to provide confidentiality. */ @Override public String[] getDefaultCipherSuites() { return CipherSuite.namesOf(context.getDefaultCipherSuites(true)); } /** * Returns the names of the cipher suites which could be enabled for use * on an SSL connection. Normally, only a subset of these will actually * be enabled by default, since this list may include cipher suites which * do not support the mutual authentication of servers and clients, or * which do not protect data confidentiality. Servers may also need * certain kinds of certificates to use certain cipher suites. * * @return an array of cipher suite names */ @Override public String[] getSupportedCipherSuites() { return CipherSuite.namesOf(context.getSupportedCipherSuites()); }
こちらですね。
// SSLSocketFactoryImpl @Override public String[] getDefaultCipherSuites() { return CipherSuite.namesOf(context.getDefaultCipherSuites(false)); } // SSLServerSocketFactoryImpl @Override public String[] getDefaultCipherSuites() { return CipherSuite.namesOf(context.getDefaultCipherSuites(true)); }
この後、さらにSSLSocket#setEnabledCipherSuites
などで使用する暗号スイートを絞り込んだりできるわけですが。
今回、SSLContext
やSSLSocketFactory
から利用できるプロトコルや暗号スイートを確認しつつ、getSupported〜
やgetDefault〜
の
違いを見ていこうと思います。
環境
今回の環境はこちら。
$ java --version openjdk 21.0.2 2024-01-16 OpenJDK Runtime Environment (build 21.0.2+13-Ubuntu-122.04.1) OpenJDK 64-Bit Server VM (build 21.0.2+13-Ubuntu-122.04.1, mixed mode, sharing) $ mvn --version Apache Maven 3.9.7 (8b094c9513efc1b9ce2d952b3b9c8eaedaf8cbf0) Maven home: $HOME/.sdkman/candidates/maven/current Java version: 21.0.2, vendor: Private Build, runtime: /usr/lib/jvm/java-21-openjdk-amd64 Default locale: en, platform encoding: UTF-8 OS name: "linux", version: "5.15.0-107-generic", arch: "amd64", family: "unix"
java.securityファイルの内容を確認する
最初にjava.security
ファイルの内容を確認してみましょう。コメントを除外して確認。
$ grep -vE '^ *#' /usr/lib/jvm/java-21-openjdk-amd64/conf/security/java.security | grep -v '^$'
jdk.tls.disabledAlgorithms
セキュリティプロパティーは、このようになっていました。
jdk.tls.disabledAlgorithms=SSLv3, TLSv1, TLSv1.1, DTLSv1.0, RC4, DES, \ MD5withRSA, DH keySize < 1024, EC keySize < 224, 3DES_EDE_CBC, anon, NULL, \ ECDH
準備
それでは、動作確認を行うソースコードを書く準備をします。
Maven依存関係等はこちら。
<properties> <maven.compiler.release>21</maven.compiler.release> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> </properties> <dependencies> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter</artifactId> <version>5.10.2</version> <scope>test</scope> </dependency> <dependency> <groupId>org.assertj</groupId> <artifactId>assertj-core</artifactId> <version>3.26.0</version> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <artifactId>maven-surefire-plugin</artifactId> <version>3.1.2</version> </plugin> </plugins> </build>
動作確認はテストコードで行うことにします。その雛形はこちら。
src/test/java/org/littlewings/ssl/SslProtocolsTest.java
package org.littlewings.ssl; import org.junit.jupiter.api.Test; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLServerSocketFactory; import javax.net.ssl.SSLSocketFactory; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import static org.assertj.core.api.Assertions.assertThat; class SslProtocolsTest { // ここに、テストを書く }
以降では、テストコードを書いていきます。
サポートしているSSL/TLSプロトコルを確認する
まずはサポートしているSSL/TLSプロトコルを確認してみます。
最初はデフォルトのSSLContext
で確認してみます。このような結果になりました。
@Test void defaultContextSupportedProtocols() throws NoSuchAlgorithmException { SSLContext sslContext = SSLContext.getDefault(); assertThat(sslContext.getProtocol()).isEqualTo("Default"); assertThat(sslContext.getSupportedSSLParameters().getProtocols()).containsExactly( "TLSv1.3", "TLSv1.2", "TLSv1.1", "TLSv1", "SSLv3", "SSLv2Hello" ); assertThat(sslContext.getDefaultSSLParameters().getProtocols()).containsExactly( "TLSv1.3", "TLSv1.2" ); }
こう見ると、確かにプロバイダーで利用可能になっているのがgetSupported〜
、実際に利用できるのはgetDefault〜
を見るというのは
合っていそうです。
java.security
ファイルでSSLv3やTLSv1〜1.1までは無効になっていましたからね。
jdk.tls.disabledAlgorithms=SSLv3, TLSv1, TLSv1.1, DTLSv1.0, RC4, DES, \ MD5withRSA, DH keySize < 1024, EC keySize < 224, 3DES_EDE_CBC, anon, NULL, \ ECDH
明示的にTLSv1.3を指定して確認。
@Test void tls13ContextSupportedProtocols() throws NoSuchAlgorithmException, KeyManagementException { SSLContext sslContext = SSLContext.getInstance("TLSv1.3"); sslContext.init(null, null, new SecureRandom()); assertThat(sslContext.getProtocol()).isEqualTo("TLSv1.3"); assertThat(sslContext.getSupportedSSLParameters().getProtocols()).containsExactly( "TLSv1.3", "TLSv1.2", "TLSv1.1", "TLSv1", "SSLv3", "SSLv2Hello" ); assertThat(sslContext.getDefaultSSLParameters().getProtocols()).containsExactly( "TLSv1.3", "TLSv1.2" ); }
SSLContext#getProtocol
の結果が変わるくらいで、ここでgetSupported〜
とgetDefault〜
の差は出ませんでした。
サポートしている暗号スイートを確認する
次は、SSLSocketFactory
およびSSLServerSocketFactory
でサポートしている暗号スイートを確認してみます。
最初はデフォルトのSSLContext
からSSLSocketFactory
およびSSLServerSocketFactory
を作成して確認します。
@Test void defaultContextSupportedCipherSuites() throws NoSuchAlgorithmException { SSLContext sslContext = SSLContext.getDefault(); SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory(); assertThat(sslSocketFactory.getSupportedCipherSuites()).containsExactly( "TLS_AES_256_GCM_SHA384", "TLS_AES_128_GCM_SHA256", "TLS_CHACHA20_POLY1305_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", // 省略 "TLS_RSA_WITH_AES_256_CBC_SHA256", "TLS_RSA_WITH_AES_128_CBC_SHA256", "TLS_RSA_WITH_AES_256_CBC_SHA", "TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_EMPTY_RENEGOTIATION_INFO_SCSV" ); assertThat(sslSocketFactory.getDefaultCipherSuites()).containsExactly( "TLS_AES_256_GCM_SHA384", "TLS_AES_128_GCM_SHA256", "TLS_CHACHA20_POLY1305_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", // 省略 "TLS_RSA_WITH_AES_256_CBC_SHA256", "TLS_RSA_WITH_AES_128_CBC_SHA256", "TLS_RSA_WITH_AES_256_CBC_SHA", "TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_EMPTY_RENEGOTIATION_INFO_SCSV" ); assertThat(sslSocketFactory.getSupportedCipherSuites()) .containsExactly(sslSocketFactory.getDefaultCipherSuites()); assertThat(sslSocketFactory.getSupportedCipherSuites()).hasSize(37); assertThat(sslSocketFactory.getDefaultCipherSuites()).hasSize(37); SSLServerSocketFactory sslServerSocketFactory = sslContext.getServerSocketFactory(); assertThat(sslServerSocketFactory.getSupportedCipherSuites()).containsExactly( "TLS_AES_256_GCM_SHA384", "TLS_AES_128_GCM_SHA256", "TLS_CHACHA20_POLY1305_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", // 省略 "TLS_RSA_WITH_AES_256_CBC_SHA256", "TLS_RSA_WITH_AES_128_CBC_SHA256", "TLS_RSA_WITH_AES_256_CBC_SHA", "TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_EMPTY_RENEGOTIATION_INFO_SCSV" ); assertThat(sslServerSocketFactory.getDefaultCipherSuites()).containsExactly( "TLS_AES_256_GCM_SHA384", "TLS_AES_128_GCM_SHA256", "TLS_CHACHA20_POLY1305_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", // 省略 "TLS_RSA_WITH_AES_256_CBC_SHA256", "TLS_RSA_WITH_AES_128_CBC_SHA256", "TLS_RSA_WITH_AES_256_CBC_SHA", "TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_EMPTY_RENEGOTIATION_INFO_SCSV" ); assertThat(sslServerSocketFactory.getSupportedCipherSuites()) .containsExactly(sslServerSocketFactory.getDefaultCipherSuites()); assertThat(sslServerSocketFactory.getSupportedCipherSuites()).hasSize(37); assertThat(sslServerSocketFactory.getDefaultCipherSuites()).hasSize(37); assertThat(sslSocketFactory.getSupportedCipherSuites()) .isEqualTo(sslServerSocketFactory.getSupportedCipherSuites()); assertThat(sslSocketFactory.getDefaultCipherSuites()) .isEqualTo(sslServerSocketFactory.getDefaultCipherSuites()); }
暗号スイートを全部並べると長いので、途中は省略します。
デフォルトのSSLContext
から得られたSSLSocketFactory
とSSLServerSocketFactory
では、getSupportedCipherSuites
と
getDefaultCipherSuites
結果が同じでした。クライアント用、サーバー用をまたいで比較しても同じでしたね。
なので、この結果としてはサポートしている暗号スイートと利用できるようになっている暗号スイートが同じということです。
次に、TLSv1.2として作成したSSLContext
で試してみます。
@Test void tls12ContextSupportedCipherSuites() throws NoSuchAlgorithmException, KeyManagementException { SSLContext sslContext = SSLContext.getInstance("TLSv1.2"); sslContext.init(null, null, new SecureRandom()); SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory(); assertThat(sslSocketFactory.getSupportedCipherSuites()).containsExactly( "TLS_AES_256_GCM_SHA384", "TLS_AES_128_GCM_SHA256", "TLS_CHACHA20_POLY1305_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", // 省略 "TLS_RSA_WITH_AES_256_CBC_SHA256", "TLS_RSA_WITH_AES_128_CBC_SHA256", "TLS_RSA_WITH_AES_256_CBC_SHA", "TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_EMPTY_RENEGOTIATION_INFO_SCSV" ); assertThat(sslSocketFactory.getDefaultCipherSuites()).containsExactly( "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", // 省略 "TLS_RSA_WITH_AES_256_CBC_SHA256", "TLS_RSA_WITH_AES_128_CBC_SHA256", "TLS_RSA_WITH_AES_256_CBC_SHA", "TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_EMPTY_RENEGOTIATION_INFO_SCSV" ); // 異なる assertThat(sslSocketFactory.getSupportedCipherSuites()) .isNotEqualTo(sslSocketFactory.getDefaultCipherSuites()); assertThat(sslSocketFactory.getSupportedCipherSuites()).hasSize(37); assertThat(sslSocketFactory.getDefaultCipherSuites()).hasSize(34); SSLServerSocketFactory sslServerSocketFactory = sslContext.getServerSocketFactory(); assertThat(sslServerSocketFactory.getSupportedCipherSuites()).containsExactly( "TLS_AES_256_GCM_SHA384", "TLS_AES_128_GCM_SHA256", "TLS_CHACHA20_POLY1305_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", // 省略 "TLS_RSA_WITH_AES_256_CBC_SHA256", "TLS_RSA_WITH_AES_128_CBC_SHA256", "TLS_RSA_WITH_AES_256_CBC_SHA", "TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_EMPTY_RENEGOTIATION_INFO_SCSV" ); assertThat(sslServerSocketFactory.getDefaultCipherSuites()).containsExactly( "TLS_AES_256_GCM_SHA384", "TLS_AES_128_GCM_SHA256", "TLS_CHACHA20_POLY1305_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", // 省略 "TLS_RSA_WITH_AES_256_CBC_SHA256", "TLS_RSA_WITH_AES_128_CBC_SHA256", "TLS_RSA_WITH_AES_256_CBC_SHA", "TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_EMPTY_RENEGOTIATION_INFO_SCSV" ); assertThat(sslServerSocketFactory.getSupportedCipherSuites()) .containsExactly(sslServerSocketFactory.getDefaultCipherSuites()); assertThat(sslServerSocketFactory.getDefaultCipherSuites()).hasSize(37); assertThat(sslServerSocketFactory.getSupportedCipherSuites()).hasSize(37); assertThat(sslSocketFactory.getSupportedCipherSuites()) .isEqualTo(sslServerSocketFactory.getSupportedCipherSuites()); // 異なる assertThat(sslSocketFactory.getDefaultCipherSuites()) .isNotEqualTo(sslServerSocketFactory.getDefaultCipherSuites()); }
こちらはSSLSocketFactory
、つまりクライアント側でgetSupportedCipherSuites
とgetDefaultCipherSuites
の結果が異なりましたね。
getDefaultCipherSuites
の方が数が少なくなりました。
// 異なる assertThat(sslSocketFactory.getSupportedCipherSuites()) .isNotEqualTo(sslSocketFactory.getDefaultCipherSuites()); assertThat(sslSocketFactory.getSupportedCipherSuites()).hasSize(37); assertThat(sslSocketFactory.getDefaultCipherSuites()).hasSize(34);
サーバー側であるSSLServerSocketFactory
ではgetSupportedCipherSuites
とgetDefaultCipherSuites
の結果は同じですが、クライアント側と
サーバー側で利用できる暗号スイートが異なることになります。
というわけで、最初に仮定した実行環境で実際に使える情報を見たい場合は、getDefault〜
の方を使った方がよさそうという考え方は
合っていそうなことが確認できました。
jdk.tls.client.cipherSuitesおよびjdk.tls.server.cipherSuitesシステムプロパティーを設定する
最後にjdk.tls.client.cipherSuites
およびjdk.tls.server.cipherSuites
を設定して確認してみましょう。
jdk.tls.disabledAlgorithms
がセキュリティプロパティーだったのに対して、jdk.tls.client.cipherSuites
とjdk.tls.server.cipherSuites
は
システムプロパティーです。
これらのシステムプロパティーで、クライアント側またはサーバー側で利用できる暗号スイートを限定することができます。
確認に使用したテストコードはこちら。
src/test/java/org/littlewings/ssl/SslLimitedCipherSuitesTest.java
package org.littlewings.ssl; import org.junit.jupiter.api.Test; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLServerSocketFactory; import javax.net.ssl.SSLSocketFactory; import java.security.NoSuchAlgorithmException; import static org.assertj.core.api.Assertions.assertThat; class SslLimitedCipherSuitesTest { @Test void cipherSuites() throws NoSuchAlgorithmException { System.setProperty("jdk.tls.client.cipherSuites", "TLS_AES_256_GCM_SHA384,TLS_AES_128_GCM_SHA256"); System.setProperty("jdk.tls.server.cipherSuites", "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"); SSLContext sslContext = SSLContext.getDefault(); SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory(); assertThat(sslSocketFactory.getSupportedCipherSuites()).containsExactly( "TLS_AES_256_GCM_SHA384", "TLS_AES_128_GCM_SHA256", "TLS_CHACHA20_POLY1305_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256", "TLS_DHE_DSS_WITH_AES_256_GCM_SHA384", "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256", "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256", "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256", "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "TLS_DHE_RSA_WITH_AES_256_CBC_SHA", "TLS_DHE_DSS_WITH_AES_256_CBC_SHA", "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", "TLS_DHE_DSS_WITH_AES_128_CBC_SHA", "TLS_RSA_WITH_AES_256_GCM_SHA384", "TLS_RSA_WITH_AES_128_GCM_SHA256", "TLS_RSA_WITH_AES_256_CBC_SHA256", "TLS_RSA_WITH_AES_128_CBC_SHA256", "TLS_RSA_WITH_AES_256_CBC_SHA", "TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_EMPTY_RENEGOTIATION_INFO_SCSV" ); assertThat(sslSocketFactory.getDefaultCipherSuites()).containsExactly( "TLS_AES_256_GCM_SHA384", "TLS_AES_128_GCM_SHA256" ); assertThat(sslSocketFactory.getSupportedCipherSuites()) .isNotEqualTo(sslSocketFactory.getDefaultCipherSuites()); assertThat(sslSocketFactory.getSupportedCipherSuites()).hasSize(37); assertThat(sslSocketFactory.getDefaultCipherSuites()).hasSize(2); SSLServerSocketFactory sslServerSocketFactory = sslContext.getServerSocketFactory(); assertThat(sslServerSocketFactory.getSupportedCipherSuites()).containsExactly( "TLS_AES_256_GCM_SHA384", "TLS_AES_128_GCM_SHA256", "TLS_CHACHA20_POLY1305_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256", "TLS_DHE_DSS_WITH_AES_256_GCM_SHA384", "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256", "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256", "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256", "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "TLS_DHE_RSA_WITH_AES_256_CBC_SHA", "TLS_DHE_DSS_WITH_AES_256_CBC_SHA", "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", "TLS_DHE_DSS_WITH_AES_128_CBC_SHA", "TLS_RSA_WITH_AES_256_GCM_SHA384", "TLS_RSA_WITH_AES_128_GCM_SHA256", "TLS_RSA_WITH_AES_256_CBC_SHA256", "TLS_RSA_WITH_AES_128_CBC_SHA256", "TLS_RSA_WITH_AES_256_CBC_SHA", "TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_EMPTY_RENEGOTIATION_INFO_SCSV" ); assertThat(sslServerSocketFactory.getDefaultCipherSuites()).containsExactly( "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256" ); assertThat(sslServerSocketFactory.getSupportedCipherSuites()) .isNotEqualTo(sslServerSocketFactory.getDefaultCipherSuites()); assertThat(sslServerSocketFactory.getSupportedCipherSuites()).hasSize(37); assertThat(sslServerSocketFactory.getDefaultCipherSuites()).hasSize(2); assertThat(sslSocketFactory.getSupportedCipherSuites()) .isEqualTo(sslServerSocketFactory.getSupportedCipherSuites()); assertThat(sslSocketFactory.getDefaultCipherSuites()) .isNotEqualTo(sslServerSocketFactory.getDefaultCipherSuites()); } }
今回は、System#setProperty
で指定することにしました。クライアント側、サーバー側それぞれ別のものを指定しています。
System.setProperty("jdk.tls.client.cipherSuites", "TLS_AES_256_GCM_SHA384,TLS_AES_128_GCM_SHA256"); System.setProperty("jdk.tls.server.cipherSuites", "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256");
結果、getSupportedCipherSuites
は変わりませんがgetDefaultCipherSuites
で得られる暗号スイートはそれぞれのシステムプロパティーで
指定したものに限定されることになりました。
SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory(); assertThat(sslSocketFactory.getSupportedCipherSuites()).containsExactly( "TLS_AES_256_GCM_SHA384", "TLS_AES_128_GCM_SHA256", "TLS_CHACHA20_POLY1305_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256", "TLS_DHE_DSS_WITH_AES_256_GCM_SHA384", "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256", "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256", "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256", "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "TLS_DHE_RSA_WITH_AES_256_CBC_SHA", "TLS_DHE_DSS_WITH_AES_256_CBC_SHA", "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", "TLS_DHE_DSS_WITH_AES_128_CBC_SHA", "TLS_RSA_WITH_AES_256_GCM_SHA384", "TLS_RSA_WITH_AES_128_GCM_SHA256", "TLS_RSA_WITH_AES_256_CBC_SHA256", "TLS_RSA_WITH_AES_128_CBC_SHA256", "TLS_RSA_WITH_AES_256_CBC_SHA", "TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_EMPTY_RENEGOTIATION_INFO_SCSV" ); assertThat(sslSocketFactory.getDefaultCipherSuites()).containsExactly( "TLS_AES_256_GCM_SHA384", "TLS_AES_128_GCM_SHA256" ); assertThat(sslSocketFactory.getSupportedCipherSuites()) .isNotEqualTo(sslSocketFactory.getDefaultCipherSuites()); assertThat(sslSocketFactory.getSupportedCipherSuites()).hasSize(37); assertThat(sslSocketFactory.getDefaultCipherSuites()).hasSize(2); SSLServerSocketFactory sslServerSocketFactory = sslContext.getServerSocketFactory(); assertThat(sslServerSocketFactory.getSupportedCipherSuites()).containsExactly( "TLS_AES_256_GCM_SHA384", "TLS_AES_128_GCM_SHA256", "TLS_CHACHA20_POLY1305_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256", "TLS_DHE_DSS_WITH_AES_256_GCM_SHA384", "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256", "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256", "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256", "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "TLS_DHE_RSA_WITH_AES_256_CBC_SHA", "TLS_DHE_DSS_WITH_AES_256_CBC_SHA", "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", "TLS_DHE_DSS_WITH_AES_128_CBC_SHA", "TLS_RSA_WITH_AES_256_GCM_SHA384", "TLS_RSA_WITH_AES_128_GCM_SHA256", "TLS_RSA_WITH_AES_256_CBC_SHA256", "TLS_RSA_WITH_AES_128_CBC_SHA256", "TLS_RSA_WITH_AES_256_CBC_SHA", "TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_EMPTY_RENEGOTIATION_INFO_SCSV" ); assertThat(sslServerSocketFactory.getDefaultCipherSuites()).containsExactly( "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256" );
これでだいたい使い方はわかった感じですね。
オマケ
最後に、暗号スイートを列挙した箇所を省略していないソースコードを載せておきます。
src/test/java/org/littlewings/ssl/SslProtocolsTest.java
package org.littlewings.ssl; import org.junit.jupiter.api.Test; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLServerSocketFactory; import javax.net.ssl.SSLSocketFactory; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import static org.assertj.core.api.Assertions.assertThat; class SslProtocolsTest { @Test void defaultContextSupportedProtocols() throws NoSuchAlgorithmException { SSLContext sslContext = SSLContext.getDefault(); assertThat(sslContext.getProtocol()).isEqualTo("Default"); assertThat(sslContext.getSupportedSSLParameters().getProtocols()).containsExactly( "TLSv1.3", "TLSv1.2", "TLSv1.1", "TLSv1", "SSLv3", "SSLv2Hello" ); assertThat(sslContext.getDefaultSSLParameters().getProtocols()).containsExactly( "TLSv1.3", "TLSv1.2" ); } @Test void tls13ContextSupportedProtocols() throws NoSuchAlgorithmException, KeyManagementException { SSLContext sslContext = SSLContext.getInstance("TLSv1.3"); sslContext.init(null, null, new SecureRandom()); assertThat(sslContext.getProtocol()).isEqualTo("TLSv1.3"); assertThat(sslContext.getSupportedSSLParameters().getProtocols()).containsExactly( "TLSv1.3", "TLSv1.2", "TLSv1.1", "TLSv1", "SSLv3", "SSLv2Hello" ); assertThat(sslContext.getDefaultSSLParameters().getProtocols()).containsExactly( "TLSv1.3", "TLSv1.2" ); } @Test void defaultContextSupportedCipherSuites() throws NoSuchAlgorithmException { SSLContext sslContext = SSLContext.getDefault(); SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory(); assertThat(sslSocketFactory.getSupportedCipherSuites()).containsExactly( "TLS_AES_256_GCM_SHA384", "TLS_AES_128_GCM_SHA256", "TLS_CHACHA20_POLY1305_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256", "TLS_DHE_DSS_WITH_AES_256_GCM_SHA384", "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256", "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256", "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256", "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "TLS_DHE_RSA_WITH_AES_256_CBC_SHA", "TLS_DHE_DSS_WITH_AES_256_CBC_SHA", "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", "TLS_DHE_DSS_WITH_AES_128_CBC_SHA", "TLS_RSA_WITH_AES_256_GCM_SHA384", "TLS_RSA_WITH_AES_128_GCM_SHA256", "TLS_RSA_WITH_AES_256_CBC_SHA256", "TLS_RSA_WITH_AES_128_CBC_SHA256", "TLS_RSA_WITH_AES_256_CBC_SHA", "TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_EMPTY_RENEGOTIATION_INFO_SCSV" ); assertThat(sslSocketFactory.getDefaultCipherSuites()).containsExactly( "TLS_AES_256_GCM_SHA384", "TLS_AES_128_GCM_SHA256", "TLS_CHACHA20_POLY1305_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256", "TLS_DHE_DSS_WITH_AES_256_GCM_SHA384", "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256", "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256", "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256", "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "TLS_DHE_RSA_WITH_AES_256_CBC_SHA", "TLS_DHE_DSS_WITH_AES_256_CBC_SHA", "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", "TLS_DHE_DSS_WITH_AES_128_CBC_SHA", "TLS_RSA_WITH_AES_256_GCM_SHA384", "TLS_RSA_WITH_AES_128_GCM_SHA256", "TLS_RSA_WITH_AES_256_CBC_SHA256", "TLS_RSA_WITH_AES_128_CBC_SHA256", "TLS_RSA_WITH_AES_256_CBC_SHA", "TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_EMPTY_RENEGOTIATION_INFO_SCSV" ); assertThat(sslSocketFactory.getSupportedCipherSuites()) .containsExactly(sslSocketFactory.getDefaultCipherSuites()); assertThat(sslSocketFactory.getSupportedCipherSuites()).hasSize(37); assertThat(sslSocketFactory.getDefaultCipherSuites()).hasSize(37); SSLServerSocketFactory sslServerSocketFactory = sslContext.getServerSocketFactory(); assertThat(sslServerSocketFactory.getSupportedCipherSuites()).containsExactly( "TLS_AES_256_GCM_SHA384", "TLS_AES_128_GCM_SHA256", "TLS_CHACHA20_POLY1305_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256", "TLS_DHE_DSS_WITH_AES_256_GCM_SHA384", "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256", "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256", "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256", "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "TLS_DHE_RSA_WITH_AES_256_CBC_SHA", "TLS_DHE_DSS_WITH_AES_256_CBC_SHA", "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", "TLS_DHE_DSS_WITH_AES_128_CBC_SHA", "TLS_RSA_WITH_AES_256_GCM_SHA384", "TLS_RSA_WITH_AES_128_GCM_SHA256", "TLS_RSA_WITH_AES_256_CBC_SHA256", "TLS_RSA_WITH_AES_128_CBC_SHA256", "TLS_RSA_WITH_AES_256_CBC_SHA", "TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_EMPTY_RENEGOTIATION_INFO_SCSV" ); assertThat(sslServerSocketFactory.getDefaultCipherSuites()).containsExactly( "TLS_AES_256_GCM_SHA384", "TLS_AES_128_GCM_SHA256", "TLS_CHACHA20_POLY1305_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256", "TLS_DHE_DSS_WITH_AES_256_GCM_SHA384", "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256", "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256", "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256", "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "TLS_DHE_RSA_WITH_AES_256_CBC_SHA", "TLS_DHE_DSS_WITH_AES_256_CBC_SHA", "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", "TLS_DHE_DSS_WITH_AES_128_CBC_SHA", "TLS_RSA_WITH_AES_256_GCM_SHA384", "TLS_RSA_WITH_AES_128_GCM_SHA256", "TLS_RSA_WITH_AES_256_CBC_SHA256", "TLS_RSA_WITH_AES_128_CBC_SHA256", "TLS_RSA_WITH_AES_256_CBC_SHA", "TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_EMPTY_RENEGOTIATION_INFO_SCSV" ); assertThat(sslServerSocketFactory.getSupportedCipherSuites()) .containsExactly(sslServerSocketFactory.getDefaultCipherSuites()); assertThat(sslServerSocketFactory.getSupportedCipherSuites()).hasSize(37); assertThat(sslServerSocketFactory.getDefaultCipherSuites()).hasSize(37); assertThat(sslSocketFactory.getSupportedCipherSuites()) .isEqualTo(sslServerSocketFactory.getSupportedCipherSuites()); assertThat(sslSocketFactory.getDefaultCipherSuites()) .isEqualTo(sslServerSocketFactory.getDefaultCipherSuites()); } @Test void tls12ContextSupportedCipherSuites() throws NoSuchAlgorithmException, KeyManagementException { SSLContext sslContext = SSLContext.getInstance("TLSv1.2"); sslContext.init(null, null, new SecureRandom()); SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory(); assertThat(sslSocketFactory.getSupportedCipherSuites()).containsExactly( "TLS_AES_256_GCM_SHA384", "TLS_AES_128_GCM_SHA256", "TLS_CHACHA20_POLY1305_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256", "TLS_DHE_DSS_WITH_AES_256_GCM_SHA384", "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256", "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256", "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256", "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "TLS_DHE_RSA_WITH_AES_256_CBC_SHA", "TLS_DHE_DSS_WITH_AES_256_CBC_SHA", "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", "TLS_DHE_DSS_WITH_AES_128_CBC_SHA", "TLS_RSA_WITH_AES_256_GCM_SHA384", "TLS_RSA_WITH_AES_128_GCM_SHA256", "TLS_RSA_WITH_AES_256_CBC_SHA256", "TLS_RSA_WITH_AES_128_CBC_SHA256", "TLS_RSA_WITH_AES_256_CBC_SHA", "TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_EMPTY_RENEGOTIATION_INFO_SCSV" ); assertThat(sslSocketFactory.getDefaultCipherSuites()).containsExactly( "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256", "TLS_DHE_DSS_WITH_AES_256_GCM_SHA384", "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256", "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256", "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256", "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "TLS_DHE_RSA_WITH_AES_256_CBC_SHA", "TLS_DHE_DSS_WITH_AES_256_CBC_SHA", "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", "TLS_DHE_DSS_WITH_AES_128_CBC_SHA", "TLS_RSA_WITH_AES_256_GCM_SHA384", "TLS_RSA_WITH_AES_128_GCM_SHA256", "TLS_RSA_WITH_AES_256_CBC_SHA256", "TLS_RSA_WITH_AES_128_CBC_SHA256", "TLS_RSA_WITH_AES_256_CBC_SHA", "TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_EMPTY_RENEGOTIATION_INFO_SCSV" ); // 異なる assertThat(sslSocketFactory.getSupportedCipherSuites()) .isNotEqualTo(sslSocketFactory.getDefaultCipherSuites()); assertThat(sslSocketFactory.getSupportedCipherSuites()).hasSize(37); assertThat(sslSocketFactory.getDefaultCipherSuites()).hasSize(34); SSLServerSocketFactory sslServerSocketFactory = sslContext.getServerSocketFactory(); assertThat(sslServerSocketFactory.getSupportedCipherSuites()).containsExactly( "TLS_AES_256_GCM_SHA384", "TLS_AES_128_GCM_SHA256", "TLS_CHACHA20_POLY1305_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256", "TLS_DHE_DSS_WITH_AES_256_GCM_SHA384", "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256", "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256", "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256", "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "TLS_DHE_RSA_WITH_AES_256_CBC_SHA", "TLS_DHE_DSS_WITH_AES_256_CBC_SHA", "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", "TLS_DHE_DSS_WITH_AES_128_CBC_SHA", "TLS_RSA_WITH_AES_256_GCM_SHA384", "TLS_RSA_WITH_AES_128_GCM_SHA256", "TLS_RSA_WITH_AES_256_CBC_SHA256", "TLS_RSA_WITH_AES_128_CBC_SHA256", "TLS_RSA_WITH_AES_256_CBC_SHA", "TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_EMPTY_RENEGOTIATION_INFO_SCSV" ); assertThat(sslServerSocketFactory.getDefaultCipherSuites()).containsExactly( "TLS_AES_256_GCM_SHA384", "TLS_AES_128_GCM_SHA256", "TLS_CHACHA20_POLY1305_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256", "TLS_DHE_DSS_WITH_AES_256_GCM_SHA384", "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256", "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256", "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256", "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "TLS_DHE_RSA_WITH_AES_256_CBC_SHA", "TLS_DHE_DSS_WITH_AES_256_CBC_SHA", "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", "TLS_DHE_DSS_WITH_AES_128_CBC_SHA", "TLS_RSA_WITH_AES_256_GCM_SHA384", "TLS_RSA_WITH_AES_128_GCM_SHA256", "TLS_RSA_WITH_AES_256_CBC_SHA256", "TLS_RSA_WITH_AES_128_CBC_SHA256", "TLS_RSA_WITH_AES_256_CBC_SHA", "TLS_RSA_WITH_AES_128_CBC_SHA", "TLS_EMPTY_RENEGOTIATION_INFO_SCSV" ); assertThat(sslServerSocketFactory.getSupportedCipherSuites()) .containsExactly(sslServerSocketFactory.getDefaultCipherSuites()); assertThat(sslServerSocketFactory.getDefaultCipherSuites()).hasSize(37); assertThat(sslServerSocketFactory.getSupportedCipherSuites()).hasSize(37); assertThat(sslSocketFactory.getSupportedCipherSuites()) .isEqualTo(sslServerSocketFactory.getSupportedCipherSuites()); // 異なる assertThat(sslSocketFactory.getDefaultCipherSuites()) .isNotEqualTo(sslServerSocketFactory.getDefaultCipherSuites()); } }
おわりに
JSSEでサポートしているSSL/TLSプロトコル、SSLSocketFactoryでサポートしている暗号スイートを確認する方法や、設定変更について
調べてみました。
このあたり、ざっくりとしか見ていなかったのでSSL/TLSまわりのカスタマイズについていろいろと勉強になりました。
そんなに頻繁に使う知識でもないと思いますが、せっかくなのでメモとして。