[Python-checkins] bpo-24334: Cleanup SSLSocket (#5252)

Christian Heimes webhook-mailer at python.org
Sat Feb 24 15:11:00 EST 2018


https://github.com/python/cpython/commit/141c5e8c2437a9fed95a04c81e400ef725592a17
commit: 141c5e8c2437a9fed95a04c81e400ef725592a17
branch: master
author: Christian Heimes <christian at python.org>
committer: GitHub <noreply at github.com>
date: 2018-02-24T21:10:57+01:00
summary:

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.

files:
A Misc/NEWS.d/next/Library/2018-01-20-23-17-25.bpo-24334.GZuQLv.rst
M Lib/ssl.py
M Lib/test/test_ssl.py
M Modules/_ssl.c
M Modules/clinic/_ssl.c.h

diff --git a/Lib/ssl.py b/Lib/ssl.py
index ecdbb7076283..94ea35e358a3 100644
--- a/Lib/ssl.py
+++ b/Lib/ssl.py
@@ -166,10 +166,7 @@
 
 socket_error = OSError  # keep that public name in module namespace
 
-if _ssl.HAS_TLS_UNIQUE:
-    CHANNEL_BINDING_TYPES = ['tls-unique']
-else:
-    CHANNEL_BINDING_TYPES = []
+CHANNEL_BINDING_TYPES = ['tls-unique']
 
 HAS_NEVER_CHECK_COMMON_NAME = hasattr(_ssl, 'HOSTFLAG_NEVER_CHECK_SUBJECT')
 
@@ -407,11 +404,11 @@ def wrap_bio(self, incoming, outgoing, server_side=False,
                  server_hostname=None, session=None):
         # Need to encode server_hostname here because _wrap_bio() can only
         # handle ASCII str.
-        sslobj = self._wrap_bio(
+        return self.sslobject_class(
             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):
         protos = bytearray()
@@ -616,12 +613,13 @@ class SSLObject:
      * The ``do_handshake_on_connect`` and ``suppress_ragged_eofs`` machinery.
     """
 
-    def __init__(self, sslobj, owner=None, session=None):
-        self._sslobj = sslobj
-        # Note: _sslobj takes a weak reference to owner
-        self._sslobj.owner = owner or self
-        if session is not None:
-            self._sslobj.session = session
+    def __init__(self, incoming, outgoing, server_side=False,
+                 server_hostname=None, session=None, _context=None):
+        self._sslobj = _context._wrap_bio(
+            incoming, outgoing, server_side=server_side,
+            server_hostname=server_hostname,
+            owner=self, session=session
+        )
 
     @property
     def context(self):
@@ -684,7 +682,7 @@ def getpeercert(self, binary_form=False):
         Return None if no certificate was provided, {} if a certificate was
         provided, but not validated.
         """
-        return self._sslobj.peer_certificate(binary_form)
+        return self._sslobj.getpeercert(binary_form)
 
     def selected_npn_protocol(self):
         """Return the currently selected NPN protocol as a string, or ``None``
@@ -732,13 +730,7 @@ def get_channel_binding(self, cb_type="tls-unique"):
         """Get channel binding data for current connection.  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)."""
-        if cb_type not in CHANNEL_BINDING_TYPES:
-            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()
+        return self._sslobj.get_channel_binding(cb_type)
 
     def version(self):
         """Return a string identifying the protocol version used by the
@@ -832,10 +824,10 @@ def __init__(self, sock=None, keyfile=None, certfile=None,
         if connected:
             # create the SSL object
             try:
-                sslobj = self._context._wrap_socket(self, server_side,
-                                                    self.server_hostname)
-                self._sslobj = SSLObject(sslobj, owner=self,
-                                         session=self._session)
+                self._sslobj = self._context._wrap_socket(
+                    self, server_side, self.server_hostname,
+                    owner=self, session=self._session,
+                )
                 if do_handshake_on_connect:
                     timeout = self.gettimeout()
                     if timeout == 0.0:
@@ -895,10 +887,13 @@ def read(self, len=1024, buffer=None):
         Return zero-length string on EOF."""
 
         self._checkClosed()
-        if not self._sslobj:
+        if self._sslobj is None:
             raise ValueError("Read on closed or unwrapped SSL socket.")
         try:
-            return self._sslobj.read(len, buffer)
+            if buffer is not None:
+                return self._sslobj.read(len, buffer)
+            else:
+                return self._sslobj.read(len)
         except SSLError as x:
             if x.args[0] == SSL_ERROR_EOF and self.suppress_ragged_eofs:
                 if buffer is not None:
@@ -913,7 +908,7 @@ def write(self, data):
         number of bytes of DATA actually transmitted."""
 
         self._checkClosed()
-        if not self._sslobj:
+        if self._sslobj is None:
             raise ValueError("Write on closed or unwrapped SSL socket.")
         return self._sslobj.write(data)
 
@@ -929,41 +924,42 @@ def getpeercert(self, binary_form=False):
 
     def selected_npn_protocol(self):
         self._checkClosed()
-        if not self._sslobj or not _ssl.HAS_NPN:
+        if self._sslobj is None or not _ssl.HAS_NPN:
             return None
         else:
             return self._sslobj.selected_npn_protocol()
 
     def selected_alpn_protocol(self):
         self._checkClosed()
-        if not self._sslobj or not _ssl.HAS_ALPN:
+        if self._sslobj is None or not _ssl.HAS_ALPN:
             return None
         else:
             return self._sslobj.selected_alpn_protocol()
 
     def cipher(self):
         self._checkClosed()
-        if not self._sslobj:
+        if self._sslobj is None:
             return None
         else:
             return self._sslobj.cipher()
 
     def shared_ciphers(self):
         self._checkClosed()
-        if not self._sslobj:
+        if self._sslobj is None:
             return None
-        return self._sslobj.shared_ciphers()
+        else:
+            return self._sslobj.shared_ciphers()
 
     def compression(self):
         self._checkClosed()
-        if not self._sslobj:
+        if self._sslobj is None:
             return None
         else:
             return self._sslobj.compression()
 
     def send(self, data, flags=0):
         self._checkClosed()
-        if self._sslobj:
+        if self._sslobj is not None:
             if flags != 0:
                 raise ValueError(
                     "non-zero flags not allowed in calls to send() on %s" %
@@ -974,7 +970,7 @@ def send(self, data, flags=0):
 
     def sendto(self, data, flags_or_addr, addr=None):
         self._checkClosed()
-        if self._sslobj:
+        if self._sslobj is not None:
             raise ValueError("sendto not allowed on instances of %s" %
                              self.__class__)
         elif addr is None:
@@ -990,7 +986,7 @@ def sendmsg(self, *args, **kwargs):
 
     def sendall(self, data, flags=0):
         self._checkClosed()
-        if self._sslobj:
+        if self._sslobj is not None:
             if flags != 0:
                 raise ValueError(
                     "non-zero flags not allowed in calls to sendall() on %s" %
@@ -1008,15 +1004,15 @@ def sendfile(self, file, offset=0, count=None):
         """Send a file, possibly by using os.sendfile() if this is a
         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
             return super().sendfile(file, offset, count)
-        else:
-            return self._sendfile_use_send(file, offset, count)
 
     def recv(self, buflen=1024, flags=0):
         self._checkClosed()
-        if self._sslobj:
+        if self._sslobj is not None:
             if flags != 0:
                 raise ValueError(
                     "non-zero flags not allowed in calls to recv() on %s" %
@@ -1031,7 +1027,7 @@ def recv_into(self, buffer, nbytes=None, flags=0):
             nbytes = len(buffer)
         elif nbytes is None:
             nbytes = 1024
-        if self._sslobj:
+        if self._sslobj is not None:
             if flags != 0:
                 raise ValueError(
                   "non-zero flags not allowed in calls to recv_into() on %s" %
@@ -1042,7 +1038,7 @@ def recv_into(self, buffer, nbytes=None, flags=0):
 
     def recvfrom(self, buflen=1024, flags=0):
         self._checkClosed()
-        if self._sslobj:
+        if self._sslobj is not None:
             raise ValueError("recvfrom not allowed on instances of %s" %
                              self.__class__)
         else:
@@ -1050,7 +1046,7 @@ def recvfrom(self, buflen=1024, flags=0):
 
     def recvfrom_into(self, buffer, nbytes=None, flags=0):
         self._checkClosed()
-        if self._sslobj:
+        if self._sslobj is not None:
             raise ValueError("recvfrom_into not allowed on instances of %s" %
                              self.__class__)
         else:
@@ -1066,7 +1062,7 @@ def recvmsg_into(self, *args, **kwargs):
 
     def pending(self):
         self._checkClosed()
-        if self._sslobj:
+        if self._sslobj is not None:
             return self._sslobj.pending()
         else:
             return 0
@@ -1078,7 +1074,7 @@ def shutdown(self, how):
 
     def unwrap(self):
         if self._sslobj:
-            s = self._sslobj.unwrap()
+            s = self._sslobj.shutdown()
             self._sslobj = None
             return s
         else:
@@ -1096,6 +1092,11 @@ def do_handshake(self, block=False):
             if timeout == 0.0 and block:
                 self.settimeout(None)
             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:
             self.settimeout(timeout)
 
@@ -1104,11 +1105,12 @@ def _real_connect(self, addr, connect_ex):
             raise ValueError("can't connect in server-side mode")
         # Here we assume that the socket is client-side, and not
         # 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!")
-        sslobj = self.context._wrap_socket(self, False, self.server_hostname)
-        self._sslobj = SSLObject(sslobj, owner=self,
-                                 session=self._session)
+        self._sslobj = self.context._wrap_socket(
+            self, False, self.server_hostname,
+            owner=self, session=self._session
+        )
         try:
             if connect_ex:
                 rc = super().connect_ex(addr)
@@ -1151,18 +1153,24 @@ def get_channel_binding(self, cb_type="tls-unique"):
         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).
         """
-        if self._sslobj is None:
+        if self._sslobj is not None:
+            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
-        return self._sslobj.get_channel_binding(cb_type)
 
     def version(self):
         """
         Return a string identifying the protocol version used by the
         current SSL channel, or None if there is no established channel.
         """
-        if self._sslobj is None:
+        if self._sslobj is not None:
+            return self._sslobj.version()
+        else:
             return None
-        return self._sslobj.version()
 
 
 # Python does not support forward declaration of types.
diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py
index 7aa112335cdb..3f2c50b7795a 100644
--- a/Lib/test/test_ssl.py
+++ b/Lib/test/test_ssl.py
@@ -455,6 +455,8 @@ def test_wrapped_unconnected(self):
             self.assertRaises(OSError, ss.recvfrom_into, bytearray(b'x'), 1)
             self.assertRaises(OSError, ss.send, b'x')
             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):
         # Issue #8524: when creating an SSL socket, the timeout of the
@@ -3381,11 +3383,13 @@ def test_version_basic(self):
                                 chatty=False) as server:
             with context.wrap_socket(socket.socket()) as s:
                 self.assertIs(s.version(), None)
+                self.assertIs(s._sslobj, None)
                 s.connect((HOST, server.port))
                 if ssl.OPENSSL_VERSION_INFO >= (1, 0, 2):
                     self.assertEqual(s.version(), 'TLSv1.2')
                 else:  # 0.9.8 to 1.0.1
                     self.assertIn(s.version(), ('TLSv1', 'TLSv1.2'))
+            self.assertIs(s._sslobj, None)
             self.assertIs(s.version(), None)
 
     @unittest.skipUnless(ssl.HAS_TLSv1_3,
diff --git a/Misc/NEWS.d/next/Library/2018-01-20-23-17-25.bpo-24334.GZuQLv.rst b/Misc/NEWS.d/next/Library/2018-01-20-23-17-25.bpo-24334.GZuQLv.rst
new file mode 100644
index 000000000000..2b4877fad7e1
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2018-01-20-23-17-25.bpo-24334.GZuQLv.rst
@@ -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.
diff --git a/Modules/_ssl.c b/Modules/_ssl.c
index a0f8c1cb3244..2136cbdeae47 100644
--- a/Modules/_ssl.c
+++ b/Modules/_ssl.c
@@ -408,6 +408,8 @@ class _ssl.SSLSession "PySSLSession *" "&PySSLSession_Type"
 
 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 PySSLMemoryBIO_Check(v)    (Py_TYPE(v) == &PySSLMemoryBIO_Type)
 #define PySSLSession_Check(v)   (Py_TYPE(v) == &PySSLSession_Type)
@@ -799,6 +801,7 @@ static PySSLSocket *
 newPySSLSocket(PySSLContext *sslctx, PySocketSockObject *sock,
                enum py_ssl_server_or_client socket_type,
                char *server_hostname,
+               PyObject *owner, PyObject *session,
                PySSLMemoryBIO *inbio, PySSLMemoryBIO *outbio)
 {
     PySSLSocket *self;
@@ -875,6 +878,18 @@ newPySSLSocket(PySSLContext *sslctx, PySocketSockObject *sock,
             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;
 }
 
@@ -1677,7 +1692,7 @@ _ssl__test_decode_cert_impl(PyObject *module, PyObject *path)
 
 
 /*[clinic input]
-_ssl._SSLSocket.peer_certificate
+_ssl._SSLSocket.getpeercert
     der as binary_mode: bool = False
     /
 
@@ -1693,8 +1708,8 @@ return the certificate even if it wasn't validated.
 [clinic start generated code]*/
 
 static PyObject *
-_ssl__SSLSocket_peer_certificate_impl(PySSLSocket *self, int binary_mode)
-/*[clinic end generated code: output=f0dc3e4d1d818a1d input=8281bd1d193db843]*/
+_ssl__SSLSocket_getpeercert_impl(PySSLSocket *self, int binary_mode)
+/*[clinic end generated code: output=1f0ab66dfb693c88 input=c0fbe802e57629b7]*/
 {
     int verification;
     X509 *peer_cert;
@@ -2395,13 +2410,11 @@ _ssl__SSLSocket_read_impl(PySSLSocket *self, int len, int group_right_1,
 _ssl._SSLSocket.shutdown
 
 Does the SSL shutdown handshake with the remote end.
-
-Returns the underlying socket object.
 [clinic start generated code]*/
 
 static PyObject *
 _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 zeros = 0;
@@ -2506,37 +2519,48 @@ _ssl__SSLSocket_shutdown_impl(PySSLSocket *self)
 }
 
 /*[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]*/
 
 static PyObject *
-_ssl__SSLSocket_tls_unique_cb_impl(PySSLSocket *self)
-/*[clinic end generated code: output=f3a832d603f586af input=439525c7b3d8d34d]*/
+_ssl__SSLSocket_get_channel_binding_impl(PySSLSocket *self,
+                                         const char *cb_type)
+/*[clinic end generated code: output=34bac9acb6a61d31 input=08b7e43b99c17d41]*/
 {
-    PyObject *retval = NULL;
     char buf[PySSL_CB_MAXLEN];
     size_t len;
 
-    if (SSL_session_reused(self->ssl) ^ !self->socket_type) {
-        /* if session is resumed XOR we are the client */
-        len = SSL_get_finished(self->ssl, buf, PySSL_CB_MAXLEN);
+    if (strcmp(cb_type, "tls-unique") == 0) {
+        if (SSL_session_reused(self->ssl) ^ !self->socket_type) {
+            /* if session is resumed XOR we are the client */
+            len = SSL_get_finished(self->ssl, buf, PySSL_CB_MAXLEN);
+        }
+        else {
+            /* if a new session XOR we are the server */
+            len = SSL_get_peer_finished(self->ssl, buf, PySSL_CB_MAXLEN);
+        }
     }
     else {
-        /* if a new session XOR we are the server */
-        len = SSL_get_peer_finished(self->ssl, buf, PySSL_CB_MAXLEN);
+        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 */
     if (len == 0)
         Py_RETURN_NONE;
 
-    retval = PyBytes_FromStringAndSize(buf, len);
-
-    return retval;
+    return PyBytes_FromStringAndSize(buf, len);
 }
 
 #ifdef OPENSSL_VERSION_1_1
@@ -2706,7 +2730,8 @@ static PyMethodDef PySSLMethods[] = {
     _SSL__SSLSOCKET_WRITE_METHODDEF
     _SSL__SSLSOCKET_READ_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_SHARED_CIPHERS_METHODDEF
     _SSL__SSLSOCKET_VERSION_METHODDEF
@@ -2714,7 +2739,6 @@ static PyMethodDef PySSLMethods[] = {
     _SSL__SSLSOCKET_SELECTED_ALPN_PROTOCOL_METHODDEF
     _SSL__SSLSOCKET_COMPRESSION_METHODDEF
     _SSL__SSLSOCKET_SHUTDOWN_METHODDEF
-    _SSL__SSLSOCKET_TLS_UNIQUE_CB_METHODDEF
     {NULL, NULL}
 };
 
@@ -3810,13 +3834,17 @@ _ssl._SSLContext._wrap_socket
     sock: object(subclass_of="PySocketModule.Sock_Type")
     server_side: int
     server_hostname as hostname_obj: object = None
+    *
+    owner: object = None
+    session: object = None
 
 [clinic start generated code]*/
 
 static PyObject *
 _ssl__SSLContext__wrap_socket_impl(PySSLContext *self, PyObject *sock,
-                                   int server_side, PyObject *hostname_obj)
-/*[clinic end generated code: output=6973e4b60995e933 input=83859b9156ddfc63]*/
+                                   int server_side, PyObject *hostname_obj,
+                                   PyObject *owner, PyObject *session)
+/*[clinic end generated code: output=f103f238633940b4 input=957d5006183d1894]*/
 {
     char *hostname = NULL;
     PyObject *res;
@@ -3830,6 +3858,7 @@ _ssl__SSLContext__wrap_socket_impl(PySSLContext *self, PyObject *sock,
 
     res = (PyObject *) newPySSLSocket(self, (PySocketSockObject *)sock,
                                       server_side, hostname,
+                                      owner, session,
                                       NULL, NULL);
     if (hostname != NULL)
         PyMem_Free(hostname);
@@ -3842,14 +3871,18 @@ _ssl._SSLContext._wrap_bio
     outgoing: object(subclass_of="&PySSLMemoryBIO_Type", type="PySSLMemoryBIO *")
     server_side: int
     server_hostname as hostname_obj: object = None
+    *
+    owner: object = None
+    session: object = None
 
 [clinic start generated code]*/
 
 static PyObject *
 _ssl__SSLContext__wrap_bio_impl(PySSLContext *self, PySSLMemoryBIO *incoming,
                                 PySSLMemoryBIO *outgoing, int server_side,
-                                PyObject *hostname_obj)
-/*[clinic end generated code: output=4fe4ba75ad95940d input=17725ecdac0bf220]*/
+                                PyObject *hostname_obj, PyObject *owner,
+                                PyObject *session)
+/*[clinic end generated code: output=5c5d6d9b41f99332 input=8cf22f4d586ac56a]*/
 {
     char *hostname = NULL;
     PyObject *res;
@@ -3862,6 +3895,7 @@ _ssl__SSLContext__wrap_bio_impl(PySSLContext *self, PySSLMemoryBIO *incoming,
     }
 
     res = (PyObject *) newPySSLSocket(self, NULL, server_side, hostname,
+                                      owner, session,
                                       incoming, outgoing);
 
     PyMem_Free(hostname);
@@ -5663,10 +5697,6 @@ PyInit__ssl(void)
     Py_INCREF(r);
     PyModule_AddObject(m, "HAS_SNI", r);
 
-    r = Py_True;
-    Py_INCREF(r);
-    PyModule_AddObject(m, "HAS_TLS_UNIQUE", r);
-
 #ifdef OPENSSL_NO_ECDH
     r = Py_False;
 #else
diff --git a/Modules/clinic/_ssl.c.h b/Modules/clinic/_ssl.c.h
index d1a9afcd1d1e..5b6c4af11fb7 100644
--- a/Modules/clinic/_ssl.c.h
+++ b/Modules/clinic/_ssl.c.h
@@ -45,8 +45,8 @@ _ssl__test_decode_cert(PyObject *module, PyObject *arg)
     return return_value;
 }
 
-PyDoc_STRVAR(_ssl__SSLSocket_peer_certificate__doc__,
-"peer_certificate($self, der=False, /)\n"
+PyDoc_STRVAR(_ssl__SSLSocket_getpeercert__doc__,
+"getpeercert($self, der=False, /)\n"
 "--\n"
 "\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"
 "return the certificate even if it wasn\'t validated.");
 
-#define _SSL__SSLSOCKET_PEER_CERTIFICATE_METHODDEF    \
-    {"peer_certificate", (PyCFunction)_ssl__SSLSocket_peer_certificate, METH_FASTCALL, _ssl__SSLSocket_peer_certificate__doc__},
+#define _SSL__SSLSOCKET_GETPEERCERT_METHODDEF    \
+    {"getpeercert", (PyCFunction)_ssl__SSLSocket_getpeercert, METH_FASTCALL, _ssl__SSLSocket_getpeercert__doc__},
 
 static PyObject *
-_ssl__SSLSocket_peer_certificate_impl(PySSLSocket *self, int binary_mode);
+_ssl__SSLSocket_getpeercert_impl(PySSLSocket *self, int binary_mode);
 
 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;
     int binary_mode = 0;
 
-    if (!_PyArg_ParseStack(args, nargs, "|p:peer_certificate",
+    if (!_PyArg_ParseStack(args, nargs, "|p:getpeercert",
         &binary_mode)) {
         goto exit;
     }
-    return_value = _ssl__SSLSocket_peer_certificate_impl(self, binary_mode);
+    return_value = _ssl__SSLSocket_getpeercert_impl(self, binary_mode);
 
 exit:
     return return_value;
@@ -293,9 +293,7 @@ PyDoc_STRVAR(_ssl__SSLSocket_shutdown__doc__,
 "shutdown($self, /)\n"
 "--\n"
 "\n"
-"Does the SSL shutdown handshake with the remote end.\n"
-"\n"
-"Returns the underlying socket object.");
+"Does the SSL shutdown handshake with the remote end.");
 
 #define _SSL__SSLSOCKET_SHUTDOWN_METHODDEF    \
     {"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);
 }
 
-PyDoc_STRVAR(_ssl__SSLSocket_tls_unique_cb__doc__,
-"tls_unique_cb($self, /)\n"
+PyDoc_STRVAR(_ssl__SSLSocket_get_channel_binding__doc__,
+"get_channel_binding($self, /, cb_type=\'tls-unique\')\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"
-"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    \
-    {"tls_unique_cb", (PyCFunction)_ssl__SSLSocket_tls_unique_cb, METH_NOARGS, _ssl__SSLSocket_tls_unique_cb__doc__},
+#define _SSL__SSLSOCKET_GET_CHANNEL_BINDING_METHODDEF    \
+    {"get_channel_binding", (PyCFunction)_ssl__SSLSocket_get_channel_binding, METH_FASTCALL|METH_KEYWORDS, _ssl__SSLSocket_get_channel_binding__doc__},
 
 static PyObject *
-_ssl__SSLSocket_tls_unique_cb_impl(PySSLSocket *self);
+_ssl__SSLSocket_get_channel_binding_impl(PySSLSocket *self,
+                                         const char *cb_type);
 
 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 *
@@ -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__},
 
 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");
 
@@ -547,23 +561,26 @@ PyDoc_STRVAR(_ssl__SSLContext__wrap_socket__doc__,
 
 static PyObject *
 _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 *
 _ssl__SSLContext__wrap_socket(PySSLContext *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
 {
     PyObject *return_value = NULL;
-    static const char * const _keywords[] = {"sock", "server_side", "server_hostname", NULL};
-    static _PyArg_Parser _parser = {"O!i|O:_wrap_socket", _keywords, 0};
+    static const char * const _keywords[] = {"sock", "server_side", "server_hostname", "owner", "session", NULL};
+    static _PyArg_Parser _parser = {"O!i|O$OO:_wrap_socket", _keywords, 0};
     PyObject *sock;
     int server_side;
     PyObject *hostname_obj = Py_None;
+    PyObject *owner = Py_None;
+    PyObject *session = Py_None;
 
     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;
     }
-    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:
     return return_value;
@@ -571,7 +588,7 @@ _ssl__SSLContext__wrap_socket(PySSLContext *self, PyObject *const *args, Py_ssiz
 
 PyDoc_STRVAR(_ssl__SSLContext__wrap_bio__doc__,
 "_wrap_bio($self, /, incoming, outgoing, server_side,\n"
-"          server_hostname=None)\n"
+"          server_hostname=None, *, owner=None, session=None)\n"
 "--\n"
 "\n");
 
@@ -581,24 +598,27 @@ PyDoc_STRVAR(_ssl__SSLContext__wrap_bio__doc__,
 static PyObject *
 _ssl__SSLContext__wrap_bio_impl(PySSLContext *self, PySSLMemoryBIO *incoming,
                                 PySSLMemoryBIO *outgoing, int server_side,
-                                PyObject *hostname_obj);
+                                PyObject *hostname_obj, PyObject *owner,
+                                PyObject *session);
 
 static PyObject *
 _ssl__SSLContext__wrap_bio(PySSLContext *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
 {
     PyObject *return_value = NULL;
-    static const char * const _keywords[] = {"incoming", "outgoing", "server_side", "server_hostname", NULL};
-    static _PyArg_Parser _parser = {"O!O!i|O:_wrap_bio", _keywords, 0};
+    static const char * const _keywords[] = {"incoming", "outgoing", "server_side", "server_hostname", "owner", "session", NULL};
+    static _PyArg_Parser _parser = {"O!O!i|O$OO:_wrap_bio", _keywords, 0};
     PySSLMemoryBIO *incoming;
     PySSLMemoryBIO *outgoing;
     int server_side;
     PyObject *hostname_obj = Py_None;
+    PyObject *owner = Py_None;
+    PyObject *session = Py_None;
 
     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;
     }
-    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:
     return return_value;
@@ -1155,4 +1175,4 @@ _ssl_enum_crls(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObje
 #ifndef _SSL_ENUM_CRLS_METHODDEF
     #define _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]*/



More information about the Python-checkins mailing list