[pypy-commit] pypy py3.5-ssl: passing all tests in test_ssl.py
plan_rich
pypy.commits at gmail.com
Thu Nov 17 07:34:54 EST 2016
Author: Richard Plangger <planrichi at gmail.com>
Branch: py3.5-ssl
Changeset: r88428:d9f42756c388
Date: 2016-11-17 13:34 +0100
http://bitbucket.org/pypy/pypy/changeset/d9f42756c388/
Log: passing all tests in test_ssl.py
diff --git a/lib_pypy/openssl/_cffi_src/openssl/bio.py b/lib_pypy/openssl/_cffi_src/openssl/bio.py
--- a/lib_pypy/openssl/_cffi_src/openssl/bio.py
+++ b/lib_pypy/openssl/_cffi_src/openssl/bio.py
@@ -82,6 +82,8 @@
int BIO_write(BIO *, const void *, int);
int BIO_puts(BIO *, const char *);
int BIO_method_type(const BIO *);
+
+int * Cryptography_bio_references(const BIO *);
"""
MACROS = """
@@ -132,7 +134,12 @@
long BIO_set_nbio(BIO *, long);
void BIO_set_retry_read(BIO *);
void BIO_clear_retry_flags(BIO *);
+
+#define CRYPTO_LOCK_BIO ...
"""
CUSTOMIZATIONS = """
+int * Cryptography_bio_references(const BIO * b) {
+ return &b->references;
+}
"""
diff --git a/lib_pypy/openssl/_cffi_src/openssl/crypto.py b/lib_pypy/openssl/_cffi_src/openssl/crypto.py
--- a/lib_pypy/openssl/_cffi_src/openssl/crypto.py
+++ b/lib_pypy/openssl/_cffi_src/openssl/crypto.py
@@ -57,6 +57,8 @@
/* This was removed in 1.1.0 */
void CRYPTO_lock(int, int, const char *, int);
+
+void CRYPTO_add(void*,int,int);
"""
CUSTOMIZATIONS = """
diff --git a/lib_pypy/openssl/_stdssl/__init__.py b/lib_pypy/openssl/_stdssl/__init__.py
--- a/lib_pypy/openssl/_stdssl/__init__.py
+++ b/lib_pypy/openssl/_stdssl/__init__.py
@@ -98,6 +98,10 @@
# TODO threads?
lib.OpenSSL_add_all_algorithms()
+def check_signals():
+ # TODO PyErr_CheckSignal equivalent for pypy?
+ pass
+
def _socket_timeout(s):
if s is None:
return 0.0
@@ -218,13 +222,14 @@
if sock:
lib.SSL_set_fd(ssl, sock.fileno())
else:
- raise NotImplementedError("implement _SSLSocket inbio, outbio params")
- # /* BIOs are reference counted and SSL_set_bio borrows our reference.
- # * To prevent a double free in memory_bio_dealloc() we need to take an
- # * extra reference here. */
- # CRYPTO_add(&inbio->bio->references, 1, CRYPTO_LOCK_BIO);
- # CRYPTO_add(&outbio->bio->references, 1, CRYPTO_LOCK_BIO);
- # SSL_set_bio(self->ssl, inbio->bio, outbio->bio);
+ # BIOs are reference counted and SSL_set_bio borrows our reference.
+ # To prevent a double free in memory_bio_dealloc() we need to take an
+ # extra reference here.
+ irefaddr = lib.Cryptography_bio_references(inbio.bio);
+ orefaddr = lib.Cryptography_bio_references(outbio.bio);
+ lib.CRYPTO_add(irefaddr, 1, lib.CRYPTO_LOCK_BIO)
+ lib.CRYPTO_add(orefaddr, 1, lib.CRYPTO_LOCK_BIO)
+ lib.SSL_set_bio(self.ssl, inbio.bio, outbio.bio)
mode = lib.SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER
if lib.SSL_MODE_AUTO_RETRY:
@@ -287,12 +292,17 @@
@context.setter
def context(self, value):
- self.ctx = value
+ if isinstance(value, _SSLContext):
+ if not HAS_SNI:
+ raise NotImplementedError("setting a socket's "
+ "context is not supported by your OpenSSL library")
+ self.ctx = value
+ lib.SSL_set_SSL_CTX(self.ssl, self.ctx.ctx);
+ else:
+ raise TypeError("The value must be a SSLContext")
def do_handshake(self):
- sock = self.get_socket_or_None()
- if sock is None:
- raise ssl_error("Underlying socket connection gone", SSL_ERROR_NO_SOCKET)
+ sock = self.get_socket_or_connection_gone()
ssl = self.ssl
timeout = _socket_timeout(sock)
if sock:
@@ -313,8 +323,7 @@
err = lib.SSL_get_error(ssl, ret)
# end allow threads
- #if (PyErr_CheckSignals())
- # goto error;
+ check_signals()
if has_timeout:
# REIVIEW monotonic clock?
@@ -399,8 +408,7 @@
err = lib.SSL_get_error(self.ssl, length)
#PySSL_END_ALLOW_THREADS
- # TODO if (PyErr_CheckSignals())
- # TODO goto error;
+ check_signals()
if has_timeout:
# TODO monotonic clock
@@ -428,14 +436,12 @@
raise pyssl_error(self, length)
def read(self, length, buffer_into=None):
- sock = self.get_socket_or_None()
ssl = self.ssl
if length < 0 and buffer_into is None:
raise ValueError("size should not be negative")
- if sock is None:
- raise ssl_error("Underlying socket connection gone", SSL_ERROR_NO_SOCKET)
+ sock = self.get_socket_or_connection_gone()
if not buffer_into:
dest = _buffer_new(length)
@@ -467,9 +473,7 @@
err = lib.SSL_get_error(self.ssl, count);
#PySSL_END_ALLOW_THREADS
- # TODO
- #if (PyErr_CheckSignals())
- # goto error;
+ check_signals()
if has_timeout:
timeout = deadline - time.time() # TODO ? _PyTime_GetMonotonicClock();
@@ -512,9 +516,10 @@
def shared_ciphers(self):
sess = lib.SSL_get_session(self.ssl)
-
+ if sess == ffi.NULL:
+ return None
ciphers = lib.Cryptography_get_ssl_session_ciphers(sess)
- if sess is None or ciphers == ffi.NULL:
+ if ciphers == ffi.NULL:
return None
res = []
count = lib.sk_SSL_CIPHER_num(ciphers)
@@ -559,18 +564,28 @@
return self.socket()
def get_socket_or_connection_gone(self):
+ """ There are three states:
+ 1) self.socket is None (In C that would mean: self->Socket == NULL)
+ 2) self.socket() is None (-> The socket is gone)
+ 3) self.socket() is not None
+ This method returns True if there is not weakref object allocated
+ """
if self.socket is None:
+ return None
+ sock = self.socket()
+ if not sock:
raise ssl_error("Underlying socket connection gone", SSL_ERROR_NO_SOCKET)
- return self.socket()
+ return sock
def shutdown(self):
sock = self.get_socket_or_None()
nonblocking = False
ssl = self.ssl
- if sock is not None:
+ if self.socket is not None:
# Guard against closed socket
- if sock.fileno() < 0:
+ sock = self.socket()
+ if sock is None or sock.fileno() < 0:
raise ssl_error("Underlying socket connection gone", SSL_ERROR_NO_SOCKET)
timeout = _socket_timeout(sock)
@@ -1129,7 +1144,6 @@
"is not in the current OpenSSL library.")
if callback is None:
lib.SSL_CTX_set_tlsext_servername_callback(self.ctx, ffi.NULL)
- self.set_hostname = None
self._set_hostname_handle = None
return
if not callable(callback):
@@ -1161,6 +1175,16 @@
else:
raise NotImplementedError("The NPN extension requires OpenSSL 1.0.1 or later.")
+ def _wrap_bio(self, incoming, outgoing, server_side, server_hostname):
+ # server_hostname is either None (or absent), or to be encoded
+ # using the idna encoding.
+ hostname = None
+ if server_hostname is not None:
+ hostname = server_hostname.encode("idna")
+
+ sock = _SSLSocket._new__ssl_socket(self, None, server_side, hostname, incoming, outgoing)
+ return sock
+
if HAS_SNI and not lib.Cryptography_NO_TLSEXT:
@@ -1360,15 +1384,16 @@
def _RAND_bytes(count, pseudo):
if count < 0:
raise ValueError("num must be positive")
- buf = ffi.new("unsigned char[]", b"\x00"*count)
+ buf = ffi.new("unsigned char[%d]" % count)
if pseudo:
ok = lib.RAND_pseudo_bytes(buf, count)
if ok == 1 or ok == 0:
- return (ffi.string(buf), ok == 1)
+ _bytes = _bytes_with_len(buf, count)
+ return (_bytes, ok == 1)
else:
ok = lib.RAND_bytes(buf, count)
if ok == 1:
- return ffi.string(buf)
+ return _bytes_with_len(buf, count)
raise ssl_error(None, errcode=lib.ERR_get_error())
def RAND_pseudo_bytes(count):
diff --git a/lib_pypy/openssl/_stdssl/error.py b/lib_pypy/openssl/_stdssl/error.py
--- a/lib_pypy/openssl/_stdssl/error.py
+++ b/lib_pypy/openssl/_stdssl/error.py
@@ -101,14 +101,18 @@
errval = SSL_ERROR_WANT_CONNECT
elif err == SSL_ERROR_SYSCALL:
if e == 0:
- if ret == 0 or obj.get_socket_or_None() is None:
- errtype = EOFError
+ if ret == 0 or obj.socket is not None:
+ errtype = SSLEOFError
errstr = "EOF occurred in violation of protocol"
errval = SSL_ERROR_EOF
- elif ret == -1:
+ elif ret == -1 and obj.socket is not None:
# the underlying BIO reported an I/0 error
- errno = ffi.errno
- return IOError(errno)
+ lib.ERR_clear_error()
+ s = obj.get_socket_or_None()
+ s.errorhandler()
+ assert 0, "must not get here"
+ #errno = ffi.errno
+ #return IOError(errno)
else:
errtype = SSLSyscallError
errstr = "Some I/O error occurred"
More information about the pypy-commit
mailing list