7 from dnsdisttests
import DNSDistTest
13 class DNSDistTLSSessionResumptionTest(DNSDistTest
):
15 _consoleKey
= DNSDistTest
.generateConsoleKey()
16 _consoleKeyB64
= base64
.b64encode(_consoleKey
).decode('ascii')
19 def checkSessionResumed(cls
, addr
, port
, serverName
, caFile
, ticketFileOut
, ticketFileIn
):
20 # we force TLS 1.3 because the session file gets updated when an existing ticket encrypted with an older key gets re-encrypted with the active key
21 # whereas in TLS 1.2 the existing ticket is written instead..
22 testcmd
= ['openssl', 's_client', '-tls1_3', '-CAfile', caFile
, '-connect', '%s:%d' % (addr
, port
), '-servername', serverName
, '-sess_out', ticketFileOut
]
23 if ticketFileIn
and os
.path
.exists(ticketFileIn
):
24 testcmd
= testcmd
+ ['-sess_in', ticketFileIn
]
28 process
= subprocess
.Popen(testcmd
, stdout
=subprocess
.PIPE
, stdin
=subprocess
.PIPE
, stderr
=subprocess
.STDOUT
, close_fds
=True)
29 # we need to wait just a bit so that the Post-Handshake New Session Ticket has the time to arrive..
31 output
= process
.communicate(input=b
'')
32 except subprocess
.CalledProcessError
as exc
:
33 raise AssertionError('dnsdist --check-config failed (%d): %s' % (exc
.returncode
, exc
.output
))
35 for line
in output
[0].decode().splitlines():
36 if line
.startswith('Reused, TLSv1.'):
42 def generateTicketKeysFile(numberOfTickets
, outputFile
):
43 with
open(outputFile
, 'wb') as fp
:
44 fp
.write(os
.urandom(numberOfTickets
* 80))
46 class TestNoTLSSessionResumptionDOH(DNSDistTLSSessionResumptionTest
):
48 _serverKey
= 'server.key'
49 _serverCert
= 'server.chain'
50 _serverName
= 'tls.tests.dnsdist.org'
54 _config_template
= """
55 newServer{address="127.0.0.1:%s"}
57 addDOHLocal("127.0.0.1:%s", "%s", "%s", { "/" }, { numberOfTicketsKeys=%d, numberOfStoredSessions=0, sessionTickets=false })
59 _config_params
= ['_testServerPort', '_dohServerPort', '_serverCert', '_serverKey', '_numberOfKeys']
61 def testNoSessionResumption(self
):
63 Session Resumption: DoH (disabled)
65 self
.assertFalse(self
.checkSessionResumed('127.0.0.1', self
._dohServerPort
, self
._serverName
, self
._caCert
, '/tmp/session.out', None))
66 self
.assertFalse(self
.checkSessionResumed('127.0.0.1', self
._dohServerPort
, self
._serverName
, self
._caCert
, '/tmp/session.out', '/tmp/session.out'))
68 class TestTLSSessionResumptionDOH(DNSDistTLSSessionResumptionTest
):
70 _serverKey
= 'server.key'
71 _serverCert
= 'server.chain'
72 _serverName
= 'tls.tests.dnsdist.org'
76 _config_template
= """
78 controlSocket("127.0.0.1:%s")
79 newServer{address="127.0.0.1:%s"}
81 addDOHLocal("127.0.0.1:%s", "%s", "%s", { "/" }, { numberOfTicketsKeys=%d })
83 _config_params
= ['_consoleKeyB64', '_consolePort', '_testServerPort', '_dohServerPort', '_serverCert', '_serverKey', '_numberOfKeys']
85 def testSessionResumption(self
):
87 Session Resumption: DoH
89 self
.assertFalse(self
.checkSessionResumed('127.0.0.1', self
._dohServerPort
, self
._serverName
, self
._caCert
, '/tmp/session', None))
90 self
.assertTrue(self
.checkSessionResumed('127.0.0.1', self
._dohServerPort
, self
._serverName
, self
._caCert
, '/tmp/session', '/tmp/session'))
92 # rotate the TLS session ticket keys several times, but keep the previously active one around so we can resume
93 for _
in range(self
._numberOfKeys
- 1):
94 self
.sendConsoleCommand("getDOHFrontend(0):rotateTicketsKey()")
96 # the session should be resumed and a new ticket, encrypted with the newly active key, should be stored
97 self
.assertTrue(self
.checkSessionResumed('127.0.0.1', self
._dohServerPort
, self
._serverName
, self
._caCert
, '/tmp/session', '/tmp/session'))
99 # rotate the TLS session ticket keys several times, but keep the previously active one around so we can resume
100 for _
in range(self
._numberOfKeys
- 1):
101 self
.sendConsoleCommand("getDOHFrontend(0):rotateTicketsKey()")
103 self
.assertTrue(self
.checkSessionResumed('127.0.0.1', self
._dohServerPort
, self
._serverName
, self
._caCert
, '/tmp/session', '/tmp/session'))
105 # rotate the TLS session ticket keys several times, not keeping any key around this time!
106 for _
in range(self
._numberOfKeys
):
107 self
.sendConsoleCommand("getDOHFrontend(0):rotateTicketsKey()")
109 # we should not be able to resume
110 self
.assertFalse(self
.checkSessionResumed('127.0.0.1', self
._dohServerPort
, self
._serverName
, self
._caCert
, '/tmp/session', '/tmp/session'))
112 # generate a file containing _numberOfKeys ticket keys
113 self
.generateTicketKeysFile(self
._numberOfKeys
, '/tmp/ticketKeys.1')
114 self
.generateTicketKeysFile(self
._numberOfKeys
- 1, '/tmp/ticketKeys.2')
115 # load all ticket keys from the file
116 self
.sendConsoleCommand("getDOHFrontend(0):loadTicketsKeys('/tmp/ticketKeys.1')")
118 # create a new session, resume it
119 self
.assertFalse(self
.checkSessionResumed('127.0.0.1', self
._dohServerPort
, self
._serverName
, self
._caCert
, '/tmp/session', None))
120 self
.assertTrue(self
.checkSessionResumed('127.0.0.1', self
._dohServerPort
, self
._serverName
, self
._caCert
, '/tmp/session', '/tmp/session'))
122 # reload the same keys
123 self
.sendConsoleCommand("getDOHFrontend(0):loadTicketsKeys('/tmp/ticketKeys.1')")
125 # should still be able to resume
126 self
.assertTrue(self
.checkSessionResumed('127.0.0.1', self
._dohServerPort
, self
._serverName
, self
._caCert
, '/tmp/session', '/tmp/session'))
128 # rotate the TLS session ticket keys several times, but keep the previously active one around so we can resume
129 for _
in range(self
._numberOfKeys
- 1):
130 self
.sendConsoleCommand("getDOHFrontend(0):rotateTicketsKey()")
131 # should still be able to resume
132 self
.assertTrue(self
.checkSessionResumed('127.0.0.1', self
._dohServerPort
, self
._serverName
, self
._caCert
, '/tmp/session', '/tmp/session'))
134 # reload the same keys
135 self
.sendConsoleCommand("getDOHFrontend(0):loadTicketsKeys('/tmp/ticketKeys.1')")
136 # since the last key was only present in memory, we should not be able to resume
137 self
.assertFalse(self
.checkSessionResumed('127.0.0.1', self
._dohServerPort
, self
._serverName
, self
._caCert
, '/tmp/session', '/tmp/session'))
140 self
.assertTrue(self
.checkSessionResumed('127.0.0.1', self
._dohServerPort
, self
._serverName
, self
._caCert
, '/tmp/session', '/tmp/session'))
142 # generate a file with only _numberOfKeys - 1 keys, so the last active one should still be around after loading that one
143 self
.generateTicketKeysFile(self
._numberOfKeys
- 1, '/tmp/ticketKeys.2')
144 self
.sendConsoleCommand("getDOHFrontend(0):loadTicketsKeys('/tmp/ticketKeys.2')")
145 # we should be able to resume, and the ticket should be re-encrypted with the new key (NOTE THAT we store into a new file!!)
146 self
.assertTrue(self
.checkSessionResumed('127.0.0.1', self
._dohServerPort
, self
._serverName
, self
._caCert
, '/tmp/session.2', '/tmp/session'))
147 self
.assertTrue(self
.checkSessionResumed('127.0.0.1', self
._dohServerPort
, self
._serverName
, self
._caCert
, '/tmp/session.2', '/tmp/session.2'))
149 # rotate all keys, we should not be able to resume
150 for _
in range(self
._numberOfKeys
):
151 self
.sendConsoleCommand("getDOHFrontend(0):rotateTicketsKey()")
152 self
.assertFalse(self
.checkSessionResumed('127.0.0.1', self
._dohServerPort
, self
._serverName
, self
._caCert
, '/tmp/session.3', '/tmp/session.2'))
154 # reload from file 1, the old session should resume
155 self
.sendConsoleCommand("getDOHFrontend(0):loadTicketsKeys('/tmp/ticketKeys.1')")
156 self
.assertTrue(self
.checkSessionResumed('127.0.0.1', self
._dohServerPort
, self
._serverName
, self
._caCert
, '/tmp/session', '/tmp/session'))
158 # reload from file 2, the latest session should resume
159 self
.sendConsoleCommand("getDOHFrontend(0):loadTicketsKeys('/tmp/ticketKeys.2')")
160 self
.assertTrue(self
.checkSessionResumed('127.0.0.1', self
._dohServerPort
, self
._serverName
, self
._caCert
, '/tmp/session.2', '/tmp/session.2'))
162 class TestNoTLSSessionResumptionDOT(DNSDistTLSSessionResumptionTest
):
164 _serverKey
= 'server.key'
165 _serverCert
= 'server.chain'
166 _serverName
= 'tls.tests.dnsdist.org'
168 _tlsServerPort
= 8443
170 _config_template
= """
171 newServer{address="127.0.0.1:%s"}
173 addTLSLocal("127.0.0.1:%s", "%s", "%s", { numberOfTicketsKeys=%d, numberOfStoredSessions=0, sessionTickets=false })
175 _config_params
= ['_testServerPort', '_tlsServerPort', '_serverCert', '_serverKey', '_numberOfKeys']
177 def testNoSessionResumption(self
):
179 Session Resumption: DoT (disabled)
181 self
.assertFalse(self
.checkSessionResumed('127.0.0.1', self
._tlsServerPort
, self
._serverName
, self
._caCert
, '/tmp/session.out', None))
182 self
.assertFalse(self
.checkSessionResumed('127.0.0.1', self
._tlsServerPort
, self
._serverName
, self
._caCert
, '/tmp/session.out', '/tmp/session.out'))
184 class TestTLSSessionResumptionDOT(DNSDistTLSSessionResumptionTest
):
186 _serverKey
= 'server.key'
187 _serverCert
= 'server.chain'
188 _serverName
= 'tls.tests.dnsdist.org'
190 _tlsServerPort
= 8443
192 _config_template
= """
194 controlSocket("127.0.0.1:%s")
195 newServer{address="127.0.0.1:%s"}
197 addTLSLocal("127.0.0.1:%s", "%s", "%s", { provider="openssl", numberOfTicketsKeys=%d })
199 _config_params
= ['_consoleKeyB64', '_consolePort', '_testServerPort', '_tlsServerPort', '_serverCert', '_serverKey', '_numberOfKeys']
201 def testSessionResumption(self
):
203 Session Resumption: DoT
205 self
.assertFalse(self
.checkSessionResumed('127.0.0.1', self
._tlsServerPort
, self
._serverName
, self
._caCert
, '/tmp/session', None))
206 self
.assertTrue(self
.checkSessionResumed('127.0.0.1', self
._tlsServerPort
, self
._serverName
, self
._caCert
, '/tmp/session', '/tmp/session'))
208 # rotate the TLS session ticket keys several times, but keep the previously active one around so we can resume
209 for _
in range(self
._numberOfKeys
- 1):
210 self
.sendConsoleCommand("getTLSContext(0):rotateTicketsKey()")
212 # the session should be resumed and a new ticket, encrypted with the newly active key, should be stored
213 self
.assertTrue(self
.checkSessionResumed('127.0.0.1', self
._tlsServerPort
, self
._serverName
, self
._caCert
, '/tmp/session', '/tmp/session'))
215 # rotate the TLS session ticket keys several times, but keep the previously active one around so we can resume
216 for _
in range(self
._numberOfKeys
- 1):
217 self
.sendConsoleCommand("getTLSContext(0):rotateTicketsKey()")
219 self
.assertTrue(self
.checkSessionResumed('127.0.0.1', self
._tlsServerPort
, self
._serverName
, self
._caCert
, '/tmp/session', '/tmp/session'))
221 # rotate the TLS session ticket keys several times, not keeping any key around this time!
222 for _
in range(self
._numberOfKeys
):
223 self
.sendConsoleCommand("getTLSContext(0):rotateTicketsKey()")
225 # we should not be able to resume
226 self
.assertFalse(self
.checkSessionResumed('127.0.0.1', self
._tlsServerPort
, self
._serverName
, self
._caCert
, '/tmp/session', '/tmp/session'))
228 # generate a file containing _numberOfKeys ticket keys
229 self
.generateTicketKeysFile(self
._numberOfKeys
, '/tmp/ticketKeys.1')
230 self
.generateTicketKeysFile(self
._numberOfKeys
- 1, '/tmp/ticketKeys.2')
231 # load all ticket keys from the file
232 self
.sendConsoleCommand("getTLSContext(0):loadTicketsKeys('/tmp/ticketKeys.1')")
234 # create a new session, resume it
235 self
.assertFalse(self
.checkSessionResumed('127.0.0.1', self
._tlsServerPort
, self
._serverName
, self
._caCert
, '/tmp/session', None))
236 self
.assertTrue(self
.checkSessionResumed('127.0.0.1', self
._tlsServerPort
, self
._serverName
, self
._caCert
, '/tmp/session', '/tmp/session'))
238 # reload the same keys
239 self
.sendConsoleCommand("getTLSContext(0):loadTicketsKeys('/tmp/ticketKeys.1')")
241 # should still be able to resume
242 self
.assertTrue(self
.checkSessionResumed('127.0.0.1', self
._tlsServerPort
, self
._serverName
, self
._caCert
, '/tmp/session', '/tmp/session'))
244 # rotate the TLS session ticket keys several times, but keep the previously active one around so we can resume
245 for _
in range(self
._numberOfKeys
- 1):
246 self
.sendConsoleCommand("getTLSContext(0):rotateTicketsKey()")
247 # should still be able to resume
248 self
.assertTrue(self
.checkSessionResumed('127.0.0.1', self
._tlsServerPort
, self
._serverName
, self
._caCert
, '/tmp/session', '/tmp/session'))
250 # reload the same keys
251 self
.sendConsoleCommand("getTLSContext(0):loadTicketsKeys('/tmp/ticketKeys.1')")
252 # since the last key was only present in memory, we should not be able to resume
253 self
.assertFalse(self
.checkSessionResumed('127.0.0.1', self
._tlsServerPort
, self
._serverName
, self
._caCert
, '/tmp/session', '/tmp/session'))
256 self
.assertTrue(self
.checkSessionResumed('127.0.0.1', self
._tlsServerPort
, self
._serverName
, self
._caCert
, '/tmp/session', '/tmp/session'))
258 # generate a file with only _numberOfKeys - 1 keys, so the last active one should still be around after loading that one
259 self
.generateTicketKeysFile(self
._numberOfKeys
- 1, '/tmp/ticketKeys.2')
260 self
.sendConsoleCommand("getTLSContext(0):loadTicketsKeys('/tmp/ticketKeys.2')")
261 # we should be able to resume, and the ticket should be re-encrypted with the new key (NOTE THAT we store into a new file!!)
262 self
.assertTrue(self
.checkSessionResumed('127.0.0.1', self
._tlsServerPort
, self
._serverName
, self
._caCert
, '/tmp/session.2', '/tmp/session'))
263 self
.assertTrue(self
.checkSessionResumed('127.0.0.1', self
._tlsServerPort
, self
._serverName
, self
._caCert
, '/tmp/session.2', '/tmp/session.2'))
265 # rotate all keys, we should not be able to resume
266 for _
in range(self
._numberOfKeys
):
267 self
.sendConsoleCommand("getTLSContext(0):rotateTicketsKey()")
268 self
.assertFalse(self
.checkSessionResumed('127.0.0.1', self
._tlsServerPort
, self
._serverName
, self
._caCert
, '/tmp/session.3', '/tmp/session.2'))
270 # reload from file 1, the old session should resume
271 self
.sendConsoleCommand("getTLSContext(0):loadTicketsKeys('/tmp/ticketKeys.1')")
272 self
.assertTrue(self
.checkSessionResumed('127.0.0.1', self
._tlsServerPort
, self
._serverName
, self
._caCert
, '/tmp/session', '/tmp/session'))
274 # reload from file 2, the latest session should resume
275 self
.sendConsoleCommand("getTLSContext(0):loadTicketsKeys('/tmp/ticketKeys.2')")
276 self
.assertTrue(self
.checkSessionResumed('127.0.0.1', self
._tlsServerPort
, self
._serverName
, self
._caCert
, '/tmp/session.2', '/tmp/session.2'))