[3.6] bpo-31400: Improve SSL error handling on Windows (GH-3463) (#3466) · python/cpython@16f16db (original) (raw)
`@@ -302,6 +302,11 @@ typedef struct {
`
302
302
`enum py_ssl_server_or_client socket_type;
`
303
303
`PyObject owner; / Python level "owner" passed to servername callback */
`
304
304
`PyObject *server_hostname;
`
``
305
`+
int ssl_errno; /* last seen error from SSL */
`
``
306
`+
int c_errno; /* last seen error from libc */
`
``
307
`+
#ifdef MS_WINDOWS
`
``
308
`+
int ws_errno; /* last seen error from winsock */
`
``
309
`+
#endif
`
305
310
`} PySSLSocket;
`
306
311
``
307
312
`typedef struct {
`
`@@ -321,6 +326,20 @@ static PyTypeObject PySSLSocket_Type;
`
321
326
`static PyTypeObject PySSLMemoryBIO_Type;
`
322
327
`static PyTypeObject PySSLSession_Type;
`
323
328
``
``
329
`+
#ifdef MS_WINDOWS
`
``
330
`+
#define _PySSL_UPDATE_ERRNO_IF(cond, sock, retcode) if (cond) { \
`
``
331
`+
(sock)->ws_errno = WSAGetLastError(); \
`
``
332
`+
(sock)->c_errno = errno; \
`
``
333
`+
(sock)->ssl_errno = SSL_get_error((sock->ssl), (retcode)); \
`
``
334
`+
} else { sock->ws_errno = 0; sock->c_errno = 0; sock->ssl_errno = 0; }
`
``
335
`+
#else
`
``
336
`+
#define _PySSL_UPDATE_ERRNO_IF(cond, sock, retcode) if (cond) { \
`
``
337
`+
(sock)->c_errno = errno; \
`
``
338
`+
(sock)->ssl_errno = SSL_get_error((sock->ssl), (retcode)); \
`
``
339
`+
} else { (sock)->c_errno = 0; (sock)->ssl_errno = 0; }
`
``
340
`+
#endif
`
``
341
`+
#define _PySSL_UPDATE_ERRNO(sock, retcode) _PySSL_UPDATE_ERRNO_IF(1, (sock), (retcode))
`
``
342
+
324
343
`/*[clinic input]
`
325
344
`module _ssl
`
326
345
`class _ssl._SSLContext "PySSLContext *" "&PySSLContext_Type"
`
`@@ -494,7 +513,7 @@ PySSL_SetError(PySSLSocket *obj, int ret, const char *filename, int lineno)
`
494
513
`e = ERR_peek_last_error();
`
495
514
``
496
515
`if (obj->ssl != NULL) {
`
497
``
`-
err = SSL_get_error(obj->ssl, ret);
`
``
516
`+
err = obj->ssl_errno;
`
498
517
``
499
518
`switch (err) {
`
500
519
`case SSL_ERROR_ZERO_RETURN:
`
`@@ -530,8 +549,16 @@ PySSL_SetError(PySSLSocket *obj, int ret, const char *filename, int lineno)
`
530
549
`errstr = "EOF occurred in violation of protocol";
`
531
550
` } else if (s && ret == -1) {
`
532
551
`/* underlying BIO reported an I/O error */
`
533
``
`-
Py_INCREF(s);
`
534
552
`ERR_clear_error();
`
``
553
`+
#ifdef MS_WINDOWS
`
``
554
`+
if (obj->ws_errno)
`
``
555
`+
return PyErr_SetFromWindowsErr(obj->ws_errno);
`
``
556
`+
#endif
`
``
557
`+
if (obj->c_errno) {
`
``
558
`+
errno = obj->c_errno;
`
``
559
`+
return PyErr_SetFromErrno(PyExc_OSError);
`
``
560
`+
}
`
``
561
`+
Py_INCREF(s);
`
535
562
`s->errorhandler();
`
536
563
`Py_DECREF(s);
`
537
564
`return NULL;
`
`@@ -609,6 +636,11 @@ newPySSLSocket(PySSLContext *sslctx, PySocketSockObject *sock,
`
609
636
` }
`
610
637
`self->server_hostname = hostname;
`
611
638
` }
`
``
639
`+
self->ssl_errno = 0;
`
``
640
`+
self->c_errno = 0;
`
``
641
`+
#ifdef MS_WINDOWS
`
``
642
`+
self->ws_errno = 0;
`
``
643
`+
#endif
`
612
644
``
613
645
`/* Make sure the SSL error state is initialized */
`
614
646
` (void) ERR_get_state();
`
`@@ -706,8 +738,9 @@ _ssl__SSLSocket_do_handshake_impl(PySSLSocket *self)
`
706
738
`do {
`
707
739
`PySSL_BEGIN_ALLOW_THREADS
`
708
740
`ret = SSL_do_handshake(self->ssl);
`
709
``
`-
err = SSL_get_error(self->ssl, ret);
`
``
741
`+
_PySSL_UPDATE_ERRNO_IF(ret < 1, self, ret);
`
710
742
`PySSL_END_ALLOW_THREADS
`
``
743
`+
err = self->ssl_errno;
`
711
744
``
712
745
`if (PyErr_CheckSignals())
`
713
746
` goto error;
`
`@@ -2003,8 +2036,9 @@ _ssl__SSLSocket_write_impl(PySSLSocket *self, Py_buffer *b)
`
2003
2036
`do {
`
2004
2037
`PySSL_BEGIN_ALLOW_THREADS
`
2005
2038
`len = SSL_write(self->ssl, b->buf, (int)b->len);
`
2006
``
`-
err = SSL_get_error(self->ssl, len);
`
``
2039
`+
_PySSL_UPDATE_ERRNO_IF(len <= 0, self, len);
`
2007
2040
`PySSL_END_ALLOW_THREADS
`
``
2041
`+
err = self->ssl_errno;
`
2008
2042
``
2009
2043
`if (PyErr_CheckSignals())
`
2010
2044
` goto error;
`
`@@ -2058,6 +2092,7 @@ _ssl__SSLSocket_pending_impl(PySSLSocket *self)
`
2058
2092
``
2059
2093
`PySSL_BEGIN_ALLOW_THREADS
`
2060
2094
`count = SSL_pending(self->ssl);
`
``
2095
`+
_PySSL_UPDATE_ERRNO_IF(count < 0, self, count);
`
2061
2096
`PySSL_END_ALLOW_THREADS
`
2062
2097
`if (count < 0)
`
2063
2098
`return PySSL_SetError(self, count, FILE, LINE);
`
`@@ -2146,7 +2181,7 @@ _ssl__SSLSocket_read_impl(PySSLSocket *self, int len, int group_right_1,
`
2146
2181
`do {
`
2147
2182
`PySSL_BEGIN_ALLOW_THREADS
`
2148
2183
`count = SSL_read(self->ssl, mem, len);
`
2149
``
`-
err = SSL_get_error(self->ssl, count);
`
``
2184
`+
_PySSL_UPDATE_ERRNO_IF(count <= 0, self, count);
`
2150
2185
`PySSL_END_ALLOW_THREADS
`
2151
2186
``
2152
2187
`if (PyErr_CheckSignals())
`
`@@ -2155,6 +2190,7 @@ _ssl__SSLSocket_read_impl(PySSLSocket *self, int len, int group_right_1,
`
2155
2190
`if (has_timeout)
`
2156
2191
`timeout = deadline - _PyTime_GetMonotonicClock();
`
2157
2192
``
``
2193
`+
err = self->ssl_errno;
`
2158
2194
`if (err == SSL_ERROR_WANT_READ) {
`
2159
2195
`sockstate = PySSL_select(sock, 0, timeout);
`
2160
2196
` } else if (err == SSL_ERROR_WANT_WRITE) {
`
`@@ -2211,7 +2247,7 @@ static PyObject *
`
2211
2247
`_ssl__SSLSocket_shutdown_impl(PySSLSocket *self)
`
2212
2248
`/[clinic end generated code: output=ca1aa7ed9d25ca42 input=ede2cc1a2ddf0ee4]/
`
2213
2249
`{
`
2214
``
`-
int err, ssl_err, sockstate, nonblocking;
`
``
2250
`+
int err, sockstate, nonblocking;
`
2215
2251
`int zeros = 0;
`
2216
2252
`PySocketSockObject *sock = GET_SOCKET(self);
`
2217
2253
`_PyTime_t timeout, deadline = 0;
`
`@@ -2250,6 +2286,7 @@ _ssl__SSLSocket_shutdown_impl(PySSLSocket *self)
`
2250
2286
`if (self->shutdown_seen_zero)
`
2251
2287
`SSL_set_read_ahead(self->ssl, 0);
`
2252
2288
`err = SSL_shutdown(self->ssl);
`
``
2289
`+
_PySSL_UPDATE_ERRNO_IF(err < 0, self, err);
`
2253
2290
`PySSL_END_ALLOW_THREADS
`
2254
2291
``
2255
2292
`/* If err == 1, a secure shutdown with SSL_shutdown() is complete */
`
`@@ -2270,16 +2307,16 @@ _ssl__SSLSocket_shutdown_impl(PySSLSocket *self)
`
2270
2307
`timeout = deadline - _PyTime_GetMonotonicClock();
`
2271
2308
``
2272
2309
`/* Possibly retry shutdown until timeout or failure */
`
2273
``
`-
ssl_err = SSL_get_error(self->ssl, err);
`
2274
``
`-
if (ssl_err == SSL_ERROR_WANT_READ)
`
``
2310
`+
_PySSL_UPDATE_ERRNO(self, err);
`
``
2311
`+
if (self->ssl_errno == SSL_ERROR_WANT_READ)
`
2275
2312
`sockstate = PySSL_select(sock, 0, timeout);
`
2276
``
`-
else if (ssl_err == SSL_ERROR_WANT_WRITE)
`
``
2313
`+
else if (self->ssl_errno == SSL_ERROR_WANT_WRITE)
`
2277
2314
`sockstate = PySSL_select(sock, 1, timeout);
`
2278
2315
`else
`
2279
2316
`break;
`
2280
2317
``
2281
2318
`if (sockstate == SOCKET_HAS_TIMED_OUT) {
`
2282
``
`-
if (ssl_err == SSL_ERROR_WANT_READ)
`
``
2319
`+
if (self->ssl_errno == SSL_ERROR_WANT_READ)
`
2283
2320
`PyErr_SetString(PySocketModule.timeout_error,
`
2284
2321
`"The read operation timed out");
`
2285
2322
`else
`