[PYTHON-CRYPTO] m2crypto blocking all other threads
Rune Froysa
rune.froysa at USIT.UIO.NO
Fri Sep 23 11:22:48 CEST 2005
Heikki Toivonen <heikki at OSAFOUNDATION.ORG> writes:
> Rune Froysa wrote:
> > I'm using m2crypto for a SSL-based xmlrpc service. This service is
> > frequently DOSed by what appears to be a bug in m2crypto: it blocks
>
> It seems like this is user error. In a multithreaded application you
> need to initialize M2Crypto for threading. With those changes your
> sample works for me. See below:
Sorry about that. Is this documented some place? For some reason,
demo/ssl/https_srv.py works without it (two "openssl s_client -connect
localhost:19443" can connect simultaneously without problems).
However, a "telnet localhost 19443"+<do nothing> first will prevent
any later s_clients from reaching past the "CONNECTED(00000003)"
state.
The threading.init() trick seems to work for my previous example, but
if I add a threading.init() to line 135 (first in __main__) of
demo/ssl/https_srv.py, i get a segfault when a client connects (python
2.3.4) (It works if I actually have created a separate thread):
Starting program: /usr/bin/python https_srv.py
[Thread debugging using libthread_db enabled]
[New Thread -1208785216 (LWP 12122)]
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread -1208785216 (LWP 12122)]
0x00dbdb4a in sem_post at GLIBC_2.0 () from /lib/tls/libpthread.so.0
(gdb) where
#0 0x00dbdb4a in sem_post at GLIBC_2.0 () from /lib/tls/libpthread.so.0
#1 0x080cf636 in PyThread_release_lock (lock=0x0) at Python/thread_pthread.h:431
#2 0x080ca519 in PyGILState_Release (oldstate=3080343864) at Python/pystate.c:473
#3 0xb7ad39e8 in ssl_info_callback (s=0x81ef058, where=16, ret=1) at SWIG/_m2crypto.c:1058
#4 0x00b251e2 in ssl23_accept () from /lib/libssl.so.4
#5 0x00b2a093 in SSL_accept () from /lib/libssl.so.4
#6 0xb7ad73b3 in ssl_accept (ssl=0x81ef058) at SWIG/_m2crypto.c:3492
#7 0xb7ae2d23 in _wrap_ssl_accept (self=0x0, args=0xb79b310c) at SWIG/_m2crypto.c:11191
#8 0x080ed9b0 in PyCFunction_Call (func=0xb7b2218c, arg=0xb79b310c, kw=0x1) at Objects/methodobject.c:108
#9 0x080a4f67 in call_function (pp_stack=0xbfffee9c, oparg=135426480) at Python/ceval.c:3439
...
> > BTW: under 0.15, the https_srv.py complains from line 126 -> SSL/Context.py: 118:
> > TypeError: ssl_ctx_load_verify_locations() argument 3 must be string, not None
>
> This does not happen for me.
Strange. Latest version from svn:
/tmp/m2/demo/ssl at dresden >PYTHONPATH=/tmp/m2/build/lib.linux-i686-2.3 python https_srv.py
Traceback (most recent call last):
File "https_srv.py", line 141, in ?
SSL.verify_none)
File "https_srv.py", line 126, in init_context
ctx.load_verify_info(cafile)
File "/tmp/m2/build/lib.linux-i686-2.3/M2Crypto/SSL/Context.py", line 121, in load_verify_locations
return m2.ssl_ctx_load_verify_locations(self.ctx, cafile, capath)
TypeError: ssl_ctx_load_verify_locations() argument 3 must be string, not None
It would be great if there was some way to set a timeout value on
connected clients. With the below patch, https_srv.py could
instantiate the HTTPS_Server with a default_timeout=SSL.timeout(sec=4)
keyword argument to kill misbehaving clients (like the telnet above).
Could something like this be considered for future inclusion? (I don't
believe there is a standard pythonic way of setting timeout on client
sockets):
Index: M2Crypto/SSL/SSLServer.py
===================================================================
--- M2Crypto/SSL/SSLServer.py (revision 319)
+++ M2Crypto/SSL/SSLServer.py (working copy)
@@ -12,7 +12,7 @@
class SSLServer(SocketServer.TCPServer):
- def __init__(self, server_address, RequestHandlerClass, ssl_context):
+ def __init__(self, server_address, RequestHandlerClass, ssl_context, default_timeout=None):
"""
Superclass says: Constructor. May be extended, do not override.
This class says: Ho-hum.
@@ -21,6 +21,8 @@
self.RequestHandlerClass=RequestHandlerClass
self.ssl_ctx=ssl_context
self.socket=Connection(self.ssl_ctx)
+ if default_timeout is not None:
+ self.socket.set_default_client_timeout(default_timeout)
self.server_bind()
self.server_activate()
Index: M2Crypto/SSL/Connection.py
===================================================================
--- M2Crypto/SSL/Connection.py (revision 319)
+++ M2Crypto/SSL/Connection.py (working copy)
@@ -38,6 +38,7 @@
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self._fileno = self.socket.fileno()
+ self._default_client_timeout = None
def __del__(self):
if getattr(self, 'sslbio', None):
@@ -102,16 +103,27 @@
def accept_ssl(self):
return m2.ssl_accept(self.ssl)
+ def set_default_client_timeout(self, timeout):
+ self._default_client_timeout = timeout
+
def accept(self):
"""Accept an SSL connection. The return value is a pair (ssl, addr) where
ssl is a new SSL connection object and addr is the address bound to the
the other end of the SSL connection."""
sock, addr = self.socket.accept()
+ if self._default_client_timeout is not None:
+ sock.setsockopt(socket.SOL_SOCKET, socket.SO_RCVTIMEO,
+ self._default_client_timeout.pack())
+ sock.setsockopt(socket.SOL_SOCKET, socket.SO_SNDTIMEO,
+ self._default_client_timeout.pack())
+
ssl = Connection(self.ctx, sock)
ssl.addr = addr
ssl.setup_ssl()
ssl.set_accept_state()
- ssl.accept_ssl()
+ if ssl.accept_ssl() != 1:
+ raise SSLError(m2.err_reason_error_string(m2.err_get_error()))
+
check = getattr(self, 'postConnectionCheck', self.serverPostConnectionCheck)
if check is not None:
if not check(self.get_peer_cert(), ssl.addr[0]):
Regards,
Rune Frøysa
More information about the python-crypto
mailing list