jdk7 call https url handshake_failure - https

jdk1.7.0_79 and okhttp 3.8 call https url failed
main, WRITE: TLSv1 Handshake, length = 148
main, READ: TLSv1 Alert, length = 2
main, RECV TLSv1 ALERT: fatal, handshake_failure
main, called closeSocket()
main, handling exception: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
main, called close()
main, called closeInternal(true)
write and read both TLSv1 why still handshake_failure , and if use jdk8 it's ok , handshake info as below
main, WRITE: TLSv1.2 Handshake, length = 170
main, READ: TLSv1.2 Handshake, length = 93
main, READ: TLSv1.2 Handshake, length = 5516
both client and server uses TLSv1.2
so tried change jdk7 default tls to TLSv1.2 follow below method in this doc
// Enable TLS 1.0, 1.1 and 1.2 in an SSLSocket object.
sslSocket.setEnabledProtocols(new String[] {"TLSv1", "TLSv1.1", "TLSv1.2"});
but still handshake_failure this time the debug info is
main, WRITE: TLSv1.2 Handshake, length = 178
main, READ: TLSv1.2 Alert, length = 2
main, RECV TLSv1 ALERT: fatal, handshake_failure
main, called closeSocket()
main, handling exception: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
main, called close()
main, called closeInternal(true)
this time write uses TLSv1.2 but recv still uses TLSv1.
Why is so? how to let client and server both use TLSV1.2?

OkHttp 3.12.12 (the maintained version of 3.x for JDK 7) should activate TLSv1.2 on JDK 7 already. Not sure why you have this code yourself.
https://github.com/square/okhttp/blob/parent-3.12.12/okhttp/src/main/java/okhttp3/internal/platform/Platform.java#L298
public SSLContext getSSLContext() {
String jvmVersion = System.getProperty("java.specification.version");
if ("1.7".equals(jvmVersion)) {
try {
// JDK 1.7 (public version) only support > TLSv1 with named protocols
return SSLContext.getInstance("TLSv1.2");
} catch (NoSuchAlgorithmException e) {
// fallback to TLS
}
}
try {
return SSLContext.getInstance("TLS");
} catch (NoSuchAlgorithmException e) {
throw new IllegalStateException("No TLS provider", e);
}
}
You can enable frame logging with code similar to https://github.com/square/okhttp/blob/master/okhttp-testing-support/src/main/kotlin/okhttp3/OkHttpDebugLogging.kt

As the other answer points out, if using Java 7 you need at least OkHttp 3.12.12 to support TLSv1.2.
But you also have to take into account the cipher suites enabled in the server that must be compatible with OkHttp.
By default OkHttp uses a list of 17 "approved" cipher suites, that you can check here https://github.com/square/okhttp/blob/okhttp_3.12.x/okhttp/src/main/java/okhttp3/ConnectionSpec.java (see APPROVED_CIPHER_SUITES)
But of those 17, only 5 are supported by de JDK 1.7:
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
TLS_RSA_WITH_AES_256_CBC_SHA
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
TLS_RSA_WITH_AES_128_CBC_SHA
SSL_RSA_WITH_3DES_EDE_CBC_SHA
So if the server doesn't accept any of this cipher suites, you get the handshake failure error.
If the server accepts some cipher suites supported by Java 7, but that are not on the list of APPROVED_CIPHER_SUITES in OkHttp you can create your own ConnectionSpec and use it in the OkHttpClient.Builder. For example, supposing the server accepts the following cipher suites supported by Java 7:
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
You could do something like this to add them to the list of OkHttp supported cipher suites:
// Create a list of cipher suites based on the default approved list by OkHttp
List<CipherSuite> cipherSuites = new ArrayList<CipherSuite>(ConnectionSpec.MODERN_TLS.cipherSuites());
// Add another cipher suites suported by Java 7
cipherSuites.add(CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384);
cipherSuites.add(CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256);
// Build a connection spec based on the default overridding the cipher suites.
ConnectionSpec COMPATIBLE_SPEC = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
.cipherSuites(cipherSuites.toArray(new CipherSuite[0]))
.build();
// Build a client specifying our own connection spec
OkHttpClient client = new OkHttpClient.Builder()
.connectionSpecs(Util.immutableList(COMPATIBLE_SPEC))
.build();

Related

Issues establishing a secure connection to Mosquitto Broker 2.0.10 using M2MQTT v4.3.0.0 and signed certificates

I'm trying to implement MQTT in my program using M2MQTT v4.3.0.0 (github), but when I try to connect using signed certificates my code cannot establish a connection. I'm on a Windows 10 system, and using C# with .NET 4.8. The version of Mosquitto I have installed is 2.0.10.
To make the server certificate I followed this tutorial:
http://www.steves-internet-guide.com/mosquitto-tls/#server
To make the client certificate I followed this tutorial:
http://www.steves-internet-guide.com/creating-and-using-client-certificates-with-mqtt-and-mosquitto/
I also made a host name in my etc/hosts file for 127.0.0.1 that points to localhost.conrad.com.
The configuration for my Mosquitto Broker is:
bind_address localhost.conrad.com
port 8883
allow_anonymous true
cafile C:/mosquitto/certs/ca.crt
keyfile C:/mosquitto/certs/server.key
certfile C:/mosquitto/certs/server.crt
require_certificate true
tls_version tlsv1.2
log_dest file C:/mosquitto/log/mosquitto.log
log_type error
log_type warning
log_type notice
log_type information
I successfully tested that this configuration works using Mosquitto's command line publish tool with
mosquitto_pub --cafile C:\mosquitto\certs\ca.crt --cert C:\mosquitto\certs\client.crt --key C:\mosquitto\certs\client.key -d -h localhost.conrad.com -p 8883 -t herp/derp/test -m "hi"
I received this message after using the command.
Client (null) sending CONNECT
Client (null) received CONNACK (0)
Client (null) sending PUBLISH (d0, q0, r0, m1, 'herp/derp/test', ... (2 bytes))
Client (null) sending DISCONNECT
My Mosquitto log confirms a successful connection:
1621547553: New connection from 127.0.0.1:57874 on port 8883.
1621547553: New client connected from 127.0.0.1:57874 as auto-6A8387C3-E091-0EC6-CED7-0A78BAA63099 (p2, c1, k60).
1621547553: Client auto-6A8387C3-E091-0EC6-CED7-0A78BAA63099 disconnected.
However when I try to connect using M2MQTT I run into a problem when trying to connect using signed certificates. My code is as follows:
int securePort = 8883;
MqttClient client = null;
string subTopic1 = "herp/derp/test";
string subTopic2 = "herp/derp/test2";
X509Certificate caCert = new X509Certificate("C:/mosquitto/certs/ca.crt");
X509Certificate clientCert = new X509Certificate("C:/mosquitto/certs/client.crt");
string clientID = "TestClientID";
public MQTTTest()
{
try
{
client = new MqttClient("localhost.conrad.com", securePort, true, caCert, clientCert, MqttSslProtocols.TLSv1_2, RemoteCertificateValidationCallback);
client.MqttMsgPublishReceived += client_MqttMsgPublishReceived;
client.MqttMsgPublished += client_MqttMsgPublished;
client.MqttMsgSubscribed += client_MqttMsgSubscribed;
client.ConnectionClosed += client_ConnectionClosed;
client.Connect(clientID, "", "", true, 1000);
client.Subscribe(new string[] { subTopic1, subTopic2 }, new byte[] { MqttMsgBase.QOS_LEVEL_AT_LEAST_ONCE, MqttMsgBase.QOS_LEVEL_AT_LEAST_ONCE });
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
I get the following exception when trying at client.Connect.
Exception message: "A call to SSPI failed, see inner exception."
Inner exception: "The message received was unexpected or badly formatted"
My Mosquitto logs show:
1621547793: New connection from 127.0.0.1:57896 on port 8883.
1621547793: OpenSSL Error[0]: error:1417C0C7:SSL routines:tls_process_client_certificate:peer did not return a certificate
1621547793: Client <unknown> disconnected: protocol error.
I can establish insecure connections just fine. As it is written my code also connects when I set require_certificate to false in my Mosquitto config file; however I am worried that if require_certificate is set to false that I won't have the security I want. Any help would be greatly appreciated.
Thanks to Brits' comment I was able to figure it out (link to answer). I made a pfx certificate and used that instead of using a crt.
Instead of...
X509Certificate caCert = new X509Certificate("C:/mosquitto/certs/ca.crt");
X509Certificate clientCert = new X509Certificate("C:/mosquitto/certs/client.crt");
I used...
X509Certificate2 caCert = new X509Certificate2("C:/mosquitto/certs/ca.pfx", "password");
X509Certificate2 clientCert = new X509Certificate2("C:/mosquitto/certs/client.pfx", "password");

How to bypass SSL certificate in Gsoap for C++

I have this error for webservice accessment with Gsoap.
We are doing test so no SSL certificate check is required.
But my client side, how can I bypass SSL check?
i'm using C++.
My error is
SOAP 1.2 fault SOAP-ENV:Sender[no subcode]
"OpenSSL not installed: recompile with -DWITH_OPENSSL"
Detail: [no detail]
This is the solution.
#include "calc.nsmap"
#include "soapcalcProxy.h" // generated with soapcpp2 -j calc.h
calcProxy calc("https-server-endpoint-URL");
double sum;
soap_ssl_init(); // init SSL (just need to do this once in an application)
// soap_ssl_no_init(); // or prevent init OpenSSL when already initialized elsewhere in an application
if (soap_ssl_client_context(calc.soap,
SOAP_SSL_DEFAULT,
NULL, // no keyfile
NULL, // no keyfile password
"cacerts.pem", // trusted certificates (or use self-signed cacert.pem)
NULL, // no capath to trusted certificates
NULL // no random data to seed randomness
))
{
calc.soap_stream_fault(std::cerr);
exit(EXIT_FAILURE);
}
if (calc.add(1.23, 4.56, sum) == SOAP_OK)

Redirect HTTP requests to HTTPS in netty

I am modifying elasticsearch code to configure HTTPS without x-pack and reverse proxies.
I modified initchannel() method in the netty4HttpServerTransport file , https is working fine,but i want to redirect http to https..
The code is,
char[] password = "your5663".toCharArray();
KeyStore ks = KeyStore.getInstance("JKS");
ks.load(new FileInputStream("C:/OpenSSL-Win64/bin/keystore1.jks"),password);
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(ks, password);
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(ks);
TrustManager[] tm = tmf.getTrustManagers();
SSLContext sslContext = SSLContext.getInstance("TLSv1.3");
sslContext .init( kmf.getKeyManagers(), tm, null);
SSLEngine sslengine = sslContext .createSSLEngine();
sslengine.setUseClientMode(false);
String[] DEFAULT_PROTOCOLS = { "TLSv1", "TLSv1.1", "TLSv1.2","TLSv1.3" };
String[] DEFAULT_CIPHERS = {"TLS_RSA_WITH_AES_128_CBC_SHA256", "TLS_RSA_WITH_AES_128_CBC_SHA"};
sslengine.setEnabledProtocols(DEFAULT_PROTOCOLS);
sslengine.setEnabledCipherSuites(DEFAULT_CIPHERS);
SslHandler sslHandler = new SslHandler(sslengine);
ch.pipeline().addLast("ssl", sslHandler);
ch.pipeline().addAfter("ssl","handshake",new StringEventHandler());
How do i make http to https redirect in this code.
Redirect works on the payload (http) level, not ssl transport level. You would need to listen on both protocol (http and https) and on the http channel you can respond with redirect status code. Long story short - there is no direct place on in your code you can do that.
Very commonly a proxy server is used for this task. I am not sure if you can do it in elasticsearch, you can try to configure a filter servlet to check the protocol respond with a redirect. This may be helpful https://github.com/elastic/elasticsearch-transport-wares
Another fact - if the redirect is for service clients (not browser based ui), the clients may/will consider a redirect response an an error response. Depending on your environment - maybe you can just expose the ssl endpoint (no redirects) and clients will have to comply
Netty has a built in handler for this, OptionalSslHandler.
You put it at the front of your pipeline and it detects if the message is encrypted or not. If it is, then the message will be sent onto the normal SSL pipeline, if not then you can specify somewhere else to send it, e.g. to a 301 redirect to https.
You could either use this Netty version or make your own handler that does something similar.
However, to use the Netty version you will need to refactor slightly to produce a Netty SslContext io.netty.handler.ssl.SslContext, instead of an SSLEngine.
Something like this:
char[] password = "your5663".toCharArray();
KeyStore ks = KeyStore.getInstance("JKS");
ks.load(new FileInputStream("C:/OpenSSL-Win64/bin/keystore1.jks"),password);
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(ks, password);
SslContext sslContext = SslContextBuilder.forServer(keyManagerFactory).build();
ch.pipeline().addLast("ssl", sslHandler);
// this is an imaginary handler you create that sends HTTP a 301 to HTTPS
// non-SSL can be detected easily because there is no SslHandler on this channel
ch.pipeline().addLast("redirectHandler", new RedirectHandler());
ch.pipeline().addLast("handshake",new StringEventHandler());

Getting Error - javax.net.ssl.SSLHandshakeException: Server chose TLSv1, but that protocol version is not enabled or not supported by the client

Getting Error - javax.net.ssl.SSLHandshakeException: Server chose TLSv1, but that protocol version is not enabled or not supported by the client when making a call to a secured webservice.
Appended the following option to the JAVA_OPTIONS variable in the mydomain\bin\ setDomainEnv.cmd as advised in the oracle site but same issue.
-Dweblogic.security.SSL.protocolVersion=TLS1
Java client code :
File pKeyFile = new File("C:\\myJKS.jks");
if (pKeyFile.exists() && !pKeyFile.isDirectory()) {
logger.debug("JKS file exists, and it is a file");
}
KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(new FileInputStream(pKeyFile.toString()),
pKeyPassword.toCharArray());
KeyManagerFactory keyManagerFactory = KeyManagerFactory
.getInstance("SunX509");
keyManagerFactory.init(keyStore, pKeyPassword.toCharArray());
**SSLContext context = SSLContext.getInstance("TLSv1.1");**
context.init(keyManagerFactory.getKeyManagers(), null,
new SecureRandom());
sockFact = context.getSocketFactory();
if(sockFact == null){
logger.debug("SocketFactory is null");
throw new NullPointerException("socketFactory == null");
}
Client Env - JDK version: 7, Application server:Weblogic.
Trying to make it work from couple of days, but no luck.

How to configure WebSockets (RFC 6455) in Netty 3.3?

I have Netty 3.3 server with WebSockets from https://github.com/netty/netty/tree/3.2/src/main/java/org/jboss/netty/example/http/websocketx/server
I have client that implement RFC 6455, but server can't decode it's messages by default. While debugging, I see that WebSocket08FrameDecoder is used (instead WebSocket13FrameDecoder). When I downgrade client to draft00 everything works fine.
How do I configure Netty to decode RFC 6455 messages?
update
Client send this handshake package:
GET /websocket HTTP/1.1
Upgrade: WebSocket
Connection: Upgrade
Sec-WebSocket-Version: 13
Sec-WebSocket-Key: 5a087
Host: 127.0.0.1
Origin: 127.0.0.1
And the handshaker on the server is WebSocketServerHandshaker13, but I still get error:
org.jboss.netty.handler.codec.frame.CorruptedFrameException: unmasked client to server frame
at org.jboss.netty.handler.codec.http.websocketx.WebSocket08FrameDecoder.protocolViolation(WebSocket08FrameDecoder.java:350)
at org.jboss.netty.handler.codec.http.websocketx.WebSocket08FrameDecoder.decode(WebSocket08FrameDecoder.java:138)
at org.jboss.netty.handler.codec.http.websocketx.WebSocket08FrameDecoder.decode(WebSocket08FrameDecoder.java:56)
at org.jboss.netty.handler.codec.replay.ReplayingDecoder.callDecode(ReplayingDecoder.java:465)
at org.jboss.netty.handler.codec.replay.ReplayingDecoder.messageReceived(ReplayingDecoder.java:438)
at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:268)
at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:255)
at org.jboss.netty.channel.socket.nio.NioWorker.read(NioWorker.java:343)
at org.jboss.netty.channel.socket.nio.NioWorker.processSelectedKeys(NioWorker.java:274)
at org.jboss.netty.channel.socket.nio.NioWorker.run(NioWorker.java:194)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:662)`
If you look in WebSocketServerHandshakerFactory, it instances the decoder based on the web socket version passed in the HTTP header.
public WebSocketServerHandshaker newHandshaker(HttpRequest req) {
String version = req.getHeader(Names.SEC_WEBSOCKET_VERSION);
if (version != null) {
if (version.equals(WebSocketVersion.V13.toHttpHeaderValue())) {
// Version 13 of the wire protocol - RFC 6455 (version 17 of the draft hybi specification).
return new WebSocketServerHandshaker13(webSocketURL, subprotocols, allowExtensions);
} else if (version.equals(WebSocketVersion.V08.toHttpHeaderValue())) {
// Version 8 of the wire protocol - version 10 of the draft hybi specification.
return new WebSocketServerHandshaker08(webSocketURL, subprotocols, allowExtensions);
} else {
return null;
}
} else {
// Assume version 00 where version header was not specified
return new WebSocketServerHandshaker00(webSocketURL, subprotocols);
}
}
Please check your client implementation to see which version it is sending in the HTTP header. It should be Sec-WebSocket-Version: 13.

Resources