Skip to content

Commit 78731b5

Browse files
committed
tls: Split context into context and buffer
1 parent b259481 commit 78731b5

File tree

6 files changed

+91
-106
lines changed

6 files changed

+91
-106
lines changed

ChangeLog

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
[next]
22

3+
* tls: Context and TLSWrappedBuffer are now entirely separated.
4+
** The contexts are now picklable.
5+
** The contexts do not support TLSWrappedBuffer API anymore.
6+
* tls: TLSSession currently *unsupported*!
37
* Update wheels to mbedtls 2.28.0 (current LTS).
48

59
[1.7.0] - 2022-03-23

README.rst

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -504,22 +504,6 @@ Content-Type: text/html
504504
<p>Successful connection.</p>
505505
<BLANKLINE>
506506

507-
Now, it is possible to cache the session before closing the client side
508-
509-
>>> from mbedtls.tls import TLSSession
510-
>>> session = TLSSession()
511-
>>> session.save(tls_cli.context)
512-
513-
and resume it later
514-
515-
>>> other_cli = session.resume(
516-
... tls.TLSConfiguration(
517-
... trust_store=trust_store,
518-
... validate_certificates=True,
519-
... )
520-
... )
521-
...
522-
523507
The last step is to stop the extra process and close the sockets.
524508

525509
>>> tls_cli.close()

src/mbedtls/_tls.pxd

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -450,8 +450,12 @@ cdef struct _C_Buffers:
450450

451451

452452
cdef class _BaseContext:
453-
cdef mbedtls_ssl_context _ctx
454453
cdef _BaseConfiguration _conf
454+
455+
456+
cdef class MbedTLSBuffer:
457+
cdef _BaseContext _context
458+
cdef mbedtls_ssl_context _ctx
455459
cdef _C_Buffers _c_buffers
456460
cpdef set_bio(self, _rb.RingBuffer input, _rb.RingBuffer output)
457461
# DTLS only:

src/mbedtls/_tls.pyx

Lines changed: 28 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1096,23 +1096,6 @@ cdef class TLSSession:
10961096
def __repr__(self):
10971097
return "%s()" % type(self).__name__
10981098

1099-
def save(self, _BaseContext context not None):
1100-
# Client only
1101-
try:
1102-
_exc.check_error(
1103-
_tls.mbedtls_ssl_get_session(&context._ctx, &self._ctx)
1104-
)
1105-
except _exc.TLSError as exc:
1106-
raise ValueError(context) from exc
1107-
1108-
def resume(self, _BaseConfiguration configuration not None):
1109-
# Client only
1110-
cdef _BaseContext client = _BaseContext(configuration)
1111-
_exc.check_error(
1112-
_tls.mbedtls_ssl_set_session(&client._ctx, &self._ctx)
1113-
)
1114-
return client
1115-
11161099

11171100
cdef class _BaseContext:
11181101
# _pep543._BaseContext
@@ -1130,9 +1113,30 @@ cdef class _BaseContext:
11301113
Purpose.CLIENT_AUTH: _tls.MBEDTLS_SSL_IS_CLIENT,
11311114
Purpose.SERVER_AUTH: _tls.MBEDTLS_SSL_IS_SERVER,
11321115
}[self._purpose])
1133-
_exc.check_error(_tls.mbedtls_ssl_setup(&self._ctx, &self._conf._ctx))
11341116

