Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2026, IBM Corporation. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -172,9 +173,18 @@ private Set<String> decomposes(SSLCipher bulkCipher) {
case B_AES_128_GCM:
components.add("AES_128_GCM");
break;
case B_AES_128_GCM_IV:
components.add("AES_128_GCM");
break;
case B_AES_256_GCM:
components.add("AES_256_GCM");
break;
case B_AES_256_GCM_IV:
components.add("AES_256_GCM");
break;
case B_CC20_P1305:
components.add("CHACHA20_POLY1305");
break;
}

return components;
Expand Down
218 changes: 218 additions & 0 deletions test/jdk/javax/net/ssl/ciphersuites/BulkCipherDisabledAlgorithms.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
/*
* Copyright (c) 2026, IBM Corporation. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/

/*
* @test
* @bug 8387124
* @summary Test TLS cipher suite disabling via jdk.tls.disabledAlgorithms,
* including matching on bulk cipher components, covering both
* visibility and handshake behavior.
* @library /test/lib
* /javax/net/ssl/TLSCommon
* /javax/net/ssl/templates
* @run main/othervm BulkCipherDisabledAlgorithms visibility
* @run main/othervm BulkCipherDisabledAlgorithms handshake
*/

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javax.net.ssl.*;

import jdk.test.lib.process.Proc;

import java.security.NoSuchAlgorithmException;
import java.security.Security;

