2

I have a simple TLS client in python that connects to TLS servers. I do not have control over the servers. I need a fresh TLS handshake with each server even if I visited it recently.

1) Do non-browser TLS clients such as the following python client perform session resumption by default?

2) How can I know if they do or do not? How can I disable session resumption if it is performed in the background?

Please note that I create a new socket for each new domain that I connect to.

import socket, ssl

context = ssl.SSLContext() 
context.verify_mode = ssl.CERT_NONE 
context.check_hostname = False 

mycipher = "DHE-RSA-AES128-SHA"
context.set_ciphers(mycipher) 
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
domain = "google.com"
mySocket = context.wrap_socket(sock, server_hostname = domain) 
mySocket.connect((domain, 443))
mySocket.close()
user9371654
  • 2,160
  • 16
  • 45
  • 78

3 Answers3

2

This is a difficult but interesting question. And you did use the appropriate term TLS which brings me joy ;-)

First, see that session resumption has changed in TLS1.3, so this may impact things in the future for you (at least the naming, pre TLS1.3 this feature speaks more about sessions and tickets while TLS1.3 prefers to speak about a pre shared key): https://timtaubert.de/blog/2017/02/the-future-of-session-resumption/

Now about your questions:

1) Do non-browser TLS clients such as the following python client perform session resumption by default?

  1. Python documentation at https://docs.python.org/3.7/library/ssl.html does not say anything about "resumption"; I would posit if it says nothing about it it is not doing it at all. But it does speak up about "cache" which could be a synonym.
  2. In fact you can note at https://docs.python.org/3.7/library/ssl.html#ssl.SSLSession that the session has the following attributes: ticket_lifetime_hint and has_ticket; this should be related to resumption.
  3. Now look at https://docs.python.org/3.7/library/ssl.html#ssl.SSLContext.options and if you browse all possible values, you get:

    ssl.OP_NO_TICKET Prevent client side from requesting a session ticket.

  4. So my assumption in 1) may be wrong and you have session resumption by default. You should disable it using the above option

  5. (On the contrary) it seems to exist in PyOpenSSL (vs just stock ssl) because there is even one question here on how to disable this feature for that library: How to disable session resumption in pyOpenSSL?

  6. Empirically you could try to discover that by running your application in such a way that it connects twice in close time to same endpoint and see what kind of TLS messages are exchanged. For example in TLS 1.3 (should be similar with other versions, but some name may change), a fresh handshake starts with ClientHello/ServerHello where a resumption starts with the same messages but with a pre_shared_key extension. Its presence will show TLS resumption. In TLS 1.2 the client would send a SessionTicketextension during resumption handshake.

2) How can I know if they do or do not? How can I disable session resumption if it is performed in the background?

  1. If I am right about the above, make sure to use ssl.OP_NO_TICKET in ths SSL context object. Otherwise it is OP_ALL by default which is a bag of various options designed to maximize interoperability but the content may change depending on your Python version and the underlying OpenSSL library used.
  2. If your session has the has_ticket attribute filled I guess it uses TLS resumption or is set up to use it.
Patrick Mevzek
  • 10,995
  • 16
  • 38
  • 54
  • Thanks. Just one more thing. If the client changed its ciphersuites using `set_ciphers`. i.e., the client made a first handshake to the server using a ciphersuit, then the client changed its ciphersuite using `set_ciphers`, then, the client made a 2nd handshake to the same server (just after the 1st one). Can session resumption still be used? does changing the cipher by the client enforces new fresh handshake? It is a bit tricky for me to be sure so I will appreciate your help. – user9371654 Aug 02 '18 at 03:39
  • and I'm talking about TLS 1.2. – user9371654 Aug 02 '18 at 03:40
  • Can you please check my question [here](https://stackoverflow.com/questions/51672803/how-to-change-a-tls-context-option) – user9371654 Aug 03 '18 at 12:44
  • From where did you get the impression you could change ciphers on the fly? It is true that the message is called ChangeCipherSpec but this is just exchanged at beginning of handshake, not in-flight. See in TLS1.2: *The ChangeCipherSpec message is sent during the handshake after the security parameters have been agreed upon, but before the verifying Finished message is sent.*. – Patrick Mevzek Aug 04 '18 at 02:39
  • Thank you very much for your help. Can you please check my follow-up question [here](https://stackoverflow.com/questions/51684190/how-to-enable-a-disabled-cipher-by-default-in-openssl-1-1-0g)? – user9371654 Aug 04 '18 at 09:21
0

1) Do non-browser TLS clients such as the following python client perform session resumption by default?

By default the python tls/ssl libraries do not perform session resumption.

2) How can I know if they do or do not? How can I disable session resumption if it is performed in the background?

You can verify that session resumption has not happened with the following code:

import socket
import ssl

hostname = 'www.stackoverflow.com'
context = ssl.create_default_context()

# Create a new socket, then create a secure socket
sock = socket.create_connection((hostname, 443))
ssock = context.wrap_socket(sock, server_hostname=hostname)

# Was the TLS Session re-used?
print(ssock.session_reused) # False
Patrick
  • 141
  • 1
  • 5
0

TLS session resumption can be enabled by using last ssl session.

hostname = 'google.com'
port = 443
resource = '/'

context = ssl.SSLContext(ssl.PROTOCOL_TLS)

sock = socket.create_connection((hostname, port))
ssock = context.wrap_socket(sock, server_hostname=hostname)

#send - receive

ssr = ssock.session
print(ssock.session_reused) # False
ssock.close()

# Connecting Again
# Here we're using the previous session ssr in wrap_socket()

sock = socket.create_connection((hostname, port))
ssock = context.wrap_socket(sock, server_hostname=hostname, session=ssr)

#send - receive

print(ssock.session_reused) # True if server supports session resumption otherwise False

ssock.close()
Al Mamun
  • 944
  • 9
  • 27