blob: 79734ab63d2e0f2ef3c2fa8528687a4010ebab42 [file] [log] [blame]
Victor Stinner231b4042015-01-14 00:19:09 +01001import collections
Andrew Svetlov5fb06ed2021-05-03 00:34:15 +03002import enum
Victor Stinner978a9af2015-01-29 17:50:58 +01003import warnings
Victor Stinner231b4042015-01-14 00:19:09 +01004try:
5 import ssl
6except ImportError: # pragma: no cover
7 ssl = None
8
Neil Aspinallf7686c12017-12-19 19:45:42 +00009from . import constants
Andrew Svetlov5fb06ed2021-05-03 00:34:15 +030010from . import exceptions
Victor Stinner231b4042015-01-14 00:19:09 +010011from . import protocols
12from . import transports
13from .log import logger
14
Christian Heimes37ebdf02021-05-03 09:38:56 +020015if ssl is not None:
16 SSLAgainErrors = (ssl.SSLWantReadError, ssl.SSLSyscallError)
Andrew Svetlov5fb06ed2021-05-03 00:34:15 +030017
18
19class SSLProtocolState(enum.Enum):
20 UNWRAPPED = "UNWRAPPED"
21 DO_HANDSHAKE = "DO_HANDSHAKE"
22 WRAPPED = "WRAPPED"
23 FLUSHING = "FLUSHING"
24 SHUTDOWN = "SHUTDOWN"
25
26
27class AppProtocolState(enum.Enum):
28 # This tracks the state of app protocol (https://git.io/fj59P):
29 #
30 # INIT -cm-> CON_MADE [-dr*->] [-er-> EOF?] -cl-> CON_LOST
31 #
32 # * cm: connection_made()
33 # * dr: data_received()
34 # * er: eof_received()
35 # * cl: connection_lost()
36
37 STATE_INIT = "STATE_INIT"
38 STATE_CON_MADE = "STATE_CON_MADE"
39 STATE_EOF = "STATE_EOF"
40 STATE_CON_LOST = "STATE_CON_LOST"
41
Victor Stinner231b4042015-01-14 00:19:09 +010042
43def _create_transport_context(server_side, server_hostname):
44 if server_side:
45 raise ValueError('Server side SSL needs a valid SSLContext')
46
47 # Client side may pass ssl=True to use a default
48 # context; in that case the sslcontext passed is None.
49 # The default is secure for client connections.
Andrew Svetlov51d546a2017-11-18 18:54:05 +020050 # Python 3.4+: use up-to-date strong settings.
51 sslcontext = ssl.create_default_context()
52 if not server_hostname:
53 sslcontext.check_hostname = False
Victor Stinner231b4042015-01-14 00:19:09 +010054 return sslcontext
55
56
Andrew Svetlov5fb06ed2021-05-03 00:34:15 +030057def add_flowcontrol_defaults(high, low, kb):
58 if high is None:
59 if low is None:
60 hi = kb * 1024
61 else:
62 lo = low
63 hi = 4 * lo
64 else:
65 hi = high
66 if low is None:
67 lo = hi // 4
68 else:
69 lo = low
Victor Stinner231b4042015-01-14 00:19:09 +010070
Andrew Svetlov5fb06ed2021-05-03 00:34:15 +030071 if not hi >= lo >= 0:
72 raise ValueError('high (%r) must be >= low (%r) must be >= 0' %
73 (hi, lo))
Victor Stinner231b4042015-01-14 00:19:09 +010074
Andrew Svetlov5fb06ed2021-05-03 00:34:15 +030075 return hi, lo
Victor Stinner231b4042015-01-14 00:19:09 +010076
77
78class _SSLProtocolTransport(transports._FlowControlMixin,
79 transports.Transport):
80
Andrew Svetlov5fb06ed2021-05-03 00:34:15 +030081 _start_tls_compatible = True
Andrew Svetlov7c684072018-01-27 21:22:47 +020082 _sendfile_compatible = constants._SendfileMode.FALLBACK
83
jlacolineea2ef5d2017-10-19 19:49:57 +020084 def __init__(self, loop, ssl_protocol):
Victor Stinner231b4042015-01-14 00:19:09 +010085 self._loop = loop
86 self._ssl_protocol = ssl_protocol
Victor Stinner978a9af2015-01-29 17:50:58 +010087 self._closed = False
Victor Stinner231b4042015-01-14 00:19:09 +010088
89 def get_extra_info(self, name, default=None):
90 """Get optional transport information."""
91 return self._ssl_protocol._get_extra_info(name, default)
92
Yury Selivanova05a6ef2016-09-11 21:11:02 -040093 def set_protocol(self, protocol):
Yury Selivanov21790222018-05-29 05:02:40 -040094 self._ssl_protocol._set_app_protocol(protocol)
Yury Selivanova05a6ef2016-09-11 21:11:02 -040095
96 def get_protocol(self):
jlacolineea2ef5d2017-10-19 19:49:57 +020097 return self._ssl_protocol._app_protocol
Yury Selivanova05a6ef2016-09-11 21:11:02 -040098
Yury Selivanov5bb1afb2015-11-16 12:43:21 -050099 def is_closing(self):
100 return self._closed
101
Victor Stinner231b4042015-01-14 00:19:09 +0100102 def close(self):
103 """Close the transport.
104
105 Buffered data will be flushed asynchronously. No more data
106 will be received. After all buffered data is flushed, the
107 protocol's connection_lost() method will (eventually) called
108 with None as its argument.
109 """
Victor Stinner978a9af2015-01-29 17:50:58 +0100110 self._closed = True
Victor Stinner231b4042015-01-14 00:19:09 +0100111 self._ssl_protocol._start_shutdown()
112
Andrew Svetlov5fb06ed2021-05-03 00:34:15 +0300113 def __del__(self, _warnings=warnings):
INADA Naoki3e2ad8e2017-04-25 10:57:18 +0900114 if not self._closed:
Andrew Svetlov5fb06ed2021-05-03 00:34:15 +0300115 self._closed = True
116 _warnings.warn(
117 "unclosed transport <asyncio._SSLProtocolTransport "
118 "object>", ResourceWarning)
Victor Stinner978a9af2015-01-29 17:50:58 +0100119
Yury Selivanovd757aaf2017-12-18 17:03:23 -0500120 def is_reading(self):
Andrew Svetlov5fb06ed2021-05-03 00:34:15 +0300121 return not self._ssl_protocol._app_reading_paused
Yury Selivanovd757aaf2017-12-18 17:03:23 -0500122
Victor Stinner231b4042015-01-14 00:19:09 +0100123 def pause_reading(self):
124 """Pause the receiving end.
125
126 No data will be passed to the protocol's data_received()
127 method until resume_reading() is called.
128 """
Andrew Svetlov5fb06ed2021-05-03 00:34:15 +0300129 self._ssl_protocol._pause_reading()
Victor Stinner231b4042015-01-14 00:19:09 +0100130
131 def resume_reading(self):
132 """Resume the receiving end.
133
134 Data received will once again be passed to the protocol's
135 data_received() method.
136 """
Andrew Svetlov5fb06ed2021-05-03 00:34:15 +0300137 self._ssl_protocol._resume_reading()
Victor Stinner231b4042015-01-14 00:19:09 +0100138
139 def set_write_buffer_limits(self, high=None, low=None):
140 """Set the high- and low-water limits for write flow control.
141
142 These two values control when to call the protocol's
143 pause_writing() and resume_writing() methods. If specified,
144 the low-water limit must be less than or equal to the
145 high-water limit. Neither value can be negative.
146
147 The defaults are implementation-specific. If only the
Serhiy Storchakad65c9492015-11-02 14:10:23 +0200148 high-water limit is given, the low-water limit defaults to an
Victor Stinner231b4042015-01-14 00:19:09 +0100149 implementation-specific value less than or equal to the
150 high-water limit. Setting high to zero forces low to zero as
151 well, and causes pause_writing() to be called whenever the
152 buffer becomes non-empty. Setting low to zero causes
153 resume_writing() to be called only once the buffer is empty.
154 Use of zero for either limit is generally sub-optimal as it
155 reduces opportunities for doing I/O and computation
156 concurrently.
157 """
Andrew Svetlov5fb06ed2021-05-03 00:34:15 +0300158 self._ssl_protocol._set_write_buffer_limits(high, low)
159 self._ssl_protocol._control_app_writing()
160
161 def get_write_buffer_limits(self):
162 return (self._ssl_protocol._outgoing_low_water,
163 self._ssl_protocol._outgoing_high_water)
Victor Stinner231b4042015-01-14 00:19:09 +0100164
165 def get_write_buffer_size(self):
Andrew Svetlov5fb06ed2021-05-03 00:34:15 +0300166 """Return the current size of the write buffers."""
167 return self._ssl_protocol._get_write_buffer_size()
168
169 def set_read_buffer_limits(self, high=None, low=None):
170 """Set the high- and low-water limits for read flow control.
171
172 These two values control when to call the upstream transport's
173 pause_reading() and resume_reading() methods. If specified,
174 the low-water limit must be less than or equal to the
175 high-water limit. Neither value can be negative.
176
177 The defaults are implementation-specific. If only the
178 high-water limit is given, the low-water limit defaults to an
179 implementation-specific value less than or equal to the
180 high-water limit. Setting high to zero forces low to zero as
181 well, and causes pause_reading() to be called whenever the
182 buffer becomes non-empty. Setting low to zero causes
183 resume_reading() to be called only once the buffer is empty.
184 Use of zero for either limit is generally sub-optimal as it
185 reduces opportunities for doing I/O and computation
186 concurrently.
187 """
188 self._ssl_protocol._set_read_buffer_limits(high, low)
189 self._ssl_protocol._control_ssl_reading()
190
191 def get_read_buffer_limits(self):
192 return (self._ssl_protocol._incoming_low_water,
193 self._ssl_protocol._incoming_high_water)
194
195 def get_read_buffer_size(self):
196 """Return the current size of the read buffer."""
197 return self._ssl_protocol._get_read_buffer_size()
Victor Stinner231b4042015-01-14 00:19:09 +0100198
Andrew Svetlov7c684072018-01-27 21:22:47 +0200199 @property
200 def _protocol_paused(self):
201 # Required for sendfile fallback pause_writing/resume_writing logic
Andrew Svetlov5fb06ed2021-05-03 00:34:15 +0300202 return self._ssl_protocol._app_writing_paused
Andrew Svetlov7c684072018-01-27 21:22:47 +0200203
Victor Stinner231b4042015-01-14 00:19:09 +0100204 def write(self, data):
205 """Write some data bytes to the transport.
206
207 This does not block; it buffers the data and arranges for it
208 to be sent out asynchronously.
209 """
210 if not isinstance(data, (bytes, bytearray, memoryview)):
Yury Selivanov6370f342017-12-10 18:36:12 -0500211 raise TypeError(f"data: expecting a bytes-like instance, "
212 f"got {type(data).__name__}")
Victor Stinner231b4042015-01-14 00:19:09 +0100213 if not data:
214 return
Andrew Svetlov5fb06ed2021-05-03 00:34:15 +0300215 self._ssl_protocol._write_appdata((data,))
216
217 def writelines(self, list_of_data):
218 """Write a list (or any iterable) of data bytes to the transport.
219
220 The default implementation concatenates the arguments and
221 calls write() on the result.
222 """
223 self._ssl_protocol._write_appdata(list_of_data)
224
225 def write_eof(self):
226 """Close the write end after flushing buffered data.
227
228 This raises :exc:`NotImplementedError` right now.
229 """
230 raise NotImplementedError
Victor Stinner231b4042015-01-14 00:19:09 +0100231
232 def can_write_eof(self):
233 """Return True if this transport supports write_eof(), False if not."""
234 return False
235
236 def abort(self):
237 """Close the transport immediately.
238
239 Buffered data will be lost. No more data will be received.
240 The protocol's connection_lost() method will (eventually) be
241 called with None as its argument.
242 """
Yury Selivanov415bc462018-06-05 08:59:58 -0400243 self._closed = True
Andrew Svetlov5fb06ed2021-05-03 00:34:15 +0300244 self._ssl_protocol._abort()
245
246 def _force_close(self, exc):
247 self._closed = True
248 self._ssl_protocol._abort(exc)
249
250 def _test__append_write_backlog(self, data):
251 # for test only
252 self._ssl_protocol._write_backlog.append(data)
253 self._ssl_protocol._write_buffer_size += len(data)
Victor Stinner231b4042015-01-14 00:19:09 +0100254
255
Andrew Svetlov5fb06ed2021-05-03 00:34:15 +0300256class SSLProtocol(protocols.BufferedProtocol):
257 max_size = 256 * 1024 # Buffer size passed to read()
Victor Stinner231b4042015-01-14 00:19:09 +0100258
Andrew Svetlov5fb06ed2021-05-03 00:34:15 +0300259 _handshake_start_time = None
260 _handshake_timeout_handle = None
261 _shutdown_timeout_handle = None
Victor Stinner231b4042015-01-14 00:19:09 +0100262
263 def __init__(self, loop, app_protocol, sslcontext, waiter,
Yury Selivanov92e7c7f2016-10-05 19:39:54 -0400264 server_side=False, server_hostname=None,
Neil Aspinallf7686c12017-12-19 19:45:42 +0000265 call_connection_made=True,
Andrew Svetlov5fb06ed2021-05-03 00:34:15 +0300266 ssl_handshake_timeout=None,
267 ssl_shutdown_timeout=None):
Victor Stinner231b4042015-01-14 00:19:09 +0100268 if ssl is None:
Andrew Svetlov5fb06ed2021-05-03 00:34:15 +0300269 raise RuntimeError("stdlib ssl module not available")
270
271 self._ssl_buffer = bytearray(self.max_size)
272 self._ssl_buffer_view = memoryview(self._ssl_buffer)
Victor Stinner231b4042015-01-14 00:19:09 +0100273
Andrew Svetlov51eb1c62017-12-20 20:24:43 +0200274 if ssl_handshake_timeout is None:
275 ssl_handshake_timeout = constants.SSL_HANDSHAKE_TIMEOUT
276 elif ssl_handshake_timeout <= 0:
277 raise ValueError(
278 f"ssl_handshake_timeout should be a positive number, "
279 f"got {ssl_handshake_timeout}")
Andrew Svetlov5fb06ed2021-05-03 00:34:15 +0300280 if ssl_shutdown_timeout is None:
281 ssl_shutdown_timeout = constants.SSL_SHUTDOWN_TIMEOUT
282 elif ssl_shutdown_timeout <= 0:
283 raise ValueError(
284 f"ssl_shutdown_timeout should be a positive number, "
285 f"got {ssl_shutdown_timeout}")
Andrew Svetlov51eb1c62017-12-20 20:24:43 +0200286
Victor Stinner231b4042015-01-14 00:19:09 +0100287 if not sslcontext:
Yury Selivanov6370f342017-12-10 18:36:12 -0500288 sslcontext = _create_transport_context(
289 server_side, server_hostname)
Victor Stinner231b4042015-01-14 00:19:09 +0100290
291 self._server_side = server_side
292 if server_hostname and not server_side:
293 self._server_hostname = server_hostname
294 else:
295 self._server_hostname = None
296 self._sslcontext = sslcontext
297 # SSL-specific extra info. More info are set when the handshake
298 # completes.
299 self._extra = dict(sslcontext=sslcontext)
300
301 # App data write buffering
302 self._write_backlog = collections.deque()
303 self._write_buffer_size = 0
304
305 self._waiter = waiter
Victor Stinner231b4042015-01-14 00:19:09 +0100306 self._loop = loop
Yury Selivanov21790222018-05-29 05:02:40 -0400307 self._set_app_protocol(app_protocol)
Andrew Svetlov5fb06ed2021-05-03 00:34:15 +0300308 self._app_transport = None
309 self._app_transport_created = False
Victor Stinnerf7dc7fb2015-09-21 18:06:17 +0200310 # transport, ex: SelectorSocketTransport
Victor Stinner7e222f42015-01-15 13:16:27 +0100311 self._transport = None
Neil Aspinallf7686c12017-12-19 19:45:42 +0000312 self._ssl_handshake_timeout = ssl_handshake_timeout
Andrew Svetlov5fb06ed2021-05-03 00:34:15 +0300313 self._ssl_shutdown_timeout = ssl_shutdown_timeout
314 # SSL and state machine
315 self._incoming = ssl.MemoryBIO()
316 self._outgoing = ssl.MemoryBIO()
317 self._state = SSLProtocolState.UNWRAPPED
318 self._conn_lost = 0 # Set when connection_lost called
319 if call_connection_made:
320 self._app_state = AppProtocolState.STATE_INIT
321 else:
322 self._app_state = AppProtocolState.STATE_CON_MADE
323 self._sslobj = self._sslcontext.wrap_bio(
324 self._incoming, self._outgoing,
325 server_side=self._server_side,
326 server_hostname=self._server_hostname)
327
328 # Flow Control
329
330 self._ssl_writing_paused = False
331
332 self._app_reading_paused = False
333
334 self._ssl_reading_paused = False
335 self._incoming_high_water = 0
336 self._incoming_low_water = 0
337 self._set_read_buffer_limits()
338 self._eof_received = False
339
340 self._app_writing_paused = False
341 self._outgoing_high_water = 0
342 self._outgoing_low_water = 0
343 self._set_write_buffer_limits()
344 self._get_app_transport()
Victor Stinner231b4042015-01-14 00:19:09 +0100345
Yury Selivanov21790222018-05-29 05:02:40 -0400346 def _set_app_protocol(self, app_protocol):
347 self._app_protocol = app_protocol
Andrew Svetlov5fb06ed2021-05-03 00:34:15 +0300348 # Make fast hasattr check first
349 if (hasattr(app_protocol, 'get_buffer') and
350 isinstance(app_protocol, protocols.BufferedProtocol)):
351 self._app_protocol_get_buffer = app_protocol.get_buffer
352 self._app_protocol_buffer_updated = app_protocol.buffer_updated
353 self._app_protocol_is_buffer = True
354 else:
355 self._app_protocol_is_buffer = False
Yury Selivanov21790222018-05-29 05:02:40 -0400356
Victor Stinnerf07801b2015-01-29 00:36:35 +0100357 def _wakeup_waiter(self, exc=None):
358 if self._waiter is None:
359 return
360 if not self._waiter.cancelled():
361 if exc is not None:
362 self._waiter.set_exception(exc)
363 else:
364 self._waiter.set_result(None)
365 self._waiter = None
366
Andrew Svetlov5fb06ed2021-05-03 00:34:15 +0300367 def _get_app_transport(self):
368 if self._app_transport is None:
369 if self._app_transport_created:
370 raise RuntimeError('Creating _SSLProtocolTransport twice')
371 self._app_transport = _SSLProtocolTransport(self._loop, self)
372 self._app_transport_created = True
373 return self._app_transport
374
Victor Stinner231b4042015-01-14 00:19:09 +0100375 def connection_made(self, transport):
376 """Called when the low-level connection is made.
377
378 Start the SSL handshake.
379 """
380 self._transport = transport
Victor Stinner231b4042015-01-14 00:19:09 +0100381 self._start_handshake()
382
383 def connection_lost(self, exc):
384 """Called when the low-level connection is lost or closed.
385
386 The argument is an exception object or None (the latter
387 meaning a regular EOF is received or the connection was
388 aborted or closed).
389 """
Andrew Svetlov5fb06ed2021-05-03 00:34:15 +0300390 self._write_backlog.clear()
391 self._outgoing.read()
392 self._conn_lost += 1
393
394 # Just mark the app transport as closed so that its __dealloc__
395 # doesn't complain.
396 if self._app_transport is not None:
397 self._app_transport._closed = True
398
399 if self._state != SSLProtocolState.DO_HANDSHAKE:
400 if (
401 self._app_state == AppProtocolState.STATE_CON_MADE or
402 self._app_state == AppProtocolState.STATE_EOF
403 ):
404 self._app_state = AppProtocolState.STATE_CON_LOST
405 self._loop.call_soon(self._app_protocol.connection_lost, exc)
406 self._set_state(SSLProtocolState.UNWRAPPED)
Victor Stinner231b4042015-01-14 00:19:09 +0100407 self._transport = None
408 self._app_transport = None
Fantix Kingf683f462019-03-17 17:51:10 -0500409 self._app_protocol = None
Andrew Svetlov5fb06ed2021-05-03 00:34:15 +0300410 self._wakeup_waiter(exc)
Victor Stinner231b4042015-01-14 00:19:09 +0100411
Andrew Svetlov5fb06ed2021-05-03 00:34:15 +0300412 if self._shutdown_timeout_handle:
413 self._shutdown_timeout_handle.cancel()
414 self._shutdown_timeout_handle = None
415 if self._handshake_timeout_handle:
416 self._handshake_timeout_handle.cancel()
417 self._handshake_timeout_handle = None
Victor Stinner231b4042015-01-14 00:19:09 +0100418
Andrew Svetlov5fb06ed2021-05-03 00:34:15 +0300419 def get_buffer(self, n):
420 want = n
421 if want <= 0 or want > self.max_size:
422 want = self.max_size
423 if len(self._ssl_buffer) < want:
424 self._ssl_buffer = bytearray(want)
425 self._ssl_buffer_view = memoryview(self._ssl_buffer)
426 return self._ssl_buffer_view
Victor Stinner231b4042015-01-14 00:19:09 +0100427
Andrew Svetlov5fb06ed2021-05-03 00:34:15 +0300428 def buffer_updated(self, nbytes):
429 self._incoming.write(self._ssl_buffer_view[:nbytes])
Victor Stinner231b4042015-01-14 00:19:09 +0100430
Andrew Svetlov5fb06ed2021-05-03 00:34:15 +0300431 if self._state == SSLProtocolState.DO_HANDSHAKE:
432 self._do_handshake()
Andrew Svetlov5e80a712018-03-10 17:48:35 +0200433
Andrew Svetlov5fb06ed2021-05-03 00:34:15 +0300434 elif self._state == SSLProtocolState.WRAPPED:
435 self._do_read()
Victor Stinner231b4042015-01-14 00:19:09 +0100436
Andrew Svetlov5fb06ed2021-05-03 00:34:15 +0300437 elif self._state == SSLProtocolState.FLUSHING:
438 self._do_flush()
Victor Stinner231b4042015-01-14 00:19:09 +0100439
Andrew Svetlov5fb06ed2021-05-03 00:34:15 +0300440 elif self._state == SSLProtocolState.SHUTDOWN:
441 self._do_shutdown()
Victor Stinner231b4042015-01-14 00:19:09 +0100442
443 def eof_received(self):
444 """Called when the other end of the low-level stream
445 is half-closed.
446
447 If this returns a false value (including None), the transport
448 will close itself. If it returns a true value, closing the
449 transport is up to the protocol.
450 """
Andrew Svetlov5fb06ed2021-05-03 00:34:15 +0300451 self._eof_received = True
Victor Stinner231b4042015-01-14 00:19:09 +0100452 try:
453 if self._loop.get_debug():
454 logger.debug("%r received EOF", self)
Victor Stinnerb507cba2015-01-29 00:35:56 +0100455
Andrew Svetlov5fb06ed2021-05-03 00:34:15 +0300456 if self._state == SSLProtocolState.DO_HANDSHAKE:
457 self._on_handshake_complete(ConnectionResetError)
Victor Stinnerb507cba2015-01-29 00:35:56 +0100458
Andrew Svetlov5fb06ed2021-05-03 00:34:15 +0300459 elif self._state == SSLProtocolState.WRAPPED:
460 self._set_state(SSLProtocolState.FLUSHING)
461 if self._app_reading_paused:
462 return True
463 else:
464 self._do_flush()
465
466 elif self._state == SSLProtocolState.FLUSHING:
467 self._do_write()
468 self._set_state(SSLProtocolState.SHUTDOWN)
469 self._do_shutdown()
470
471 elif self._state == SSLProtocolState.SHUTDOWN:
472 self._do_shutdown()
473
474 except Exception:
Victor Stinner231b4042015-01-14 00:19:09 +0100475 self._transport.close()
Andrew Svetlov5fb06ed2021-05-03 00:34:15 +0300476 raise
Victor Stinner231b4042015-01-14 00:19:09 +0100477
478 def _get_extra_info(self, name, default=None):
479 if name in self._extra:
480 return self._extra[name]
Nikolay Kim2b27e2e2017-03-12 12:23:30 -0700481 elif self._transport is not None:
Victor Stinner231b4042015-01-14 00:19:09 +0100482 return self._transport.get_extra_info(name, default)
Nikolay Kim2b27e2e2017-03-12 12:23:30 -0700483 else:
484 return default
Victor Stinner231b4042015-01-14 00:19:09 +0100485
Andrew Svetlov5fb06ed2021-05-03 00:34:15 +0300486 def _set_state(self, new_state):
487 allowed = False
Victor Stinner231b4042015-01-14 00:19:09 +0100488
Andrew Svetlov5fb06ed2021-05-03 00:34:15 +0300489 if new_state == SSLProtocolState.UNWRAPPED:
490 allowed = True
491
492 elif (
493 self._state == SSLProtocolState.UNWRAPPED and
494 new_state == SSLProtocolState.DO_HANDSHAKE
495 ):
496 allowed = True
497
498 elif (
499 self._state == SSLProtocolState.DO_HANDSHAKE and
500 new_state == SSLProtocolState.WRAPPED
501 ):
502 allowed = True
503
504 elif (
505 self._state == SSLProtocolState.WRAPPED and
506 new_state == SSLProtocolState.FLUSHING
507 ):
508 allowed = True
509
510 elif (
511 self._state == SSLProtocolState.FLUSHING and
512 new_state == SSLProtocolState.SHUTDOWN
513 ):
514 allowed = True
515
516 if allowed:
517 self._state = new_state
518
519 else:
520 raise RuntimeError(
521 'cannot switch state from {} to {}'.format(
522 self._state, new_state))
523
524 # Handshake flow
Victor Stinner231b4042015-01-14 00:19:09 +0100525
526 def _start_handshake(self):
527 if self._loop.get_debug():
528 logger.debug("%r starts SSL handshake", self)
529 self._handshake_start_time = self._loop.time()
530 else:
531 self._handshake_start_time = None
Andrew Svetlov5fb06ed2021-05-03 00:34:15 +0300532
533 self._set_state(SSLProtocolState.DO_HANDSHAKE)
534
535 # start handshake timeout count down
Neil Aspinallf7686c12017-12-19 19:45:42 +0000536 self._handshake_timeout_handle = \
537 self._loop.call_later(self._ssl_handshake_timeout,
Andrew Svetlov5fb06ed2021-05-03 00:34:15 +0300538 lambda: self._check_handshake_timeout())
539
540 self._do_handshake()
Neil Aspinallf7686c12017-12-19 19:45:42 +0000541
542 def _check_handshake_timeout(self):
Andrew Svetlov5fb06ed2021-05-03 00:34:15 +0300543 if self._state == SSLProtocolState.DO_HANDSHAKE:
Yury Selivanov96026432018-06-04 11:32:35 -0400544 msg = (
545 f"SSL handshake is taking longer than "
546 f"{self._ssl_handshake_timeout} seconds: "
547 f"aborting the connection"
548 )
549 self._fatal_error(ConnectionAbortedError(msg))
Victor Stinner231b4042015-01-14 00:19:09 +0100550
Andrew Svetlov5fb06ed2021-05-03 00:34:15 +0300551 def _do_handshake(self):
Victor Stinner231b4042015-01-14 00:19:09 +0100552 try:
Andrew Svetlov5fb06ed2021-05-03 00:34:15 +0300553 self._sslobj.do_handshake()
554 except SSLAgainErrors:
555 self._process_outgoing()
556 except ssl.SSLError as exc:
557 self._on_handshake_complete(exc)
558 else:
559 self._on_handshake_complete(None)
560
561 def _on_handshake_complete(self, handshake_exc):
562 if self._handshake_timeout_handle is not None:
563 self._handshake_timeout_handle.cancel()
564 self._handshake_timeout_handle = None
565
566 sslobj = self._sslobj
567 try:
568 if handshake_exc is None:
569 self._set_state(SSLProtocolState.WRAPPED)
570 else:
Victor Stinner231b4042015-01-14 00:19:09 +0100571 raise handshake_exc
Victor Stinner177e9f02015-01-14 16:56:20 +0100572
573 peercert = sslobj.getpeercert()
Andrew Svetlov5fb06ed2021-05-03 00:34:15 +0300574 except Exception as exc:
575 self._set_state(SSLProtocolState.UNWRAPPED)
Yury Selivanov96026432018-06-04 11:32:35 -0400576 if isinstance(exc, ssl.CertificateError):
577 msg = 'SSL handshake failed on verifying the certificate'
Victor Stinner231b4042015-01-14 00:19:09 +0100578 else:
Yury Selivanov96026432018-06-04 11:32:35 -0400579 msg = 'SSL handshake failed'
580 self._fatal_error(exc, msg)
Andrew Svetlov5fb06ed2021-05-03 00:34:15 +0300581 self._wakeup_waiter(exc)
Yury Selivanov96026432018-06-04 11:32:35 -0400582 return
Victor Stinner231b4042015-01-14 00:19:09 +0100583
584 if self._loop.get_debug():
585 dt = self._loop.time() - self._handshake_start_time
586 logger.debug("%r: SSL handshake took %.1f ms", self, dt * 1e3)
587
588 # Add extra info that becomes available after handshake.
589 self._extra.update(peercert=peercert,
590 cipher=sslobj.cipher(),
591 compression=sslobj.compression(),
Andrew Svetlov5fb06ed2021-05-03 00:34:15 +0300592 ssl_object=sslobj)
593 if self._app_state == AppProtocolState.STATE_INIT:
594 self._app_state = AppProtocolState.STATE_CON_MADE
595 self._app_protocol.connection_made(self._get_app_transport())
Victor Stinnerf07801b2015-01-29 00:36:35 +0100596 self._wakeup_waiter()
Andrew Svetlov5fb06ed2021-05-03 00:34:15 +0300597 self._do_read()
Victor Stinner231b4042015-01-14 00:19:09 +0100598
Andrew Svetlov5fb06ed2021-05-03 00:34:15 +0300599 # Shutdown flow
600
601 def _start_shutdown(self):
602 if (
603 self._state in (
604 SSLProtocolState.FLUSHING,
605 SSLProtocolState.SHUTDOWN,
606 SSLProtocolState.UNWRAPPED
607 )
608 ):
609 return
610 if self._app_transport is not None:
611 self._app_transport._closed = True
612 if self._state == SSLProtocolState.DO_HANDSHAKE:
613 self._abort()
614 else:
615 self._set_state(SSLProtocolState.FLUSHING)
616 self._shutdown_timeout_handle = self._loop.call_later(
617 self._ssl_shutdown_timeout,
618 lambda: self._check_shutdown_timeout()
619 )
620 self._do_flush()
621
622 def _check_shutdown_timeout(self):
623 if (
624 self._state in (
625 SSLProtocolState.FLUSHING,
626 SSLProtocolState.SHUTDOWN
627 )
628 ):
629 self._transport._force_close(
630 exceptions.TimeoutError('SSL shutdown timed out'))
631
632 def _do_flush(self):
633 self._do_read()
634 self._set_state(SSLProtocolState.SHUTDOWN)
635 self._do_shutdown()
636
637 def _do_shutdown(self):
638 try:
639 if not self._eof_received:
640 self._sslobj.unwrap()
641 except SSLAgainErrors:
642 self._process_outgoing()
643 except ssl.SSLError as exc:
644 self._on_shutdown_complete(exc)
645 else:
646 self._process_outgoing()
647 self._call_eof_received()
648 self._on_shutdown_complete(None)
649
650 def _on_shutdown_complete(self, shutdown_exc):
651 if self._shutdown_timeout_handle is not None:
652 self._shutdown_timeout_handle.cancel()
653 self._shutdown_timeout_handle = None
654
655 if shutdown_exc:
656 self._fatal_error(shutdown_exc)
657 else:
658 self._loop.call_soon(self._transport.close)
659
660 def _abort(self):
661 self._set_state(SSLProtocolState.UNWRAPPED)
662 if self._transport is not None:
663 self._transport.abort()
664
665 # Outgoing flow
666
667 def _write_appdata(self, list_of_data):
668 if (
669 self._state in (
670 SSLProtocolState.FLUSHING,
671 SSLProtocolState.SHUTDOWN,
672 SSLProtocolState.UNWRAPPED
673 )
674 ):
675 if self._conn_lost >= constants.LOG_THRESHOLD_FOR_CONNLOST_WRITES:
676 logger.warning('SSL connection is closed')
677 self._conn_lost += 1
Victor Stinner231b4042015-01-14 00:19:09 +0100678 return
679
Andrew Svetlov5fb06ed2021-05-03 00:34:15 +0300680 for data in list_of_data:
681 self._write_backlog.append(data)
682 self._write_buffer_size += len(data)
683
Victor Stinner231b4042015-01-14 00:19:09 +0100684 try:
Andrew Svetlov5fb06ed2021-05-03 00:34:15 +0300685 if self._state == SSLProtocolState.WRAPPED:
686 self._do_write()
687
688 except Exception as ex:
689 self._fatal_error(ex, 'Fatal error on SSL protocol')
690
691 def _do_write(self):
692 try:
693 while self._write_backlog:
694 data = self._write_backlog[0]
695 count = self._sslobj.write(data)
696 data_len = len(data)
697 if count < data_len:
698 self._write_backlog[0] = data[count:]
699 self._write_buffer_size -= count
Victor Stinner231b4042015-01-14 00:19:09 +0100700 else:
Andrew Svetlov5fb06ed2021-05-03 00:34:15 +0300701 del self._write_backlog[0]
702 self._write_buffer_size -= data_len
703 except SSLAgainErrors:
704 pass
705 self._process_outgoing()
Victor Stinner231b4042015-01-14 00:19:09 +0100706
Andrew Svetlov5fb06ed2021-05-03 00:34:15 +0300707 def _process_outgoing(self):
708 if not self._ssl_writing_paused:
709 data = self._outgoing.read()
710 if len(data):
711 self._transport.write(data)
712 self._control_app_writing()
Victor Stinner231b4042015-01-14 00:19:09 +0100713
Andrew Svetlov5fb06ed2021-05-03 00:34:15 +0300714 # Incoming flow
715
716 def _do_read(self):
717 if (
718 self._state not in (
719 SSLProtocolState.WRAPPED,
720 SSLProtocolState.FLUSHING,
721 )
722 ):
723 return
724 try:
725 if not self._app_reading_paused:
726 if self._app_protocol_is_buffer:
727 self._do_read__buffered()
728 else:
729 self._do_read__copied()
730 if self._write_backlog:
731 self._do_write()
732 else:
733 self._process_outgoing()
734 self._control_ssl_reading()
735 except Exception as ex:
736 self._fatal_error(ex, 'Fatal error on SSL protocol')
737
738 def _do_read__buffered(self):
739 offset = 0
740 count = 1
741
742 buf = self._app_protocol_get_buffer(self._get_read_buffer_size())
743 wants = len(buf)
744
745 try:
746 count = self._sslobj.read(wants, buf)
747
748 if count > 0:
749 offset = count
750 while offset < wants:
751 count = self._sslobj.read(wants - offset, buf[offset:])
752 if count > 0:
753 offset += count
754 else:
755 break
756 else:
757 self._loop.call_soon(lambda: self._do_read())
758 except SSLAgainErrors:
759 pass
760 if offset > 0:
761 self._app_protocol_buffer_updated(offset)
762 if not count:
763 # close_notify
764 self._call_eof_received()
765 self._start_shutdown()
766
767 def _do_read__copied(self):
768 chunk = b'1'
769 zero = True
770 one = False
771
772 try:
773 while True:
774 chunk = self._sslobj.read(self.max_size)
775 if not chunk:
Victor Stinner231b4042015-01-14 00:19:09 +0100776 break
Andrew Svetlov5fb06ed2021-05-03 00:34:15 +0300777 if zero:
778 zero = False
779 one = True
780 first = chunk
781 elif one:
782 one = False
783 data = [first, chunk]
784 else:
785 data.append(chunk)
786 except SSLAgainErrors:
787 pass
788 if one:
789 self._app_protocol.data_received(first)
790 elif not zero:
791 self._app_protocol.data_received(b''.join(data))
792 if not chunk:
793 # close_notify
794 self._call_eof_received()
795 self._start_shutdown()
Victor Stinner231b4042015-01-14 00:19:09 +0100796
Andrew Svetlov5fb06ed2021-05-03 00:34:15 +0300797 def _call_eof_received(self):
798 try:
799 if self._app_state == AppProtocolState.STATE_CON_MADE:
800 self._app_state = AppProtocolState.STATE_EOF
801 keep_open = self._app_protocol.eof_received()
802 if keep_open:
803 logger.warning('returning true from eof_received() '
804 'has no effect when using ssl')
805 except (KeyboardInterrupt, SystemExit):
Yury Selivanov431b5402019-05-27 14:45:12 +0200806 raise
Andrew Svetlov5fb06ed2021-05-03 00:34:15 +0300807 except BaseException as ex:
808 self._fatal_error(ex, 'Error calling eof_received()')
809
810 # Flow control for writes from APP socket
811
812 def _control_app_writing(self):
813 size = self._get_write_buffer_size()
814 if size >= self._outgoing_high_water and not self._app_writing_paused:
815 self._app_writing_paused = True
816 try:
817 self._app_protocol.pause_writing()
818 except (KeyboardInterrupt, SystemExit):
819 raise
820 except BaseException as exc:
821 self._loop.call_exception_handler({
822 'message': 'protocol.pause_writing() failed',
823 'exception': exc,
824 'transport': self._app_transport,
825 'protocol': self,
826 })
827 elif size <= self._outgoing_low_water and self._app_writing_paused:
828 self._app_writing_paused = False
829 try:
830 self._app_protocol.resume_writing()
831 except (KeyboardInterrupt, SystemExit):
832 raise
833 except BaseException as exc:
834 self._loop.call_exception_handler({
835 'message': 'protocol.resume_writing() failed',
836 'exception': exc,
837 'transport': self._app_transport,
838 'protocol': self,
839 })
840
841 def _get_write_buffer_size(self):
842 return self._outgoing.pending + self._write_buffer_size
843
844 def _set_write_buffer_limits(self, high=None, low=None):
845 high, low = add_flowcontrol_defaults(
846 high, low, constants.FLOW_CONTROL_HIGH_WATER_SSL_WRITE)
847 self._outgoing_high_water = high
848 self._outgoing_low_water = low
849
850 # Flow control for reads to APP socket
851
852 def _pause_reading(self):
853 self._app_reading_paused = True
854
855 def _resume_reading(self):
856 if self._app_reading_paused:
857 self._app_reading_paused = False
858
859 def resume():
860 if self._state == SSLProtocolState.WRAPPED:
861 self._do_read()
862 elif self._state == SSLProtocolState.FLUSHING:
863 self._do_flush()
864 elif self._state == SSLProtocolState.SHUTDOWN:
865 self._do_shutdown()
866 self._loop.call_soon(resume)
867
868 # Flow control for reads from SSL socket
869
870 def _control_ssl_reading(self):
871 size = self._get_read_buffer_size()
872 if size >= self._incoming_high_water and not self._ssl_reading_paused:
873 self._ssl_reading_paused = True
874 self._transport.pause_reading()
875 elif size <= self._incoming_low_water and self._ssl_reading_paused:
876 self._ssl_reading_paused = False
877 self._transport.resume_reading()
878
879 def _set_read_buffer_limits(self, high=None, low=None):
880 high, low = add_flowcontrol_defaults(
881 high, low, constants.FLOW_CONTROL_HIGH_WATER_SSL_READ)
882 self._incoming_high_water = high
883 self._incoming_low_water = low
884
885 def _get_read_buffer_size(self):
886 return self._incoming.pending
887
888 # Flow control for writes to SSL socket
889
890 def pause_writing(self):
891 """Called when the low-level transport's buffer goes over
892 the high-water mark.
893 """
894 assert not self._ssl_writing_paused
895 self._ssl_writing_paused = True
896
897 def resume_writing(self):
898 """Called when the low-level transport's buffer drains below
899 the low-water mark.
900 """
901 assert self._ssl_writing_paused
902 self._ssl_writing_paused = False
903 self._process_outgoing()
Victor Stinner231b4042015-01-14 00:19:09 +0100904
905 def _fatal_error(self, exc, message='Fatal error on transport'):
Andrew Svetlov5fb06ed2021-05-03 00:34:15 +0300906 if self._transport:
907 self._transport._force_close(exc)
908
Andrew Svetlov1f39c282019-05-27 16:28:34 +0300909 if isinstance(exc, OSError):
Victor Stinner231b4042015-01-14 00:19:09 +0100910 if self._loop.get_debug():
911 logger.debug("%r: %s", self, message, exc_info=True)
Andrew Svetlov5fb06ed2021-05-03 00:34:15 +0300912 elif not isinstance(exc, exceptions.CancelledError):
Victor Stinner231b4042015-01-14 00:19:09 +0100913 self._loop.call_exception_handler({
914 'message': message,
915 'exception': exc,
916 'transport': self._transport,
917 'protocol': self,
918 })