public class BulkCipherDisabledAlgorithms {

public static void main(String[] args) throws Exception {
if (args.length == 0) {
throw new RuntimeException("Missing mode argument");
}

String mode = args[0];
boolean isVisibilityTest = "visibility".equals(mode);
boolean isHandshakeTest = "handshake".equals(mode);

if (args.length == 1) {
List<String[]> tests = buildTests(isVisibilityTest);

for (String[] test : tests) {
String suite = test[0];
String disabled = test[1];
String expected = test[2];

System.out.println("=================================================");
System.out.println("Testing: " + mode +
", suite=" + suite +
", disabled=" + disabled +
", expected=" + expected);

Proc p = Proc.create(
BulkCipherDisabledAlgorithms.class.getName())
.args(mode, suite, expected)
.secprop("jdk.tls.disabledAlgorithms", disabled)
.inheritIO();

p.start().waitFor(0);
}

System.out.println("TEST PASS - OK");
return;
}

String suite = args[1];
String expected = args[2];
boolean expectedDisabled = "disabled".equals(expected);

if (isVisibilityTest) {
testCipherSuiteVisibility(suite, expectedDisabled);
}

if (isHandshakeTest) {
testHandshake(suite, expectedDisabled);
}
}

// Returns cipher suites for testing.
// - true: use all supported suites (independent of disabledAlgorithms)
// - false: use default enabled suites (candidates for handshake)
private static CipherSuite[] getCipherSuites(boolean useSupportedSuites)
throws NoSuchAlgorithmException {
SSLEngine engine = SSLContext.getDefault().createSSLEngine();
String[] suites = useSupportedSuites
? engine.getSupportedCipherSuites()
: engine.getEnabledCipherSuites();

return Arrays.stream(suites)
.map(CipherSuite::cipherSuite)
.filter(cs -> cs != CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV)
.toArray(CipherSuite[]::new);
}

private static List<String[]> buildTests(boolean useSupportedSuites)
throws NoSuchAlgorithmException {
if (useSupportedSuites) {
// disabledAlgorithms limits supported suites; clear to list all
Security.setProperty("jdk.tls.disabledAlgorithms", "");
}

List<String[]> tests = new ArrayList<>();
CipherSuite[] suites = getCipherSuites(useSupportedSuites);

for (CipherSuite suite : suites) {
String suiteName = suite.name();
String bulk = extractBulkCipher(suiteName);

tests.add(new String[] { suiteName, suiteName, "disabled" });
tests.add(new String[] { suiteName, bulk, "disabled" });

for (CipherSuite other : suites) {
// Negative test case: disable a different bulk cipher than the one
// used by the current suite. This ensures that the suite remains
// enabled and a successful TLS handshake can still be negotiated.
if (other == suite) {
continue;
}

String otherBulk = extractBulkCipher(other.name());

if (!bulk.equals(otherBulk)
&& !suiteName.contains(otherBulk)) {
tests.add(new String[] { suiteName, otherBulk, "enabled" });
break;
}
}
}

return tests;
}

/**
* Separator used in TLS cipher suite names to mark the start of
* the bulk cipher component (e.g. TLS_RSA_WITH_AES_128_CBC_SHA).
*/
private static final String WITH = "_WITH_";

private static String extractBulkCipher(String suite) {
if (suite.contains(WITH)) {
String after = suite.substring(suite.indexOf(WITH) + WITH.length());
int last = after.lastIndexOf('_');
return after.substring(0, last);
} else {
int first = suite.indexOf('_');
int last = suite.lastIndexOf('_');
return suite.substring(first + 1, last);
}
}

private static void testCipherSuiteVisibility(String suite, boolean expectedDisabled)
throws NoSuchAlgorithmException {
boolean visible = Arrays.asList(getCipherSuites(true))
.contains(CipherSuite.cipherSuite(suite));

if (!expectedDisabled && !visible) {
throw new RuntimeException(
"Cipher suite '" + suite + "' not visible but expected to be enabled");
} else if (expectedDisabled && visible) {
throw new RuntimeException(
"Cipher suite '" + suite + "' visible but expected to be disabled");
}
}

private static void testHandshake(String suite, boolean expectedDisabled) throws Exception {
try {
new TLSHandshakeTest(suite).run();

if (expectedDisabled) {
throw new RuntimeException(
"Handshake succeeded but should fail: " + suite);
}
} catch (SSLHandshakeException e) {
if (!expectedDisabled) {
throw new RuntimeException(
"Handshake failed unexpectedly: " + suite, e);
}
}
}

private static class TLSHandshakeTest extends SSLSocketTemplate {
private final String suite;

TLSHandshakeTest(String suite) {
this.suite = suite;
}

@Override
protected void configureClientSocket(SSLSocket socket) {
socket.setEnabledCipherSuites(new String[] { suite });
}

@Override
protected void configureServerSocket(SSLServerSocket socket) {
socket.setEnabledCipherSuites(new String[] { suite });
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* Copyright (c) 2026, IBM Corporation. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/

/*
* @test
* @bug 8387124
* @summary Test disabling TLS 1.3 cipher suites with bulk ciphers names
* @run testng/othervm TLS13BulkCipherDisabledCipherSuite
*/

import static org.testng.AssertJUnit.assertTrue;

import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;

import java.security.Security;
import java.util.List;

public class TLS13BulkCipherDisabledCipherSuite extends AbstractDisableCipherSuites {

private static final String SECURITY_PROPERTY = "jdk.tls.disabledAlgorithms";
private static final String TEST_ALGORITHMS = "AES_256_GCM,"
+ " AES_128_GCM,"
+ " CHACHA20_POLY1305";
private static final String[] CIPHER_SUITES = new String[] {
"TLS_AES_256_GCM_SHA384",
"TLS_AES_128_GCM_SHA256",
"TLS_CHACHA20_POLY1305_SHA256"
};
static final List<Integer> CIPHER_SUITES_IDS = List.of(
0x1301,
0x1302,
0x1303);

@Override
protected String getProtocol() {
return "TLSv1.3";
}

@BeforeTest
void setUp() throws Exception {
Security.setProperty(SECURITY_PROPERTY, TEST_ALGORITHMS);
}

@Test
public void testDefault() throws Exception {
assertTrue(testDefaultCase(CIPHER_SUITES_IDS));
}

@Test
public void testAddDisabled() throws Exception {
assertTrue(testEngAddDisabled(CIPHER_SUITES, CIPHER_SUITES_IDS));
}

@Test
public void testOnlyDisabled() throws Exception {
assertTrue(testEngOnlyDisabled(CIPHER_SUITES));
}
}