I have a very basic question: how does client_hello or server_hello in SSL handshake determine what SSL/TLS version can it support? I mean, as far as I understand, first client and then server send out the highest possible SSL version they support. But, how is this determined?
Is it the version field in a certificate?
Best regards,
HL
This is all described in the TLS specification, appendix E. This is phrased slightly differently in the TLS 1.0, 1.1 and 1.2 specification, but the principle remains the same.
Essentially, the client asks for the highest version it can support and the server responds with the highest version it can support up to the client's version:
min(max. client supported version, max. server supported version)
This works as long as there the resulting version is indeed supported by both parties.
The client is responsible for initiating an SSL handshake by sending the ClientHello message. If this isn't the first message that is sent, the server responds with an error and shuts down the socket.
The client advertises to the server which cipher specs it supports, it's not required to support all of them.
The client sends the server the client's SSL version number, cipher settings, session-specific data, and other information that the server needs to communicate with the client using SSL.
The client also sends a challenge token, which the server must encrypt using the newly negotiated key before sending back the encrypted value, in its hello message. The client verifies that the decrypted token is the same as what was sent. If it's not, the handshake is rejected.
View the complete demo here
Related
I have java app deployed to tomcat server 8.5.32.
I configured the server to use only TLS 1.2 so if the user send a request to the app(tomcat server) using browser and the browser is old(supports only TLS 1.0 and TLS 1.1) then i want to know that someone tries to reach my app but no handshake is made and I want to make a record in DB.
Is there any way I can know that client is using TLS version that my server is not supporting it and somehow get that info what is the TLS version of the client? OR at least to know that client is using older TLS version?
I used Wireshark to monitor packages of some websites, but found that there are such many communicating patterns of TLS 1.2.
The first one is a generic one:
Client: Client Hello
Server: Server Hello, Certificate, Server Hello Done
Client: Client Key Exchange, Change Cipher Spec, Encrypted Handshake Message
Server: Change Cipher Spec, Encrypted Handshake Message
Second one is as followed:
Wireshark1
I'm just confused with why Certificate and Server Hello Done was in another package. Who demand server to do that? For what reasons?
After multiply refreshing page, I got the third one:
Wireshark2
Only 3 packages in handshake? A lot of processes were missed, was it because the information was cached? And how about the pre-master key?
Thanks for the answering!
TLS is a protocol over TCP, i.e. over a streaming transport protocol. For transport the data stream gets split into packets and thus it can happen that the ServerHelloDone is contained in one packet or in another or even split over two packets. Since the sizes are visible in your second example but not in the first it is unknown why the difference is exactly but it might be caused by the size of the certificate(s) contained in the handshake.
As for the third example: this is simple a TLS session reuse, i.e. it continues an older session and thus no sending of server certificate or similar is needed.
I would like to display a message to customers who's browser's highest level of encryption is SSLv3. Is it possible for me to target browser settings of SSLv3 and lower? Client or Server code? We will be allowing lower versions of SSL to use our site during a certain grace period. During this grace period, we would like to display a message only to those users that have browser settings of SSL3 or lower.
Not easily. The browser's supported SSL versions are not detectable until the SSL handshake is in progress, and even then only if the browser uses an SSLv2 handshake to allow dynamic version negotiation. If an unsupported version were detected, you would not be able to send a message back since the handshake failed and the connection would be closed before you could send any message. However, SSL itself has an error packet that gets sent during handshaking, and it can specify a version mismatch error.
The best you can do in your own code is support all SSL versions on the server side, let the client complete a handshake normally, and then detect which version was actually used and send back a message if the SSL version is too low.
Or, you could simply enable TLSv1 or higher only, and simply refuse to let older clients connect at all. They just would not get a nice error message unless the browser decided to detect the SSL version mismatch error and display its own pretty message about it.
Firstly, nowadays, you can generally forget about clients that don't support at least SSLv3. SSLv3 has been widely available for many years.
The TLS Client Hello message, sent when the connection is initiated by the browser, should contain the highest TLS version it supports:
client_version
The version of the TLS protocol by which the client wishes to
communicate during this session. This SHOULD be the latest
(highest valued) version supported by the client. For this
version of the specification, the version will be 3.3 (see
Appendix E for details about backward compatibility).
Appendix E is of course worth looking at.
(The Client Hello message will also contain the list of cipher suites the client supports, which is possibly relevant for the general idea of your question.)
Of course, this specification is just a "SHOULD", so a client supporting TLS 1.2 could still send a Client Hello for TLS 1.1, but what would be the point? By doing so it would have no chance ever to use TLS 1.2 anyway. It could be a preference box that is turned off, but that would effectively make it a client that doesn't support the highest version anyway. (If you want anything more subtle, you'd need to build a database of known user agents, which will be partly unreliable, and for which you'd need to analyse the full user agent string to know everything possible about the platform.)
Now, how to convey the content of the Client Hello message to your application is another matter, and depends very much on which SSL/TLS stack you use. It might not even be directly possible without modifying that SSL/TLS library or the server you're using.
This being said, you can generally get the negotiated TLS version during the current session quite easily. Since that version is the "lower of that suggested by the client in the client hello and the highest supported by the server" (i.e. "min(max(client), max(server))"). If your server supports SSLv3, TLS 1.0, TLS 1.1 and TLS 1.2, and since the latest version is TLS 1.2 anyway, what you'll get during your current connection will also be the max currently supported by the client. As long as your server supports the latest version, you should be able to know what the client supports at best from any live connection.
If you're behind Apache HTTP server's mod_ssl, you should be able to get that from the SSL_PROTOCOL environment variable. You should also be able to get the protocol from the SSLSession in Java.
(If you are willing to write a more bespoke service, you could pass further details like the cipher suites more directly to your application, like this service from Qualys SSL Labs does, although I'm not sure if it's meant to be widely available or just a test service.)
I'd have to agree with Remy about it being a bit challenging.
However, a good starting point may be to retrieve some SSL (certificate) information.
Something similar to this:
X509Certificate certChain[] =
(X509Certificate[]) req.getAttribute("javax.net.ssl.peer_certificates");
Another way of getting more information is to retrieve the cipher_suite attribute (similar to the code snippet above).
javax.net.ssl.cipher_suite
I hope this (at least) gets you closer.
Good luck.
I am using Amazon RDS MySQL and connecting with SSL certificate(the default certificate available at http://s3.amazonaws.com/rds-downloads/mysql-ssl-ca-cert.pem), I am doing the following steps:
Downloaded the mysql-ssl-ca-cert.pem
Modified the above file to JKS format
And connecting from a web application through Spring - Hibernate template (org.springframework.beans.factory.config.PropertyPlaceholderConfigurer) and also use c3p0, we are setting additional URL parameter as jdbc:URL/DB?autoReconnect=true&useUniCode=true&characterEncoding=UTF-8&useSSL=true&verifyServerCertificate=false&requireSSL=true
But I am facing the below issue...
javax.net.ssl.SSLException: Unsupported record version Unknown-0.0
How can I fix this?
Basically it means that the SSL parser is lost. The sockets layer has passed it some bytes that don't fit the SSL protocol.
When you transmit using an SSL Socket, it calls a formatting and encryption routine to create the encrypted packet. It then calls the plain sockets layer to transfer the encrypted packet to the server. The server's sockets layer receives the packet and then calls the SSL package to decrypt the packet. If the packet doesn't fit the SSL format, you get the unsupport version exception.
All bytes that arrive at the socket layer are sent to the SSL package. So the simplest way to get that error is to use the plain sockets layer to transmit a plain text message after establishing the SSL connection.
In my particular case, I ran into this error message because I was transmitting extra bytes. Let's see if I can explain my mistake clearly.
I had a buffer that was (for example) 100 bytes. I packed the buffer with my 50 byte message and called the SSL encryption routine. The resulting packet was 75 bytes long. I called send() to transmit the buffer. This was a plain sockets send; it did what I told it to do, which was transmit the entire 100 byte buffer.
At the server, the entire 100 bytes was received. The SSL package tried to decrypt the packet. It found a perfectly good SSL message packed into the first 75 bytes that were received. So far so good. Then it tried to figure out what the remaining 25 bytes meant. It assued that it was a SECOND SSL message and tried to decrypt it. That's when it choked and kicked out that nasty exception.
I hope that gives you some clues about what to look for in your code.
I found this error if I presented an unsupported client certificate. Blanking out "-Djavax.net.ssl.keyStore" and connecting with no client certificate worked.
See also http://feed.askmaclean.com/archives/secure-java-connections-by-default.html :
Support for various TLS versions differs based on the JRE version used. Make sure you know the capabilities of the JDK you are using before restricting specific TLS versions. When first running the test above, Eclipse was using JRE 1.6.0_45 instead of JRE 1.8.0_65 I expected, and was connecting using TLSv1.0 ciphers. When MySQL Server was configured to only allow TLSv1.1 and TLSv1.2, I received the following Exception:
Caused by: javax.net.ssl.SSLException: Unsupported record version Unknown-0.0
at com.sun.net.ssl.internal.ssl.InputRecord.readV3Record(InputRecord.java:504)
Usage of older JREs should be assessed before disabling TLSv1.0 – fortunately, PERFORMANCE_SCHEMA makes it easy to survey client JREs without having to inspect every application server.
How can one tell if the SSL communication between a client and a server is SSLv2 or SSLv3?
On the SSL protocol level, the second byte of the header contains the major version of the protocol, which is 3 for SSLv3/TLS, presumably 2 for SSLv2. Note that the client sends the highest version it supports in its ClientHello message, and the server responds with the version it chose (which may be lower) in the ServerHello message.
Of course, you should work with an API that allows you to query the version without getting down to the protocol level.