How long is an established SSL connection valid? - ssl

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).

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.

What is SSL context?

When programming for a SSL, no matter which language you choose (C++, Java, Ruby etc.), you probably encounter SSLContext object which would be used. I do not know what does SSLContext semantically means? When I search google for it, there just come many pages explaining the syntactical usage of such object for various programming languages.
My Question: What does SSLContext mean/do in terms of SSL? Regardless of the language which implements it.
SSL Context is a collection of ciphers, protocol versions, trusted certificates, TLS options, TLS extensions etc. Since it is very common to have multiple connections with the same settings they are put together in a context and the relevant SSL connections are then created based on this context. And to create a new connection you need only refer to the context which thus saves time and memory compared to the case you would have to re-create of all these settings.
EDIT: #EJP nicely describes this "collection" as factory. A SSL context is not the same as a SSL session even both are collections of settings. A session is what you get after the SSL handshake and covers only the cipher and protocol version both parties agreed on and also the exchanged key. Whereas the context covers all the ciphers and protocol versions and also the list of trusted certificates the local system (client or server) is willing to support when establishing a new TLS connection. Thus a SSL session describes an established SSL relation while the SSL context describes what you need to establish an SSL relation.
SSLContext: Instances of this class represent a secure socket protocol implementation which acts as a factory for secure socket factories or SSLEngines. This class is initialized with an optional set of key and trust managers and source of secure random bytes.
SSLSession: In SSL, sessions are used to describe an ongoing relationship between two entities. Each SSL connection involves one session at a time, but that session may be used on many connections between those entities, simultaneously or sequentially. The session used on a connection may also be replaced by a different session. Sessions are created, or rejoined, as part of the SSL handshaking protocol. Sessions may be invalidated due to policies affecting security or resource usage, or by an application explicitly calling invalidate. Session management policies are typically used to tune performance.
SSLSessionContext: A SSLSessionContext represents a set of SSLSessions associated with a single entity. For example, it could be associated with a server or client who participates in many sessions concurrently. An SSLSessionContext can be configured with a session timeout.

Can I detect the SSL version that a browser supports?

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.

Use OpenSSL with a custom channel

I developed (in CPP) a unique protocol over HTTP and I use it to communicate with my server.
Now, I want to establish SSL connection over my proprietary protocol to transfer the data itself.
Can I do it using OpenSSL? I searched the web and all I found is something related with BIO, but I didn't understood how to use it for my needs..
Anyway, the best solution for me will be a way I can pass OpenSSL my proprietary send & receive functions so all the communication itself will go only through my functions.
TNX ahead :)
Use BIO pairs. You can find an example in the ssltest.c program, search the source for bio_pair. The basic idea is that you treat the OpenSSL engine as a black box.
There are four things your code has to do:
When you receive encrypted data over the connection to the other side, you have to write it to the SSL engine's encrypted BIO.
When the SSL engine wants to send encrypted data to the other side, you have to read it from the SSL engine's encrypted BIO and transport it to the other side.
When you have plaintext you want to encrypt and send, you have to write it to the SSL engine's plaintext BIO.
When the SSL engine has plaintext it has decrypted for you, you have to read it from the SSL engine's plaintext BIO.
OpenSSL acts purely as an engine following the SSL protocol and moving data between the two BIOs. It does all the protocol negotiation and operations for you, so long as you keep all four of these data streams moving.
One caution I can give you is this -- do not assume any special relationship between these things. For example, you might have some plaintext you want to encrypt and send, and when you write it to the SSL engine's plaintext BIO, the SSL engine might not be able to make forward progress until it receives some encrypted data from the other side. Treat the SSL engine as a black box and do all these four things whenever possible . Do not try to "look through" the SSL engine and, for example, expect that because you handed the SSL engine some encrypted data it will have necessarily plaintext for you. It might, but it might also need to send encrypted data to the other side.
One other caution: the SSL engine has only one state. It does not have a read state and a write state. (Search this thread for "the nightmare scenario" if you want the ugly details.) This is most likely to bite you if you use an SSL connection with multiple threads and expect it to behave just like a TCP connection (where the read and write sides are independent except in the case of a fatal error or connection close).
Second option - a protocol that has its own messages and uses HTTP to
pass them between the client and the server.
If you're using HTTP to pass your own messages, using OpenSSL for SSL/TLS would imply that you'd need to write your own HTTP library library too.
Instead, use an HTTP library that supports HTTPS (most do), via OpenSSL or not. Exchanging your custom messages on top of HTTPS should be fairly transparent and similar to using plain HTTP. You'd just need to configure HTTPS normally.