Different communicating patterns in TLS 1.2 - ssl

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.

Related

During handshake of TLS connection where does the client fetch the list of cipher suites from?

From where does the client fetches the list of cipher suites that it is going to propose to server?
For example, it looks like that on same machine, clients of two different applications can propose the different list of cipher suits.
To limit the scope of question, I want to understand it for RabbitMQ Client and TLS1.2.
More clarification
So I have RabbitMQ service installed on my machine and then in C# code I try to connect (Ex. var connection = factory.CreateConnection()) to it without any cipher suits configuration.
So here my C# application could be considered as Client.
please note that I am asking about the ciphers that client sends in 'Client Hello' message.
P.S. somewhere I read that rabbitmq internally uses openssl, so when I ran the command 'openssl ciphers -s -tls1_2' I got a list that is different when I see rabbitmq client hello's cipher suits in wireshark. Also I don't have any group policy on machine that overrides the ciphers.
See https://tls13.ulfheim.net/ for a nice graphical representation of a TLS 1.3 exchange.
In the second message, ClientHello, the client gives among other things a list of ciphers it supports. Where it gets it? Either hard-coded in the application or computed dynamically once decided to connect, etc. this all depends on the application, so you need to investigate its code source/its configuration.
If you take for example openssl s_client as TLS client, you have -cipher and -ciphersuites configuration options to specify which specific ciphers to announce when connecting.
If you look later in the exchange, there is a ServerHello where the server announces which cipher suite will be used.
How that happens? Typically, the server has its own list of preferred ciphers ordered by "quality" (cryptographic strength like preferring 256bits over 128bits and/or other properties like preferring PFS over non PFS), and based on what it got from the client, it tries to select the "best" one that is supported on both side, which is not necessarily always possible.
Now as you put in comments a specific application (Google Chrome), you can see at https://source.chromium.org/chromium/chromium/src/+/main:third_party/boringssl/src/ssl/ssl_cipher.cc;l=1152?q=cipher&ss=chromium%2Fchromium%2Fsrc the definition of a function called "ssl_create_cipher_list" whose goal is to build the cipher list, starting from all compiled ones, and then applying various rules to enable/disable some and sorting them in an order that makes sense. This is of course highly dependent on the application for how it is done, but you can certainly find similar operations in other toolkits.
Finally, do note that there is a big difference between TLS 1.2 (ciphers) and TLS 1.3 (ciphersuites). They are disjoint sets, and when TLS 1.2 has "myriad" of ciphers in the wild (see for example https://www.openssl.org/docs/man1.1.1/man1/ciphers.html for lots of them), TLS 1.3 defines only 5 ciphersuites (see https://datatracker.ietf.org/doc/html/rfc8446#appendix-B.4) with one being mandatory to implement, so the whole question of auto-negotiation between client and server becomes almost moot.
As you mention explicitly tls1.2 as tag, do note there is no real reason today not to use 1.3 instead (which is why my first link is on purpose specially for 1.3 - the handshake routine is different in 1.2 but identical for things related to your question of ciphers), you will gain a lot of benefits, from simplified operations, better cryptography all around, and fewer holes.

In what cases will server send empty session id during TLS handshake?

I want to uses the SSL session ID for session stickiness and session persistence on loadbalancer. The SSL handshake process is successful. But i see in tcp traces server empty session id during TLS handshake. I want to know how to enable SSL session ID on application server. Using apache-tomcat for my application.
Wireshare captures
I assume you're not using the 'JSSE-Java' stack (i.e. the real one that comes builtin to 'standard' Java) because AFAICT that always sends session-id in TLS1.2 or lower ServerHello.
If you're using OpenSSL, either directly by specifying an APR 'protocol' (in all versions I've seen) or using a NIO or NIO2 'protocol' with sslImplementationName selecting OpenSSL (in at least 8.5 up) or automatically with AprLifeCycleListener (in all versions I remember), then for TLS1.2 and lower:
if session tickets are enabled and the client requests one, OpenSSL server sends no session-id and does send a ticket (later in the handshake). You can disable this with SSLHostConfig.disableSessionTickets or Connector.SSLDisableSessionTickets (in at least 8.5 up, don't remember for earlier).
without ticket(s), OpenSSL server does send session-id unless session caching is disabled, which AFAICS there is no way to do in Tomcat, so effectively always.
Note however that TLS1.3 is very different, if and when your systems move up to it. As one of many sops to broken middleboxes, RFC8446 requires (and both JSSE-Java and OpenSSL correctly implement) that all ClientHello have a random session-id value and all ServerHello echo it, even when resumption is not being done (e.g. on the first connection for a given endpoint pair), but this does not actually identify any session and will not be the same for related connections for the same pair.
This is (at least mostly) because 1.3 no longer does resumption by saving and reusing the session master secret; now it supports forward secrecy by instead optionally setting one or several resumption secret(s) one-way-derived from the current connection secret, which is(are) established and identified by NewSessionTicket message(s), and subsequently referenced and used by Pre-Shared Key (PSK) mode. And 1.3 NewSessionTicket is encrypted, so a middlebox like a (nonterminating) loadbalancer won't be able to use it.

How long is an established SSL connection valid?

Suppose I am sending "hello" to an api over ssl. My understanding is there would be a symmetric key exchange established over ssl and then the message "hello" will be encrypted using that symmetric key and sent over to the other server.
Now my question is, the next time I send a "hello 2", does the symmetric key exchange happen again? My guess would be that if it's a persistent connection, there would be no need for the key exchange again. Can someone confirm?
Meta: this doesn't appear to me to be programming, although it might be development and is mostly dupe How long does SSL connection between a client and a server persist? .
It depends on the application protocol used on top of SSL (which since 1999 is really TLS, although many things e.g. implementation classes still use the old name) and usually the implementations at both ends. For example, HTTP/1.1 defaults to connection persistence (which was often done in 1.0 as an extension called keep-alive), but either endpoint can change this by specifying connection: close, and even if the connection is kept open can choose to close it anytime later, perhaps after a minute or two, perhaps after a day or a week. The HTTPS implementation in browsers usually keeps connections open for a little while but has limits on the total connections open so those that haven't been used recently may need to be closed when others are opened. Other applications, libraries, and platforms vary. Other protocols also vary; for example an email agent using SMTPS would normally make a connection, transmit one or more emails, and then disconnect.
In addition, SSL-now-TLS through 1.2 supports session resumption, which allows the keyexchange (and other handshake results) performed on one connection to be saved (at both endpoints, or with the 'ticket' option, at client only) and reused on a new connection, for as long as the endpoint(s) agree; implementations usually call this session caching. See e.g. RFC 5246 section 7.3 specifically the part starting in the middle of page 36, and for one fairly common server (Apache) see SessionCache and SessionCacheTimeout directives. Resumption uses a new handshake but not a full keyexchange on that handshake.
However, this creates a security vulnerability if an endpoint's sesssion cache is compromised, so TLS 1.3 replaces it with a different method using dynamically created PSKs; see RFC 8446 section 2.2. This allows either a partial handshake (doing the actual keyexchange with [EC]DHE but authentication tied to the previous session by the PSK rather than full certificate-based authentication) which provides forward secrecy, or a minimal handshake (using the PSK both as the new initial secret and for authentication) which does not.
If you want an answer for specific software, and specific server(s), you need to look at the capabilities and configuration, and often also the current status, of that software and those server(s).

SSL Handshake Client_Hello version

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

Accessing RDS With SSL - Unsupported record version Unknown-0.0

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.