I am running a test using the Java socket class, but somehow my socket.connect ALWAYS connects successfully to something, even if my url variable is null or incorrect. Does anyone know why?
package ping_run_send;
import java.util.*;
import java.lang.*;
import java.net.*;
import java.io.*
import java.security.cert.*;
import javax.net.ssl.*;
public class tcpping {
private String url, status;
private Date timestamp;
private long rtime;
tcpping(String input_url){
this.url = input_url;
}
void ping() {
try{
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("my proxy", 80));
Socket socket = new Socket(proxy);
long tStart = System.currentTimeMillis();
socket.connect(new InetSocketAddress(url, 80),2000);
long tEnd = System.currentTimeMillis();
rtime = tEnd-tStart;
timestamp = new Date(tStart);
InputStream sIn = socket.getInputStream();
if (sIn != null) {
status = "normal";
socket.close();
}else {
status = "error";
}
} catch(final MalformedURLException e){
status = "error";
} catch(IOException e){
status = "error";
}
}
Long get_rtime() {
return rtime;
}
Date get_timestamp() {
return timestamp;
}
String get_status() {
return status;
}
}
I also tried changing the if statement from isConnected() to
InputStream sIn = socket.getInputStream();
if (sIn != null) {
status = "normal";
socket.close();
}else {
status = "error";
}
But nothing seems to be have changed on its ability to detect connection error.
my testing file:
package ping_run_send;
import java.lang.*;
import java.util.*;
import java.io.*;
import ping_run_send.httpping;
public class main {
public static void main(String[] args){
String url = "http://google.com";
//urls like "",http://gowegwgwoJOIJOI03OINEPJPogle.#(*%" all works somehow
tcpping testTcp = new tcpping(url);
testTcp.ping();
System.out.println("tcp ping:");
System.out.println(testTcp.get_rtime());
System.out.println(testTcp.get_timestamp());
System.out.println(testTcp.get_status());
}
}
It is connecting to the Proxy. When you specify a Proxy the connection is made to the Proxy and the Proxy itself handles the connections to the real endpoint.
I am trying to figure out why my pipeline is being executed out of order.
I took the HexDumpProxy example and was trying to turn it into a http-proxy where I can look at all the traffic. For some reason the code is being executed backwards and I can't figure out why.
My server listens on 8443 and takes in the http content. I wanted to read the host header and create a frontend handler to route the data to the server, but my frontend handler executes first despite being last in the pipeline. I am unsure why it is running first I thought it would be execute in the following order.
LoggingHandler
HttpRequestDecoder
HttpObjectAggregator
HttpProxyListener
HttpReEncoder
HTTPProxyFrontEnd
The goal is to remove frontendhandler from the pipeline and have the HTTPProxy listener add it to the pipeline after reading the host header. but if I remove the frontend handler no data is transferred. Using breakpoints HTTPProxyFrontEnd is hit before HttpProxyListener. I am unsure why it is being executed so out of order.
Main
```
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new HttpProxyServerInitializer(REMOTE_HOST, REMOTE_PORT))
.childOption(ChannelOption.AUTO_READ, false)
.bind(LOCAL_PORT).sync().channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
```
Pipeline
```
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.handler.codec.MessageToByteEncoder;
import io.netty.handler.codec.http.*;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.ssl.SslHandler;
import io.netty.handler.ssl.util.SelfSignedCertificate;
import javax.net.ssl.SSLEngine;
public class HttpProxyServerInitializer extends ChannelInitializer {
private final String remoteHost;
private final int remotePort;
public HttpProxyServerInitializer(String remoteHost, int remotePort) {
this.remoteHost = remoteHost;
this.remotePort = remotePort;
}
#Override
protected void initChannel(Channel ch) throws Exception {
ch.pipeline().addLast(
new LoggingHandler(LogLevel.INFO),
new HttpRequestDecoder(),
new HttpObjectAggregator(8192),
new HttpProxyListener(),
new HttpReEncoder(),
new HTTPProxyFrontEnd(remoteHost, remotePort));
}
}
```
Proxy Front end
```
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.embedded.EmbeddedChannel;
import io.netty.handler.codec.DecoderResult;
import io.netty.handler.codec.http.*;
import io.netty.handler.codec.http.cookie.ServerCookieDecoder;
import io.netty.handler.codec.http.cookie.ServerCookieEncoder;
import io.netty.util.CharsetUtil;
import java.net.SocketAddress;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static io.netty.handler.codec.http.HttpResponseStatus.BAD_REQUEST;
import static io.netty.handler.codec.http.HttpResponseStatus.OK;
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
public class HTTPProxyFrontEnd extends ChannelInboundHandlerAdapter {
private final String remoteHost;
private final int remotePort;
private final StringBuilder buf = new StringBuilder();
private HttpRequest request;
// As we use inboundChannel.eventLoop() when building the Bootstrap this does not need to be volatile as
// the outboundChannel will use the same EventLoop (and therefore Thread) as the inboundChannel.
private Channel outboundChannel;
public HTTPProxyFrontEnd(String remoteHost, int remotePort) {
this.remoteHost = remoteHost;
this.remotePort = remotePort;
}
#Override
public void channelActive(ChannelHandlerContext ctx) {
System.out.println("HTTPFrontEnd");
final Channel inboundChannel = ctx.channel();
// Start the connection attempt.
Bootstrap b = new Bootstrap();
b.group(inboundChannel.eventLoop())
.channel(ctx.channel().getClass())
.handler(new HexDumpProxyBackendHandler(inboundChannel))
.option(ChannelOption.AUTO_READ, false);
ChannelFuture f = b.connect(remoteHost, remotePort);
SocketAddress test = ctx.channel().remoteAddress();
outboundChannel = f.channel();
f.addListener(new ChannelFutureListener() {
#Override
public void operationComplete(ChannelFuture future) {
if (future.isSuccess()) {
// connection complete start to read first data
inboundChannel.read();
} else {
// Close the connection if the connection attempt has failed.
inboundChannel.close();
}
}
});
}
#Override
public void channelRead(final ChannelHandlerContext ctx, Object msg) throws InterruptedException {
if (outboundChannel.isActive()) {
outboundChannel.writeAndFlush(msg).addListener(new ChannelFutureListener() {
#Override
public void operationComplete(ChannelFuture future) {
if (future.isSuccess()) {
// was able to flush out data, start to read the next chunk
ctx.channel().read();
} else {
future.channel().close();
}
}
});
}
}
private boolean writeResponse(HttpObject currentObj, ChannelHandlerContext ctx) {
// Decide whether to close the connection or not.
boolean keepAlive = HttpUtil.isKeepAlive(request);
// Build the response object.
FullHttpResponse response = new DefaultFullHttpResponse(
HTTP_1_1, currentObj.decoderResult().isSuccess()? OK : BAD_REQUEST,
Unpooled.copiedBuffer(buf.toString(), CharsetUtil.UTF_8));
response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain; charset=UTF-8");
if (keepAlive) {
// Add 'Content-Length' header only for a keep-alive connection.
response.headers().setInt(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes());
// Add keep alive header as per:
// - http://www.w3.org/Protocols/HTTP/1.1/draft-ietf-http-v11-spec-01.html#Connection
response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
}
// Encode the cookie.
String cookieString = request.headers().get(HttpHeaderNames.COOKIE);
if (cookieString != null) {
Set<io.netty.handler.codec.http.cookie.Cookie> cookies = ServerCookieDecoder.STRICT.decode(cookieString);
if (!cookies.isEmpty()) {
// Reset the cookies if necessary.
for (io.netty.handler.codec.http.cookie.Cookie cookie: cookies) {
response.headers().add(HttpHeaderNames.SET_COOKIE, io.netty.handler.codec.http.cookie.ServerCookieEncoder.STRICT.encode(cookie));
}
}
} else {
// Browser sent no cookie. Add some.
response.headers().add(HttpHeaderNames.SET_COOKIE, io.netty.handler.codec.http.cookie.ServerCookieEncoder.STRICT.encode("key1", "value1"));
response.headers().add(HttpHeaderNames.SET_COOKIE, ServerCookieEncoder.STRICT.encode("key2", "value2"));
}
// Write the response.
//ctx.writeAndFlush(response);
return keepAlive;
}
private static void appendDecoderResult(StringBuilder buf, HttpObject o) {
DecoderResult result = o.decoderResult();
if (result.isSuccess()) {
return;
}
buf.append(".. WITH DECODER FAILURE: ");
buf.append(result.cause());
buf.append("\r\n");
}
#Override
public void channelInactive(ChannelHandlerContext ctx) {
if (outboundChannel != null) {
closeOnFlush(outboundChannel);
}
}
#Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
closeOnFlush(ctx.channel());
}
/**
* Closes the specified channel after all queued write requests are flushed.
*/
static void closeOnFlush(Channel ch) {
if (ch.isActive()) {
ch.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);
}
}
}
```
I read from a url/port perform some processing and write back to the url/port. The Url/Port allows only a single connection (of which you need to read and write when needed).
Flink can read and write to the rl port but opens 2 connections.
I have used the basic connection and from a url/port through flink
// set up the streaming execution environment
val env = StreamExecutionEnvironment.getExecutionEnvironment
val data_stream = env.socketTextStream(url, port, socket_stream_deliminator, socket_connection_retries)
.map(x => printInput(x))
.writeToSocket(url, port, new SimpleStringSchema())
//.addSink(new SocketClientSink[String](url, port.toInt, new SimpleStringSchema))
// execute program
env.execute("Flink Streaming Scala API Skeleton")
The ideal solution or only solution for my case is to read and write from the same connection and not create 2 seperate connections
How would I go about doing this?
As I said in the comment, you have to store your connection in some static variable because your Sources- and Sinks won't use the same connection otherwise.
You must also ensure that your Source and Sink run on the same JVM using the same Classloader, otherwise you will still have more than one connection.
I built this wrapper class which holds a raw Socket-Connection and a Reader/Writer instance for that connection. Because your Source will always stop before your Sink (thats how Flink works), this class also does reconnect if it was closed before.
package example;
import java.io.BufferedReader;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;
public class SocketConnection implements Closeable {
private final String host;
private final int port;
private final Object lock;
private volatile Socket socket;
private volatile BufferedReader reader;
private volatile PrintStream writer;
public SocketConnection(String host, int port) {
this.host = host;
this.port = port;
this.lock = new Object();
this.socket = null;
this.reader = null;
this.writer = null;
}
private void connect() throws IOException {
this.socket = new Socket(this.host, this.port);
this.reader = new BufferedReader(new InputStreamReader(this.socket.getInputStream()));
this.writer = new PrintStream(this.socket.getOutputStream());
}
private void ensureConnected() throws IOException {
// only acquire lock if null
if (this.socket == null) {
synchronized (this.lock) {
// recheck if socket is still null
if (this.socket == null) {
connect();
}
}
}
}
public BufferedReader getReader() throws IOException {
ensureConnected();
return this.reader;
}
public PrintStream getWriter() throws IOException {
ensureConnected();
return this.writer;
}
#Override
public void close() throws IOException {
if (this.socket != null) {
synchronized (this.lock) {
if (this.socket != null) {
this.reader.close();
this.reader = null;
this.writer.close();
this.writer = null;
this.socket.close();
this.socket = null;
}
}
}
}
}
Your Main Class (or any other class) holds one instance of this class which is then accessed by both your source and your sink:
package example;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
public class Main {
public static final SocketConnection CONNECTION = new SocketConnection("your-host", 12345);
public static void main(String[] args) throws Exception {
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.addSource(new SocketTextStreamSource())
.addSink(new SocketTextStreamSink());
env.execute("Flink Streaming Scala API Skeleton");
}
}
Your SourceFunction could look more or less like this:
package example;
import org.apache.flink.streaming.api.functions.source.SourceFunction;
public class SocketTextStreamSource implements SourceFunction<String> {
private volatile boolean running;
public SocketTextStreamSource() {
this.running = true;
}
#Override
public void run(SourceContext<String> context) throws Exception {
try (SocketConnection conn = Main.CONNECTION) {
String line;
while (this.running && (line = conn.getReader().readLine()) != null) {
context.collect(line);
}
}
}
#Override
public void cancel() {
this.running = false;
}
}
And your SinkFunction:
package example;
import org.apache.flink.configuration.Configuration;
import org.apache.flink.streaming.api.functions.sink.RichSinkFunction;
public class SocketTextStreamSink extends RichSinkFunction<String> {
private transient SocketConnection connection;
#Override
public void open(Configuration parameters) throws Exception {
this.connection = Main.CONNECTION;
}
#Override
public void invoke(String value, Context context) throws Exception {
this.connection.getWriter().println(value);
this.connection.getWriter().flush();
}
#Override
public void close() throws Exception {
this.connection.close();
}
}
Note that I always use getReader() and getWriter() because the underlying Socket may have been closed in the meantime.
I'm using IntelliJ IDEA.
I've done all that my Googling has provided me with as potential solutions.
I've tried doing the File -> Invalidate Caches/Restart, it still doesn't fix it.
This is the entire code;
This was copied from the OCI documentation, and I've already made some amendments to the code, but I don't know how to fix this.
I'm a junior yes, but am I wrong to be annoyed over how much of the documentation through the use of which I'm to be developing myself has these kinds of issues..
This is the entire code.
package com;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.security.SecureRandom;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import org.apache.commons.codec.binary.Base64;
import static java.lang.System.out;
import static com.sun.org.apache.xalan.internal.xsltc.cmdline.Compile.printUsage;
public class ociAuth {
private static String server;
private static String user;
private static String password;
private static String port = "8443";
private static String response_format = "json";
private static String server_url;
public static void main(String[] args) {
if(args.length < 3 || args.length > 4) {
printUsage();
System.exit(1);
}
setUserArguments(args);
server_url = "https://" + server + ":" + port + "/rest/v1/assets/storages";
try {
HttpsURLConnection connection =
getAllTrustingHttpsUrlConnection();
if(connection == null) {
System.err.println("FATAL: Failed to create HTTPS connection to URL: " + server_url);
System.exit(1);
}
System.out.println("Invoking API: " + server_url);
connection.setRequestMethod("GET");
connection.setRequestProperty("Accept", "application/" + response_format);
String authString = getAuthorizationString();
connection.setRequestProperty("Authorization", "Basic " +
authString);
if (connection.getResponseCode() != 200) {
System.err.println("API Invocation Failed : HTTP error code : "
+ connection.getResponseCode());
System.exit(1);
}
BufferedReader br = new BufferedReader(new InputStreamReader(
(connection.getInputStream())));
String response;
System.out.println("Response:");
while ((response = br.readLine()) != null) {
System.out.println(response);
}
connection.disconnect();
} catch (Exception e) {
e.printStackTrace();
}
}
//THESE PRINTS HERE BELLOW
//THESE PRINTS HERE BELLOW
//THESE PRINTS HERE BELLOW
System.out.print("\nUsage:\n\tHelloApiServices <api-server host[:port]> <user> <password> [json|xml]\n");
System.out.print("\nExamples:\n\tHelloApiServices localhost admin mypassword");
System.out.print("\tHelloApiServices 10.22.12.34:8320 admin password");
System.out.print("\tHelloApiServices 10.22.12.34 admin password xml");
System.out.print("\tHelloApiServices 10.22.12.34:8212 admin password xml\n");
System.out.print("\nNote:\n\t(1) When port number is not provided, 8443 is chosen by default.");
System.out.print("\t(2) When response format (json or xml) is not provided, json is chosen by default. \n");
}
//THESE PRINTS HERE ABOVE
//THESE PRINTS HERE ABOVE
//THESE PRINTS HERE ABOVE
private static void setUserArguments(String[] args) {
server = args[0];
user = args[1];
password = args[2];
if(args.length == 4) {
response_format = args[3];
if(!response_format.equals("json") && ! response_format.equals("xml")) {
printUsage();
System.exit(1);
}
}
if(server.contains(":")) {
String[] parts = server.split(":");
server = parts[0];
port = parts[1];
}
}
private static HttpsURLConnection getAllTrustingHttpsUrlConnection() {
HttpsURLConnection conn = null;
try {
TrustManager[] trustAllCertificatesManager = new
TrustManager[]{new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return
null;
}
public void checkClientTrusted(X509Certificate[]
certs, String authType) {
}
public void checkServerTrusted(X509Certificate[]
certs, String authType) {
}
}};
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustAllCertificatesManager, new
SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
URL url = new URL(server_url);
conn = (HttpsURLConnection) url.openConnection();
conn.setHostnameVerifier(new HostnameVerifier() {
public boolean verify(String host, SSLSession
session) {
return true;
}
});
} catch (Exception e) {
e.printStackTrace();
}
return conn;
}
private static String getAuthorizationString() {
String userPassword = user + ":" + password;
byte[] authEncodedBytes =
Base64.encodeBase64(userPassword.getBytes());
String ajdeovako = new String(authEncodedBytes);
return ajdeovako;
}
}
You have an extra bracket. The System.out.print calls are not inside you main method, but are instead between methods and the closing bracket after the print calls shouldn't be there. Move the print calls up inside your main method and it should compile fine.
You have one extra }, removing it will fix your error.
} <-- remove this
//THESE PRINTS HERE BELLOW
//THESE PRINTS HERE BELLOW
//THESE PRINTS HERE BELLOW
System.out.print("\nUsage:\n\tHelloApiServices <api-server host[:port]> <user> <password> [json|xml]\n");
System.out.print("\nExamples:\n\tHelloApiServices localhost admin mypassword");
System.out.print("\tHelloApiServices 10.22.12.34:8320 admin password");
System.out.print("\tHelloApiServices 10.22.12.34 admin password xml");
System.out.print("\tHelloApiServices 10.22.12.34:8212 admin password xml\n");
System.out.print("\nNote:\n\t(1) When port number is not provided, 8443 is chosen by default.");
System.out.print("\t(2) When response format (json or xml) is not provided, json is chosen by default. \n");
}
It seems that Java 6 supports TLS up to v1.0, is there any way to use TLS 1.2 in Java 6?
Maybe a patch or a particular update of Java 6 will have support for it?
After a few hours of playing with the Oracle JDK 1.6, I was able to make it work without any code change. The magic is done by Bouncy Castle to handle SSL and allow JDK 1.6 to run with TLSv1.2 by default. In theory, it could also be applied to older Java versions with eventual adjustments.
Download the latest Java 1.6 version from the Java Archive Oracle website
Uncompress it on your preferred path and set your JAVA_HOME environment variable
Update the JDK with the latest Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files 6
Download the Bounce Castle jar files bcprov-jdk15to18-1.71.jar and bctls-jdk15to18-1.71.jar and copy them into your ${JAVA_HOME}/jre/lib/ext folder
Modify the file ${JAVA_HOME}/jre/lib/security/java.security commenting out the providers section and adding some extra lines
# Original security providers (just comment it)
# security.provider.1=sun.security.provider.Sun
# security.provider.2=sun.security.rsa.SunRsaSign
# security.provider.3=com.sun.net.ssl.internal.ssl.Provider
# security.provider.4=com.sun.crypto.provider.SunJCE
# security.provider.5=sun.security.jgss.SunProvider
# security.provider.6=com.sun.security.sasl.Provider
# security.provider.7=org.jcp.xml.dsig.internal.dom.XMLDSigRI
# security.provider.8=sun.security.smartcardio.SunPCSC
# Add the Bouncy Castle security providers with higher priority
security.provider.1=org.bouncycastle.jce.provider.BouncyCastleProvider
security.provider.2=org.bouncycastle.jsse.provider.BouncyCastleJsseProvider
# Original security providers with different priorities
security.provider.3=sun.security.provider.Sun
security.provider.4=sun.security.rsa.SunRsaSign
security.provider.5=com.sun.net.ssl.internal.ssl.Provider
security.provider.6=com.sun.crypto.provider.SunJCE
security.provider.7=sun.security.jgss.SunProvider
security.provider.8=com.sun.security.sasl.Provider
security.provider.9=org.jcp.xml.dsig.internal.dom.XMLDSigRI
security.provider.10=sun.security.smartcardio.SunPCSC
# Here we are changing the default SSLSocketFactory implementation
ssl.SocketFactory.provider=org.bouncycastle.jsse.provider.SSLSocketFactoryImpl
Just to make sure it's working let's make a simple Java program to download files from one URL using https.
import java.io.*;
import java.net.*;
public class DownloadWithHttps {
public static void main(String[] args) {
try {
URL url = new URL(args[0]);
System.out.println("File to Download: " + url);
String filename = url.getFile();
File f = new File(filename);
System.out.println("Output File: " + f.getName());
BufferedInputStream in = new BufferedInputStream(url.openStream());
FileOutputStream fileOutputStream = new FileOutputStream(f.getName());
int bytesRead;
byte dataBuffer[] = new byte[1024];
while ((bytesRead = in.read(dataBuffer, 0, 1024)) != -1) {
fileOutputStream.write(dataBuffer, 0, bytesRead);
}
fileOutputStream.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
Now, just compile the DownloadWithHttps.java program and execute it with your Java 1.6
${JAVA_HOME}/bin/javac DownloadWithHttps.java
${JAVA_HOME}/bin/java DownloadWithHttps https://repo1.maven.org/maven2/org/apache/commons/commons-lang3/3.10/commons-lang3-3.10.jar
Important note for Windows users: This solution was tested in a Linux OS, if you are using Windows, please replace the ${JAVA_HOME} by %JAVA_HOME%.
Public Oracle Java 6 releases do not support TLSv1.2. Paid-for releases of Java 6 (post-EOL) might. (UPDATE - TLSv1.1 is available for Java 1.6 from update 111 onwards; source)
Contact Oracle sales.
Other alternatives are:
Use an alternative JCE implementation such as Bouncy Castle. See this answer for details on how to do it. It changes the default SSLSocketFactory implementation, so that your application will use BC transparently. (Other answers show how to use the BC SSLSocketFactory implementation explicitly, but that approach will entail modifying application or library code that that is opening sockets.)
Use an IBM Java 6 ... if available for your platform. According to "IBM SDK, Java Technology Edition fixes to mitigate against the POODLE security vulnerability (CVE-2014-3566)":
"TLSv1.1 and TLSv1.2 are available only for Java 6 service refresh 10, Java 6.0.1 service refresh 1 (J9 VM2.6), and later releases."
However, I'd advise upgrading to a Java 11 (now). Java 6 was EOL'd in Feb 2013, and continuing to use it is potentially risky. Free Oracle Java 8 is EOL for many use-cases. (Tell or remind the boss / the client. They need to know.)
Java 6, now support TLS 1.2, check out below
http://www.oracle.com/technetwork/java/javase/overview-156328.html#R160_121
Here a TLSConnection Factory:
package test.connection;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
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.UnknownHostException;
import java.security.Principal;
import java.security.SecureRandom;
import java.security.Security;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.util.Hashtable;
import java.util.LinkedList;
import java.util.List;
import javax.net.ssl.HandshakeCompletedEvent;
import javax.net.ssl.HandshakeCompletedListener;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSessionContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.security.cert.X509Certificate;
import org.bouncycastle.crypto.tls.Certificate;
import org.bouncycastle.crypto.tls.CertificateRequest;
import org.bouncycastle.crypto.tls.DefaultTlsClient;
import org.bouncycastle.crypto.tls.ExtensionType;
import org.bouncycastle.crypto.tls.TlsAuthentication;
import org.bouncycastle.crypto.tls.TlsClientProtocol;
import org.bouncycastle.crypto.tls.TlsCredentials;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
/**
* This Class enables TLS V1.2 connection based on BouncyCastle Providers.
* Just to use:
* URL myurl = new URL( "http:// ...URL tha only Works in TLS 1.2);
HttpsURLConnection con = (HttpsURLConnection )myurl.openConnection();
con.setSSLSocketFactory(new TSLSocketConnectionFactory());
* #author AZIMUTS
*
*/
public class TSLSocketConnectionFactory extends SSLSocketFactory {
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Adding Custom BouncyCastleProvider
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
static {
if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null)
Security.addProvider(new BouncyCastleProvider());
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//HANDSHAKE LISTENER
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
public class TLSHandshakeListener implements HandshakeCompletedListener {
#Override
public void handshakeCompleted(HandshakeCompletedEvent event) {
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//SECURE RANDOM
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
private SecureRandom _secureRandom = new SecureRandom();
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Adding Custom BouncyCastleProvider
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
#Override
public Socket createSocket(Socket socket, final String host, int port, boolean arg3)
throws IOException {
if (socket == null) {
socket = new Socket();
}
if (!socket.isConnected()) {
socket.connect(new InetSocketAddress(host, port));
}
final TlsClientProtocol tlsClientProtocol = new TlsClientProtocol(socket.getInputStream(), socket.getOutputStream(), _secureRandom);
return _createSSLSocket(host, tlsClientProtocol);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// SOCKET FACTORY METHODS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#Override
public String[] getDefaultCipherSuites() {
return null;
}
#Override
public String[] getSupportedCipherSuites(){
return null;
}
#Override
public Socket createSocket(String host, int port) throws IOException,UnknownHostException{
return null;
}
#Override
public Socket createSocket(InetAddress host, int port) throws IOException {
return null;
}
#Override
public Socket createSocket(String host, int port, InetAddress localHost,
int localPort) throws IOException, UnknownHostException {
return null;
}
#Override
public Socket createSocket(InetAddress address, int port,
InetAddress localAddress, int localPort) throws IOException{
return null;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//SOCKET CREATION
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private SSLSocket _createSSLSocket(final String host , final TlsClientProtocol tlsClientProtocol) {
return new SSLSocket() {
private java.security.cert.Certificate[] peertCerts;
#Override
public InputStream getInputStream() throws IOException {
return tlsClientProtocol.getInputStream();
}
#Override
public OutputStream getOutputStream() throws IOException {
return tlsClientProtocol.getOutputStream();
}
#Override
public synchronized void close() throws IOException {
tlsClientProtocol.close();
}
#Override
public void addHandshakeCompletedListener(HandshakeCompletedListener arg0) {
}
#Override
public boolean getEnableSessionCreation() {
return false;
}
#Override
public String[] getEnabledCipherSuites() {
return null;
}
#Override
public String[] getEnabledProtocols() {
// TODO Auto-generated method stub
return null;
}
#Override
public boolean getNeedClientAuth(){
return false;
}
#Override
public SSLSession getSession() {
return new SSLSession() {
#Override
public int getApplicationBufferSize() {
return 0;
}
#Override
public String getCipherSuite() {
throw new UnsupportedOperationException();
}
#Override
public long getCreationTime() {
throw new UnsupportedOperationException();
}
#Override
public byte[] getId() {
throw new UnsupportedOperationException();
}
#Override
public long getLastAccessedTime() {
throw new UnsupportedOperationException();
}
#Override
public java.security.cert.Certificate[] getLocalCertificates() {
throw new UnsupportedOperationException();
}
#Override
public Principal getLocalPrincipal() {
throw new UnsupportedOperationException();
}
#Override
public int getPacketBufferSize() {
throw new UnsupportedOperationException();
}
#Override
public X509Certificate[] getPeerCertificateChain()
throws SSLPeerUnverifiedException {
// TODO Auto-generated method stub
return null;
}
#Override
public java.security.cert.Certificate[] getPeerCertificates()throws SSLPeerUnverifiedException {
return peertCerts;
}
#Override
public String getPeerHost() {
throw new UnsupportedOperationException();
}
#Override
public int getPeerPort() {
return 0;
}
#Override
public Principal getPeerPrincipal() throws SSLPeerUnverifiedException {
return null;
//throw new UnsupportedOperationException();
}
#Override
public String getProtocol() {
throw new UnsupportedOperationException();
}
#Override
public SSLSessionContext getSessionContext() {
throw new UnsupportedOperationException();
}
#Override
public Object getValue(String arg0) {
throw new UnsupportedOperationException();
}
#Override
public String[] getValueNames() {
throw new UnsupportedOperationException();
}
#Override
public void invalidate() {
throw new UnsupportedOperationException();
}
#Override
public boolean isValid() {
throw new UnsupportedOperationException();
}
#Override
public void putValue(String arg0, Object arg1) {
throw new UnsupportedOperationException();
}
#Override
public void removeValue(String arg0) {
throw new UnsupportedOperationException();
}
};
}
#Override
public String[] getSupportedProtocols() {
return null;
}
#Override
public boolean getUseClientMode() {
return false;
}
#Override
public boolean getWantClientAuth() {
return false;
}
#Override
public void removeHandshakeCompletedListener(HandshakeCompletedListener arg0) {
}
#Override
public void setEnableSessionCreation(boolean arg0) {
}
#Override
public void setEnabledCipherSuites(String[] arg0) {
}
#Override
public void setEnabledProtocols(String[] arg0) {
}
#Override
public void setNeedClientAuth(boolean arg0) {
}
#Override
public void setUseClientMode(boolean arg0) {
}
#Override
public void setWantClientAuth(boolean arg0) {
}
#Override
public String[] getSupportedCipherSuites() {
return null;
}
#Override
public void startHandshake() throws IOException {
tlsClientProtocol.connect(new DefaultTlsClient() {
#Override
public Hashtable<Integer, byte[]> getClientExtensions() throws IOException {
Hashtable<Integer, byte[]> clientExtensions = super.getClientExtensions();
if (clientExtensions == null) {
clientExtensions = new Hashtable<Integer, byte[]>();
}
//Add host_name
byte[] host_name = host.getBytes();
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
final DataOutputStream dos = new DataOutputStream(baos);
dos.writeShort(host_name.length + 3); // entry size
dos.writeByte(0); // name type = hostname
dos.writeShort(host_name.length);
dos.write(host_name);
dos.close();
clientExtensions.put(ExtensionType.server_name, baos.toByteArray());
return clientExtensions;
}
#Override
public TlsAuthentication getAuthentication()
throws IOException {
return new TlsAuthentication() {
#Override
public void notifyServerCertificate(Certificate serverCertificate) throws IOException {
try {
CertificateFactory cf = CertificateFactory.getInstance("X.509");
List<java.security.cert.Certificate> certs = new LinkedList<java.security.cert.Certificate>();
for ( org.bouncycastle.asn1.x509.Certificate c : serverCertificate.getCertificateList()) {
certs.add(cf.generateCertificate(new ByteArrayInputStream(c.getEncoded())));
}
peertCerts = certs.toArray(new java.security.cert.Certificate[0]);
} catch (CertificateException e) {
System.out.println( "Failed to cache server certs"+ e);
throw new IOException(e);
}
}
#Override
public TlsCredentials getClientCredentials(CertificateRequest arg0)
throws IOException {
return null;
}
};
}
});
}
};//Socket
}
}
Remember that to prove this is, the best is to test against a website that exposes ONLY TLS 1.2. If the web exposes TLS 1.0, TLS 1.1 depending on the Java implementation will connect using tls 1.0, tls 1.1. Test it against a site that only exposes TLS 1.2. An example can be the NIST secure site https://www.nist.gov
You must create your own SSLSocketFactory based on Bouncy Castle. After to use it, pass to the common HttpsConnextion for using this customized SocketFactory.
1. First : Create a TLSConnectionFactory
Here one tips:
1.1 Extend SSLConnectionFactory
1.2 Override this method :
#Override
public Socket createSocket(Socket socket, final String host, int port, boolean arg3)
This method will call the next internal method,
1.3 Implement an internal method _createSSLSocket(host, tlsClientProtocol);
Here you must create a Socket using TlsClientProtocol . The trick is override ...startHandshake() method calling TlsClientProtocol
private SSLSocket _createSSLSocket(final String host , final TlsClientProtocol tlsClientProtocol) {
return new SSLSocket() {
.... Override and implement SSLSocket methods, particulary:
startHandshake() {
}
}
Important : The full sample how to use TLS Client Protocol is well explained here: Using BouncyCastle for a simple HTTPS query
2. Second : Use this Customized SSLConnextionFactory on common HTTPSConnection.
This is important ! In other samples you can see into the web , u see hard-coded HTTP Commands....so with a customized SSLConnectionFactory u don't need nothing more...
URL myurl = new URL( "http:// ...URL tha only Works in TLS 1.2);
HttpsURLConnection con = (HttpsURLConnection )myurl.openConnection();
con.setSSLSocketFactory(new TSLSocketConnectionFactory());
In case you need to access a specific set of remote services you could use an intermediate reverse-proxy, to perform tls1.2 for you. This would save you from trying to patch or upgrade java1.6.
e.g.
app -> proxy:http(5500)[tls-1.2] -> remote:https(443)
Configuration in its simplest form (one port per service) for apache httpd is:
Listen 127.0.0.1:5000
<VirtualHost *:5500>
SSLProxyEngine On
ProxyPass / https://remote-domain/
ProxyPassReverse / https://remote-domain/
</VirtualHost>
Then instead of accessing https://remote-domain/ you access http://localhost:5500/
Note: In case you cannot change the service-client code/config so that it targets the localhost domain, you can always play with hosts file and translate the the remote domain to the proxy's ip. But this has a catch. The reverse-proxy specifically will need to resolve the same domain to the original service ip. You can achieve this by moving the proxy to a different machine (with no hosts file entry) or by dockerizing it and utilizing the --add-host feature (or extra_hosts in docker-compose ).
I think that the solution of #Azimuts (https://stackoverflow.com/a/33375677/6503697) is for HTTP only connection.
For FTPS connection you can use Bouncy Castle with org.apache.commons.net.ftp.FTPSClient without the need for rewrite FTPS protocol.
I have a program running on JRE 1.6.0_04 and I can not update the JRE.
The program has to connect to an FTPS server that work only with TLS 1.2 (IIS server).
I struggled for days and finally I have understood that there are few versions of bouncy castle library right in my use case: bctls-jdk15on-1.60.jar and bcprov-jdk15on-1.60.jar are ok, but 1.64 versions are not.
The version of apache commons-net is 3.1 .
Following is a small snippet of code that should work:
import java.io.ByteArrayOutputStream;
import java.security.SecureRandom;
import java.security.Security;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPReply;
import org.apache.commons.net.ftp.FTPSClient;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jsse.provider.BouncyCastleJsseProvider;
import org.junit.Test;
public class FtpsTest {
// Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) {
}
} };
#Test public void test() throws Exception {
Security.insertProviderAt(new BouncyCastleProvider(), 1);
Security.addProvider(new BouncyCastleJsseProvider());
SSLContext sslContext = SSLContext.getInstance("TLS", new BouncyCastleJsseProvider());
sslContext.init(null, trustAllCerts, new SecureRandom());
org.apache.commons.net.ftp.FTPSClient ftpClient = new FTPSClient(sslContext);
ByteArrayOutputStream out = null;
try {
ftpClient.connect("hostaname", 21);
if (!FTPReply.isPositiveCompletion(ftpClient.getReplyCode())) {
String msg = "Il server ftp ha rifiutato la connessione.";
throw new Exception(msg);
}
if (!ftpClient.login("username", "pwd")) {
String msg = "Il server ftp ha rifiutato il login con username: username e pwd: password .";
ftpClient.disconnect();
throw new Exception(msg);
}
ftpClient.enterLocalPassiveMode();
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
ftpClient.setDataTimeout(60000);
ftpClient.execPBSZ(0); // Set protection buffer size
ftpClient.execPROT("P"); // Set data channel protection to private
int bufSize = 1024 * 1024; // 1MB
ftpClient.setBufferSize(bufSize);
out = new ByteArrayOutputStream(bufSize);
ftpClient.retrieveFile("remoteFileName", out);
out.toByteArray();
}
finally {
if (out != null) {
out.close();
}
ftpClient.disconnect();
}
}
}
I also got a similar error when forced to use TLS1.2 for java 6.
And I handled it thanks to this library:
Clone Source Code:
https://github.com/tobszarny/ssl-provider-jvm16
Add Main Class:
public static void main(String[] args) throws Exception {
try {
String apiUrl = "https://domain/api/query?test=123";
URL myurl = new URL(apiUrl);
HttpsURLConnection con = (HttpsURLConnection) myurl.openConnection();
con.setSSLSocketFactory(new TSLSocketConnectionFactory());
int responseCode = con.getResponseCode();
System.out.println("GET Response Code :: " + responseCode);
} catch (Exception ex) {
ex.printStackTrace();
}
}
another BouncyCastle example. Just using bcprov-jdk15to18, bctls-jdk15to18, bcutil-jdk15to18, did the work for our old 1.6 client application. UPDATE: BC version 1.71
public static void main(String[] args) throws Exception {
//put BC providers in runtime context
if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
Security.insertProviderAt(new BouncyCastleProvider(), 1);
Security.insertProviderAt(new BouncyCastleJsseProvider(), 2);
}
//create an empty trust manager
TrustManager[] trustManager = new TrustManager[] { new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; }
public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) {}
public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) {}
} };
//initialize SSLContext
SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
sslContext.init(null, trustManager, new SecureRandom());
//connect and print data
URL url = new URL("https://stackoverflow.com");
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
connection.setSSLSocketFactory(sslContext.getSocketFactory());
connection.setRequestMethod("GET");
InputStream returnStream = connection.getInputStream();
for (int ch; (ch = returnStream.read()) != -1; ) {
System.out.print((char) ch);
}
returnStream.close();
connection.disconnect();
}