Răsfoiți Sursa

HUE-574: Making Hue start over SSL on Python 2.4.

Aditya Acharya 14 ani în urmă
părinte
comite
d26726b051

+ 13 - 0
desktop/core/ext-py/ssl-1.15/MANIFEST

@@ -0,0 +1,13 @@
+setup.py
+Makefile
+MANIFEST
+ssl/__init__.py
+ssl/_ssl2.c
+ssl/2.3.6/socketmodule.h
+ssl/2.5.1/socketmodule.h
+test/badcert.pem
+test/badkey.pem
+test/keycert.pem
+test/nullcert.pem
+test/test_ssl.py
+test/https_svn_python_org_root.pem

+ 19 - 0
desktop/core/ext-py/ssl-1.15/Makefile

@@ -0,0 +1,19 @@
+all: build
+
+build: ssl
+	python setup.py build
+
+install:
+	python setup.py install
+
+sdist:
+	python setup.py sdist
+
+clean:
+	python setup.py clean
+	rm -rf build
+
+.PHONY: test
+
+test:
+	python setup.py test

+ 83 - 0
desktop/core/ext-py/ssl-1.15/PKG-INFO

@@ -0,0 +1,83 @@
+Metadata-Version: 1.0
+Name: ssl
+Version: 1.15
+Summary: SSL wrapper for socket objects (2.3, 2.4, 2.5 compatible)
+Home-page: http://docs.python.org/dev/library/ssl.html
+Author: See long_description for details
+Author-email: python.ssl.maintainer@gmail.com
+License: Python (MIT-like)
+Description: 
+        The old socket.ssl() support for TLS over sockets is being
+        superseded in Python 2.6 by a new 'ssl' module.  This package
+        brings that module to older Python releases, 2.3.5 and up (it may
+        also work on older versions of 2.3, but we haven't tried it).
+        
+        It's quite similar to the 2.6 ssl module.  There's no stand-alone
+        documentation for this package; instead, just use the development
+        branch documentation for the SSL module at
+        http://docs.python.org/dev/library/ssl.html.
+        
+        Version 1.0 had a problem with Python 2.5.1 -- the structure of
+        the socket object changed from earlier versions.
+        
+        Version 1.1 was missing various package metadata information.
+        
+        Version 1.2 added more package metadata, and support for
+        ssl.get_server_certificate(), and the PEM-to-DER encode/decode
+        routines.  Plus integrated Paul Moore's patch to setup.py for
+        Windows.  Plus added support for asyncore, and asyncore HTTPS
+        server test.
+        
+        Version 1.3 fixed a bug in the test suite.
+        
+        Version 1.4 incorporated use of -static switch.
+        
+        Version 1.5 fixed bug in Python version check affecting build on
+        Python 2.5.0.
+        
+        Version 1.7 (and 1.6) fixed some bugs with asyncore support (recv and
+        send not being called on the SSLSocket class, wrong semantics for
+        sendall).
+        
+        Version 1.8 incorporated some code from Chris Stawarz to handle
+        sockets which are set to non-blocking before negotiating the SSL
+        session.
+        
+        Version 1.9 makes ssl.SSLError a subtype of socket.error.
+        
+        Version 1.10 fixes a bug in sendall().
+        
+        Version 1.11 includes the MANIFEST file, and by default will turne
+        unexpected EOFs occurring during a read into a regular EOF.  It also
+        removes the code for SSLFileStream, to use the regular socket module's
+        _fileobject instead.
+        
+        Version 1.12 fixes the bug in SSLSocket.accept() reported by Georg
+        Brandl, and adds a test case for that fix.
+        
+        Version 1.13 fixes a bug in calling do_handshake() automatically
+        on non-blocking sockets.  Thanks to Giampaolo Rodola.  Now includes
+        real asyncore test case.
+        
+        Version 1.14 incorporates some fixes to naming (rename "recv_from" to
+        "recvfrom" and "send_to" to "sendto"), and a fix to the asyncore test
+        case to unregister the connection handler when the connection is
+        closed.  It also exposes the SSL shutdown via the "unwrap" method
+        on an SSLSocket.  It exposes "subjectPublicKey" in the data received
+        from a peer cert.
+        
+        Version 1.15 fixes a bug in write retries, where the output buffer has
+        changed location because of garbage collection during the interim.
+        It also provides the new flag, PROTOCOL_NOSSLv2, which selects SSL23,
+        but disallows actual use of SSL2.
+        
+        Authorship: A cast of dozens over the years have written the Python
+        SSL support, including Marc-Alan Lemburg, Robin Dunn, GvR, Kalle
+        Svensson, Skip Montanaro, Mark Hammond, Martin von Loewis, Jeremy
+        Hylton, Andrew Kuchling, Georg Brandl, Bill Janssen, Chris Stawarz,
+        Neal Norwitz, and many others.  Thanks to Paul Moore, David Bolen and
+        Mark Hammond for help with the Windows side of the house.  And it's
+        all based on OpenSSL, which has its own cast of dozens!
+        
+        
+Platform: UNKNOWN

+ 266 - 0
desktop/core/ext-py/ssl-1.15/setup.py

@@ -0,0 +1,266 @@
+import os, sys
+from distutils.core import setup, Extension
+from distutils.sysconfig import get_python_lib
+from distutils.cmd import Command
+from distutils.command.build import build
+
+if (sys.version_info >= (2, 6, 0)):
+    sys.stderr.write("Skipping building ssl-1.15 because" +
+                     "it is a built-in module in Python" +
+                     "2.6 and later.\n")
+    sys.exit(0)
+elif (sys.version_info < (2, 3, 5)):
+    sys.stderr.write("Warning:  This code has not been tested "
+                     + "with versions of Python less than 2.3.5.\n")
+
+class Test (Command):
+
+    user_options = []
+
+    def initialize_options(self):
+        pass
+
+    def finalize_options(self):
+        pass
+
+    def run (self):
+
+        """Run the regrtest module appropriately"""
+
+        # figure out where the _ssl2 extension will be put
+        b = build(self.distribution)
+        b.initialize_options()
+        b.finalize_options()
+        extdir = os.path.abspath(b.build_platlib)
+
+        # now set up the load path
+        topdir = os.path.dirname(os.path.abspath(__file__))
+        localtestdir = os.path.join(topdir, "test")
+        sys.path.insert(0, topdir)        # for ssl package
+        sys.path.insert(0, localtestdir)  # for test module
+        sys.path.insert(0, extdir)        # for _ssl2 extension
+
+        # make sure the network is enabled
+        import test.test_support
+        test.test_support.use_resources = ["network"]
+
+        # and load the test and run it
+        os.chdir(localtestdir)
+        the_module = __import__("test_ssl", globals(), locals(), [])
+        # Most tests run to completion simply as a side-effect of
+        # being imported.  For the benefit of tests that can't run
+        # that way (like test_threaded_import), explicitly invoke
+        # their test_main() function (if it exists).
+        indirect_test = getattr(the_module, "test_main", None)
+        if indirect_test is not None:
+            indirect_test()
+
+
+def find_file(filename, std_dirs, paths):
+    """Searches for the directory where a given file is located,
+    and returns a possibly-empty list of additional directories, or None
+    if the file couldn't be found at all.
+
+    'filename' is the name of a file, such as readline.h or libcrypto.a.
+    'std_dirs' is the list of standard system directories; if the
+        file is found in one of them, no additional directives are needed.
+    'paths' is a list of additional locations to check; if the file is
+        found in one of them, the resulting list will contain the directory.
+    """
+
+    # Check the standard locations
+    for dir in std_dirs:
+        f = os.path.join(dir, filename)
+        print 'looking for', f
+        if os.path.exists(f): return []
+
+    # Check the additional directories
+    for dir in paths:
+        f = os.path.join(dir, filename)
+        print 'looking for', f
+        if os.path.exists(f):
+            return [dir]
+
+    # Not found anywhere
+    return None
+
+def find_library_file(compiler, libname, std_dirs, paths):
+    result = compiler.find_library_file(std_dirs + paths, libname)
+    if result is None:
+        return None
+
+    # Check whether the found file is in one of the standard directories
+    dirname = os.path.dirname(result)
+    for p in std_dirs:
+        # Ensure path doesn't end with path separator
+        p = p.rstrip(os.sep)
+        if p == dirname:
+            return [ ]
+
+    # Otherwise, it must have been in one of the additional directories,
+    # so we have to figure out which one.
+    for p in paths:
+        # Ensure path doesn't end with path separator
+        p = p.rstrip(os.sep)
+        if p == dirname:
+            return [p]
+    else:
+        assert False, "Internal error: Path not found in std_dirs or paths"
+
+
+def find_ssl():
+
+    # Detect SSL support for the socket module (via _ssl)
+    from distutils.ccompiler import new_compiler
+
+    compiler = new_compiler()
+    inc_dirs = compiler.include_dirs + ['/usr/include']
+
+    search_for_ssl_incs_in = [
+                          '/usr/local/ssl/include',
+                          '/usr/contrib/ssl/include/'
+                         ]
+    ssl_incs = find_file('openssl/ssl.h', inc_dirs,
+                         search_for_ssl_incs_in
+                         )
+    if ssl_incs is not None:
+        krb5_h = find_file('krb5.h', inc_dirs,
+                           ['/usr/kerberos/include'])
+        if krb5_h:
+            ssl_incs += krb5_h
+
+    ssl_libs = find_library_file(compiler, 'ssl',
+                                 ['/usr/lib'],
+                                 ['/usr/local/lib',
+                                  '/usr/local/ssl/lib',
+                                  '/usr/contrib/ssl/lib/'
+                                 ] )
+
+    if (ssl_incs is not None and ssl_libs is not None):
+        return ssl_incs, ssl_libs, ['ssl', 'crypto']
+
+    raise Exception("No SSL support found")
+
+if (sys.version_info >= (2, 5, 1)):
+    socket_inc = "./ssl/2.5.1"
+else:
+    socket_inc = "./ssl/2.3.6"
+
+link_args = []
+if sys.platform == 'win32':
+
+    # Assume the openssl libraries from GnuWin32 are installed in the
+    # following location:
+    gnuwin32_dir = os.environ.get("GNUWIN32_DIR", r"C:\Utils\GnuWin32")
+
+    # Set this to 1 for a dynamic build (depends on openssl DLLs)
+    # Dynamic build is about 26k, static is 670k
+    dynamic = int(os.environ.get("SSL_DYNAMIC", 0))
+
+    ssl_incs = [os.environ.get("C_INCLUDE_DIR") or os.path.join(gnuwin32_dir, "include")]
+    ssl_libs = [os.environ.get("C_LIB_DIR") or os.path.join(gnuwin32_dir, "lib")]
+    libs = ['ssl', 'crypto', 'wsock32']
+    if not dynamic:
+	libs = libs + ['gdi32', 'gw32c', 'ole32', 'uuid']
+        link_args = ['-static']
+else:
+    ssl_incs, ssl_libs, libs = find_ssl()
+
+testdir = os.path.join(get_python_lib(False), "test")                                 
+
+setup(name='ssl',
+      version='1.15',
+      description='SSL wrapper for socket objects (2.3, 2.4, 2.5 compatible)',
+      long_description=
+"""
+The old socket.ssl() support for TLS over sockets is being
+superseded in Python 2.6 by a new 'ssl' module.  This package
+brings that module to older Python releases, 2.3.5 and up (it may
+also work on older versions of 2.3, but we haven't tried it).
+
+It's quite similar to the 2.6 ssl module.  There's no stand-alone
+documentation for this package; instead, just use the development
+branch documentation for the SSL module at
+http://docs.python.org/dev/library/ssl.html.
+
+Version 1.0 had a problem with Python 2.5.1 -- the structure of
+the socket object changed from earlier versions.
+
+Version 1.1 was missing various package metadata information.
+
+Version 1.2 added more package metadata, and support for
+ssl.get_server_certificate(), and the PEM-to-DER encode/decode
+routines.  Plus integrated Paul Moore's patch to setup.py for
+Windows.  Plus added support for asyncore, and asyncore HTTPS
+server test.
+
+Version 1.3 fixed a bug in the test suite.
+
+Version 1.4 incorporated use of -static switch.
+
+Version 1.5 fixed bug in Python version check affecting build on
+Python 2.5.0.
+
+Version 1.7 (and 1.6) fixed some bugs with asyncore support (recv and
+send not being called on the SSLSocket class, wrong semantics for
+sendall).
+
+Version 1.8 incorporated some code from Chris Stawarz to handle
+sockets which are set to non-blocking before negotiating the SSL
+session.
+
+Version 1.9 makes ssl.SSLError a subtype of socket.error.
+
+Version 1.10 fixes a bug in sendall().
+
+Version 1.11 includes the MANIFEST file, and by default will turne
+unexpected EOFs occurring during a read into a regular EOF.  It also
+removes the code for SSLFileStream, to use the regular socket module's
+_fileobject instead.
+
+Version 1.12 fixes the bug in SSLSocket.accept() reported by Georg
+Brandl, and adds a test case for that fix.
+
+Version 1.13 fixes a bug in calling do_handshake() automatically
+on non-blocking sockets.  Thanks to Giampaolo Rodola.  Now includes
+real asyncore test case.
+
+Version 1.14 incorporates some fixes to naming (rename "recv_from" to
+"recvfrom" and "send_to" to "sendto"), and a fix to the asyncore test
+case to unregister the connection handler when the connection is
+closed.  It also exposes the SSL shutdown via the "unwrap" method
+on an SSLSocket.  It exposes "subjectPublicKey" in the data received
+from a peer cert.
+
+Version 1.15 fixes a bug in write retries, where the output buffer has
+changed location because of garbage collection during the interim.
+It also provides the new flag, PROTOCOL_NOSSLv2, which selects SSL23,
+but disallows actual use of SSL2.
+
+Authorship: A cast of dozens over the years have written the Python
+SSL support, including Marc-Alan Lemburg, Robin Dunn, GvR, Kalle
+Svensson, Skip Montanaro, Mark Hammond, Martin von Loewis, Jeremy
+Hylton, Andrew Kuchling, Georg Brandl, Bill Janssen, Chris Stawarz,
+Neal Norwitz, and many others.  Thanks to Paul Moore, David Bolen and
+Mark Hammond for help with the Windows side of the house.  And it's
+all based on OpenSSL, which has its own cast of dozens!
+
+""",
+
+      license='Python (MIT-like)',
+      author='See long_description for details',
+      author_email='python.ssl.maintainer@gmail.com',
+      url='http://docs.python.org/dev/library/ssl.html',
+      cmdclass={'test': Test},
+      packages=['ssl'],
+      ext_modules=[Extension('ssl._ssl2', ['ssl/_ssl2.c'],
+                             include_dirs = ssl_incs + [socket_inc],
+                             library_dirs = ssl_libs,
+                             libraries = libs,
+                             extra_link_args = link_args)],
+      data_files=[(testdir, ['test/test_ssl.py',
+                             'test/keycert.pem',
+                             'test/badcert.pem',
+                             'test/badkey.pem',
+                             'test/nullcert.pem'])],
+      )

+ 221 - 0
desktop/core/ext-py/ssl-1.15/ssl/2.3.6/socketmodule.h

@@ -0,0 +1,221 @@
+/* Socket module header file */
+
+/* Includes needed for the sockaddr_* symbols below */
+#ifndef MS_WINDOWS
+#ifdef __VMS
+#   include <socket.h>
+# else
+#   include <sys/socket.h>
+# endif
+# include <netinet/in.h>
+# if !(defined(__BEOS__) || defined(__CYGWIN__) || (defined(PYOS_OS2) && defined(PYCC_VACPP)))
+#  include <netinet/tcp.h>
+# endif
+
+#else /* MS_WINDOWS */
+#if _MSC_VER >= 1300
+# include <winsock2.h>
+# include <ws2tcpip.h>
+# define HAVE_ADDRINFO
+# define HAVE_SOCKADDR_STORAGE
+# define HAVE_GETADDRINFO
+# define HAVE_GETNAMEINFO
+# define ENABLE_IPV6
+#else
+# include <winsock.h>
+#endif
+#endif
+
+#ifdef HAVE_SYS_UN_H
+# include <sys/un.h>
+#else
+# undef AF_UNIX
+#endif
+
+#ifdef HAVE_NETPACKET_PACKET_H
+# include <sys/ioctl.h>
+# include <net/if.h>
+# include <netpacket/packet.h>
+#endif
+
+#ifndef Py__SOCKET_H
+#define Py__SOCKET_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Python module and C API name */
+#define PySocket_MODULE_NAME	"_socket"
+#define PySocket_CAPI_NAME	"CAPI"
+
+/* Abstract the socket file descriptor type */
+#ifdef MS_WINDOWS
+typedef SOCKET SOCKET_T;
+#	ifdef MS_WIN64
+#		define SIZEOF_SOCKET_T 8
+#	else
+#		define SIZEOF_SOCKET_T 4
+#	endif
+#else
+typedef int SOCKET_T;
+#	define SIZEOF_SOCKET_T SIZEOF_INT
+#endif
+
+/* The object holding a socket.  It holds some extra information,
+   like the address family, which is used to decode socket address
+   arguments properly. */
+
+typedef struct {
+	PyObject_HEAD
+	SOCKET_T sock_fd;	/* Socket file descriptor */
+	int sock_family;	/* Address family, e.g., AF_INET */
+	int sock_type;		/* Socket type, e.g., SOCK_STREAM */
+	int sock_proto;		/* Protocol type, usually 0 */
+	union sock_addr {
+		struct sockaddr_in in;
+#ifdef AF_UNIX
+		struct sockaddr_un un;
+#endif
+#ifdef ENABLE_IPV6
+		struct sockaddr_in6 in6;
+		struct sockaddr_storage storage;
+#endif
+#ifdef HAVE_NETPACKET_PACKET_H
+		struct sockaddr_ll ll;
+#endif
+	} sock_addr;
+	PyObject *(*errorhandler)(void); /* Error handler; checks
+					    errno, returns NULL and
+					    sets a Python exception */
+	double sock_timeout;		 /* Operation timeout in seconds;
+					    0.0 means non-blocking */
+} PySocketSockObject;
+
+/* --- C API ----------------------------------------------------*/
+
+/* Short explanation of what this C API export mechanism does
+   and how it works:
+
+    The _ssl module needs access to the type object defined in 
+    the _socket module. Since cross-DLL linking introduces a lot of
+    problems on many platforms, the "trick" is to wrap the
+    C API of a module in a struct which then gets exported to
+    other modules via a PyCObject.
+
+    The code in socketmodule.c defines this struct (which currently
+    only contains the type object reference, but could very
+    well also include other C APIs needed by other modules)
+    and exports it as PyCObject via the module dictionary
+    under the name "CAPI".
+
+    Other modules can now include the socketmodule.h file
+    which defines the needed C APIs to import and set up
+    a static copy of this struct in the importing module.
+
+    After initialization, the importing module can then
+    access the C APIs from the _socket module by simply
+    referring to the static struct, e.g.
+
+    Load _socket module and its C API; this sets up the global
+    PySocketModule:
+    
+	if (PySocketModule_ImportModuleAndAPI())
+	    return;
+
+
+    Now use the C API as if it were defined in the using
+    module:
+
+        if (!PyArg_ParseTuple(args, "O!|zz:ssl",
+
+			      PySocketModule.Sock_Type,
+
+			      (PyObject*)&Sock,
+			      &key_file, &cert_file))
+	    return NULL;
+
+    Support could easily be extended to export more C APIs/symbols
+    this way. Currently, only the type object is exported, 
+    other candidates would be socket constructors and socket
+    access functions.
+
+*/
+
+/* C API for usage by other Python modules */
+typedef struct {
+	PyTypeObject *Sock_Type;
+} PySocketModule_APIObject;
+
+/* XXX The net effect of the following appears to be to define a function
+   XXX named PySocketModule_APIObject in _ssl.c.  It's unclear why it isn't
+   XXX defined there directly. 
+
+   >>> It's defined here because other modules might also want to use
+   >>> the C API.
+
+*/
+#ifndef PySocket_BUILDING_SOCKET
+
+/* --- C API ----------------------------------------------------*/
+
+/* Interfacestructure to C API for other modules.
+   Call PySocketModule_ImportModuleAndAPI() to initialize this
+   structure. After that usage is simple:
+
+   if (!PyArg_ParseTuple(args, "O!|zz:ssl",
+                         &PySocketModule.Sock_Type, (PyObject*)&Sock,
+	 		 &key_file, &cert_file))
+ 	 return NULL;
+   ...
+*/
+
+static
+PySocketModule_APIObject PySocketModule;
+
+/* You *must* call this before using any of the functions in
+   PySocketModule and check its outcome; otherwise all accesses will
+   result in a segfault. Returns 0 on success. */
+
+#ifndef DPRINTF
+# define DPRINTF if (0) printf
+#endif
+
+static
+int PySocketModule_ImportModuleAndAPI(void)
+{
+	PyObject *mod = 0, *v = 0;
+	char *apimodule = PySocket_MODULE_NAME;
+	char *apiname = PySocket_CAPI_NAME;
+	void *api;
+
+	DPRINTF("Importing the %s C API...\n", apimodule);
+	mod = PyImport_ImportModule(apimodule);
+	if (mod == NULL)
+		goto onError;
+	DPRINTF(" %s package found\n", apimodule);
+	v = PyObject_GetAttrString(mod, apiname);
+	if (v == NULL)
+		goto onError;
+	Py_DECREF(mod);
+	DPRINTF(" API object %s found\n", apiname);
+	api = PyCObject_AsVoidPtr(v);
+	if (api == NULL)
+		goto onError;
+	Py_DECREF(v);
+	memcpy(&PySocketModule, api, sizeof(PySocketModule));
+	DPRINTF(" API object loaded and initialized.\n");
+	return 0;
+
+ onError:
+	DPRINTF(" not found.\n");
+	Py_XDECREF(mod);
+	Py_XDECREF(v);
+	return -1;
+}
+
+#endif /* !PySocket_BUILDING_SOCKET */
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* !Py__SOCKET_H */

+ 252 - 0
desktop/core/ext-py/ssl-1.15/ssl/2.5.1/socketmodule.h

@@ -0,0 +1,252 @@
+/* Socket module header file */
+
+/* Includes needed for the sockaddr_* symbols below */
+#ifndef MS_WINDOWS
+#ifdef __VMS
+#   include <socket.h>
+# else
+#   include <sys/socket.h>
+# endif
+# include <netinet/in.h>
+# if !(defined(__BEOS__) || defined(__CYGWIN__) || (defined(PYOS_OS2) && defined(PYCC_VACPP)))
+#  include <netinet/tcp.h>
+# endif
+
+#else /* MS_WINDOWS */
+#if _MSC_VER >= 1300
+# include <winsock2.h>
+# include <ws2tcpip.h>
+# define HAVE_ADDRINFO
+# define HAVE_SOCKADDR_STORAGE
+# define HAVE_GETADDRINFO
+# define HAVE_GETNAMEINFO
+# define ENABLE_IPV6
+#else
+# include <winsock.h>
+#endif
+#endif
+
+#ifdef HAVE_SYS_UN_H
+# include <sys/un.h>
+#else
+# undef AF_UNIX
+#endif
+
+#ifdef HAVE_LINUX_NETLINK_H
+# ifdef HAVE_ASM_TYPES_H
+#  include <asm/types.h>
+# endif
+# include <linux/netlink.h>
+#else
+#  undef AF_NETLINK
+#endif
+
+#ifdef HAVE_BLUETOOTH_BLUETOOTH_H
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/rfcomm.h>
+#include <bluetooth/l2cap.h>
+#include <bluetooth/sco.h>
+#endif
+
+#ifdef HAVE_BLUETOOTH_H
+#include <bluetooth.h>
+#endif
+
+#ifdef HAVE_NETPACKET_PACKET_H
+# include <sys/ioctl.h>
+# include <net/if.h>
+# include <netpacket/packet.h>
+#endif
+
+#ifndef Py__SOCKET_H
+#define Py__SOCKET_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Python module and C API name */
+#define PySocket_MODULE_NAME	"_socket"
+#define PySocket_CAPI_NAME	"CAPI"
+
+/* Abstract the socket file descriptor type */
+#ifdef MS_WINDOWS
+typedef SOCKET SOCKET_T;
+#	ifdef MS_WIN64
+#		define SIZEOF_SOCKET_T 8
+#	else
+#		define SIZEOF_SOCKET_T 4
+#	endif
+#else
+typedef int SOCKET_T;
+#	define SIZEOF_SOCKET_T SIZEOF_INT
+#endif
+
+/* Socket address */
+typedef union sock_addr {
+	struct sockaddr_in in;
+#ifdef AF_UNIX
+	struct sockaddr_un un;
+#endif
+#ifdef AF_NETLINK
+	struct sockaddr_nl nl;
+#endif
+#ifdef ENABLE_IPV6
+	struct sockaddr_in6 in6;
+	struct sockaddr_storage storage;
+#endif
+#ifdef HAVE_BLUETOOTH_BLUETOOTH_H
+	struct sockaddr_l2 bt_l2;
+	struct sockaddr_rc bt_rc;
+	struct sockaddr_sco bt_sco;
+#endif
+#ifdef HAVE_NETPACKET_PACKET_H
+	struct sockaddr_ll ll;
+#endif
+} sock_addr_t;
+
+/* The object holding a socket.  It holds some extra information,
+   like the address family, which is used to decode socket address
+   arguments properly. */
+
+typedef struct {
+	PyObject_HEAD
+	SOCKET_T sock_fd;	/* Socket file descriptor */
+	int sock_family;	/* Address family, e.g., AF_INET */
+	int sock_type;		/* Socket type, e.g., SOCK_STREAM */
+	int sock_proto;		/* Protocol type, usually 0 */
+	PyObject *(*errorhandler)(void); /* Error handler; checks
+					    errno, returns NULL and
+					    sets a Python exception */
+	double sock_timeout;		 /* Operation timeout in seconds;
+					    0.0 means non-blocking */
+} PySocketSockObject;
+
+/* --- C API ----------------------------------------------------*/
+
+/* Short explanation of what this C API export mechanism does
+   and how it works:
+
+    The _ssl module needs access to the type object defined in 
+    the _socket module. Since cross-DLL linking introduces a lot of
+    problems on many platforms, the "trick" is to wrap the
+    C API of a module in a struct which then gets exported to
+    other modules via a PyCObject.
+
+    The code in socketmodule.c defines this struct (which currently
+    only contains the type object reference, but could very
+    well also include other C APIs needed by other modules)
+    and exports it as PyCObject via the module dictionary
+    under the name "CAPI".
+
+    Other modules can now include the socketmodule.h file
+    which defines the needed C APIs to import and set up
+    a static copy of this struct in the importing module.
+
+    After initialization, the importing module can then
+    access the C APIs from the _socket module by simply
+    referring to the static struct, e.g.
+
+    Load _socket module and its C API; this sets up the global
+    PySocketModule:
+    
+	if (PySocketModule_ImportModuleAndAPI())
+	    return;
+
+
+    Now use the C API as if it were defined in the using
+    module:
+
+        if (!PyArg_ParseTuple(args, "O!|zz:ssl",
+
+			      PySocketModule.Sock_Type,
+
+			      (PyObject*)&Sock,
+			      &key_file, &cert_file))
+	    return NULL;
+
+    Support could easily be extended to export more C APIs/symbols
+    this way. Currently, only the type object is exported, 
+    other candidates would be socket constructors and socket
+    access functions.
+
+*/
+
+/* C API for usage by other Python modules */
+typedef struct {
+	PyTypeObject *Sock_Type;
+        PyObject *error;
+} PySocketModule_APIObject;
+
+/* XXX The net effect of the following appears to be to define a function
+   XXX named PySocketModule_APIObject in _ssl.c.  It's unclear why it isn't
+   XXX defined there directly. 
+
+   >>> It's defined here because other modules might also want to use
+   >>> the C API.
+
+*/
+#ifndef PySocket_BUILDING_SOCKET
+
+/* --- C API ----------------------------------------------------*/
+
+/* Interfacestructure to C API for other modules.
+   Call PySocketModule_ImportModuleAndAPI() to initialize this
+   structure. After that usage is simple:
+
+   if (!PyArg_ParseTuple(args, "O!|zz:ssl",
+                         &PySocketModule.Sock_Type, (PyObject*)&Sock,
+	 		 &key_file, &cert_file))
+ 	 return NULL;
+   ...
+*/
+
+static
+PySocketModule_APIObject PySocketModule;
+
+/* You *must* call this before using any of the functions in
+   PySocketModule and check its outcome; otherwise all accesses will
+   result in a segfault. Returns 0 on success. */
+
+#ifndef DPRINTF
+# define DPRINTF if (0) printf
+#endif
+
+static
+int PySocketModule_ImportModuleAndAPI(void)
+{
+	PyObject *mod = 0, *v = 0;
+	char *apimodule = PySocket_MODULE_NAME;
+	char *apiname = PySocket_CAPI_NAME;
+	void *api;
+
+	DPRINTF("Importing the %s C API...\n", apimodule);
+	mod = PyImport_ImportModule(apimodule);
+	if (mod == NULL)
+		goto onError;
+	DPRINTF(" %s package found\n", apimodule);
+	v = PyObject_GetAttrString(mod, apiname);
+	if (v == NULL)
+		goto onError;
+	Py_DECREF(mod);
+	DPRINTF(" API object %s found\n", apiname);
+	api = PyCObject_AsVoidPtr(v);
+	if (api == NULL)
+		goto onError;
+	Py_DECREF(v);
+	memcpy(&PySocketModule, api, sizeof(PySocketModule));
+	DPRINTF(" API object loaded and initialized.\n");
+	return 0;
+
+ onError:
+	DPRINTF(" not found.\n");
+	Py_XDECREF(mod);
+	Py_XDECREF(v);
+	return -1;
+}
+
+#endif /* !PySocket_BUILDING_SOCKET */
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* !Py__SOCKET_H */

+ 413 - 0
desktop/core/ext-py/ssl-1.15/ssl/__init__.py

@@ -0,0 +1,413 @@
+# Wrapper module for _ssl, providing some additional facilities
+# implemented in Python.  Written by Bill Janssen.
+
+"""\
+This module provides some more Pythonic support for SSL.
+
+Object types:
+
+  SSLSocket -- subtype of socket.socket which does SSL over the socket
+
+Exceptions:
+
+  SSLError -- exception raised for I/O errors
+
+Functions:
+
+  cert_time_to_seconds -- convert time string used for certificate
+                          notBefore and notAfter functions to integer
+                          seconds past the Epoch (the time values
+                          returned from time.time())
+
+  fetch_server_certificate (HOST, PORT) -- fetch the certificate provided
+                          by the server running on HOST at port PORT.  No
+                          validation of the certificate is performed.
+
+Integer constants:
+
+SSL_ERROR_ZERO_RETURN
+SSL_ERROR_WANT_READ
+SSL_ERROR_WANT_WRITE
+SSL_ERROR_WANT_X509_LOOKUP
+SSL_ERROR_SYSCALL
+SSL_ERROR_SSL
+SSL_ERROR_WANT_CONNECT
+
+SSL_ERROR_EOF
+SSL_ERROR_INVALID_ERROR_CODE
+
+The following group define certificate requirements that one side is
+allowing/requiring from the other side:
+
+CERT_NONE - no certificates from the other side are required (or will
+            be looked at if provided)
+CERT_OPTIONAL - certificates are not required, but if provided will be
+                validated, and if validation fails, the connection will
+                also fail
+CERT_REQUIRED - certificates are required, and will be validated, and
+                if validation fails, the connection will also fail
+
+The following constants identify various SSL protocol variants:
+
+PROTOCOL_SSLv2
+PROTOCOL_SSLv3
+PROTOCOL_SSLv23
+PROTOCOL_TLSv1
+PROTOCOL_NOSSLv2 -- anything except version 2
+"""
+
+import os, sys
+
+import _ssl2             # if we can't import it, let the error propagate
+
+from _ssl2 import SSLError
+from _ssl2 import CERT_NONE, CERT_OPTIONAL, CERT_REQUIRED
+from _ssl2 import PROTOCOL_SSLv2, PROTOCOL_SSLv3, PROTOCOL_SSLv23, PROTOCOL_TLSv1, PROTOCOL_NOSSLv2
+from _ssl2 import RAND_status, RAND_egd, RAND_add
+from _ssl2 import \
+     SSL_ERROR_ZERO_RETURN, \
+     SSL_ERROR_WANT_READ, \
+     SSL_ERROR_WANT_WRITE, \
+     SSL_ERROR_WANT_X509_LOOKUP, \
+     SSL_ERROR_SYSCALL, \
+     SSL_ERROR_SSL, \
+     SSL_ERROR_WANT_CONNECT, \
+     SSL_ERROR_EOF, \
+     SSL_ERROR_INVALID_ERROR_CODE
+
+from socket import socket, _fileobject
+from socket import getnameinfo as _getnameinfo
+import base64        # for DER-to-PEM translation
+import select        # for handshake
+
+class SSLSocket (socket):
+
+    """This class implements a subtype of socket.socket that wraps
+    the underlying OS socket in an SSL context when necessary, and
+    provides read and write methods over that channel."""
+
+    def __init__(self, sock, keyfile=None, certfile=None,
+                 server_side=False, cert_reqs=CERT_NONE,
+                 ssl_version=PROTOCOL_SSLv23, ca_certs=None,
+                 do_handshake_on_connect=True,
+                 suppress_ragged_eofs=True):
+        socket.__init__(self, _sock=sock._sock)
+        # the initializer for socket trashes the methods (tsk, tsk), so...
+        self.send = lambda x, flags=0: SSLSocket.send(self, x, flags)
+        self.recv = lambda x, flags=0: SSLSocket.recv(self, x, flags)
+        self.sendto = lambda data, addr, flags=0: SSLSocket.sendto(self, data, addr, flags)
+        self.recvfrom = lambda addr, buflen, flags: SSLSocket.recvfrom(self, addr, buflen, flags)
+
+        if certfile and not keyfile:
+            keyfile = certfile
+        # see if it's connected
+        try:
+            socket.getpeername(self)
+        except:
+            # no, no connection yet
+            self._sslobj = None
+        else:
+            # yes, create the SSL object
+            self._sslobj = _ssl2.sslwrap(self._sock, server_side,
+                                         keyfile, certfile,
+                                         cert_reqs, ssl_version, ca_certs)
+            if do_handshake_on_connect:
+                timeout = self.gettimeout()
+                if timeout == 0.0:
+                    # non-blocking
+                    raise ValueError("do_handshake_on_connect should not be specified for non-blocking sockets")
+                self.do_handshake()
+        self.keyfile = keyfile
+        self.certfile = certfile
+        self.cert_reqs = cert_reqs
+        self.ssl_version = ssl_version
+        self.ca_certs = ca_certs
+        self.do_handshake_on_connect = do_handshake_on_connect
+        self.suppress_ragged_eofs = suppress_ragged_eofs
+        self._makefile_refs = 0
+
+    def read(self, len=1024):
+
+        """Read up to LEN bytes and return them.
+        Return zero-length string on EOF."""
+
+        try:
+            return self._sslobj.read(len)
+        except SSLError, x:
+            if x.args[0] == SSL_ERROR_EOF and self.suppress_ragged_eofs:
+                return ''
+            else:
+                raise                
+
+    def write(self, data):
+
+        """Write DATA to the underlying SSL channel.  Returns
+        number of bytes of DATA actually transmitted."""
+
+        return self._sslobj.write(data)
+
+    def getpeercert(self, binary_form=False):
+
+        """Returns a formatted version of the data in the
+        certificate provided by the other end of the SSL channel.
+        Return None if no certificate was provided, {} if a
+        certificate was provided, but not validated."""
+
+        return self._sslobj.peer_certificate(binary_form)
+
+    def cipher (self):
+
+        if not self._sslobj:
+            return None
+        else:
+            return self._sslobj.cipher()
+
+    def send (self, data, flags=0):
+        if self._sslobj:
+            if flags != 0:
+                raise ValueError(
+                    "non-zero flags not allowed in calls to send() on %s" %
+                    self.__class__)
+            while True:
+                try:
+                    v = self._sslobj.write(data)
+                except SSLError, x:
+                    if x.args[0] == SSL_ERROR_WANT_READ:
+                        return 0
+                    elif x.args[0] == SSL_ERROR_WANT_WRITE:
+                        return 0
+                    else:
+                        raise
+                else:
+                    return v
+        else:
+            return socket.send(self, data, flags)
+
+    def sendto (self, data, addr, flags=0):
+        if self._sslobj:
+            raise ValueError("sendto not allowed on instances of %s" %
+                             self.__class__)
+        else:
+            return socket.sendto(self, data, addr, flags)
+
+    def sendall (self, data, flags=0):
+        if self._sslobj:
+            if flags != 0:
+                raise ValueError(
+                    "non-zero flags not allowed in calls to sendall() on %s" %
+                    self.__class__)
+            amount = len(data)
+            count = 0
+            while (count < amount):
+                v = self.send(data[count:])
+                count += v
+            return amount
+        else:
+            return socket.sendall(self, data, flags)
+
+    def recv (self, buflen=1024, flags=0):
+        if self._sslobj:
+            if flags != 0:
+                raise ValueError(
+                    "non-zero flags not allowed in calls to recv() on %s" %
+                    self.__class__)
+            while True:
+                try:
+                    return self.read(buflen)
+                except SSLError, x:
+                    if x.args[0] == SSL_ERROR_WANT_READ:
+                        continue
+                    else:
+                        raise x
+        else:
+            return socket.recv(self, buflen, flags)
+
+    def recvfrom (self, addr, buflen=1024, flags=0):
+        if self._sslobj:
+            raise ValueError("recvfrom not allowed on instances of %s" %
+                             self.__class__)
+        else:
+            return socket.recvfrom(self, addr, buflen, flags)
+
+    def pending(self):
+        if self._sslobj:
+            return self._sslobj.pending()
+        else:
+            return 0
+
+    def unwrap (self):
+        if self._sslobj:
+            s = self._sslobj.shutdown()
+            self._sslobj = None
+            return s
+        else:
+            raise ValueError("No SSL wrapper around " + str(self))
+
+    def shutdown (self, how):
+        self._sslobj = None
+        socket.shutdown(self, how)
+
+    def close (self):
+        if self._makefile_refs < 1:
+            self._sslobj = None
+            socket.close(self)
+        else:
+            self._makefile_refs -= 1
+
+    def do_handshake(self, block=False):
+
+        """Perform a TLS/SSL handshake."""
+
+        timeout = self.gettimeout()
+        try:
+            if timeout == 0.0 and block:
+                self.settimeout(None)
+            self._sslobj.do_handshake()
+        finally:
+            self.settimeout(timeout)
+
+    def connect(self, addr):
+
+        """Connects to remote ADDR, and then wraps the connection in
+        an SSL channel."""
+
+        # Here we assume that the socket is client-side, and not
+        # connected at the time of the call.  We connect it, then wrap it.
+        if self._sslobj:
+            raise ValueError("attempt to connect already-connected SSLSocket!")
+        socket.connect(self, addr)
+        self._sslobj = _ssl2.sslwrap(self._sock, False, self.keyfile, self.certfile,
+                                     self.cert_reqs, self.ssl_version,
+                                     self.ca_certs)
+        if self.do_handshake_on_connect:
+            self.do_handshake()
+
+    def accept(self):
+
+        """Accepts a new connection from a remote client, and returns
+        a tuple containing that new connection wrapped with a server-side
+        SSL channel, and the address of the remote client."""
+
+        newsock, addr = socket.accept(self)
+        return (SSLSocket(newsock,
+                          keyfile=self.keyfile,
+                          certfile=self.certfile,
+                          server_side=True,
+                          cert_reqs=self.cert_reqs,
+                          ssl_version=self.ssl_version,
+                          ca_certs=self.ca_certs,
+                          do_handshake_on_connect=self.do_handshake_on_connect),
+                addr)
+
+    def makefile(self, mode='r', bufsize=-1):
+
+        """Ouch.  Need to make and return a file-like object that
+        works with the SSL connection."""
+
+        self._makefile_refs += 1
+        return _fileobject(self, mode, bufsize)
+
+
+
+def wrap_socket(sock, keyfile=None, certfile=None,
+                server_side=False, cert_reqs=CERT_NONE,
+                ssl_version=PROTOCOL_SSLv23, ca_certs=None,
+                do_handshake_on_connect=True):
+
+    return SSLSocket(sock, keyfile=keyfile, certfile=certfile,
+                     server_side=server_side, cert_reqs=cert_reqs,
+                     ssl_version=ssl_version, ca_certs=ca_certs,
+                     do_handshake_on_connect=do_handshake_on_connect)
+
+# some utility functions
+
+def cert_time_to_seconds(cert_time):
+
+    """Takes a date-time string in standard ASN1_print form
+    ("MON DAY 24HOUR:MINUTE:SEC YEAR TIMEZONE") and return
+    a Python time value in seconds past the epoch."""
+
+    import time
+    return time.mktime(time.strptime(cert_time, "%b %d %H:%M:%S %Y GMT"))
+
+PEM_HEADER = "-----BEGIN CERTIFICATE-----"
+PEM_FOOTER = "-----END CERTIFICATE-----"
+
+def DER_cert_to_PEM_cert(der_cert_bytes):
+
+    """Takes a certificate in binary DER format and returns the
+    PEM version of it as a string."""
+
+    if hasattr(base64, 'standard_b64encode'):
+        # preferred because older API gets line-length wrong
+        f = base64.standard_b64encode(der_cert_bytes)
+        rval = PEM_HEADER + '\n'
+        while len(f) > 0:
+            l = min(len(f),64)
+            rval += f[:l] + '\n'
+            f = f[l:]
+        rval += PEM_FOOTER + '\n'
+        return rval
+    else:
+        return (PEM_HEADER + '\n' +
+                base64.encodestring(der_cert_bytes) +
+                PEM_FOOTER + '\n')
+
+def PEM_cert_to_DER_cert(pem_cert_string):
+
+    """Takes a certificate in ASCII PEM format and returns the
+    DER-encoded version of it as a byte sequence"""
+
+    if not pem_cert_string.startswith(PEM_HEADER):
+        raise ValueError("Invalid PEM encoding; must start with %s"
+                         % PEM_HEADER)
+    if not pem_cert_string.strip().endswith(PEM_FOOTER):
+        raise ValueError("Invalid PEM encoding; must end with %s"
+                         % PEM_FOOTER)
+    d = pem_cert_string.strip()[len(PEM_HEADER):-len(PEM_FOOTER)]
+    return base64.decodestring(d)
+
+def get_server_certificate (addr, ssl_version=PROTOCOL_SSLv3, ca_certs=None):
+
+    """Retrieve the certificate from the server at the specified address,
+    and return it as a PEM-encoded string.
+    If 'ca_certs' is specified, validate the server cert against it.
+    If 'ssl_version' is specified, use it in the connection attempt."""
+    
+    host, port = addr
+    if (ca_certs is not None):
+        cert_reqs = CERT_REQUIRED
+    else:
+        cert_reqs = CERT_NONE
+    s = wrap_socket(socket(), ssl_version=ssl_version,
+                    cert_reqs=cert_reqs, ca_certs=ca_certs)
+    s.connect(addr)
+    dercert = s.getpeercert(True)
+    s.close()
+    return DER_cert_to_PEM_cert(dercert)
+
+def get_protocol_name (protocol_code):
+    if protocol_code == PROTOCOL_TLSv1:
+        return "TLSv1"
+    elif protocol_code == PROTOCOL_SSLv23:
+        return "SSLv23"
+    elif protocol_code == PROTOCOL_SSLv2:
+        return "SSLv2"
+    elif protocol_code == PROTOCOL_SSLv3:
+        return "SSLv3"
+    else:
+        return "<unknown>"
+
+
+# a replacement for the old socket.ssl function
+
+def sslwrap_simple (sock, keyfile=None, certfile=None):
+
+    """A replacement for the old socket.ssl function.  Designed
+    for compability with Python 2.5 and earlier.  Will disappear in
+    Python 3.0."""
+
+    ssl_sock = _ssl2.sslwrap(sock._sock, 0, keyfile, certfile, CERT_NONE,
+                        PROTOCOL_SSLv23, None)
+    ssl_sock.do_handshake()
+    return ssl_sock()

+ 1692 - 0
desktop/core/ext-py/ssl-1.15/ssl/_ssl2.c

@@ -0,0 +1,1692 @@
+/* SSL socket module
+
+   2.3 compatible version
+
+   SSL support based on patches by Brian E Gallew and Laszlo Kovacs.
+   Re-worked a bit by Bill Janssen to add server-side support and
+   certificate decoding.
+
+   This module is imported by ssl.py. It should *not* be used
+   directly.
+
+   XXX should partial writes be enabled, SSL_MODE_ENABLE_PARTIAL_WRITE?
+
+   XXX what about SSL_MODE_AUTO_RETRY
+*/
+
+#include "Python.h"
+
+#ifdef WITH_THREAD
+#include "pythread.h"
+#define PySSL_BEGIN_ALLOW_THREADS { \
+			PyThreadState *_save = NULL;  \
+			if (_ssl_locks_count>0) {_save = PyEval_SaveThread();}
+#define PySSL_BLOCK_THREADS	if (_ssl_locks_count>0){PyEval_RestoreThread(_save)};
+#define PySSL_UNBLOCK_THREADS	if (_ssl_locks_count>0){_save = PyEval_SaveThread()};
+#define PySSL_END_ALLOW_THREADS	if (_ssl_locks_count>0){PyEval_RestoreThread(_save);} \
+		 }
+
+#else	/* no WITH_THREAD */
+
+#define PySSL_BEGIN_ALLOW_THREADS
+#define PySSL_BLOCK_THREADS
+#define PySSL_UNBLOCK_THREADS
+#define PySSL_END_ALLOW_THREADS
+
+#endif
+
+/* bring in this define */
+#define Py_Type(x)	((x)->ob_type)
+
+enum py_ssl_error {
+	/* these mirror ssl.h */
+	PY_SSL_ERROR_NONE,
+	PY_SSL_ERROR_SSL,
+	PY_SSL_ERROR_WANT_READ,
+	PY_SSL_ERROR_WANT_WRITE,
+	PY_SSL_ERROR_WANT_X509_LOOKUP,
+	PY_SSL_ERROR_SYSCALL,     /* look at error stack/return value/errno */
+	PY_SSL_ERROR_ZERO_RETURN,
+	PY_SSL_ERROR_WANT_CONNECT,
+	/* start of non ssl.h errorcodes */
+	PY_SSL_ERROR_EOF,         /* special case of SSL_ERROR_SYSCALL */
+	PY_SSL_ERROR_INVALID_ERROR_CODE
+};
+
+enum py_ssl_server_or_client {
+	PY_SSL_CLIENT,
+	PY_SSL_SERVER
+};
+
+enum py_ssl_cert_requirements {
+	PY_SSL_CERT_NONE,
+	PY_SSL_CERT_OPTIONAL,
+	PY_SSL_CERT_REQUIRED
+};
+
+enum py_ssl_version {
+	PY_SSL_VERSION_SSL2,
+	PY_SSL_VERSION_SSL3,
+	PY_SSL_VERSION_SSL23,
+	PY_SSL_VERSION_TLS1,
+        PY_SSL_VERSION_NOSSL2,
+};
+
+/* Include symbols from _socket module */
+#include "socketmodule.h"
+
+#if defined(HAVE_POLL_H)
+#include <poll.h>
+#elif defined(HAVE_SYS_POLL_H)
+#include <sys/poll.h>
+#endif
+
+/* Include OpenSSL header files */
+#include "openssl/rsa.h"
+#include "openssl/crypto.h"
+#include "openssl/x509.h"
+#include "openssl/x509v3.h"
+#include "openssl/pem.h"
+#include "openssl/ssl.h"
+#include "openssl/err.h"
+#include "openssl/rand.h"
+
+/* SSL error object */
+static PyObject *PySSLErrorObject;
+
+#ifdef WITH_THREAD
+
+/* serves as a flag to see whether we've initialized the SSL thread support. */
+/* 0 means no, greater than 0 means yes */
+
+static unsigned int _ssl_locks_count = 0;
+
+#endif /* def WITH_THREAD */
+
+/* SSL socket object */
+
+#define X509_NAME_MAXLEN 256
+
+/* RAND_* APIs got added to OpenSSL in 0.9.5 */
+#if OPENSSL_VERSION_NUMBER >= 0x0090500fL
+# define HAVE_OPENSSL_RAND 1
+#else
+# undef HAVE_OPENSSL_RAND
+#endif
+
+typedef struct {
+	PyObject_HEAD
+	PySocketSockObject *Socket;	/* Socket on which we're layered */
+	SSL_CTX*	ctx;
+	SSL*		ssl;
+	X509*		peer_cert;
+	char		server[X509_NAME_MAXLEN];
+	char		issuer[X509_NAME_MAXLEN];
+
+} PySSLObject;
+
+static PyTypeObject PySSL_Type;
+static PyObject *PySSL_SSLwrite(PySSLObject *self, PyObject *args);
+static PyObject *PySSL_SSLread(PySSLObject *self, PyObject *args);
+static int check_socket_and_wait_for_timeout(PySocketSockObject *s,
+					     int writing);
+static PyObject *PySSL_peercert(PySSLObject *self, PyObject *args);
+static PyObject *PySSL_cipher(PySSLObject *self);
+static PyObject *PySSL_SSLshutdown(PySSLObject *self);
+
+#define PySSLObject_Check(v)	(Py_Type(v) == &PySSL_Type)
+
+typedef enum {
+	SOCKET_IS_NONBLOCKING,
+	SOCKET_IS_BLOCKING,
+	SOCKET_HAS_TIMED_OUT,
+	SOCKET_HAS_BEEN_CLOSED,
+	SOCKET_TOO_LARGE_FOR_SELECT,
+	SOCKET_OPERATION_OK
+} timeout_state;
+
+/* Wrap error strings with filename and line # */
+#define STRINGIFY1(x) #x
+#define STRINGIFY2(x) STRINGIFY1(x)
+#define ERRSTR1(x,y,z) (x ":" y ": " z)
+#define ERRSTR(x) ERRSTR1("_ssl.c", STRINGIFY2(__LINE__), x)
+
+/* XXX It might be helpful to augment the error message generated
+   below with the name of the SSL function that generated the error.
+   I expect it's obvious most of the time.
+*/
+
+static PyObject *
+PySSL_SetError(PySSLObject *obj, int ret, char *filename, int lineno)
+{
+	PyObject *v;
+	char buf[2048];
+	char *errstr;
+	int err;
+	enum py_ssl_error p = PY_SSL_ERROR_NONE;
+
+	assert(ret <= 0);
+
+	if (obj->ssl != NULL) {
+		err = SSL_get_error(obj->ssl, ret);
+
+		switch (err) {
+		case SSL_ERROR_ZERO_RETURN:
+			errstr = "TLS/SSL connection has been closed";
+			p = PY_SSL_ERROR_ZERO_RETURN;
+			break;
+		case SSL_ERROR_WANT_READ:
+			errstr = "The operation did not complete (read)";
+			p = PY_SSL_ERROR_WANT_READ;
+			break;
+		case SSL_ERROR_WANT_WRITE:
+			p = PY_SSL_ERROR_WANT_WRITE;
+			errstr = "The operation did not complete (write)";
+			break;
+		case SSL_ERROR_WANT_X509_LOOKUP:
+			p = PY_SSL_ERROR_WANT_X509_LOOKUP;
+			errstr =
+                            "The operation did not complete (X509 lookup)";
+			break;
+		case SSL_ERROR_WANT_CONNECT:
+			p = PY_SSL_ERROR_WANT_CONNECT;
+			errstr = "The operation did not complete (connect)";
+			break;
+		case SSL_ERROR_SYSCALL:
+		{
+			unsigned long e = ERR_get_error();
+			if (e == 0) {
+				if (ret == 0 || !obj->Socket) {
+				  p = PY_SSL_ERROR_EOF;
+				  errstr =
+                                      "EOF occurred in violation of protocol";
+				} else if (ret == -1) {
+				  /* underlying BIO reported an I/O error */
+                                  return obj->Socket->errorhandler();
+				} else { /* possible? */
+                                  p = PY_SSL_ERROR_SYSCALL;
+                                  errstr = "Some I/O error occurred";
+				}
+			} else {
+				p = PY_SSL_ERROR_SYSCALL;
+				/* XXX Protected by global interpreter lock */
+				errstr = ERR_error_string(e, NULL);
+			}
+			break;
+		}
+		case SSL_ERROR_SSL:
+		{
+			unsigned long e = ERR_get_error();
+			p = PY_SSL_ERROR_SSL;
+			if (e != 0)
+				/* XXX Protected by global interpreter lock */
+				errstr = ERR_error_string(e, NULL);
+			else {	/* possible? */
+				errstr =
+                                    "A failure in the SSL library occurred";
+			}
+			break;
+		}
+		default:
+			p = PY_SSL_ERROR_INVALID_ERROR_CODE;
+			errstr = "Invalid error code";
+		}
+	} else {
+		errstr = ERR_error_string(ERR_peek_last_error(), NULL);
+	}
+	PyOS_snprintf(buf, sizeof(buf), "_ssl.c:%d: %s", lineno, errstr);
+	v = Py_BuildValue("(is)", p, buf);
+	if (v != NULL) {
+		PyErr_SetObject(PySSLErrorObject, v);
+		Py_DECREF(v);
+	}
+	return NULL;
+}
+
+static PyObject *
+_setSSLError (char *errstr, int errcode, char *filename, int lineno) {
+
+	char buf[2048];
+	PyObject *v;
+
+	if (errstr == NULL) {
+		errcode = ERR_peek_last_error();
+		errstr = ERR_error_string(errcode, NULL);
+	}
+	PyOS_snprintf(buf, sizeof(buf), "_ssl.c:%d: %s", lineno, errstr);
+	v = Py_BuildValue("(is)", errcode, buf);
+	if (v != NULL) {
+		PyErr_SetObject(PySSLErrorObject, v);
+		Py_DECREF(v);
+	}
+	return NULL;
+}
+
+static PySSLObject *
+newPySSLObject(PySocketSockObject *Sock, char *key_file, char *cert_file,
+	       enum py_ssl_server_or_client socket_type,
+	       enum py_ssl_cert_requirements certreq,
+	       enum py_ssl_version proto_version,
+	       char *cacerts_file)
+{
+	PySSLObject *self;
+	char *errstr = NULL;
+	int ret;
+	int verification_mode;
+
+	self = PyObject_New(PySSLObject, &PySSL_Type); /* Create new object */
+	if (self == NULL)
+		return NULL;
+	memset(self->server, '\0', sizeof(char) * X509_NAME_MAXLEN);
+	memset(self->issuer, '\0', sizeof(char) * X509_NAME_MAXLEN);
+	self->peer_cert = NULL;
+	self->ssl = NULL;
+	self->ctx = NULL;
+	self->Socket = NULL;
+
+	/* Make sure the SSL error state is initialized */
+	(void) ERR_get_state();
+	ERR_clear_error();
+
+	if ((key_file && !cert_file) || (!key_file && cert_file)) {
+		errstr = ERRSTR("Both the key & certificate files "
+                                "must be specified");
+		goto fail;
+	}
+
+	if ((socket_type == PY_SSL_SERVER) &&
+	    ((key_file == NULL) || (cert_file == NULL))) {
+		errstr = ERRSTR("Both the key & certificate files "
+                                "must be specified for server-side operation");
+		goto fail;
+	}
+
+	PySSL_BEGIN_ALLOW_THREADS
+	if (proto_version == PY_SSL_VERSION_TLS1)
+		self->ctx = SSL_CTX_new(TLSv1_method()); /* Set up context */
+	else if (proto_version == PY_SSL_VERSION_SSL3)
+		self->ctx = SSL_CTX_new(SSLv3_method()); /* Set up context */
+	else if (proto_version == PY_SSL_VERSION_SSL2)
+		self->ctx = SSL_CTX_new(SSLv2_method()); /* Set up context */
+	else if (proto_version == PY_SSL_VERSION_SSL23)
+		self->ctx = SSL_CTX_new(SSLv23_method()); /* Set up context */
+        else if (proto_version == PY_SSL_VERSION_NOSSL2) {
+                self->ctx = SSL_CTX_new(SSLv23_method());
+                SSL_CTX_set_options(self->ctx, SSL_OP_NO_SSLv2);
+        };
+	PySSL_END_ALLOW_THREADS
+
+	if (self->ctx == NULL) {
+		errstr = ERRSTR("Invalid SSL protocol variant specified.");
+		goto fail;
+	}
+
+	if (certreq != PY_SSL_CERT_NONE) {
+		if (cacerts_file == NULL) {
+			errstr = ERRSTR("No root certificates specified for "
+                                  "verification of other-side certificates.");
+			goto fail;
+		} else {
+			PySSL_BEGIN_ALLOW_THREADS
+			ret = SSL_CTX_load_verify_locations(self->ctx,
+							    cacerts_file,
+                                                            NULL);
+			PySSL_END_ALLOW_THREADS
+			if (ret != 1) {
+				_setSSLError(NULL, 0, __FILE__, __LINE__);
+				goto fail;
+			}
+		}
+	}
+	if (key_file) {
+		PySSL_BEGIN_ALLOW_THREADS
+		ret = SSL_CTX_use_PrivateKey_file(self->ctx, key_file,
+						  SSL_FILETYPE_PEM);
+		PySSL_END_ALLOW_THREADS
+		if (ret != 1) {
+			_setSSLError(NULL, ret, __FILE__, __LINE__);
+			goto fail;
+		}
+
+		PySSL_BEGIN_ALLOW_THREADS
+		ret = SSL_CTX_use_certificate_chain_file(self->ctx,
+							 cert_file);
+		PySSL_END_ALLOW_THREADS
+		if (ret != 1) {
+			/*
+			fprintf(stderr, "ret is %d, errcode is %lu, %lu, with file \"%s\"\n",
+				ret, ERR_peek_error(), ERR_peek_last_error(), cert_file);
+				*/
+			if (ERR_peek_last_error() != 0) {
+				_setSSLError(NULL, ret, __FILE__, __LINE__);
+				goto fail;
+			}
+		}
+	}
+
+        /* ssl compatibility */
+        SSL_CTX_set_options(self->ctx, SSL_OP_ALL);
+        SSL_CTX_set_mode(self->ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
+
+	verification_mode = SSL_VERIFY_NONE;
+	if (certreq == PY_SSL_CERT_OPTIONAL)
+		verification_mode = SSL_VERIFY_PEER;
+	else if (certreq == PY_SSL_CERT_REQUIRED)
+		verification_mode = (SSL_VERIFY_PEER |
+				     SSL_VERIFY_FAIL_IF_NO_PEER_CERT);
+	SSL_CTX_set_verify(self->ctx, verification_mode,
+			   NULL); /* set verify lvl */
+
+	PySSL_BEGIN_ALLOW_THREADS
+	self->ssl = SSL_new(self->ctx); /* New ssl struct */
+	PySSL_END_ALLOW_THREADS
+	SSL_set_fd(self->ssl, Sock->sock_fd);	/* Set the socket for SSL */
+
+	/* If the socket is in non-blocking mode or timeout mode, set the BIO
+	 * to non-blocking mode (blocking is the default)
+	 */
+	if (Sock->sock_timeout >= 0.0) {
+		/* Set both the read and write BIO's to non-blocking mode */
+		BIO_set_nbio(SSL_get_rbio(self->ssl), 1);
+		BIO_set_nbio(SSL_get_wbio(self->ssl), 1);
+	}
+
+	PySSL_BEGIN_ALLOW_THREADS
+	if (socket_type == PY_SSL_CLIENT)
+		SSL_set_connect_state(self->ssl);
+	else
+		SSL_set_accept_state(self->ssl);
+	PySSL_END_ALLOW_THREADS
+
+	self->Socket = Sock;
+	Py_INCREF(self->Socket);
+	return self;
+ fail:
+	if (errstr)
+		PyErr_SetString(PySSLErrorObject, errstr);
+	Py_DECREF(self);
+	return NULL;
+}
+
+static PyObject *
+PySSL_sslwrap(PyObject *self, PyObject *args)
+{
+	PySocketSockObject *Sock;
+	int server_side = 0;
+	int verification_mode = PY_SSL_CERT_NONE;
+	int protocol = PY_SSL_VERSION_SSL23;
+	char *key_file = NULL;
+	char *cert_file = NULL;
+	char *cacerts_file = NULL;
+
+	if (!PyArg_ParseTuple(args, "O!i|zziiz:sslwrap",
+			      PySocketModule.Sock_Type,
+			      &Sock,
+			      &server_side,
+			      &key_file, &cert_file,
+			      &verification_mode, &protocol,
+			      &cacerts_file))
+		return NULL;
+
+	/*
+	fprintf(stderr,
+		"server_side is %d, keyfile %p, certfile %p, verify_mode %d, "
+		"protocol %d, certs %p\n",
+		server_side, key_file, cert_file, verification_mode,
+		protocol, cacerts_file);
+	 */
+
+	return (PyObject *) newPySSLObject(Sock, key_file, cert_file,
+					   server_side, verification_mode,
+					   protocol, cacerts_file);
+}
+
+PyDoc_STRVAR(ssl_doc,
+"sslwrap(socket, server_side, [keyfile, certfile, certs_mode, protocol,\n"
+"                              cacertsfile]) -> sslobject");
+
+/* SSL object methods */
+
+static PyObject *PySSL_SSLdo_handshake(PySSLObject *self)
+{
+	int ret;
+	int err;
+	int sockstate;
+
+	/* Actually negotiate SSL connection */
+	/* XXX If SSL_do_handshake() returns 0, it's also a failure. */
+	sockstate = 0;
+	do {
+		PySSL_BEGIN_ALLOW_THREADS
+		ret = SSL_do_handshake(self->ssl);
+		err = SSL_get_error(self->ssl, ret);
+		PySSL_END_ALLOW_THREADS
+		if(PyErr_CheckSignals()) {
+			return NULL;
+		}
+		if (err == SSL_ERROR_WANT_READ) {
+			sockstate = check_socket_and_wait_for_timeout(self->Socket, 0);
+		} else if (err == SSL_ERROR_WANT_WRITE) {
+			sockstate = check_socket_and_wait_for_timeout(self->Socket, 1);
+		} else {
+			sockstate = SOCKET_OPERATION_OK;
+		}
+		if (sockstate == SOCKET_HAS_TIMED_OUT) {
+			PyErr_SetString(PySSLErrorObject,
+				ERRSTR("The handshake operation timed out"));
+			return NULL;
+		} else if (sockstate == SOCKET_HAS_BEEN_CLOSED) {
+			PyErr_SetString(PySSLErrorObject,
+				ERRSTR("Underlying socket has been closed."));
+			return NULL;
+		} else if (sockstate == SOCKET_TOO_LARGE_FOR_SELECT) {
+			PyErr_SetString(PySSLErrorObject,
+			  ERRSTR("Underlying socket too large for select()."));
+			return NULL;
+		} else if (sockstate == SOCKET_IS_NONBLOCKING) {
+			break;
+		}
+	} while (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE);
+	if (ret < 1)
+		return PySSL_SetError(self, ret, __FILE__, __LINE__);
+	self->ssl->debug = 1;
+
+	if (self->peer_cert)
+		X509_free (self->peer_cert);
+	PySSL_BEGIN_ALLOW_THREADS
+	if ((self->peer_cert = SSL_get_peer_certificate(self->ssl))) {
+		X509_NAME_oneline(X509_get_subject_name(self->peer_cert),
+				  self->server, X509_NAME_MAXLEN);
+		X509_NAME_oneline(X509_get_issuer_name(self->peer_cert),
+				  self->issuer, X509_NAME_MAXLEN);
+	}
+	PySSL_END_ALLOW_THREADS
+
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+static PyObject *
+PySSL_server(PySSLObject *self)
+{
+	return PyString_FromString(self->server);
+}
+
+static PyObject *
+PySSL_issuer(PySSLObject *self)
+{
+	return PyString_FromString(self->issuer);
+}
+
+static PyObject *
+_create_tuple_for_attribute (ASN1_OBJECT *name, ASN1_STRING *value) {
+
+	char namebuf[X509_NAME_MAXLEN];
+	int buflen;
+	PyObject *name_obj;
+	PyObject *value_obj;
+	PyObject *attr;
+	unsigned char *valuebuf = NULL;
+
+	buflen = OBJ_obj2txt(namebuf, sizeof(namebuf), name, 0);
+	if (buflen < 0) {
+		_setSSLError(NULL, 0, __FILE__, __LINE__);
+		goto fail;
+	}
+	name_obj = PyString_FromStringAndSize(namebuf, buflen);
+	if (name_obj == NULL)
+		goto fail;
+	
+	buflen = ASN1_STRING_to_UTF8(&valuebuf, value);
+	if (buflen < 0) {
+		_setSSLError(NULL, 0, __FILE__, __LINE__);
+		Py_DECREF(name_obj);
+		goto fail;
+	}
+	value_obj = PyUnicode_DecodeUTF8((char *) valuebuf,
+						 buflen, "strict");
+	OPENSSL_free(valuebuf);
+	if (value_obj == NULL) {
+		Py_DECREF(name_obj);
+		goto fail;
+	}
+	attr = PyTuple_New(2);
+	if (attr == NULL) {
+		Py_DECREF(name_obj);
+		Py_DECREF(value_obj);
+		goto fail;
+	}
+	PyTuple_SET_ITEM(attr, 0, name_obj);
+	PyTuple_SET_ITEM(attr, 1, value_obj);
+	return attr;
+
+  fail:
+	return NULL;
+}
+
+static PyObject *
+_create_tuple_for_X509_NAME (X509_NAME *xname)
+{
+	PyObject *dn = NULL;    /* tuple which represents the "distinguished name" */
+        PyObject *rdn = NULL;   /* tuple to hold a "relative distinguished name" */
+	PyObject *rdnt;
+        PyObject *attr = NULL;   /* tuple to hold an attribute */
+        int entry_count = X509_NAME_entry_count(xname);
+	X509_NAME_ENTRY *entry;
+	ASN1_OBJECT *name;
+	ASN1_STRING *value;
+	int index_counter;
+	int rdn_level = -1;
+	int retcode;
+
+        dn = PyList_New(0);
+	if (dn == NULL)
+		return NULL;
+        /* now create another tuple to hold the top-level RDN */
+        rdn = PyList_New(0);
+	if (rdn == NULL)
+		goto fail0;
+
+	for (index_counter = 0;
+	     index_counter < entry_count;
+	     index_counter++)
+	{
+		entry = X509_NAME_get_entry(xname, index_counter);
+
+		/* check to see if we've gotten to a new RDN */
+		if (rdn_level >= 0) {
+			if (rdn_level != entry->set) {
+				/* yes, new RDN */
+				/* add old RDN to DN */
+				rdnt = PyList_AsTuple(rdn);
+				Py_DECREF(rdn);
+				if (rdnt == NULL)
+					goto fail0;
+				retcode = PyList_Append(dn, rdnt);
+				Py_DECREF(rdnt);
+				if (retcode < 0)
+					goto fail0;
+				/* create new RDN */
+				rdn = PyList_New(0);
+				if (rdn == NULL)
+					goto fail0;
+			}
+		}
+		rdn_level = entry->set;
+
+		/* now add this attribute to the current RDN */
+		name = X509_NAME_ENTRY_get_object(entry);
+		value = X509_NAME_ENTRY_get_data(entry);
+		attr = _create_tuple_for_attribute(name, value);
+                /*
+                fprintf(stderr, "RDN level %d, attribute %s: %s\n",
+                        entry->set,
+                        PyString_AS_STRING(PyTuple_GET_ITEM(attr, 0)),
+                        PyString_AS_STRING(PyTuple_GET_ITEM(attr, 1)));                        
+                */
+		if (attr == NULL)
+			goto fail1;
+                retcode = PyList_Append(rdn, attr);
+		Py_DECREF(attr);
+		if (retcode < 0)
+			goto fail1;
+	}
+	/* now, there's typically a dangling RDN */
+	if ((rdn != NULL) && (PyList_Size(rdn) > 0)) {
+		rdnt = PyList_AsTuple(rdn);
+		Py_DECREF(rdn);
+		if (rdnt == NULL)
+			goto fail0;
+		retcode = PyList_Append(dn, rdnt);
+		Py_DECREF(rdnt);
+		if (retcode < 0)
+			goto fail0;
+	}
+
+	/* convert list to tuple */
+	rdnt = PyList_AsTuple(dn);
+	Py_DECREF(dn);
+	if (rdnt == NULL)
+		return NULL;
+	return rdnt;
+
+  fail1:
+	Py_XDECREF(rdn);
+
+  fail0:
+	Py_XDECREF(dn);
+	return NULL;
+}
+
+static PyObject *
+_get_peer_alt_names (X509 *certificate) {
+                  
+	/* this code follows the procedure outlined in
+	   OpenSSL's crypto/x509v3/v3_prn.c:X509v3_EXT_print()
+	   function to extract the STACK_OF(GENERAL_NAME),
+	   then iterates through the stack to add the
+	   names. */
+
+	int i, j;
+	PyObject *peer_alt_names = Py_None;
+	PyObject *v, *t;
+	X509_EXTENSION *ext = NULL;
+	GENERAL_NAMES *names = NULL;
+	GENERAL_NAME *name;
+	X509V3_EXT_METHOD *method;	
+	BIO *biobuf = NULL;
+	char buf[2048];
+	char *vptr;
+	int len;
+	unsigned char *p;
+
+	if (certificate == NULL)
+		return peer_alt_names;
+
+	/* get a memory buffer */
+	biobuf = BIO_new(BIO_s_mem());
+
+	i = 0;
+	while ((i = X509_get_ext_by_NID(
+			certificate, NID_subject_alt_name, i)) >= 0) {
+
+		if (peer_alt_names == Py_None) {
+                        peer_alt_names = PyList_New(0);
+                        if (peer_alt_names == NULL)
+				goto fail;
+		}
+		
+		/* now decode the altName */
+		ext = X509_get_ext(certificate, i);
+		if(!(method = X509V3_EXT_get(ext))) {
+			PyErr_SetString(PySSLErrorObject,
+					ERRSTR("No method for internalizing subjectAltName!"));
+			goto fail;
+		}
+
+		p = ext->value->data;
+		if(method->it)
+			names = (GENERAL_NAMES*) (ASN1_item_d2i(NULL,
+								(const unsigned char **) (&p),
+								ext->value->length,
+								ASN1_ITEM_ptr(method->it)));
+		else
+			names = (GENERAL_NAMES*) (method->d2i(NULL,
+							      (const unsigned char **) (&p),
+							      ext->value->length));
+
+		for(j = 0; j < sk_GENERAL_NAME_num(names); j++) {
+
+			/* get a rendering of each name in the set of names */
+
+			name = sk_GENERAL_NAME_value(names, j);
+			if (name->type == GEN_DIRNAME) {
+
+				/* we special-case DirName as a tuple of tuples of attributes */
+
+				t = PyTuple_New(2);
+				if (t == NULL) {
+					goto fail;
+				}
+
+				v = PyString_FromString("DirName");
+				if (v == NULL) {
+					Py_DECREF(t);
+					goto fail;
+				}
+				PyTuple_SET_ITEM(t, 0, v);
+
+				v = _create_tuple_for_X509_NAME (name->d.dirn);
+				if (v == NULL) {
+					Py_DECREF(t);
+					goto fail;
+				}
+				PyTuple_SET_ITEM(t, 1, v);
+				
+			} else {
+
+				/* for everything else, we use the OpenSSL print form */
+
+				(void) BIO_reset(biobuf);
+				GENERAL_NAME_print(biobuf, name);
+				len = BIO_gets(biobuf, buf, sizeof(buf)-1);
+				if (len < 0) {
+					_setSSLError(NULL, 0, __FILE__, __LINE__);
+					goto fail;
+				}
+				vptr = strchr(buf, ':');
+				if (vptr == NULL)
+					goto fail;
+				t = PyTuple_New(2);
+				if (t == NULL)
+					goto fail;
+				v = PyString_FromStringAndSize(buf, (vptr - buf));
+				if (v == NULL) {
+					Py_DECREF(t);
+					goto fail;
+				}
+				PyTuple_SET_ITEM(t, 0, v);
+				v = PyString_FromStringAndSize((vptr + 1), (len - (vptr - buf + 1)));
+				if (v == NULL) {
+					Py_DECREF(t);
+					goto fail;
+				}
+				PyTuple_SET_ITEM(t, 1, v);
+			}
+
+			/* and add that rendering to the list */
+
+			if (PyList_Append(peer_alt_names, t) < 0) {
+				Py_DECREF(t);
+				goto fail;
+			}
+			Py_DECREF(t);
+		}
+	}
+	BIO_free(biobuf);
+	if (peer_alt_names != Py_None) {
+		v = PyList_AsTuple(peer_alt_names);
+		Py_DECREF(peer_alt_names);
+		return v;
+	} else {
+		return peer_alt_names;
+	}
+	
+
+  fail:
+	if (biobuf != NULL)
+		BIO_free(biobuf);
+
+	if (peer_alt_names != Py_None) {
+		Py_XDECREF(peer_alt_names);
+	}
+
+	return NULL;
+}
+
+static PyObject *
+_decode_certificate (X509 *certificate, int verbose) {
+
+	PyObject *retval = NULL;
+	BIO *biobuf = NULL;
+	PyObject *peer;
+	PyObject *peer_alt_names = NULL;
+	PyObject *issuer;
+	PyObject *version;
+	PyObject *sn_obj;
+	PyObject *pubkey_obj;
+	ASN1_INTEGER *serialNumber;
+	char buf[2048];
+	int len;
+	ASN1_TIME *notBefore, *notAfter;
+	PyObject *pnotBefore, *pnotAfter;
+
+	retval = PyDict_New();
+	if (retval == NULL)
+		return NULL;
+
+	peer = _create_tuple_for_X509_NAME(
+		X509_get_subject_name(certificate));
+	if (peer == NULL)
+		goto fail0;
+	if (PyDict_SetItemString(retval, (const char *) "subject", peer) < 0) {
+		Py_DECREF(peer);
+		goto fail0;
+	}
+	Py_DECREF(peer);
+
+	if (verbose) {
+		issuer = _create_tuple_for_X509_NAME(
+			X509_get_issuer_name(certificate));
+		if (issuer == NULL)
+			goto fail0;
+		if (PyDict_SetItemString(retval, (const char *)"issuer", issuer) < 0) {
+			Py_DECREF(issuer);
+			goto fail0;
+		}
+		Py_DECREF(issuer);
+	
+		version = PyInt_FromLong(X509_get_version(certificate) + 1);
+		if (PyDict_SetItemString(retval, "version", version) < 0) {
+			Py_DECREF(version);
+			goto fail0;
+		}
+		Py_DECREF(version);
+	}
+	
+	/* get a memory buffer */
+	biobuf = BIO_new(BIO_s_mem());
+	
+	if (verbose) {
+
+		(void) BIO_reset(biobuf);
+		serialNumber = X509_get_serialNumber(certificate);
+		/* should not exceed 20 octets, 160 bits, so buf is big enough */
+		i2a_ASN1_INTEGER(biobuf, serialNumber);
+		len = BIO_gets(biobuf, buf, sizeof(buf)-1);
+		if (len < 0) {
+			_setSSLError(NULL, 0, __FILE__, __LINE__);
+			goto fail1;
+		}
+		sn_obj = PyString_FromStringAndSize(buf, len);
+		if (sn_obj == NULL)
+			goto fail1;
+		if (PyDict_SetItemString(retval, "serialNumber", sn_obj) < 0) {
+			Py_DECREF(sn_obj);
+			goto fail1;
+		}
+		Py_DECREF(sn_obj);
+
+		(void) BIO_reset(biobuf);
+		notBefore = X509_get_notBefore(certificate);
+		ASN1_TIME_print(biobuf, notBefore);
+		len = BIO_gets(biobuf, buf, sizeof(buf)-1);
+		if (len < 0) {
+			_setSSLError(NULL, 0, __FILE__, __LINE__);
+			goto fail1;
+		}
+		pnotBefore = PyString_FromStringAndSize(buf, len);
+		if (pnotBefore == NULL)
+			goto fail1;
+		if (PyDict_SetItemString(retval, "notBefore", pnotBefore) < 0) {
+			Py_DECREF(pnotBefore);
+			goto fail1;
+		}
+		Py_DECREF(pnotBefore);
+	}
+
+	(void) BIO_reset(biobuf);
+	notAfter = X509_get_notAfter(certificate);
+	ASN1_TIME_print(biobuf, notAfter);
+	len = BIO_gets(biobuf, buf, sizeof(buf)-1);
+	if (len < 0) {
+		_setSSLError(NULL, 0, __FILE__, __LINE__);
+		goto fail1;
+	}
+	pnotAfter = PyString_FromStringAndSize(buf, len);
+	if (pnotAfter == NULL)
+		goto fail1;
+	if (PyDict_SetItemString(retval, "notAfter", pnotAfter) < 0) {
+		Py_DECREF(pnotAfter);
+		goto fail1;
+	}
+	Py_DECREF(pnotAfter);
+
+	/* Now look for subjectAltName */
+
+	peer_alt_names = _get_peer_alt_names(certificate);
+	if (peer_alt_names == NULL)
+		goto fail1;
+	else if (peer_alt_names != Py_None) {
+		if (PyDict_SetItemString(retval, "subjectAltName",
+					 peer_alt_names) < 0) {
+			Py_DECREF(peer_alt_names);
+			goto fail1;
+		}
+		Py_DECREF(peer_alt_names);
+	}
+	
+        /* And get the public key of the subject */
+        (void) BIO_reset(biobuf);
+        EVP_PKEY *key = X509_get_pubkey(certificate);
+        len = i2d_PUBKEY_bio(biobuf, key);
+        if (len < 0) {
+                _setSSLError(NULL, 0, __FILE__, __LINE__);
+                goto fail1;
+        }
+        len = BIO_gets(biobuf, buf, sizeof(buf)-1);
+        if (len < 0) {
+                _setSSLError(NULL, 0, __FILE__, __LINE__);
+                goto fail1;
+        }
+        pubkey_obj = PyString_FromStringAndSize(buf, len);
+        if (pubkey_obj == NULL)
+                goto fail1;
+        if (PyDict_SetItemString(retval, "subjectPublicKey", pubkey_obj) < 0) {
+                Py_DECREF(pubkey_obj);
+        goto fail1;
+        }
+        Py_DECREF(pubkey_obj);
+        
+	BIO_free(biobuf);
+	return retval;
+
+  fail1:
+	if (biobuf != NULL)
+		BIO_free(biobuf);
+  fail0:
+	Py_XDECREF(retval);
+	return NULL;
+}
+
+
+static PyObject *
+PySSL_test_decode_certificate (PyObject *mod, PyObject *args) {
+
+	PyObject *retval = NULL;
+	char *filename = NULL;
+	X509 *x=NULL;
+	BIO *cert;
+	int verbose = 1;
+
+	if (!PyArg_ParseTuple(args, "s|i:test_decode_certificate", &filename, &verbose))
+		return NULL;
+
+	if ((cert=BIO_new(BIO_s_file())) == NULL) {
+		PyErr_SetString(PySSLErrorObject, "Can't malloc memory to read file");
+		goto fail0;
+	}
+
+	if (BIO_read_filename(cert,filename) <= 0) {
+		PyErr_SetString(PySSLErrorObject, "Can't open file");
+		goto fail0;
+	}
+
+	x = PEM_read_bio_X509_AUX(cert,NULL, NULL, NULL);
+	if (x == NULL) {
+		PyErr_SetString(PySSLErrorObject, "Error decoding PEM-encoded file");
+		goto fail0;
+	}
+
+	retval = _decode_certificate(x, verbose);
+
+  fail0:
+		
+	if (cert != NULL) BIO_free(cert);
+	return retval;
+}
+
+
+static PyObject *
+PySSL_peercert(PySSLObject *self, PyObject *args)
+{
+	PyObject *retval = NULL;
+	int len;
+	int verification;
+	PyObject *binary_mode = Py_None;
+
+	if (!PyArg_ParseTuple(args, "|O:peer_certificate", &binary_mode))
+		return NULL;
+
+	if (!self->peer_cert) {
+		Py_INCREF(Py_None);
+		return Py_None;
+	}
+
+	if (PyObject_IsTrue(binary_mode)) {
+		/* return cert in DER-encoded format */
+
+		unsigned char *bytes_buf = NULL;
+
+		bytes_buf = NULL;
+		len = i2d_X509(self->peer_cert, &bytes_buf);
+		if (len < 0) {
+			PySSL_SetError(self, len, __FILE__, __LINE__);
+			return NULL;
+		}
+		retval = PyString_FromStringAndSize((const char *) bytes_buf, len);
+		OPENSSL_free(bytes_buf);
+		return retval;
+
+	} else {
+
+		verification = SSL_CTX_get_verify_mode(self->ctx);
+		if ((verification & SSL_VERIFY_PEER) == 0)
+			return PyDict_New();
+		else
+			return _decode_certificate (self->peer_cert, 0);
+	}
+}
+
+PyDoc_STRVAR(PySSL_peercert_doc,
+"peer_certificate([der=False]) -> certificate\n\
+\n\
+Returns the certificate for the peer.  If no certificate was provided,\n\
+returns None.  If a certificate was provided, but not validated, returns\n\
+an empty dictionary.  Otherwise returns a dict containing information\n\
+about the peer certificate.\n\
+\n\
+If the optional argument is True, returns a DER-encoded copy of the\n\
+peer certificate, or None if no certificate was provided.  This will\n\
+return the certificate even if it wasn't validated.");
+
+static PyObject *PySSL_cipher (PySSLObject *self) {
+
+	PyObject *retval, *v;
+	SSL_CIPHER *current;
+	char *cipher_name;
+	char *cipher_protocol;
+
+	if (self->ssl == NULL)
+		return Py_None;
+	current = SSL_get_current_cipher(self->ssl);
+	if (current == NULL)
+		return Py_None;
+
+	retval = PyTuple_New(3);
+	if (retval == NULL)
+		return NULL;
+
+	cipher_name = (char *) SSL_CIPHER_get_name(current);
+	if (cipher_name == NULL) {
+		PyTuple_SET_ITEM(retval, 0, Py_None);
+	} else {
+		v = PyString_FromString(cipher_name);
+		if (v == NULL)
+			goto fail0;
+		PyTuple_SET_ITEM(retval, 0, v);
+	}
+	cipher_protocol = SSL_CIPHER_get_version(current);
+	if (cipher_protocol == NULL) {
+		PyTuple_SET_ITEM(retval, 1, Py_None);
+	} else {
+		v = PyString_FromString(cipher_protocol);
+		if (v == NULL)
+			goto fail0;
+		PyTuple_SET_ITEM(retval, 1, v);
+	}
+	v = PyInt_FromLong(SSL_CIPHER_get_bits(current, NULL));
+	if (v == NULL)
+		goto fail0;
+	PyTuple_SET_ITEM(retval, 2, v);
+	return retval;
+	
+  fail0:
+	Py_DECREF(retval);
+	return NULL;
+}
+
+static void PySSL_dealloc(PySSLObject *self)
+{
+	if (self->peer_cert)	/* Possible not to have one? */
+		X509_free (self->peer_cert);
+	if (self->ssl)
+		SSL_free(self->ssl);
+	if (self->ctx)
+		SSL_CTX_free(self->ctx);
+	Py_XDECREF(self->Socket);
+	PyObject_Del(self);
+}
+
+/* If the socket has a timeout, do a select()/poll() on the socket.
+   The argument writing indicates the direction.
+   Returns one of the possibilities in the timeout_state enum (above).
+ */
+
+static int
+check_socket_and_wait_for_timeout(PySocketSockObject *s, int writing)
+{
+	fd_set fds;
+	struct timeval tv;
+	int rc;
+
+	/* Nothing to do unless we're in timeout mode (not non-blocking) */
+	if (s->sock_timeout < 0.0)
+		return SOCKET_IS_BLOCKING;
+	else if (s->sock_timeout == 0.0)
+		return SOCKET_IS_NONBLOCKING;
+
+	/* Guard against closed socket */
+	if (s->sock_fd < 0)
+		return SOCKET_HAS_BEEN_CLOSED;
+
+	/* Prefer poll, if available, since you can poll() any fd
+	 * which can't be done with select(). */
+#ifdef HAVE_POLL
+	{
+		struct pollfd pollfd;
+		int timeout;
+
+		pollfd.fd = s->sock_fd;
+		pollfd.events = writing ? POLLOUT : POLLIN;
+
+		/* s->sock_timeout is in seconds, timeout in ms */
+		timeout = (int)(s->sock_timeout * 1000 + 0.5);
+		PySSL_BEGIN_ALLOW_THREADS
+		rc = poll(&pollfd, 1, timeout);
+		PySSL_END_ALLOW_THREADS
+
+		goto normal_return;
+	}
+#endif
+
+	/* Guard against socket too large for select*/
+#ifndef Py_SOCKET_FD_CAN_BE_GE_FD_SETSIZE
+	if (s->sock_fd >= FD_SETSIZE)
+		return SOCKET_TOO_LARGE_FOR_SELECT;
+#endif
+
+	/* Construct the arguments to select */
+	tv.tv_sec = (int)s->sock_timeout;
+	tv.tv_usec = (int)((s->sock_timeout - tv.tv_sec) * 1e6);
+	FD_ZERO(&fds);
+	FD_SET(s->sock_fd, &fds);
+
+	/* See if the socket is ready */
+	PySSL_BEGIN_ALLOW_THREADS
+	if (writing)
+		rc = select(s->sock_fd+1, NULL, &fds, NULL, &tv);
+	else
+		rc = select(s->sock_fd+1, &fds, NULL, NULL, &tv);
+	PySSL_END_ALLOW_THREADS
+
+#ifdef HAVE_POLL
+normal_return:
+#endif
+	/* Return SOCKET_TIMED_OUT on timeout, SOCKET_OPERATION_OK otherwise
+	   (when we are able to write or when there's something to read) */
+	return rc == 0 ? SOCKET_HAS_TIMED_OUT : SOCKET_OPERATION_OK;
+}
+
+static PyObject *PySSL_SSLwrite(PySSLObject *self, PyObject *args)
+{
+	char *data;
+	int len;
+	int count;
+	int sockstate;
+	int err;
+        int nonblocking;
+
+	if (!PyArg_ParseTuple(args, "s#:write", &data, &count))
+		return NULL;
+
+        /* just in case the blocking state of the socket has been changed */
+	nonblocking = (self->Socket->sock_timeout >= 0.0);
+        BIO_set_nbio(SSL_get_rbio(self->ssl), nonblocking);
+        BIO_set_nbio(SSL_get_wbio(self->ssl), nonblocking);
+
+	sockstate = check_socket_and_wait_for_timeout(self->Socket, 1);
+	if (sockstate == SOCKET_HAS_TIMED_OUT) {
+		PyErr_SetString(PySSLErrorObject,
+                                "The write operation timed out");
+		return NULL;
+	} else if (sockstate == SOCKET_HAS_BEEN_CLOSED) {
+		PyErr_SetString(PySSLErrorObject,
+                                "Underlying socket has been closed.");
+		return NULL;
+	} else if (sockstate == SOCKET_TOO_LARGE_FOR_SELECT) {
+		PyErr_SetString(PySSLErrorObject,
+                                "Underlying socket too large for select().");
+		return NULL;
+	}
+	do {
+		err = 0;
+		PySSL_BEGIN_ALLOW_THREADS
+		len = SSL_write(self->ssl, data, count);
+		err = SSL_get_error(self->ssl, len);
+		PySSL_END_ALLOW_THREADS
+		if(PyErr_CheckSignals()) {
+			return NULL;
+		}
+		if (err == SSL_ERROR_WANT_READ) {
+			sockstate =
+                            check_socket_and_wait_for_timeout(self->Socket, 0);
+		} else if (err == SSL_ERROR_WANT_WRITE) {
+			sockstate =
+                            check_socket_and_wait_for_timeout(self->Socket, 1);
+		} else {
+			sockstate = SOCKET_OPERATION_OK;
+		}
+		if (sockstate == SOCKET_HAS_TIMED_OUT) {
+			PyErr_SetString(PySSLErrorObject,
+                                        "The write operation timed out");
+			return NULL;
+		} else if (sockstate == SOCKET_HAS_BEEN_CLOSED) {
+			PyErr_SetString(PySSLErrorObject,
+                                        "Underlying socket has been closed.");
+			return NULL;
+		} else if (sockstate == SOCKET_IS_NONBLOCKING) {
+			break;
+		}
+	} while (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE);
+	if (len > 0)
+		return PyInt_FromLong(len);
+	else
+		return PySSL_SetError(self, len, __FILE__, __LINE__);
+}
+
+PyDoc_STRVAR(PySSL_SSLwrite_doc,
+"write(s) -> len\n\
+\n\
+Writes the string s into the SSL object.  Returns the number\n\
+of bytes written.");
+
+static PyObject *PySSL_SSLpending(PySSLObject *self)
+{
+	int count = 0;
+
+	PySSL_BEGIN_ALLOW_THREADS
+	count = SSL_pending(self->ssl);
+	PySSL_END_ALLOW_THREADS
+	if (count < 0)
+		return PySSL_SetError(self, count, __FILE__, __LINE__);
+	else
+		return PyInt_FromLong(count);
+}
+
+PyDoc_STRVAR(PySSL_SSLpending_doc,
+"pending() -> count\n\
+\n\
+Returns the number of already decrypted bytes available for read,\n\
+pending on the connection.\n");
+
+static PyObject *PySSL_SSLread(PySSLObject *self, PyObject *args)
+{
+	PyObject *buf;
+	int count = 0;
+	int len = 1024;
+	int sockstate;
+	int err;
+        int nonblocking;
+
+	if (!PyArg_ParseTuple(args, "|i:read", &len))
+		return NULL;
+
+	if (!(buf = PyString_FromStringAndSize((char *) 0, len)))
+		return NULL;
+
+        /* just in case the blocking state of the socket has been changed */
+	nonblocking = (self->Socket->sock_timeout >= 0.0);
+        BIO_set_nbio(SSL_get_rbio(self->ssl), nonblocking);
+        BIO_set_nbio(SSL_get_wbio(self->ssl), nonblocking);
+
+	/* first check if there are bytes ready to be read */
+	PySSL_BEGIN_ALLOW_THREADS
+	count = SSL_pending(self->ssl);
+	PySSL_END_ALLOW_THREADS
+
+	if (!count) {
+		sockstate = check_socket_and_wait_for_timeout(self->Socket, 0);
+		if (sockstate == SOCKET_HAS_TIMED_OUT) {
+			PyErr_SetString(PySSLErrorObject,
+					"The read operation timed out");
+			Py_DECREF(buf);
+			return NULL;
+		} else if (sockstate == SOCKET_TOO_LARGE_FOR_SELECT) {
+			PyErr_SetString(PySSLErrorObject,
+				"Underlying socket too large for select().");
+			Py_DECREF(buf);
+			return NULL;
+		} else if (sockstate == SOCKET_HAS_BEEN_CLOSED) {
+			if (SSL_get_shutdown(self->ssl) !=
+			    SSL_RECEIVED_SHUTDOWN)
+			{
+                            Py_DECREF(buf);
+                            PyErr_SetString(PySSLErrorObject,
+                              "Socket closed without SSL shutdown handshake");
+				return NULL;
+			} else {
+				/* should contain a zero-length string */
+				_PyString_Resize(&buf, 0);
+				return buf;
+			}
+		}
+	}
+	do {
+		err = 0;
+		PySSL_BEGIN_ALLOW_THREADS
+		count = SSL_read(self->ssl, PyString_AsString(buf), len);
+		err = SSL_get_error(self->ssl, count);
+		PySSL_END_ALLOW_THREADS
+		if(PyErr_CheckSignals()) {
+			Py_DECREF(buf);
+			return NULL;
+		}
+		if (err == SSL_ERROR_WANT_READ) {
+			sockstate =
+			  check_socket_and_wait_for_timeout(self->Socket, 0);
+		} else if (err == SSL_ERROR_WANT_WRITE) {
+			sockstate =
+			  check_socket_and_wait_for_timeout(self->Socket, 1);
+		} else if ((err == SSL_ERROR_ZERO_RETURN) &&
+			   (SSL_get_shutdown(self->ssl) ==
+			    SSL_RECEIVED_SHUTDOWN))
+		{
+			_PyString_Resize(&buf, 0);
+			return buf;
+		} else {
+			sockstate = SOCKET_OPERATION_OK;
+		}
+		if (sockstate == SOCKET_HAS_TIMED_OUT) {
+			PyErr_SetString(PySSLErrorObject,
+					"The read operation timed out");
+			Py_DECREF(buf);
+			return NULL;
+		} else if (sockstate == SOCKET_IS_NONBLOCKING) {
+			break;
+		}
+	} while (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE);
+	if (count <= 0) {
+		Py_DECREF(buf);
+		return PySSL_SetError(self, count, __FILE__, __LINE__);
+	}
+	if (count != len)
+		_PyString_Resize(&buf, count);
+	return buf;
+}
+
+PyDoc_STRVAR(PySSL_SSLread_doc,
+"read([len]) -> string\n\
+\n\
+Read up to len bytes from the SSL socket.");
+
+static PyObject *PySSL_SSLshutdown(PySSLObject *self)
+{
+	int err;
+
+	/* Guard against closed socket */
+	if (self->Socket->sock_fd < 0) {
+		PyErr_SetString(PySSLErrorObject,
+				"Underlying socket has been closed.");
+		return NULL;
+	}
+
+	PySSL_BEGIN_ALLOW_THREADS
+	err = SSL_shutdown(self->ssl);
+	if (err == 0) {
+		/* we need to call it again to finish the shutdown */
+		err = SSL_shutdown(self->ssl);
+	}
+	PySSL_END_ALLOW_THREADS
+
+	if (err < 0)
+		return PySSL_SetError(self, err, __FILE__, __LINE__);
+	else {
+		Py_INCREF(self->Socket);
+		return (PyObject *) (self->Socket);
+	}
+}
+
+PyDoc_STRVAR(PySSL_SSLshutdown_doc,
+"shutdown(s) -> socket\n\
+\n\
+Does the SSL shutdown handshake with the remote end, and returns\n\
+the underlying socket object.");
+
+static PyMethodDef PySSLMethods[] = {
+	{"do_handshake", (PyCFunction)PySSL_SSLdo_handshake, METH_NOARGS},
+	{"write", (PyCFunction)PySSL_SSLwrite, METH_VARARGS,
+	 PySSL_SSLwrite_doc},
+	{"read", (PyCFunction)PySSL_SSLread, METH_VARARGS,
+	 PySSL_SSLread_doc},
+	{"pending", (PyCFunction)PySSL_SSLpending, METH_NOARGS,
+	 PySSL_SSLpending_doc},
+	{"server", (PyCFunction)PySSL_server, METH_NOARGS},
+	{"issuer", (PyCFunction)PySSL_issuer, METH_NOARGS},
+	{"peer_certificate", (PyCFunction)PySSL_peercert, METH_VARARGS,
+	 PySSL_peercert_doc},
+	{"cipher", (PyCFunction)PySSL_cipher, METH_NOARGS},
+	{"shutdown", (PyCFunction)PySSL_SSLshutdown, METH_NOARGS,
+         PySSL_SSLshutdown_doc},
+	{NULL, NULL}
+};
+
+static PyObject *PySSL_getattr(PySSLObject *self, char *name)
+{
+	return Py_FindMethod(PySSLMethods, (PyObject *)self, name);
+}
+
+static PyTypeObject PySSL_Type = {
+	PyObject_HEAD_INIT(NULL)
+	0,
+	"_ssl2.SSLContext",		/*tp_name*/
+	sizeof(PySSLObject),		/*tp_basicsize*/
+	0,				/*tp_itemsize*/
+	/* methods */
+	(destructor)PySSL_dealloc,	/*tp_dealloc*/
+	0,				/*tp_print*/
+	(getattrfunc)PySSL_getattr,	/*tp_getattr*/
+	0,				/*tp_setattr*/
+	0,				/*tp_compare*/
+	0,				/*tp_repr*/
+	0,				/*tp_as_number*/
+	0,				/*tp_as_sequence*/
+	0,				/*tp_as_mapping*/
+	0,				/*tp_hash*/
+};
+
+#ifdef HAVE_OPENSSL_RAND
+
+/* helper routines for seeding the SSL PRNG */
+static PyObject *
+PySSL_RAND_add(PyObject *self, PyObject *args)
+{
+    char *buf;
+    int len;
+    double entropy;
+
+    if (!PyArg_ParseTuple(args, "s#d:RAND_add", &buf, &len, &entropy))
+	return NULL;
+    RAND_add(buf, len, entropy);
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+PyDoc_STRVAR(PySSL_RAND_add_doc,
+"RAND_add(string, entropy)\n\
+\n\
+Mix string into the OpenSSL PRNG state.  entropy (a float) is a lower\n\
+bound on the entropy contained in string.  See RFC 1750.");
+
+static PyObject *
+PySSL_RAND_status(PyObject *self)
+{
+    return PyInt_FromLong(RAND_status());
+}
+
+PyDoc_STRVAR(PySSL_RAND_status_doc,
+"RAND_status() -> 0 or 1\n\
+\n\
+Returns 1 if the OpenSSL PRNG has been seeded with enough data and 0 if not.\n\
+It is necessary to seed the PRNG with RAND_add() on some platforms before\n\
+using the ssl() function.");
+
+static PyObject *
+PySSL_RAND_egd(PyObject *self, PyObject *arg)
+{
+    int bytes;
+
+    if (!PyString_Check(arg))
+	return PyErr_Format(PyExc_TypeError,
+			    "RAND_egd() expected string, found %s",
+			    Py_Type(arg)->tp_name);
+    bytes = RAND_egd(PyString_AS_STRING(arg));
+    if (bytes == -1) {
+	PyErr_SetString(PySSLErrorObject,
+			"EGD connection failed or EGD did not return "
+			"enough data to seed the PRNG");
+	return NULL;
+    }
+    return PyInt_FromLong(bytes);
+}
+
+PyDoc_STRVAR(PySSL_RAND_egd_doc,
+"RAND_egd(path) -> bytes\n\
+\n\
+Queries the entropy gather daemon (EGD) on the socket named by 'path'.\n\
+Returns number of bytes read.  Raises SSLError if connection to EGD\n\
+fails or if it does provide enough data to seed PRNG.");
+
+#endif
+
+/* List of functions exported by this module. */
+
+static PyMethodDef PySSL_methods[] = {
+	{"sslwrap",             PySSL_sslwrap,
+         METH_VARARGS, ssl_doc},
+	{"_test_decode_cert",	PySSL_test_decode_certificate,
+	 METH_VARARGS},
+#ifdef HAVE_OPENSSL_RAND
+	{"RAND_add",            PySSL_RAND_add, METH_VARARGS,
+	 PySSL_RAND_add_doc},
+	{"RAND_egd",            PySSL_RAND_egd, METH_O,
+	 PySSL_RAND_egd_doc},
+	{"RAND_status",         (PyCFunction)PySSL_RAND_status, METH_NOARGS,
+	 PySSL_RAND_status_doc},
+#endif
+	{NULL,                  NULL}            /* Sentinel */
+};
+
+
+#ifdef WITH_THREAD
+
+/* an implementation of OpenSSL threading operations in terms
+   of the Python C thread library */
+
+static PyThread_type_lock *_ssl_locks = NULL;
+
+static unsigned long _ssl_thread_id_function (void) {
+	return PyThread_get_thread_ident();
+}
+
+static void _ssl_thread_locking_function (int mode, int n, const char *file, int line) {
+	/* this function is needed to perform locking on shared data
+	   structures. (Note that OpenSSL uses a number of global data
+	   structures that will be implicitly shared whenever multiple threads
+	   use OpenSSL.) Multi-threaded applications will crash at random if
+	   it is not set.
+
+	   locking_function() must be able to handle up to CRYPTO_num_locks()
+	   different mutex locks. It sets the n-th lock if mode & CRYPTO_LOCK, and
+	   releases it otherwise.
+
+	   file and line are the file number of the function setting the
+	   lock. They can be useful for debugging.
+	*/
+
+	if ((_ssl_locks == NULL) ||
+	    (n < 0) || (n >= _ssl_locks_count))
+		return;
+
+	if (mode & CRYPTO_LOCK) {
+		PyThread_acquire_lock(_ssl_locks[n], 1);
+	} else {
+		PyThread_release_lock(_ssl_locks[n]);
+	}
+}
+
+static int _setup_ssl_threads(void) {
+
+	int i;
+
+	if (_ssl_locks == NULL) {
+		_ssl_locks_count = CRYPTO_num_locks();
+		_ssl_locks = (PyThread_type_lock *)
+			malloc(sizeof(PyThread_type_lock) * _ssl_locks_count);
+		if (_ssl_locks == NULL)
+			return 0;
+		memset(_ssl_locks, 0, sizeof(PyThread_type_lock) * _ssl_locks_count);
+		for (i = 0;  i < _ssl_locks_count;  i++) {
+			_ssl_locks[i] = PyThread_allocate_lock();
+			if (_ssl_locks[i] == NULL) {
+				int j;
+				for (j = 0;  j < i;  j++) {
+					PyThread_free_lock(_ssl_locks[j]);
+				}
+				free(_ssl_locks);
+				return 0;
+			}
+		}
+		CRYPTO_set_locking_callback(_ssl_thread_locking_function);
+		CRYPTO_set_id_callback(_ssl_thread_id_function);
+	}
+	return 1;
+}
+
+#endif	/* def HAVE_THREAD */
+
+PyDoc_STRVAR(module_doc,
+"Implementation module for SSL socket operations.  See the socket module\n\
+for documentation.");
+
+PyMODINIT_FUNC
+init_ssl2(void)
+{
+	PyObject *m, *d;
+        PyObject *socket_error = NULL;
+
+	Py_Type(&PySSL_Type) = &PyType_Type;
+
+	/* Load _socket module and its C API */
+	if (PySocketModule_ImportModuleAndAPI())
+		return;
+
+        /* get the socket error object to subtype */
+        m = PyImport_ImportModule("_socket");
+        if (m == NULL)
+		return;
+	d = PyModule_GetDict(m);
+	if (d == NULL)
+		return;
+	socket_error = PyMapping_GetItemString(d, "error");
+	if (socket_error == NULL)
+		return;
+	Py_INCREF(socket_error);
+
+	m = Py_InitModule3("_ssl2", PySSL_methods, module_doc);
+	if (m == NULL)
+		return;
+	d = PyModule_GetDict(m);
+	if (d == NULL)
+		return;
+
+	/* Init OpenSSL */
+	SSL_load_error_strings();
+#ifdef WITH_THREAD
+	/* note that this will start threading if not already started */
+	if (!_setup_ssl_threads()) {
+		return;
+	}
+#endif
+	SSLeay_add_ssl_algorithms();
+
+	/* Add symbols to module dict */
+	PySSLErrorObject = PyErr_NewException("ssl.SSLError",
+					      socket_error,
+					      NULL);
+	if (PySSLErrorObject == NULL)
+		return;
+	if (PyDict_SetItemString(d, "SSLError", PySSLErrorObject) != 0)
+		return;
+	if (PyDict_SetItemString(d, "SSLType",
+				 (PyObject *)&PySSL_Type) != 0)
+		return;
+	PyModule_AddIntConstant(m, "SSL_ERROR_ZERO_RETURN",
+				PY_SSL_ERROR_ZERO_RETURN);
+	PyModule_AddIntConstant(m, "SSL_ERROR_WANT_READ",
+				PY_SSL_ERROR_WANT_READ);
+	PyModule_AddIntConstant(m, "SSL_ERROR_WANT_WRITE",
+				PY_SSL_ERROR_WANT_WRITE);
+	PyModule_AddIntConstant(m, "SSL_ERROR_WANT_X509_LOOKUP",
+				PY_SSL_ERROR_WANT_X509_LOOKUP);
+	PyModule_AddIntConstant(m, "SSL_ERROR_SYSCALL",
+				PY_SSL_ERROR_SYSCALL);
+	PyModule_AddIntConstant(m, "SSL_ERROR_SSL",
+				PY_SSL_ERROR_SSL);
+	PyModule_AddIntConstant(m, "SSL_ERROR_WANT_CONNECT",
+				PY_SSL_ERROR_WANT_CONNECT);
+	/* non ssl.h errorcodes */
+	PyModule_AddIntConstant(m, "SSL_ERROR_EOF",
+				PY_SSL_ERROR_EOF);
+	PyModule_AddIntConstant(m, "SSL_ERROR_INVALID_ERROR_CODE",
+				PY_SSL_ERROR_INVALID_ERROR_CODE);
+	/* cert requirements */
+	PyModule_AddIntConstant(m, "CERT_NONE",
+				PY_SSL_CERT_NONE);
+	PyModule_AddIntConstant(m, "CERT_OPTIONAL",
+				PY_SSL_CERT_OPTIONAL);
+	PyModule_AddIntConstant(m, "CERT_REQUIRED",
+				PY_SSL_CERT_REQUIRED);
+
+	/* protocol versions */
+	PyModule_AddIntConstant(m, "PROTOCOL_SSLv2",
+				PY_SSL_VERSION_SSL2);
+	PyModule_AddIntConstant(m, "PROTOCOL_SSLv3",
+				PY_SSL_VERSION_SSL3);
+	PyModule_AddIntConstant(m, "PROTOCOL_SSLv23",
+				PY_SSL_VERSION_SSL23);
+	PyModule_AddIntConstant(m, "PROTOCOL_TLSv1",
+				PY_SSL_VERSION_TLS1);
+	PyModule_AddIntConstant(m, "PROTOCOL_NOSSLv2",
+				PY_SSL_VERSION_NOSSL2);
+}

+ 36 - 0
desktop/core/ext-py/ssl-1.15/test/badcert.pem

@@ -0,0 +1,36 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXwIBAAKBgQC8ddrhm+LutBvjYcQlnH21PPIseJ1JVG2HMmN2CmZk2YukO+9L
+opdJhTvbGfEj0DQs1IE8M+kTUyOmuKfVrFMKwtVeCJphrAnhoz7TYOuLBSqt7lVH
+fhi/VwovESJlaBOp+WMnfhcduPEYHYx/6cnVapIkZnLt30zu2um+DzA9jQIDAQAB
+AoGBAK0FZpaKj6WnJZN0RqhhK+ggtBWwBnc0U/ozgKz2j1s3fsShYeiGtW6CK5nU
+D1dZ5wzhbGThI7LiOXDvRucc9n7vUgi0alqPQ/PFodPxAN/eEYkmXQ7W2k7zwsDA
+IUK0KUhktQbLu8qF/m8qM86ba9y9/9YkXuQbZ3COl5ahTZrhAkEA301P08RKv3KM
+oXnGU2UHTuJ1MAD2hOrPxjD4/wxA/39EWG9bZczbJyggB4RHu0I3NOSFjAm3HQm0
+ANOu5QK9owJBANgOeLfNNcF4pp+UikRFqxk5hULqRAWzVxVrWe85FlPm0VVmHbb/
+loif7mqjU8o1jTd/LM7RD9f2usZyE2psaw8CQQCNLhkpX3KO5kKJmS9N7JMZSc4j
+oog58yeYO8BBqKKzpug0LXuQultYv2K4veaIO04iL9VLe5z9S/Q1jaCHBBuXAkEA
+z8gjGoi1AOp6PBBLZNsncCvcV/0aC+1se4HxTNo2+duKSDnbq+ljqOM+E7odU+Nq
+ewvIWOG//e8fssd0mq3HywJBAJ8l/c8GVmrpFTx8r/nZ2Pyyjt3dH1widooDXYSV
+q6Gbf41Llo5sYAtmxdndTLASuHKecacTgZVhy0FryZpLKrU=
+-----END RSA PRIVATE KEY-----
+-----BEGIN CERTIFICATE-----
+Just bad cert data
+-----END CERTIFICATE-----
+-----BEGIN RSA PRIVATE KEY-----
+MIICXwIBAAKBgQC8ddrhm+LutBvjYcQlnH21PPIseJ1JVG2HMmN2CmZk2YukO+9L
+opdJhTvbGfEj0DQs1IE8M+kTUyOmuKfVrFMKwtVeCJphrAnhoz7TYOuLBSqt7lVH
+fhi/VwovESJlaBOp+WMnfhcduPEYHYx/6cnVapIkZnLt30zu2um+DzA9jQIDAQAB
+AoGBAK0FZpaKj6WnJZN0RqhhK+ggtBWwBnc0U/ozgKz2j1s3fsShYeiGtW6CK5nU
+D1dZ5wzhbGThI7LiOXDvRucc9n7vUgi0alqPQ/PFodPxAN/eEYkmXQ7W2k7zwsDA
+IUK0KUhktQbLu8qF/m8qM86ba9y9/9YkXuQbZ3COl5ahTZrhAkEA301P08RKv3KM
+oXnGU2UHTuJ1MAD2hOrPxjD4/wxA/39EWG9bZczbJyggB4RHu0I3NOSFjAm3HQm0
+ANOu5QK9owJBANgOeLfNNcF4pp+UikRFqxk5hULqRAWzVxVrWe85FlPm0VVmHbb/
+loif7mqjU8o1jTd/LM7RD9f2usZyE2psaw8CQQCNLhkpX3KO5kKJmS9N7JMZSc4j
+oog58yeYO8BBqKKzpug0LXuQultYv2K4veaIO04iL9VLe5z9S/Q1jaCHBBuXAkEA
+z8gjGoi1AOp6PBBLZNsncCvcV/0aC+1se4HxTNo2+duKSDnbq+ljqOM+E7odU+Nq
+ewvIWOG//e8fssd0mq3HywJBAJ8l/c8GVmrpFTx8r/nZ2Pyyjt3dH1widooDXYSV
+q6Gbf41Llo5sYAtmxdndTLASuHKecacTgZVhy0FryZpLKrU=
+-----END RSA PRIVATE KEY-----
+-----BEGIN CERTIFICATE-----
+Just bad cert data
+-----END CERTIFICATE-----

+ 40 - 0
desktop/core/ext-py/ssl-1.15/test/badkey.pem

@@ -0,0 +1,40 @@
+-----BEGIN RSA PRIVATE KEY-----
+Bad Key, though the cert should be OK
+-----END RSA PRIVATE KEY-----
+-----BEGIN CERTIFICATE-----
+MIICpzCCAhCgAwIBAgIJAP+qStv1cIGNMA0GCSqGSIb3DQEBBQUAMIGJMQswCQYD
+VQQGEwJVUzERMA8GA1UECBMIRGVsYXdhcmUxEzARBgNVBAcTCldpbG1pbmd0b24x
+IzAhBgNVBAoTGlB5dGhvbiBTb2Z0d2FyZSBGb3VuZGF0aW9uMQwwCgYDVQQLEwNT
+U0wxHzAdBgNVBAMTFnNvbWVtYWNoaW5lLnB5dGhvbi5vcmcwHhcNMDcwODI3MTY1
+NDUwWhcNMTMwMjE2MTY1NDUwWjCBiTELMAkGA1UEBhMCVVMxETAPBgNVBAgTCERl
+bGF3YXJlMRMwEQYDVQQHEwpXaWxtaW5ndG9uMSMwIQYDVQQKExpQeXRob24gU29m
+dHdhcmUgRm91bmRhdGlvbjEMMAoGA1UECxMDU1NMMR8wHQYDVQQDExZzb21lbWFj
+aGluZS5weXRob24ub3JnMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8ddrh
+m+LutBvjYcQlnH21PPIseJ1JVG2HMmN2CmZk2YukO+9LopdJhTvbGfEj0DQs1IE8
+M+kTUyOmuKfVrFMKwtVeCJphrAnhoz7TYOuLBSqt7lVHfhi/VwovESJlaBOp+WMn
+fhcduPEYHYx/6cnVapIkZnLt30zu2um+DzA9jQIDAQABoxUwEzARBglghkgBhvhC
+AQEEBAMCBkAwDQYJKoZIhvcNAQEFBQADgYEAF4Q5BVqmCOLv1n8je/Jw9K669VXb
+08hyGzQhkemEBYQd6fzQ9A/1ZzHkJKb1P6yreOLSEh4KcxYPyrLRC1ll8nr5OlCx
+CMhKkTnR6qBsdNV0XtdU2+N25hqW+Ma4ZeqsN/iiJVCGNOZGnvQuvCAGWF8+J/f/
+iHkC6gGdBJhogs4=
+-----END CERTIFICATE-----
+-----BEGIN RSA PRIVATE KEY-----
+Bad Key, though the cert should be OK
+-----END RSA PRIVATE KEY-----
+-----BEGIN CERTIFICATE-----
+MIICpzCCAhCgAwIBAgIJAP+qStv1cIGNMA0GCSqGSIb3DQEBBQUAMIGJMQswCQYD
+VQQGEwJVUzERMA8GA1UECBMIRGVsYXdhcmUxEzARBgNVBAcTCldpbG1pbmd0b24x
+IzAhBgNVBAoTGlB5dGhvbiBTb2Z0d2FyZSBGb3VuZGF0aW9uMQwwCgYDVQQLEwNT
+U0wxHzAdBgNVBAMTFnNvbWVtYWNoaW5lLnB5dGhvbi5vcmcwHhcNMDcwODI3MTY1
+NDUwWhcNMTMwMjE2MTY1NDUwWjCBiTELMAkGA1UEBhMCVVMxETAPBgNVBAgTCERl
+bGF3YXJlMRMwEQYDVQQHEwpXaWxtaW5ndG9uMSMwIQYDVQQKExpQeXRob24gU29m
+dHdhcmUgRm91bmRhdGlvbjEMMAoGA1UECxMDU1NMMR8wHQYDVQQDExZzb21lbWFj
+aGluZS5weXRob24ub3JnMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8ddrh
+m+LutBvjYcQlnH21PPIseJ1JVG2HMmN2CmZk2YukO+9LopdJhTvbGfEj0DQs1IE8
+M+kTUyOmuKfVrFMKwtVeCJphrAnhoz7TYOuLBSqt7lVHfhi/VwovESJlaBOp+WMn
+fhcduPEYHYx/6cnVapIkZnLt30zu2um+DzA9jQIDAQABoxUwEzARBglghkgBhvhC
+AQEEBAMCBkAwDQYJKoZIhvcNAQEFBQADgYEAF4Q5BVqmCOLv1n8je/Jw9K669VXb
+08hyGzQhkemEBYQd6fzQ9A/1ZzHkJKb1P6yreOLSEh4KcxYPyrLRC1ll8nr5OlCx
+CMhKkTnR6qBsdNV0XtdU2+N25hqW+Ma4ZeqsN/iiJVCGNOZGnvQuvCAGWF8+J/f/
+iHkC6gGdBJhogs4=
+-----END CERTIFICATE-----

+ 26 - 0
desktop/core/ext-py/ssl-1.15/test/https_svn_python_org_root.pem

@@ -0,0 +1,26 @@
+-----BEGIN CERTIFICATE-----
+MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUFADCB
+lzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
+Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho
+dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3Qt
+SGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQyWhcNMTkwNzA5MTgxOTIyWjCBlzELMAkG
+A1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEe
+MBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8v
+d3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdh
+cmUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn
+0G2f0v9Y8+efK+wNiVSZuTiZFvfgIXlIwrthdBKWHTxqctU8EGc6Oe0rE81m65UJ
+M6Rsl7HoxuzBdXmcRl6Nq9Bq/bkqVRcQVLMZ8Jr28bFdtqdt++BxF2uiiPsA3/4a
+MXcMmgF6sTLjKwEHOG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8i4fDidNd
+oI6yqqr2jmmIBsX6iSHzCJ1pLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqI
+DsjfPe58BEydCl5rkdbux+0ojatNh4lz0G6k0B4WixThdkQDf2Os5M1JnMWS9Ksy
+oUhbAgMBAAGjgbkwgbYwCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYD
+VR0OBBYEFKFyXyYbKJhDlV0HN9WFlp1L0sNFMEQGA1UdHwQ9MDswOaA3oDWGM2h0
+dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNFUkZpcnN0LUhhcmR3YXJlLmNy
+bDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUFBwMGBggrBgEF
+BQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0oXnWO6y1n7k57K9cM
+//bey1WiCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjAbPLPSbtNk28Gpgoiskli
+CE7/yMgUsogWXecB5BKV5UU0s4tpvc+0hY91UZ59Ojg6FEgSxvunOxqNDYJAB+gE
+CJChicsZUN/KHAG8HQQZexB2lzvukJDKxA4fFm517zP4029bHpbj4HR3dHuKom4t
+3XbWOTCC8KucUvIqx69JXn7HaOWCgchqJ/kniCrVWFCVH/A7HFe7fRQ5YiuayZSS
+KqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67nfhmqA==
+-----END CERTIFICATE-----

+ 32 - 0
desktop/core/ext-py/ssl-1.15/test/keycert.pem

@@ -0,0 +1,32 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXwIBAAKBgQC8ddrhm+LutBvjYcQlnH21PPIseJ1JVG2HMmN2CmZk2YukO+9L
+opdJhTvbGfEj0DQs1IE8M+kTUyOmuKfVrFMKwtVeCJphrAnhoz7TYOuLBSqt7lVH
+fhi/VwovESJlaBOp+WMnfhcduPEYHYx/6cnVapIkZnLt30zu2um+DzA9jQIDAQAB
+AoGBAK0FZpaKj6WnJZN0RqhhK+ggtBWwBnc0U/ozgKz2j1s3fsShYeiGtW6CK5nU
+D1dZ5wzhbGThI7LiOXDvRucc9n7vUgi0alqPQ/PFodPxAN/eEYkmXQ7W2k7zwsDA
+IUK0KUhktQbLu8qF/m8qM86ba9y9/9YkXuQbZ3COl5ahTZrhAkEA301P08RKv3KM
+oXnGU2UHTuJ1MAD2hOrPxjD4/wxA/39EWG9bZczbJyggB4RHu0I3NOSFjAm3HQm0
+ANOu5QK9owJBANgOeLfNNcF4pp+UikRFqxk5hULqRAWzVxVrWe85FlPm0VVmHbb/
+loif7mqjU8o1jTd/LM7RD9f2usZyE2psaw8CQQCNLhkpX3KO5kKJmS9N7JMZSc4j
+oog58yeYO8BBqKKzpug0LXuQultYv2K4veaIO04iL9VLe5z9S/Q1jaCHBBuXAkEA
+z8gjGoi1AOp6PBBLZNsncCvcV/0aC+1se4HxTNo2+duKSDnbq+ljqOM+E7odU+Nq
+ewvIWOG//e8fssd0mq3HywJBAJ8l/c8GVmrpFTx8r/nZ2Pyyjt3dH1widooDXYSV
+q6Gbf41Llo5sYAtmxdndTLASuHKecacTgZVhy0FryZpLKrU=
+-----END RSA PRIVATE KEY-----
+-----BEGIN CERTIFICATE-----
+MIICpzCCAhCgAwIBAgIJAP+qStv1cIGNMA0GCSqGSIb3DQEBBQUAMIGJMQswCQYD
+VQQGEwJVUzERMA8GA1UECBMIRGVsYXdhcmUxEzARBgNVBAcTCldpbG1pbmd0b24x
+IzAhBgNVBAoTGlB5dGhvbiBTb2Z0d2FyZSBGb3VuZGF0aW9uMQwwCgYDVQQLEwNT
+U0wxHzAdBgNVBAMTFnNvbWVtYWNoaW5lLnB5dGhvbi5vcmcwHhcNMDcwODI3MTY1
+NDUwWhcNMTMwMjE2MTY1NDUwWjCBiTELMAkGA1UEBhMCVVMxETAPBgNVBAgTCERl
+bGF3YXJlMRMwEQYDVQQHEwpXaWxtaW5ndG9uMSMwIQYDVQQKExpQeXRob24gU29m
+dHdhcmUgRm91bmRhdGlvbjEMMAoGA1UECxMDU1NMMR8wHQYDVQQDExZzb21lbWFj
+aGluZS5weXRob24ub3JnMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8ddrh
+m+LutBvjYcQlnH21PPIseJ1JVG2HMmN2CmZk2YukO+9LopdJhTvbGfEj0DQs1IE8
+M+kTUyOmuKfVrFMKwtVeCJphrAnhoz7TYOuLBSqt7lVHfhi/VwovESJlaBOp+WMn
+fhcduPEYHYx/6cnVapIkZnLt30zu2um+DzA9jQIDAQABoxUwEzARBglghkgBhvhC
+AQEEBAMCBkAwDQYJKoZIhvcNAQEFBQADgYEAF4Q5BVqmCOLv1n8je/Jw9K669VXb
+08hyGzQhkemEBYQd6fzQ9A/1ZzHkJKb1P6yreOLSEh4KcxYPyrLRC1ll8nr5OlCx
+CMhKkTnR6qBsdNV0XtdU2+N25hqW+Ma4ZeqsN/iiJVCGNOZGnvQuvCAGWF8+J/f/
+iHkC6gGdBJhogs4=
+-----END CERTIFICATE-----

+ 0 - 0
desktop/core/ext-py/ssl-1.15/test/nullcert.pem


+ 1052 - 0
desktop/core/ext-py/ssl-1.15/test/test_ssl.py

@@ -0,0 +1,1052 @@
+# Test the support for SSL and sockets
+
+import sys
+import unittest
+from test import test_support
+import select
+import socket
+import errno
+import time
+import os
+import pprint
+import urllib, urlparse
+import shutil
+import traceback
+import asyncore
+
+from BaseHTTPServer import HTTPServer
+from SimpleHTTPServer import SimpleHTTPRequestHandler
+
+# Optionally test SSL support, if we have it in the tested platform
+skip_expected = False
+try:
+    import ssl
+except ImportError, x:
+    print "error: ", x
+    skip_expected = True
+
+CERTFILE = None
+SVN_PYTHON_ORG_ROOT_CERT = None
+
+TESTPORT = 10025
+
+def handle_error(prefix):
+    exc_format = ' '.join(traceback.format_exception(*sys.exc_info()))
+    if test_support.verbose:
+        sys.stdout.write(prefix + exc_format)
+
+
+class BasicTests(unittest.TestCase):
+
+    def testCrucialConstants(self):
+        ssl.PROTOCOL_SSLv2
+        ssl.PROTOCOL_SSLv23
+        ssl.PROTOCOL_SSLv3
+        ssl.PROTOCOL_TLSv1
+        ssl.CERT_NONE
+        ssl.CERT_OPTIONAL
+        ssl.CERT_REQUIRED
+
+    def testRAND(self):
+        v = ssl.RAND_status()
+        if test_support.verbose:
+            sys.stdout.write("\n RAND_status is %d (%s)\n"
+                             % (v, (v and "sufficient randomness") or
+                                "insufficient randomness"))
+        try:
+            ssl.RAND_egd(1)
+        except TypeError:
+            pass
+        else:
+            print "didn't raise TypeError"
+        ssl.RAND_add("this is a random string", 75.0)
+
+    def testParseCert(self):
+        # note that this uses an 'unofficial' function in _ssl.c,
+        # provided solely for this test, to exercise the certificate
+        # parsing code
+        p = ssl._ssl2._test_decode_cert(CERTFILE, False)
+        if test_support.verbose:
+            sys.stdout.write("\n" + pprint.pformat(p) + "\n")
+
+    def testDERtoPEM(self):
+
+        pem = open(SVN_PYTHON_ORG_ROOT_CERT, 'r').read()
+        d1 = ssl.PEM_cert_to_DER_cert(pem)
+        p2 = ssl.DER_cert_to_PEM_cert(d1)
+        d2 = ssl.PEM_cert_to_DER_cert(p2)
+        if (d1 != d2):
+            raise test_support.TestFailed("PEM-to-DER or DER-to-PEM translation failed")
+
+class NetworkedTests(unittest.TestCase):
+
+    def testConnect(self):
+        import os
+        s = ssl.wrap_socket(socket.socket(socket.AF_INET),
+                            cert_reqs=ssl.CERT_NONE)
+        s.connect(("pop.gmail.com", 995))
+        c = s.getpeercert()
+        if c:
+            raise test_support.TestFailed("Peer cert %s shouldn't be here!")
+        s.close()
+
+        # this should fail because we have no verification certs
+        s = ssl.wrap_socket(socket.socket(socket.AF_INET),
+                            cert_reqs=ssl.CERT_REQUIRED)
+        try:
+            try:
+                s.connect(("pop.gmail.com", 995))
+            except ssl.SSLError:
+                pass
+        finally:
+            s.close()
+
+        # this should succeed because we specify the root cert
+        s = ssl.wrap_socket(socket.socket(socket.AF_INET),
+                            cert_reqs=ssl.CERT_REQUIRED,
+                            ca_certs=SVN_PYTHON_ORG_ROOT_CERT)
+        try:
+            try:
+                s.connect(("svn.python.org", 443))
+            except ssl.SSLError, x:
+                raise test_support.TestFailed("Unexpected exception %s" % x)
+        finally:
+            s.close()
+
+
+    def testNonBlockingHandshake(self):
+        s = socket.socket(socket.AF_INET)
+        s.connect(("svn.python.org", 443))
+        s.setblocking(False)
+        s = ssl.wrap_socket(s,
+                            cert_reqs=ssl.CERT_NONE,
+                            do_handshake_on_connect=False)
+        count = 0
+        while True:
+            try:
+                count += 1
+                s.do_handshake()
+                break
+            except ssl.SSLError, err:
+                if err.args[0] == ssl.SSL_ERROR_WANT_READ:
+                    select.select([s], [], [])
+                elif err.args[0] == ssl.SSL_ERROR_WANT_WRITE:
+                    select.select([], [s], [])
+                else:
+                    raise
+        s.close()
+        if test_support.verbose:
+            sys.stdout.write("\nNeeded %d calls to do_handshake() to establish session.\n" % count)
+
+    def testFetchServerCert(self):
+
+        pem = ssl.get_server_certificate(("svn.python.org", 443))
+        if not pem:
+            raise test_support.TestFailed("No server certificate on svn.python.org:443!")
+
+        try:
+            pem = ssl.get_server_certificate(("svn.python.org", 443), ca_certs=CERTFILE)
+        except ssl.SSLError:
+            #should fail
+            pass
+        else:
+            raise test_support.TestFailed("Got server certificate %s for svn.python.org!" % pem)
+
+        pem = ssl.get_server_certificate(("svn.python.org", 443), ca_certs=SVN_PYTHON_ORG_ROOT_CERT)
+        if not pem:
+            raise test_support.TestFailed("No server certificate on svn.python.org:443!")
+        if test_support.verbose:
+            sys.stdout.write("\nVerified certificate for svn.python.org:443 is\n%s\n" % pem)
+
+
+
+try:
+    import threading
+except ImportError:
+    print "No threads!"
+    _have_threads = False
+else:
+
+    _have_threads = True
+
+    class ThreadedEchoServer(threading.Thread):
+
+        class ConnectionHandler(threading.Thread):
+
+            """A mildly complicated class, because we want it to work both
+            with and without the SSL wrapper around the socket connection, so
+            that we can test the STARTTLS functionality."""
+
+            def __init__(self, server, connsock):
+                self.server = server
+                self.running = False
+                self.sock = connsock
+                self.sock.setblocking(1)
+                self.sslconn = None
+                threading.Thread.__init__(self)
+                self.setDaemon(True)
+
+            def show_conn_details(self):
+                if self.server.certreqs == ssl.CERT_REQUIRED:
+                    cert = self.sslconn.getpeercert()
+                    if test_support.verbose and self.server.chatty:
+                        sys.stdout.write(" client cert is " + pprint.pformat(cert) + "\n")
+                    cert_binary = self.sslconn.getpeercert(True)
+                    if test_support.verbose and self.server.chatty:
+                        sys.stdout.write(" cert binary is " + str(len(cert_binary)) + " bytes\n")
+                cipher = self.sslconn.cipher()
+                if test_support.verbose and self.server.chatty:
+                    sys.stdout.write(" server: connection cipher is now " + str(cipher) + "\n")
+
+            def wrap_conn (self):
+                try:
+                    self.sslconn = ssl.wrap_socket(self.sock, server_side=True,
+                                                   certfile=self.server.certificate,
+                                                   ssl_version=self.server.protocol,
+                                                   ca_certs=self.server.cacerts,
+                                                   cert_reqs=self.server.certreqs)
+                except:
+                    if self.server.chatty:
+                        handle_error("\n server:  bad connection attempt from " +
+                                     str(self.sock.getpeername()) + ":\n")
+                    self.close()
+                    if not self.server.expect_bad_connects:
+                        # here, we want to stop the server, because this shouldn't
+                        # happen in the context of our test case
+                        self.running = False
+                        # normally, we'd just stop here, but for the test
+                        # harness, we want to stop the server
+                        self.server.stop()
+                    return False
+
+                else:
+                    return True
+
+            def read(self):
+                if self.sslconn:
+                    return self.sslconn.read()
+                else:
+                    return self.sock.recv(1024)
+
+            def write(self, bytes):
+                if self.sslconn:
+                    return self.sslconn.write(bytes)
+                else:
+                    return self.sock.send(bytes)
+
+            def close(self):
+                if self.sslconn:
+                    self.sslconn.close()
+                else:
+                    # close is broken on sockets
+                    os.close(self.sock.fileno())
+
+            def run (self):
+                self.running = True
+                if not self.server.starttls_server:
+                    if isinstance(self.sock, ssl.SSLSocket):
+                        self.sslconn = self.sock
+                    elif not self.wrap_conn():
+                        return
+                    self.show_conn_details()
+                while self.running:
+                    try:
+                        msg = self.read()
+                        if not msg:
+                            # eof, so quit this handler
+                            self.running = False
+                            self.close()
+                        elif msg.strip() == 'over':
+                            if test_support.verbose and self.server.connectionchatty:
+                                sys.stdout.write(" server: client closed connection\n")
+                            self.close()
+                            return
+                        elif self.server.starttls_server and msg.strip() == 'STARTTLS':
+                            if test_support.verbose and self.server.connectionchatty:
+                                sys.stdout.write(" server: read STARTTLS from client, sending OK...\n")
+                            self.write("OK\n")
+                            if not self.wrap_conn():
+                                return
+                        elif self.server.starttls_server and self.sslconn and msg.strip() == 'ENDTLS':
+                            if test_support.verbose and self.server.connectionchatty:
+                                sys.stdout.write(" server: read ENDTLS from client, sending OK...\n")
+                            self.write("OK\n")
+                            self.sock = self.sslconn.unwrap()
+                            self.sslconn = None
+                            if test_support.verbose and self.server.connectionchatty:
+                                sys.stdout.write(" server: connection is now unencrypted...\n")
+                        else:
+                            if (test_support.verbose and
+                                self.server.connectionchatty):
+                                ctype = (self.sslconn and "encrypted") or "unencrypted"
+                                sys.stdout.write(" server: read %s (%s), sending back %s (%s)...\n"
+                                                 % (repr(msg), ctype, repr(msg.lower()), ctype))
+                            self.write(msg.lower())
+                    except ssl.SSLError:
+                        if self.server.chatty:
+                            handle_error("Test server failure:\n")
+                        self.close()
+                        self.running = False
+                        # normally, we'd just stop here, but for the test
+                        # harness, we want to stop the server
+                        self.server.stop()
+                    except:
+                        handle_error('')
+
+        def __init__(self, port, certificate, ssl_version=None,
+                     certreqs=None, cacerts=None, expect_bad_connects=False,
+                     chatty=True, connectionchatty=False, starttls_server=False,
+                     wrap_accepting_socket=False):
+            if ssl_version is None:
+                ssl_version = ssl.PROTOCOL_TLSv1
+            if certreqs is None:
+                certreqs = ssl.CERT_NONE
+            self.certificate = certificate
+            self.protocol = ssl_version
+            self.certreqs = certreqs
+            self.cacerts = cacerts
+            self.expect_bad_connects = expect_bad_connects
+            self.chatty = chatty
+            self.connectionchatty = connectionchatty
+            self.starttls_server = starttls_server
+            self.sock = socket.socket()
+            self.flag = None
+            if hasattr(socket, 'SO_REUSEADDR'):
+                self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+            if hasattr(socket, 'SO_REUSEPORT'):
+                self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
+            if wrap_accepting_socket:
+                self.sock = ssl.wrap_socket(self.sock, server_side=True,
+                                            certfile=self.certificate,
+                                            cert_reqs = self.certreqs,
+                                            ca_certs = self.cacerts,
+                                            ssl_version = self.protocol)
+                if test_support.verbose and self.chatty:
+                    sys.stdout.write(' server:  wrapped server socket as %s\n' % str(self.sock))
+            self.sock.bind(('127.0.0.1', port))
+            self.active = False
+            threading.Thread.__init__(self)
+            self.setDaemon(False)
+
+        def start (self, flag=None):
+            self.flag = flag
+            threading.Thread.start(self)
+
+        def run (self):
+            self.sock.settimeout(0.5)
+            self.sock.listen(5)
+            self.active = True
+            if self.flag:
+                # signal an event
+                self.flag.set()
+            while self.active:
+                try:
+                    newconn, connaddr = self.sock.accept()
+                    if test_support.verbose and self.chatty:
+                        sys.stdout.write(' server:  new connection from '
+                                         + str(connaddr) + '\n')
+                    handler = self.ConnectionHandler(self, newconn)
+                    handler.start()
+                except socket.timeout:
+                    pass
+                except KeyboardInterrupt:
+                    self.stop()
+                except:
+                    if self.chatty:
+                        handle_error("Test server failure:\n")
+            self.sock.close()
+
+        def stop (self):
+            self.active = False
+
+
+    class AsyncoreEchoServer(threading.Thread):
+
+        class EchoServer (asyncore.dispatcher):
+
+            class ConnectionHandler (asyncore.dispatcher_with_send):
+
+                def __init__(self, conn, certfile):
+                    asyncore.dispatcher_with_send.__init__(self, conn)
+                    self.socket = ssl.wrap_socket(conn, server_side=True,
+                                                  certfile=certfile,
+                                                  do_handshake_on_connect=False)
+                    # now we have to do the handshake
+                    # we'll just do it the easy way, and block the connection
+                    # till it's finished.  If we were doing it right, we'd
+                    # do this in multiple calls to handle_read...
+                    self.do_handshake(block=True)
+
+                def readable(self):
+                    if isinstance(self.socket, ssl.SSLSocket):
+                        while self.socket.pending() > 0:
+                            self.handle_read_event()
+                    return True
+
+                def handle_read(self):
+                    data = self.recv(1024)
+                    self.send(data.lower())
+
+                def handle_close(self):
+                    self.close()
+                    if test_support.verbose:
+                        sys.stdout.write(" server:  closed connection %s\n" % self.socket)
+
+                def handle_error(self):
+                    raise
+
+            def __init__(self, port, certfile):
+                self.port = port
+                self.certfile = certfile
+                asyncore.dispatcher.__init__(self)
+                self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
+                self.bind(('', port))
+                self.listen(5)
+
+            def handle_accept(self):
+                sock_obj, addr = self.accept()
+                if test_support.verbose:
+                    sys.stdout.write(" server:  new connection from %s:%s\n" %addr)
+                self.ConnectionHandler(sock_obj, self.certfile)
+
+            def handle_error(self):
+                raise
+
+        def __init__(self, port, certfile):
+            self.flag = None
+            self.active = False
+            self.server = self.EchoServer(port, certfile)
+            threading.Thread.__init__(self)
+            self.setDaemon(True)
+
+        def __str__(self):
+            return "<%s %s>" % (self.__class__.__name__, self.server)
+
+        def start (self, flag=None):
+            self.flag = flag
+            threading.Thread.start(self)
+
+        def run (self):
+            self.active = True
+            if self.flag:
+                self.flag.set()
+            while self.active:
+                try:
+                    asyncore.loop(1)
+                except:
+                    pass
+
+        def stop (self):
+            self.active = False
+            self.server.close()
+
+    class SocketServerHTTPSServer(threading.Thread):
+
+        class HTTPSServer(HTTPServer):
+
+            def __init__(self, server_address, RequestHandlerClass, certfile):
+
+                HTTPServer.__init__(self, server_address, RequestHandlerClass)
+                # we assume the certfile contains both private key and certificate
+                self.certfile = certfile
+                self.active = False
+                self.allow_reuse_address = True
+
+            def __str__(self):
+                return ('<%s %s:%s>' %
+                        (self.__class__.__name__,
+                         self.server_name,
+                         self.server_port))
+
+            def get_request (self):
+                # override this to wrap socket with SSL
+                sock, addr = self.socket.accept()
+                sslconn = ssl.wrap_socket(sock, server_side=True,
+                                          certfile=self.certfile)
+                return sslconn, addr
+
+            def server_activate(self):
+                # override this to set timeout, so we get
+                # a chance to stop the server
+                self.socket.settimeout(0.5)
+                HTTPServer.server_activate(self)
+
+            def serve_forever(self):
+                # We want this to run in a thread, so we use a slightly
+                # modified version of "forever".
+                self.active = True
+                while self.active:
+                    try:
+                        self.handle_request()
+                    except socket.timeout:
+                        pass
+                    except KeyboardInterrupt:
+                        self.server_close()
+                        return
+                    except:
+                        sys.stdout.write(''.join(traceback.format_exception(*sys.exc_info())));
+
+            def server_close(self):
+                # Again, we want this to run in a thread, so we need to override
+                # close to clear the "active" flag, so that serve_forever() will
+                # terminate.
+                HTTPServer.server_close(self)
+                self.active = False
+
+        class RootedHTTPRequestHandler(SimpleHTTPRequestHandler):
+
+            # need to override translate_path to get a known root,
+            # instead of using os.curdir, since the test could be
+            # run from anywhere
+            #
+            # We also want to override log_request() to suppress logging
+
+            root = None
+
+            def translate_path(self, path):
+                """Translate a /-separated PATH to the local filename syntax.
+
+                Components that mean special things to the local file system
+                (e.g. drive or directory names) are ignored.  (XXX They should
+                probably be diagnosed.)
+
+                """
+                # abandon query parameters
+                path = urlparse.urlparse(path)[2]
+                path = os.path.normpath(urllib.unquote(path))
+                words = path.split('/')
+                words = filter(None, words)
+                path = self.root
+                for word in words:
+                    drive, word = os.path.splitdrive(word)
+                    head, word = os.path.split(word)
+                    if word in self.root: continue
+                    path = os.path.join(path, word)
+                return path
+
+            def log_message(self, format, *args):
+
+                # we override this to suppress logging unless "verbose"
+
+                if test_support.verbose:
+                    sys.stdout.write(" server (%s:%d %s):\n   [%s] %s\n" %
+                                     (self.server.server_address,
+                                      self.server.server_port,
+                                      self.request.cipher(),
+                                      self.log_date_time_string(),
+                                      format%args))
+
+
+        def __init__(self, port, certfile):
+            self.flag = None
+            self.active = False
+            self.RootedHTTPRequestHandler.root = os.path.split(CERTFILE)[0]
+            self.server = self.HTTPSServer(
+                ('127.0.0.1', port), self.RootedHTTPRequestHandler, certfile)
+            threading.Thread.__init__(self)
+            self.setDaemon(True)
+
+        def __str__(self):
+            return "<%s %s>" % (self.__class__.__name__, self.server)
+
+        def start (self, flag=None):
+            self.flag = flag
+            threading.Thread.start(self)
+
+        def run (self):
+            self.active = True
+            if self.flag:
+                self.flag.set()
+            self.server.serve_forever()
+            self.active = False
+
+        def stop (self):
+            self.active = False
+            self.server.server_close()
+
+
+    def badCertTest (certfile):
+        server = ThreadedEchoServer(TESTPORT, CERTFILE,
+                                    certreqs=ssl.CERT_REQUIRED,
+                                    cacerts=CERTFILE, chatty=False)
+        flag = threading.Event()
+        server.start(flag)
+        # wait for it to start
+        flag.wait()
+        # try to connect
+        try:
+            try:
+                s = ssl.wrap_socket(socket.socket(),
+                                    certfile=certfile,
+                                    ssl_version=ssl.PROTOCOL_TLSv1)
+                s.connect(('127.0.0.1', TESTPORT))
+            except ssl.SSLError, x:
+                if test_support.verbose:
+                    sys.stdout.write("\nSSLError is %s\n" % x[1])
+            else:
+                raise test_support.TestFailed(
+                    "Use of invalid cert should have failed!")
+        finally:
+            server.stop()
+            server.join()
+
+    def serverParamsTest (certfile, protocol, certreqs, cacertsfile,
+                          client_certfile, client_protocol=None, indata="FOO\n",
+                          chatty=True, connectionchatty=False,
+                          wrap_accepting_socket=False):
+
+        server = ThreadedEchoServer(TESTPORT, certfile,
+                                    certreqs=certreqs,
+                                    ssl_version=protocol,
+                                    cacerts=cacertsfile,
+                                    chatty=chatty,
+                                    connectionchatty=connectionchatty,
+                                    wrap_accepting_socket=wrap_accepting_socket)
+        flag = threading.Event()
+        server.start(flag)
+        # wait for it to start
+        flag.wait()
+        # try to connect
+        if client_protocol is None:
+            client_protocol = protocol
+        try:
+            try:
+                s = ssl.wrap_socket(socket.socket(),
+                                    certfile=client_certfile,
+                                    ca_certs=cacertsfile,
+                                    cert_reqs=certreqs,
+                                    ssl_version=client_protocol)
+                s.connect(('127.0.0.1', TESTPORT))
+            except ssl.SSLError, x:
+                raise test_support.TestFailed("Unexpected SSL error:  " + str(x))
+            except Exception, x:
+                raise test_support.TestFailed("Unexpected exception:  " + str(x))
+            else:
+                if connectionchatty:
+                    if test_support.verbose:
+                        sys.stdout.write(
+                            " client:  sending %s...\n" % (repr(indata)))
+                s.write(indata)
+                outdata = s.read()
+                if connectionchatty:
+                    if test_support.verbose:
+                        sys.stdout.write(" client:  read %s\n" % repr(outdata))
+                if outdata != indata.lower():
+                    raise test_support.TestFailed(
+                        "bad data <<%s>> (%d) received; expected <<%s>> (%d)\n"
+                        % (outdata[:min(len(outdata),20)], len(outdata),
+                           indata[:min(len(indata),20)].lower(), len(indata)))
+                s.write("over\n")
+                if connectionchatty:
+                    if test_support.verbose:
+                        sys.stdout.write(" client:  closing connection.\n")
+                s.close()
+        finally:
+            server.stop()
+            server.join()
+
+    def tryProtocolCombo (server_protocol,
+                          client_protocol,
+                          expectedToWork,
+                          certsreqs=None):
+
+        if certsreqs == None:
+            certsreqs = ssl.CERT_NONE
+
+        if certsreqs == ssl.CERT_NONE:
+            certtype = "CERT_NONE"
+        elif certsreqs == ssl.CERT_OPTIONAL:
+            certtype = "CERT_OPTIONAL"
+        elif certsreqs == ssl.CERT_REQUIRED:
+            certtype = "CERT_REQUIRED"
+        if test_support.verbose:
+            formatstr = (expectedToWork and " %s->%s %s\n") or " {%s->%s} %s\n"
+            sys.stdout.write(formatstr %
+                             (ssl.get_protocol_name(client_protocol),
+                              ssl.get_protocol_name(server_protocol),
+                              certtype))
+        try:
+            serverParamsTest(CERTFILE, server_protocol, certsreqs,
+                             CERTFILE, CERTFILE, client_protocol, chatty=False)
+        except test_support.TestFailed:
+            if expectedToWork:
+                raise
+        else:
+            if not expectedToWork:
+                raise test_support.TestFailed(
+                    "Client protocol %s succeeded with server protocol %s!"
+                    % (ssl.get_protocol_name(client_protocol),
+                       ssl.get_protocol_name(server_protocol)))
+
+
+    class ThreadedTests(unittest.TestCase):
+
+        def testRudeShutdown(self):
+
+            listener_ready = threading.Event()
+            listener_gone = threading.Event()
+
+            # `listener` runs in a thread.  It opens a socket listening on
+            # PORT, and sits in an accept() until the main thread connects.
+            # Then it rudely closes the socket, and sets Event `listener_gone`
+            # to let the main thread know the socket is gone.
+            def listener():
+                s = socket.socket()
+                if hasattr(socket, 'SO_REUSEADDR'):
+                    s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+                if hasattr(socket, 'SO_REUSEPORT'):
+                    s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
+                s.bind(('127.0.0.1', TESTPORT))
+                s.listen(5)
+                listener_ready.set()
+                s.accept()
+                s = None # reclaim the socket object, which also closes it
+                listener_gone.set()
+
+            def connector():
+                listener_ready.wait()
+                s = socket.socket()
+                s.connect(('127.0.0.1', TESTPORT))
+                listener_gone.wait()
+                try:
+                    ssl_sock = ssl.wrap_socket(s)
+                except socket.error:
+                    pass
+                else:
+                    raise test_support.TestFailed(
+                          'connecting to closed SSL socket should have failed')
+
+            t = threading.Thread(target=listener)
+            t.start()
+            connector()
+            t.join()
+
+        def testEcho (self):
+
+            if test_support.verbose:
+                sys.stdout.write("\n")
+            serverParamsTest(CERTFILE, ssl.PROTOCOL_TLSv1, ssl.CERT_NONE,
+                             CERTFILE, CERTFILE, ssl.PROTOCOL_TLSv1,
+                             chatty=True, connectionchatty=True)
+
+        def testReadCert(self):
+
+            if test_support.verbose:
+                sys.stdout.write("\n")
+            s2 = socket.socket()
+            server = ThreadedEchoServer(TESTPORT, CERTFILE,
+                                        certreqs=ssl.CERT_NONE,
+                                        ssl_version=ssl.PROTOCOL_SSLv23,
+                                        cacerts=CERTFILE,
+                                        chatty=False)
+            flag = threading.Event()
+            server.start(flag)
+            # wait for it to start
+            flag.wait()
+            # try to connect
+            try:
+                try:
+                    s = ssl.wrap_socket(socket.socket(),
+                                        certfile=CERTFILE,
+                                        ca_certs=CERTFILE,
+                                        cert_reqs=ssl.CERT_REQUIRED,
+                                        ssl_version=ssl.PROTOCOL_SSLv23)
+                    s.connect(('127.0.0.1', TESTPORT))
+                except ssl.SSLError, x:
+                    raise test_support.TestFailed(
+                        "Unexpected SSL error:  " + str(x))
+                except Exception, x:
+                    raise test_support.TestFailed(
+                        "Unexpected exception:  " + str(x))
+                else:
+                    if not s:
+                        raise test_support.TestFailed(
+                            "Can't SSL-handshake with test server")
+                    cert = s.getpeercert()
+                    if not cert:
+                        raise test_support.TestFailed(
+                            "Can't get peer certificate.")
+                    cipher = s.cipher()
+                    if test_support.verbose:
+                        sys.stdout.write(pprint.pformat(cert) + '\n')
+                        sys.stdout.write("Connection cipher is " + str(cipher) + '.\n')
+                    if not cert.has_key('subject'):
+                        raise test_support.TestFailed(
+                            "No subject field in certificate: %s." %
+                            pprint.pformat(cert))
+                    if ((('organizationName', 'Python Software Foundation'),)
+                        not in cert['subject']):
+                        raise test_support.TestFailed(
+                            "Missing or invalid 'organizationName' field in certificate subject; "
+                            "should be 'Python Software Foundation'.");
+                    s.close()
+            finally:
+                server.stop()
+                server.join()
+
+        def testNULLcert(self):
+            badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
+                                     "nullcert.pem"))
+        def testMalformedCert(self):
+            badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
+                                     "badcert.pem"))
+        def testMalformedKey(self):
+            badCertTest(os.path.join(os.path.dirname(__file__) or os.curdir,
+                                     "badkey.pem"))
+
+        def testProtocolSSL2(self):
+            if test_support.verbose:
+                sys.stdout.write("\n")
+            tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True)
+            tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_OPTIONAL)
+            tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_REQUIRED)
+            tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, True)
+            tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv3, False)
+            tryProtocolCombo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLSv1, False)
+
+        def testProtocolSSL23(self):
+            if test_support.verbose:
+                sys.stdout.write("\n")
+            try:
+                tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv2, True)
+            except test_support.TestFailed, x:
+                # this fails on some older versions of OpenSSL (0.9.7l, for instance)
+                if test_support.verbose:
+                    sys.stdout.write(
+                        " SSL2 client to SSL23 server test unexpectedly failed:\n %s\n"
+                        % str(x))
+            tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True)
+            tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True)
+            tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True)
+
+            tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
+            tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_OPTIONAL)
+            tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
+
+            tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
+            tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_REQUIRED)
+            tryProtocolCombo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
+
+        def testProtocolSSL3(self):
+            if test_support.verbose:
+                sys.stdout.write("\n")
+            tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True)
+            tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
+            tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
+            tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv2, False)
+            tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv23, False)
+            tryProtocolCombo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_TLSv1, False)
+
+        def testProtocolTLS1(self):
+            if test_support.verbose:
+                sys.stdout.write("\n")
+            tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True)
+            tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
+            tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
+            tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv2, False)
+            tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv3, False)
+            tryProtocolCombo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv23, False)
+
+        def testSTARTTLS (self):
+
+            msgs = ("msg 1", "MSG 2", "STARTTLS", "MSG 3", "msg 4", "ENDTLS", "msg 5", "msg 6")
+
+            server = ThreadedEchoServer(TESTPORT, CERTFILE,
+                                        ssl_version=ssl.PROTOCOL_TLSv1,
+                                        starttls_server=True,
+                                        chatty=True,
+                                        connectionchatty=True)
+            flag = threading.Event()
+            server.start(flag)
+            # wait for it to start
+            flag.wait()
+            # try to connect
+            wrapped = False
+            try:
+                try:
+                    s = socket.socket()
+                    s.setblocking(1)
+                    s.connect(('127.0.0.1', TESTPORT))
+                except Exception, x:
+                    raise test_support.TestFailed("Unexpected exception:  " + str(x))
+                else:
+                    if test_support.verbose:
+                        sys.stdout.write("\n")
+                    for indata in msgs:
+                        if test_support.verbose:
+                            sys.stdout.write(" client:  sending %s...\n" % repr(indata))
+                        if wrapped:
+                            conn.write(indata)
+                            outdata = conn.read()
+                        else:
+                            s.send(indata)
+                            outdata = s.recv(1024)
+                        if indata == "STARTTLS" and outdata.strip().lower().startswith("ok"):
+                            if test_support.verbose:
+                                sys.stdout.write(" client:  read %s from server, starting TLS...\n" % repr(outdata))
+                            conn = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_TLSv1)
+
+                            wrapped = True
+                        elif (indata == "ENDTLS" and
+                            outdata.strip().lower().startswith("ok")):
+                            if test_support.verbose:
+                                sys.stdout.write(
+                                    " client:  read %s from server, ending TLS...\n"
+                                    % repr(outdata))
+                            s = conn.unwrap()
+                            wrapped = False
+                        else:
+                            if test_support.verbose:
+                                sys.stdout.write(" client:  read %s from server\n" % repr(outdata))
+                    if test_support.verbose:
+                        sys.stdout.write(" client:  closing connection.\n")
+                    if wrapped:
+                        conn.write("over\n")
+                    else:
+                        s.send("over\n")
+                    s.close()
+            finally:
+                server.stop()
+                server.join()
+
+        def testSocketServer(self):
+
+            server = SocketServerHTTPSServer(TESTPORT, CERTFILE)
+            flag = threading.Event()
+            server.start(flag)
+            # wait for it to start
+            flag.wait()
+            # try to connect
+            try:
+                try:
+                    if test_support.verbose:
+                        sys.stdout.write('\n')
+                    d1 = open(CERTFILE, 'rb').read()
+                    d2 = ''
+                    # now fetch the same data from the HTTPS server
+                    url = 'https://127.0.0.1:%d/%s' % (
+                        TESTPORT, os.path.split(CERTFILE)[1])
+                    f = urllib.urlopen(url)
+                    dlen = f.info().getheader("content-length")
+                    if dlen and (int(dlen) > 0):
+                        d2 = f.read(int(dlen))
+                    if test_support.verbose:
+                        sys.stdout.write(
+                            " client: read %d bytes from remote server '%s'\n"
+                            % (len(d2), server))
+                    f.close()
+                except:
+                    print ''.join(traceback.format_exception(*sys.exc_info()))
+                    raise
+                else:
+                    if not (d1 == d2):
+                        raise test_support.TestFailed("Couldn't fetch data from HTTPS server")
+            finally:
+                server.stop()
+                server.join()
+
+        def testWrappedAccept (self):
+
+            if test_support.verbose:
+                sys.stdout.write("\n")
+            serverParamsTest(CERTFILE, ssl.PROTOCOL_SSLv23, ssl.CERT_REQUIRED,
+                             CERTFILE, CERTFILE, ssl.PROTOCOL_SSLv23,
+                             chatty=True, connectionchatty=True,
+                             wrap_accepting_socket=True)
+
+
+        def testAsyncoreServer (self):
+
+            indata = "TEST MESSAGE of mixed case\n"
+
+            if test_support.verbose:
+                sys.stdout.write("\n")
+            server = AsyncoreEchoServer(TESTPORT, CERTFILE)
+            flag = threading.Event()
+            server.start(flag)
+            # wait for it to start
+            flag.wait()
+            # try to connect
+            try:
+                try:
+                    s = ssl.wrap_socket(socket.socket())
+                    s.connect(('127.0.0.1', TESTPORT))
+                except ssl.SSLError, x:
+                    raise test_support.TestFailed("Unexpected SSL error:  " + str(x))
+                except Exception, x:
+                    raise test_support.TestFailed("Unexpected exception:  " + str(x))
+                else:
+                    if test_support.verbose:
+                        sys.stdout.write(
+                            " client:  sending %s...\n" % (repr(indata)))
+                    s.write(indata)
+                    outdata = s.read()
+                    if test_support.verbose:
+                        sys.stdout.write(" client:  read %s\n" % repr(outdata))
+                    if outdata != indata.lower():
+                        raise test_support.TestFailed(
+                            "bad data <<%s>> (%d) received; expected <<%s>> (%d)\n"
+                            % (outdata[:min(len(outdata),20)], len(outdata),
+                               indata[:min(len(indata),20)].lower(), len(indata)))
+                    s.write("over\n")
+                    if test_support.verbose:
+                        sys.stdout.write(" client:  closing connection.\n")
+                    s.close()
+            finally:
+                server.stop()
+                # wait for server thread to end
+                server.join()
+
+
+def findtestsocket(start, end):
+    def testbind(i):
+        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+        try:
+            try:
+                s.bind(("127.0.0.1", i))
+            except:
+                return 0
+            else:
+                return 1
+        finally:
+            s.close()
+
+    for i in range(start, end):
+        if testbind(i) and testbind(i+1):
+            return i
+    return 0
+
+
+def test_main(verbose=False):
+    if skip_expected:
+        raise test_support.TestSkipped("No SSL support")
+
+    global CERTFILE, TESTPORT, SVN_PYTHON_ORG_ROOT_CERT
+    CERTFILE = os.path.join(os.path.dirname(__file__) or os.curdir,
+                            "keycert.pem")
+    SVN_PYTHON_ORG_ROOT_CERT = os.path.join(
+        os.path.dirname(__file__) or os.curdir,
+        "https_svn_python_org_root.pem")
+
+    if (not os.path.exists(CERTFILE) or
+        not os.path.exists(SVN_PYTHON_ORG_ROOT_CERT)):
+        raise test_support.TestFailed("Can't read certificate files!")
+
+    TESTPORT = findtestsocket(10025, 12000)
+    if not TESTPORT:
+        raise test_support.TestFailed("Can't find open port to test servers on!")
+
+    tests = [BasicTests]
+
+    if test_support.is_resource_enabled('network'):
+        tests.append(NetworkedTests)
+
+    if _have_threads:
+        if CERTFILE and test_support.is_resource_enabled('network'):
+            tests.append(ThreadedTests)
+
+    test_support.run_unittest(*tests)
+
+
+if __name__ == "__main__":
+    test_main()

+ 1 - 0
ext/thirdparty/README.md

@@ -42,6 +42,7 @@ Checked-in third party dependencies
 |Y|simplejson|2.0.9|MIT|http://pypi.python.org/packages/source/s/simplejson/simplejson-2.0.9.tar.gz|
 |Y|South|0.7|Apache|http://south.aeracode.org/|
 |Y|Spawning|0.9.6|MIT|http://pypi.python.org/pypi/Spawning/0.9.6/|
+|Y|ssl|1.15|Python|http://pypi.python.org/pypi/ssl/1.15|
 |Y|threadframe|0.2|Python|http://www.majid.info/mylos/stories/2004/06/10/threadframe.html|
 |Y|Thrift|?|Apache|http://incubator.apache.org/thrift/download/|
 |Y|Twisted|8.2.0|MIT|http://twistedmatrix.com/trac/|