Author: Richard Plangger <planri...@gmail.com> Branch: ppc-vsx-support Changeset: r88063:a51b31b31124 Date: 2016-11-02 11:34 +0100 http://bitbucket.org/pypy/pypy/changeset/a51b31b31124/
Log: merge default diff --git a/lib-python/2.7/test/test_ssl.py b/lib-python/2.7/test/test_ssl.py --- a/lib-python/2.7/test/test_ssl.py +++ b/lib-python/2.7/test/test_ssl.py @@ -26,6 +26,8 @@ PROTOCOLS = sorted(ssl._PROTOCOL_NAMES) HOST = support.HOST +IS_LIBRESSL = ssl.OPENSSL_VERSION.startswith('LibreSSL') +IS_OPENSSL_1_1 = not IS_LIBRESSL and ssl.OPENSSL_VERSION_INFO >= (1, 1, 0) def data_file(*name): return os.path.join(os.path.dirname(__file__), *name) @@ -742,15 +744,15 @@ def test_options(self): ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) # OP_ALL | OP_NO_SSLv2 | OP_NO_SSLv3 is the default value - self.assertEqual(ssl.OP_ALL | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3, - ctx.options) + default = (ssl.OP_ALL | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3) + if not IS_LIBRESSL and ssl.OPENSSL_VERSION_INFO >= (1, 1, 0): + default |= ssl.OP_NO_COMPRESSION + self.assertEqual(default, ctx.options) ctx.options |= ssl.OP_NO_TLSv1 - self.assertEqual(ssl.OP_ALL | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3 | ssl.OP_NO_TLSv1, - ctx.options) + self.assertEqual(default | ssl.OP_NO_TLSv1, ctx.options) if can_clear_options(): - ctx.options = (ctx.options & ~ssl.OP_NO_SSLv2) | ssl.OP_NO_TLSv1 - self.assertEqual(ssl.OP_ALL | ssl.OP_NO_TLSv1 | ssl.OP_NO_SSLv3, - ctx.options) + ctx.options = (ctx.options & ~ssl.OP_NO_TLSv1) + self.assertEqual(default, ctx.options) ctx.options = 0 self.assertEqual(0, ctx.options) else: @@ -2918,18 +2920,27 @@ client_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) client_context.load_cert_chain(CERTFILE) client_context.set_alpn_protocols(client_protocols) - stats = server_params_test(client_context, server_context, - chatty=True, connectionchatty=True) - - msg = "failed trying %s (s) and %s (c).\n" \ - "was expecting %s, but got %%s from the %%s" \ - % (str(server_protocols), str(client_protocols), - str(expected)) - client_result = stats['client_alpn_protocol'] - self.assertEqual(client_result, expected, msg % (client_result, "client")) - server_result = stats['server_alpn_protocols'][-1] \ - if len(stats['server_alpn_protocols']) else 'nothing' - self.assertEqual(server_result, expected, msg % (server_result, "server")) + try: + stats = server_params_test(client_context, server_context, + chatty=True, connectionchatty=True) + except ssl.SSLError as e: + stats = e + + if expected is None and IS_OPENSSL_1_1: + # OpenSSL 1.1.0 raises handshake error + self.assertIsInstance(stats, ssl.SSLError) + else: + msg = "failed trying %s (s) and %s (c).\n" \ + "was expecting %s, but got %%s from the %%s" \ + % (str(server_protocols), str(client_protocols), + str(expected)) + client_result = stats['client_alpn_protocol'] + self.assertEqual(client_result, expected, + msg % (client_result, "client")) + server_result = stats['server_alpn_protocols'][-1] \ + if len(stats['server_alpn_protocols']) else 'nothing' + self.assertEqual(server_result, expected, + msg % (server_result, "server")) def test_selected_npn_protocol(self): # selected_npn_protocol() is None unless NPN is used diff --git a/lib_pypy/cffi.egg-info/PKG-INFO b/lib_pypy/cffi.egg-info/PKG-INFO --- a/lib_pypy/cffi.egg-info/PKG-INFO +++ b/lib_pypy/cffi.egg-info/PKG-INFO @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: cffi -Version: 1.8.4 +Version: 1.9.0 Summary: Foreign Function Interface for Python calling C code. Home-page: http://cffi.readthedocs.org Author: Armin Rigo, Maciej Fijalkowski diff --git a/lib_pypy/cffi/__init__.py b/lib_pypy/cffi/__init__.py --- a/lib_pypy/cffi/__init__.py +++ b/lib_pypy/cffi/__init__.py @@ -4,8 +4,8 @@ from .api import FFI, CDefError, FFIError from .ffiplatform import VerificationError, VerificationMissing -__version__ = "1.8.4" -__version_info__ = (1, 8, 4) +__version__ = "1.9.0" +__version_info__ = (1, 9, 0) # The verifier module file names are based on the CRC32 of a string that # contains the following version number. It may be older than __version__ diff --git a/lib_pypy/cffi/_embedding.h b/lib_pypy/cffi/_embedding.h --- a/lib_pypy/cffi/_embedding.h +++ b/lib_pypy/cffi/_embedding.h @@ -233,7 +233,7 @@ f = PySys_GetObject((char *)"stderr"); if (f != NULL && f != Py_None) { PyFile_WriteString("\nFrom: " _CFFI_MODULE_NAME - "\ncompiled with cffi version: 1.8.4" + "\ncompiled with cffi version: 1.9.0" "\n_cffi_backend module: ", f); modules = PyImport_GetModuleDict(); mod = PyDict_GetItemString(modules, "_cffi_backend"); diff --git a/pypy/doc/release-pypy2.7-v5.6.0.rst b/pypy/doc/release-pypy2.7-v5.6.0.rst --- a/pypy/doc/release-pypy2.7-v5.6.0.rst +++ b/pypy/doc/release-pypy2.7-v5.6.0.rst @@ -16,6 +16,9 @@ We changed ``timeit`` to now report average +- standard deviation, which is better than the misleading minimum value reported in CPython. +We now support building PyPy with OpenSSL 1.1 in our built-in _sll module, as +well as maintaining support for previous versions. + XXX As always, this release fixed many issues and bugs raised by the @@ -72,7 +75,7 @@ * New features * Allow tests run with `-A` to find `libm.so` even if it is a script not a dynamically loadable file - * Backport fixes to rposix on windows from py2.5 + * Backport fixes to rposix on windows from py3.5 * Allow user-defined ``__getitem__`` on subclasses of ``str`` and ``unicode`` * Add ``inode`` to ``scandir()`` on posix systems * Support more attributes on ``super`` @@ -98,6 +101,8 @@ * Support translation on FreeBSD running on PowerPC * Implement ``__rmod__`` on ``str`` and ``unicode`` types * Issue warnings for stricter handling of ``__new__``, ``__init__`` args + * When using ``struct.unpack('q', ...`` try harder to prefer int to long + * Support OpenSSL version 1.1 (in addition to version 1.0) * Bug Fixes * Tweak a float comparison with 0 in `backendopt.inline` to avoid rounding errors diff --git a/pypy/module/_cffi_backend/__init__.py b/pypy/module/_cffi_backend/__init__.py --- a/pypy/module/_cffi_backend/__init__.py +++ b/pypy/module/_cffi_backend/__init__.py @@ -3,7 +3,7 @@ from rpython.rlib import rdynload, clibffi, entrypoint from rpython.rtyper.lltypesystem import rffi -VERSION = "1.8.4" +VERSION = "1.9.0" FFI_DEFAULT_ABI = clibffi.FFI_DEFAULT_ABI try: diff --git a/pypy/module/_cffi_backend/test/_backend_test_c.py b/pypy/module/_cffi_backend/test/_backend_test_c.py --- a/pypy/module/_cffi_backend/test/_backend_test_c.py +++ b/pypy/module/_cffi_backend/test/_backend_test_c.py @@ -1,7 +1,7 @@ # ____________________________________________________________ import sys -assert __version__ == "1.8.4", ("This test_c.py file is for testing a version" +assert __version__ == "1.9.0", ("This test_c.py file is for testing a version" " of cffi that differs from the one that we" " get from 'import _cffi_backend'") if sys.version_info < (3,): diff --git a/pypy/module/_hashlib/__init__.py b/pypy/module/_hashlib/__init__.py --- a/pypy/module/_hashlib/__init__.py +++ b/pypy/module/_hashlib/__init__.py @@ -1,5 +1,6 @@ from pypy.interpreter.mixedmodule import MixedModule -from pypy.module._hashlib.interp_hashlib import algorithms, fetch_names +from pypy.module._hashlib.interp_hashlib import ( + algorithms, fetch_names, HAS_FAST_PKCS5_PBKDF2_HMAC) class Module(MixedModule): @@ -13,6 +14,9 @@ for name in algorithms: interpleveldefs['openssl_' + name] = 'interp_hashlib.new_' + name + if HAS_FAST_PKCS5_PBKDF2_HMAC: + interpleveldefs['pbkdf2_hmac'] = 'interp_hashlib.pbkdf2_hmac' + def startup(self, space): w_meth_names = fetch_names(space) space.setattr(self, space.wrap('openssl_md_meth_names'), w_meth_names) diff --git a/pypy/module/_hashlib/interp_hashlib.py b/pypy/module/_hashlib/interp_hashlib.py --- a/pypy/module/_hashlib/interp_hashlib.py +++ b/pypy/module/_hashlib/interp_hashlib.py @@ -8,7 +8,7 @@ from pypy.interpreter.baseobjspace import W_Root from pypy.interpreter.error import OperationError, oefmt -from pypy.interpreter.gateway import unwrap_spec, interp2app +from pypy.interpreter.gateway import unwrap_spec, interp2app, WrappedDefault from pypy.interpreter.typedef import TypeDef, GetSetProperty from pypy.module.thread.os_lock import Lock @@ -58,23 +58,26 @@ def __init__(self, space, name, copy_from=NULL_CTX): self.name = name digest_type = self.digest_type_by_name(space) - self.digest_size = rffi.getintfield(digest_type, 'c_md_size') + self.digest_size = ropenssl.EVP_MD_size(digest_type) # Allocate a lock for each HASH object. # An optimization would be to not release the GIL on small requests, # and use a custom lock only when needed. self.lock = Lock(space) - ctx = lltype.malloc(ropenssl.EVP_MD_CTX.TO, flavor='raw') + ctx = ropenssl.EVP_MD_CTX_new() + if ctx is None: + raise MemoryError rgc.add_memory_pressure(ropenssl.HASH_MALLOC_SIZE + self.digest_size) try: if copy_from: - ropenssl.EVP_MD_CTX_copy(ctx, copy_from) + if not ropenssl.EVP_MD_CTX_copy(ctx, copy_from): + raise ValueError else: ropenssl.EVP_DigestInit(ctx, digest_type) self.ctx = ctx except: - lltype.free(ctx, flavor='raw') + ropenssl.EVP_MD_CTX_free(ctx) raise self.register_finalizer(space) @@ -82,8 +85,7 @@ ctx = self.ctx if ctx: self.ctx = lltype.nullptr(ropenssl.EVP_MD_CTX.TO) - ropenssl.EVP_MD_CTX_cleanup(ctx) - lltype.free(ctx, flavor='raw') + ropenssl.EVP_MD_CTX_free(ctx) def digest_type_by_name(self, space): digest_type = ropenssl.EVP_get_digestbyname(self.name) @@ -128,21 +130,26 @@ def get_block_size(self, space): digest_type = self.digest_type_by_name(space) - block_size = rffi.getintfield(digest_type, 'c_block_size') + block_size = ropenssl.EVP_MD_block_size(digest_type) return space.wrap(block_size) def get_name(self, space): return space.wrap(self.name) def _digest(self, space): - with lltype.scoped_alloc(ropenssl.EVP_MD_CTX.TO) as ctx: + ctx = ropenssl.EVP_MD_CTX_new() + if ctx is None: + raise MemoryError + try: with self.lock: - ropenssl.EVP_MD_CTX_copy(ctx, self.ctx) + if not ropenssl.EVP_MD_CTX_copy(ctx, self.ctx): + raise ValueError digest_size = self.digest_size with rffi.scoped_alloc_buffer(digest_size) as buf: ropenssl.EVP_DigestFinal(ctx, buf.raw, None) - ropenssl.EVP_MD_CTX_cleanup(ctx) return buf.str(digest_size) + finally: + ropenssl.EVP_MD_CTX_free(ctx) W_Hash.typedef = TypeDef( @@ -177,3 +184,27 @@ for _name in algorithms: _newname = 'new_%s' % (_name,) globals()[_newname] = make_new_hash(_name, _newname) + + +HAS_FAST_PKCS5_PBKDF2_HMAC = ropenssl.PKCS5_PBKDF2_HMAC is not None +if HAS_FAST_PKCS5_PBKDF2_HMAC: + @unwrap_spec(name=str, password=str, salt=str, rounds=int, + w_dklen=WrappedDefault(None)) + def pbkdf2_hmac(space, name, password, salt, rounds, w_dklen): + digest = ropenssl.EVP_get_digestbyname(name) + if not digest: + raise oefmt(space.w_ValueError, "unknown hash function") + if space.is_w(w_dklen, space.w_None): + dklen = ropenssl.EVP_MD_size(digest) + else: + dklen = space.int_w(w_dklen) + if dklen < 1: + raise oefmt(space.w_ValueError, + "key length must be greater than 0.") + with rffi.scoped_alloc_buffer(dklen) as buf: + r = ropenssl.PKCS5_PBKDF2_HMAC( + password, len(password), salt, len(salt), rounds, digest, + dklen, buf.raw) + if not r: + raise ValueError + return space.wrap(buf.str(dklen)) diff --git a/pypy/module/_hashlib/test/test_hashlib.py b/pypy/module/_hashlib/test/test_hashlib.py --- a/pypy/module/_hashlib/test/test_hashlib.py +++ b/pypy/module/_hashlib/test/test_hashlib.py @@ -15,17 +15,19 @@ def test_attributes(self): import hashlib - for name, expected_size in {'md5': 16, - 'sha1': 20, - 'sha224': 28, - 'sha256': 32, - 'sha384': 48, - 'sha512': 64, - }.items(): + for name, (expected_size, expected_block_size) in { + 'md5': (16, 64), + 'sha1': (20, 64), + 'sha224': (28, 64), + 'sha256': (32, 64), + 'sha384': (48, 128), + 'sha512': (64, 128), + }.items(): h = hashlib.new(name) assert h.name == name assert h.digest_size == expected_size assert h.digestsize == expected_size + assert h.block_size == expected_block_size # h.update('abc') h2 = h.copy() @@ -46,6 +48,7 @@ h = py_new(name)('') assert h.digest_size == expected_size assert h.digestsize == expected_size + assert h.block_size == expected_block_size # h.update('abc') h2 = h.copy() @@ -108,3 +111,13 @@ got.decode('hex') if expected is not None: assert got == expected + + def test_pbkdf2(self): + try: + from _hashlib import pbkdf2_hmac + except ImportError: + skip("Requires OpenSSL >= 1.1") + out = pbkdf2_hmac('sha1', 'password', 'salt', 1) + assert out == '0c60c80f961f0e71f3a9b524af6012062fe037a6'.decode('hex') + out = pbkdf2_hmac('sha1', 'password', 'salt', 2, None) + assert out == 'ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957'.decode('hex') diff --git a/pypy/module/_ssl/interp_ssl.py b/pypy/module/_ssl/interp_ssl.py --- a/pypy/module/_ssl/interp_ssl.py +++ b/pypy/module/_ssl/interp_ssl.py @@ -33,9 +33,10 @@ PY_SSL_CLIENT, PY_SSL_SERVER = 0, 1 (PY_SSL_VERSION_SSL2, PY_SSL_VERSION_SSL3, - PY_SSL_VERSION_SSL23, PY_SSL_VERSION_TLS1, PY_SSL_VERSION_TLS1_1, + PY_SSL_VERSION_TLS, PY_SSL_VERSION_TLS1, PY_SSL_VERSION_TLS1_1, PY_SSL_VERSION_TLS1_2) = range(6) + SOCKET_IS_NONBLOCKING, SOCKET_IS_BLOCKING = 0, 1 SOCKET_HAS_TIMED_OUT, SOCKET_HAS_BEEN_CLOSED = 2, 3 SOCKET_TOO_LARGE_FOR_SELECT, SOCKET_OPERATION_OK = 4, 5 @@ -68,11 +69,12 @@ constants["HAS_NPN"] = HAS_NPN constants["HAS_ALPN"] = HAS_ALPN +constants["PROTOCOL_TLS"] = PY_SSL_VERSION_TLS +constants["PROTOCOL_SSLv23"] = PY_SSL_VERSION_TLS # Legacy name if not OPENSSL_NO_SSL2: constants["PROTOCOL_SSLv2"] = PY_SSL_VERSION_SSL2 if not OPENSSL_NO_SSL3: constants["PROTOCOL_SSLv3"] = PY_SSL_VERSION_SSL3 -constants["PROTOCOL_SSLv23"] = PY_SSL_VERSION_SSL23 constants["PROTOCOL_TLSv1"] = PY_SSL_VERSION_TLS1 if HAVE_TLSv1_2: constants["PROTOCOL_TLSv1_1"] = PY_SSL_VERSION_TLS1_1 @@ -111,7 +113,10 @@ err_reason = libssl_ERR_GET_REASON(errcode) reason_str = ERROR_CODES_TO_NAMES.get((err_lib, err_reason), None) lib_str = LIBRARY_CODES_TO_NAMES.get(err_lib, None) - msg = rffi.charp2str(libssl_ERR_reason_error_string(errcode)) + raw_msg = libssl_ERR_reason_error_string(errcode) + msg = None + if raw_msg: + msg = rffi.charp2str(raw_msg) if not msg: msg = "unknown error" if reason_str and lib_str: @@ -637,9 +642,12 @@ if not self.ssl: return space.w_None comp_method = libssl_SSL_get_current_compression(self.ssl) - if not comp_method or intmask(comp_method[0].c_type) == NID_undef: + if not comp_method: return space.w_None - short_name = libssl_OBJ_nid2sn(comp_method[0].c_type) + method_type = intmask(libssl_COMP_get_type(comp_method)) + if method_type == NID_undef: + return space.w_None + short_name = libssl_COMP_get_name(comp_method) if not short_name: return space.w_None return space.wrap(rffi.charp2str(short_name)) @@ -795,7 +803,7 @@ for index in range(entry_count): entry = libssl_X509_NAME_get_entry(xname, index) # check to see if we've gotten to a new RDN - entry_level = intmask(entry[0].c_set) + entry_level = intmask(libssl_X509_NAME_ENTRY_set(entry)) if rdn_level >= 0: if rdn_level != entry_level: # yes, new RDN @@ -846,8 +854,9 @@ "No method for internalizing subjectAltName!'") with lltype.scoped_alloc(rffi.CCHARPP.TO, 1) as p_ptr: - p_ptr[0] = ext[0].c_value.c_data - length = intmask(ext[0].c_value.c_length) + ext_value = libssl_X509_EXTENSION_get_data(ext) + p_ptr[0] = ext_value.c_data + length = intmask(ext_value.c_length) null = lltype.nullptr(rffi.VOIDP.TO) if method[0].c_it: names = rffi.cast(GENERAL_NAMES, libssl_ASN1_item_d2i( @@ -967,10 +976,8 @@ if OPENSSL_VERSION_NUMBER >= 0x10001000: # Calls x509v3_cache_extensions and sets up crldp libssl_X509_check_ca(certificate) - dps = certificate[0].c_crldp - else: - dps = rffi.cast(stack_st_DIST_POINT, libssl_X509_get_ext_d2i( - certificate, NID_crl_distribution_points, None, None)) + dps = rffi.cast(stack_st_DIST_POINT, libssl_X509_get_ext_d2i( + certificate, NID_crl_distribution_points, None, None)) if not dps: return None @@ -1268,14 +1275,14 @@ @staticmethod @unwrap_spec(protocol=int) def descr_new(space, w_subtype, protocol): - if protocol == PY_SSL_VERSION_TLS1: + if protocol == PY_SSL_VERSION_TLS: + method = libssl_TLS_method() + elif protocol == PY_SSL_VERSION_TLS1: method = libssl_TLSv1_method() elif protocol == PY_SSL_VERSION_SSL3 and not OPENSSL_NO_SSL3: method = libssl_SSLv3_method() elif protocol == PY_SSL_VERSION_SSL2 and not OPENSSL_NO_SSL2: method = libssl_SSLv2_method() - elif protocol == PY_SSL_VERSION_SSL23: - method = libssl_SSLv23_method() elif protocol == PY_SSL_VERSION_TLS1_1 and HAVE_TLSv1_2: method = libssl_TLSv1_1_method() elif protocol == PY_SSL_VERSION_TLS1_2 and HAVE_TLSv1_2: @@ -1303,6 +1310,7 @@ # OpenSSL 1.0.2+), or use prime256v1 by default. # This is Apache mod_ssl's initialization # policy, so we should be safe. + # OpenSSL 1.1 has it enabled by default. if libssl_SSL_CTX_set_ecdh_auto: libssl_SSL_CTX_set_ecdh_auto(self.ctx, 1) else: @@ -1390,20 +1398,22 @@ def descr_get_verify_flags(self, space): store = libssl_SSL_CTX_get_cert_store(self.ctx) - flags = libssl_X509_VERIFY_PARAM_get_flags(store[0].c_param) + param = libssl_X509_STORE_get0_param(store) + flags = libssl_X509_VERIFY_PARAM_get_flags(param) return space.wrap(flags) def descr_set_verify_flags(self, space, w_obj): new_flags = space.int_w(w_obj) store = libssl_SSL_CTX_get_cert_store(self.ctx) - flags = libssl_X509_VERIFY_PARAM_get_flags(store[0].c_param) + param = libssl_X509_STORE_get0_param(store) + flags = libssl_X509_VERIFY_PARAM_get_flags(param) flags_clear = flags & ~new_flags flags_set = ~flags & new_flags if flags_clear and not libssl_X509_VERIFY_PARAM_clear_flags( - store[0].c_param, flags_clear): + param, flags_clear): raise _ssl_seterror(space, None, 0) if flags_set and not libssl_X509_VERIFY_PARAM_set_flags( - store[0].c_param, flags_set): + param, flags_set): raise _ssl_seterror(space, None, 0) def descr_get_check_hostname(self, space): @@ -1614,14 +1624,16 @@ x509 = 0 x509_ca = 0 crl = 0 - for i in range(libssl_sk_X509_OBJECT_num(store[0].c_objs)): - obj = libssl_sk_X509_OBJECT_value(store[0].c_objs, i) - if intmask(obj.c_type) == X509_LU_X509: + objs = libssl_X509_STORE_get0_objects(store) + for i in range(libssl_sk_X509_OBJECT_num(objs)): + obj = libssl_sk_X509_OBJECT_value(objs, i) + obj_type = intmask(libssl_X509_OBJECT_get_type(obj)) + if obj_type == X509_LU_X509: x509 += 1 if libssl_X509_check_ca( - libssl_pypy_X509_OBJECT_data_x509(obj)): + libssl_X509_OBJECT_get0_X509(obj)): x509_ca += 1 - elif intmask(obj.c_type) == X509_LU_CRL: + elif obj_type == X509_LU_CRL: crl += 1 else: # Ignore X509_LU_FAIL, X509_LU_RETRY, X509_LU_PKEY. @@ -1660,13 +1672,14 @@ binary_mode = False rlist = [] store = libssl_SSL_CTX_get_cert_store(self.ctx) - for i in range(libssl_sk_X509_OBJECT_num(store[0].c_objs)): - obj = libssl_sk_X509_OBJECT_value(store[0].c_objs, i) - if intmask(obj.c_type) != X509_LU_X509: + objs = libssl_X509_STORE_get0_objects(store) + for i in range(libssl_sk_X509_OBJECT_num(objs)): + obj = libssl_sk_X509_OBJECT_value(objs, i) + if intmask(libssl_X509_OBJECT_get_type(obj)) != X509_LU_X509: # not a x509 cert continue # CA for any purpose - cert = libssl_pypy_X509_OBJECT_data_x509(obj) + cert = libssl_X509_OBJECT_get0_X509(obj) if not libssl_X509_check_ca(cert): continue if binary_mode: diff --git a/pypy/module/_ssl/test/test_ssl.py b/pypy/module/_ssl/test/test_ssl.py --- a/pypy/module/_ssl/test/test_ssl.py +++ b/pypy/module/_ssl/test/test_ssl.py @@ -77,7 +77,7 @@ if sys.version_info < (2, 7, 9): ss = _ssl.sslwrap(s, 0) else: - ctx = _ssl._SSLContext(_ssl.PROTOCOL_TLSv1) + ctx = _ssl._SSLContext(_ssl.PROTOCOL_TLS) ss = ctx._wrap_socket(s, 0) assert ss.context is ctx exc = raises(_socket.error, ss.do_handshake) @@ -95,7 +95,7 @@ if sys.version_info < (2, 7, 9): ss = _ssl.sslwrap(s, 0) else: - ss = _ssl._SSLContext(_ssl.PROTOCOL_TLSv1)._wrap_socket(s, 0) + ss = _ssl._SSLContext(_ssl.PROTOCOL_TLS)._wrap_socket(s, 0) s.close() exc = raises(_ssl.SSLError, ss.write, "data") assert exc.value.message == 'Underlying socket has been closed.' @@ -123,13 +123,13 @@ def test_context(self): import _ssl - s = _ssl._SSLContext(_ssl.PROTOCOL_TLSv1) + s = _ssl._SSLContext(_ssl.PROTOCOL_TLS) raises(ValueError, _ssl._SSLContext, -1) assert type(s.options) is long - assert s.options & _ssl.OP_NO_SSLv2 - s.options &= ~_ssl.OP_NO_SSLv2 - assert not s.options & _ssl.OP_NO_SSLv2 + assert s.options & _ssl.OP_NO_SSLv3 + s.options &= ~_ssl.OP_NO_SSLv3 + assert not s.options & _ssl.OP_NO_SSLv3 raises(TypeError, "s.options = 2.5") assert not s.check_hostname @@ -159,7 +159,7 @@ def test_set_default_verify_paths(self): import _ssl - s = _ssl._SSLContext(_ssl.PROTOCOL_TLSv1) + s = _ssl._SSLContext(_ssl.PROTOCOL_TLS) s.set_default_verify_paths() @@ -253,13 +253,44 @@ if not _ssl.HAS_NPN: skip("NPN requires OpenSSL 1.0.1 or greater") - ctx = _ssl._SSLContext(_ssl.PROTOCOL_TLSv1) + ctx = _ssl._SSLContext(_ssl.PROTOCOL_TLS) ctx._set_npn_protocols(b'\x08http/1.1\x06spdy/2') ss = ctx._wrap_socket(self.s._sock, True, server_hostname="svn.python.org") self.s.close() del ss; gc.collect() + def test_peer_certificate(self): + import _ssl, gc + ctx = _ssl._SSLContext(_ssl.PROTOCOL_TLS) + ss = ctx._wrap_socket(self.s._sock, False) + ss.do_handshake() + assert isinstance(ss.peer_certificate(der=True), bytes) + assert isinstance(ss.peer_certificate(), dict) + self.s.close() + del ss; gc.collect() + + def test_peer_certificate_verify(self): + import _ssl, ssl, gc + paths = ssl.get_default_verify_paths() + if not paths.capath and not paths.cafile: + skip("ssl.get_default_verify_paths() failed to return any path") + + ctx = _ssl._SSLContext(_ssl.PROTOCOL_TLS) + ctx.verify_mode = _ssl.CERT_REQUIRED + ctx.load_verify_locations(capath=paths.capath, cafile=paths.cafile) + + ss = ctx._wrap_socket(self.s._sock, False) + try: + ss.do_handshake() + except _ssl.SSLError as e: + if e.reason == 'CERTIFICATE_VERIFY_FAILED': + skip("Certificate verification failed. " + "Most likely we just don't have any CA certificates.") + assert ss.peer_certificate() + self.s.close() + del ss; gc.collect() + def test_tls_unique_cb(self): import ssl, sys, gc ss = ssl.wrap_socket(self.s) @@ -325,7 +356,7 @@ def test_load_cert_chain(self): import _ssl, errno - ctx = _ssl._SSLContext(_ssl.PROTOCOL_TLSv1) + ctx = _ssl._SSLContext(_ssl.PROTOCOL_TLS) ctx.load_cert_chain(self.keycert) ctx.load_cert_chain(self.cert, self.key) exc = raises(IOError, ctx.load_cert_chain, "inexistent.pem") @@ -344,11 +375,11 @@ def test_load_verify_locations(self): import _ssl - ctx = _ssl._SSLContext(_ssl.PROTOCOL_TLSv1) + ctx = _ssl._SSLContext(_ssl.PROTOCOL_TLS) ctx.load_verify_locations(self.keycert) ctx.load_verify_locations(cafile=self.keycert, capath=None) - ctx = _ssl._SSLContext(_ssl.PROTOCOL_TLSv1) + ctx = _ssl._SSLContext(_ssl.PROTOCOL_TLS) with open(self.keycert) as f: cacert_pem = f.read().decode('ascii') ctx.load_verify_locations(cadata=cacert_pem) @@ -356,7 +387,7 @@ def test_get_ca_certs(self): import _ssl - ctx = _ssl._SSLContext(_ssl.PROTOCOL_TLSv1) + ctx = _ssl._SSLContext(_ssl.PROTOCOL_TLS) ctx.load_verify_locations(self.keycert) assert ctx.get_ca_certs() == [] ctx.load_verify_locations(self.python_org_cert) @@ -370,7 +401,7 @@ def test_cert_store_stats(self): import _ssl - ctx = _ssl._SSLContext(_ssl.PROTOCOL_TLSv1) + ctx = _ssl._SSLContext(_ssl.PROTOCOL_TLS) assert ctx.cert_store_stats() == {'x509_ca': 0, 'crl': 0, 'x509': 0} ctx.load_cert_chain(self.keycert) assert ctx.cert_store_stats() == {'x509_ca': 0, 'crl': 0, 'x509': 0} @@ -379,7 +410,7 @@ def test_load_dh_params(self): import _ssl, errno - ctx = _ssl._SSLContext(_ssl.PROTOCOL_TLSv1) + ctx = _ssl._SSLContext(_ssl.PROTOCOL_TLS) ctx.load_dh_params(self.dh512) raises(TypeError, ctx.load_dh_params) raises(TypeError, ctx.load_dh_params, None) @@ -389,7 +420,7 @@ def test_set_ecdh_curve(self): import _ssl - ctx = _ssl._SSLContext(_ssl.PROTOCOL_TLSv1) + ctx = _ssl._SSLContext(_ssl.PROTOCOL_TLS) ctx.set_ecdh_curve("prime256v1") raises(ValueError, ctx.set_ecdh_curve, "foo") @@ -434,7 +465,7 @@ def test_lib_reason(self): # Test the library and reason attributes import _ssl - ctx = _ssl._SSLContext(_ssl.PROTOCOL_TLSv1) + ctx = _ssl._SSLContext(_ssl.PROTOCOL_TLS) exc = raises(_ssl.SSLError, ctx.load_dh_params, self.keycert) assert exc.value.library == 'PEM' assert exc.value.reason == 'NO_START_LINE' @@ -445,7 +476,7 @@ # Check that the appropriate SSLError subclass is raised # (this only tests one of them) import _ssl, _socket - ctx = _ssl._SSLContext(_ssl.PROTOCOL_TLSv1) + ctx = _ssl._SSLContext(_ssl.PROTOCOL_TLS) s = _socket.socket() try: s.bind(("127.0.0.1", 0)) diff --git a/pypy/module/pyexpat/interp_pyexpat.py b/pypy/module/pyexpat/interp_pyexpat.py --- a/pypy/module/pyexpat/interp_pyexpat.py +++ b/pypy/module/pyexpat/interp_pyexpat.py @@ -524,8 +524,8 @@ maxindex = XML_GetSpecifiedAttributeCount(self.itself) else: maxindex = 0 - while attrs[maxindex]: - maxindex += 2 # copied + while attrs[maxindex]: + maxindex += 2 # copied if self.ordered_attributes: w_attrs = space.newlist([ diff --git a/rpython/rlib/ropenssl.py b/rpython/rlib/ropenssl.py --- a/rpython/rlib/ropenssl.py +++ b/rpython/rlib/ropenssl.py @@ -57,8 +57,19 @@ '#define pypy_GENERAL_NAME_dirn(name) (name->d.dirn)', '#define pypy_GENERAL_NAME_uri(name) (name->d.uniformResourceIdentifier)', '#define pypy_GENERAL_NAME_pop_free(names) (sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free))', - '#define pypy_X509_OBJECT_data_x509(obj) (obj->data.x509)', '#define pypy_DIST_POINT_fullname(obj) (obj->distpoint->name.fullname)', + # Backwards compatibility for functions introduced in 1.1 + '#if (OPENSSL_VERSION_NUMBER < 0x10100000) || defined(LIBRESSL_VERSION_NUMBER)\n' + '# define COMP_get_name(meth) (meth->name)\n' + '# define COMP_get_type(meth) (meth->type)\n' + '# define X509_NAME_ENTRY_set(ne) (ne->set)\n' + '# define X509_OBJECT_get0_X509(obj) (obj->data.x509)\n' + '# define X509_OBJECT_get_type(obj) (obj->type)\n' + '# define X509_STORE_get0_objects(store) (store->objs)\n' + '# define X509_STORE_get0_param(store) (store->param)\n' + '#else\n' + '# define OPENSSL_NO_SSL2\n' + '#endif', ], ) @@ -88,6 +99,7 @@ "OPENSSL_EXPORT_VAR_AS_FUNCTION") OPENSSL_VERSION_NUMBER = rffi_platform.ConstantInteger( "OPENSSL_VERSION_NUMBER") + LIBRESSL = rffi_platform.Defined("LIBRESSL_VERSION_NUMBER") cconfig = rffi_platform.configure(CConfigBootstrap) if cconfig["OPENSSL_EXPORT_VAR_AS_FUNCTION"]: @@ -95,23 +107,10 @@ else: ASN1_ITEM_EXP = ASN1_ITEM OPENSSL_VERSION_NUMBER = cconfig["OPENSSL_VERSION_NUMBER"] +LIBRESSL = cconfig["LIBRESSL"] +OPENSSL_1_1 = OPENSSL_VERSION_NUMBER >= 0x10100000 and not LIBRESSL HAVE_TLSv1_2 = OPENSSL_VERSION_NUMBER >= 0x10001000 -if (OPENSSL_VERSION_NUMBER >= 0x10100000 and - OPENSSL_VERSION_NUMBER < 0x20000000): # <= libressl :-( - eci.pre_include_bits = () - eci.post_include_bits = () - raise Exception("""OpenSSL version >= 1.1 not supported yet. - - This program requires OpenSSL version 1.0.x, and may also - work with LibreSSL or OpenSSL 0.9.x. OpenSSL 1.1 is quite - some work to update to; contributions are welcome. Sorry, - you need to install an older version of OpenSSL for now. - Make sure this older version is the one picked up by this - program when it runs the compiler. - - This is the configuration used: %r""" % (eci,)) - class CConfig: _compilation_info_ = eci @@ -210,28 +209,10 @@ OBJ_NAME_TYPE_MD_METH = rffi_platform.ConstantInteger( "OBJ_NAME_TYPE_MD_METH") - if OPENSSL_VERSION_NUMBER >= 0x10001000: - X509_st = rffi_platform.Struct( - 'struct x509_st', - [('crldp', stack_st_DIST_POINT)]) - # Some structures, with only the fields used in the _ssl module - X509_name_entry_st = rffi_platform.Struct('struct X509_name_entry_st', - [('set', rffi.INT)]) asn1_string_st = rffi_platform.Struct('struct asn1_string_st', [('length', rffi.INT), ('data', rffi.CCHARP)]) - X509_extension_st = rffi_platform.Struct( - 'struct X509_extension_st', - [('value', ASN1_STRING)]) - x509_store_st = rffi_platform.Struct( - 'struct x509_store_st', - [('objs', stack_st_X509_OBJECT), - ('param', X509_VERIFY_PARAM)]) - x509_object_st = rffi_platform.Struct( - 'struct x509_object_st', - [('type', rffi.INT)]) - X509_LU_X509 = rffi_platform.ConstantInteger("X509_LU_X509") X509_LU_CRL = rffi_platform.ConstantInteger("X509_LU_CRL") @@ -244,12 +225,6 @@ GENERAL_NAME_st = rffi_platform.Struct( 'struct GENERAL_NAME_st', [('type', rffi.INT)]) - EVP_MD_st = rffi_platform.Struct( - 'EVP_MD', - [('md_size', rffi.INT), - ('block_size', rffi.INT)]) - EVP_MD_SIZE = rffi_platform.SizeOf('EVP_MD') - EVP_MD_CTX_SIZE = rffi_platform.SizeOf('EVP_MD_CTX') OBJ_NAME_st = rffi_platform.Struct( 'OBJ_NAME', @@ -257,10 +232,6 @@ ('name', rffi.CCHARP), ]) - COMP_METHOD_st = rffi_platform.Struct( - 'struct comp_method_st', - [('type', rffi.INT),]) - ACCESS_DESCRIPTION_st = rffi_platform.Struct( 'struct ACCESS_DESCRIPTION_st', [('method', ASN1_OBJECT), @@ -275,14 +246,12 @@ SSL_CIPHER = rffi.COpaquePtr('SSL_CIPHER') SSL = rffi.COpaquePtr('SSL') BIO = rffi.COpaquePtr('BIO') -if OPENSSL_VERSION_NUMBER >= 0x10001000: - X509 = rffi.CArrayPtr(X509_st) -else: - X509 = rffi.COpaquePtr('X509') -X509_NAME_ENTRY = rffi.CArrayPtr(X509_name_entry_st) -X509_EXTENSION = rffi.CArrayPtr(X509_extension_st) -X509_STORE = rffi.CArrayPtr(x509_store_st) -X509_OBJECT = lltype.Ptr(x509_object_st) +X509 = rffi.COpaquePtr('X509') +X509_OBJECT = rffi.COpaquePtr('X509_OBJECT') +COMP_METHOD = rffi.COpaquePtr('COMP_METHOD') +X509_NAME_ENTRY = rffi.COpaquePtr('X509_NAME_ENTRY') +X509_EXTENSION = rffi.COpaquePtr('X509_EXTENSION') +X509_STORE = rffi.COpaquePtr('X509_STORE') X509V3_EXT_METHOD = rffi.CArrayPtr(v3_ext_method) ASN1_STRING.TO.become(asn1_string_st) ASN1_TIME = rffi.COpaquePtr('ASN1_TIME') @@ -290,9 +259,9 @@ GENERAL_NAMES = rffi.COpaquePtr('GENERAL_NAMES') GENERAL_NAME.TO.become(GENERAL_NAME_st) OBJ_NAME = rffi.CArrayPtr(OBJ_NAME_st) -COMP_METHOD = rffi.CArrayPtr(COMP_METHOD_st) ACCESS_DESCRIPTION = rffi.CArrayPtr(ACCESS_DESCRIPTION_st) + HAVE_OPENSSL_RAND = OPENSSL_VERSION_NUMBER >= 0x0090500f HAVE_OPENSSL_FINISHED = OPENSSL_VERSION_NUMBER >= 0x0090500f HAVE_SSL_CTX_CLEAR_OPTIONS = OPENSSL_VERSION_NUMBER >= 0x009080df and \ @@ -314,8 +283,10 @@ globals()['libssl_' + name] = external( name, argtypes, restype, **kw) -ssl_external('SSL_load_error_strings', [], lltype.Void) -ssl_external('SSL_library_init', [], rffi.INT) +ssl_external('SSL_load_error_strings', [], lltype.Void, + macro=OPENSSL_1_1 or None) +ssl_external('SSL_library_init', [], rffi.INT, + macro=OPENSSL_1_1 or None) ssl_external('CRYPTO_num_locks', [], rffi.INT) ssl_external('CRYPTO_set_locking_callback', [lltype.Ptr(lltype.FuncType( @@ -341,7 +312,11 @@ ssl_external('TLSv1_2_method', [], SSL_METHOD) ssl_external('SSLv2_method', [], SSL_METHOD) ssl_external('SSLv3_method', [], SSL_METHOD) -ssl_external('SSLv23_method', [], SSL_METHOD) +# Windows note: fails in untranslated tests if the following function is +# made 'macro=True'. Not sure I want to dig into the reason for that mess. +libssl_TLS_method = external( + 'TLS_method' if OPENSSL_1_1 else 'SSLv23_method', + [], SSL_METHOD) ssl_external('SSL_CTX_use_PrivateKey_file', [SSL_CTX, rffi.CCHARP, rffi.INT], rffi.INT, save_err=rffi.RFFI_FULL_ERRNO_ZERO) ssl_external('SSL_CTX_use_certificate_chain_file', [SSL_CTX, rffi.CCHARP], rffi.INT, @@ -370,7 +345,7 @@ lltype.Void, macro=True) ssl_external('SSL_CTX_set_tlsext_servername_arg', [SSL_CTX, rffi.VOIDP], lltype.Void, macro=True) ssl_external('SSL_CTX_set_tmp_ecdh', [SSL_CTX, EC_KEY], lltype.Void, macro=True) -if OPENSSL_VERSION_NUMBER >= 0x10002000: +if OPENSSL_VERSION_NUMBER >= 0x10002000 and not OPENSSL_1_1: ssl_external('SSL_CTX_set_ecdh_auto', [SSL_CTX, rffi.INT], lltype.Void, macro=True) else: @@ -416,6 +391,8 @@ ssl_external('X509_NAME_get_entry', [X509_NAME, rffi.INT], X509_NAME_ENTRY) ssl_external('X509_NAME_ENTRY_get_object', [X509_NAME_ENTRY], ASN1_OBJECT) ssl_external('X509_NAME_ENTRY_get_data', [X509_NAME_ENTRY], ASN1_STRING) +ssl_external('X509_NAME_ENTRY_set', [X509_NAME_ENTRY], rffi.INT, + macro=(not OPENSSL_1_1) or None) ssl_external('i2d_X509', [X509, rffi.CCHARPP], rffi.INT, save_err=SAVE_ERR) ssl_external('X509_free', [X509], lltype.Void, releasegil=False) ssl_external('X509_check_ca', [X509], rffi.INT) @@ -427,11 +404,16 @@ ssl_external('X509_get_ext', [X509, rffi.INT], X509_EXTENSION) ssl_external('X509_get_ext_d2i', [X509, rffi.INT, rffi.VOIDP, rffi.VOIDP], rffi.VOIDP) ssl_external('X509V3_EXT_get', [X509_EXTENSION], X509V3_EXT_METHOD) +ssl_external('X509_EXTENSION_get_data', [X509_EXTENSION], ASN1_STRING) ssl_external('X509_VERIFY_PARAM_get_flags', [X509_VERIFY_PARAM], rffi.ULONG) ssl_external('X509_VERIFY_PARAM_set_flags', [X509_VERIFY_PARAM, rffi.ULONG], rffi.INT) ssl_external('X509_VERIFY_PARAM_clear_flags', [X509_VERIFY_PARAM, rffi.ULONG], rffi.INT) ssl_external('X509_STORE_add_cert', [X509_STORE, X509], rffi.INT) +ssl_external('X509_STORE_get0_objects', [X509_STORE], stack_st_X509_OBJECT, + macro=bool(not OPENSSL_1_1) or None) +ssl_external('X509_STORE_get0_param', [X509_STORE], X509_VERIFY_PARAM, + macro=bool(not OPENSSL_1_1) or None) ssl_external('X509_get_default_cert_file_env', [], rffi.CCHARP) ssl_external('X509_get_default_cert_file', [], rffi.CCHARP) @@ -468,8 +450,14 @@ macro=True) ssl_external('sk_X509_OBJECT_value', [stack_st_X509_OBJECT, rffi.INT], X509_OBJECT, macro=True) -ssl_external('pypy_X509_OBJECT_data_x509', [X509_OBJECT], X509, - macro=True) +ssl_external('X509_OBJECT_get0_X509', [X509_OBJECT], X509, + macro=bool(not OPENSSL_1_1) or None) +ssl_external('X509_OBJECT_get_type', [X509_OBJECT], rffi.INT, + macro=bool(not OPENSSL_1_1) or None) +ssl_external('COMP_get_name', [COMP_METHOD], rffi.CCHARP, + macro=bool(not OPENSSL_1_1) or None) +ssl_external('COMP_get_type', [COMP_METHOD], rffi.INT, + macro=bool(not OPENSSL_1_1) or None) ssl_external('sk_DIST_POINT_num', [stack_st_DIST_POINT], rffi.INT, macro=True) ssl_external('sk_DIST_POINT_value', [stack_st_DIST_POINT, rffi.INT], DIST_POINT, @@ -511,8 +499,12 @@ # with the GIL held, and so is allowed to run in a RPython __del__ method. ssl_external('SSL_free', [SSL], lltype.Void, releasegil=False) ssl_external('SSL_CTX_free', [SSL_CTX], lltype.Void, releasegil=False) -ssl_external('CRYPTO_free', [rffi.VOIDP], lltype.Void) -libssl_OPENSSL_free = libssl_CRYPTO_free +if OPENSSL_1_1: + ssl_external('OPENSSL_free', [rffi.VOIDP], lltype.Void, macro=True) +else: + ssl_external('CRYPTO_free', [rffi.VOIDP], lltype.Void) + libssl_OPENSSL_free = libssl_CRYPTO_free + del libssl_CRYPTO_free ssl_external('SSL_write', [SSL, rffi.CCHARP, rffi.INT], rffi.INT, save_err=SAVE_ERR) @@ -576,10 +568,11 @@ SSL, rffi.CCHARPP, rffi.UINTP], lltype.Void) EVP_MD_CTX = rffi.COpaquePtr('EVP_MD_CTX', compilation_info=eci) -EVP_MD = lltype.Ptr(EVP_MD_st) +EVP_MD = rffi.COpaquePtr('EVP_MD') OpenSSL_add_all_digests = external( - 'OpenSSL_add_all_digests', [], lltype.Void) + 'OpenSSL_add_all_digests', [], lltype.Void, + macro=OPENSSL_1_1 or None) EVP_get_digestbyname = external( 'EVP_get_digestbyname', [rffi.CCHARP], EVP_MD) @@ -592,10 +585,25 @@ EVP_DigestFinal = external( 'EVP_DigestFinal', [EVP_MD_CTX, rffi.CCHARP, rffi.VOIDP], rffi.INT) +EVP_MD_size = external( + 'EVP_MD_size', [EVP_MD], rffi.INT) +EVP_MD_block_size = external( + 'EVP_MD_block_size', [EVP_MD], rffi.INT) EVP_MD_CTX_copy = external( 'EVP_MD_CTX_copy', [EVP_MD_CTX, EVP_MD_CTX], rffi.INT) -EVP_MD_CTX_cleanup = external( - 'EVP_MD_CTX_cleanup', [EVP_MD_CTX], rffi.INT, releasegil=False) +EVP_MD_CTX_new = external( + 'EVP_MD_CTX_new' if OPENSSL_1_1 else 'EVP_MD_CTX_create', + [], EVP_MD_CTX) +EVP_MD_CTX_free = external( + 'EVP_MD_CTX_free' if OPENSSL_1_1 else 'EVP_MD_CTX_destroy', + [EVP_MD_CTX], lltype.Void, releasegil=False) + +if OPENSSL_1_1: + PKCS5_PBKDF2_HMAC = external('PKCS5_PBKDF2_HMAC', [ + rffi.CCHARP, rffi.INT, rffi.CCHARP, rffi.INT, rffi.INT, EVP_MD, + rffi.INT, rffi.CCHARP], rffi.INT) +else: + PKCS5_PBKDF2_HMAC = None OBJ_NAME_CALLBACK = lltype.Ptr(lltype.FuncType( [OBJ_NAME, rffi.VOIDP], lltype.Void)) @@ -606,7 +614,7 @@ # Used for adding memory pressure. Last number is an (under?)estimate of # EVP_PKEY_CTX's size. # XXX: Make a better estimate here -HASH_MALLOC_SIZE = EVP_MD_SIZE + EVP_MD_CTX_SIZE \ +HASH_MALLOC_SIZE = 120 + 48 \ + rffi.sizeof(EVP_MD) * 2 + 208 def init_ssl(): diff --git a/rpython/translator/c/test/test_newgc.py b/rpython/translator/c/test/test_newgc.py --- a/rpython/translator/c/test/test_newgc.py +++ b/rpython/translator/c/test/test_newgc.py @@ -1575,15 +1575,13 @@ class A: def __init__(self): - self.ctx = lltype.malloc(ropenssl.EVP_MD_CTX.TO, - flavor='raw') digest = ropenssl.EVP_get_digestbyname('sha1') + self.ctx = ropenssl.EVP_MD_CTX_new() ropenssl.EVP_DigestInit(self.ctx, digest) rgc.add_memory_pressure(ropenssl.HASH_MALLOC_SIZE + 64) def __del__(self): - ropenssl.EVP_MD_CTX_cleanup(self.ctx) - lltype.free(self.ctx, flavor='raw') + ropenssl.EVP_MD_CTX_free(self.ctx) #A() --- can't call it here?? get glibc crashes on tannit64 def f(): am1 = am2 = am3 = None _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit