[3.7] bpo-24334: Cleanup SSLSocket (GH-5252) (#5857)
* 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.
(cherry picked from commit 141c5e8c2437a9fed95a04c81e400ef725592a17)
Co-authored-by: Christian Heimes <christian@python.org>
diff --git a/Modules/_ssl.c b/Modules/_ssl.c
index a0f8c1c..2136cbd 100644
--- a/Modules/_ssl.c
+++ b/Modules/_ssl.c
@@ -408,6 +408,8 @@
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 @@
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 @@
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 @@
/*[clinic input]
-_ssl._SSLSocket.peer_certificate
+_ssl._SSLSocket.getpeercert
der as binary_mode: bool = False
/
@@ -1693,8 +1708,8 @@
[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.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 @@
}
/*[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 @@
_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 @@
_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 @@
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 @@
res = (PyObject *) newPySSLSocket(self, (PySocketSockObject *)sock,
server_side, hostname,
+ owner, session,
NULL, NULL);
if (hostname != NULL)
PyMem_Free(hostname);
@@ -3842,14 +3871,18 @@
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 @@
}
res = (PyObject *) newPySSLSocket(self, NULL, server_side, hostname,
+ owner, session,
incoming, outgoing);
PyMem_Free(hostname);
@@ -5663,10 +5697,6 @@
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