-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
PEP 748: tlslib - context & socket #4960
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
539e879
791d34e
506c877
92016be
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -351,7 +351,15 @@ The ``ClientContext`` protocol class has the following class definition: | |
| ... | ||
|
|
||
| @abstractmethod | ||
| def connect(self, address: tuple[str | None, int]) -> TLSSocket: | ||
| def create_connection( | ||
| self, | ||
| address: tuple[str | None, bytes | str | int | None], | ||
| timeout: float | None = ..., | ||
| source_address: _Address | None = None, | ||
| *, | ||
| all_errors: bool = False, | ||
| sever_hostname: str | None = None, | ||
| ) -> TLSSocket: | ||
| """Creates a TLSSocket that behaves like a socket.socket, and | ||
| contains information about the TLS exchange | ||
| (cipher, negotiated_protocol, negotiated_tls_version, etc.). | ||
|
|
@@ -365,7 +373,45 @@ The ``ClientContext`` protocol class has the following class definition: | |
| (cipher, negotiated_protocol, negotiated_tls_version, etc.).""" | ||
| ... | ||
|
|
||
| The ``ServerContext`` is similar, taking a ``TLSServerConfiguration`` instead. | ||
| The ``ServerContext`` protocol class has the following class definition: | ||
|
|
||
| .. code-block:: python | ||
|
|
||
| class ServerContext(Protocol): | ||
| @abstractmethod | ||
| def __init__(self, configuration: TLSServerConfiguration) -> None: | ||
| """Create a new server context object from a given TLS server configuration.""" | ||
| ... | ||
|
|
||
| @property | ||
| @abstractmethod | ||
| def configuration(self) -> TLSServerConfiguration: | ||
| """Returns the TLS server configuration that was used to create the server context.""" | ||
| ... | ||
|
|
||
| @abstractmethod | ||
| def create_server( | ||
| self, | ||
| address: _Address, | ||
| *, | ||
| family: int = socket.AF_INET, | ||
| backlog: int | None = None, | ||
| reuse_port: bool = False, | ||
| dualstack_ipv6: bool = False, | ||
| ) -> TLSSocket: | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we want stronger typing for the TLS sockets? Both 'listening sockets' and 'connected sockets' are still the same type.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I decided to implement them using stronger types in siotls, but IMO we need not to enforce it in the spec. |
||
| """Creates a listening socket with an accept() function that returns | ||
| a TLSSocket that behaves like a socket.socket, and contains | ||
| information about the TLS exchange | ||
| (cipher, negotiated_protocol, negotiated_tls_version, etc.). | ||
| """ | ||
| ... | ||
|
|
||
| @abstractmethod | ||
| def create_buffer(self) -> TLSBuffer: | ||
| """Creates a TLSBuffer that acts as an in-memory channel, | ||
| and contains information about the TLS exchange | ||
| (cipher, negotiated_protocol, negotiated_tls_version, etc.).""" | ||
| ... | ||
|
|
||
| Socket | ||
| ~~~~~~ | ||
|
|
@@ -375,8 +421,8 @@ specification of the ``TLSSocket`` protocol class. Specifically, implementations | |
| need to implement the following: | ||
|
|
||
| * ``recv`` and ``send`` | ||
| * ``listen`` and ``accept`` | ||
| * ``close`` | ||
| * ``accept`` (server-side) | ||
| * ``shutdown`` and ``close`` | ||
| * ``getsockname`` | ||
| * ``getpeername`` | ||
|
|
||
|
|
@@ -392,6 +438,12 @@ The following code describes these functions in more detail: | |
|
|
||
| .. code-block:: python | ||
|
|
||
| class TLSShutdownMode(enum.IntEnum): | ||
| SHUT_RD = 0 | ||
| SHUT_WR = 1 | ||
| SHUT_RDWR = 2 | ||
|
|
||
|
|
||
| class TLSSocket(Protocol): | ||
| """This class implements a socket.socket-like object that creates an OS | ||
| socket, wraps it in an SSL context, and provides read and write methods | ||
|
|
@@ -418,22 +470,41 @@ The following code describes these functions in more detail: | |
| ... | ||
|
|
||
| @abstractmethod | ||
| def close(self, force: bool = False) -> None: | ||
| """Shuts down the connection and mark the socket closed. | ||
| If force is True, this method should send the close_notify alert and shut down | ||
| the socket without waiting for the other side. | ||
| If force is False, this method should send the close_notify alert and raise | ||
| the WantReadError exception until a corresponding close_notify alert has been | ||
| received from the other side. | ||
| In either case, this method should return WantWriteError if sending the | ||
| close_notify alert currently fails.""" | ||
| def shutdown(self, how: TLSShutdownMode) -> None: | ||
| """ | ||
| Shutdown TLS and the underlying socket. | ||
|
|
||
| * ``SHUT_RD`` (``0``) unilateraly close the receiving-side: discard | ||
| present and future unread messages. | ||
| * ``SHUT_WR`` (``1``) gracefully close the sending-side: send a | ||
| closing alert and prevent sending more messages. | ||
| * ``SHUT_RDWR`` (``2``): both ``SHUT_WR`` and ``SHUT_RD``. | ||
|
|
||
| .. danger:: | ||
|
|
||
| Both ``shutdown(SHUT_RD)`` and ``shutdown(SHUT_RDWR)`` pose a | ||
| risk of data loss: they are unsafe unless the connection is | ||
| otherwise known to be over or when truncation is not an issue. | ||
|
|
||
| In TLS 1.2, the same risk applies also to ``shutdown(SHUT_WR)``. | ||
| """ | ||
| ... | ||
|
|
||
| @abstractmethod | ||
| def listen(self, backlog: int) -> None: | ||
| """Enable a server to accept connections. If backlog is specified, it | ||
| specifies the number of unaccepted connections that the system will allow | ||
| before refusing new connections.""" | ||
| def close(self) -> None: | ||
| """ | ||
| Close the underlying socket, but only when it is safe to do so. | ||
|
|
||
| When the sending-side of the connection is still open, it gracefully | ||
| closes the TLS sending-side before closing the socket, raising | ||
| ``WantWriteError`` when it fails. | ||
|
|
||
| When the receiving-side of the connection is still open, it always | ||
| raises ``WantReadError`` as there's a risk of data loss / truncation | ||
| attack. The user must first either: (safe) ``recv`` until the peer | ||
| closes its sending-side of the connection, or (unsafe) take the risk | ||
| and unilateraly ``shutdown`` the receiving-side of the connection. | ||
| """ | ||
| ... | ||
|
|
||
| @abstractmethod | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.