1135-
def __cinit__(self):
1117+
def __eq__(self, other):
1118+
if not isinstance(other, type(self)):
1119+
return False
1120+
if not type(self) is type(other):
1121+
return False
1122+
return self.configuration == other.configuration
1123+
1124+
@property
1125+
def configuration(self):
1126+
# PEP 543
1127+
return self._conf
1128+
1129+
@property
1130+
def _purpose(self) -> Purpose:
1131+
raise NotImplementedError
1132+
1133+
1134+
cdef class MbedTLSBuffer:
1135+
def __init__(self, _BaseContext context):
1136+
self._context = context
1137+
_exc.check_error(_tls.mbedtls_ssl_setup(&self._ctx, &self._context._conf._ctx))
1138+
1139+
def __cinit__(self, _BaseContext context):
11361140
"""Initialize an `ssl_context`."""
11371141
_tls.mbedtls_ssl_init(&self._ctx)
11381142
_tls.mbedtls_ssl_set_timer_cb(
@@ -1158,24 +1162,16 @@ cdef class _BaseContext:
11581162
def __getstate__(self):
11591163
raise TypeError(f"cannot pickle {self.__class__.__name__!r} object")
11601164

1161-
def __repr__(self):
1162-
return "%s(%r)" % (type(self).__name__, self._conf)
1163-
11641165
@property
1165-
def configuration(self):
1166-
# PEP 543
1167-
return self._conf
1168-
1169-
@property
1170-
def _purpose(self) -> Purpose:
1171-
raise NotImplementedError
1166+
def context(self):
1167+
return self._context
11721168

11731169
@property
11741170
def _verified(self):
11751171
return _tls.mbedtls_ssl_get_verify_result(&self._ctx) == 0
11761172

11771173
@property
1178-
def _hostname(self):
1174+
def _server_hostname(self):
11791175
# Client side
11801176
if self._ctx.hostname is NULL:
11811177
return None
@@ -1298,11 +1294,11 @@ cdef class _BaseContext:
12981294
return cipher[0]
12991295

13001296
@property
1301-
def _state(self):
1297+
def _handshake_state(self):
13021298
return HandshakeStep(self._ctx.state)
13031299

13041300
def do_handshake(self):
1305-
if self._state is HandshakeStep.HANDSHAKE_OVER:
1301+
if self._handshake_state is HandshakeStep.HANDSHAKE_OVER:
13061302
raise ValueError("handshake already over")
13071303
self._handle_handshake_response(_tls.mbedtls_ssl_handshake_step(&self._ctx))
13081304

src/mbedtls/tls.py

Lines changed: 35 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
DTLSVersion,
2020
HandshakeStep,
2121
HelloVerifyRequest,
22+
MbedTLSBuffer,
2223
NextProtocol,
2324
Purpose,
2425
RaggedEOF,
@@ -149,8 +150,7 @@ def wrap_socket(self, socket, server_hostname):
149150
def wrap_buffers(self, server_hostname):
150151
"""Create an in-memory stream for TLS."""
151152
# PEP 543
152-
self._set_hostname(server_hostname)
153-
return TLSWrappedBuffer(self)
153+
return TLSWrappedBuffer(self, server_hostname)
154154

155155

156156
class ServerContext(_BaseContext):
@@ -172,11 +172,12 @@ def wrap_buffers(self):
172172

173173
class TLSWrappedBuffer:
174174
# _pep543.TLSWrappedBuffer
175-
def __init__(self, context):
175+
def __init__(self, context, server_hostname=None):
176176
self._output_buffer = _rb.RingBuffer(TLS_BUFFER_CAPACITY)
177177
self._input_buffer = _rb.RingBuffer(TLS_BUFFER_CAPACITY)
178-
context.set_bio(self._output_buffer, self._input_buffer)
179-
self._context = context
178+
self._tlsbuf = MbedTLSBuffer(context)
179+
self._tlsbuf.set_bio(self._output_buffer, self._input_buffer)
180+
self._tlsbuf._set_hostname(server_hostname)
180181

181182
def __repr__(self):
182183
return "%s(%r)" % (type(self).__name__, self.context)
@@ -185,6 +186,14 @@ def __getstate__(self):
185186
# We could make this pickable by copying the buffers.
186187
raise TypeError(f"cannot pickle {self.__class__.__name__!r} object")
187188

189+
@property
190+
def _server_hostname(self):
191+
return self._tlsbuf._server_hostname
192+
193+
@property
194+
def _handshake_state(self):
195+
return self._tlsbuf._handshake_state
196+
188197
def read(self, amt):
189198
# PEP 543
190199
if amt <= 0:
@@ -198,39 +207,42 @@ def read(self, amt):
198207

199208
def readinto(self, buffer, amt):
200209
# PEP 543
201-
return self.context.readinto(buffer, amt)
210+
return self._tlsbuf.readinto(buffer, amt)
202211

203212
def write(self, buffer):
204213
# PEP 543
205-
amt = self.context.write(buffer)
214+
amt = self._tlsbuf.write(buffer)
206215
assert amt == len(buffer)
207216
return len(self._output_buffer)
208217

209218
def do_handshake(self):
210219
# PEP 543
211-
self.context.do_handshake()
220+
self._tlsbuf.do_handshake()
221+
222+
def setcookieparam(self, param):
223+
self._tlsbuf.setcookieparam(param)
212224

213225
def cipher(self):
214226
# PEP 543
215-
return self.context.cipher()
227+
return self._tlsbuf.cipher()
216228

217229
def negotiated_protocol(self):
218230
# PEP 543
219-
return self.context.negotiated_protocol()
231+
return self._tlsbuf.negotiated_protocol()
220232

221233
@property
222234
def context(self):
223235
# PEP 543
224236
"""The ``Context`` object this buffer is tied to."""
225-
return self._context
237+
return self._tlsbuf.context
226238

227239
def negotiated_tls_version(self):
228240
# PEP 543
229-
return self.context.negotiated_tls_version()
241+
return self._tlsbuf.negotiated_tls_version()
230242

231243
def shutdown(self):
232244
# PEP 543
233-
self.context.shutdown()
245+
self._tlsbuf.shutdown()
234246

235247
def receive_from_network(self, data):
236248
# PEP 543
@@ -311,7 +323,7 @@ def bind(self, address):
311323

312324
def close(self):
313325
self._closed = True
314-
self.context.shutdown()
326+
self._buffer.shutdown()
315327
self._socket.close()
316328

317329
def connect(self, address):
@@ -414,15 +426,16 @@ def setsockopt(self, level, optname, value):
414426

415427
def shutdown(self, how):
416428
self._buffer.shutdown()
417-
self._context.shutdown()
418429
self._socket.shutdown(how)
419430

420431
# PEP 543 adds the following methods.
421432

422433
def do_handshake(self):
423-
while self.context._state is not HandshakeStep.HANDSHAKE_OVER:
434+
while (
435+
self._buffer._handshake_state is not HandshakeStep.HANDSHAKE_OVER
436+
):
424437
try:
425-
self.context.do_handshake()
438+
self._buffer.do_handshake()
426439
amt = self._socket.send(self._buffer.peek_outgoing(1024))
427440
self._buffer.consume_outgoing(amt)
428441
except WantReadError:
@@ -433,22 +446,21 @@ def do_handshake(self):
433446
self._buffer.receive_from_network(data)
434447

435448
def setcookieparam(self, param):
436-
self.context.setcookieparam(param)
449+
self._buffer.setcookieparam(param)
437450

438451
def cipher(self):
439-
return self.context.cipher()
452+
return self._buffer.cipher()
440453

441454
def negotiated_protocol(self):
442-
return self.context.negotiated_protocol()
455+
return self._buffer.negotiated_protocol()
443456

444457
@property
445458
def context(self):
446-
return self._context
459+
return self._buffer.context
447460

448461
def negotiated_tls_version(self):
449-
return self.context.negotiated_tls_version()
462+
return self._buffer.negotiated_tls_version()
450463

451464
def unwrap(self):
452465
self._buffer.shutdown()
453-
self.context.shutdown()
454466
return self._socket

0 commit comments

Comments
 (0)