[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

`