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:
russell@unturf.com 2026-03-26 17:11:57 -04:00
commit 0a580b313d
70422 changed files with 17213626 additions and 0 deletions

View file

@ -0,0 +1,415 @@
/*
* Copyright (c) 2004, 2021, 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 5026745
* @library /test/lib
* @run main/othervm ChunkedOutputStream
* @run main/othervm -Djava.net.preferIPv6Addresses=true ChunkedOutputStream
*
* SunJSSE does not support dynamic system properties, no way to re-use
* system properties in samevm/agentvm mode.
* @summary Cannot flush output stream when writing to an HttpUrlConnection
*/
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpRetryException;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.SocketException;
import java.net.URL;
import java.nio.charset.Charset;
import java.security.KeyStore;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManagerFactory;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpsConfigurator;
import com.sun.net.httpserver.HttpsServer;
public class ChunkedOutputStream implements HttpHandler {
/*
* Where do we find the keystores for ssl?
*/
static String pathToStores = "../../../../../javax/net/ssl/etc";
static String keyStoreFile = "keystore";
static String trustStoreFile = "truststore";
static String passwd = "passphrase";
static int count = 0;
static final AtomicInteger rogueCount = new AtomicInteger();
static final String str1 = "Helloworld1234567890abcdefghijklmnopqrstuvwxyz"+
"1234567890abcdefkjsdlkjflkjsldkfjlsdkjflkj"+
"1434567890abcdefkjsdlkjflkjsldkfjlsdkjflkj";
static final String str2 = "Helloworld1234567890abcdefghijklmnopqrstuvwxyz"+
"1234567890";
private static String getAuthority() {
InetAddress address = server.getAddress().getAddress();
String hostaddr = address.getHostAddress();
if (address.isAnyLocalAddress()) hostaddr = "localhost";
if (hostaddr.indexOf(':') > -1) hostaddr = "[" + hostaddr + "]";
return hostaddr + ":" + server.getAddress().getPort();
}
public void handle(HttpExchange req) throws IOException {
// this is needed (count++ doesn't work), 'cause we
// are doing concurrent tests
System.out.println("Request Received");
String path = req.getRequestURI().getPath();
if (path.equals("/d0")) {
count = 0;
} else if (path.equals("/d01")) {
count = 1;
} else if (path.equals("/d3")) {
count = 2;
} else if (path.equals("/d4") || path.equals("/d5")) {
count = 3;
} else if (path.equals("/d6")) {
count = 3;
} else if (path.equals("/d7")) {
count = 4;
} else if (path.equals("/d8")) {
count = 5;
}
switch (count) {
case 0: /* test1 -- keeps conn alive */
case 1: /* test2 -- closes conn */
String reqbody = "";
try(InputStream inputStream = req.getRequestBody()) {
reqbody = new String(inputStream.readAllBytes(), Charset.forName("ISO8859_1"));
}
if (!reqbody.equals(str1)) {
req.sendResponseHeaders(500, -1);
break;
}
String chunk = req.getRequestHeaders().getFirst("Transfer-encoding");
if (!"chunked".equals(chunk)) {
req.sendResponseHeaders(501, -1);
break;
}
if (count == 1) {
req.getResponseHeaders().set("Connection", "close");
}
req.sendResponseHeaders(200, 0);
try (OutputStream os = req.getResponseBody()) {
os.write(reqbody.getBytes(Charset.forName("ISO8859_1")));
}
break;
case 2: /* test 3 */
reqbody = new String(req.getRequestBody().readAllBytes(), Charset.forName("ISO8859_1"));
if (!reqbody.equals(str2)) {
req.sendResponseHeaders(500, -1);
break;
}
int clen = Integer.parseInt (req.getRequestHeaders().getFirst("Content-length"));
if (clen != str2.length()) {
req.sendResponseHeaders(501, -1);
break;
}
req.getResponseHeaders().set("Connection", "close");
req.sendResponseHeaders(200, 0);
try (OutputStream os = req.getResponseBody()) {
os.write(reqbody.getBytes(Charset.forName("ISO8859_1")));
}
break;
case 3: /* test 6 */
if (path.equals("/d6")) {
reqbody = new String(req.getRequestBody().readAllBytes(), Charset.forName("ISO8859_1"));
}
req.getResponseHeaders().set("Location", "https://foo.bar/");
req.getResponseHeaders().set("Connection", "close");
req.sendResponseHeaders(307, -1);
break;
case 4: /* test 7 */
case 5: /* test 8 */
reqbody = new String(req.getRequestBody().readAllBytes(), Charset.forName("ISO8859_1"));
if (reqbody != null && !"".equals(reqbody)) {
req.sendResponseHeaders(501, -1);
break;
}
req.getResponseHeaders().set("Connection", "close");
req.sendResponseHeaders(200, -1);
break;
default:
req.sendResponseHeaders(404, -1);
break;
}
req.close();
}
static void readAndCompare(InputStream is, String cmp) throws IOException {
int c;
byte buf[] = new byte[1024];
int off = 0;
int len = 1024;
while ((c=is.read(buf, off, len)) != -1) {
off += c;
len -= c;
}
String s1 = new String(buf, 0, off, "ISO8859_1");
if (!cmp.equals(s1)) {
throw new IOException("strings not same");
}
}
/* basic smoke test: verify that server drops plain connections */
static void testPlainText(String authority) throws Exception {
URL url = new URL("http://" + authority + "/Donauschiffsgesellschaftskapitaenskajuete");
System.out.println("client opening connection to: " + url);
HttpURLConnection urlc = (HttpURLConnection)url.openConnection(Proxy.NO_PROXY);
int rogue = rogueCount.get();
try {
int code = urlc.getResponseCode();
System.out.println("Unexpected response: " + code);
throw new AssertionError("Unexpected response: " + code);
} catch (SocketException x) {
// we expect that the server will drop the connection and
// close the accepted socket, so we should get a SocketException
System.out.println("Got expected exception: " + x);
}
}
/* basic chunked test (runs twice) */
static void test1(String u) throws Exception {
URL url = new URL(u);
System.out.println("client opening connection to: " + u);
HttpURLConnection urlc = (HttpURLConnection)url.openConnection(Proxy.NO_PROXY);
urlc.setChunkedStreamingMode(20);
urlc.setDoOutput(true);
urlc.setRequestMethod("POST");
OutputStream os = urlc.getOutputStream();
os.write(str1.getBytes(Charset.forName("ISO8859_1")));
os.close();
InputStream is = urlc.getInputStream();
readAndCompare(is, str1);
is.close();
}
/* basic fixed length test */
static void test3(String u) throws Exception {
URL url = new URL(u);
System.out.println("client opening connection to: " + u);
HttpURLConnection urlc = (HttpURLConnection)url.openConnection(Proxy.NO_PROXY);
urlc.setFixedLengthStreamingMode(str2.length());
urlc.setDoOutput(true);
urlc.setRequestMethod("POST");
OutputStream os = urlc.getOutputStream();
os.write (str2.getBytes(Charset.forName("ISO8859_1")));
os.close();
InputStream is = urlc.getInputStream();
readAndCompare(is, str2);
is.close();
}
/* write too few bytes */
static void test4(String u) throws Exception {
URL url = new URL(u);
System.out.println("client opening connection to: " + u);
HttpURLConnection urlc = (HttpURLConnection)url.openConnection(Proxy.NO_PROXY);
urlc.setFixedLengthStreamingMode(str2.length()+1);
urlc.setDoOutput(true);
urlc.setRequestMethod("POST");
OutputStream os = urlc.getOutputStream();
os.write(str2.getBytes(Charset.forName("ISO8859_1")));
try {
os.close();
throw new Exception("should have thrown IOException");
} catch (IOException e) {}
}
/* write too many bytes */
static void test5(String u) throws Exception {
URL url = new URL(u);
System.out.println("client opening connection to: " + u);
HttpURLConnection urlc = (HttpURLConnection)url.openConnection(Proxy.NO_PROXY);
urlc.setFixedLengthStreamingMode(str2.length()-1);
urlc.setDoOutput(true);
urlc.setRequestMethod("POST");
OutputStream os = urlc.getOutputStream();
try {
os.write(str2.getBytes(Charset.forName("ISO8859_1")));
throw new Exception("should have thrown IOException");
} catch (IOException e) {}
}
/* check for HttpRetryException on redirection */
static void test6(String u) throws Exception {
URL url = new URL(u);
System.out.println("client opening connection to: " + u);
HttpURLConnection urlc = (HttpURLConnection)url.openConnection(Proxy.NO_PROXY);
urlc.setChunkedStreamingMode(20);
urlc.setDoOutput(true);
urlc.setRequestMethod("POST");
OutputStream os = urlc.getOutputStream();
os.write(str1.getBytes(Charset.forName("ISO8859_1")));
os.close();
try {
InputStream is = urlc.getInputStream();
throw new Exception("should have gotten HttpRetryException");
} catch (HttpRetryException e) {
if (e.responseCode() != 307) {
throw new Exception("Wrong response code " + e.responseCode());
}
if (!e.getLocation().equals("https://foo.bar/")) {
throw new Exception("Wrong location " + e.getLocation());
}
}
}
/* next two tests send zero length posts */
static void test7(String u) throws Exception {
URL url = new URL(u);
System.out.println("client opening connection to: " + u);
HttpURLConnection urlc = (HttpURLConnection)url.openConnection(Proxy.NO_PROXY);
urlc.setChunkedStreamingMode(20);
urlc.setDoOutput(true);
urlc.setRequestMethod("POST");
OutputStream os = urlc.getOutputStream();
os.close();
int ret = urlc.getResponseCode();
if (ret != 200) {
throw new Exception("Expected 200: got " + ret);
}
}
static void test8(String u) throws Exception {
URL url = new URL(u);
System.out.println("client opening connection to: " + u);
HttpURLConnection urlc = (HttpURLConnection)url.openConnection(Proxy.NO_PROXY);
urlc.setFixedLengthStreamingMode(0);
urlc.setDoOutput(true);
urlc.setRequestMethod("POST");
OutputStream os = urlc.getOutputStream();
os.close();
int ret = urlc.getResponseCode();
if (ret != 200) {
throw new Exception("Expected 200: got " + ret);
}
}
static HttpsServer server;
public static void main(String[] args) throws Exception {
ChunkedOutputStream chunkedOutputStream = new ChunkedOutputStream();
// setup properties to do ssl
String keyFilename =
System.getProperty("test.src", "./") + "/" + pathToStores +
"/" + keyStoreFile;
String trustFilename =
System.getProperty("test.src", "./") + "/" + pathToStores +
"/" + trustStoreFile;
InetAddress loopback = InetAddress.getLoopbackAddress();
HostnameVerifier reservedHV =
HttpsURLConnection.getDefaultHostnameVerifier();
try {
System.setProperty("javax.net.ssl.keyStore", keyFilename);
System.setProperty("javax.net.ssl.keyStorePassword", passwd);
System.setProperty("javax.net.ssl.trustStore", trustFilename);
System.setProperty("javax.net.ssl.trustStorePassword", passwd);
HttpsURLConnection.setDefaultHostnameVerifier(new NameVerifier());
try {
// create and initialize a SSLContext
KeyStore ks = KeyStore.getInstance("JKS");
KeyStore ts = KeyStore.getInstance("JKS");
char[] passphrase = "passphrase".toCharArray();
ks.load(new FileInputStream(System.getProperty("javax.net.ssl.keyStore")), passphrase);
ts.load(new FileInputStream(System.getProperty("javax.net.ssl.trustStore")), passphrase);
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(ks, passphrase);
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(ts);
SSLContext sslCtx = SSLContext.getInstance("TLS");
sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
server = HttpsServer.create(new InetSocketAddress(loopback, 0), 10);
server.setHttpsConfigurator(new HttpsConfigurator(sslCtx));
server.createContext("/", chunkedOutputStream);
server.setExecutor(Executors.newSingleThreadExecutor());
server.start();
System.out.println("Server started: listening on: " + getAuthority());
testPlainText(getAuthority());
// the test server doesn't support keep-alive yet
// test1("http://" + server.getAuthority() + "/d0");
test1("https://" + getAuthority() + "/d01");
test3("https://" + getAuthority() + "/d3");
test4("https://" + getAuthority() + "/d4");
test5("https://" + getAuthority() + "/d5");
test6("https://" + getAuthority() + "/d6");
test7("https://" + getAuthority() + "/d7");
test8("https://" + getAuthority() + "/d8");
} catch (Exception e) {
if (server != null) {
server.stop(1);
}
throw e;
}
server.stop(1);
} finally {
HttpsURLConnection.setDefaultHostnameVerifier(reservedHV);
}
}
static class NameVerifier implements HostnameVerifier {
public boolean verify(String hostname, SSLSession session) {
return true;
}
}
public static void except(String s) {
server.stop(1);
throw new RuntimeException(s);
}
}

View file

@ -0,0 +1,77 @@
/*
* Copyright (c) 2002, 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.
*/
import java.io.*;
import java.nio.channels.*;
import java.util.*;
class ClosedChannelList {
static final long TIMEOUT = 10 * 1000; /* 10 sec */
static class Element {
long expiry;
SelectionKey key;
Element (long l, SelectionKey key) {
expiry = l;
this.key = key;
}
}
LinkedList list;
public ClosedChannelList () {
list = new LinkedList ();
}
/* close chan after TIMEOUT milliseconds */
public synchronized void add (SelectionKey key) {
long exp = System.currentTimeMillis () + TIMEOUT;
list.add (new Element (exp, key));
}
public synchronized void check () {
check (false);
}
public synchronized void terminate () {
check (true);
}
public synchronized void check (boolean forceClose) {
Iterator iter = list.iterator ();
long now = System.currentTimeMillis();
while (iter.hasNext ()) {
Element elm = (Element)iter.next();
if (forceClose || elm.expiry <= now) {
SelectionKey k = elm.key;
try {
k.channel().close ();
} catch (IOException e) {}
k.cancel();
iter.remove();
}
}
}
}

View file

@ -0,0 +1,147 @@
/*
* Copyright (c) 2001, 2004, 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.
*/
import javax.net.ssl.X509KeyManager;
import java.io.*;
import java.security.*;
import java.security.cert.*;
import java.security.cert.Certificate;
import java.util.*;
import java.net.Socket;
import javax.net.ssl.X509KeyManager;
import java.util.Set;
final class MyKeyManager implements X509KeyManager {
private HashMap keyMap = new HashMap();
private HashMap certChainMap = new HashMap();
MyKeyManager(KeyStore ks, char[] password)
throws KeyStoreException, NoSuchAlgorithmException,
UnrecoverableKeyException
{
if (ks == null) {
return;
}
Enumeration aliases = ks.aliases();
while (aliases.hasMoreElements()) {
String alias = (String)aliases.nextElement();
if (ks.isKeyEntry(alias)) {
Certificate[] certs;
certs = ks.getCertificateChain(alias);
if (certs != null && certs.length > 0 &&
certs[0] instanceof X509Certificate) {
if (!(certs instanceof X509Certificate[])) {
Certificate[] tmp = new X509Certificate[certs.length];
System.arraycopy(certs, 0, tmp, 0, certs.length);
certs = tmp;
}
Key key = ks.getKey(alias, password);
certChainMap.put(alias, certs);
keyMap.put(alias, key);
}
}
}
}
/*
* Choose an alias to authenticate the client side of a secure
* socket given the public key type and the list of
* certificate issuer authorities recognized by the peer (if any).
*/
public String chooseClientAlias(String[] keyTypes, Principal[] issuers,
Socket socket) {
return "client";
}
/*
* Get the matching aliases for authenticating the client side of a secure
* socket given the public key type and the list of
* certificate issuer authorities recognized by the peer (if any).
*/
public String[] getClientAliases(String keyType, Principal[] issuers) {
String[] s = new String[1];
s[0] = "client";
return s;
}
private HashMap serverAliasCache = new HashMap();
/*
* Choose an alias to authenticate the server side of a secure
* socket given the public key type and the list of
* certificate issuer authorities recognized by the peer (if any).
*/
public synchronized String chooseServerAlias(String keyType,
Principal[] issuers, Socket socket) {
return "server";
}
/*
* Get the matching aliases for authenticating the server side of a secure
* socket given the public key type and the list of
* certificate issuer authorities recognized by the peer (if any).
*/
public String[] getServerAliases(String keyType, Principal[] issuers) {
String[] s = new String[1];
s[0] = "server";
return s;
}
/**
* Returns the certificate chain associated with the given alias.
*
* @param alias the alias name
*
* @return the certificate chain (ordered with the user's certificate first
* and the root certificate authority last)
*
* @exception KeyStoreException if the alias is invalid
*/
public X509Certificate[] getCertificateChain(String alias) {
Object chain;
chain = certChainMap.get(alias);
if (!(chain instanceof X509Certificate[]))
return null;
return (X509Certificate[]) chain;
}
/*
* Returns the key associated with the given alias, using the given
* password to recover it.
*
* @param alias the alias name
*
* @return the requested key
* @exception KeyStoreException if the alias is invalid
*/
public PrivateKey getPrivateKey(String alias) {
Object key;
key = keyMap.get(alias);
if (!(key instanceof PrivateKey))
return null;
return (PrivateKey)key;
}
}

View file

@ -0,0 +1,276 @@
/*
* Copyright (c) 2001, 2022, 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.
*/
//
// SunJSSE does not support dynamic system properties, no way to re-use
// system properties in samevm/agentvm mode.
//
/*
* @test
* @bug 4323990 4413069 8160838
* @summary HttpsURLConnection doesn't send Proxy-Authorization on CONNECT
* Incorrect checking of proxy server response
* @modules jdk.crypto.ec
* java.base/sun.net.www
* @library /test/lib /javax/net/ssl/templates
* @run main/othervm ProxyAuthTest fail
* @run main/othervm -Djdk.http.auth.tunneling.disabledSchemes=Basic
* ProxyAuthTest fail
* @run main/othervm -Djdk.http.auth.tunneling.disabledSchemes=Basic,
* ProxyAuthTest fail
* @run main/othervm -Djdk.http.auth.tunneling.disabledSchemes=BAsIc
* ProxyAuthTest fail
* @run main/othervm -Djdk.http.auth.tunneling.disabledSchemes=Basic,Digest
* ProxyAuthTest fail
* @run main/othervm -Djdk.http.auth.tunneling.disabledSchemes=Unknown,bAsIc
* ProxyAuthTest fail
* @run main/othervm -Djdk.http.auth.tunneling.disabledSchemes=
* ProxyAuthTest succeed
* @run main/othervm
* -Djdk.http.auth.tunneling.disabledSchemes=Digest,NTLM,Negotiate
* ProxyAuthTest succeed
* @run main/othervm -Djdk.http.auth.tunneling.disabledSchemes=UNKNOWN,notKnown
* ProxyAuthTest succeed
*/
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Authenticator;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.PasswordAuthentication;
import java.net.Proxy;
import java.net.URL;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLContext;
import static java.nio.charset.StandardCharsets.US_ASCII;
/*
* ProxyAuthTest.java -- includes a simple server that can serve
* Http get request in both clear and secure channel, and a client
* that makes https requests behind the firewall through an
* authentication proxy
*/
public class ProxyAuthTest extends SSLSocketTemplate {
private static boolean expectSuccess;
ProxyAuthTest() {
serverAddress = InetAddress.getLoopbackAddress();
}
/*
* Run the test case.
*/
public static void main(String[] args) throws Exception {
// Get the customized arguments.
parseArguments(args);
(new ProxyAuthTest()).run();
}
@Override
protected boolean isCustomizedClientConnection() {
return true;
}
@Override
protected void doServerSide() throws Exception {
if (expectSuccess) {
super.doServerSide();
} else {
// we don't expect anything to connect to the server
serverPort = 443;
serverCondition.countDown();
}
}
@Override
protected void runServerApplication(SSLSocket socket) throws Exception {
String response = "Proxy authentication for tunneling succeeded ..";
DataOutputStream out = new DataOutputStream(socket.getOutputStream());
try {
BufferedReader in = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
// read the request
readRequest(in);
// retrieve bytecodes
byte[] bytecodes = response.getBytes(US_ASCII);
// send bytecodes in response (assumes HTTP/1.0 or later)
out.writeBytes("HTTP/1.0 200 OK\r\n");
out.writeBytes("Content-Length: " + bytecodes.length + "\r\n");
out.writeBytes("Content-Type: text/html\r\n\r\n");
out.write(bytecodes);
out.flush();
} catch (IOException e) {
// write out error response
out.writeBytes("HTTP/1.0 400 " + e.getMessage() + "\r\n");
out.writeBytes("Content-Type: text/html\r\n\r\n");
out.flush();
}
}
@Override
protected void runClientApplication(int serverPort) throws Exception {
/*
* Set the default SSLSocketFactory.
*/
SSLContext context = createClientSSLContext();
HttpsURLConnection.setDefaultSSLSocketFactory(
context.getSocketFactory());
/*
* setup up a proxy with authentication information
*/
ProxyTunnelServer ps = setupProxy();
/*
* we want to avoid URLspoofCheck failures in cases where the cert
* DN name does not match the hostname in the URL.
*/
HttpsURLConnection.setDefaultHostnameVerifier(new NameVerifier());
InetSocketAddress paddr = InetSocketAddress
.createUnresolved(ps.getInetAddress().getHostAddress(),
ps.getPort());
Proxy proxy = new Proxy(Proxy.Type.HTTP, paddr);
InetAddress serverAddress = this.serverAddress;
String host = serverAddress == null
? "localhost"
: serverAddress.getHostAddress();
if (host.indexOf(':') > -1) host = "[" + host + "]";
URL url = new URL(
"https://" + host + ":" + serverPort + "/index.html");
System.out.println("URL: " + url);
BufferedReader in = null;
HttpsURLConnection uc = (HttpsURLConnection) url.openConnection(proxy);
try {
in = new BufferedReader(new InputStreamReader(uc.getInputStream()));
String inputLine;
System.out.print("Client received from the server: ");
while ((inputLine = in.readLine()) != null) {
System.out.println(inputLine);
}
if (!expectSuccess) {
throw new RuntimeException(
"Expected exception/failure to connect, but succeeded.");
}
} catch (IOException e) {
if (expectSuccess) {
System.out.println("Client side failed: " + e.getMessage());
throw e;
}
// Assert that the error stream is not accessible from the failed
// tunnel setup.
if (uc.getErrorStream() != null) {
throw new RuntimeException("Unexpected error stream.");
}
if (!e.getMessage().contains("Unable to tunnel through proxy") ||
!e.getMessage().contains("407")) {
throw new RuntimeException(
"Expected exception about cannot tunnel, " +
"407, etc, but got", e);
} else {
// Informative
System.out.println(
"Caught expected exception: " + e.getMessage());
}
} finally {
if (in != null) {
in.close();
}
}
}
private static void parseArguments(String[] args) {
if (args[0].equals("succeed")) {
expectSuccess = true;
} else {
expectSuccess = false;
}
}
/**
* read the response, don't care for the syntax of the request-line
* for this testing
*/
private static void readRequest(BufferedReader in) throws IOException {
String line = null;
System.out.println("Server received: ");
do {
if (line != null) {
System.out.println(line);
}
line = in.readLine();
} while ((line.length() != 0) &&
(line.charAt(0) != '\r') && (line.charAt(0) != '\n'));
}
private static class NameVerifier implements HostnameVerifier {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
}
private static ProxyTunnelServer setupProxy() throws IOException {
InetAddress loopback = InetAddress.getLoopbackAddress();
ProxyTunnelServer pserver = new ProxyTunnelServer(loopback);
/*
* register a system wide authenticator and setup the proxy for
* authentication
*/
Authenticator.setDefault(new TestAuthenticator());
// register with the username and password
pserver.needUserAuth(true);
pserver.setUserAuth("Test", "test123");
pserver.start();
return pserver;
}
private static class TestAuthenticator extends Authenticator {
@Override
public PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication("Test", "test123".toCharArray());
}
}
}

View file

@ -0,0 +1,330 @@
/*
* Copyright (c) 2001, 2022, 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.
*/
/**
*
* This class includes a proxy server that processes HTTP CONNECT requests,
* and tunnels the data from the client to the server, once the CONNECT
* is accepted.
* It is used by the regression test for the bug fixes: 4323990, 4413069
*/
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Base64;
import javax.net.ServerSocketFactory;
import jdk.test.lib.net.HttpHeaderParser;
public class ProxyTunnelServer extends Thread {
private static ServerSocket ss = null;
/*
* holds the registered user's username and password
* only one such entry is maintained
*/
private String userPlusPass;
// client requesting for a tunnel
private Socket clientSocket = null;
/*
* Origin server's address and port that the client
* wants to establish the tunnel for communication.
*/
private InetAddress serverInetAddr;
private int serverPort;
/*
* denote whether the proxy needs to authorize
* CONNECT requests.
*/
static boolean needAuth = false;
public ProxyTunnelServer() throws IOException {
this(null); // use wildcard
}
public ProxyTunnelServer(InetAddress proxyAddress) throws IOException {
if (ss == null) {
ss = (ServerSocket) ServerSocketFactory.getDefault().
createServerSocket();
ss.bind(new InetSocketAddress(proxyAddress, 0));
}
setDaemon(true);
}
public void needUserAuth(boolean auth) {
needAuth = auth;
}
/*
* register users with the proxy, by providing username and
* password. The username and password are used for authorizing the
* user when a CONNECT request is made and needAuth is set to true.
*/
public void setUserAuth(String uname, String passwd) {
userPlusPass = uname + ":" + passwd;
}
public void run() {
try {
clientSocket = ss.accept();
processRequests();
} catch (Exception e) {
System.out.println("Proxy Failed: " + e);
e.printStackTrace();
try {
ss.close();
}
catch (IOException excep) {
System.out.println("ProxyServer close error: " + excep);
excep.printStackTrace();
}
}
}
/*
* Processes the CONNECT requests, if needAuth is set to true, then
* the name and password are extracted from the Proxy-Authorization header
* of the request. They are checked against the one that is registered,
* if there is a match, connection is set in tunneling mode. If
* needAuth is set to false, Proxy-Authorization checks are not made
*/
private void processRequests() throws Exception {
InputStream in = clientSocket.getInputStream();
HttpHeaderParser mheader = new HttpHeaderParser(in);
String statusLine = mheader.getRequestDetails();
if (statusLine.startsWith("CONNECT")) {
// retrieve the host and port info from the status-line
retrieveConnectInfo(statusLine);
if (needAuth) {
String authInfo;
if ((authInfo = (mheader.getHeaderValue("Proxy-Authorization") != null) ?
mheader.getHeaderValue("Proxy-Authorization").get(0) : null)
!= null) {
if (authenticate(authInfo)) {
needAuth = false;
System.out.println(
"Proxy: client authentication successful");
}
}
}
respondForConnect(needAuth);
// connection set to the tunneling mode
if (!needAuth) {
doTunnel();
/*
* done with tunneling, we process only one successful
* tunneling request
*/
ss.close();
} else {
// we may get another request with Proxy-Authorization set
in.close();
clientSocket.close();
restart();
}
} else {
System.out.println("proxy server: processes only "
+ "CONNECT method requests, recieved: "
+ statusLine);
}
}
private void respondForConnect(boolean needAuth) throws Exception {
OutputStream out = clientSocket.getOutputStream();
PrintWriter pout = new PrintWriter(out);
if (needAuth) {
pout.println("HTTP/1.1 407 Proxy Auth Required");
pout.println("Proxy-Authenticate: Basic realm=\"WallyWorld\"");
pout.println();
pout.flush();
out.close();
} else {
pout.println("HTTP/1.1 200 OK");
pout.println();
pout.flush();
}
}
private void restart() throws IOException {
(new Thread(this)).start();
}
/*
* note: Tunneling has to be provided in both directions, i.e
* from client->server and server->client, even if the application
* data may be unidirectional, SSL handshaking data flows in either
* direction.
*/
private void doTunnel() throws Exception {
Socket serverSocket = new Socket(serverInetAddr, serverPort);
ProxyTunnel clientToServer = new ProxyTunnel(
clientSocket, serverSocket);
ProxyTunnel serverToClient = new ProxyTunnel(
serverSocket, clientSocket);
clientToServer.start();
serverToClient.start();
System.out.println("Proxy: Started tunneling.......");
clientToServer.join();
serverToClient.join();
System.out.println("Proxy: Finished tunneling........");
clientToServer.close();
serverToClient.close();
}
/*
* This inner class provides unidirectional data flow through the sockets
* by continuously copying bytes from the input socket onto the output
* socket, until both sockets are open and EOF has not been received.
*/
class ProxyTunnel extends Thread {
Socket sockIn;
Socket sockOut;
InputStream input;
OutputStream output;
public ProxyTunnel(Socket sockIn, Socket sockOut)
throws Exception {
this.sockIn = sockIn;
this.sockOut = sockOut;
input = sockIn.getInputStream();
output = sockOut.getOutputStream();
setDaemon(true);
}
public void run() {
int BUFFER_SIZE = 400;
byte[] buf = new byte[BUFFER_SIZE];
int bytesRead = 0;
int count = 0; // keep track of the amount of data transfer
try {
while ((bytesRead = input.read(buf)) >= 0) {
output.write(buf, 0, bytesRead);
output.flush();
count += bytesRead;
}
} catch (IOException e) {
/*
* The peer end has closed the connection
* we will close the tunnel
*/
close();
}
}
public void close() {
try {
if (!sockIn.isClosed())
sockIn.close();
if (!sockOut.isClosed())
sockOut.close();
} catch (IOException ignored) { }
}
}
/*
***************************************************************
* helper methods follow
***************************************************************
*/
/*
* This method retrieves the hostname and port of the destination
* that the connect request wants to establish a tunnel for
* communication.
* The input, connectStr is of the form:
* CONNECT server-name:server-port HTTP/1.x
*/
private void retrieveConnectInfo(String connectStr) throws Exception {
int starti;
int endi;
String connectInfo;
String serverName = null;
try {
starti = connectStr.indexOf(' ');
endi = connectStr.lastIndexOf(' ');
connectInfo = connectStr.substring(starti+1, endi).trim();
// retrieve server name and port
endi = connectInfo.indexOf(':');
serverName = connectInfo.substring(0, endi);
serverPort = Integer.parseInt(connectInfo.substring(endi+1));
} catch (Exception e) {
throw new IOException("Proxy received a request: "
+ connectStr, e);
}
serverInetAddr = InetAddress.getByName(serverName);
}
public int getPort() {
return ss.getLocalPort();
}
public InetAddress getInetAddress() {
return ss.getInetAddress();
}
/*
* do "basic" authentication, authInfo is of the form:
* Basic <encoded username":"password>
* reference RFC 2617
*/
private boolean authenticate(String authInfo) throws IOException {
boolean matched = false;
try {
authInfo.trim();
int ind = authInfo.indexOf(' ');
String recvdUserPlusPass = authInfo.substring(ind + 1).trim();
// extract encoded (username:passwd
if (userPlusPass.equals(
new String( Base64.getMimeDecoder()
.decode(recvdUserPlusPass))))
{
matched = true;
}
} catch (Exception e) {
throw new IOException(
"Proxy received invalid Proxy-Authorization value: "
+ authInfo);
}
return matched;
}
}

View file

@ -0,0 +1,262 @@
/*
* Copyright (c) 2001, 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.
*/
//
// SunJSSE does not support dynamic system properties, no way to re-use
// system properties in samevm/agentvm mode.
//
/*
* @test
* @bug 4328195
* @summary Need to include the alternate subject DN for certs,
* https should check for this
* @modules java.base/sun.security.x509
* java.base/sun.security.util
* @library /javax/net/ssl/templates
* /test/lib
* @run main/othervm ServerIdentityTest dns localhost
* @run main/othervm ServerIdentityTest ip 127.0.0.1
*
* @author Yingxian Wang
*/
import static jdk.test.lib.Asserts.fail;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.math.BigInteger;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.Proxy;
import java.net.URL;
import java.net.UnknownHostException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.List;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.TrustManagerFactory;
import jdk.test.lib.security.CertificateBuilder;
import sun.security.x509.AuthorityKeyIdentifierExtension;
import sun.security.x509.GeneralName;
import sun.security.x509.GeneralNames;
import sun.security.x509.KeyIdentifier;
import sun.security.x509.SerialNumber;
import sun.security.x509.X500Name;
public final class ServerIdentityTest extends SSLSocketTemplate {
private static String hostname;
private static SSLContext serverContext;
/*
* Run the test case.
*/
public static void main(String[] args) throws Exception {
// Get the customized arguments.
initialize(args);
new ServerIdentityTest().run();
}
ServerIdentityTest() throws UnknownHostException {
serverAddress = InetAddress.getByName(hostname);
}
@Override
protected boolean isCustomizedClientConnection() {
return true;
}
@Override
protected void runServerApplication(SSLSocket socket) throws Exception {
InputStream sslIS = socket.getInputStream();
sslIS.read();
BufferedWriter bw = new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream()));
bw.write("HTTP/1.1 200 OK\r\n\r\n\r\n");
bw.flush();
socket.getSession().invalidate();
}
@Override
protected void runClientApplication(int serverPort) throws Exception {
URL url = new URL(
"https://" + hostname + ":" + serverPort + "/index.html");
HttpURLConnection urlc = null;
InputStream is = null;
try {
urlc = (HttpURLConnection) url.openConnection(Proxy.NO_PROXY);
is = urlc.getInputStream();
} finally {
if (is != null) {
is.close();
}
if (urlc != null) {
urlc.disconnect();
}
}
}
@Override
protected SSLContext createServerSSLContext() throws Exception {
return serverContext;
}
private static void initialize(String[] args) throws Exception {
String mode = args[0];
hostname = args[1];
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
KeyPair caKeys = kpg.generateKeyPair();
KeyPair serverKeys = kpg.generateKeyPair();
KeyPair clientKeys = kpg.generateKeyPair();
CertificateBuilder serverCertificateBuilder = customCertificateBuilder(
"CN=server, O=Some-Org, L=Some-City, ST=Some-State, C=US",
serverKeys.getPublic(), caKeys.getPublic())
.addBasicConstraintsExt(false, false, -1);
if (mode.equalsIgnoreCase("dns")) {
serverCertificateBuilder.addSubjectAltNameDNSExt(List.of(hostname));
} else if (mode.equalsIgnoreCase("ip")) {
serverCertificateBuilder.addSubjectAltNameIPExt(List.of(hostname));
} else {
fail("Unknown mode: " + mode);
}
X509Certificate trustedCert = createTrustedCert(caKeys);
X509Certificate serverCert = serverCertificateBuilder.build(
trustedCert, caKeys.getPrivate(), "SHA256WithRSA");
X509Certificate clientCert = customCertificateBuilder(
"CN=localhost, OU=SSL-Client, O=Some-Org, L=Some-City, ST=Some-State, C=US",
clientKeys.getPublic(), caKeys.getPublic())
.addBasicConstraintsExt(false, false, -1)
.build(trustedCert, caKeys.getPrivate(), "SHA256WithRSA");
serverContext = getSSLContext(
trustedCert, serverCert, serverKeys.getPrivate());
SSLContext clientContext = getSSLContext(
trustedCert, clientCert, clientKeys.getPrivate());
HttpsURLConnection.setDefaultSSLSocketFactory(
clientContext.getSocketFactory());
}
private static SSLContext getSSLContext(
X509Certificate trustedCertificate, X509Certificate keyCertificate,
PrivateKey privateKey)
throws Exception {
// create a key store
KeyStore ks = KeyStore.getInstance("PKCS12");
ks.load(null, null);
// import the trusted cert
ks.setCertificateEntry("TLS Signer", trustedCertificate);
// generate certificate chain
Certificate[] chain = new Certificate[2];
chain[0] = keyCertificate;
chain[1] = trustedCertificate;
// import the key entry.
final char[] passphrase = "passphrase".toCharArray();
ks.setKeyEntry("Whatever", privateKey, passphrase, chain);
// Using PKIX TrustManager
TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");
tmf.init(ks);
// Using PKIX KeyManager
KeyManagerFactory kmf = KeyManagerFactory.getInstance("PKIX");
// create SSL context
SSLContext ctx = SSLContext.getInstance("TLS");
kmf.init(ks, passphrase);
ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
return ctx;
}
private static X509Certificate createTrustedCert(KeyPair caKeys)
throws Exception {
SecureRandom random = new SecureRandom();
KeyIdentifier kid = new KeyIdentifier(caKeys.getPublic());
GeneralNames gns = new GeneralNames();
GeneralName name = new GeneralName(new X500Name(
"O=Some-Org, L=Some-City, ST=Some-State, C=US"));
gns.add(name);
BigInteger serialNumber = BigInteger.valueOf(
random.nextLong(1000000) + 1);
return customCertificateBuilder(
"O=Some-Org, L=Some-City, ST=Some-State, C=US",
caKeys.getPublic(), caKeys.getPublic())
.setSerialNumber(serialNumber)
.addExtension(new AuthorityKeyIdentifierExtension(kid, gns,
new SerialNumber(serialNumber)))
.addBasicConstraintsExt(true, true, -1)
.build(null, caKeys.getPrivate(), "SHA256WithRSA");
}
private static CertificateBuilder customCertificateBuilder(
String subjectName, PublicKey publicKey, PublicKey caKey)
throws CertificateException, IOException {
SecureRandom random = new SecureRandom();
CertificateBuilder builder = new CertificateBuilder()
.setSubjectName(subjectName)
.setPublicKey(publicKey)
.setNotBefore(
Date.from(Instant.now().minus(1, ChronoUnit.HOURS)))
.setNotAfter(Date.from(Instant.now().plus(1, ChronoUnit.HOURS)))
.setSerialNumber(
BigInteger.valueOf(random.nextLong(1000000) + 1))
.addSubjectKeyIdExt(publicKey)
.addAuthorityKeyIdExt(caKey);
builder.addKeyUsageExt(
new boolean[]{true, true, true, true, true, true});
return builder;
}
}

View file

@ -0,0 +1,218 @@
/*
* Copyright (c) 2005, 2021, 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.
*/
//
// SunJSSE does not support dynamic system properties, no way to re-use
// system properties in samevm/agentvm mode.
//
/*
* @test
* @bug 6216082
* @summary Redirect problem with HttpsURLConnection using a proxy
* @modules java.base/sun.net.www
* @library .. /test/lib
* @build jdk.test.lib.NetworkConfiguration
* jdk.test.lib.Platform
* ClosedChannelList
* TunnelProxy
* @key intermittent
* @run main/othervm B6216082
*/
import java.io.FileInputStream;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.NetworkInterface;
import java.net.ProxySelector;
import java.net.URL;
import java.security.KeyStore;
import java.util.Optional;
import java.util.concurrent.Executors;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManagerFactory;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpsConfigurator;
import com.sun.net.httpserver.HttpsServer;
import jdk.test.lib.NetworkConfiguration;
public class B6216082 {
static SimpleHttpTransaction httpTrans;
static HttpsServer server;
static TunnelProxy proxy;
// it seems there's no proxy ever if a url points to 'localhost',
// even if proxy related properties are set. so we need to bind
// our simple http proxy and http server to a non-loopback address
static InetAddress firstNonLoAddress = null;
public static void main(String[] args) throws Exception {
HostnameVerifier reservedHV =
HttpsURLConnection.getDefaultHostnameVerifier();
try {
// XXX workaround for CNFE
Class.forName("java.nio.channels.ClosedByInterruptException");
if (!setupEnv()) {
return;
}
startHttpServer();
// https.proxyPort can only be set after the TunnelProxy has been
// created as it will use an ephemeral port.
ProxySelector.setDefault(ProxySelector.of(new InetSocketAddress(firstNonLoAddress, proxy.getLocalPort())));
makeHttpCall();
} finally {
if (proxy != null) {
proxy.terminate();
}
if (server != null) {
server.stop(1);
}
HttpsURLConnection.setDefaultHostnameVerifier(reservedHV);
}
}
/*
* Where do we find the keystores for ssl?
*/
static String pathToStores = "../../../../../../javax/net/ssl/etc";
static String keyStoreFile = "keystore";
static String trustStoreFile = "truststore";
static String passwd = "passphrase";
public static boolean setupEnv() throws Exception {
firstNonLoAddress = getNonLoAddress();
if (firstNonLoAddress == null) {
System.err.println("The test needs at least one non-loopback address to run. Quit now.");
return false;
}
System.out.println(firstNonLoAddress.getHostAddress());
// will use proxy
System.setProperty( "https.proxyHost", firstNonLoAddress.getHostAddress());
// setup properties to do ssl
String keyFilename = System.getProperty("test.src", "./") + "/" +
pathToStores + "/" + keyStoreFile;
String trustFilename = System.getProperty("test.src", "./") + "/" +
pathToStores + "/" + trustStoreFile;
System.setProperty("javax.net.ssl.keyStore", keyFilename);
System.setProperty("javax.net.ssl.keyStorePassword", passwd);
System.setProperty("javax.net.ssl.trustStore", trustFilename);
System.setProperty("javax.net.ssl.trustStorePassword", passwd);
HttpsURLConnection.setDefaultHostnameVerifier(new NameVerifier());
return true;
}
public static InetAddress getNonLoAddress() throws Exception {
InetAddress lh = InetAddress.getByName("localhost");
NetworkInterface loNIC = NetworkInterface.getByInetAddress(lh);
NetworkConfiguration nc = NetworkConfiguration.probe();
Optional<InetAddress> oaddr = nc.interfaces()
.filter(nif -> !nif.getName().equalsIgnoreCase(loNIC.getName()))
.flatMap(nif -> nc.addresses(nif))
.filter(a -> !a.isLoopbackAddress())
.findFirst();
return oaddr.orElseGet(() -> null);
}
public static void startHttpServer() throws Exception {
// Both the https server and the proxy let the
// system pick up an ephemeral port.
httpTrans = new SimpleHttpTransaction();
// create and initialize a SSLContext
KeyStore ks = KeyStore.getInstance("JKS");
KeyStore ts = KeyStore.getInstance("JKS");
char[] passphrase = "passphrase".toCharArray();
ks.load(new FileInputStream(System.getProperty("javax.net.ssl.keyStore")), passphrase);
ts.load(new FileInputStream(System.getProperty("javax.net.ssl.trustStore")), passphrase);
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(ks, passphrase);
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(ts);
SSLContext sslCtx = SSLContext.getInstance("TLS");
sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
server = HttpsServer.create(new InetSocketAddress(firstNonLoAddress, 0), 10);
server.setHttpsConfigurator(new HttpsConfigurator(sslCtx));
server.createContext("/", httpTrans);
server.setExecutor(Executors.newSingleThreadExecutor());
server.start();
proxy = new TunnelProxy(1, 10, firstNonLoAddress, 0);
}
public static void makeHttpCall() throws Exception {
System.out.println("https server listen on: " + server.getAddress().getPort());
System.out.println("https proxy listen on: " + proxy.getLocalPort());
URL url = new URL("https" , firstNonLoAddress.getHostAddress(),
server.getAddress().getPort(), "/");
HttpURLConnection uc = (HttpURLConnection)url.openConnection();
System.out.println(uc.getResponseCode());
if(uc.getResponseCode() != 200) {
uc.disconnect();
throw new RuntimeException("Test failed : bad http request with response code : "+ uc.getResponseCode());
}
uc.disconnect();
}
static class NameVerifier implements HostnameVerifier {
public boolean verify(String hostname, SSLSession session) {
return true;
}
}
}
class SimpleHttpTransaction implements HttpHandler {
/*
* Our http server which simply redirect first call
*/
public void handle(HttpExchange trans) {
try {
String path = trans.getRequestURI().getPath();
if (path.equals("/")) {
// the first call, redirect it
String location = "/redirect";
trans.getResponseHeaders().set("Location", location);
trans.sendResponseHeaders(302, -1);
} else {
trans.sendResponseHeaders(200, -1);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}

View file

@ -0,0 +1,218 @@
/*
* Copyright (c) 2005, 2022, 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 6226610 6973030
* @summary HTTP tunnel connections send user headers to proxy
* @library /test/lib
* @run main/othervm B6226610
*/
/* This class includes a proxy server that processes the HTTP CONNECT request,
* and validates that the request does not have the user defined header in it.
* The proxy server always returns 400 Bad Request so that the Http client
* will not try to proceed with the connection as there is no back end http server.
*/
import java.io.*;
import java.net.*;
import jdk.test.lib.net.HttpHeaderParser;
public class B6226610 {
static HeaderCheckerProxyTunnelServer proxy;
public static void main(String[] args) throws Exception
{
proxy = new HeaderCheckerProxyTunnelServer();
proxy.start();
InetAddress localHost = InetAddress.getLocalHost();
String hostname = localHost.getHostName();
String hostAddress = localHost.getHostAddress();
try {
URL u = new URL("https://" + hostname + "/");
System.out.println("Connecting to " + u);
InetSocketAddress proxyAddr = InetSocketAddress.createUnresolved(hostAddress, proxy.getLocalPort());
java.net.URLConnection c = u.openConnection(new Proxy(Proxy.Type.HTTP, proxyAddr));
/* I want this header to go to the destination server only, protected
* by SSL
*/
c.setRequestProperty("X-TestHeader", "value");
c.connect();
} catch (IOException e) {
if ( e.getMessage().equals("Unable to tunnel through proxy. Proxy returns \"HTTP/1.1 400 Bad Request\"") )
{
// OK. Proxy will always return 400 so that the main thread can terminate correctly.
}
else
System.out.println(e);
} finally {
if (proxy != null) proxy.shutdown();
}
if (HeaderCheckerProxyTunnelServer.failed)
throw new RuntimeException("Test failed; see output");
}
}
class HeaderCheckerProxyTunnelServer extends Thread
{
public static boolean failed = false;
private static ServerSocket ss = null;
// client requesting for a tunnel
private Socket clientSocket = null;
/*
* Origin server's address and port that the client
* wants to establish the tunnel for communication.
*/
private InetAddress serverInetAddr;
private int serverPort;
public HeaderCheckerProxyTunnelServer() throws IOException
{
if (ss == null) {
ss = new ServerSocket();
ss.bind(new InetSocketAddress(InetAddress.getLocalHost(), 0));
}
}
void shutdown() {
try { ss.close(); } catch (IOException e) {}
}
public void run()
{
try {
clientSocket = ss.accept();
processRequests();
} catch (IOException e) {
System.out.println("Proxy Failed: " + e);
e.printStackTrace();
try {
ss.close();
}
catch (IOException excep) {
System.out.println("ProxyServer close error: " + excep);
excep.printStackTrace();
}
}
}
/**
* Returns the port on which the proxy is accepting connections.
*/
public int getLocalPort() {
return ss.getLocalPort();
}
/*
* Processes the CONNECT request
*/
private void processRequests() throws IOException
{
InputStream in = clientSocket.getInputStream();
HttpHeaderParser mheader = new HttpHeaderParser(in);
String statusLine = mheader.getRequestDetails();
if (statusLine.startsWith("CONNECT")) {
// retrieve the host and port info from the status-line
retrieveConnectInfo(statusLine);
if (mheader.getHeaderValue("X-TestHeader") != null) {
System.out.println("Proxy should not receive user defined headers for tunneled requests");
failed = true;
}
// 6973030
String value;
if ((value = mheader.getHeaderValue("Proxy-Connection").get(0)) == null ||
!value.equals("keep-alive")) {
System.out.println("Proxy-Connection:keep-alive not being sent");
failed = true;
}
//This will allow the main thread to terminate without trying to perform the SSL handshake.
send400();
in.close();
clientSocket.close();
ss.close();
}
else {
System.out.println("proxy server: processes only "
+ "CONNECT method requests, recieved: "
+ statusLine);
}
}
private void send400() throws IOException
{
OutputStream out = clientSocket.getOutputStream();
PrintWriter pout = new PrintWriter(out);
pout.println("HTTP/1.1 400 Bad Request");
pout.println();
pout.flush();
}
private void restart() throws IOException {
(new Thread(this)).start();
}
/*
* This method retrieves the hostname and port of the destination
* that the connect request wants to establish a tunnel for
* communication.
* The input, connectStr is of the form:
* CONNECT server-name:server-port HTTP/1.x
*/
private void retrieveConnectInfo(String connectStr) throws IOException {
int starti;
int endi;
String connectInfo;
String serverName = null;
try {
starti = connectStr.indexOf(' ');
endi = connectStr.lastIndexOf(' ');
connectInfo = connectStr.substring(starti+1, endi).trim();
// retrieve server name and port
endi = connectInfo.indexOf(':');
serverName = connectInfo.substring(0, endi);
serverPort = Integer.parseInt(connectInfo.substring(endi+1));
} catch (Exception e) {
throw new IOException("Proxy recieved a request: "
+ connectStr, e);
}
serverInetAddr = InetAddress.getByName(serverName);
}
}

View file

@ -0,0 +1,135 @@
/*
* Copyright (c) 2001, 2019, 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 4423074
* @summary Need to rebase all the duplicated classes from Merlin.
* This test will check out http POST
* @modules java.base/sun.net.www.protocol.https
*/
import java.net.*;
import java.util.*;
import java.lang.reflect.*;
import sun.net.www.protocol.https.HttpsURLConnectionImpl;
public class CheckMethods {
static boolean debug = false;
static class MethodSignature {
String name;
Class[] paramTypes;
MethodSignature(String name, Class[] paramTypes) {
this.name = name;
this.paramTypes = paramTypes;
}
public boolean equals(Object obj) {
if (debug)
System.out.println("comparing "+this +" against: "+obj);
if (!(obj instanceof MethodSignature)) {
if (debug)
System.out.println(false);
return false;
}
MethodSignature ms = (MethodSignature) obj;
Class[] types = ms.paramTypes;
try {
for (int i = 0; i < types.length; i++) {
if (!types[i].equals(paramTypes[i])) {
if (debug)
System.out.println(false);
return false;
}
}
} catch (Exception e) {
if (debug)
System.out.println(false);
return false;
}
boolean result = this.name.equals(ms.name);
if (debug)
System.out.println(result);
return result;
}
public String toString() {
StringBuffer sb = new StringBuffer(name+"(");
for (int i = 0; i < paramTypes.length; i++) {
sb.append(paramTypes[i].getName()+",");
if (i == (paramTypes.length -1))
sb.deleteCharAt(sb.length()-1);
}
sb.append(")");
return sb.toString();
}
}
// check HttpsURLConnectionImpl contain all public and protected methods
// defined in HttpURLConnection and URLConnection
public static void main(String[] args) {
ArrayList allMethods = new ArrayList(
Arrays.asList(HttpURLConnection.class.getDeclaredMethods()));
allMethods.addAll(Arrays.asList(URLConnection.class.getDeclaredMethods()));
ArrayList allMethodSignatures = new ArrayList();
for (Iterator itr = allMethods.iterator(); itr.hasNext(); ) {
Method m = (Method)itr.next();
// don't include static and private methods
if (!Modifier.isStatic(m.getModifiers()) &&
(Modifier.isPublic(m.getModifiers()) ||
Modifier.isProtected(m.getModifiers()))) {
allMethodSignatures.add(
new MethodSignature(m.getName(), m.getParameterTypes()));
}
}
// testing HttpsURLConnectionImpl
List httpsMethods =
Arrays.asList(HttpsURLConnectionImpl.class.getDeclaredMethods());
ArrayList httpsMethodSignatures = new ArrayList();
for (Iterator itr = httpsMethods.iterator(); itr.hasNext(); ) {
Method m = (Method)itr.next();
if (!Modifier.isStatic(m.getModifiers())) {
httpsMethodSignatures.add(
new MethodSignature(m.getName(), m.getParameterTypes()));
}
}
if (!httpsMethodSignatures.containsAll(allMethodSignatures)) {
throw new RuntimeException("Method definition test failed on HttpsURLConnectionImpl");
}
// testing for non static public field
ArrayList allFields = new ArrayList(
Arrays.asList(URLConnection.class.getFields()));
allFields.addAll(Arrays.asList(HttpURLConnection.class.getFields()));
for (Iterator itr = allFields.iterator(); itr.hasNext(); ) {
Field f = (Field) itr.next();
if (!Modifier.isStatic(f.getModifiers())) {
throw new RuntimeException("Non static Public fields" +
" declared in superclasses");
}
}
}
}

View file

@ -0,0 +1,314 @@
/*
* Copyright (c) 2008, 2011, 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 6618387
* @summary SSL client sessions do not close cleanly. A TCP reset occurs
* instead of a close_notify alert.
* @run main/othervm CloseKeepAliveCached
*
* SunJSSE does not support dynamic system properties, no way to re-use
* system properties in samevm/agentvm mode.
*
* @ignore
* After run the test manually, at the end of the debug output,
* if "MainThread, called close()" found, the test passed. Otherwise,
* if "Keep-Alive-Timer: called close()", the test failed.
*/
import java.net.*;
import java.util.*;
import java.io.*;
import javax.net.ssl.*;
public class CloseKeepAliveCached {
static Map cookies;
ServerSocket ss;
/*
* =============================================================
* Set the various variables needed for the tests, then
* specify what tests to run on each side.
*/
/*
* Should we run the client or server in a separate thread?
* Both sides can throw exceptions, but do you have a preference
* as to which side should be the main thread.
*/
static boolean separateServerThread = true;
/*
* Where do we find the keystores?
*/
static String pathToStores = "../../../../../../javax/net/ssl/etc";
static String keyStoreFile = "keystore";
static String trustStoreFile = "truststore";
static String passwd = "passphrase";
/*
* Is the server ready to serve?
*/
volatile static boolean serverReady = false;
/*
* Turn on SSL debugging?
*/
static boolean debug = false;
private SSLServerSocket sslServerSocket = null;
/*
* Define the server side of the test.
*
* If the server prematurely exits, serverReady will be set to true
* to avoid infinite hangs.
*/
void doServerSide() throws Exception {
SSLServerSocketFactory sslssf =
(SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
sslServerSocket =
(SSLServerSocket) sslssf.createServerSocket(serverPort);
serverPort = sslServerSocket.getLocalPort();
/*
* Signal Client, we're ready for his connect.
*/
serverReady = true;
SSLSocket sslSocket = null;
try {
sslSocket = (SSLSocket) sslServerSocket.accept();
for (int i = 0; i < 3 && !sslSocket.isClosed(); i++) {
// read request
InputStream is = sslSocket.getInputStream ();
BufferedReader r = new BufferedReader(
new InputStreamReader(is));
String x;
while ((x=r.readLine()) != null) {
if (x.length() ==0) {
break;
}
}
PrintStream out = new PrintStream(
new BufferedOutputStream(
sslSocket.getOutputStream() ));
/* send the header */
out.print("HTTP/1.1 200 OK\r\n");
out.print("Keep-Alive: timeout=15, max=100\r\n");
out.print("Connection: Keep-Alive\r\n");
out.print("Content-Type: text/html; charset=iso-8859-1\r\n");
out.print("Content-Length: 9\r\n");
out.print("\r\n");
out.print("Testing\r\n");
out.flush();
Thread.sleep(50);
}
sslSocket.close();
sslServerSocket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/*
* Define the client side of the test.
*
* If the server prematurely exits, serverReady will be set to true
* to avoid infinite hangs.
*/
void doClientSide() throws Exception {
/*
* Wait for server to get started.
*/
while (!serverReady) {
Thread.sleep(50);
}
HostnameVerifier reservedHV =
HttpsURLConnection.getDefaultHostnameVerifier();
try {
HttpsURLConnection http = null;
/* establish http connection to server */
URL url = new URL("https://localhost:" + serverPort+"/");
HttpsURLConnection.setDefaultHostnameVerifier(new NameVerifier());
http = (HttpsURLConnection)url.openConnection();
InputStream is = http.getInputStream ();
while (is.read() != -1);
is.close();
url = new URL("https://localhost:" + serverPort+"/");
http = (HttpsURLConnection)url.openConnection();
is = http.getInputStream ();
while (is.read() != -1);
// if inputstream.close() called, the http.disconnect() will
// not able to close the cached connection. If application
// wanna close the keep-alive cached connection immediately
// with httpURLConnection.disconnect(), they should not call
// inputstream.close() explicitly, the
// httpURLConnection.disconnect() will do it internally.
// is.close();
// close the connection, sending close_notify to peer.
// otherwise, the connection will be closed by Finalizer or
// Keep-Alive-Timer if timeout.
http.disconnect();
// Thread.sleep(5000);
} catch (IOException ioex) {
if (sslServerSocket != null)
sslServerSocket.close();
throw ioex;
} finally {
HttpsURLConnection.setDefaultHostnameVerifier(reservedHV);
}
}
static class NameVerifier implements HostnameVerifier {
public boolean verify(String hostname, SSLSession session) {
return true;
}
}
/*
* =============================================================
* The remainder is just support stuff
*/
// use any free port by default
volatile int serverPort = 0;
volatile Exception serverException = null;
volatile Exception clientException = null;
public static void main(String args[]) throws Exception {
String keyFilename =
System.getProperty("test.src", "./") + "/" + pathToStores +
"/" + keyStoreFile;
String trustFilename =
System.getProperty("test.src", "./") + "/" + pathToStores +
"/" + trustStoreFile;
System.setProperty("javax.net.ssl.keyStore", keyFilename);
System.setProperty("javax.net.ssl.keyStorePassword", passwd);
System.setProperty("javax.net.ssl.trustStore", trustFilename);
System.setProperty("javax.net.ssl.trustStorePassword", passwd);
if (debug)
System.setProperty("javax.net.debug", "all");
/*
* Start the tests.
*/
new CloseKeepAliveCached();
}
Thread clientThread = null;
Thread serverThread = null;
/*
* Primary constructor, used to drive remainder of the test.
*
* Fork off the other side, then do your work.
*/
CloseKeepAliveCached() throws Exception {
if (separateServerThread) {
startServer(true);
startClient(false);
} else {
startClient(true);
startServer(false);
}
/*
* Wait for other side to close down.
*/
if (separateServerThread) {
serverThread.join();
} else {
clientThread.join();
}
/*
* When we get here, the test is pretty much over.
*
* If the main thread excepted, that propagates back
* immediately. If the other thread threw an exception, we
* should report back.
*/
if (serverException != null)
throw serverException;
if (clientException != null)
throw clientException;
}
void startServer(boolean newThread) throws Exception {
if (newThread) {
serverThread = new Thread() {
public void run() {
try {
doServerSide();
} catch (Exception e) {
/*
* Our server thread just died.
*
* Release the client, if not active already...
*/
System.err.println("Server died...");
serverReady = true;
serverException = e;
}
}
};
serverThread.start();
} else {
doServerSide();
}
}
void startClient(boolean newThread) throws Exception {
if (newThread) {
clientThread = new Thread() {
public void run() {
try {
doClientSide();
} catch (Exception e) {
/*
* Our client thread just died.
*/
System.err.println("Client died...");
clientException = e;
}
}
};
clientThread.start();
} else {
doClientSide();
}
}
}

View file

@ -0,0 +1,342 @@
/*
* Copyright (c) 2003, 2019, 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 4696506 4942650
* @summary Unit test for java.net.CookieHandler
* @library /test/lib
* @run main/othervm CookieHandlerTest
*
* SunJSSE does not support dynamic system properties, no way to re-use
* system properties in samevm/agentvm mode.
* @author Yingxian Wang
*/
import java.net.*;
import java.util.*;
import java.io.*;
import javax.net.ssl.*;
import jdk.test.lib.net.URIBuilder;
public class CookieHandlerTest {
static Map<String,String> cookies;
ServerSocket ss;
/*
* =============================================================
* Set the various variables needed for the tests, then
* specify what tests to run on each side.
*/
/*
* Should we run the client or server in a separate thread?
* Both sides can throw exceptions, but do you have a preference
* as to which side should be the main thread.
*/
static boolean separateServerThread = true;
/*
* Where do we find the keystores?
*/
static String pathToStores = "../../../../../../javax/net/ssl/etc";
static String keyStoreFile = "keystore";
static String trustStoreFile = "truststore";
static String passwd = "passphrase";
/*
* Is the server ready to serve?
*/
volatile static boolean serverReady = false;
/*
* Turn on SSL debugging?
*/
static boolean debug = false;
/*
* Define the server side of the test.
*
* If the server prematurely exits, serverReady will be set to true
* to avoid infinite hangs.
*/
void doServerSide() throws Exception {
InetAddress loopback = InetAddress.getLoopbackAddress();
SSLServerSocketFactory sslssf =
(SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
SSLServerSocket sslServerSocket =
(SSLServerSocket) sslssf.createServerSocket();
sslServerSocket.bind(new InetSocketAddress(loopback, serverPort));
serverPort = sslServerSocket.getLocalPort();
/*
* Signal Client, we're ready for his connect.
*/
serverReady = true;
SSLSocket sslSocket = null;
try {
sslSocket = (SSLSocket) sslServerSocket.accept();
// check request contains "Cookie"
InputStream is = sslSocket.getInputStream ();
BufferedReader r = new BufferedReader(new InputStreamReader(is));
boolean flag = false;
String x;
while ((x=r.readLine()) != null) {
if (x.length() ==0) {
break;
}
String header = "Cookie: ";
if (x.startsWith(header)) {
if (x.equals("Cookie: "+((String)cookies.get("Cookie")))) {
flag = true;
}
}
}
if (!flag) {
throw new RuntimeException("server should see cookie in request");
}
PrintStream out = new PrintStream(
new BufferedOutputStream(
sslSocket.getOutputStream() ));
/* send the header */
out.print("HTTP/1.1 200 OK\r\n");
out.print("Set-Cookie2: "+((String)cookies.get("Set-Cookie2")+"\r\n"));
out.print("Content-Type: text/html; charset=iso-8859-1\r\n");
out.print("Connection: close\r\n");
out.print("\r\n");
out.print("<HTML>");
out.print("<HEAD><TITLE>Testing cookie</TITLE></HEAD>");
out.print("<BODY>OK.</BODY>");
out.print("</HTML>");
out.flush();
sslSocket.close();
sslServerSocket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/*
* Define the client side of the test.
*
* If the server prematurely exits, serverReady will be set to true
* to avoid infinite hangs.
*/
void doClientSide() throws Exception {
/*
* Wait for server to get started.
*/
while (!serverReady) {
Thread.sleep(50);
}
HttpsURLConnection http = null;
/* establish http connection to server */
URL url = URIBuilder.newBuilder()
.scheme("https")
.loopback()
.port(serverPort)
.toURL();
HttpsURLConnection.setDefaultHostnameVerifier(new NameVerifier());
http = (HttpsURLConnection)url.openConnection();
int respCode = http.getResponseCode();
http.disconnect();
}
static class NameVerifier implements HostnameVerifier {
public boolean verify(String hostname, SSLSession session) {
return true;
}
}
/*
* =============================================================
* The remainder is just support stuff
*/
// use any free port by default
volatile int serverPort = 0;
volatile Exception serverException = null;
volatile Exception clientException = null;
public static void main(String args[]) throws Exception {
String keyFilename =
System.getProperty("test.src", "./") + "/" + pathToStores +
"/" + keyStoreFile;
String trustFilename =
System.getProperty("test.src", "./") + "/" + pathToStores +
"/" + trustStoreFile;
CookieHandler reservedCookieHandler = CookieHandler.getDefault();
HostnameVerifier reservedHV =
HttpsURLConnection.getDefaultHostnameVerifier();
try {
System.setProperty("javax.net.ssl.keyStore", keyFilename);
System.setProperty("javax.net.ssl.keyStorePassword", passwd);
System.setProperty("javax.net.ssl.trustStore", trustFilename);
System.setProperty("javax.net.ssl.trustStorePassword", passwd);
if (debug)
System.setProperty("javax.net.debug", "all");
/*
* Start the tests.
*/
cookies = new HashMap<String, String>();
cookies.put("Cookie",
"$Version=\"1\"; Customer=\"WILE_E_COYOTE\"; $Path=\"/acme\"");
cookies.put("Set-Cookie2",
"$Version=\"1\"; Part_Number=\"Riding_Rocket_0023\"; " +
"$Path=\"/acme/ammo\"; Part_Number=\"Rocket_Launcher_0001\"; "+
"$Path=\"/acme\"");
CookieHandler.setDefault(new MyCookieHandler());
new CookieHandlerTest();
} finally {
HttpsURLConnection.setDefaultHostnameVerifier(reservedHV);
CookieHandler.setDefault(reservedCookieHandler);
}
}
Thread clientThread = null;
Thread serverThread = null;
/*
* Primary constructor, used to drive remainder of the test.
*
* Fork off the other side, then do your work.
*/
CookieHandlerTest() throws Exception {
if (separateServerThread) {
startServer(true);
startClient(false);
} else {
startClient(true);
startServer(false);
}
/*
* Wait for other side to close down.
*/
if (separateServerThread) {
serverThread.join();
} else {
clientThread.join();
}
/*
* When we get here, the test is pretty much over.
*
* If the main thread excepted, that propagates back
* immediately. If the other thread threw an exception, we
* should report back.
*/
if (serverException != null)
throw serverException;
if (clientException != null)
throw clientException;
if (!getCalled || !putCalled) {
throw new RuntimeException ("Either get or put method is not called");
}
}
void startServer(boolean newThread) throws Exception {
if (newThread) {
serverThread = new Thread() {
public void run() {
try {
doServerSide();
} catch (Exception e) {
/*
* Our server thread just died.
*
* Release the client, if not active already...
*/
System.err.println("Server died...");
serverReady = true;
serverException = e;
}
}
};
serverThread.start();
} else {
doServerSide();
}
}
void startClient(boolean newThread) throws Exception {
if (newThread) {
clientThread = new Thread() {
public void run() {
try {
doClientSide();
} catch (Exception e) {
/*
* Our client thread just died.
*/
System.err.println("Client died...");
clientException = e;
}
}
};
clientThread.start();
} else {
doClientSide();
}
}
static boolean getCalled = false, putCalled = false;
static class MyCookieHandler extends CookieHandler {
public Map<String,List<String>>
get(URI uri, Map<String,List<String>> requestHeaders)
throws IOException {
getCalled = true;
// returns cookies[0]
// they will be include in request
Map<String,List<String>> map = new HashMap<>();
List<String> l = new ArrayList<>();
l.add(cookies.get("Cookie"));
map.put("Cookie",l);
return Collections.unmodifiableMap(map);
}
public void
put(URI uri, Map<String,List<String>> responseHeaders)
throws IOException {
putCalled = true;
// check response has cookies[1]
List<String> l = responseHeaders.get("Set-Cookie2");
String value = l.get(0);
if (!value.equals((String)cookies.get("Set-Cookie2"))) {
throw new RuntimeException("cookie should be available for handle to put into cache");
}
}
}
}

View file

@ -0,0 +1,361 @@
/*
* Copyright (c) 2012, 2019, 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.
*/
// SunJSSE does not support dynamic system properties, no way to re-use
// system properties in samevm/agentvm mode.
/*
* @test
* @bug 7129083
* @summary Cookiemanager does not store cookies if url is read
* before setting cookiemanager
* @library /test/lib
* @run main/othervm CookieHttpsClientTest
*/
import java.net.CookieHandler;
import java.net.CookieManager;
import java.net.CookiePolicy;
import java.net.InetAddress;
import java.net.URL;
import java.io.InputStream;
import java.io.IOException;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import jdk.test.lib.net.URIBuilder;
public class CookieHttpsClientTest {
static final int TIMEOUT = 10 * 1000;
static final String replyString = "HTTP/1.1 200 OK\r\n" +
"Set-Cookie: name=test\r\n" +
"Content-Length: 10\r\n\r\n" +
"1234567890";
/*
* =============================================================
* Set the various variables needed for the tests, then
* specify what tests to run on each side.
*/
/*
* Should we run the client or server in a separate thread?
* Both sides can throw exceptions, but do you have a preference
* as to which side should be the main thread.
*/
static boolean separateServerThread = true;
/*
* Where do we find the keystores?
*/
static String pathToStores = "../../../../../../javax/net/ssl/etc";
static String keyStoreFile = "keystore";
static String trustStoreFile = "truststore";
static String passwd = "passphrase";
/*
* Is the server ready to serve?
*/
volatile static boolean serverReady = false;
/*
* Turn on SSL debugging?
*/
static boolean debug = false;
/*
* Define the server side of the test.
*
* If the server prematurely exits, serverReady will be set to true
* to avoid infinite hangs.
*/
void doServerSide() throws Exception {
InetAddress loopback = InetAddress.getLoopbackAddress();
SSLServerSocketFactory sslssf =
(SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
SSLServerSocket sslServerSocket =
(SSLServerSocket) sslssf.createServerSocket(serverPort, 0, loopback);
serverPort = sslServerSocket.getLocalPort();
/*
* Signal Client, we're ready for his connect.
*/
serverReady = true;
SSLSocket sslSocket = null;
try {
sslSocket = (SSLSocket) sslServerSocket.accept();
sslSocket.setSoTimeout(TIMEOUT);
readOneRequest(sslSocket.getInputStream());
sslSocket.getOutputStream().write(replyString.getBytes());
readOneRequest(sslSocket.getInputStream());
sslSocket.getOutputStream().write(replyString.getBytes());
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (sslSocket != null) { sslSocket.close(); }
sslServerSocket.close();
} catch (IOException unused) { /* gulp!burp! */ }
}
}
/*
* Define the client side of the test.
*
* If the server prematurely exits, serverReady will be set to true
* to avoid infinite hangs.
*/
void doClientSide() throws Exception {
// Wait for server to get started.
while (!serverReady) {
Thread.sleep(50);
}
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}});
URL url = URIBuilder.newBuilder()
.scheme("https")
.loopback()
.port(serverPort)
.path("/")
.toURL();
System.out.println("Client ready to connect to: " + url);
// Run without a CookieHandler first
InputStream in = url.openConnection(java.net.Proxy.NO_PROXY).getInputStream();
while (in.read() != -1); // read response body so connection can be reused
// Set a CookeHandler and retest using the HttpClient from the KAC
CookieManager manager = new CookieManager(null, CookiePolicy.ACCEPT_ALL);
CookieHandler.setDefault(manager);
in = url.openConnection().getInputStream();
while (in.read() != -1);
if (manager.getCookieStore().getCookies().isEmpty()) {
throw new RuntimeException("Failed: No cookies in the cookie Handler.");
}
}
static final byte[] requestEnd = new byte[] {'\r', '\n', '\r', '\n' };
// Read until the end of a HTTP request
static void readOneRequest(InputStream is) throws IOException {
int requestEndCount = 0, r;
while ((r = is.read()) != -1) {
if (r == requestEnd[requestEndCount]) {
requestEndCount++;
if (requestEndCount == 4) {
break;
}
} else {
requestEndCount = 0;
}
}
}
/*
* =============================================================
* The remainder is just support stuff
*/
// use any free port by default
volatile int serverPort = 0;
volatile Exception serverException = null;
volatile Exception clientException = null;
private boolean sslConnectionFailed() {
return clientException instanceof SSLHandshakeException;
}
public static void main(String args[]) throws Exception {
String keyFilename =
System.getProperty("test.src", ".") + "/" + pathToStores +
"/" + keyStoreFile;
String trustFilename =
System.getProperty("test.src", ".") + "/" + pathToStores +
"/" + trustStoreFile;
System.setProperty("javax.net.ssl.keyStore", keyFilename);
System.setProperty("javax.net.ssl.keyStorePassword", passwd);
System.setProperty("javax.net.ssl.trustStore", trustFilename);
System.setProperty("javax.net.ssl.trustStorePassword", passwd);
if (debug)
System.setProperty("javax.net.debug", "all");
new CookieHttpsClientTest();
}
Thread clientThread = null;
Thread serverThread = null;
/*
* Primary constructor, used to drive remainder of the test.
*
* Fork off the other side, then do your work.
*/
CookieHttpsClientTest() throws Exception {
Exception startException = null;
try {
if (separateServerThread) {
startServer(true);
startClient(false);
} else {
startClient(true);
startServer(false);
}
} catch (Exception e) {
startException = e;
}
/*
* Wait for other side to close down.
*/
if (separateServerThread) {
if (serverThread != null) {
// don't join the server thread if the
// client failed to connect
if (!sslConnectionFailed()) {
serverThread.join();
}
}
} else {
if (clientThread != null) {
clientThread.join();
}
}
/*
* When we get here, the test is pretty much over.
* Which side threw the error?
*/
Exception local;
Exception remote;
if (separateServerThread) {
remote = serverException;
local = clientException;
} else {
remote = clientException;
local = serverException;
}
Exception exception = null;
/*
* Check various exception conditions.
*/
if ((local != null) && (remote != null)) {
// If both failed, return the curthread's exception.
local.addSuppressed(remote);
exception = local;
} else if (local != null) {
exception = local;
} else if (remote != null) {
exception = remote;
} else if (startException != null) {
exception = startException;
}
/*
* If there was an exception *AND* a startException,
* output it.
*/
if (exception != null) {
if (exception != startException && startException != null) {
exception.addSuppressed(startException);
}
throw exception;
}
// Fall-through: no exception to throw!
}
void startServer(boolean newThread) throws Exception {
if (newThread) {
serverThread = new Thread() {
public void run() {
try {
doServerSide();
} catch (Exception e) {
/*
* Our server thread just died.
*
* Release the client, if not active already...
*/
System.err.println("Server died...");
serverReady = true;
serverException = e;
}
}
};
serverThread.start();
} else {
try {
doServerSide();
} catch (Exception e) {
serverException = e;
} finally {
serverReady = true;
}
}
}
void startClient(boolean newThread) throws Exception {
if (newThread) {
clientThread = new Thread() {
public void run() {
try {
doClientSide();
} catch (Exception e) {
/*
* Our client thread just died.
*/
System.err.println("Client died: " + e);
clientException = e;
}
}
};
clientThread.start();
} else {
try {
doClientSide();
} catch (Exception e) {
System.err.println("Client died: " + e);
clientException = e;
}
}
}
}

View file

@ -0,0 +1,311 @@
/*
* Copyright (c) 2010, 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.
*/
//
// SunJSSE does not support dynamic system properties, no way to re-use
// system properties in samevm/agentvm mode.
//
/* @test id=tls12
* @bug 6766775
* @summary X509 certificate hostname checking is broken in JDK1.6.0_10
* @library /test/lib
* @run main/othervm DNSIdentities TLSv1.2 MD5withRSA
* @author Xuelei Fan
*/
/* @test id=tls13
* @bug 6766775
* @summary X509 certificate hostname checking is broken in JDK1.6.0_10
* @library /test/lib
* @run main/othervm DNSIdentities TLSv1.3 SHA256withRSA
* @author Xuelei Fan
*/
import jdk.test.lib.security.CertificateBuilder;
import jdk.test.lib.security.SecurityUtils;
import sun.security.x509.DNSName;
import sun.security.x509.GeneralName;
import sun.security.x509.GeneralNames;
import sun.security.x509.SubjectAlternativeNameExtension;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSocket;
import java.io.PrintStream;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URL;
import java.util.List;
public class DNSIdentities extends IdentitiesBase {
/*
* Should we run the client or server in a separate thread?
* Both sides can throw exceptions, but do you have a preference
* as to which side should be the main thread.
*/
static boolean separateServerThread = true;
/*
* Is the server ready to serve?
*/
volatile static boolean serverReady = false;
/*
* Is the connection ready to close?
*/
volatile static boolean closeReady = false;
/*
* Turn on SSL debugging?
*/
static boolean debug = false;
private SSLServerSocket sslServerSocket = null;
@Override
protected CertificateBuilder customizeServerCert(CertificateBuilder builder) throws Exception {
GeneralNames gns = new GeneralNames();
gns.add(new GeneralName(new DNSName("localhost")));
return builder.addExtension(new SubjectAlternativeNameExtension(true, gns));
}
@Override
protected CertificateBuilder customizeClientCert(CertificateBuilder builder) throws Exception {
GeneralNames gns = new GeneralNames();
gns.add(new GeneralName(new DNSName("localhost")));
return builder.addExtension(new SubjectAlternativeNameExtension(true, gns));
}
/*
* Define the server side of the test.
*
* If the server prematurely exits, serverReady will be set to true
* to avoid infinite hangs.
*/
void doServerSide() throws Exception {
SSLContext context = getServerSSLContext();
SSLServerSocketFactory sslssf = context.getServerSocketFactory();
// doClientSide() connects to "localhost"
InetAddress localHost = InetAddress.getByName("localhost");
InetSocketAddress address = new InetSocketAddress(localHost, serverPort);
sslServerSocket =
(SSLServerSocket) sslssf.createServerSocket();
sslServerSocket.bind(address);
serverPort = sslServerSocket.getLocalPort();
/*
* Signal Client, we're ready for his connect.
*/
serverReady = true;
SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
sslSocket.setNeedClientAuth(true);
PrintStream out =
new PrintStream(sslSocket.getOutputStream());
try {
// ignore request data
// send the response
out.print("HTTP/1.1 200 OK\r\n");
out.print("Content-Type: text/html; charset=iso-8859-1\r\n");
out.print("Content-Length: "+ 9 +"\r\n");
out.print("\r\n");
out.print("Testing\r\n");
out.flush();
} finally {
// close the socket
while (!closeReady) {
Thread.sleep(50);
}
System.out.println("Server closing socket");
sslSocket.close();
serverReady = false;
}
}
/*
* Define the client side of the test.
*
* If the server prematurely exits, serverReady will be set to true
* to avoid infinite hangs.
*/
void doClientSide() throws Exception {
SSLContext reservedSSLContext = SSLContext.getDefault();
try {
SSLContext context = getClientSSLContext();
SSLContext.setDefault(context);
/*
* Wait for server to get started.
*/
while (!serverReady) {
Thread.sleep(50);
}
HttpsURLConnection http = null;
/* establish http connection to server */
URL url = new URL("https://localhost:" + serverPort+"/");
System.out.println("url is "+url.toString());
try {
http = (HttpsURLConnection)url.openConnection(Proxy.NO_PROXY);
int respCode = http.getResponseCode();
System.out.println("respCode = "+respCode);
} finally {
if (http != null) {
http.disconnect();
}
closeReady = true;
}
} finally {
SSLContext.setDefault(reservedSSLContext);
}
}
/*
* =============================================================
* The remainder is just support stuff
*/
// use any free port by default
volatile int serverPort = 0;
volatile Exception serverException = null;
volatile Exception clientException = null;
public static void main(String [] args) throws Exception {
if (args[1].contains("MD5")) {
SecurityUtils.removeFromDisabledAlgs(
"jdk.certpath.disabledAlgorithms", List.of("MD5"));
SecurityUtils.removeFromDisabledTlsAlgs("MD5");
}
if (debug)
System.setProperty("javax.net.debug", "all");
/*
* Start the tests.
*/
new DNSIdentities(args[0], args[1]);
}
Thread clientThread = null;
Thread serverThread = null;
/*
* Primary constructor, used to drive remainder of the test.
*
* Fork off the other side, then do your work.
*/
DNSIdentities(String protocol, String signatureAlg) throws Exception {
super(protocol, signatureAlg);
if (separateServerThread) {
startServer(true);
startClient(false);
} else {
startClient(true);
startServer(false);
}
/*
* Wait for other side to close down.
*/
if (separateServerThread) {
serverThread.join();
} else {
clientThread.join();
}
/*
* When we get here, the test is pretty much over.
*
* If the main thread excepted, that propagates back
* immediately. If the other thread threw an exception, we
* should report back.
*/
if (serverException != null)
throw serverException;
if (clientException != null)
throw clientException;
}
void startServer(boolean newThread) throws Exception {
if (newThread) {
serverThread = new Thread() {
public void run() {
try {
doServerSide();
} catch (Exception e) {
/*
* Our server thread just died.
*
* Release the client, if not active already...
*/
System.err.println("Server died...");
serverReady = true;
serverException = e;
}
}
};
serverThread.start();
} else {
doServerSide();
}
}
void startClient(boolean newThread) throws Exception {
if (newThread) {
clientThread = new Thread() {
public void run() {
try {
doClientSide();
} catch (Exception e) {
/*
* Our client thread just died.
*/
System.err.println("Client died...");
clientException = e;
}
}
};
clientThread.start();
} else {
doClientSide();
}
}
}

View file

@ -0,0 +1,302 @@
/*
* Copyright (c) 2026, 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 8376031
* @modules jdk.httpserver
* @library /test/lib
* @summary Ensure HttpsURLConnection::getServerCertificates does not
* throw after calling getResponseCode() if the response doesn't have
* a body.
* @run main/othervm ${test.main.class}
* @run main/othervm -Djava.net.preferIPv6Addresses=true ${test.main.class}
*/
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import com.sun.net.httpserver.HttpsConfigurator;
import com.sun.net.httpserver.HttpsServer;
import jdk.test.lib.net.SimpleSSLContext;
import jdk.test.lib.net.URIBuilder;
import static com.sun.net.httpserver.HttpExchange.RSPBODY_EMPTY;
public class GetServerCertificates {
static final String URI_PATH = "/GetServerCertificates/";
static final String BODY = "Go raibh maith agat";
enum TESTS {
HEAD("head", 200, "HEAD"),
NOBODY("nobody", 200, "GET", "POST"),
S204("204", 204, "GET", "POST"),
S304("304", 304, "GET", "POST"),
S200("200", 200, "GET", "POST");
final String test;
final int code;
final List<String> methods;
private TESTS(String test, int code, String... methods) {
this.test = test;
this.code = code;
this.methods = List.of(methods);
}
boolean isFor(String path) {
return path != null && path.endsWith("/" + test);
}
String test() { return test; }
int code() { return code; }
List<String> methods() { return methods; }
static Optional<TESTS> fromPath(String path) {
return Stream.of(values())
.filter(test -> test.isFor(path))
.findFirst();
}
}
void test(String[] args) throws Exception {
SSLContext.setDefault(SimpleSSLContext.findSSLContext());
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
HttpServer server = startHttpServer();
try {
InetSocketAddress address = server.getAddress();
URI uri = URIBuilder.newBuilder()
.scheme("https")
.host(address.getAddress())
.port(address.getPort())
.path(URI_PATH)
.build();
for (var test : TESTS.values()) {
for (String method : test.methods()) {
doClient(method, uri, test);
}
}
} finally {
server.stop(1000);
}
}
void doClient(String method, URI baseUri, TESTS test) throws Exception {
assert baseUri.getRawQuery() == null;
assert baseUri.getRawFragment() == null;
assert test.methods().contains(method);
String uriStr = baseUri.toString();
if (!uriStr.endsWith("/")) uriStr = uriStr + "/";
URI uri = new URI(uriStr + test.test());
assert uri.toString().endsWith("/" + test.test());
int code = test.code();
System.out.println("doClient(%s, %s, %s)"
.formatted(method, test.test(), test.code));
// first request - should create a TCP connection
HttpsURLConnection uc = (HttpsURLConnection)
uri.toURL().openConnection(Proxy.NO_PROXY);
if (!"GET".equals(method)) {
uc.setRequestMethod(method);
}
try {
uc.getServerCertificates();
throw new AssertionError("Expected IllegalStateException not thrown");
} catch (IllegalStateException ise) {
System.out.println("Got expected ISE: " + ise);
}
int resp = uc.getResponseCode();
check(resp == code, "Unexpected response code. Expected %s, got %s"
.formatted(code, resp));
check(uc.getServerCertificates());
if (test == TESTS.S200) {
byte[] bytes = uc.getInputStream().readAllBytes();
String body = new String(bytes, StandardCharsets.UTF_8);
System.out.println("body: " + body);
check(BODY.equals(body), "Unexpected response body. Expected \"%s\", got \"%s\""
.formatted(BODY, body));
}
// second request - should go on the same TCP connection.
// We don't have a reliable way to test that, and it could
// go on a new TCP connection if the previous connection
// was already closed. It is not an issue either way.
uc = (HttpsURLConnection)
uri.toURL().openConnection(Proxy.NO_PROXY);
if (!"GET".equals(method)) {
uc.setRequestMethod(method);
}
try {
uc.getServerCertificates();
throw new AssertionError("Expected IllegalStateException not thrown");
} catch (IllegalStateException ise) {
System.out.println("Got expected ISE: " + ise);
}
resp = uc.getResponseCode();
check(resp == code, "Unexpected response code. Expected %s, got %s"
.formatted(code, resp));
check(uc.getServerCertificates());
if (test == TESTS.S200) {
byte[] bytes = uc.getInputStream().readAllBytes();
String body = new String(bytes, StandardCharsets.UTF_8);
System.out.println("body: " + body);
check(BODY.equals(body), "Unexpected response body. Expected \"%s\", got \"%s\""
.formatted(BODY, body));
}
uc.disconnect();
try {
uc.getServerCertificates();
throw new AssertionError("Expected IllegalStateException not thrown");
} catch (IllegalStateException ise) {
System.out.println("Got expected ISE: " + ise);
}
// third request - forces the connection to close
// after use so that we don't find any connection in the pool
// for the next test case, assuming there was only
// one connection in the first place.
// Again there's no easy way to verify that the pool
// is empty (and it's not really necessary to bother)
uc = (HttpsURLConnection)
uri.toURL().openConnection(Proxy.NO_PROXY);
if (!"GET".equals(method)) {
uc.setRequestMethod(method);
}
uc.setRequestProperty("Connection", "close");
try {
uc.getServerCertificates();
throw new AssertionError("Expected IllegalStateException not thrown");
} catch (IllegalStateException ise) {
System.out.println("Got expected ISE: " + ise);
}
resp = uc.getResponseCode();
check(resp == code, "Unexpected response code. Expected %s, got %s"
.formatted(code, resp));
check(uc.getServerCertificates());
uc.disconnect();
try {
uc.getServerCertificates();
throw new AssertionError("Expected IllegalStateException not thrown");
} catch (IllegalStateException ise) {
System.out.println("Got expected ISE: " + ise);
}
}
// HTTP Server
HttpServer startHttpServer() throws IOException {
InetAddress localhost = InetAddress.getLoopbackAddress();
HttpsServer httpServer = HttpsServer
.create(new InetSocketAddress(localhost, 0), 0);
var configurator = new HttpsConfigurator(SimpleSSLContext.findSSLContext());
httpServer.setHttpsConfigurator(configurator);
httpServer.createContext(URI_PATH, new SimpleHandler());
httpServer.start();
return httpServer;
}
static class SimpleHandler implements HttpHandler {
@Override
public void handle(HttpExchange t) throws IOException {
try {
String path = t.getRequestURI().getRawPath();
var test = TESTS.fromPath(path);
if (!path.startsWith(URI_PATH) || !test.isPresent()) {
t.getRequestBody().close();
t.getResponseHeaders().add("Connection", "close");
t.sendResponseHeaders(421, RSPBODY_EMPTY);
t.close();
return;
}
try (var is = t.getRequestBody()) {
is.readAllBytes();
}
switch (test.get()) {
case S204, S304, NOBODY ->
t.sendResponseHeaders(test.get().code(), RSPBODY_EMPTY);
case S200 -> {
byte[] bytes = BODY.getBytes(StandardCharsets.UTF_8);
t.sendResponseHeaders(test.get().code(), bytes.length);
try (var os = t.getResponseBody()) {
os.write(bytes);
}
}
case HEAD -> {
assert t.getRequestMethod().equals("HEAD");
byte[] bytes = BODY.getBytes(StandardCharsets.UTF_8);
t.sendResponseHeaders(test.get().code(), bytes.length);
}
}
t.close();
} catch (Throwable error) {
error.printStackTrace();
throw error;
}
}
}
volatile int passed = 0, failed = 0;
boolean debug = false;
void pass() {passed++;}
void fail() {failed++;}
void fail(String msg) {System.err.println(msg); fail();}
void unexpected(Throwable t) {failed++; t.printStackTrace();}
void debug(String message) { if (debug) System.out.println(message); }
void check(boolean cond, String failMessage) {if (cond) pass(); else fail(failMessage);}
void check(java.security.cert.Certificate[] certs) {
// Use List.of to check that certs is not null and does not
// contain null. NullPointerException will be thrown here
// if that happens, which will make the test fail.
check(!List.of(certs).isEmpty(), "no certificates returned");
}
public static void main(String[] args) throws Throwable {
Class<?> k = new Object(){}.getClass().getEnclosingClass();
try {k.getMethod("instanceMain",String[].class)
.invoke( k.newInstance(), (Object) args);}
catch (Throwable e) {throw e.getCause();}}
public void instanceMain(String[] args) throws Throwable {
try {test(args);} catch (Throwable t) {unexpected(t);}
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
if (failed > 0) throw new AssertionError("Some tests failed");}
}

View file

@ -0,0 +1,228 @@
/*
* Copyright (c) 2010, 2019, 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 6771432
* @summary createSocket() - smpatch fails using 1.6.0_10 because of
* "Unconnected sockets not implemented"
* @modules jdk.httpserver
* @library /test/lib
* @run main/othervm HttpsCreateSockTest
* @run main/othervm -Djava.net.preferIPv6Addresses=true HttpsCreateSockTest
*
* SunJSSE does not support dynamic system properties, no way to re-use
* system properties in samevm/agentvm mode.
*/
import javax.net.SocketFactory;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import java.security.NoSuchAlgorithmException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.Socket;
import java.net.URL;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpsConfigurator;
import jdk.test.lib.net.URIBuilder;
/*
* This class tests that the HTTPS protocol handler is using its socket factory for
* creating new Sockets. It does this by wrapping the default SSLSocketFactory with
* its own socket factory, SimpleSSLSocketFactory, and verifying that when a https
* connection is made one of the socket factories createSocket methods, that
* actually creates a Socket, is being invoked by the protocol handler.
*/
public class HttpsCreateSockTest
{
/*
* Where do we find the keystores?
*/
static String pathToStores = "../../../../../../javax/net/ssl/etc";
static String keyStoreFile = "keystore";
static String trustStoreFile = "truststore";
static String passwd = "passphrase";
com.sun.net.httpserver.HttpsServer httpsServer;
MyHandler httpHandler;
public static void main(String[] args) {
String keyFilename =
System.getProperty("test.src", "./") + "/" + pathToStores +
"/" + keyStoreFile;
String trustFilename =
System.getProperty("test.src", "./") + "/" + pathToStores +
"/" + trustStoreFile;
System.setProperty("javax.net.ssl.keyStore", keyFilename);
System.setProperty("javax.net.ssl.keyStorePassword", passwd);
System.setProperty("javax.net.ssl.trustStore", trustFilename);
System.setProperty("javax.net.ssl.trustStorePassword", passwd);
new HttpsCreateSockTest();
}
public HttpsCreateSockTest() {
try {
startHttpsServer();
doClient();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (IOException ioe) {
ioe.printStackTrace();
} finally {
httpsServer.stop(1);
}
}
void doClient() throws IOException {
InetSocketAddress address = httpsServer.getAddress();
URL url = URIBuilder.newBuilder()
.scheme("https")
.host(address.getAddress())
.port(address.getPort())
.path("/")
.toURLUnchecked();
System.out.println("trying to connect to " + url + "...");
HttpsURLConnection uc = (HttpsURLConnection) url.openConnection(Proxy.NO_PROXY);
uc.setHostnameVerifier(new AllHostnameVerifier());
if (uc instanceof javax.net.ssl.HttpsURLConnection) {
((javax.net.ssl.HttpsURLConnection) uc).setSSLSocketFactory(new SimpleSSLSocketFactory());
System.out.println("Using TestSocketFactory");
}
uc.connect();
System.out.println("CONNECTED " + uc);
System.out.println(uc.getResponseMessage());
uc.disconnect();
}
/**
* Https Server
*/
public void startHttpsServer() throws IOException, NoSuchAlgorithmException {
InetAddress loopback = InetAddress.getLoopbackAddress();
InetSocketAddress address = new InetSocketAddress(loopback, 0);
httpsServer = com.sun.net.httpserver.HttpsServer.create(address, 0);
httpsServer.createContext("/", new MyHandler());
httpsServer.setHttpsConfigurator(new HttpsConfigurator(SSLContext.getDefault()));
httpsServer.start();
}
class MyHandler implements HttpHandler {
private String message = "This is a message!";
@Override
public void handle(HttpExchange t) throws IOException {
t.sendResponseHeaders(200, message.length());
BufferedWriter writer = new BufferedWriter( new OutputStreamWriter(t.getResponseBody(), "ISO8859-1"));
writer.write(message, 0, message.length());
writer.close();
t.close();
}
}
/**
* Simple wrapper on default SSLSocketFactory
*/
class SimpleSSLSocketFactory extends SSLSocketFactory
{
/*
* true if this factory has been used to create a new Socket, i.e.
* one of the SocketFactory methods has been called.
*/
boolean socketCreated = false;
/*
* true if this factory has been used to wrap a Socket, i.e.
* the SSLSocketFactory method,
* createSocket(Socket, String, int, boolean), has been called.
*/
boolean socketWrapped = false;
@Override
public Socket createSocket(InetAddress host, int port) throws IOException {
socketCreated = true;
return SocketFactory.getDefault().createSocket(host, port);
}
@Override
public Socket createSocket(InetAddress address, int port, InetAddress localAddress,
int localPort) throws IOException {
socketCreated = true;
return SocketFactory.getDefault().createSocket(address, port, localAddress, localPort);
}
@Override
public Socket createSocket(String host, int port) throws IOException {
socketCreated = true;
return SocketFactory.getDefault().createSocket(host, port);
}
@Override
public Socket createSocket(String host, int port, InetAddress localHost,
int localPort) throws IOException {
socketCreated = true;
return SocketFactory.getDefault().createSocket(host, port, localHost, localPort);
}
// methods from SSLSocketFactory
@Override
public Socket createSocket(Socket s, String host, int port,
boolean autoClose) throws IOException {
socketWrapped = true;
return ((SSLSocketFactory) SSLSocketFactory.getDefault()).createSocket
(s, host, port, autoClose);
}
@Override
public String[] getDefaultCipherSuites() {
return ((SSLSocketFactory) SSLSocketFactory.getDefault()).getDefaultCipherSuites();
}
@Override
public String[] getSupportedCipherSuites() {
return ((SSLSocketFactory) SSLSocketFactory.getDefault()).getSupportedCipherSuites();
}
}
class AllHostnameVerifier implements HostnameVerifier
{
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
}
}

View file

@ -0,0 +1,316 @@
/*
* Copyright (c) 2001, 2019, 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 4423074
* @summary Need to rebase all the duplicated classes from Merlin.
* This test will check out http POST
* @library /test/lib
* @run main/othervm HttpsPost
* @run main/othervm -Djava.net.preferIPv6Addresses=true HttpsPost
*
* SunJSSE does not support dynamic system properties, no way to re-use
* system properties in samevm/agentvm mode.
*/
import java.io.*;
import java.net.*;
import javax.net.ssl.*;
import jdk.test.lib.net.URIBuilder;
public class HttpsPost {
/*
* =============================================================
* Set the various variables needed for the tests, then
* specify what tests to run on each side.
*/
/*
* Should we run the client or server in a separate thread?
* Both sides can throw exceptions, but do you have a preference
* as to which side should be the main thread.
*/
static boolean separateServerThread = true;
/*
* Where do we find the keystores?
*/
static String pathToStores = "../../../../../../javax/net/ssl/etc";
static String keyStoreFile = "keystore";
static String trustStoreFile = "truststore";
static String passwd = "passphrase";
/*
* Is the server ready to serve?
*/
volatile static boolean serverReady = false;
/*
* Is the connection ready to close?
*/
volatile static boolean closeReady = false;
/*
* Turn on SSL debugging?
*/
static boolean debug = false;
/*
* Message posted
*/
static String postMsg = "Testing HTTP post on a https server";
/*
* If the client or server is doing some kind of object creation
* that the other side depends on, and that thread prematurely
* exits, you may experience a hang. The test harness will
* terminate all hung threads after its timeout has expired,
* currently 3 minutes by default, but you might try to be
* smart about it....
*/
/*
* Define the server side of the test.
*
* If the server prematurely exits, serverReady will be set to true
* to avoid infinite hangs.
*/
void doServerSide() throws Exception {
InetAddress loopback = InetAddress.getLoopbackAddress();
SSLServerSocketFactory sslssf =
(SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
SSLServerSocket sslServerSocket =
(SSLServerSocket) sslssf.createServerSocket(serverPort, 0, loopback);
serverPort = sslServerSocket.getLocalPort();
System.out.println("Starting server at: "
+ sslServerSocket.getInetAddress()
+ ":" + serverPort);
/*
* Signal Client, we're ready for his connect.
*/
serverReady = true;
SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
try {
InputStream sslIS = sslSocket.getInputStream();
OutputStream sslOS = sslSocket.getOutputStream();
BufferedReader br =
new BufferedReader(new InputStreamReader(sslIS));
PrintStream ps = new PrintStream(sslOS);
// process HTTP POST request from client
System.out.println("status line: "+br.readLine());
String msg = null;
while ((msg = br.readLine()) != null && msg.length() > 0);
msg = br.readLine();
if (msg.equals(postMsg)) {
ps.println("HTTP/1.1 200 OK\n\n");
} else {
ps.println("HTTP/1.1 500 Not OK\n\n");
}
ps.flush();
// close the socket
while (!closeReady) {
Thread.sleep(50);
}
} finally {
sslSocket.close();
sslServerSocket.close();
}
}
/*
* Define the client side of the test.
*
* If the server prematurely exits, serverReady will be set to true
* to avoid infinite hangs.
*/
void doClientSide() throws Exception {
HostnameVerifier reservedHV =
HttpsURLConnection.getDefaultHostnameVerifier();
try {
/*
* Wait for server to get started.
*/
while (!serverReady) {
Thread.sleep(50);
}
// Send HTTP POST request to server
URL url = URIBuilder.newBuilder()
.scheme("https")
.loopback()
.port(serverPort)
.toURL();
System.out.println("Client connecting to: " + url);
HttpsURLConnection.setDefaultHostnameVerifier(new NameVerifier());
HttpsURLConnection http = (HttpsURLConnection)url.openConnection(Proxy.NO_PROXY);
http.setDoOutput(true);
http.setRequestMethod("POST");
PrintStream ps = new PrintStream(http.getOutputStream());
try {
ps.println(postMsg);
ps.flush();
if (http.getResponseCode() != 200) {
throw new RuntimeException("test Failed");
}
} finally {
ps.close();
http.disconnect();
closeReady = true;
}
} finally {
HttpsURLConnection.setDefaultHostnameVerifier(reservedHV);
}
}
static class NameVerifier implements HostnameVerifier {
public boolean verify(String hostname, SSLSession session) {
return true;
}
}
/*
* =============================================================
* The remainder is just support stuff
*/
// use any free port by default
volatile int serverPort = 0;
volatile Exception serverException = null;
volatile Exception clientException = null;
public static void main(String[] args) throws Exception {
String keyFilename =
System.getProperty("test.src", "./") + "/" + pathToStores +
"/" + keyStoreFile;
String trustFilename =
System.getProperty("test.src", "./") + "/" + pathToStores +
"/" + trustStoreFile;
System.setProperty("javax.net.ssl.keyStore", keyFilename);
System.setProperty("javax.net.ssl.keyStorePassword", passwd);
System.setProperty("javax.net.ssl.trustStore", trustFilename);
System.setProperty("javax.net.ssl.trustStorePassword", passwd);
if (debug)
System.setProperty("javax.net.debug", "all");
/*
* Start the tests.
*/
new HttpsPost();
}
Thread clientThread = null;
Thread serverThread = null;
/*
* Primary constructor, used to drive remainder of the test.
*
* Fork off the other side, then do your work.
*/
HttpsPost() throws Exception {
if (separateServerThread) {
startServer(true);
startClient(false);
} else {
startClient(true);
startServer(false);
}
/*
* Wait for other side to close down.
*/
if (separateServerThread) {
serverThread.join();
} else {
clientThread.join();
}
/*
* When we get here, the test is pretty much over.
*
* If the main thread excepted, that propagates back
* immediately. If the other thread threw an exception, we
* should report back.
*/
if (serverException != null)
throw serverException;
if (clientException != null)
throw clientException;
}
void startServer(boolean newThread) throws Exception {
if (newThread) {
serverThread = new Thread() {
public void run() {
try {
doServerSide();
} catch (Exception e) {
/*
* Our server thread just died.
*
* Release the client, if not active already...
*/
System.err.println("Server died...");
serverReady = true;
serverException = e;
}
}
};
serverThread.start();
} else {
doServerSide();
}
}
void startClient(boolean newThread) throws Exception {
if (newThread) {
clientThread = new Thread() {
public void run() {
try {
doClientSide();
} catch (Exception e) {
/*
* Our client thread just died.
*/
System.err.println("Client died...");
clientException = e;
}
}
};
clientThread.start();
} else {
doClientSide();
}
}
}

View file

@ -0,0 +1,121 @@
/*
* Copyright (c) 2011, 2019, 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 6670868
* @summary StackOverFlow with bad authenticated Proxy tunnels
* @run main/othervm HttpsProxyStackOverflow
*
* No way to reserve default Authenticator, need to run in othervm mode.
*/
import java.io.IOException;
import java.io.InputStream;
import java.net.Authenticator;
import java.net.Proxy;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.PasswordAuthentication;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.URL;
import javax.net.ssl.HttpsURLConnection;
public class HttpsProxyStackOverflow {
public static void main(String[] args) throws IOException {
BadAuthProxyServer server = startServer();
doClient(server);
}
static void doClient(BadAuthProxyServer server) throws IOException {
// url doesn't matter since we will never make the connection
URL url = new URL("https://anythingwilldo/");
InetAddress loopback = InetAddress.getLoopbackAddress();
String loopbackAddress = loopback.getHostAddress();
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection(
new Proxy(Proxy.Type.HTTP,
InetSocketAddress.createUnresolved(loopbackAddress, server.getPort())));
try (InputStream is = conn.getInputStream()) {
} catch(IOException unused) {
// no real server, IOException is expected.
// failure if StackOverflowError
} finally {
server.done();
}
}
static BadAuthProxyServer startServer() throws IOException {
Authenticator.setDefault(new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication("xyz", "xyz".toCharArray());
}
});
InetAddress loopback = InetAddress.getLoopbackAddress();
InetSocketAddress address = new InetSocketAddress(loopback, 0);
ServerSocket ss = new ServerSocket();
ss.bind(address);
BadAuthProxyServer server = new BadAuthProxyServer(ss);
Thread serverThread = new Thread(server);
serverThread.start();
return server;
}
static class BadAuthProxyServer implements Runnable {
private ServerSocket ss;
private boolean done;
BadAuthProxyServer(ServerSocket ss) { this.ss = ss; }
public void run() {
try {
while (!done) {
Socket s = ss.accept();
s.getOutputStream().write(
("HTTP/1.1 407\nProxy-Authenticate:Basic " +
"realm=\"WallyWorld\"\n\n").getBytes("US-ASCII"));
s.close();
s = ss.accept();
s.close();
}
} catch (IOException e) {
// Ignore IOException when the main thread calls done
} finally {
try { ss.close(); } catch (IOException e) {}
}
}
int getPort() {
return ss.getLocalPort();
}
void done() {
try { ss.close(); } catch (IOException e) {}
done = true;
}
}
}

View file

@ -0,0 +1,238 @@
/*
* Copyright (c) 2010, 2019, 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 6614957
* @summary HttpsURLConnection not using the set SSLSocketFactory for creating all its Sockets
* @modules jdk.httpserver
* @library /test/lib
* @run main/othervm HttpsSocketFacTest
*
* SunJSSE does not support dynamic system properties, no way to re-use
* system properties in samevm/agentvm mode.
*/
import javax.net.SocketFactory;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.URL;
import java.net.Proxy;
import java.security.NoSuchAlgorithmException;
import java.io.BufferedWriter;
import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpsConfigurator;
import jdk.test.lib.net.URIBuilder;
/*
* This class tests that the HTTPS protocol handler is using its socket factory for
* creating new Sockets. It does this by wrapping the default SSLSocketFactory with
* its own socket factory, SimpleSSLSocketFactory, and verifying that when a https
* connection is made one of the socket factories createSocket methods, that
* actually creates a Socket, is being invoked by the protocol handler.
*/
public class HttpsSocketFacTest
{
/*
* Where do we find the keystores?
*/
static String pathToStores = "../../../../../../javax/net/ssl/etc";
static String keyStoreFile = "keystore";
static String trustStoreFile = "truststore";
static String passwd = "passphrase";
com.sun.net.httpserver.HttpsServer httpsServer;
MyHandler httpHandler;
public static void main(String[] args) {
String keyFilename =
System.getProperty("test.src", "./") + "/" + pathToStores +
"/" + keyStoreFile;
String trustFilename =
System.getProperty("test.src", "./") + "/" + pathToStores +
"/" + trustStoreFile;
System.setProperty("javax.net.ssl.keyStore", keyFilename);
System.setProperty("javax.net.ssl.keyStorePassword", passwd);
System.setProperty("javax.net.ssl.trustStore", trustFilename);
System.setProperty("javax.net.ssl.trustStorePassword", passwd);
new HttpsSocketFacTest();
}
public HttpsSocketFacTest() {
try {
startHttpsServer();
doClient();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (IOException ioe) {
ioe.printStackTrace();
} finally {
httpsServer.stop(1);
}
}
void doClient() throws IOException {
InetSocketAddress address = httpsServer.getAddress();
URL url = URIBuilder.newBuilder()
.scheme("https")
.loopback()
.port(address.getPort())
.path("/test6614957/")
.toURLUnchecked();
System.out.println("trying to connect to " + url + "...");
HttpsURLConnection uc = (HttpsURLConnection) url.openConnection(Proxy.NO_PROXY);
SimpleSSLSocketFactory sssf = new SimpleSSLSocketFactory();
uc.setSSLSocketFactory(sssf);
uc.setHostnameVerifier(new AllHostnameVerifier());
InputStream is = uc.getInputStream();
byte[] ba = new byte[1024];
int read = 0;
while ((read = is.read(ba)) != -1) {
System.out.println(new String(ba, 0, read));
}
System.out.println("SimpleSSLSocketFactory.socketCreated = " + sssf.socketCreated);
System.out.println("SimpleSSLSocketFactory.socketWrapped = " + sssf.socketWrapped);
if (!sssf.socketCreated)
throw new RuntimeException("Failed: Socket Factory not being called to create Socket");
}
/**
* Https Server
*/
public void startHttpsServer() throws IOException, NoSuchAlgorithmException {
httpsServer = com.sun.net.httpserver.HttpsServer
.create(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0), 0);
httpsServer.createContext("/test6614957/", new MyHandler());
httpsServer.setHttpsConfigurator(new HttpsConfigurator(SSLContext.getDefault()));
httpsServer.start();
}
class MyHandler implements HttpHandler {
private String message = "This is a message!";
@Override
public void handle(HttpExchange t) throws IOException {
t.sendResponseHeaders(200, message.length());
BufferedWriter writer = new BufferedWriter( new OutputStreamWriter(t.getResponseBody(), "ISO8859-1"));
writer.write(message, 0, message.length());
writer.close();
t.close();
}
}
/**
* Simple wrapper on default SSLSocketFactory
*/
class SimpleSSLSocketFactory extends SSLSocketFactory
{
/*
* true if this factory has been used to create a new Socket, i.e.
* one of the SocketFactory methods has been called.
*/
boolean socketCreated = false;
/*
* true if this factory has been used to wrap a Socket, i.e.
* the SSLSocketFactory method,
* createSocket(Socket, String, int, boolean), has been called.
*/
boolean socketWrapped = false;
// methods for SocketFactory
@Override
public Socket createSocket() throws IOException {
socketCreated = true;
return SocketFactory.getDefault().createSocket();
}
@Override
public Socket createSocket(InetAddress host, int port) throws IOException {
socketCreated = true;
return SocketFactory.getDefault().createSocket(host, port);
}
@Override
public Socket createSocket(InetAddress address, int port, InetAddress localAddress,
int localPort) throws IOException {
socketCreated = true;
return SocketFactory.getDefault().createSocket(address, port, localAddress, localPort);
}
@Override
public Socket createSocket(String host, int port) throws IOException {
socketCreated = true;
return SocketFactory.getDefault().createSocket(host, port);
}
@Override
public Socket createSocket(String host, int port, InetAddress localHost,
int localPort) throws IOException {
socketCreated = true;
return SocketFactory.getDefault().createSocket(host, port, localHost, localPort);
}
// methods from SSLSocketFactory
@Override
public Socket createSocket(Socket s, String host, int port,
boolean autoClose) throws IOException {
socketWrapped = true;
return ((SSLSocketFactory) SSLSocketFactory.getDefault()).createSocket
(s, host, port, autoClose);
}
@Override
public String[] getDefaultCipherSuites() {
return ((SSLSocketFactory) SSLSocketFactory.getDefault()).getDefaultCipherSuites();
}
@Override
public String[] getSupportedCipherSuites() {
return ((SSLSocketFactory) SSLSocketFactory.getDefault()).getSupportedCipherSuites();
}
}
class AllHostnameVerifier implements HostnameVerifier
{
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
}
}

View file

@ -0,0 +1,318 @@
/*
* Copyright (c) 2010, 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 id=tls12
* @bug 6766775
* @library /test/lib
* @summary X509 certificate hostname checking is broken in JDK1.6.0_10
*
* @author Xuelei Fan
* @run main/othervm IPAddressDNSIdentities TLSv1.2 MD5withRSA
*/
/* @test id=tls13
* @bug 6766775
* @library /test/lib
* @summary X509 certificate hostname checking is broken in JDK1.6.0_10
*
* @author Xuelei Fan
* @run main/othervm IPAddressDNSIdentities TLSv1.3 SHA256withRSA
*/
import java.net.*;
import java.util.*;
import java.io.*;
import javax.net.ssl.*;
import java.security.KeyStore;
import java.security.KeyFactory;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.spec.*;
import java.security.interfaces.*;
import java.math.BigInteger;
import jdk.test.lib.net.URIBuilder;
import jdk.test.lib.security.CertificateBuilder;
import jdk.test.lib.security.SecurityUtils;
public class IPAddressDNSIdentities extends IdentitiesBase {
/*
* Should we run the client or server in a separate thread?
* Both sides can throw exceptions, but do you have a preference
* as to which side should be the main thread.
*/
static boolean separateServerThread = true;
/*
* Is the server ready to serve?
*/
volatile static boolean serverReady = false;
/*
* Is the connection ready to close?
*/
volatile static boolean closeReady = false;
private SSLServerSocket sslServerSocket = null;
/*
* Define the server side of the test.
*
* If the server prematurely exits, serverReady will be set to true
* to avoid infinite hangs.
*/
void doServerSide() throws Exception {
SSLContext context = getServerSSLContext();
SSLServerSocketFactory sslssf = context.getServerSocketFactory();
// doClientSide() connects to the loopback address
InetAddress loopback = InetAddress.getLoopbackAddress();
InetSocketAddress address = new InetSocketAddress(loopback, serverPort);
sslServerSocket =
(SSLServerSocket) sslssf.createServerSocket();
sslServerSocket.bind(address);
serverPort = sslServerSocket.getLocalPort();
/*
* Signal Client, we're ready for his connect.
*/
serverReady = true;
SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
sslSocket.setNeedClientAuth(true);
PrintStream out =
new PrintStream(sslSocket.getOutputStream());
try {
// ignore request data
// send the response
out.print("HTTP/1.1 200 OK\r\n");
out.print("Content-Type: text/html; charset=iso-8859-1\r\n");
out.print("Content-Length: "+ 9 +"\r\n");
out.print("\r\n");
out.print("Testing\r\n");
out.flush();
} finally {
// close the socket
while (!closeReady) {
Thread.sleep(50);
}
System.out.println("Server closing socket");
sslSocket.close();
serverReady = false;
}
}
/*
* Define the client side of the test.
*
* If the server prematurely exits, serverReady will be set to true
* to avoid infinite hangs.
*/
void doClientSide() throws Exception {
SSLContext reservedSSLContext = SSLContext.getDefault();
try {
SSLContext context = getClientSSLContext();
SSLContext.setDefault(context);
/*
* Wait for server to get started.
*/
while (!serverReady) {
Thread.sleep(50);
}
HttpsURLConnection http = null;
/* establish http connection to server */
URL url = URIBuilder.newBuilder()
.scheme("https")
.loopback()
.port(serverPort)
.path("/")
.toURL();
System.out.println("url is "+url.toString());
try {
http = (HttpsURLConnection)url.openConnection(Proxy.NO_PROXY);
int respCode = http.getResponseCode();
System.out.println("respCode = " + respCode);
throw new Exception("Unexpectly found " +
"subject alternative name matching IP address");
} catch (SSLHandshakeException sslhe) {
// no subject alternative names matching IP address 127.0.0.1
// found that's the expected exception, ignore it.
} catch (IOException ioe) {
// HttpsClient may throw IOE during checking URL spoofing,
// that's the expected exception, ignore it.
} finally {
if (http != null) {
http.disconnect();
}
closeReady = true;
}
} finally {
SSLContext.setDefault(reservedSSLContext);
}
}
/*
* =============================================================
* The remainder is just support stuff
*/
// use any free port by default
volatile int serverPort = 0;
volatile Exception serverException = null;
volatile Exception clientException = null;
public static void main(String[] args) throws Exception {
if (args[1].contains("MD5")) {
System.err.println("RE-ENABLING MD5");
SecurityUtils.removeFromDisabledAlgs(
"jdk.certpath.disabledAlgorithms", List.of("MD5"));
SecurityUtils.removeFromDisabledTlsAlgs("MD5");
}
if (debug)
System.setProperty("javax.net.debug", "all");
/*
* Start the tests.
*/
new IPAddressDNSIdentities(args[0], args[1]);
}
Thread clientThread = null;
Thread serverThread = null;
/*
* Primary constructor, used to drive remainder of the test.
*
* Fork off the other side, then do your work.
*/
IPAddressDNSIdentities(String protocol, String signatureAlgo) throws Exception {
super(protocol, signatureAlgo);
if (separateServerThread) {
startServer(true);
startClient(false);
} else {
startClient(true);
startServer(false);
}
/*
* Wait for other side to close down.
*/
if (separateServerThread) {
serverThread.join();
} else {
clientThread.join();
}
/*
* When we get here, the test is pretty much over.
*
* If the main thread excepted, that propagates back
* immediately. If the other thread threw an exception, we
* should report back.
*/
if (serverException != null)
throw serverException;
if (clientException != null)
throw clientException;
}
void startServer(boolean newThread) throws Exception {
if (newThread) {
serverThread = new Thread() {
public void run() {
try {
doServerSide();
} catch (Exception e) {
/*
* Our server thread just died.
*
* Release the client, if not active already...
*/
System.err.println("Server died...");
serverReady = true;
serverException = e;
}
}
};
serverThread.start();
} else {
doServerSide();
}
}
void startClient(boolean newThread) throws Exception {
if (newThread) {
clientThread = new Thread() {
public void run() {
try {
doClientSide();
} catch (Exception e) {
/*
* Our client thread just died.
*/
System.err.println("Client died...");
clientException = e;
}
}
};
clientThread.start();
} else {
doClientSide();
}
}
@Override
protected CertificateBuilder customizeServerCert(CertificateBuilder builder)
throws Exception {
return builder.addExtension(CertificateBuilder.createDNSSubjectAltNameExt(
true, "localhost"));
}
@Override
protected CertificateBuilder customizeClientCert(CertificateBuilder builder)
throws Exception {
return builder.addExtension(CertificateBuilder.createDNSSubjectAltNameExt(
true, "localhost"));
}
}

View file

@ -0,0 +1,302 @@
/*
* Copyright (c) 2010, 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.
*/
//
// SunJSSE does not support dynamic system properties, no way to re-use
// system properties in samevm/agentvm mode.
//
/* @test id=tls12
* @summary X509 certificate hostname checking is broken in JDK1.6.0_10
* @library /test/lib
* @bug 6766775
* @run main/othervm IPAddressIPIdentities TLSv1.2 MD5withRSA
* @author Xuelei Fan
*/
/* @test id=tls13
* @summary X509 certificate hostname checking is broken in JDK1.6.0_10
* @library /test/lib
* @bug 6766775
* @run main/othervm IPAddressIPIdentities TLSv1.3 SHA256withRSA
* @author Xuelei Fan
*/
import java.io.PrintStream;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URL;
import jdk.test.lib.net.URIBuilder;
import jdk.test.lib.security.SecurityUtils;
import java.util.List;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSocket;
public class IPAddressIPIdentities extends IdentitiesBase {
/*
* =============================================================
* Set the various variables needed for the tests, then
* specify what tests to run on each side.
*/
/*
* Should we run the client or server in a separate thread?
* Both sides can throw exceptions, but do you have a preference
* as to which side should be the main thread.
*/
static boolean separateServerThread = true;
/*
* Is the server ready to serve?
*/
volatile static boolean serverReady = false;
/*
* Is the connection ready to close?
*/
volatile static boolean closeReady = false;
private SSLServerSocket sslServerSocket = null;
/*
* Define the server side of the test.
*
* If the server prematurely exits, serverReady will be set to true
* to avoid infinite hangs.
*/
void doServerSide() throws Exception {
SSLContext context = getServerSSLContext();
SSLServerSocketFactory sslssf = context.getServerSocketFactory();
// doClientSide() connects to the loopback address
InetAddress loopback = InetAddress.getLoopbackAddress();
InetSocketAddress address = new InetSocketAddress(loopback, serverPort);
sslServerSocket =
(SSLServerSocket) sslssf.createServerSocket();
sslServerSocket.bind(address);
serverPort = sslServerSocket.getLocalPort();
/*
* Signal Client, we're ready for his connect.
*/
serverReady = true;
SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
sslSocket.setNeedClientAuth(true);
PrintStream out =
new PrintStream(sslSocket.getOutputStream());
try {
// ignore request data
// send the response
out.print("HTTP/1.1 200 OK\r\n");
out.print("Content-Type: text/html; charset=iso-8859-1\r\n");
out.print("Content-Length: "+ 9 +"\r\n");
out.print("\r\n");
out.print("Testing\r\n");
out.flush();
} finally {
// close the socket
while (!closeReady) {
Thread.sleep(50);
}
System.out.println("Server closing socket");
sslSocket.close();
serverReady = false;
}
}
/*
* Define the client side of the test.
*
* If the server prematurely exits, serverReady will be set to true
* to avoid infinite hangs.
*/
void doClientSide() throws Exception {
SSLContext reservedSSLContext = SSLContext.getDefault();
try {
SSLContext context = getClientSSLContext();
SSLContext.setDefault(context);
/*
* Wait for server to get started.
*/
while (!serverReady) {
Thread.sleep(50);
}
HttpsURLConnection http = null;
/* establish http connection to server */
URL url = URIBuilder.newBuilder()
.scheme("https")
.loopback()
.port(serverPort)
.path("/")
.toURL();
System.out.println("url is "+url.toString());
try {
http = (HttpsURLConnection)url.openConnection(Proxy.NO_PROXY);
int respCode = http.getResponseCode();
System.out.println("respCode = "+respCode);
} finally {
if (http != null) {
http.disconnect();
}
closeReady = true;
}
} finally {
SSLContext.setDefault(reservedSSLContext);
}
}
/*
* =============================================================
* The remainder is just support stuff
*/
// use any free port by default
volatile int serverPort = 0;
volatile Exception serverException = null;
volatile Exception clientException = null;
public static void main(String args[]) throws Exception {
if (args[1].contains("MD5")) {
SecurityUtils.removeFromDisabledAlgs(
"jdk.certpath.disabledAlgorithms", List.of("MD5"));
SecurityUtils.removeFromDisabledTlsAlgs("MD5");
}
if (debug)
System.setProperty("javax.net.debug", "all");
/*
* Start the tests.
*/
new IPAddressIPIdentities(args[0], args[1]);
}
Thread clientThread = null;
Thread serverThread = null;
/*
* Primary constructor, used to drive remainder of the test.
*
* Fork off the other side, then do your work.
*/
IPAddressIPIdentities(String protocol, String signatureAlg) throws Exception {
super(protocol, signatureAlg);
if (separateServerThread) {
startServer(true);
startClient(false);
} else {
startClient(true);
startServer(false);
}
/*
* Wait for other side to close down.
*/
if (separateServerThread) {
serverThread.join();
} else {
clientThread.join();
}
/*
* When we get here, the test is pretty much over.
*
* If the main thread excepted, that propagates back
* immediately. If the other thread threw an exception, we
* should report back.
*/
if (serverException != null)
throw serverException;
if (clientException != null)
throw clientException;
}
void startServer(boolean newThread) throws Exception {
if (newThread) {
serverThread = new Thread() {
public void run() {
try {
doServerSide();
} catch (Exception e) {
/*
* Our server thread just died.
*
* Release the client, if not active already...
*/
System.err.println("Server died...");
serverReady = true;
serverException = e;
}
}
};
serverThread.start();
} else {
doServerSide();
}
}
void startClient(boolean newThread) throws Exception {
if (newThread) {
clientThread = new Thread() {
public void run() {
try {
doClientSide();
} catch (Exception e) {
/*
* Our client thread just died.
*/
System.err.println("Client died...");
clientException = e;
}
}
};
clientThread.start();
} else {
doClientSide();
}
}
}

View file

@ -0,0 +1,318 @@
/*
* Copyright (c) 2010, 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.
*/
//
// SunJSSE does not support dynamic system properties, no way to re-use
// system properties in samevm/agentvm mode.
//
/* @test id=tls12
* @bug 6766775
* @summary X509 certificate hostname checking is broken in JDK1.6.0_10
* @library /test/lib
* @run main/othervm Identities TLSv1.2 MD5withRSA
* @author Xuelei Fan
*/
/* @test id=tls13
* @bug 6766775
* @summary X509 certificate hostname checking is broken in JDK1.6.0_10
* @library /test/lib
* @run main/othervm Identities TLSv1.3 SHA256withRSA
* @author Xuelei Fan
*/
import jdk.test.lib.security.CertificateBuilder;
import jdk.test.lib.security.SecurityUtils;
import sun.security.x509.DNSName;
import sun.security.x509.GeneralName;
import sun.security.x509.GeneralNames;
import sun.security.x509.IPAddressName;
import sun.security.x509.SubjectAlternativeNameExtension;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSocket;
import java.io.PrintStream;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URL;
import java.util.List;
public class Identities extends IdentitiesBase {
/*
* =============================================================
* Set the various variables needed for the tests, then
* specify what tests to run on each side.
*/
/*
* Should we run the client or server in a separate thread?
* Both sides can throw exceptions, but do you have a preference
* as to which side should be the main thread.
*/
static boolean separateServerThread = true;
/*
* Is the server ready to serve?
*/
volatile static boolean serverReady = false;
/*
* Is the connection ready to close?
*/
volatile static boolean closeReady = false;
private SSLServerSocket sslServerSocket = null;
@Override
protected CertificateBuilder customizeServerCert(CertificateBuilder builder) throws Exception {
GeneralNames gns = new GeneralNames();
gns.add(new GeneralName(new IPAddressName("127.0.0.1")));
gns.add(new GeneralName(new DNSName("localhost")));
return builder.addExtension(new SubjectAlternativeNameExtension(true, gns));
}
@Override
protected CertificateBuilder customizeClientCert(CertificateBuilder builder) throws Exception {
GeneralNames gns = new GeneralNames();
gns.add(new GeneralName(new IPAddressName("127.0.0.1")));
gns.add(new GeneralName(new DNSName("localhost")));
return builder.addExtension(new SubjectAlternativeNameExtension(true, gns));
}
/*
* Define the server side of the test.
*
* If the server prematurely exits, serverReady will be set to true
* to avoid infinite hangs.
*/
void doServerSide() throws Exception {
SSLContext context = getServerSSLContext();
SSLServerSocketFactory sslssf = context.getServerSocketFactory();
// doClientSide() connects to "localhost"
InetAddress localHost = InetAddress.getByName("localhost");
InetSocketAddress address = new InetSocketAddress(localHost, serverPort);
sslServerSocket =
(SSLServerSocket) sslssf.createServerSocket();
sslServerSocket.bind(address);
serverPort = sslServerSocket.getLocalPort();
/*
* Signal Client, we're ready for his connect.
*/
serverReady = true;
SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
sslSocket.setNeedClientAuth(true);
PrintStream out =
new PrintStream(sslSocket.getOutputStream());
try {
// ignore request data
// send the response
out.print("HTTP/1.1 200 OK\r\n");
out.print("Content-Type: text/html; charset=iso-8859-1\r\n");
out.print("Content-Length: "+ 9 +"\r\n");
out.print("\r\n");
out.print("Testing\r\n");
out.flush();
} finally {
// close the socket
while (!closeReady) {
Thread.sleep(50);
}
System.out.println("Server closing socket");
sslSocket.close();
serverReady = false;
}
}
/*
* Define the client side of the test.
*
* If the server prematurely exits, serverReady will be set to true
* to avoid infinite hangs.
*/
void doClientSide() throws Exception {
SSLContext reservedSSLContext = SSLContext.getDefault();
try {
SSLContext context = getClientSSLContext();
SSLContext.setDefault(context);
/*
* Wait for server to get started.
*/
while (!serverReady) {
Thread.sleep(50);
}
HttpsURLConnection http = null;
/* establish http connection to server */
URL url = new URL("https://localhost:" + serverPort+"/");
System.out.println("url is "+url.toString());
try {
http = (HttpsURLConnection)url.openConnection(Proxy.NO_PROXY);
int respCode = http.getResponseCode();
System.out.println("respCode = "+respCode);
} finally {
if (http != null) {
http.disconnect();
}
closeReady = true;
}
} finally {
SSLContext.setDefault(reservedSSLContext);
}
}
/*
* =============================================================
* The remainder is just support stuff
*/
// use any free port by default
volatile int serverPort = 0;
volatile Exception serverException = null;
volatile Exception clientException = null;
public static void main(String args[]) throws Exception {
if (args[1].contains("MD5")) {
SecurityUtils.removeFromDisabledAlgs(
"jdk.certpath.disabledAlgorithms", List.of("MD5"));
SecurityUtils.removeFromDisabledTlsAlgs("MD5");
}
if (debug)
System.setProperty("javax.net.debug", "all");
/*
* Start the tests.
*/
new Identities(args[0], args[1]);
}
Thread clientThread = null;
Thread serverThread = null;
/*
* Primary constructor, used to drive remainder of the test.
*
* Fork off the other side, then do your work.
*/
Identities(String protocol, String signatureAlg) throws Exception {
super(protocol, signatureAlg);
if (separateServerThread) {
startServer(true);
startClient(false);
} else {
startClient(true);
startServer(false);
}
/*
* Wait for other side to close down.
*/
if (separateServerThread) {
serverThread.join();
} else {
clientThread.join();
}
/*
* When we get here, the test is pretty much over.
*
* If the main thread excepted, that propagates back
* immediately. If the other thread threw an exception, we
* should report back.
*/
if (serverException != null)
throw serverException;
if (clientException != null)
throw clientException;
}
void startServer(boolean newThread) throws Exception {
if (newThread) {
serverThread = new Thread() {
public void run() {
try {
doServerSide();
} catch (Exception e) {
/*
* Our server thread just died.
*
* Release the client, if not active already...
*/
System.err.println("Server died...");
serverReady = true;
serverException = e;
}
}
};
serverThread.start();
} else {
doServerSide();
}
}
void startClient(boolean newThread) throws Exception {
if (newThread) {
clientThread = new Thread() {
public void run() {
try {
doClientSide();
} catch (Exception e) {
/*
* Our client thread just died.
*/
System.err.println("Client died...");
clientException = e;
}
}
};
clientThread.start();
} else {
doClientSide();
}
}
}

View file

@ -0,0 +1,187 @@
/*
* Copyright (c) 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.
*/
import jdk.test.lib.security.CertificateBuilder;
import sun.security.x509.AuthorityKeyIdentifierExtension;
import sun.security.x509.GeneralName;
import sun.security.x509.GeneralNames;
import sun.security.x509.KeyIdentifier;
import sun.security.x509.SerialNumber;
import sun.security.x509.X500Name;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
import java.math.BigInteger;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.SecureRandom;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
public abstract class IdentitiesBase {
static X509Certificate trustedCert;
static X509Certificate serverCert;
static X509Certificate clientCert;
static KeyPair serverKeys;
static KeyPair clientKeys;
static char[] passphrase = "passphrase".toCharArray();
protected final String protocol;
protected final String signatureAlg;
/*
* Turn on SSL debugging?
*/
static boolean debug = Boolean.getBoolean("test.debug");
public IdentitiesBase(String protocol, String signatureAlg) throws Exception {
this.protocol = protocol;
this.signatureAlg = signatureAlg;
setupCertificates();
}
protected String getTrustedDname() {
return "O=Some-Org, L=Some-City, ST=Some-State, C=US";
}
protected String getServerDname() {
return "CN=localhost, OU=SSL-Server, O=Some-Org, L=Some-City, ST=Some-State, C=US";
}
protected String getClientDname() {
return "CN=localhost, OU=SSL-Client, O=Some-Org, L=Some-City, ST=Some-State, C=US";
}
protected CertificateBuilder customizeServerCert(CertificateBuilder builder) throws Exception {
return builder;
}
protected CertificateBuilder customizeClientCert(CertificateBuilder builder) throws Exception {
return builder;
}
private void setupCertificates() throws Exception {
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
KeyPair caKeys = kpg.generateKeyPair();
serverKeys = kpg.generateKeyPair();
clientKeys = kpg.generateKeyPair();
trustedCert = createTrustedCert(getTrustedDname(), caKeys, signatureAlg);
if (debug) {
System.out.println("----------- Trusted Cert -----------");
CertificateBuilder.printCertificate(trustedCert, System.out);
}
CertificateBuilder builder = CertificateBuilder.newCertificateBuilder(
getServerDname(),
serverKeys.getPublic(), caKeys.getPublic(),
CertificateBuilder.KeyUsage.DIGITAL_SIGNATURE,
CertificateBuilder.KeyUsage.NONREPUDIATION,
CertificateBuilder.KeyUsage.KEY_ENCIPHERMENT)
.addBasicConstraintsExt(false, false, -1)
.addExtension(CertificateBuilder.createIPSubjectAltNameExt(true, "127.0.0.1", "::1"))
.setOneHourValidity();
serverCert = customizeServerCert(builder)
.build(trustedCert, caKeys.getPrivate(), signatureAlg);
if (debug) {
System.out.println("----------- Server Cert -----------");
CertificateBuilder.printCertificate(serverCert, System.out);
}
builder = CertificateBuilder.newCertificateBuilder(
getClientDname(),
clientKeys.getPublic(), caKeys.getPublic(),
CertificateBuilder.KeyUsage.DIGITAL_SIGNATURE,
CertificateBuilder.KeyUsage.NONREPUDIATION,
CertificateBuilder.KeyUsage.KEY_ENCIPHERMENT)
.addExtension(CertificateBuilder.createIPSubjectAltNameExt(true, "127.0.0.1", "::1"))
.addBasicConstraintsExt(false, false, -1)
.setOneHourValidity();
builder = customizeClientCert(builder);
clientCert = builder.build(trustedCert, caKeys.getPrivate(), signatureAlg);
if (debug) {
System.out.println("----------- Client Cert -----------");
CertificateBuilder.printCertificate(clientCert, System.out);
}
}
protected static X509Certificate createTrustedCert(String dname, KeyPair caKeys,
String signatureAlgo) throws Exception {
SecureRandom random = new SecureRandom();
KeyIdentifier kid = new KeyIdentifier(caKeys.getPublic());
GeneralNames gns = new GeneralNames();
GeneralName name = new GeneralName(new X500Name(dname));
gns.add(name);
BigInteger serialNumber = BigInteger.valueOf(random.nextLong(1000000) + 1);
return CertificateBuilder.newCertificateBuilder(dname,
caKeys.getPublic(), caKeys.getPublic())
.setSerialNumber(serialNumber)
.addExtension(new AuthorityKeyIdentifierExtension(kid, gns,
new SerialNumber(serialNumber)))
.addBasicConstraintsExt(true, true, -1)
.setOneHourValidity()
.build(null, caKeys.getPrivate(), signatureAlgo);
}
protected SSLContext getClientSSLContext() throws Exception {
return getSSLContext(trustedCert, clientCert, clientKeys, passphrase);
}
protected SSLContext getServerSSLContext() throws Exception {
return getSSLContext(trustedCert, serverCert, serverKeys, passphrase);
}
// get the ssl context
private SSLContext getSSLContext(X509Certificate trustedCert,
X509Certificate keyCert, KeyPair key, char[] passphrase)
throws Exception {
// create a key store
KeyStore ks = KeyStore.getInstance("PKCS12");
ks.load(null, null);
// import the trused cert
ks.setCertificateEntry("RSA Export Signer", trustedCert);
Certificate[] chain = new Certificate[2];
chain[0] = keyCert;
chain[1] = trustedCert;
// import the key entry.
ks.setKeyEntry("Whatever", key.getPrivate(), passphrase, chain);
// create SSL context
TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");
tmf.init(ks);
SSLContext ctx = SSLContext.getInstance(protocol);
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(ks, passphrase);
ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
return ctx;
}
}

View file

@ -0,0 +1,400 @@
/*
* Copyright (c) 2016, 2019, 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.
*/
//
// SunJSSE does not support dynamic system properties, no way to re-use
// system properties in samevm/agentvm mode.
//
/*
* @test
* @bug 8144566
* @summary Custom HostnameVerifier disables SNI extension
* @run main/othervm ImpactOnSNI
*/
import java.io.*;
import java.net.*;
import javax.net.ssl.*;
public class ImpactOnSNI {
/*
* =============================================================
* Set the various variables needed for the tests, then
* specify what tests to run on each side.
*/
/*
* Should we run the client or server in a separate thread?
* Both sides can throw exceptions, but do you have a preference
* as to which side should be the main thread.
*/
private static final boolean separateServerThread = true;
/*
* Where do we find the keystores?
*/
private static final String pathToStores =
"../../../../../../javax/net/ssl/etc";
private static final String keyStoreFile = "keystore";
private static final String trustStoreFile = "truststore";
private static final String passwd = "passphrase";
/*
* Is the server ready to serve?
*/
private static volatile boolean serverReady = false;
/*
* Is the connection ready to close?
*/
private static volatile boolean closeReady = false;
/*
* Turn on SSL debugging?
*/
private static final boolean debug = false;
/*
* Message posted
*/
private static final String postMsg = "HTTP post on a https server";
/*
* the fully qualified domain name of localhost
*/
private static String hostname = null;
/*
* If the client or server is doing some kind of object creation
* that the other side depends on, and that thread prematurely
* exits, you may experience a hang. The test harness will
* terminate all hung threads after its timeout has expired,
* currently 3 minutes by default, but you might try to be
* smart about it....
*/
private SSLServerSocket createServerSocket(SSLServerSocketFactory sslssf)
throws Exception {
SSLServerSocket sslServerSocket =
(SSLServerSocket)sslssf.createServerSocket();
InetAddress localHost = InetAddress.getLocalHost();
InetSocketAddress address = new InetSocketAddress(localHost, serverPort);
sslServerSocket.bind(address);
return sslServerSocket;
}
/*
* Define the server side of the test.
*
* If the server prematurely exits, serverReady will be set to true
* to avoid infinite hangs.
*/
private void doServerSide() throws Exception {
SSLServerSocketFactory sslssf =
(SSLServerSocketFactory)SSLServerSocketFactory.getDefault();
try (SSLServerSocket sslServerSocket = createServerSocket(sslssf)) {
serverPort = sslServerSocket.getLocalPort();
/*
* Signal Client, we're ready for his connect.
*/
serverReady = true;
/*
* Accept connections
*/
try (SSLSocket sslSocket = (SSLSocket)sslServerSocket.accept()) {
InputStream sslIS = sslSocket.getInputStream();
OutputStream sslOS = sslSocket.getOutputStream();
BufferedReader br =
new BufferedReader(new InputStreamReader(sslIS));
PrintStream ps = new PrintStream(sslOS);
// process HTTP POST request from client
System.out.println("status line: " + br.readLine());
String msg = null;
while ((msg = br.readLine()) != null && msg.length() > 0);
msg = br.readLine();
if (msg.equals(postMsg)) {
ps.println("HTTP/1.1 200 OK\n\n");
} else {
ps.println("HTTP/1.1 500 Not OK\n\n");
}
ps.flush();
ExtendedSSLSession session =
(ExtendedSSLSession)sslSocket.getSession();
if (session.getRequestedServerNames().isEmpty()) {
throw new Exception("No expected Server Name Indication");
}
// close the socket
while (!closeReady) {
Thread.sleep(50);
}
}
}
}
/*
* Define the client side of the test.
*
* If the server prematurely exits, serverReady will be set to true
* to avoid infinite hangs.
*/
private void doClientSide() throws Exception {
/*
* Wait for server to get started.
*/
while (!serverReady) {
Thread.sleep(50);
}
// Send HTTP POST request to server
URL url = new URL("https://" + hostname + ":" + serverPort);
HttpsURLConnection.setDefaultHostnameVerifier(new NameVerifier());
HttpsURLConnection http = (HttpsURLConnection)url.openConnection();
http.setDoOutput(true);
http.setRequestMethod("POST");
PrintStream ps = new PrintStream(http.getOutputStream());
try {
ps.println(postMsg);
ps.flush();
if (http.getResponseCode() != 200) {
throw new RuntimeException("test Failed");
}
} finally {
ps.close();
http.disconnect();
closeReady = true;
}
}
private static class NameVerifier implements HostnameVerifier {
public boolean verify(String hostname, SSLSession session) {
return true;
}
}
/*
* =============================================================
* The remainder is just support stuff
*/
// use any free port by default
private volatile int serverPort = 0;
private volatile Exception serverException = null;
private volatile Exception clientException = null;
public static void main(String[] args) throws Exception {
String keyFilename =
System.getProperty("test.src", "./") + "/" + pathToStores +
"/" + keyStoreFile;
String trustFilename =
System.getProperty("test.src", "./") + "/" + pathToStores +
"/" + trustStoreFile;
System.setProperty("javax.net.ssl.keyStore", keyFilename);
System.setProperty("javax.net.ssl.keyStorePassword", passwd);
System.setProperty("javax.net.ssl.trustStore", trustFilename);
System.setProperty("javax.net.ssl.trustStorePassword", passwd);
if (debug) {
System.setProperty("javax.net.debug", "all");
}
try {
hostname = InetAddress.getLocalHost().getCanonicalHostName();
} catch (UnknownHostException uhe) {
System.out.println(
"Ignore the test as the local hostname cannot be determined");
return;
}
System.out.println(
"The fully qualified domain name of the local host is " +
hostname);
// Ignore the test if the hostname does not sound like a domain name.
if ((hostname == null) || hostname.isEmpty() ||
!hostname.contains(".") || hostname.endsWith(".") ||
hostname.startsWith("localhost") ||
Character.isDigit(hostname.charAt(hostname.length() - 1))) {
System.out.println("Ignore the test as the local hostname " +
"cannot be determined as fully qualified domain name");
return;
}
/*
* Start the tests.
*/
new ImpactOnSNI();
}
private Thread clientThread = null;
private Thread serverThread = null;
/*
* Primary constructor, used to drive remainder of the test.
*
* Fork off the other side, then do your work.
*/
ImpactOnSNI() throws Exception {
Exception startException = null;
try {
if (separateServerThread) {
startServer(true);
startClient(false);
} else {
startClient(true);
startServer(false);
}
} catch (Exception e) {
startException = e;
}
/*
* Wait for other side to close down.
*/
if (separateServerThread) {
if (serverThread != null) {
serverThread.join();
}
} else {
if (clientThread != null) {
clientThread.join();
}
}
/*
* When we get here, the test is pretty much over.
* Which side threw the error?
*/
Exception local;
Exception remote;
if (separateServerThread) {
remote = serverException;
local = clientException;
} else {
remote = clientException;
local = serverException;
}
Exception exception = null;
/*
* Check various exception conditions.
*/
if ((local != null) && (remote != null)) {
// If both failed, return the curthread's exception.
local.initCause(remote);
exception = local;
} else if (local != null) {
exception = local;
} else if (remote != null) {
exception = remote;
} else if (startException != null) {
exception = startException;
}
/*
* If there was an exception *AND* a startException,
* output it.
*/
if (exception != null) {
if (exception != startException && startException != null) {
exception.addSuppressed(startException);
}
throw exception;
}
// Fall-through: no exception to throw!
}
private void startServer(boolean newThread) throws Exception {
if (newThread) {
serverThread = new Thread() {
@Override
public void run() {
try {
doServerSide();
} catch (Exception e) {
/*
* Our server thread just died.
*
* Release the client, if not active already...
*/
System.err.println("Server died...");
serverReady = true;
serverException = e;
}
}
};
serverThread.start();
} else {
try {
doServerSide();
} catch (Exception e) {
serverException = e;
} finally {
serverReady = true;
}
}
}
private void startClient(boolean newThread) throws Exception {
if (newThread) {
clientThread = new Thread() {
@Override
public void run() {
try {
doClientSide();
} catch (Exception e) {
/*
* Our client thread just died.
*/
System.err.println("Client died...");
clientException = e;
}
}
};
clientThread.start();
} else {
try {
doClientSide();
} catch (Exception e) {
clientException = e;
}
}
}
}

View file

@ -0,0 +1,153 @@
/*
* Copyright (c) 2001, 2003, 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.
*/
/*
*
* This is a HTTP test server.
*/
import java.io.*;
import java.net.*;
import javax.net.*;
/*
* OriginServer.java -- a simple server that can serve
* http requests in both clear and secure channel.
*/
public abstract class OriginServer implements Runnable {
private ServerSocket server = null;
Exception serverException = null;
/**
* Constructs a OriginServer based on ss and
* obtains a response data's bytecodes using the method
* getBytes.
*/
protected OriginServer(ServerSocket ss) throws Exception
{
server = ss;
newListener();
if (serverException != null)
throw serverException;
}
/**
* Returns an array of bytes containing the bytes for
* data sent in the response.
*
* @return the bytes for the information that is being sent
*/
public abstract byte[] getBytes();
/**
* The "listen" thread that accepts a connection to the
* server, parses header and sends back the response
*/
public void run()
{
Socket socket;
// accept a connection
try {
socket = server.accept();
} catch (IOException e) {
System.out.println("Class Server died: " + e.getMessage());
serverException = e;
return;
}
try {
DataOutputStream out =
new DataOutputStream(socket.getOutputStream());
try {
BufferedReader in =
new BufferedReader(new InputStreamReader(
socket.getInputStream()));
// read the request
readRequest(in);
// retrieve bytecodes
byte[] bytecodes = getBytes();
// send bytecodes in response (assumes HTTP/1.0 or later)
try {
out.writeBytes("HTTP/1.0 200 OK\r\n");
out.writeBytes("Content-Length: " + bytecodes.length +
"\r\n");
out.writeBytes("Content-Type: text/html\r\n\r\n");
out.write(bytecodes);
out.flush();
} catch (IOException ie) {
serverException = ie;
return;
}
} catch (Exception e) {
// write out error response
out.writeBytes("HTTP/1.0 400 " + e.getMessage() + "\r\n");
out.writeBytes("Content-Type: text/html\r\n\r\n");
out.flush();
}
} catch (IOException ex) {
System.out.println("Server: Error writing response: "
+ ex.getMessage());
serverException = ex;
} finally {
try {
socket.close();
} catch (IOException e) {
serverException = e;
}
}
}
/**
* Create a new thread to listen.
*/
private void newListener()
{
(new Thread(this)).start();
}
/**
* read the response, don't care for the syntax of the request-line
*/
private static void readRequest(BufferedReader in)
throws IOException
{
String line = null;
do {
line = in.readLine();
System.out.println("Server recieved: " + line);
} while ((line.length() != 0) &&
(line.charAt(0) != '\r') && (line.charAt(0) != '\n'));
// read the last line to clear the POST input buffer
// would be best to make sure all bytes are read, maybe later.
line = in.readLine();
System.out.println("Command received: " + line);
System.out.println("");
}
}

View file

@ -0,0 +1,236 @@
/*
* Copyright (c) 2001, 2019, 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.
*/
import java.io.*;
import java.net.*;
import java.security.KeyStore;
import javax.net.*;
import javax.net.ssl.*;
import jdk.test.lib.net.URIBuilder;
/*
* @test
* @bug 4423074
* @modules java.base/sun.net.www
* @summary This test case is written to test the https POST through a proxy.
* There is no proxy authentication done. It includes a simple server
* that serves http POST method requests in secure channel, and a client
* that makes https POST request through a proxy.
* @library /test/lib
* @compile OriginServer.java ProxyTunnelServer.java
* @run main/othervm PostThruProxy
*/
public class PostThruProxy {
private static final String TEST_SRC = System.getProperty("test.src", ".");
private static final int TIMEOUT = 30000;
/*
* Where do we find the keystores?
*/
static String pathToStores = "../../../../../../javax/net/ssl/etc";
static String keyStoreFile = "keystore";
static String trustStoreFile = "truststore";
static String passwd = "passphrase";
private static int serverPort = 0;
private static ProxyTunnelServer pserver;
private static TestServer server;
static final String RESPONSE_MSG = "Https POST thru proxy is successful";
/*
* The TestServer implements a OriginServer that
* processes HTTP requests and responses.
*/
static class TestServer extends OriginServer {
public TestServer(ServerSocket ss) throws Exception {
super(ss);
}
/*
* Returns an array of bytes containing the bytes for
* the data sent in the response.
*
* @return bytes for the data in the response
*/
public byte[] getBytes() {
return RESPONSE_MSG.getBytes();
}
}
/*
* Main method to create the server and client
*/
public static void main(String args[]) throws Exception {
String keyFilename = TEST_SRC + "/" + pathToStores + "/" + keyStoreFile;
String trustFilename = TEST_SRC + "/" + pathToStores + "/"
+ trustStoreFile;
System.setProperty("javax.net.ssl.keyStore", keyFilename);
System.setProperty("javax.net.ssl.keyStorePassword", passwd);
System.setProperty("javax.net.ssl.trustStore", trustFilename);
System.setProperty("javax.net.ssl.trustStorePassword", passwd);
InetAddress loopback = InetAddress.getLoopbackAddress();
boolean useSSL = true;
/*
* setup the server
*/
try {
ServerSocketFactory ssf = getServerSocketFactory(useSSL);
ServerSocket ss = ssf.createServerSocket(serverPort, 0, loopback);
ss.setSoTimeout(TIMEOUT); // 30 seconds
serverPort = ss.getLocalPort();
server = new TestServer(ss);
System.out.println("Server started at: " + ss);
} catch (Exception e) {
System.out.println("Server side failed:" +
e.getMessage());
throw e;
}
// trigger the client
try {
doClientSide();
} catch (Exception e) {
System.out.println("Client side failed: " +
e.getMessage());
throw e;
}
long connectCount = pserver.getConnectCount();
if (connectCount == 0) {
throw new AssertionError("Proxy was not used!");
} else {
System.out.println("Proxy CONNECT count: " + connectCount);
}
}
private static ServerSocketFactory getServerSocketFactory
(boolean useSSL) throws Exception {
if (useSSL) {
// set up key manager to do server authentication
SSLContext ctx = SSLContext.getInstance("TLS");
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
KeyStore ks = KeyStore.getInstance("JKS");
char[] passphrase = passwd.toCharArray();
ks.load(new FileInputStream(System.getProperty(
"javax.net.ssl.keyStore")), passphrase);
kmf.init(ks, passphrase);
ctx.init(kmf.getKeyManagers(), null, null);
return ctx.getServerSocketFactory();
} else {
return ServerSocketFactory.getDefault();
}
}
/*
* Message to be posted
*/
static String postMsg = "Testing HTTP post on a https server";
static void doClientSide() throws Exception {
HostnameVerifier reservedHV =
HttpsURLConnection.getDefaultHostnameVerifier();
try {
/*
* setup up a proxy
*/
SocketAddress pAddr = setupProxy();
/*
* we want to avoid URLspoofCheck failures in cases where the cert
* DN name does not match the hostname in the URL.
*/
HttpsURLConnection.setDefaultHostnameVerifier(
new NameVerifier());
URL url = URIBuilder.newBuilder()
.scheme("https")
.loopback()
.port(serverPort)
.toURL();
Proxy p = new Proxy(Proxy.Type.HTTP, pAddr);
System.out.println("Client connecting to: " + url);
System.out.println("Through proxy: " + pAddr);
HttpsURLConnection https = (HttpsURLConnection)url.openConnection(p);
https.setConnectTimeout(TIMEOUT);
https.setReadTimeout(TIMEOUT);
https.setDoOutput(true);
https.setRequestMethod("POST");
PrintStream ps = null;
try {
ps = new PrintStream(https.getOutputStream());
ps.println(postMsg);
ps.flush();
if (https.getResponseCode() != 200) {
throw new RuntimeException("test Failed");
}
ps.close();
// clear the pipe
BufferedReader in = new BufferedReader(
new InputStreamReader(
https.getInputStream()));
String inputLine;
boolean msgFound = false;
while ((inputLine = in.readLine()) != null) {
System.out.println("Client received: " + inputLine);
if (inputLine.contains(RESPONSE_MSG)) msgFound = true;
}
in.close();
if (!msgFound) {
throw new RuntimeException("POST message not found.");
}
} catch (SSLException e) {
if (ps != null)
ps.close();
throw e;
} catch (SocketTimeoutException e) {
System.out.println("Client can not get response in time: "
+ e.getMessage());
}
} finally {
HttpsURLConnection.setDefaultHostnameVerifier(reservedHV);
}
}
static class NameVerifier implements HostnameVerifier {
public boolean verify(String hostname, SSLSession session) {
return true;
}
}
static SocketAddress setupProxy() throws IOException {
InetAddress loopback = InetAddress.getLoopbackAddress();
pserver = new ProxyTunnelServer(loopback);
// disable proxy authentication
pserver.needUserAuth(false);
pserver.start();
return new InetSocketAddress(loopback, pserver.getPort());
}
}

View file

@ -0,0 +1,266 @@
/*
* Copyright (c) 2001, 2019, 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.
*/
import java.io.*;
import java.net.*;
import java.security.KeyStore;
import javax.net.*;
import javax.net.ssl.*;
import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.process.ProcessTools;
import jdk.test.lib.net.URIBuilder;
/*
* @test
* @bug 4423074
* @modules java.base/sun.net.www
* @summary This test case is written to test the https POST through a proxy
* with proxy authentication. It includes a simple server that serves
* http POST method requests in secure channel, and a client that
* makes https POST request through a proxy.
* @library /test/lib
* @build jdk.test.lib.Utils
* jdk.test.lib.Asserts
* jdk.test.lib.JDKToolFinder
* jdk.test.lib.JDKToolLauncher
* jdk.test.lib.Platform
* jdk.test.lib.process.*
* @compile OriginServer.java ProxyTunnelServer.java
* @run main/othervm -Djdk.http.auth.tunneling.disabledSchemes= PostThruProxyWithAuth
* @run main/othervm -Djava.net.preferIPv6Addresses=true
-Djdk.http.auth.tunneling.disabledSchemes= PostThruProxyWithAuth
*/
public class PostThruProxyWithAuth {
private static final String TEST_SRC = System.getProperty("test.src", ".");
private static final int TIMEOUT = 30000;
/*
* Where do we find the keystores?
*/
static String pathToStores = "../../../../../../javax/net/ssl/etc";
static String keyStoreFile = "keystore";
static String trustStoreFile = "truststore";
static String passwd = "passphrase";
volatile private static int serverPort = 0;
private static ProxyTunnelServer pserver;
private static TestServer server;
static final String RESPONSE_MSG =
"Https POST thru proxy is successful with proxy authentication";
/*
* The TestServer implements a OriginServer that
* processes HTTP requests and responses.
*/
static class TestServer extends OriginServer {
public TestServer(ServerSocket ss) throws Exception {
super(ss);
}
/*
* Returns an array of bytes containing the bytes for
* the data sent in the response.
*
* @return bytes for the data in the response
*/
public byte[] getBytes() {
return RESPONSE_MSG.getBytes();
}
}
/*
* Main method to create the server and client
*/
public static void main(String args[]) throws Exception {
String keyFilename = TEST_SRC + "/" + pathToStores + "/" + keyStoreFile;
String trustFilename = TEST_SRC + "/" + pathToStores + "/"
+ trustStoreFile;
System.setProperty("javax.net.ssl.keyStore", keyFilename);
System.setProperty("javax.net.ssl.keyStorePassword", passwd);
System.setProperty("javax.net.ssl.trustStore", trustFilename);
System.setProperty("javax.net.ssl.trustStorePassword", passwd);
boolean useSSL = true;
/*
* setup the server
*/
try {
InetAddress localhost = InetAddress.getLocalHost();
ServerSocketFactory ssf = getServerSocketFactory(useSSL);
ServerSocket ss = ssf.createServerSocket(serverPort, 0, localhost);
ss.setSoTimeout(TIMEOUT); // 30 seconds
serverPort = ss.getLocalPort();
server = new TestServer(ss);
System.out.println("Server started at: " + ss);
} catch (Exception e) {
System.out.println("Server side failed:" +
e.getMessage());
throw e;
}
// trigger the client
try {
doClientSide();
} catch (Exception e) {
System.out.println("Client side failed: " +
e.getMessage());
throw e;
}
long connectCount = pserver.getConnectCount();
if (connectCount == 0) {
throw new AssertionError("Proxy was not used!");
} else {
System.out.println("Proxy CONNECT count: " + connectCount);
}
}
private static ServerSocketFactory getServerSocketFactory
(boolean useSSL) throws Exception {
if (useSSL) {
// set up key manager to do server authentication
SSLContext ctx = SSLContext.getInstance("TLS");
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
KeyStore ks = KeyStore.getInstance("JKS");
char[] passphrase = passwd.toCharArray();
ks.load(new FileInputStream(System.getProperty(
"javax.net.ssl.keyStore")), passphrase);
kmf.init(ks, passphrase);
ctx.init(kmf.getKeyManagers(), null, null);
return ctx.getServerSocketFactory();
} else {
return ServerSocketFactory.getDefault();
}
}
/*
* Message to be posted
*/
static String postMsg = "Testing HTTP post on a https server";
static void doClientSide() throws Exception {
/*
* setup up a proxy
*/
SocketAddress pAddr = setupProxy();
/*
* we want to avoid URLspoofCheck failures in cases where the cert
* DN name does not match the hostname in the URL.
*/
HttpsURLConnection.setDefaultHostnameVerifier(
new NameVerifier());
URL url = URIBuilder.newBuilder()
.scheme("https")
.host(getHostname())
.port(serverPort)
.toURL();
Proxy p = new Proxy(Proxy.Type.HTTP, pAddr);
System.out.println("Client connecting to: " + url);
System.out.println("Through proxy: " + pAddr);
HttpsURLConnection https = (HttpsURLConnection)url.openConnection(p);
https.setConnectTimeout(TIMEOUT);
https.setReadTimeout(TIMEOUT);
https.setDoOutput(true);
https.setRequestMethod("POST");
PrintStream ps = null;
try {
ps = new PrintStream(https.getOutputStream());
ps.println(postMsg);
ps.flush();
if (https.getResponseCode() != 200) {
throw new RuntimeException("test Failed");
}
ps.close();
// clear the pipe
BufferedReader in = new BufferedReader(
new InputStreamReader(
https.getInputStream()));
String inputLine;
boolean msgFound = false;
while ((inputLine = in.readLine()) != null) {
System.out.println("Client received: " + inputLine);
if (inputLine.contains(RESPONSE_MSG)) msgFound = true;
}
in.close();
if (!msgFound) {
throw new RuntimeException("POST message not found.");
}
} catch (SSLException e) {
if (ps != null)
ps.close();
throw e;
} catch (SocketTimeoutException e) {
System.out.println("Client can not get response in time: "
+ e.getMessage());
}
}
static class NameVerifier implements HostnameVerifier {
public boolean verify(String hostname, SSLSession session) {
return true;
}
}
static SocketAddress setupProxy() throws IOException {
InetAddress localhost = InetAddress.getLocalHost();
pserver = new ProxyTunnelServer(localhost);
/*
* register a system wide authenticator and setup the proxy for
* authentication
*/
Authenticator.setDefault(new TestAuthenticator());
// register with the username and password
pserver.needUserAuth(true);
pserver.setUserAuth("Test", "test123");
pserver.start();
return new InetSocketAddress(localhost, pserver.getPort());
}
public static class TestAuthenticator extends Authenticator {
public PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication("Test",
"test123".toCharArray());
}
}
private static String getHostname() {
try {
OutputAnalyzer oa = ProcessTools.executeCommand("hostname");
return oa.getOutput().trim();
} catch (Throwable e) {
throw new RuntimeException("Get hostname failed.", e);
}
}
}

View file

@ -0,0 +1,351 @@
/*
* Copyright (c) 2001, 2022, 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.
*/
/**
*
* This class includes a proxy server that processes HTTP CONNECT requests,
* and tunnels the data from the client to the server, once the CONNECT
* request is accepted.
* The proxy server processes only one transaction, i.e a CONNECT request
* followed by the corresponding tunnel data.
*/
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.util.Base64;
import javax.net.ServerSocketFactory;
import jdk.test.lib.net.HttpHeaderParser;
public class ProxyTunnelServer extends Thread {
private static final int TIMEOUT = 30000;
private static ServerSocket ss = null;
/*
* holds the registered user's username and password
* only one such entry is maintained
*/
private String userPlusPass;
// client requesting for a tunnel
private Socket clientSocket = null;
/*
* Origin server's address and port that the client
* wants to establish the tunnel for communication.
*/
private InetAddress serverInetAddr;
private int serverPort;
/*
* denote whether the proxy needs to authorize
* CONNECT requests.
*/
static boolean needAuth = false;
volatile long connectCount;
public ProxyTunnelServer() throws IOException {
if (ss == null) {
ss = (ServerSocket) ServerSocketFactory.getDefault()
.createServerSocket(0);
ss.setSoTimeout(TIMEOUT);
System.out.println("Proxy server created: " + ss);
}
}
public ProxyTunnelServer(InetAddress address) throws IOException {
if (ss == null) {
ss = (ServerSocket) ServerSocketFactory.getDefault()
.createServerSocket(0, 0, address);
ss.setSoTimeout(TIMEOUT);
System.out.println("Proxy server created: " + ss);
}
}
public void needUserAuth(boolean auth) {
needAuth = auth;
}
/*
* register users with the proxy, by providing username and
* password. The username and password are used for authorizing the
* user when a CONNECT request is made and needAuth is set to true.
*/
public void setUserAuth(String uname, String passwd) {
userPlusPass = uname + ":" + passwd;
}
public void run() {
try {
System.out.println("Proxy server listening at: " + ss);
clientSocket = ss.accept();
System.out.println("Proxy server accepted connection: " + clientSocket);
processRequests();
} catch (SocketTimeoutException e) {
System.out.println(
"Proxy can not get response in time: " + e.getMessage());
} catch (Exception e) {
System.out.println("Proxy Failed: " + e);
e.printStackTrace();
try {
ss.close();
}
catch (IOException excep) {
System.out.println("ProxyServer close error: " + excep);
excep.printStackTrace();
}
} finally {
System.out.println("Proxy server: request served");
}
}
/*
* Processes the CONNECT requests, if needAuth is set to true, then
* the name and password are extracted from the Proxy-Authorization header
* of the request. They are checked against the one that is registered,
* if there is a match, connection is set in tunneling mode. If
* needAuth is set to false, Proxy-Authorization checks are not made
*/
private void processRequests() throws Exception {
InputStream in = clientSocket.getInputStream();
HttpHeaderParser mheader = new HttpHeaderParser(in);
String statusLine = mheader.getRequestDetails();
if (statusLine.startsWith("CONNECT")) {
synchronized(this) { connectCount++; }
// retrieve the host and port info from the status-line
retrieveConnectInfo(statusLine);
if (needAuth) {
String authInfo;
if ((authInfo = (mheader.getHeaderValue("Proxy-Authorization") != null ?
mheader.getHeaderValue("Proxy-Authorization").get(0) : null))
!= null) {
if (authenticate(authInfo)) {
needAuth = false;
System.out.println(
"Proxy: client authentication successful");
}
}
}
respondForConnect(needAuth);
// connection set to the tunneling mode
if (!needAuth) {
doTunnel();
/*
* done with tunneling, we process only one successful
* tunneling request
*/
ss.close();
} else {
// we may get another request with Proxy-Authorization set
in.close();
clientSocket.close();
restart();
}
} else {
System.out.println("proxy server: processes only "
+ "CONNECT method requests, recieved: "
+ statusLine);
}
}
public long getConnectCount() {
return connectCount;
}
private void respondForConnect(boolean needAuth) throws Exception {
OutputStream out = clientSocket.getOutputStream();
PrintWriter pout = new PrintWriter(out);
if (needAuth) {
pout.println("HTTP/1.1 407 Proxy Auth Required");
pout.println("Proxy-Authenticate: Basic realm=\"WallyWorld\"");
pout.println();
pout.flush();
out.close();
} else {
pout.println("HTTP/1.1 200 OK");
pout.println();
pout.flush();
}
}
private void restart() throws IOException {
(new Thread(this)).start();
}
/*
* note: Tunneling has to be provided in both directions, i.e
* from client->server and server->client, even if the application
* data may be unidirectional, SSL handshaking data flows in either
* direction.
*/
private void doTunnel() throws Exception {
Socket serverSocket = new Socket(serverInetAddr, serverPort);
ProxyTunnel clientToServer = new ProxyTunnel(
clientSocket, serverSocket);
ProxyTunnel serverToClient = new ProxyTunnel(
serverSocket, clientSocket);
clientToServer.start();
serverToClient.start();
System.out.println("Proxy: Started tunneling.......");
clientToServer.join(TIMEOUT);
serverToClient.join(TIMEOUT);
System.out.println("Proxy: Finished tunneling........");
clientToServer.close();
serverToClient.close();
}
/*
* This inner class provides unidirectional data flow through the sockets
* by continuously copying bytes from the input socket onto the output
* socket, until both sockets are open and EOF has not been received.
*/
class ProxyTunnel extends Thread {
Socket sockIn;
Socket sockOut;
InputStream input;
OutputStream output;
public ProxyTunnel(Socket sockIn, Socket sockOut)
throws Exception {
this.sockIn = sockIn;
this.sockOut = sockOut;
input = sockIn.getInputStream();
output = sockOut.getOutputStream();
}
public void run() {
int BUFFER_SIZE = 400;
byte[] buf = new byte[BUFFER_SIZE];
int bytesRead = 0;
try {
while ((bytesRead = input.read(buf)) >= 0) {
output.write(buf, 0, bytesRead);
output.flush();
}
} catch (IOException e) {
/*
* The peer end has closed the connection
* we will close the tunnel
*/
close();
}
}
private void close() {
try {
if (!sockIn.isClosed())
sockIn.close();
if (!sockOut.isClosed())
sockOut.close();
} catch (IOException ignored) { }
}
}
/*
***************************************************************
* helper methods follow
***************************************************************
*/
/*
* This method retrieves the hostname and port of the destination
* that the connect request wants to establish a tunnel for
* communication.
* The input, connectStr is of the form:
* CONNECT server-name:server-port HTTP/1.x
*/
private void retrieveConnectInfo(String connectStr) throws Exception {
int starti;
int endi;
String connectInfo;
String serverName = null;
try {
starti = connectStr.indexOf(' ');
endi = connectStr.lastIndexOf(' ');
connectInfo = connectStr.substring(starti+1, endi).trim();
// retrieve server name and port
if (connectInfo.charAt(0) == '[') {
endi = connectInfo.indexOf(']');
serverName = connectInfo.substring(1, endi++);
assert connectInfo.charAt(endi) == ':' : "Expected [IPv6]:port";
} else {
endi = connectInfo.indexOf(':');
serverName = connectInfo.substring(0, endi);
}
serverPort = Integer.parseInt(connectInfo.substring(endi+1));
} catch (Exception e) {
throw new IOException("Proxy recieved a request: "
+ connectStr, e);
}
serverInetAddr = InetAddress.getByName(serverName);
}
public int getPort() {
return ss.getLocalPort();
}
/*
* do "basic" authentication, authInfo is of the form:
* Basic <encoded username":"password>
* reference RFC 2617
*/
private boolean authenticate(String authInfo) throws IOException {
boolean matched = false;
try {
authInfo.trim();
int ind = authInfo.indexOf(' ');
String recvdUserPlusPass = authInfo.substring(ind + 1).trim();
// extract encoded (username:passwd
if (userPlusPass.equals(
new String( Base64.getMimeDecoder()
.decode(recvdUserPlusPass))))
{
matched = true;
}
} catch (Exception e) {
throw new IOException(
"Proxy received invalid Proxy-Authorization value: "
+ authInfo);
}
return matched;
}
}

View file

@ -0,0 +1,364 @@
/*
* Copyright (c) 2003, 2019, 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.
*/
//
// SunJSSE does not support dynamic system properties, no way to re-use
// system properties in samevm/agentvm mode.
//
/*
* @test
* @bug 4811482 4700777 4905410
* @summary sun.net.client.defaultConnectTimeout should work with
* HttpsURLConnection; HTTP client: Connect and read timeouts;
* Https needs to support new tiger features that went into http
* @library /test/lib
* @run main/othervm ReadTimeout
*/
import java.io.*;
import java.net.*;
import javax.net.ssl.*;
import jdk.test.lib.net.URIBuilder;
public class ReadTimeout {
/*
* =============================================================
* Set the various variables needed for the tests, then
* specify what tests to run on each side.
*/
/*
* Should we run the client or server in a separate thread?
* Both sides can throw exceptions, but do you have a preference
* as to which side should be the main thread.
*/
static boolean separateServerThread = true;
/*
* Where do we find the keystores?
*/
static String pathToStores = "../../../../../../javax/net/ssl/etc";
static String keyStoreFile = "keystore";
static String trustStoreFile = "truststore";
static String passwd = "passphrase";
/*
* Is the server ready to serve?
*/
volatile static boolean serverReady = false;
/*
* Turn on SSL debugging?
*/
static boolean debug = false;
/*
* Message posted
*/
static String postMsg = "Testing HTTP post on a https server";
/*
* If the client or server is doing some kind of object creation
* that the other side depends on, and that thread prematurely
* exits, you may experience a hang. The test harness will
* terminate all hung threads after its timeout has expired,
* currently 3 minutes by default, but you might try to be
* smart about it....
*/
/*
* Define the server side of the test.
*
* If the server prematurely exits, serverReady will be set to true
* to avoid infinite hangs.
*/
void doServerSide() throws Exception {
InetAddress loopback = InetAddress.getLoopbackAddress();
SSLServerSocketFactory sslssf =
(SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
SSLServerSocket sslServerSocket =
(SSLServerSocket) sslssf.createServerSocket(serverPort, 0, loopback);
serverPort = sslServerSocket.getLocalPort();
/*
* Signal Client, we're ready for his connect.
*/
serverReady = true;
try {
try (SSLSocket sslSocket = (SSLSocket)sslServerSocket.accept()) {
InputStream sslIS = sslSocket.getInputStream();
BufferedReader br =
new BufferedReader(new InputStreamReader(sslIS));
br.readLine();
while (!finished()) {
Thread.sleep(2000);
}
}
reset();
// doing second test
try (SSLSocket sslSocket = (SSLSocket)sslServerSocket.accept()) {
InputStream sslIS = sslSocket.getInputStream();
BufferedReader br =
new BufferedReader(new InputStreamReader(sslIS));
br.readLine();
while (!finished()) {
Thread.sleep(2000);
}
}
} catch (Exception e) {
System.out.println("Should be an expected exception: " + e);
} finally {
sslServerSocket.close();
}
}
boolean isFinished = false;
synchronized boolean finished () {
return (isFinished);
}
synchronized void done () {
isFinished = true;
}
synchronized void reset() {
isFinished = false;
}
/*
* Define the client side of the test.
*
* If the server prematurely exits, serverReady will be set to true
* to avoid infinite hangs.
*/
void doClientSide() throws Exception {
HostnameVerifier reservedHV =
HttpsURLConnection.getDefaultHostnameVerifier();
try {
/*
* Wait for server to get started.
*/
while (!serverReady) {
Thread.sleep(50);
}
HttpsURLConnection http = null;
try {
URL url = URIBuilder.newBuilder()
.scheme("https")
.loopback()
.port(serverPort)
.toURL();
// set read timeout through system property
System.setProperty("sun.net.client.defaultReadTimeout", "2000");
HttpsURLConnection.setDefaultHostnameVerifier(
new NameVerifier());
http = (HttpsURLConnection)url.openConnection();
InputStream is = http.getInputStream();
throw new Exception(
"system property timeout configuration does not work");
} catch (SSLException | SocketTimeoutException ex) {
System.out.println("Got expected timeout exception for " +
"system property timeout configuration: " + getCause(ex));
} finally {
done();
http.disconnect();
}
try {
URL url = URIBuilder.newBuilder()
.scheme("https")
.loopback()
.port(serverPort)
.toURL();
HttpsURLConnection.setDefaultHostnameVerifier(
new NameVerifier());
http = (HttpsURLConnection)url.openConnection();
// set read timeout through API
http.setReadTimeout(2000);
InputStream is = http.getInputStream();
throw new Exception(
"HttpsURLConnection.setReadTimeout() does not work");
} catch (SSLException | SocketTimeoutException ex) {
System.out.println("Got expected timeout exception for " +
"HttpsURLConnection.setReadTimeout(): " + getCause(ex));
} finally {
done();
http.disconnect();
}
} finally {
HttpsURLConnection.setDefaultHostnameVerifier(reservedHV);
}
}
private Exception getCause(Exception ex) {
Exception cause = null;
if (ex instanceof SSLException) {
cause = (Exception) ex.getCause();
if (!(cause instanceof SocketTimeoutException)) {
throw new RuntimeException("Unexpected cause", cause);
}
} else {
cause = ex;
}
return cause;
}
static class NameVerifier implements HostnameVerifier {
public boolean verify(String hostname, SSLSession session) {
return true;
}
}
/*
* =============================================================
* The remainder is just support stuff
*/
// use any free port by default
volatile int serverPort = 0;
volatile Exception serverException = null;
volatile Exception clientException = null;
private boolean sslConnectionFailed() {
return clientException instanceof SSLHandshakeException;
}
public static void main(String[] args) throws Exception {
String keyFilename =
System.getProperty("test.src", "./") + "/" + pathToStores +
"/" + keyStoreFile;
String trustFilename =
System.getProperty("test.src", "./") + "/" + pathToStores +
"/" + trustStoreFile;
System.setProperty("javax.net.ssl.keyStore", keyFilename);
System.setProperty("javax.net.ssl.keyStorePassword", passwd);
System.setProperty("javax.net.ssl.trustStore", trustFilename);
System.setProperty("javax.net.ssl.trustStorePassword", passwd);
if (debug)
System.setProperty("javax.net.debug", "all");
/*
* Start the tests.
*/
new ReadTimeout();
}
Thread clientThread = null;
Thread serverThread = null;
/*
* Primary constructor, used to drive remainder of the test.
*
* Fork off the other side, then do your work.
*/
ReadTimeout() throws Exception {
if (separateServerThread) {
startServer(true);
startClient(false);
} else {
startClient(true);
startServer(false);
}
/*
* Wait for other side to close down.
*/
if (separateServerThread) {
if (!sslConnectionFailed()) {
serverThread.join();
}
} else {
clientThread.join();
}
/*
* When we get here, the test is pretty much over.
*
* If the main thread excepted, that propagates back
* immediately. If the other thread threw an exception, we
* should report back.
*/
if (serverException != null)
throw serverException;
if (clientException != null)
throw clientException;
}
void startServer(boolean newThread) throws Exception {
if (newThread) {
serverThread = new Thread() {
public void run() {
try {
doServerSide();
} catch (Exception e) {
/*
* Our server thread just died.
*
* Release the client, if not active already...
*/
System.err.println("Server died...");
serverReady = true;
serverException = e;
}
}
};
serverThread.start();
} else {
doServerSide();
}
}
void startClient(boolean newThread) throws Exception {
if (newThread) {
clientThread = new Thread() {
public void run() {
try {
doClientSide();
} catch (Exception e) {
/*
* Our client thread just died.
*/
System.err.println("Client died...");
clientException = e;
}
}
};
clientThread.start();
} else {
doClientSide();
}
}
}

View file

@ -0,0 +1,311 @@
/*
* Copyright (c) 2001, 2019, 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 4423074
* @summary Need to rebase all the duplicated classes from Merlin.
* This test will check out http POST
* @library /test/lib
* @run main/othervm Redirect
*
* SunJSSE does not support dynamic system properties, no way to re-use
* system properties in samevm/agentvm mode.
*/
import java.io.*;
import java.net.*;
import javax.net.ssl.*;
import jdk.test.lib.net.URIBuilder;
public class Redirect {
/*
* =============================================================
* Set the various variables needed for the tests, then
* specify what tests to run on each side.
*/
/*
* Should we run the client or server in a separate thread?
* Both sides can throw exceptions, but do you have a preference
* as to which side should be the main thread.
*/
static boolean separateServerThread = true;
/*
* Where do we find the keystores?
*/
static String pathToStores = "../../../../../../javax/net/ssl/etc";
static String keyStoreFile = "keystore";
static String trustStoreFile = "truststore";
static String passwd = "passphrase";
/*
* Is the server ready to serve?
*/
volatile static boolean serverReady = false;
/*
* Is the connection ready to close?
*/
volatile static boolean closeReady = false;
/*
* Turn on SSL debugging?
*/
static boolean debug = false;
/*
* Message posted
*/
static String postMsg = "Testing HTTP post on a https server";
/*
* If the client or server is doing some kind of object creation
* that the other side depends on, and that thread prematurely
* exits, you may experience a hang. The test harness will
* terminate all hung threads after its timeout has expired,
* currently 3 minutes by default, but you might try to be
* smart about it....
*/
/*
* Define the server side of the test.
*
* If the server prematurely exits, serverReady will be set to true
* to avoid infinite hangs.
*/
void doServerSide() throws Exception {
InetAddress loopback = InetAddress.getLoopbackAddress();
SSLServerSocketFactory sslssf =
(SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
SSLServerSocket sslServerSocket =
(SSLServerSocket) sslssf.createServerSocket(serverPort, 0, loopback);
serverPort = sslServerSocket.getLocalPort();
/*
* Signal Client, we're ready for his connect.
*/
serverReady = true;
SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
try {
InputStream sslIS = sslSocket.getInputStream();
OutputStream sslOS = sslSocket.getOutputStream();
BufferedReader br =
new BufferedReader(new InputStreamReader(sslIS));
PrintStream ps = new PrintStream(sslOS);
// process HTTP POST request from client
System.out.println("status line: "+br.readLine());
ps.println("HTTP/1.1 307 Redirect");
ps.println("Location: https://localhost:" + serverPort +
"/index.html\n\n");
ps.flush();
sslSocket = (SSLSocket) sslServerSocket.accept();
sslOS = sslSocket.getOutputStream();
ps = new PrintStream(sslOS);
ps.println("HTTP/1.1 200 Redirect succeeded\n\n");
ps.flush();
} finally {
// close the socket
while (!closeReady) {
Thread.sleep(50);
}
sslSocket.close();
sslServerSocket.close();
}
}
/*
* Define the client side of the test.
*
* If the server prematurely exits, serverReady will be set to true
* to avoid infinite hangs.
*/
void doClientSide() throws Exception {
HostnameVerifier reservedHV =
HttpsURLConnection.getDefaultHostnameVerifier();
try {
/*
* Wait for server to get started.
*/
while (!serverReady) {
Thread.sleep(50);
}
// Send HTTP POST request to server
URL url = URIBuilder.newBuilder()
.scheme("https")
.loopback()
.port(serverPort)
.toURL();
HttpsURLConnection.setDefaultHostnameVerifier(
new NameVerifier());
HttpsURLConnection http = (HttpsURLConnection)url.openConnection();
try {
System.out.println("response header: "+http.getHeaderField(0));
if (http.getResponseCode() != 200) {
throw new RuntimeException("test Failed");
}
} finally {
http.disconnect();
closeReady = true;
}
} finally {
HttpsURLConnection.setDefaultHostnameVerifier(reservedHV);
}
}
static class NameVerifier implements HostnameVerifier {
public boolean verify(String hostname, SSLSession session) {
return true;
}
}
/*
* =============================================================
* The remainder is just support stuff
*/
// use any free port by default
volatile int serverPort = 0;
volatile Exception serverException = null;
volatile Exception clientException = null;
private boolean sslConnectionFailed() {
return clientException instanceof SSLHandshakeException;
}
public static void main(String[] args) throws Exception {
String keyFilename =
System.getProperty("test.src", "./") + "/" + pathToStores +
"/" + keyStoreFile;
String trustFilename =
System.getProperty("test.src", "./") + "/" + pathToStores +
"/" + trustStoreFile;
System.setProperty("javax.net.ssl.keyStore", keyFilename);
System.setProperty("javax.net.ssl.keyStorePassword", passwd);
System.setProperty("javax.net.ssl.trustStore", trustFilename);
System.setProperty("javax.net.ssl.trustStorePassword", passwd);
if (debug)
System.setProperty("javax.net.debug", "all");
/*
* Start the tests.
*/
new Redirect();
}
Thread clientThread = null;
Thread serverThread = null;
/*
* Primary constructor, used to drive remainder of the test.
*
* Fork off the other side, then do your work.
*/
Redirect() throws Exception {
if (separateServerThread) {
startServer(true);
startClient(false);
} else {
startClient(true);
startServer(false);
}
/*
* Wait for other side to close down.
*/
if (separateServerThread) {
if (!sslConnectionFailed()) {
serverThread.join();
}
} else {
clientThread.join();
}
/*
* When we get here, the test is pretty much over.
*
* If the main thread excepted, that propagates back
* immediately. If the other thread threw an exception, we
* should report back.
*/
if (serverException != null)
throw serverException;
if (clientException != null)
throw clientException;
}
void startServer(boolean newThread) throws Exception {
if (newThread) {
serverThread = new Thread() {
public void run() {
try {
doServerSide();
} catch (Exception e) {
/*
* Our server thread just died.
*
* Release the client, if not active already...
*/
System.err.println("Server died...");
serverReady = true;
serverException = e;
}
}
};
serverThread.start();
} else {
doServerSide();
}
}
void startClient(boolean newThread) throws Exception {
if (newThread) {
clientThread = new Thread() {
public void run() {
try {
doClientSide();
} catch (Exception e) {
/*
* Our client thread just died.
*/
System.err.println("Client died...");
clientException = e;
}
}
};
clientThread.start();
} else {
doClientSide();
}
}
}

View file

@ -0,0 +1,313 @@
/*
* Copyright (c) 2003, 2019, 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 4799427
* @summary Https can not retry request
* @library /test/lib
* @run main/othervm RetryHttps
* @run main/othervm -Djava.net.preferIPv6Addresses=true RetryHttps
*
* SunJSSE does not support dynamic system properties, no way to re-use
* system properties in samevm/agentvm mode.
* @author Yingxian Wang
*/
import java.net.*;
import java.util.*;
import java.io.*;
import javax.net.ssl.*;
import jdk.test.lib.net.URIBuilder;
public class RetryHttps {
static Map cookies;
ServerSocket ss;
/*
* =============================================================
* Set the various variables needed for the tests, then
* specify what tests to run on each side.
*/
/*
* Should we run the client or server in a separate thread?
* Both sides can throw exceptions, but do you have a preference
* as to which side should be the main thread.
*/
static boolean separateServerThread = true;
/*
* Where do we find the keystores?
*/
static String pathToStores = "../../../../../../javax/net/ssl/etc";
static String keyStoreFile = "keystore";
static String trustStoreFile = "truststore";
static String passwd = "passphrase";
/*
* Is the server ready to serve?
*/
volatile static boolean serverReady = false;
/*
* Turn on SSL debugging?
*/
static boolean debug = true;
private SSLServerSocket sslServerSocket = null;
/*
* Define the server side of the test.
*
* If the server prematurely exits, serverReady will be set to true
* to avoid infinite hangs.
*/
void doServerSide() throws Exception {
InetAddress loopback = InetAddress.getLoopbackAddress();
SSLServerSocketFactory sslssf =
(SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
sslServerSocket =
(SSLServerSocket) sslssf.createServerSocket(serverPort, 0, loopback);
serverPort = sslServerSocket.getLocalPort();
System.out.println("Starting server at: "
+ sslServerSocket.getInetAddress()
+ ":" + serverPort);
/*
* Signal Client, we're ready for his connect.
*/
serverReady = true;
SSLSocket sslSocket = null;
try {
for (int i = 0; i < 2; i++) {
sslSocket = (SSLSocket) sslServerSocket.accept();
// read request
InputStream is = sslSocket.getInputStream ();
BufferedReader r = new BufferedReader(new InputStreamReader(is));
boolean flag = false;
String x;
while ((x=r.readLine()) != null) {
if (x.length() ==0) {
break;
}
}
PrintStream out = new PrintStream(
new BufferedOutputStream(
sslSocket.getOutputStream() ));
/* send the header */
out.print("HTTP/1.1 200 OK\r\n");
out.print("Content-Type: text/html; charset=iso-8859-1\r\n");
out.print("Content-Length: "+10+"\r\n");
out.print("\r\n");
out.print("Testing"+i+"\r\n");
out.flush();
sslSocket.close();
}
sslServerSocket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/*
* Define the client side of the test.
*
* If the server prematurely exits, serverReady will be set to true
* to avoid infinite hangs.
*/
void doClientSide() throws Exception {
HostnameVerifier reservedHV =
HttpsURLConnection.getDefaultHostnameVerifier();
try {
/*
* Wait for server to get started.
*/
while (!serverReady) {
Thread.sleep(50);
}
try {
HttpsURLConnection http = null;
/* establish http connection to server */
URL url = URIBuilder.newBuilder()
.scheme("https")
.loopback()
.port(serverPort)
.path("/file1")
.toURL();
System.out.println("url is "+url.toString());
HttpsURLConnection.setDefaultHostnameVerifier(
new NameVerifier());
http = (HttpsURLConnection)url.openConnection(Proxy.NO_PROXY);
int respCode = http.getResponseCode();
int cl = http.getContentLength();
InputStream is = http.getInputStream ();
int count = 0;
while (is.read() != -1 && count++ < cl);
System.out.println("respCode1 = "+respCode);
Thread.sleep(2000);
url = URIBuilder.newBuilder()
.scheme("https")
.loopback()
.port(serverPort)
.path("/file2")
.toURL();
http = (HttpsURLConnection)url.openConnection(Proxy.NO_PROXY);
respCode = http.getResponseCode();
System.out.println("respCode2 = "+respCode);
} catch (IOException ioex) {
if (sslServerSocket != null)
sslServerSocket.close();
throw ioex;
}
} finally {
HttpsURLConnection.setDefaultHostnameVerifier(reservedHV);
}
}
static class NameVerifier implements HostnameVerifier {
public boolean verify(String hostname, SSLSession session) {
return true;
}
}
/*
* =============================================================
* The remainder is just support stuff
*/
// use any free port by default
volatile int serverPort = 0;
volatile Exception serverException = null;
volatile Exception clientException = null;
public static void main(String args[]) throws Exception {
String keyFilename =
System.getProperty("test.src", "./") + "/" + pathToStores +
"/" + keyStoreFile;
String trustFilename =
System.getProperty("test.src", "./") + "/" + pathToStores +
"/" + trustStoreFile;
System.setProperty("javax.net.ssl.keyStore", keyFilename);
System.setProperty("javax.net.ssl.keyStorePassword", passwd);
System.setProperty("javax.net.ssl.trustStore", trustFilename);
System.setProperty("javax.net.ssl.trustStorePassword", passwd);
if (debug)
System.setProperty("javax.net.debug", "all");
/*
* Start the tests.
*/
new RetryHttps();
}
Thread clientThread = null;
Thread serverThread = null;
/*
* Primary constructor, used to drive remainder of the test.
*
* Fork off the other side, then do your work.
*/
RetryHttps() throws Exception {
if (separateServerThread) {
startServer(true);
startClient(false);
} else {
startClient(true);
startServer(false);
}
/*
* Wait for other side to close down.
*/
if (separateServerThread) {
serverThread.join();
} else {
clientThread.join();
}
/*
* When we get here, the test is pretty much over.
*
* If the main thread excepted, that propagates back
* immediately. If the other thread threw an exception, we
* should report back.
*/
if (serverException != null)
throw serverException;
if (clientException != null)
throw clientException;
}
void startServer(boolean newThread) throws Exception {
if (newThread) {
serverThread = new Thread() {
public void run() {
try {
doServerSide();
} catch (Exception e) {
/*
* Our server thread just died.
*
* Release the client, if not active already...
*/
System.err.println("Server died...");
serverReady = true;
serverException = e;
}
}
};
serverThread.start();
} else {
doServerSide();
}
}
void startClient(boolean newThread) throws Exception {
if (newThread) {
clientThread = new Thread() {
public void run() {
try {
doClientSide();
} catch (Exception e) {
/*
* Our client thread just died.
*/
System.err.println("Client died...");
clientException = e;
}
}
};
clientThread.start();
} else {
doClientSide();
}
}
}

View file

@ -0,0 +1,3 @@
modules = \
java.base/sun.security.util \
java.base/sun.security.x509

View file

@ -0,0 +1,737 @@
/*
* Copyright (c) 2005, 2022, 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.
*/
/*
*
*/
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.BufferOverflowException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;
import jdk.test.lib.net.HttpHeaderParser;
public class TunnelProxy {
ServerSocketChannel schan;
int threads;
int cperthread;
Server[] servers;
/**
* Create a <code>TunnelProxy<code> instance with the specified callback object
* for handling requests. One thread is created to handle requests,
* and up to ten TCP connections will be handled simultaneously.
* incoming request
*/
public TunnelProxy () throws IOException {
this (1, 10, 0);
}
/**
* Create a <code>TunnelProxy<code> instance with the specified number of
* threads and maximum number of connections per thread. This functions
* the same as the 4 arg constructor, where the port argument is set to zero.
* @param threads the number of threads to create to handle requests
* in parallel
* @param cperthread the number of simultaneous TCP connections to
* handle per thread
*/
public TunnelProxy (int threads, int cperthread)
throws IOException {
this (threads, cperthread, 0);
}
/**
* Create a <code>TunnelProxy<code> instance with the specified number
* of threads and maximum number of connections per thread and running on
* the specified port. The specified number of threads are created to
* handle incoming requests, and each thread is allowed
* to handle a number of simultaneous TCP connections.
* @param threads the number of threads to create to handle
* requests in parallel
* @param cperthread the number of simultaneous TCP connections
* to handle per thread
* @param port the port number to bind the server to. <code>Zero</code>
* means choose any free port.
*/
public TunnelProxy (int threads, int cperthread, int port)
throws IOException {
this(threads, cperthread, null, 0);
}
/**
* Create a <code>TunnelProxy<code> instance with the specified number
* of threads and maximum number of connections per thread and running on
* the specified port. The specified number of threads are created to
* handle incoming requests, and each thread is allowed
* to handle a number of simultaneous TCP connections.
* @param threads the number of threads to create to handle
* requests in parallel
* @param cperthread the number of simultaneous TCP connections
* to handle per thread
* @param address the address to bind to. null means all addresses.
* @param port the port number to bind the server to. <code>Zero</code>
* means choose any free port.
*/
public TunnelProxy (int threads, int cperthread, InetAddress address, int port)
throws IOException {
schan = ServerSocketChannel.open ();
InetSocketAddress addr = new InetSocketAddress (address, port);
schan.socket().bind (addr);
this.threads = threads;
this.cperthread = cperthread;
servers = new Server [threads];
for (int i=0; i<threads; i++) {
servers[i] = new Server (schan, cperthread);
servers[i].start();
}
}
/** Tell all threads in the server to exit within 5 seconds.
* This is an abortive termination. Just prior to the thread exiting
* all channels in that thread waiting to be closed are forceably closed.
*/
public void terminate () {
for (int i=0; i<threads; i++) {
servers[i].terminate ();
}
}
/**
* return the local port number to which the server is bound.
* @return the local port number
*/
public int getLocalPort () {
return schan.socket().getLocalPort ();
}
static class Server extends Thread {
ServerSocketChannel schan;
Selector selector;
SelectionKey listenerKey;
SelectionKey key; /* the current key being processed */
ByteBuffer consumeBuffer;
int maxconn;
int nconn;
ClosedChannelList clist;
boolean shutdown;
Pipeline pipe1 = null;
Pipeline pipe2 = null;
Server (ServerSocketChannel schan, int maxconn) {
this.schan = schan;
this.maxconn = maxconn;
nconn = 0;
consumeBuffer = ByteBuffer.allocate (512);
clist = new ClosedChannelList ();
try {
selector = Selector.open ();
schan.configureBlocking (false);
listenerKey = schan.register (selector, SelectionKey.OP_ACCEPT);
} catch (IOException e) {
System.err.println ("Server could not start: " + e);
}
}
/* Stop the thread as soon as possible */
public synchronized void terminate () {
shutdown = true;
if (pipe1 != null) pipe1.terminate();
if (pipe2 != null) pipe2.terminate();
}
public void run () {
try {
while (true) {
selector.select (1000);
Set selected = selector.selectedKeys();
Iterator iter = selected.iterator();
while (iter.hasNext()) {
key = (SelectionKey)iter.next();
if (key.equals (listenerKey)) {
SocketChannel sock = schan.accept ();
if (sock == null) {
/* false notification */
iter.remove();
continue;
}
sock.configureBlocking (false);
sock.register (selector, SelectionKey.OP_READ);
nconn ++;
if (nconn == maxconn) {
/* deregister */
listenerKey.cancel ();
listenerKey = null;
}
} else {
if (key.isReadable()) {
boolean closed;
SocketChannel chan = (SocketChannel) key.channel();
if (key.attachment() != null) {
closed = consume (chan);
} else {
closed = read (chan, key);
}
if (closed) {
chan.close ();
key.cancel ();
if (nconn == maxconn) {
listenerKey = schan.register (selector, SelectionKey.OP_ACCEPT);
}
nconn --;
}
}
}
iter.remove();
}
clist.check();
if (shutdown) {
clist.terminate ();
return;
}
}
} catch (IOException e) {
System.out.println ("Server exception: " + e);
// TODO finish
}
}
/* read all the data off the channel without looking at it
* return true if connection closed
*/
boolean consume (SocketChannel chan) {
try {
consumeBuffer.clear ();
int c = chan.read (consumeBuffer);
if (c == -1)
return true;
} catch (IOException e) {
return true;
}
return false;
}
/* return true if the connection is closed, false otherwise */
private boolean read (SocketChannel chan, SelectionKey key) {
boolean res;
try {
InputStream is = new BufferedInputStream (new NioInputStream (chan));
HttpHeaderParser mHead = new HttpHeaderParser (is);
String requestLine = mHead.getRequestDetails();
String[] req = requestLine.split (" ");
if (req.length < 2) {
/* invalid request line */
return false;
}
String cmd = req[0];
URI uri = null;
if (!("CONNECT".equalsIgnoreCase(cmd))) {
// we expect CONNECT command
return false;
}
try {
uri = new URI("http://" + req[1]);
} catch (URISyntaxException e) {
System.err.println ("Invalid URI: " + e);
res = true;
}
// CONNECT ack
OutputStream os = new BufferedOutputStream(new NioOutputStream(chan));
byte[] ack = "HTTP/1.1 200 Connection established\r\n\r\n".getBytes();
os.write(ack, 0, ack.length);
os.flush();
// tunnel anything else
tunnel(is, os, uri);
res = false;
} catch (IOException e) {
res = true;
}
return res;
}
private void tunnel(InputStream fromClient, OutputStream toClient, URI serverURI) throws IOException {
Socket sockToServer = new Socket(serverURI.getHost(), serverURI.getPort());
OutputStream toServer = sockToServer.getOutputStream();
InputStream fromServer = sockToServer.getInputStream();
pipe1 = new Pipeline(fromClient, toServer);
pipe2 = new Pipeline(fromServer, toClient);
// start pump
pipe1.start();
pipe2.start();
// wait them to end
try {
pipe1.join();
} catch (InterruptedException e) {
// No-op
} finally {
sockToServer.close();
}
}
private String readLine (InputStream is) throws IOException {
boolean done=false, readCR=false;
byte[] b = new byte [512];
int c, l = 0;
while (!done) {
c = is.read ();
if (c == '\n' && readCR) {
done = true;
} else {
if (c == '\r' && !readCR) {
readCR = true;
} else {
b[l++] = (byte)c;
}
}
}
return new String (b);
}
/** close the channel associated with the current key by:
* 1. shutdownOutput (send a FIN)
* 2. mark the key so that incoming data is to be consumed and discarded
* 3. After a period, close the socket
*/
synchronized void orderlyCloseChannel (SelectionKey key) throws IOException {
SocketChannel ch = (SocketChannel)key.channel ();
ch.socket().shutdownOutput();
key.attach (this);
clist.add (key);
}
synchronized void abortiveCloseChannel (SelectionKey key) throws IOException {
SocketChannel ch = (SocketChannel)key.channel ();
Socket s = ch.socket ();
s.setSoLinger (true, 0);
ch.close();
}
}
/**
* Implements blocking reading semantics on top of a non-blocking channel
*/
static class NioInputStream extends InputStream {
SocketChannel channel;
Selector selector;
ByteBuffer chanbuf;
SelectionKey key;
int available;
byte[] one;
boolean closed;
ByteBuffer markBuf; /* reads may be satisifed from this buffer */
boolean marked;
boolean reset;
int readlimit;
public NioInputStream (SocketChannel chan) throws IOException {
this.channel = chan;
selector = Selector.open();
chanbuf = ByteBuffer.allocate (1024);
key = chan.register (selector, SelectionKey.OP_READ);
available = 0;
one = new byte[1];
closed = marked = reset = false;
}
public synchronized int read (byte[] b) throws IOException {
return read (b, 0, b.length);
}
public synchronized int read () throws IOException {
return read (one, 0, 1);
}
public synchronized int read (byte[] b, int off, int srclen) throws IOException {
int canreturn, willreturn;
if (closed)
return -1;
if (reset) { /* satisfy from markBuf */
canreturn = markBuf.remaining ();
willreturn = canreturn>srclen ? srclen : canreturn;
markBuf.get(b, off, willreturn);
if (canreturn == willreturn) {
reset = false;
}
} else { /* satisfy from channel */
canreturn = available();
if (canreturn == 0) {
block ();
canreturn = available();
}
willreturn = canreturn>srclen ? srclen : canreturn;
chanbuf.get(b, off, willreturn);
available -= willreturn;
if (marked) { /* copy into markBuf */
try {
markBuf.put (b, off, willreturn);
} catch (BufferOverflowException e) {
marked = false;
}
}
}
return willreturn;
}
public synchronized int available () throws IOException {
if (closed)
throw new IOException ("Stream is closed");
if (reset)
return markBuf.remaining();
if (available > 0)
return available;
chanbuf.clear ();
available = channel.read (chanbuf);
if (available > 0)
chanbuf.flip();
else if (available == -1)
throw new IOException ("Stream is closed");
return available;
}
/**
* block() only called when available==0 and buf is empty
*/
private synchronized void block () throws IOException {
//assert available == 0;
int n = selector.select ();
//assert n == 1;
selector.selectedKeys().clear();
available ();
}
public void close () throws IOException {
if (closed)
return;
channel.close ();
closed = true;
}
public synchronized void mark (int readlimit) {
if (closed)
return;
this.readlimit = readlimit;
markBuf = ByteBuffer.allocate (readlimit);
marked = true;
reset = false;
}
public synchronized void reset () throws IOException {
if (closed )
return;
if (!marked)
throw new IOException ("Stream not marked");
marked = false;
reset = true;
markBuf.flip ();
}
}
static class NioOutputStream extends OutputStream {
SocketChannel channel;
ByteBuffer buf;
SelectionKey key;
Selector selector;
boolean closed;
byte[] one;
public NioOutputStream (SocketChannel channel) throws IOException {
this.channel = channel;
selector = Selector.open ();
key = channel.register (selector, SelectionKey.OP_WRITE);
closed = false;
one = new byte [1];
}
public synchronized void write (int b) throws IOException {
one[0] = (byte)b;
write (one, 0, 1);
}
public synchronized void write (byte[] b) throws IOException {
write (b, 0, b.length);
}
public synchronized void write (byte[] b, int off, int len) throws IOException {
if (closed)
throw new IOException ("stream is closed");
buf = ByteBuffer.allocate (len);
buf.put (b, off, len);
buf.flip ();
int n;
while ((n = channel.write (buf)) < len) {
len -= n;
if (len == 0)
return;
selector.select ();
selector.selectedKeys().clear ();
}
}
public void close () throws IOException {
if (closed)
return;
channel.close ();
closed = true;
}
}
/*
* Pipeline object :-
* 1) Will pump every byte from its input stream to output stream
* 2) Is an 'active object'
*/
static class Pipeline implements Runnable {
InputStream in;
OutputStream out;
Thread t;
public Pipeline(InputStream is, OutputStream os) {
in = is;
out = os;
}
public void start() {
t = new Thread(this);
t.start();
}
public void join() throws InterruptedException {
t.join();
}
public void terminate() {
t.interrupt();
}
public void run() {
byte[] buffer = new byte[10000];
try {
while (!Thread.interrupted()) {
int len;
while ((len = in.read(buffer)) != -1) {
out.write(buffer, 0, len);
out.flush();
}
}
} catch(IOException e) {
// No-op
} finally {
}
}
}
/**
* Utilities for synchronization. A condition is
* identified by a string name, and is initialized
* upon first use (ie. setCondition() or waitForCondition()). Threads
* are blocked until some thread calls (or has called) setCondition() for the same
* condition.
* <P>
* A rendezvous built on a condition is also provided for synchronizing
* N threads.
*/
private static HashMap conditions = new HashMap();
/*
* Modifiable boolean object
*/
private static class BValue {
boolean v;
}
/*
* Modifiable int object
*/
private static class IValue {
int v;
IValue (int i) {
v =i;
}
}
private static BValue getCond (String condition) {
synchronized (conditions) {
BValue cond = (BValue) conditions.get (condition);
if (cond == null) {
cond = new BValue();
conditions.put (condition, cond);
}
return cond;
}
}
/**
* Set the condition to true. Any threads that are currently blocked
* waiting on the condition, will be unblocked and allowed to continue.
* Threads that subsequently call waitForCondition() will not block.
* If the named condition did not exist prior to the call, then it is created
* first.
*/
public static void setCondition (String condition) {
BValue cond = getCond (condition);
synchronized (cond) {
if (cond.v) {
return;
}
cond.v = true;
cond.notifyAll();
}
}
/**
* If the named condition does not exist, then it is created and initialized
* to false. If the condition exists or has just been created and its value
* is false, then the thread blocks until another thread sets the condition.
* If the condition exists and is already set to true, then this call returns
* immediately without blocking.
*/
public static void waitForCondition (String condition) {
BValue cond = getCond (condition);
synchronized (cond) {
if (!cond.v) {
try {
cond.wait();
} catch (InterruptedException e) {}
}
}
}
/* conditions must be locked when accessing this */
static HashMap rv = new HashMap();
/**
* Force N threads to rendezvous (ie. wait for each other) before proceeding.
* The first thread(s) to call are blocked until the last
* thread makes the call. Then all threads continue.
* <p>
* All threads that call with the same condition name, must use the same value
* for N (or the results may be not be as expected).
* <P>
* Obviously, if fewer than N threads make the rendezvous then the result
* will be a hang.
*/
public static void rendezvous (String condition, int N) {
BValue cond;
IValue iv;
String name = "RV_"+condition;
/* get the condition */
synchronized (conditions) {
cond = (BValue)conditions.get (name);
if (cond == null) {
/* we are first caller */
if (N < 2) {
throw new RuntimeException ("rendezvous must be called with N >= 2");
}
cond = new BValue ();
conditions.put (name, cond);
iv = new IValue (N-1);
rv.put (name, iv);
} else {
/* already initialised, just decrement the counter */
iv = (IValue) rv.get (name);
iv.v --;
}
}
if (iv.v > 0) {
waitForCondition (name);
} else {
setCondition (name);
synchronized (conditions) {
clearCondition (name);
rv.remove (name);
}
}
}
/**
* If the named condition exists and is set then remove it, so it can
* be re-initialized and used again. If the condition does not exist, or
* exists but is not set, then the call returns without doing anything.
* Note, some higher level synchronization
* may be needed between clear and the other operations.
*/
public static void clearCondition(String condition) {
BValue cond;
synchronized (conditions) {
cond = (BValue) conditions.get (condition);
if (cond == null) {
return;
}
synchronized (cond) {
if (cond.v) {
conditions.remove (condition);
}
}
}
}
}

View file

@ -0,0 +1,384 @@
/*
* Copyright (c) 2001, 2019, 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 4474255
* @summary Can no longer obtain a com.sun.net.ssl.HttpsURLConnection
* @library /test/lib
* @run main/othervm JavaxHTTPSConnection
* @run main/othervm -Djava.net.preferIPv6Addresses=true JavaxHTTPSConnection
*
* SunJSSE does not support dynamic system properties, no way to re-use
* system properties in samevm/agentvm mode.
* @author Brad Wetmore
*/
import java.io.*;
import java.net.*;
import java.security.cert.*;
import javax.net.ssl.*;
import jdk.test.lib.net.URIBuilder;
/**
* See if we can obtain a javax.net.ssl.HttpsURLConnection,
* and then play with it a bit.
*/
public class JavaxHTTPSConnection {
/*
* =============================================================
* Set the various variables needed for the tests, then
* specify what tests to run on each side.
*/
/*
* Should we run the client or server in a separate thread?
* Both sides can throw exceptions, but do you have a preference
* as to which side should be the main thread.
*/
static boolean separateServerThread = true;
/*
* Where do we find the keystores?
*/
static String pathToStores = "../../../../../../javax/net/ssl/etc";
static String keyStoreFile = "keystore";
static String trustStoreFile = "truststore";
static String passwd = "passphrase";
/*
* Is the server ready to serve?
*/
volatile static boolean serverReady = false;
/*
* Turn on SSL debugging?
*/
static boolean debug = false;
/*
* If the client or server is doing some kind of object creation
* that the other side depends on, and that thread prematurely
* exits, you may experience a hang. The test harness will
* terminate all hung threads after its timeout has expired,
* currently 3 minutes by default, but you might try to be
* smart about it....
*/
/**
* Returns the path to the file obtained from
* parsing the HTML header.
*/
private static String getPath(DataInputStream in)
throws IOException
{
String line = in.readLine();
String path = "";
// extract class from GET line
if (line.startsWith("GET /")) {
line = line.substring(5, line.length()-1).trim();
int index = line.indexOf(' ');
if (index != -1) {
path = line.substring(0, index);
}
}
// eat the rest of header
do {
line = in.readLine();
} while ((line.length() != 0) &&
(line.charAt(0) != '\r') && (line.charAt(0) != '\n'));
if (path.length() != 0) {
return path;
} else {
throw new IOException("Malformed Header");
}
}
/**
* Returns an array of bytes containing the bytes for
* the file represented by the argument <b>path</b>.
*
* In our case, we just pretend to send something back.
*
* @return the bytes for the file
* @exception FileNotFoundException if the file corresponding
* to <b>path</b> could not be loaded.
*/
private byte[] getBytes(String path)
throws IOException
{
return "Hello world, I am here".getBytes();
}
/*
* Define the server side of the test.
*
* If the server prematurely exits, serverReady will be set to true
* to avoid infinite hangs.
*/
void doServerSide() throws Exception {
InetAddress loopback = InetAddress.getLoopbackAddress();
InetSocketAddress serverAddress = new InetSocketAddress(loopback, serverPort);
SSLServerSocketFactory sslssf =
(SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
SSLServerSocket sslServerSocket =
(SSLServerSocket) sslssf.createServerSocket();
sslServerSocket.bind(serverAddress);
serverPort = sslServerSocket.getLocalPort();
/*
* Signal Client, we're ready for his connect.
*/
serverReady = true;
SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
DataOutputStream out =
new DataOutputStream(sslSocket.getOutputStream());
try {
// get path to class file from header
DataInputStream in =
new DataInputStream(sslSocket.getInputStream());
String path = getPath(in);
// retrieve bytecodes
byte[] bytecodes = getBytes(path);
// send bytecodes in response (assumes HTTP/1.0 or later)
try {
out.writeBytes("HTTP/1.0 200 OK\r\n");
out.writeBytes("Content-Length: " + bytecodes.length + "\r\n");
out.writeBytes("Content-Type: text/html\r\n\r\n");
out.write(bytecodes);
out.flush();
} catch (IOException ie) {
ie.printStackTrace();
return;
}
} catch (Exception e) {
e.printStackTrace();
// write out error response
out.writeBytes("HTTP/1.0 400 " + e.getMessage() + "\r\n");
out.writeBytes("Content-Type: text/html\r\n\r\n");
out.flush();
} finally {
// close the socket
System.out.println("Server closing socket");
sslSocket.close();
serverReady = false;
}
}
/*
* Define the client side of the test.
*
* If the server prematurely exits, serverReady will be set to true
* to avoid infinite hangs.
*/
void doClientSide() throws Exception {
HostnameVerifier reservedHV =
HttpsURLConnection.getDefaultHostnameVerifier();
try {
/*
* Wait for server to get started.
*/
while (!serverReady) {
Thread.sleep(50);
}
HttpsURLConnection.setDefaultHostnameVerifier(new NameVerifier());
URL url = URIBuilder.newBuilder()
.scheme("https")
.loopback()
.port(serverPort)
.path("/etc/hosts")
.toURL();
System.out.println("Client opening: " + url);
URLConnection urlc = url.openConnection(Proxy.NO_PROXY);
if (!(urlc instanceof javax.net.ssl.HttpsURLConnection)) {
throw new Exception("URLConnection ! instanceof " +
"javax.net.ssl.HttpsURLConnection");
}
BufferedReader in = null;
try {
in = new BufferedReader(new InputStreamReader(
urlc.getInputStream()));
String inputLine;
System.out.print("Client reading... ");
while ((inputLine = in.readLine()) != null)
System.out.println(inputLine);
System.out.println("Cipher Suite: " +
((HttpsURLConnection)urlc).getCipherSuite());
Certificate[] certs =
((HttpsURLConnection)urlc).getServerCertificates();
for (int i = 0; i < certs.length; i++) {
System.out.println(certs[0]);
}
in.close();
} catch (SSLException e) {
if (in != null)
in.close();
throw e;
}
System.out.println("Client reports: SUCCESS");
} finally {
HttpsURLConnection.setDefaultHostnameVerifier(reservedHV);
}
}
static class NameVerifier implements HostnameVerifier {
public boolean verify(String hostname, SSLSession session) {
System.out.println(
"HostnameVerifier: returning true");
return true;
}
}
/*
* =============================================================
* The remainder is just support stuff
*/
// use any free port by default
volatile int serverPort = 0;
volatile Exception serverException = null;
volatile Exception clientException = null;
public static void main(String[] args) throws Exception {
String keyFilename =
System.getProperty("test.src", "./") + "/" + pathToStores +
"/" + keyStoreFile;
String trustFilename =
System.getProperty("test.src", "./") + "/" + pathToStores +
"/" + trustStoreFile;
System.setProperty("javax.net.ssl.keyStore", keyFilename);
System.setProperty("javax.net.ssl.keyStorePassword", passwd);
System.setProperty("javax.net.ssl.trustStore", trustFilename);
System.setProperty("javax.net.ssl.trustStorePassword", passwd);
if (debug)
System.setProperty("javax.net.debug", "all");
/*
* Start the tests.
*/
new JavaxHTTPSConnection();
}
Thread clientThread = null;
Thread serverThread = null;
/*
* Primary constructor, used to drive remainder of the test.
*
* Fork off the other side, then do your work.
*/
JavaxHTTPSConnection() throws Exception {
if (separateServerThread) {
startServer(true);
startClient(false);
} else {
startClient(true);
startServer(false);
}
/*
* Wait for other side to close down.
*/
if (separateServerThread) {
serverThread.join();
} else {
clientThread.join();
}
/*
* When we get here, the test is pretty much over.
*
* If the main thread excepted, that propagates back
* immediately. If the other thread threw an exception, we
* should report back.
*/
if (serverException != null) {
System.out.print("Server Exception:");
throw serverException;
}
if (clientException != null) {
System.out.print("Client Exception:");
throw clientException;
}
}
void startServer(boolean newThread) throws Exception {
if (newThread) {
serverThread = new Thread() {
public void run() {
try {
doServerSide();
} catch (Exception e) {
/*
* Our server thread just died.
*
* Release the client, if not active already...
*/
System.err.println("Server died...");
serverReady = true;
serverException = e;
}
}
};
serverThread.start();
} else {
doServerSide();
}
}
void startClient(boolean newThread) throws Exception {
if (newThread) {
clientThread = new Thread() {
public void run() {
try {
doClientSide();
} catch (Exception e) {
/*
* Our client thread just died.
*/
System.err.println("Client died...");
clientException = e;
}
}
};
clientThread.start();
} else {
doClientSide();
}
}
}

View file

@ -0,0 +1,351 @@
/*
* Copyright (c) 2001, 2019, 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.
*/
// SunJSSE does not support dynamic system properties, no way to re-use
// system properties in samevm/agentvm mode.
/*
* @test
* @bug 4474255 4484246
* @summary When an application enables anonymous SSL cipher suite,
* Hostname verification is not required
* @run main/othervm JavaxHostnameVerifier
*/
import java.io.*;
import java.net.*;
import java.security.Security;
import java.security.cert.*;
import javax.net.ssl.*;
/**
* Use javax.net.ssl.HostnameVerifier
*/
public class JavaxHostnameVerifier {
/*
* =============================================================
* Set the various variables needed for the tests, then
* specify what tests to run on each side.
*/
/*
* Should we run the client or server in a separate thread?
* Both sides can throw exceptions, but do you have a preference
* as to which side should be the main thread.
*/
static boolean separateServerThread = true;
/*
* Is the server ready to serve?
*/
volatile static boolean serverReady = false;
/*
* Turn on SSL debugging?
*/
static boolean debug = false;
/*
* If the client or server is doing some kind of object creation
* that the other side depends on, and that thread prematurely
* exits, you may experience a hang. The test harness will
* terminate all hung threads after its timeout has expired,
* currently 3 minutes by default, but you might try to be
* smart about it....
*/
/**
* Returns the path to the file obtained from
* parsing the HTML header.
*/
private static String getPath(DataInputStream in)
throws IOException
{
String line = in.readLine();
String path = "";
// extract class from GET line
if (line == null)
return null;
if (line.startsWith("GET /")) {
line = line.substring(5, line.length()-1).trim();
int index = line.indexOf(' ');
if (index != -1) {
path = line.substring(0, index);
}
}
// eat the rest of header
do {
line = in.readLine();
} while ((line.length() != 0) &&
(line.charAt(0) != '\r') && (line.charAt(0) != '\n'));
if (path.length() != 0) {
return path;
} else {
throw new IOException("Malformed Header");
}
}
/**
* Returns an array of bytes containing the bytes for
* the file represented by the argument <b>path</b>.
*
* In our case, we just pretend to send something back.
*
* @return the bytes for the file
* @exception FileNotFoundException if the file corresponding
* to <b>path</b> could not be loaded.
*/
private byte[] getBytes(String path)
throws IOException
{
return "Hello world, I am here".getBytes();
}
/*
* Define the server side of the test.
*
* If the server prematurely exits, serverReady will be set to true
* to avoid infinite hangs.
*/
void doServerSide() throws Exception {
SSLServerSocketFactory sslssf =
(SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
// doClientSide() connects to "localhost"
InetAddress localHost = InetAddress.getByName("localhost");
InetSocketAddress address = new InetSocketAddress(localHost, serverPort);
SSLServerSocket sslServerSocket =
(SSLServerSocket) sslssf.createServerSocket();
sslServerSocket.bind(address);
serverPort = sslServerSocket.getLocalPort();
String ciphers[]= { "SSL_DH_anon_WITH_3DES_EDE_CBC_SHA" };
sslServerSocket.setEnabledCipherSuites(ciphers);
/*
* Signal Client, we're ready for his connect.
*/
serverReady = true;
SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
DataOutputStream out =
new DataOutputStream(sslSocket.getOutputStream());
try {
// get path to class file from header
DataInputStream in =
new DataInputStream(sslSocket.getInputStream());
String path = getPath(in);
// retrieve bytecodes
byte[] bytecodes = getBytes(path);
// send bytecodes in response (assumes HTTP/1.0 or later)
try {
out.writeBytes("HTTP/1.0 200 OK\r\n");
out.writeBytes("Content-Length: " + bytecodes.length + "\r\n");
out.writeBytes("Content-Type: text/html\r\n\r\n");
out.write(bytecodes);
out.flush();
} catch (IOException ie) {
ie.printStackTrace();
return;
}
} catch (Exception e) {
e.printStackTrace();
// write out error response
out.writeBytes("HTTP/1.0 400 " + e.getMessage() + "\r\n");
out.writeBytes("Content-Type: text/html\r\n\r\n");
out.flush();
} finally {
// close the socket
System.out.println("Server closing socket");
sslSocket.close();
serverReady = false;
}
}
/*
* Define the client side of the test.
*
* If the server prematurely exits, serverReady will be set to true
* to avoid infinite hangs.
*/
void doClientSide() throws Exception {
/*
* Wait for server to get started.
*/
while (!serverReady) {
Thread.sleep(50);
}
System.setProperty("https.cipherSuites",
"SSL_DH_anon_WITH_3DES_EDE_CBC_SHA");
// use the default hostname verifier
URL url = new URL("https://" + "localhost:" + serverPort +
"/etc/hosts");
URLConnection urlc = url.openConnection(Proxy.NO_PROXY);
if (!(urlc instanceof javax.net.ssl.HttpsURLConnection)) {
throw new Exception(
"URLConnection ! instanceof javax.net.ssl.HttpsURLConnection");
}
BufferedReader in = null;
try {
in = new BufferedReader(new InputStreamReader(
urlc.getInputStream()));
String inputLine;
System.out.print("Client reading... ");
while ((inputLine = in.readLine()) != null)
System.out.println(inputLine);
System.out.println("Cipher Suite: " +
((HttpsURLConnection)urlc).getCipherSuite());
in.close();
} catch (SSLException e) {
if (in != null)
in.close();
throw e;
}
System.out.println("Client reports: SUCCESS");
}
/*
* =============================================================
* The remainder is just support stuff
*/
// use any free port by default
volatile int serverPort = 0;
volatile Exception serverException = null;
volatile Exception clientException = null;
public static void main(String[] args) throws Exception {
// re-enable 3DES
Security.setProperty("jdk.tls.disabledAlgorithms", "");
if (debug)
System.setProperty("javax.net.debug", "all");
/*
* Start the tests.
*/
new JavaxHostnameVerifier();
}
Thread clientThread = null;
Thread serverThread = null;
/*
* Primary constructor, used to drive remainder of the test.
*
* Fork off the other side, then do your work.
*/
JavaxHostnameVerifier() throws Exception {
if (separateServerThread) {
startServer(true);
startClient(false);
} else {
startClient(true);
startServer(false);
}
/*
* Wait for other side to close down.
*/
if (separateServerThread) {
serverThread.join();
} else {
clientThread.join();
}
/*
* When we get here, the test is pretty much over.
*
* If the main thread excepted, that propagates back
* immediately. If the other thread threw an exception, we
* should report back.
*/
if (serverException != null) {
System.out.print("Server Exception:");
throw serverException;
}
if (clientException != null) {
System.out.print("Client Exception:");
throw clientException;
}
}
void startServer(boolean newThread) throws Exception {
if (newThread) {
serverThread = new Thread() {
public void run() {
try {
doServerSide();
} catch (Exception e) {
/*
* Our server thread just died.
*
* Release the client, if not active already...
*/
System.err.println("Server died...");
serverReady = true;
serverException = e;
}
}
};
serverThread.start();
} else {
doServerSide();
}
}
void startClient(boolean newThread) throws Exception {
if (newThread) {
clientThread = new Thread() {
public void run() {
try {
doClientSide();
} catch (Exception e) {
/*
* Our client thread just died.
*/
System.err.println("Client died...");
clientException = e;
}
}
};
clientThread.start();
} else {
doClientSide();
}
}
}