bpo-24334: Cleanup SSLSocket (#5252)

* The SSLSocket is no longer implemented on top of SSLObject to
  avoid an extra level of indirection.
* Owner and session are now handled in the internal constructor.
* _ssl._SSLSocket now uses the same method names as SSLSocket and
  SSLObject.
* Channel binding type check is now handled in C code. Channel binding
  is always available.

The patch also changes the signature of SSLObject.__init__(). In my
opinion it's fine. A SSLObject is not a user-constructable object.
SSLContext.wrap_bio() is the only valid factory.
This commit is contained in:
Christian Heimes 2018-02-24 21:10:57 +01:00 committed by GitHub
parent b18f8bc1a7
commit 141c5e8c24
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 183 additions and 117 deletions

View File

@ -166,10 +166,7 @@ import warnings
socket_error = OSError # keep that public name in module namespace socket_error = OSError # keep that public name in module namespace
if _ssl.HAS_TLS_UNIQUE: CHANNEL_BINDING_TYPES = ['tls-unique']
CHANNEL_BINDING_TYPES = ['tls-unique']
else:
CHANNEL_BINDING_TYPES = []
HAS_NEVER_CHECK_COMMON_NAME = hasattr(_ssl, 'HOSTFLAG_NEVER_CHECK_SUBJECT') HAS_NEVER_CHECK_COMMON_NAME = hasattr(_ssl, 'HOSTFLAG_NEVER_CHECK_SUBJECT')
@ -407,11 +404,11 @@ class SSLContext(_SSLContext):
server_hostname=None, session=None): server_hostname=None, session=None):
# Need to encode server_hostname here because _wrap_bio() can only # Need to encode server_hostname here because _wrap_bio() can only
# handle ASCII str. # handle ASCII str.
sslobj = self._wrap_bio( return self.sslobject_class(
incoming, outgoing, server_side=server_side, incoming, outgoing, server_side=server_side,
server_hostname=self._encode_hostname(server_hostname) server_hostname=self._encode_hostname(server_hostname),
session=session, _context=self,
) )
return self.sslobject_class(sslobj, session=session)
def set_npn_protocols(self, npn_protocols): def set_npn_protocols(self, npn_protocols):
protos = bytearray() protos = bytearray()
@ -616,12 +613,13 @@ class SSLObject:
* The ``do_handshake_on_connect`` and ``suppress_ragged_eofs`` machinery. * The ``do_handshake_on_connect`` and ``suppress_ragged_eofs`` machinery.
""" """
def __init__(self, sslobj, owner=None, session=None): def __init__(self, incoming, outgoing, server_side=False,
self._sslobj = sslobj server_hostname=None, session=None, _context=None):
# Note: _sslobj takes a weak reference to owner self._sslobj = _context._wrap_bio(
self._sslobj.owner = owner or self incoming, outgoing, server_side=server_side,
if session is not None: server_hostname=server_hostname,
self._sslobj.session = session owner=self, session=session
)
@property @property
def context(self): def context(self):
@ -684,7 +682,7 @@ class SSLObject:
Return None if no certificate was provided, {} if a certificate was Return None if no certificate was provided, {} if a certificate was
provided, but not validated. provided, but not validated.
""" """
return self._sslobj.peer_certificate(binary_form) return self._sslobj.getpeercert(binary_form)
def selected_npn_protocol(self): def selected_npn_protocol(self):
"""Return the currently selected NPN protocol as a string, or ``None`` """Return the currently selected NPN protocol as a string, or ``None``
@ -732,13 +730,7 @@ class SSLObject:
"""Get channel binding data for current connection. Raise ValueError """Get channel binding data for current connection. Raise ValueError
if the requested `cb_type` is not supported. Return bytes of the data if the requested `cb_type` is not supported. Return bytes of the data
or None if the data is not available (e.g. before the handshake).""" or None if the data is not available (e.g. before the handshake)."""
if cb_type not in CHANNEL_BINDING_TYPES: return self._sslobj.get_channel_binding(cb_type)
raise ValueError("Unsupported channel binding type")
if cb_type != "tls-unique":
raise NotImplementedError(
"{0} channel binding type not implemented"
.format(cb_type))
return self._sslobj.tls_unique_cb()
def version(self): def version(self):
"""Return a string identifying the protocol version used by the """Return a string identifying the protocol version used by the
@ -832,10 +824,10 @@ class SSLSocket(socket):
if connected: if connected:
# create the SSL object # create the SSL object
try: try:
sslobj = self._context._wrap_socket(self, server_side, self._sslobj = self._context._wrap_socket(
self.server_hostname) self, server_side, self.server_hostname,
self._sslobj = SSLObject(sslobj, owner=self, owner=self, session=self._session,
session=self._session) )
if do_handshake_on_connect: if do_handshake_on_connect:
timeout = self.gettimeout() timeout = self.gettimeout()
if timeout == 0.0: if timeout == 0.0:
@ -895,10 +887,13 @@ class SSLSocket(socket):
Return zero-length string on EOF.""" Return zero-length string on EOF."""
self._checkClosed() self._checkClosed()
if not self._sslobj: if self._sslobj is None:
raise ValueError("Read on closed or unwrapped SSL socket.") raise ValueError("Read on closed or unwrapped SSL socket.")
try: try:
if buffer is not None:
return self._sslobj.read(len, buffer) return self._sslobj.read(len, buffer)
else:
return self._sslobj.read(len)
except SSLError as x: except SSLError as x:
if x.args[0] == SSL_ERROR_EOF and self.suppress_ragged_eofs: if x.args[0] == SSL_ERROR_EOF and self.suppress_ragged_eofs:
if buffer is not None: if buffer is not None:
@ -913,7 +908,7 @@ class SSLSocket(socket):
number of bytes of DATA actually transmitted.""" number of bytes of DATA actually transmitted."""
self._checkClosed() self._checkClosed()
if not self._sslobj: if self._sslobj is None:
raise ValueError("Write on closed or unwrapped SSL socket.") raise ValueError("Write on closed or unwrapped SSL socket.")
return self._sslobj.write(data) return self._sslobj.write(data)
@ -929,41 +924,42 @@ class SSLSocket(socket):
def selected_npn_protocol(self): def selected_npn_protocol(self):
self._checkClosed() self._checkClosed()
if not self._sslobj or not _ssl.HAS_NPN: if self._sslobj is None or not _ssl.HAS_NPN:
return None return None
else: else:
return self._sslobj.selected_npn_protocol() return self._sslobj.selected_npn_protocol()
def selected_alpn_protocol(self): def selected_alpn_protocol(self):
self._checkClosed() self._checkClosed()
if not self._sslobj or not _ssl.HAS_ALPN: if self._sslobj is None or not _ssl.HAS_ALPN:
return None return None
else: else:
return self._sslobj.selected_alpn_protocol() return self._sslobj.selected_alpn_protocol()
def cipher(self): def cipher(self):
self._checkClosed() self._checkClosed()
if not self._sslobj: if self._sslobj is None:
return None return None
else: else:
return self._sslobj.cipher() return self._sslobj.cipher()
def shared_ciphers(self): def shared_ciphers(self):
self._checkClosed() self._checkClosed()
if not self._sslobj: if self._sslobj is None:
return None return None
else:
return self._sslobj.shared_ciphers() return self._sslobj.shared_ciphers()
def compression(self): def compression(self):
self._checkClosed() self._checkClosed()
if not self._sslobj: if self._sslobj is None:
return None return None
else: else:
return self._sslobj.compression() return self._sslobj.compression()
def send(self, data, flags=0): def send(self, data, flags=0):
self._checkClosed() self._checkClosed()
if self._sslobj: if self._sslobj is not None:
if flags != 0: if flags != 0:
raise ValueError( raise ValueError(
"non-zero flags not allowed in calls to send() on %s" % "non-zero flags not allowed in calls to send() on %s" %
@ -974,7 +970,7 @@ class SSLSocket(socket):
def sendto(self, data, flags_or_addr, addr=None): def sendto(self, data, flags_or_addr, addr=None):
self._checkClosed() self._checkClosed()
if self._sslobj: if self._sslobj is not None:
raise ValueError("sendto not allowed on instances of %s" % raise ValueError("sendto not allowed on instances of %s" %
self.__class__) self.__class__)
elif addr is None: elif addr is None:
@ -990,7 +986,7 @@ class SSLSocket(socket):
def sendall(self, data, flags=0): def sendall(self, data, flags=0):
self._checkClosed() self._checkClosed()
if self._sslobj: if self._sslobj is not None:
if flags != 0: if flags != 0:
raise ValueError( raise ValueError(
"non-zero flags not allowed in calls to sendall() on %s" % "non-zero flags not allowed in calls to sendall() on %s" %
@ -1008,15 +1004,15 @@ class SSLSocket(socket):
"""Send a file, possibly by using os.sendfile() if this is a """Send a file, possibly by using os.sendfile() if this is a
clear-text socket. Return the total number of bytes sent. clear-text socket. Return the total number of bytes sent.
""" """
if self._sslobj is None: if self._sslobj is not None:
return self._sendfile_use_send(file, offset, count)
else:
# os.sendfile() works with plain sockets only # os.sendfile() works with plain sockets only
return super().sendfile(file, offset, count) return super().sendfile(file, offset, count)
else:
return self._sendfile_use_send(file, offset, count)
def recv(self, buflen=1024, flags=0): def recv(self, buflen=1024, flags=0):
self._checkClosed() self._checkClosed()
if self._sslobj: if self._sslobj is not None:
if flags != 0: if flags != 0:
raise ValueError( raise ValueError(
"non-zero flags not allowed in calls to recv() on %s" % "non-zero flags not allowed in calls to recv() on %s" %
@ -1031,7 +1027,7 @@ class SSLSocket(socket):
nbytes = len(buffer) nbytes = len(buffer)
elif nbytes is None: elif nbytes is None:
nbytes = 1024 nbytes = 1024
if self._sslobj: if self._sslobj is not None:
if flags != 0: if flags != 0:
raise ValueError( raise ValueError(
"non-zero flags not allowed in calls to recv_into() on %s" % "non-zero flags not allowed in calls to recv_into() on %s" %
@ -1042,7 +1038,7 @@ class SSLSocket(socket):
def recvfrom(self, buflen=1024, flags=0): def recvfrom(self, buflen=1024, flags=0):
self._checkClosed() self._checkClosed()
if self._sslobj: if self._sslobj is not None:
raise ValueError("recvfrom not allowed on instances of %s" % raise ValueError("recvfrom not allowed on instances of %s" %
self.__class__) self.__class__)
else: else:
@ -1050,7 +1046,7 @@ class SSLSocket(socket):
def recvfrom_into(self, buffer, nbytes=None, flags=0): def recvfrom_into(self, buffer, nbytes=None, flags=0):
self._checkClosed() self._checkClosed()
if self._sslobj: if self._sslobj is not None:
raise ValueError("recvfrom_into not allowed on instances of %s" % raise ValueError("recvfrom_into not allowed on instances of %s" %
self.__class__) self.__class__)
else: else:
@ -1066,7 +1062,7 @@ class SSLSocket(socket):
def pending(self): def pending(self):
self._checkClosed() self._checkClosed()
if self._sslobj: if self._sslobj is not None:
return self._sslobj.pending() return self._sslobj.pending()
else: else:
return 0 return 0
@ -1078,7 +1074,7 @@ class SSLSocket(socket):
def unwrap(self): def unwrap(self):
if self._sslobj: if self._sslobj:
s = self._sslobj.unwrap() s = self._sslobj.shutdown()
self._sslobj = None self._sslobj = None
return s return s
else: else:
@ -1096,6 +1092,11 @@ class SSLSocket(socket):
if timeout == 0.0 and block: if timeout == 0.0 and block:
self.settimeout(None) self.settimeout(None)
self._sslobj.do_handshake() self._sslobj.do_handshake()
if self.context.check_hostname:
if not self.server_hostname:
raise ValueError("check_hostname needs server_hostname "
"argument")
match_hostname(self.getpeercert(), self.server_hostname)
finally: finally:
self.settimeout(timeout) self.settimeout(timeout)
@ -1104,11 +1105,12 @@ class SSLSocket(socket):
raise ValueError("can't connect in server-side mode") raise ValueError("can't connect in server-side mode")
# Here we assume that the socket is client-side, and not # Here we assume that the socket is client-side, and not
# connected at the time of the call. We connect it, then wrap it. # connected at the time of the call. We connect it, then wrap it.
if self._connected: if self._connected or self._sslobj is not None:
raise ValueError("attempt to connect already-connected SSLSocket!") raise ValueError("attempt to connect already-connected SSLSocket!")
sslobj = self.context._wrap_socket(self, False, self.server_hostname) self._sslobj = self.context._wrap_socket(
self._sslobj = SSLObject(sslobj, owner=self, self, False, self.server_hostname,
session=self._session) owner=self, session=self._session
)
try: try:
if connect_ex: if connect_ex:
rc = super().connect_ex(addr) rc = super().connect_ex(addr)
@ -1151,18 +1153,24 @@ class SSLSocket(socket):
if the requested `cb_type` is not supported. Return bytes of the data if the requested `cb_type` is not supported. Return bytes of the data
or None if the data is not available (e.g. before the handshake). or None if the data is not available (e.g. before the handshake).
""" """
if self._sslobj is None: if self._sslobj is not None:
return None
return self._sslobj.get_channel_binding(cb_type) return self._sslobj.get_channel_binding(cb_type)
else:
if cb_type not in CHANNEL_BINDING_TYPES:
raise ValueError(
"{0} channel binding type not implemented".format(cb_type)
)
return None
def version(self): def version(self):
""" """
Return a string identifying the protocol version used by the Return a string identifying the protocol version used by the
current SSL channel, or None if there is no established channel. current SSL channel, or None if there is no established channel.
""" """
if self._sslobj is None: if self._sslobj is not None:
return None
return self._sslobj.version() return self._sslobj.version()
else:
return None
# Python does not support forward declaration of types. # Python does not support forward declaration of types.

View File

@ -455,6 +455,8 @@ class BasicSocketTests(unittest.TestCase):
self.assertRaises(OSError, ss.recvfrom_into, bytearray(b'x'), 1) self.assertRaises(OSError, ss.recvfrom_into, bytearray(b'x'), 1)
self.assertRaises(OSError, ss.send, b'x') self.assertRaises(OSError, ss.send, b'x')
self.assertRaises(OSError, ss.sendto, b'x', ('0.0.0.0', 0)) self.assertRaises(OSError, ss.sendto, b'x', ('0.0.0.0', 0))
self.assertRaises(NotImplementedError, ss.sendmsg,
[b'x'], (), 0, ('0.0.0.0', 0))
def test_timeout(self): def test_timeout(self):
# Issue #8524: when creating an SSL socket, the timeout of the # Issue #8524: when creating an SSL socket, the timeout of the
@ -3381,11 +3383,13 @@ class ThreadedTests(unittest.TestCase):
chatty=False) as server: chatty=False) as server:
with context.wrap_socket(socket.socket()) as s: with context.wrap_socket(socket.socket()) as s:
self.assertIs(s.version(), None) self.assertIs(s.version(), None)
self.assertIs(s._sslobj, None)
s.connect((HOST, server.port)) s.connect((HOST, server.port))
if ssl.OPENSSL_VERSION_INFO >= (1, 0, 2): if ssl.OPENSSL_VERSION_INFO >= (1, 0, 2):
self.assertEqual(s.version(), 'TLSv1.2') self.assertEqual(s.version(), 'TLSv1.2')
else: # 0.9.8 to 1.0.1 else: # 0.9.8 to 1.0.1
self.assertIn(s.version(), ('TLSv1', 'TLSv1.2')) self.assertIn(s.version(), ('TLSv1', 'TLSv1.2'))
self.assertIs(s._sslobj, None)
self.assertIs(s.version(), None) self.assertIs(s.version(), None)
@unittest.skipUnless(ssl.HAS_TLSv1_3, @unittest.skipUnless(ssl.HAS_TLSv1_3,

View File

@ -0,0 +1,4 @@
Internal implementation details of ssl module were cleaned up. The SSLSocket
has one less layer of indirection. Owner and session information are now
handled by the SSLSocket and SSLObject constructor. Channel binding
implementation has been simplified.

View File

@ -408,6 +408,8 @@ class _ssl.SSLSession "PySSLSession *" "&PySSLSession_Type"
static int PySSL_select(PySocketSockObject *s, int writing, _PyTime_t timeout); static int PySSL_select(PySocketSockObject *s, int writing, _PyTime_t timeout);
static int PySSL_set_owner(PySSLSocket *, PyObject *, void *);
static int PySSL_set_session(PySSLSocket *, PyObject *, void *);
#define PySSLSocket_Check(v) (Py_TYPE(v) == &PySSLSocket_Type) #define PySSLSocket_Check(v) (Py_TYPE(v) == &PySSLSocket_Type)
#define PySSLMemoryBIO_Check(v) (Py_TYPE(v) == &PySSLMemoryBIO_Type) #define PySSLMemoryBIO_Check(v) (Py_TYPE(v) == &PySSLMemoryBIO_Type)
#define PySSLSession_Check(v) (Py_TYPE(v) == &PySSLSession_Type) #define PySSLSession_Check(v) (Py_TYPE(v) == &PySSLSession_Type)
@ -799,6 +801,7 @@ static PySSLSocket *
newPySSLSocket(PySSLContext *sslctx, PySocketSockObject *sock, newPySSLSocket(PySSLContext *sslctx, PySocketSockObject *sock,
enum py_ssl_server_or_client socket_type, enum py_ssl_server_or_client socket_type,
char *server_hostname, char *server_hostname,
PyObject *owner, PyObject *session,
PySSLMemoryBIO *inbio, PySSLMemoryBIO *outbio) PySSLMemoryBIO *inbio, PySSLMemoryBIO *outbio)
{ {
PySSLSocket *self; PySSLSocket *self;
@ -875,6 +878,18 @@ newPySSLSocket(PySSLContext *sslctx, PySocketSockObject *sock,
return NULL; return NULL;
} }
} }
if (owner && owner != Py_None) {
if (PySSL_set_owner(self, owner, NULL) == -1) {
Py_DECREF(self);
return NULL;
}
}
if (session && session != Py_None) {
if (PySSL_set_session(self, session, NULL) == -1) {
Py_DECREF(self);
return NULL;
}
}
return self; return self;
} }
@ -1677,7 +1692,7 @@ _ssl__test_decode_cert_impl(PyObject *module, PyObject *path)
/*[clinic input] /*[clinic input]
_ssl._SSLSocket.peer_certificate _ssl._SSLSocket.getpeercert
der as binary_mode: bool = False der as binary_mode: bool = False
/ /
@ -1693,8 +1708,8 @@ return the certificate even if it wasn't validated.
[clinic start generated code]*/ [clinic start generated code]*/
static PyObject * static PyObject *
_ssl__SSLSocket_peer_certificate_impl(PySSLSocket *self, int binary_mode) _ssl__SSLSocket_getpeercert_impl(PySSLSocket *self, int binary_mode)
/*[clinic end generated code: output=f0dc3e4d1d818a1d input=8281bd1d193db843]*/ /*[clinic end generated code: output=1f0ab66dfb693c88 input=c0fbe802e57629b7]*/
{ {
int verification; int verification;
X509 *peer_cert; X509 *peer_cert;
@ -2395,13 +2410,11 @@ error:
_ssl._SSLSocket.shutdown _ssl._SSLSocket.shutdown
Does the SSL shutdown handshake with the remote end. Does the SSL shutdown handshake with the remote end.
Returns the underlying socket object.
[clinic start generated code]*/ [clinic start generated code]*/
static PyObject * static PyObject *
_ssl__SSLSocket_shutdown_impl(PySSLSocket *self) _ssl__SSLSocket_shutdown_impl(PySSLSocket *self)
/*[clinic end generated code: output=ca1aa7ed9d25ca42 input=ede2cc1a2ddf0ee4]*/ /*[clinic end generated code: output=ca1aa7ed9d25ca42 input=11d39e69b0a2bf4a]*/
{ {
int err, sockstate, nonblocking; int err, sockstate, nonblocking;
int zeros = 0; int zeros = 0;
@ -2506,21 +2519,25 @@ error:
} }
/*[clinic input] /*[clinic input]
_ssl._SSLSocket.tls_unique_cb _ssl._SSLSocket.get_channel_binding
cb_type: str = "tls-unique"
Returns the 'tls-unique' channel binding data, as defined by RFC 5929. Get channel binding data for current connection.
If the TLS handshake is not yet complete, None is returned. Raise ValueError if the requested `cb_type` is not supported. Return bytes
of the data or None if the data is not available (e.g. before the handshake).
Only 'tls-unique' channel binding data from RFC 5929 is supported.
[clinic start generated code]*/ [clinic start generated code]*/
static PyObject * static PyObject *
_ssl__SSLSocket_tls_unique_cb_impl(PySSLSocket *self) _ssl__SSLSocket_get_channel_binding_impl(PySSLSocket *self,
/*[clinic end generated code: output=f3a832d603f586af input=439525c7b3d8d34d]*/ const char *cb_type)
/*[clinic end generated code: output=34bac9acb6a61d31 input=08b7e43b99c17d41]*/
{ {
PyObject *retval = NULL;
char buf[PySSL_CB_MAXLEN]; char buf[PySSL_CB_MAXLEN];
size_t len; size_t len;
if (strcmp(cb_type, "tls-unique") == 0) {
if (SSL_session_reused(self->ssl) ^ !self->socket_type) { if (SSL_session_reused(self->ssl) ^ !self->socket_type) {
/* if session is resumed XOR we are the client */ /* if session is resumed XOR we are the client */
len = SSL_get_finished(self->ssl, buf, PySSL_CB_MAXLEN); len = SSL_get_finished(self->ssl, buf, PySSL_CB_MAXLEN);
@ -2529,14 +2546,21 @@ _ssl__SSLSocket_tls_unique_cb_impl(PySSLSocket *self)
/* if a new session XOR we are the server */ /* if a new session XOR we are the server */
len = SSL_get_peer_finished(self->ssl, buf, PySSL_CB_MAXLEN); len = SSL_get_peer_finished(self->ssl, buf, PySSL_CB_MAXLEN);
} }
}
else {
PyErr_Format(
PyExc_ValueError,
"'%s' channel binding type not implemented",
cb_type
);
return NULL;
}
/* It cannot be negative in current OpenSSL version as of July 2011 */ /* It cannot be negative in current OpenSSL version as of July 2011 */
if (len == 0) if (len == 0)
Py_RETURN_NONE; Py_RETURN_NONE;
retval = PyBytes_FromStringAndSize(buf, len); return PyBytes_FromStringAndSize(buf, len);
return retval;
} }
#ifdef OPENSSL_VERSION_1_1 #ifdef OPENSSL_VERSION_1_1
@ -2706,7 +2730,8 @@ static PyMethodDef PySSLMethods[] = {
_SSL__SSLSOCKET_WRITE_METHODDEF _SSL__SSLSOCKET_WRITE_METHODDEF
_SSL__SSLSOCKET_READ_METHODDEF _SSL__SSLSOCKET_READ_METHODDEF
_SSL__SSLSOCKET_PENDING_METHODDEF _SSL__SSLSOCKET_PENDING_METHODDEF
_SSL__SSLSOCKET_PEER_CERTIFICATE_METHODDEF _SSL__SSLSOCKET_GETPEERCERT_METHODDEF
_SSL__SSLSOCKET_GET_CHANNEL_BINDING_METHODDEF
_SSL__SSLSOCKET_CIPHER_METHODDEF _SSL__SSLSOCKET_CIPHER_METHODDEF
_SSL__SSLSOCKET_SHARED_CIPHERS_METHODDEF _SSL__SSLSOCKET_SHARED_CIPHERS_METHODDEF
_SSL__SSLSOCKET_VERSION_METHODDEF _SSL__SSLSOCKET_VERSION_METHODDEF
@ -2714,7 +2739,6 @@ static PyMethodDef PySSLMethods[] = {
_SSL__SSLSOCKET_SELECTED_ALPN_PROTOCOL_METHODDEF _SSL__SSLSOCKET_SELECTED_ALPN_PROTOCOL_METHODDEF
_SSL__SSLSOCKET_COMPRESSION_METHODDEF _SSL__SSLSOCKET_COMPRESSION_METHODDEF
_SSL__SSLSOCKET_SHUTDOWN_METHODDEF _SSL__SSLSOCKET_SHUTDOWN_METHODDEF
_SSL__SSLSOCKET_TLS_UNIQUE_CB_METHODDEF
{NULL, NULL} {NULL, NULL}
}; };
@ -3810,13 +3834,17 @@ _ssl._SSLContext._wrap_socket
sock: object(subclass_of="PySocketModule.Sock_Type") sock: object(subclass_of="PySocketModule.Sock_Type")
server_side: int server_side: int
server_hostname as hostname_obj: object = None server_hostname as hostname_obj: object = None
*
owner: object = None
session: object = None
[clinic start generated code]*/ [clinic start generated code]*/
static PyObject * static PyObject *
_ssl__SSLContext__wrap_socket_impl(PySSLContext *self, PyObject *sock, _ssl__SSLContext__wrap_socket_impl(PySSLContext *self, PyObject *sock,
int server_side, PyObject *hostname_obj) int server_side, PyObject *hostname_obj,
/*[clinic end generated code: output=6973e4b60995e933 input=83859b9156ddfc63]*/ PyObject *owner, PyObject *session)
/*[clinic end generated code: output=f103f238633940b4 input=957d5006183d1894]*/
{ {
char *hostname = NULL; char *hostname = NULL;
PyObject *res; PyObject *res;
@ -3830,6 +3858,7 @@ _ssl__SSLContext__wrap_socket_impl(PySSLContext *self, PyObject *sock,
res = (PyObject *) newPySSLSocket(self, (PySocketSockObject *)sock, res = (PyObject *) newPySSLSocket(self, (PySocketSockObject *)sock,
server_side, hostname, server_side, hostname,
owner, session,
NULL, NULL); NULL, NULL);
if (hostname != NULL) if (hostname != NULL)
PyMem_Free(hostname); PyMem_Free(hostname);
@ -3842,14 +3871,18 @@ _ssl._SSLContext._wrap_bio
outgoing: object(subclass_of="&PySSLMemoryBIO_Type", type="PySSLMemoryBIO *") outgoing: object(subclass_of="&PySSLMemoryBIO_Type", type="PySSLMemoryBIO *")
server_side: int server_side: int
server_hostname as hostname_obj: object = None server_hostname as hostname_obj: object = None
*
owner: object = None
session: object = None
[clinic start generated code]*/ [clinic start generated code]*/
static PyObject * static PyObject *
_ssl__SSLContext__wrap_bio_impl(PySSLContext *self, PySSLMemoryBIO *incoming, _ssl__SSLContext__wrap_bio_impl(PySSLContext *self, PySSLMemoryBIO *incoming,
PySSLMemoryBIO *outgoing, int server_side, PySSLMemoryBIO *outgoing, int server_side,
PyObject *hostname_obj) PyObject *hostname_obj, PyObject *owner,
/*[clinic end generated code: output=4fe4ba75ad95940d input=17725ecdac0bf220]*/ PyObject *session)
/*[clinic end generated code: output=5c5d6d9b41f99332 input=8cf22f4d586ac56a]*/
{ {
char *hostname = NULL; char *hostname = NULL;
PyObject *res; PyObject *res;
@ -3862,6 +3895,7 @@ _ssl__SSLContext__wrap_bio_impl(PySSLContext *self, PySSLMemoryBIO *incoming,
} }
res = (PyObject *) newPySSLSocket(self, NULL, server_side, hostname, res = (PyObject *) newPySSLSocket(self, NULL, server_side, hostname,
owner, session,
incoming, outgoing); incoming, outgoing);
PyMem_Free(hostname); PyMem_Free(hostname);
@ -5663,10 +5697,6 @@ PyInit__ssl(void)
Py_INCREF(r); Py_INCREF(r);
PyModule_AddObject(m, "HAS_SNI", r); PyModule_AddObject(m, "HAS_SNI", r);
r = Py_True;
Py_INCREF(r);
PyModule_AddObject(m, "HAS_TLS_UNIQUE", r);
#ifdef OPENSSL_NO_ECDH #ifdef OPENSSL_NO_ECDH
r = Py_False; r = Py_False;
#else #else

View File

@ -45,8 +45,8 @@ exit:
return return_value; return return_value;
} }
PyDoc_STRVAR(_ssl__SSLSocket_peer_certificate__doc__, PyDoc_STRVAR(_ssl__SSLSocket_getpeercert__doc__,
"peer_certificate($self, der=False, /)\n" "getpeercert($self, der=False, /)\n"
"--\n" "--\n"
"\n" "\n"
"Returns the certificate for the peer.\n" "Returns the certificate for the peer.\n"
@ -59,23 +59,23 @@ PyDoc_STRVAR(_ssl__SSLSocket_peer_certificate__doc__,
"peer certificate, or None if no certificate was provided. This will\n" "peer certificate, or None if no certificate was provided. This will\n"
"return the certificate even if it wasn\'t validated."); "return the certificate even if it wasn\'t validated.");
#define _SSL__SSLSOCKET_PEER_CERTIFICATE_METHODDEF \ #define _SSL__SSLSOCKET_GETPEERCERT_METHODDEF \
{"peer_certificate", (PyCFunction)_ssl__SSLSocket_peer_certificate, METH_FASTCALL, _ssl__SSLSocket_peer_certificate__doc__}, {"getpeercert", (PyCFunction)_ssl__SSLSocket_getpeercert, METH_FASTCALL, _ssl__SSLSocket_getpeercert__doc__},
static PyObject * static PyObject *
_ssl__SSLSocket_peer_certificate_impl(PySSLSocket *self, int binary_mode); _ssl__SSLSocket_getpeercert_impl(PySSLSocket *self, int binary_mode);
static PyObject * static PyObject *
_ssl__SSLSocket_peer_certificate(PySSLSocket *self, PyObject *const *args, Py_ssize_t nargs) _ssl__SSLSocket_getpeercert(PySSLSocket *self, PyObject *const *args, Py_ssize_t nargs)
{ {
PyObject *return_value = NULL; PyObject *return_value = NULL;
int binary_mode = 0; int binary_mode = 0;
if (!_PyArg_ParseStack(args, nargs, "|p:peer_certificate", if (!_PyArg_ParseStack(args, nargs, "|p:getpeercert",
&binary_mode)) { &binary_mode)) {
goto exit; goto exit;
} }
return_value = _ssl__SSLSocket_peer_certificate_impl(self, binary_mode); return_value = _ssl__SSLSocket_getpeercert_impl(self, binary_mode);
exit: exit:
return return_value; return return_value;
@ -293,9 +293,7 @@ PyDoc_STRVAR(_ssl__SSLSocket_shutdown__doc__,
"shutdown($self, /)\n" "shutdown($self, /)\n"
"--\n" "--\n"
"\n" "\n"
"Does the SSL shutdown handshake with the remote end.\n" "Does the SSL shutdown handshake with the remote end.");
"\n"
"Returns the underlying socket object.");
#define _SSL__SSLSOCKET_SHUTDOWN_METHODDEF \ #define _SSL__SSLSOCKET_SHUTDOWN_METHODDEF \
{"shutdown", (PyCFunction)_ssl__SSLSocket_shutdown, METH_NOARGS, _ssl__SSLSocket_shutdown__doc__}, {"shutdown", (PyCFunction)_ssl__SSLSocket_shutdown, METH_NOARGS, _ssl__SSLSocket_shutdown__doc__},
@ -309,24 +307,39 @@ _ssl__SSLSocket_shutdown(PySSLSocket *self, PyObject *Py_UNUSED(ignored))
return _ssl__SSLSocket_shutdown_impl(self); return _ssl__SSLSocket_shutdown_impl(self);
} }
PyDoc_STRVAR(_ssl__SSLSocket_tls_unique_cb__doc__, PyDoc_STRVAR(_ssl__SSLSocket_get_channel_binding__doc__,
"tls_unique_cb($self, /)\n" "get_channel_binding($self, /, cb_type=\'tls-unique\')\n"
"--\n" "--\n"
"\n" "\n"
"Returns the \'tls-unique\' channel binding data, as defined by RFC 5929.\n" "Get channel binding data for current connection.\n"
"\n" "\n"
"If the TLS handshake is not yet complete, None is returned."); "Raise ValueError if the requested `cb_type` is not supported. Return bytes\n"
"of the data or None if the data is not available (e.g. before the handshake).\n"
"Only \'tls-unique\' channel binding data from RFC 5929 is supported.");
#define _SSL__SSLSOCKET_TLS_UNIQUE_CB_METHODDEF \ #define _SSL__SSLSOCKET_GET_CHANNEL_BINDING_METHODDEF \
{"tls_unique_cb", (PyCFunction)_ssl__SSLSocket_tls_unique_cb, METH_NOARGS, _ssl__SSLSocket_tls_unique_cb__doc__}, {"get_channel_binding", (PyCFunction)_ssl__SSLSocket_get_channel_binding, METH_FASTCALL|METH_KEYWORDS, _ssl__SSLSocket_get_channel_binding__doc__},
static PyObject * static PyObject *
_ssl__SSLSocket_tls_unique_cb_impl(PySSLSocket *self); _ssl__SSLSocket_get_channel_binding_impl(PySSLSocket *self,
const char *cb_type);
static PyObject * static PyObject *
_ssl__SSLSocket_tls_unique_cb(PySSLSocket *self, PyObject *Py_UNUSED(ignored)) _ssl__SSLSocket_get_channel_binding(PySSLSocket *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
{ {
return _ssl__SSLSocket_tls_unique_cb_impl(self); PyObject *return_value = NULL;
static const char * const _keywords[] = {"cb_type", NULL};
static _PyArg_Parser _parser = {"|s:get_channel_binding", _keywords, 0};
const char *cb_type = "tls-unique";
if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser,
&cb_type)) {
goto exit;
}
return_value = _ssl__SSLSocket_get_channel_binding_impl(self, cb_type);
exit:
return return_value;
} }
static PyObject * static PyObject *
@ -538,7 +551,8 @@ PyDoc_STRVAR(_ssl__SSLContext_load_dh_params__doc__,
{"load_dh_params", (PyCFunction)_ssl__SSLContext_load_dh_params, METH_O, _ssl__SSLContext_load_dh_params__doc__}, {"load_dh_params", (PyCFunction)_ssl__SSLContext_load_dh_params, METH_O, _ssl__SSLContext_load_dh_params__doc__},
PyDoc_STRVAR(_ssl__SSLContext__wrap_socket__doc__, PyDoc_STRVAR(_ssl__SSLContext__wrap_socket__doc__,
"_wrap_socket($self, /, sock, server_side, server_hostname=None)\n" "_wrap_socket($self, /, sock, server_side, server_hostname=None, *,\n"
" owner=None, session=None)\n"
"--\n" "--\n"
"\n"); "\n");
@ -547,23 +561,26 @@ PyDoc_STRVAR(_ssl__SSLContext__wrap_socket__doc__,
static PyObject * static PyObject *
_ssl__SSLContext__wrap_socket_impl(PySSLContext *self, PyObject *sock, _ssl__SSLContext__wrap_socket_impl(PySSLContext *self, PyObject *sock,
int server_side, PyObject *hostname_obj); int server_side, PyObject *hostname_obj,
PyObject *owner, PyObject *session);
static PyObject * static PyObject *
_ssl__SSLContext__wrap_socket(PySSLContext *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) _ssl__SSLContext__wrap_socket(PySSLContext *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
{ {
PyObject *return_value = NULL; PyObject *return_value = NULL;
static const char * const _keywords[] = {"sock", "server_side", "server_hostname", NULL}; static const char * const _keywords[] = {"sock", "server_side", "server_hostname", "owner", "session", NULL};
static _PyArg_Parser _parser = {"O!i|O:_wrap_socket", _keywords, 0}; static _PyArg_Parser _parser = {"O!i|O$OO:_wrap_socket", _keywords, 0};
PyObject *sock; PyObject *sock;
int server_side; int server_side;
PyObject *hostname_obj = Py_None; PyObject *hostname_obj = Py_None;
PyObject *owner = Py_None;
PyObject *session = Py_None;
if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser,
PySocketModule.Sock_Type, &sock, &server_side, &hostname_obj)) { PySocketModule.Sock_Type, &sock, &server_side, &hostname_obj, &owner, &session)) {
goto exit; goto exit;
} }
return_value = _ssl__SSLContext__wrap_socket_impl(self, sock, server_side, hostname_obj); return_value = _ssl__SSLContext__wrap_socket_impl(self, sock, server_side, hostname_obj, owner, session);
exit: exit:
return return_value; return return_value;
@ -571,7 +588,7 @@ exit:
PyDoc_STRVAR(_ssl__SSLContext__wrap_bio__doc__, PyDoc_STRVAR(_ssl__SSLContext__wrap_bio__doc__,
"_wrap_bio($self, /, incoming, outgoing, server_side,\n" "_wrap_bio($self, /, incoming, outgoing, server_side,\n"
" server_hostname=None)\n" " server_hostname=None, *, owner=None, session=None)\n"
"--\n" "--\n"
"\n"); "\n");
@ -581,24 +598,27 @@ PyDoc_STRVAR(_ssl__SSLContext__wrap_bio__doc__,
static PyObject * static PyObject *
_ssl__SSLContext__wrap_bio_impl(PySSLContext *self, PySSLMemoryBIO *incoming, _ssl__SSLContext__wrap_bio_impl(PySSLContext *self, PySSLMemoryBIO *incoming,
PySSLMemoryBIO *outgoing, int server_side, PySSLMemoryBIO *outgoing, int server_side,
PyObject *hostname_obj); PyObject *hostname_obj, PyObject *owner,
PyObject *session);
static PyObject * static PyObject *
_ssl__SSLContext__wrap_bio(PySSLContext *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) _ssl__SSLContext__wrap_bio(PySSLContext *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
{ {
PyObject *return_value = NULL; PyObject *return_value = NULL;
static const char * const _keywords[] = {"incoming", "outgoing", "server_side", "server_hostname", NULL}; static const char * const _keywords[] = {"incoming", "outgoing", "server_side", "server_hostname", "owner", "session", NULL};
static _PyArg_Parser _parser = {"O!O!i|O:_wrap_bio", _keywords, 0}; static _PyArg_Parser _parser = {"O!O!i|O$OO:_wrap_bio", _keywords, 0};
PySSLMemoryBIO *incoming; PySSLMemoryBIO *incoming;
PySSLMemoryBIO *outgoing; PySSLMemoryBIO *outgoing;
int server_side; int server_side;
PyObject *hostname_obj = Py_None; PyObject *hostname_obj = Py_None;
PyObject *owner = Py_None;
PyObject *session = Py_None;
if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser,
&PySSLMemoryBIO_Type, &incoming, &PySSLMemoryBIO_Type, &outgoing, &server_side, &hostname_obj)) { &PySSLMemoryBIO_Type, &incoming, &PySSLMemoryBIO_Type, &outgoing, &server_side, &hostname_obj, &owner, &session)) {
goto exit; goto exit;
} }
return_value = _ssl__SSLContext__wrap_bio_impl(self, incoming, outgoing, server_side, hostname_obj); return_value = _ssl__SSLContext__wrap_bio_impl(self, incoming, outgoing, server_side, hostname_obj, owner, session);
exit: exit:
return return_value; return return_value;
@ -1155,4 +1175,4 @@ exit:
#ifndef _SSL_ENUM_CRLS_METHODDEF #ifndef _SSL_ENUM_CRLS_METHODDEF
#define _SSL_ENUM_CRLS_METHODDEF #define _SSL_ENUM_CRLS_METHODDEF
#endif /* !defined(_SSL_ENUM_CRLS_METHODDEF) */ #endif /* !defined(_SSL_ENUM_CRLS_METHODDEF) */
/*[clinic end generated code: output=84e1fd89aff9b0f7 input=a9049054013a1b77]*/ /*[clinic end generated code: output=d987411caeb106e7 input=a9049054013a1b77]*/