This question already has an answer here:
Get SSL Version used in HttpsURLConnection - Java
(1 answer)
Closed 4 years ago.
I've got the following lines of code to set up an SSL connection:
HttpsURLConnection con = (HttpsURLConnection) new URL(url).openConnection();
I use the given connection to send a message and retrieve a response.
Now I've gotten the question: Which security technique is used in this connection? I'd like to know if the connection is, for example, TLS1.2. How can I retrieve this using Java?
HttpsURLConnection will use whatever scheme is negotiated between the client and the server. It is possible to get some information about the cipher suites used, and the client and server certificates, but the protocol / version are not directly exposed by the public APIs.
Retrieving the protocol that was actually used is tricky.
If you have enabled SSL debug, then the debug output will include the protocol version, and copious other information. However, since the format of the debug output is not specified / subject to change, it would not be a good idea to try to extract this programatically.
But if eyeballing debug output is acceptable, this is the answer.
If you read the Java SSL codebase, you will find a class called SSLEngineImpl, which has a private field called protocolVersion that gives the protocol and version that the connection is using. Unfortunately, the "engine" instance is deeply buried and it would be difficult to get to it at runtime.
If you implement your own SSLSocketFactory, you can get the protocol used from the SSLSession object after the session has been established; see Get SSL Version used in HttpsURLConnection - Java.
Finally, it is possible to figure out which protocol is used by decoding the initial messages sent over the TCP/IP connection. The messages are the "client hello" and "server hello" messages. The connection is not encrypted at this stage.
Oracle References:
Debugging SSL/TLS Connections
Java Secure Socket Extension JSSE) Reference Guide.
Related
I currently have an application that would make HTTP post request to a lot of URLs. Some of the connections are failing with the following exception.
Exception in thread "main" javax.net.ssl.SSLProtocolException:
handshake alert: unrecognized_name at
sun.security.ssl.ClientHandshaker.handshakeAlert(ClientHandshaker.java:1410)
at sun.security.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:2004)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1113)
at
sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1363)
at
sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1391)
. . .
Hence, I want to set “jsse.enableSNIExtension” to false only for specific connections which throw the above mentioned exception.
How do I do it on an HTTPsURLConnection/SSLSocket level?
Code
URL url = new URL("https://artofskinmd.localgiftcards.com/");
HttpURLConnection httpConnection = (HttpURLConnection) url.openConnection();
httpConnection.connect();
I am trying to find a way to change the SSLParameters for the HttpsURLConnection object. But I am unable to find any setSSLParameters() method for setting an empty server names list. I am not able to find anything online on setting SSLParameters for HttpURLConnection, SSLContext etc
Obviously the site depends on SNI, otherwise it would not care about the name sent by the client in the SNI extension. This means that disabling the extension will probably not help, but instead you would then either get some handshake failure or some default site (and certificate) and probably not the site you have intended. To fix the problem you should not disable SNI but instead use the correct name, i.e. the name expected by the site.
Edit: This looks like both a bad server configuration together with a bug in Java7 and Java8. Access to the URL https://artofskinmd.localgiftcards.com/ will result in a unknown_name TLS alert warning which Java7 and Java8 wrongly consider fatal (same as the very old OpenSSL 0.9.8). Disabling SNI will actually help in this case, but there seems to be no way to disable SNI for a single HttpURLConnection object.
See
Java jar - no main manifest attribute
And this commit
https://github.com/Lekensteyn/OWASP-WebScarab/commit/8f2362eb021924cece9fb544f04bde5da7bfed4a
Folks,
We have a Java Applet communicating with the server through a BigIp Load-Balancer. The Java Applet is using an HttpURLConnection and the communication protocol is https.
The Load-Balancer implements a cookie based persistence policy to maintain session affinity.
This all works fine when the Java Applet using Java 1.5, 1.6 and early versions of Java 1.7.
Somewhere around Java 1.7.0_21 something went wrong with the Java Applet and now when we open HttpURLConnection for the 2nd time and on, the load balancer does not pass the request to the server but instead replies with the same response sent for the 1st request from the Applet as if thinking the request is for static content that can be cached.
Any ideas what has changed in recent versions of Java with respect to HttpURLConnection ?
You may want to check that you are properly negotiating an SSL connection. You can do this two ways: create an iRule to log to /var/log/ltm:
when HTTP_REQUEST {
log local0. “Requested hostname: [HTTP::host] from IP: [IP::local_addr]”
}
Turn on SSL debug logging:
tmsh modify /sys db log.ssl.level value Debug
If you are failing to negotiate SSL, you will not see anything logged from the iRule, but should have an answer as to why you are failing to handshake. Most often you need to adjust your cipher string.
I am using a Java based Web Server ( PlayFramework 2.2 FWIW - see the very good write up on TLS ), and I want to debug the SSL communication for various devices, eg: Android, to see exactly what is happening on the wire as far as TLS goes. For this I can use Wireshark to decrypt the SSL layer. This works if the server does not create an Ephemeral key, as explained nicely by Steven Iveson:
Important: Ensure the use of a Diffie-Hellman Ephemeral (DHE/EDH) or
RSA Ephemeral cipher suite is not negotiated between the two hosts.
This is indicated by the use of a ServerKeyExchange message. There is
no way to decrypt data where ephemeral ciphers are used.
The Java Secure Sockets Extension Reference Guide section on how to Disable Algorithms points to the jdk.tls.disabledAlgorithms property which I have tried setting directly in the $JAVA_HOME/jre/lib/security/java.security file to
jdk.tls.disabledAlgorithms=DH, ECDH, EDCHE, DiffieHellman
I tried using some of the Java™ Cryptography Architecture
Standard Algorithm Name Documentation as an attempt to select one of those strings, but I have been selecting a bit in the wild.
I tried setting it also using it in code to
java.security.Security.setProperty("jdk.tls.disabledAlgorithms","ECDH, ECDHE, ECDHE_RSA, DiffieHellman")
but that does not seem to stop the the appearance of the ServerKeyExchange messages, as shown in the screenshot of Wireshark 1.11.2 on OSX: . And indeed I don't seem to be able to decrypt the stream.
Any idea what I may be doing wrong?
Not sure if this will help, but try doing it inside a privileged block:
AccessController.doPrivileged(
new PrivilegedExceptionAction[Unit]() {
java.security.Security.setProperty("jdk.tls.disabledAlgorithms","ECDH, ECDHE, ECDHE_RSA, DiffieHellman")
}
)
I was close. The answer seems to be to set the security property as follows:
jdk.tls.disabledAlgorithms=DHE, ECDHE
(I came on that after reading the hot-off-the-press blog post: JDK 8 will use TLS 1.2 as default).
Once that is set on the server, an https connection captured by Wireshark no longer shows the Server Key Exchange message.
It is then possible to decrypt content that went over the wire as shown by this image
I hope this will be useful when trying to analyse what Android cell phones are receiving over the wire.
Hi I am trying out a simple java http server NanoHTTPD: http://elonen.iki.fi/code/nanohttpd/
Today I try to support it with HTTPS, so I create SSLServerSocket in its NanoHTTPD constructor:
// myServerSocket = new ServerSocket(myTcpPort);
myServerSocket = SSLServerSocketFactory.getDefault().createServerSocket(myTcpPort);
and also supplied javax.net.ssl.keyStore with 2048 bit RSA key
The result is that https connections succeed on MSIE6.0, MSIE8.0, Firefox 9.0.1
However fail on Google Chrome 17.0.963.56 m and Firefox 10.0.1:
from debugging, NanoHTTPD.HTTPSession.decodeHeader method gets only String inLine = "G" barely one single char, while normally here you will expect the standard http header "GET / HTTP/1.1".
So anybody familiar with Firefox could tell what's different in 9.0.1 and 10.0.1 regarding https / ssl? Something made by browsers may be the point. (Of course I am newbie in java ssl programming, please tell me if I am wrong in SSLServerSocket).
I have cross posted this issue:
https://support.mozilla.org/en-US/questions/920116
Thank you all.
The short of it is that your SSL implementation is broken. SSL records can be split in arbitrary ways, and Google and Mozilla changed the way they split theirs to work around some MITM attacks on SSL. Specifically, a 1-byte SSL record is sent before sendinga second SSL record with the rest of the data. It sounds like your SSL implementation is only reading the first record instead of reading all the data.
See http://rt.openssl.org/Ticket/Display.html?id=2635&user=guest&pass=guest and https://bugzilla.mozilla.org/show_bug.cgi?id=665814 and articles like http://www.livehacking.com/2011/10/27/chrome-15-broke-the-wall-street-journal-while-trying-to-beat-the-beast/
I can confirm the SSLEngine from java appears broken by default. The way I can get around it is:
^Cpck0:bin vladimirralev$ /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --disable-ssl-false-start --use-spdy=off --use-system-ssl
That turns off the weird TLS modes.
It looks like recent SSLEngine will behave correctly if you keep following the instructions it gives you to read a segmented packets. You have to loop through multiple reads (with some intermittent states in between) and you will have the complete chunk eventually.
I am using https to connect to an https server.
Specifically I am using apache httpclient and I configure the ssl context to use my keystore and truststore.
The https server I am using is IIS7 and is configured to require client authentication.
I think I have set it up properly.
Anyway, if I configure the httpClent's ssl context with a keystore (i.e. with client certificates) valid for IIS then there is no problem connecting.
Now my problem is the following:
If I do not configure the ssl context with any client certificate to send to IIS, there is no connection with the server. What makes me think though, is the fact that I was expecting to see some java exception in the code as a result of a hanshake failure alert.
Monitoring what is happening with wireshark, I could not see a certificate request from IIS to my application, but I noticed that after ServerHelloDone everything was encrypted.
I did not expect that. I think the handshake is usually in cleartext.
I used private key to decrypt traces and i saw a certificate request from IIS but after many starting and opening of new connections.
My app send back as a response a certificate of length 0 and IIS replies with a TLSv1 Finished.
After that the packets stop (i.e. seems that the communication ends).
I was expecting a handshake alert.
My question is, is this how it is supposed to work or at least how IIS works?
Or if I do not see the alert something is wrong with my use case?
Thanks
It sounds like IIS is only requiring client certificates for certain URLs (ie, for example.com/foo, but not example.com/bar).
In the initial handshake, it does not know which url you are requesting, so it does not require a certificate. When it sees that you are requesting a restricted resource (/foo), it then rehandshakes, requiring a certificate.
However, I would still expect a handshake_failure to occur.
As I was saying in an answer to this question, as far as I remember, IIS uses re-negotiation to get the client certificate. You should be able to change this behaviour using netsh and clientcertnegotiate=enable (depending on the version of IIS you're using).
You might also be interest in this similar question.
Failing to supply a certificate in response to a CertificateRequest isn't an SSL protocol error, so there is no handshake_error. 'Requiring' instead of just 'needing' client certificates is added-in by SSL libraries, and all they can do if you don't send one is just close the connection.