undefect. CWE-407 — 63 sites patched across 27 ecosystems
Authors: russell@unturf.com · brackishbert@gmail.com · foxhop.net · TimeHexOn.com Patches, unit tests, benchmarks, whitepaper, and outreach briefs. Public domain — no copyright claimed. Use freely.
This commit is contained in:
commit
0a580b313d
70422 changed files with 17213626 additions and 0 deletions
316
test/jdk/sun/security/ssl/SSLSocketImpl/SSLSocketKeyLimit.java
Normal file
316
test/jdk/sun/security/ssl/SSLSocketImpl/SSLSocketKeyLimit.java
Normal file
|
|
@ -0,0 +1,316 @@
|
|||
/*
|
||||
* Copyright (c) 2018, 2025, Oracle and/or its affiliates. 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 8164879 8300285
|
||||
* @library ../../
|
||||
* @library /test/lib
|
||||
* @modules java.base/sun.security.util
|
||||
* @summary Verify AEAD TLS cipher suite limits set in the jdk.tls.keyLimits
|
||||
* property
|
||||
* @run main SSLSocketKeyLimit 0 server TLS_AES_256_GCM_SHA384
|
||||
* AES/GCM/NoPadding keyupdate 1000000
|
||||
* @run main SSLSocketKeyLimit 0 client TLS_AES_256_GCM_SHA384
|
||||
* AES/GCM/NoPadding keyupdate 1000000
|
||||
* @run main SSLSocketKeyLimit 1 client TLS_AES_256_GCM_SHA384
|
||||
* AES/GCM/NoPadding keyupdate 2^22
|
||||
* @run main SSLSocketKeyLimit 0 server TLS_CHACHA20_POLY1305_SHA256
|
||||
* AES/GCM/NoPadding keyupdate 1000000, ChaCha20-Poly1305 KeyUpdate 1000000
|
||||
* @run main SSLSocketKeyLimit 0 client TLS_CHACHA20_POLY1305_SHA256
|
||||
* AES/GCM/NoPadding keyupdate 1000000, ChaCha20-Poly1305 KeyUpdate 1000000
|
||||
* @run main SSLSocketKeyLimit 1 client TLS_CHACHA20_POLY1305_SHA256
|
||||
* AES/GCM/NoPadding keyupdate 2^22, ChaCha20-Poly1305 KeyUpdate 2^22
|
||||
*/
|
||||
|
||||
/**
|
||||
* Verify AES/GCM's limits set in the jdk.tls.keyLimits property
|
||||
* start a new handshake sequence to renegotiate the symmetric key with an
|
||||
* SSLSocket connection. This test verifies the handshake method was called
|
||||
* via debugging info. It does not verify the renegotiation was successful
|
||||
* as that is very hard.
|
||||
*/
|
||||
|
||||
import javax.net.ssl.KeyManagerFactory;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLServerSocket;
|
||||
import javax.net.ssl.SSLServerSocketFactory;
|
||||
import javax.net.ssl.SSLSocket;
|
||||
import javax.net.ssl.SSLSocketFactory;
|
||||
import javax.net.ssl.TrustManagerFactory;
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.security.KeyStore;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Arrays;
|
||||
|
||||
import jdk.test.lib.process.OutputAnalyzer;
|
||||
import jdk.test.lib.process.ProcessTools;
|
||||
import jdk.test.lib.hexdump.HexPrinter;
|
||||
|
||||
public class SSLSocketKeyLimit {
|
||||
SSLSocket socket;
|
||||
private InputStream in;
|
||||
private OutputStream out;
|
||||
|
||||
static boolean serverReady = false;
|
||||
static int serverPort = 0;
|
||||
|
||||
static String pathToStores = "../../../../javax/net/ssl/etc/";
|
||||
static String keyStoreFile = "keystore";
|
||||
static String passwd = "passphrase";
|
||||
static int dataLen = 10240;
|
||||
static byte[] data = new byte[dataLen];
|
||||
static boolean serverwrite = true;
|
||||
int totalDataLen = 0;
|
||||
static boolean done = false;
|
||||
|
||||
SSLSocketKeyLimit() {
|
||||
}
|
||||
|
||||
SSLContext initContext() throws Exception {
|
||||
SSLContext sc = SSLContext.getInstance("TLSv1.3");
|
||||
KeyStore ks = KeyStore.getInstance(
|
||||
new File(System.getProperty("javax.net.ssl.keyStore")),
|
||||
passwd.toCharArray());
|
||||
KeyManagerFactory kmf =
|
||||
KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
|
||||
kmf.init(ks, passwd.toCharArray());
|
||||
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
|
||||
tmf.init(ks);
|
||||
sc.init(kmf.getKeyManagers(), tmf.getTrustManagers(), new SecureRandom());
|
||||
return sc;
|
||||
}
|
||||
|
||||
/**
|
||||
* args should have three values: server|client, cipher suite, <limit size>
|
||||
* Prepending 'p' is for internal use only.
|
||||
*/
|
||||
public static void main(String args[]) throws Exception {
|
||||
if (args[0].compareTo("p") != 0) {
|
||||
|
||||
boolean expectedFail = (Integer.parseInt(args[0]) == 1);
|
||||
if (expectedFail) {
|
||||
System.out.println("Test expected to not find updated msg");
|
||||
}
|
||||
//Write security property file to overwrite default
|
||||
File f = new File("keyusage."+ System.nanoTime());
|
||||
PrintWriter p = new PrintWriter(f);
|
||||
p.write("jdk.tls.keyLimits=");
|
||||
for (int i = 3; i < args.length; i++) {
|
||||
p.write(" "+ args[i]);
|
||||
}
|
||||
p.close();
|
||||
System.out.println("Keyusage path = " + f.getAbsolutePath());
|
||||
System.setProperty("test.java.opts", System.getProperty("test.java.opts") +
|
||||
" -Dtest.src=" + System.getProperty("test.src") +
|
||||
" -Dtest.jdk=" + System.getProperty("test.jdk") +
|
||||
" -Djavax.net.debug=ssl" +
|
||||
" -Djava.security.properties=" + f.getName());
|
||||
|
||||
System.out.println("test.java.opts: " +
|
||||
System.getProperty("test.java.opts"));
|
||||
|
||||
ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder(
|
||||
"SSLSocketKeyLimit", "p", args[1], args[2]);
|
||||
|
||||
OutputAnalyzer output = ProcessTools.executeProcess(pb);
|
||||
try {
|
||||
output.shouldContain(String.format(
|
||||
"\"cipher suite\" : \"%s", args[2]));
|
||||
if (expectedFail) {
|
||||
output.shouldNotContain("KeyUpdate: write key updated");
|
||||
output.shouldNotContain("KeyUpdate: read key updated");
|
||||
} else {
|
||||
output.shouldContain("trigger key update");
|
||||
output.shouldContain("KeyUpdate: write key updated");
|
||||
output.shouldContain("KeyUpdate: read key updated");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw e;
|
||||
} finally {
|
||||
System.out.println("-- BEGIN Stdout:");
|
||||
System.out.println(output.getStdout());
|
||||
System.out.println("-- END Stdout");
|
||||
System.out.println("-- BEGIN Stderr:");
|
||||
System.out.println(output.getStderr());
|
||||
System.out.println("-- END Stderr");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.length > 0 && args[1].compareToIgnoreCase("client") == 0) {
|
||||
serverwrite = false;
|
||||
}
|
||||
|
||||
String keyFilename =
|
||||
System.getProperty("test.src", "./") + "/" + pathToStores +
|
||||
"/" + keyStoreFile;
|
||||
|
||||
System.setProperty("javax.net.ssl.keyStore", keyFilename);
|
||||
System.setProperty("javax.net.ssl.keyStorePassword", passwd);
|
||||
|
||||
Arrays.fill(data, (byte)0x0A);
|
||||
Thread ts = new Thread(new Server(args[2]));
|
||||
|
||||
ts.start();
|
||||
while (!serverReady) {
|
||||
Thread.sleep(100);
|
||||
}
|
||||
new Client().run();
|
||||
ts.join(10000); // 10sec
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
void write(SSLSocket s) throws Exception {
|
||||
int i = 0;
|
||||
in = s.getInputStream();
|
||||
out = s.getOutputStream();
|
||||
while (i++ < 150) {
|
||||
out.write(data, 0, dataLen);
|
||||
System.out.print("W");
|
||||
in.readNBytes(1);
|
||||
System.out.print("R");
|
||||
}
|
||||
out.write(0x0D);
|
||||
out.flush();
|
||||
|
||||
// Let read side all the data
|
||||
while (!done) {
|
||||
Thread.sleep(100);
|
||||
}
|
||||
out.close();
|
||||
in.close();
|
||||
}
|
||||
|
||||
|
||||
void read(SSLSocket s) throws Exception {
|
||||
byte[] buf = new byte[dataLen];
|
||||
int len;
|
||||
byte i = 0;
|
||||
try {
|
||||
System.out.println("Server: connected " +
|
||||
s.getSession().getCipherSuite());
|
||||
in = s.getInputStream();
|
||||
out = s.getOutputStream();
|
||||
while (true) {
|
||||
len = in.read(buf, 0, dataLen);
|
||||
System.out.print("r");
|
||||
out.write(i++);
|
||||
System.out.print("w");
|
||||
for (byte b: buf) {
|
||||
if (b == 0x0A || b == 0x0D) {
|
||||
continue;
|
||||
}
|
||||
System.out.println("\nData invalid: " +
|
||||
HexPrinter.minimal().toString(buf));
|
||||
break;
|
||||
}
|
||||
|
||||
if (len > 0 && buf[len-1] == 0x0D) {
|
||||
System.out.println("got end byte");
|
||||
break;
|
||||
}
|
||||
totalDataLen += len;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.out.println("\n" + e.getMessage());
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
// Tell write side that we are done reading
|
||||
out.close();
|
||||
in.close();
|
||||
done = true;
|
||||
}
|
||||
System.out.println("\nTotalDataLen = " + totalDataLen);
|
||||
}
|
||||
|
||||
static class Server extends SSLSocketKeyLimit implements Runnable {
|
||||
private SSLServerSocketFactory ssf;
|
||||
private SSLServerSocket ss;
|
||||
Server(String cipherSuite) {
|
||||
super();
|
||||
try {
|
||||
ssf = initContext().getServerSocketFactory();
|
||||
ss = (SSLServerSocket) ssf.createServerSocket(serverPort);
|
||||
if (cipherSuite != null && cipherSuite.length() > 0) {
|
||||
ss.setEnabledCipherSuites(new String[] { cipherSuite });
|
||||
}
|
||||
serverPort = ss.getLocalPort();
|
||||
} catch (Exception e) {
|
||||
System.out.println("server: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void run() {
|
||||
try {
|
||||
serverReady = true;
|
||||
System.out.println("Server waiting... port: " + serverPort);
|
||||
socket = (SSLSocket) ss.accept();
|
||||
if (serverwrite) {
|
||||
write(socket);
|
||||
} else {
|
||||
read(socket);
|
||||
}
|
||||
|
||||
socket.close();
|
||||
} catch (Exception e) {
|
||||
System.out.println("server: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
System.out.println("Server closed");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static class Client extends SSLSocketKeyLimit implements Runnable {
|
||||
private SSLSocketFactory sf;
|
||||
|
||||
Client() {
|
||||
super();
|
||||
}
|
||||
|
||||
public void run() {
|
||||
try {
|
||||
sf = initContext().getSocketFactory();
|
||||
System.out.println("Client: connecting... port: " + serverPort);
|
||||
socket = (SSLSocket)sf.createSocket("localhost", serverPort);
|
||||
System.out.println("Client: connected." + socket.getSession().getCipherSuite());
|
||||
|
||||
// Opposite of what the server does
|
||||
if (!serverwrite) {
|
||||
write(socket);
|
||||
} else {
|
||||
read(socket);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
System.err.println("client: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue