mirror of
https://github.com/python/cpython.git
synced 2025-10-02 21:25:24 +00:00
Merged revisions 80392 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk ........ r80392 | antoine.pitrou | 2010-04-23 01:33:02 +0200 (ven., 23 avril 2010) | 9 lines Issue #8108: Fix the unwrap() method of SSL objects when the socket has a non-infinite timeout. Also make that method friendlier with applications wanting to continue using the socket in clear-text mode, by disabling OpenSSL's internal readahead. Thanks to Darryl Miles for guidance. Issue #8108: test_ftplib's non-blocking SSL server now has proper handling of SSL shutdowns. ........
This commit is contained in:
parent
160c6aba4b
commit
07072168fb
2 changed files with 68 additions and 6 deletions
|
@ -33,6 +33,11 @@ Core and Builtins
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- Issue #8108: Fix the unwrap() method of SSL objects when the socket has
|
||||||
|
a non-infinite timeout. Also make that method friendlier with applications
|
||||||
|
wanting to continue using the socket in clear-text mode, by disabling
|
||||||
|
OpenSSL's internal readahead. Thanks to Darryl Miles for guidance.
|
||||||
|
|
||||||
- Issue #8484: Load all ciphers and digest algorithms when initializing
|
- Issue #8484: Load all ciphers and digest algorithms when initializing
|
||||||
the _ssl extension, such that verification of some SSL certificates
|
the _ssl extension, such that verification of some SSL certificates
|
||||||
doesn't fail because of an "unknown algorithm".
|
doesn't fail because of an "unknown algorithm".
|
||||||
|
|
|
@ -9,6 +9,9 @@
|
||||||
directly.
|
directly.
|
||||||
|
|
||||||
XXX should partial writes be enabled, SSL_MODE_ENABLE_PARTIAL_WRITE?
|
XXX should partial writes be enabled, SSL_MODE_ENABLE_PARTIAL_WRITE?
|
||||||
|
|
||||||
|
XXX integrate several "shutdown modes" as suggested in
|
||||||
|
http://bugs.python.org/issue8108#msg102867 ?
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Python.h"
|
#include "Python.h"
|
||||||
|
@ -115,6 +118,7 @@ typedef struct {
|
||||||
X509* peer_cert;
|
X509* peer_cert;
|
||||||
char server[X509_NAME_MAXLEN];
|
char server[X509_NAME_MAXLEN];
|
||||||
char issuer[X509_NAME_MAXLEN];
|
char issuer[X509_NAME_MAXLEN];
|
||||||
|
int shutdown_seen_zero;
|
||||||
|
|
||||||
} PySSLObject;
|
} PySSLObject;
|
||||||
|
|
||||||
|
@ -1337,7 +1341,8 @@ Read up to len bytes from the SSL socket.");
|
||||||
|
|
||||||
static PyObject *PySSL_SSLshutdown(PySSLObject *self)
|
static PyObject *PySSL_SSLshutdown(PySSLObject *self)
|
||||||
{
|
{
|
||||||
int err;
|
int err, ssl_err, sockstate, nonblocking;
|
||||||
|
int zeros = 0;
|
||||||
|
|
||||||
/* Guard against closed socket */
|
/* Guard against closed socket */
|
||||||
if (self->Socket->sock_fd < 0) {
|
if (self->Socket->sock_fd < 0) {
|
||||||
|
@ -1346,13 +1351,65 @@ static PyObject *PySSL_SSLshutdown(PySSLObject *self)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
PySSL_BEGIN_ALLOW_THREADS
|
/* Just in case the blocking state of the socket has been changed */
|
||||||
err = SSL_shutdown(self->ssl);
|
nonblocking = (self->Socket->sock_timeout >= 0.0);
|
||||||
if (err == 0) {
|
BIO_set_nbio(SSL_get_rbio(self->ssl), nonblocking);
|
||||||
/* we need to call it again to finish the shutdown */
|
BIO_set_nbio(SSL_get_wbio(self->ssl), nonblocking);
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
PySSL_BEGIN_ALLOW_THREADS
|
||||||
|
/* Disable read-ahead so that unwrap can work correctly.
|
||||||
|
* Otherwise OpenSSL might read in too much data,
|
||||||
|
* eating clear text data that happens to be
|
||||||
|
* transmitted after the SSL shutdown.
|
||||||
|
* Should be safe to call repeatedly everytime this
|
||||||
|
* function is used and the shutdown_seen_zero != 0
|
||||||
|
* condition is met.
|
||||||
|
*/
|
||||||
|
if (self->shutdown_seen_zero)
|
||||||
|
SSL_set_read_ahead(self->ssl, 0);
|
||||||
err = SSL_shutdown(self->ssl);
|
err = SSL_shutdown(self->ssl);
|
||||||
|
PySSL_END_ALLOW_THREADS
|
||||||
|
/* If err == 1, a secure shutdown with SSL_shutdown() is complete */
|
||||||
|
if (err > 0)
|
||||||
|
break;
|
||||||
|
if (err == 0) {
|
||||||
|
/* Don't loop endlessly; instead preserve legacy
|
||||||
|
behaviour of trying SSL_shutdown() only twice.
|
||||||
|
This looks necessary for OpenSSL < 0.9.8m */
|
||||||
|
if (++zeros > 1)
|
||||||
|
break;
|
||||||
|
/* Shutdown was sent, now try receiving */
|
||||||
|
self->shutdown_seen_zero = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Possibly retry shutdown until timeout or failure */
|
||||||
|
ssl_err = SSL_get_error(self->ssl, err);
|
||||||
|
if (ssl_err == SSL_ERROR_WANT_READ)
|
||||||
|
sockstate = check_socket_and_wait_for_timeout(self->Socket, 0);
|
||||||
|
else if (ssl_err == SSL_ERROR_WANT_WRITE)
|
||||||
|
sockstate = check_socket_and_wait_for_timeout(self->Socket, 1);
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
if (sockstate == SOCKET_HAS_TIMED_OUT) {
|
||||||
|
if (ssl_err == SSL_ERROR_WANT_READ)
|
||||||
|
PyErr_SetString(PySSLErrorObject,
|
||||||
|
"The read operation timed out");
|
||||||
|
else
|
||||||
|
PyErr_SetString(PySSLErrorObject,
|
||||||
|
"The write operation timed out");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
else if (sockstate == SOCKET_TOO_LARGE_FOR_SELECT) {
|
||||||
|
PyErr_SetString(PySSLErrorObject,
|
||||||
|
"Underlying socket too large for select().");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
else if (sockstate != SOCKET_OPERATION_OK)
|
||||||
|
/* Retain the SSL error code */
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
PySSL_END_ALLOW_THREADS
|
|
||||||
|
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return PySSL_SetError(self, err, __FILE__, __LINE__);
|
return PySSL_SetError(self, err, __FILE__, __LINE__);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue