@@ -2224,6 +2224,17 @@ PySSL_dealloc(PySSLSocket *self)
2224
2224
PyTypeObject * tp = Py_TYPE (self );
2225
2225
PyObject_GC_UnTrack (self );
2226
2226
if (self -> ssl ) {
2227
+ // If we free the SSL socket object without having called SSL_shutdown,
2228
+ // OpenSSL will invalidate the linked SSL session object. While this
2229
+ // behavior is strictly RFC-compliant, it makes session reuse less
2230
+ // likely and it would also break compatibility with older stdlib
2231
+ // versions (which used an ugly workaround of duplicating the
2232
+ // SSL_SESSION object).
2233
+ // Therefore, we ensure the socket is marked as shutdown in any case.
2234
+ //
2235
+ // See elaborate explanation at
2236
+ // https://github.com/python/cpython/pull/123249#discussion_r1766164530
2237
+ SSL_set_shutdown (self -> ssl , SSL_SENT_SHUTDOWN | SSL_get_shutdown (self -> ssl ));
2227
2238
SSL_free (self -> ssl );
2228
2239
}
2229
2240
Py_XDECREF (self -> Socket );
@@ -2768,64 +2779,13 @@ _ssl__SSLSocket_verify_client_post_handshake_impl(PySSLSocket *self)
2768
2779
#endif
2769
2780
}
2770
2781
2771
- static SSL_SESSION *
2772
- _ssl_session_dup (SSL_SESSION * session ) {
2773
- SSL_SESSION * newsession = NULL ;
2774
- int slen ;
2775
- unsigned char * senc = NULL , * p ;
2776
- const unsigned char * const_p ;
2777
-
2778
- if (session == NULL ) {
2779
- PyErr_SetString (PyExc_ValueError , "Invalid session" );
2780
- goto error ;
2781
- }
2782
-
2783
- /* get length */
2784
- slen = i2d_SSL_SESSION (session , NULL );
2785
- if (slen == 0 || slen > 0xFF00 ) {
2786
- PyErr_SetString (PyExc_ValueError , "i2d() failed" );
2787
- goto error ;
2788
- }
2789
- if ((senc = PyMem_Malloc (slen )) == NULL ) {
2790
- PyErr_NoMemory ();
2791
- goto error ;
2792
- }
2793
- p = senc ;
2794
- if (!i2d_SSL_SESSION (session , & p )) {
2795
- PyErr_SetString (PyExc_ValueError , "i2d() failed" );
2796
- goto error ;
2797
- }
2798
- const_p = senc ;
2799
- newsession = d2i_SSL_SESSION (NULL , & const_p , slen );
2800
- if (newsession == NULL ) {
2801
- PyErr_SetString (PyExc_ValueError , "d2i() failed" );
2802
- goto error ;
2803
- }
2804
- PyMem_Free (senc );
2805
- return newsession ;
2806
- error :
2807
- if (senc != NULL ) {
2808
- PyMem_Free (senc );
2809
- }
2810
- return NULL ;
2811
- }
2812
-
2813
2782
static PyObject *
2814
2783
PySSL_get_session (PySSLSocket * self , void * closure ) {
2815
2784
/* get_session can return sessions from a server-side connection,
2816
2785
* it does not check for handshake done or client socket. */
2817
2786
PySSLSession * pysess ;
2818
2787
SSL_SESSION * session ;
2819
2788
2820
- /* duplicate session as workaround for session bug in OpenSSL 1.1.0,
2821
- * https://github.com/openssl/openssl/issues/1550 */
2822
- session = SSL_get0_session (self -> ssl ); /* borrowed reference */
2823
- if (session == NULL ) {
2824
- Py_RETURN_NONE ;
2825
- }
2826
- if ((session = _ssl_session_dup (session )) == NULL ) {
2827
- return NULL ;
2828
- }
2829
2789
session = SSL_get1_session (self -> ssl );
2830
2790
if (session == NULL ) {
2831
2791
Py_RETURN_NONE ;
@@ -2844,11 +2804,8 @@ PySSL_get_session(PySSLSocket *self, void *closure) {
2844
2804
}
2845
2805
2846
2806
static int PySSL_set_session (PySSLSocket * self , PyObject * value ,
2847
- void * closure )
2848
- {
2807
+ void * closure ) {
2849
2808
PySSLSession * pysess ;
2850
- SSL_SESSION * session ;
2851
- int result ;
2852
2809
2853
2810
if (!Py_IS_TYPE (value , get_state_sock (self )-> PySSLSession_Type )) {
2854
2811
PyErr_SetString (PyExc_TypeError , "Value is not a SSLSession." );
@@ -2871,14 +2828,7 @@ static int PySSL_set_session(PySSLSocket *self, PyObject *value,
2871
2828
"Cannot set session after handshake." );
2872
2829
return -1 ;
2873
2830
}
2874
- /* duplicate session */
2875
- if ((session = _ssl_session_dup (pysess -> session )) == NULL ) {
2876
- return -1 ;
2877
- }
2878
- result = SSL_set_session (self -> ssl , session );
2879
- /* free duplicate, SSL_set_session() bumps ref count */
2880
- SSL_SESSION_free (session );
2881
- if (result == 0 ) {
2831
+ if (SSL_set_session (self -> ssl , pysess -> session ) == 0 ) {
2882
2832
_setSSLError (get_state_sock (self ), NULL , 0 , __FILE__ , __LINE__ );
2883
2833
return -1 ;
2884
2834
}
0 commit comments