Author: Richard Plangger <planri...@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" _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit