merge in trunk to help with the pkcs12 type unit tests a bit
diff --git a/ChangeLog b/ChangeLog
index 98ae8ff..d9d45f8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2009-07-17  Rick Dean  <rick@fdd.com>
+            Jean-Paul Calderone  <exarkun@twistedmatrix.com>
+
+	* src/crypto/x509ext.c: Add subject and issuer parameters to
+	  X509Extension, allowing creation of extensions which require that
+	  information.  Fixes LP#322813.
+
 2009-07-16  Jean-Paul Calderone  <exarkun@twistedmatrix.com>
 
 	* test/util.py: Changed the base TestCase's tearDown to assert that
diff --git a/INSTALL b/INSTALL
index 793b9bb..b650ba6 100644
--- a/INSTALL
+++ b/INSTALL
@@ -11,47 +11,59 @@
 pyOpenSSL uses distutils, so there really shouldn't be any problems. To build
 the library:
 
-    python setup.py build
+  $ python setup.py build
 
 If your OpenSSL header files aren't in /usr/include, you may need to supply
 the -I flag to let the setup script know where to look. The same goes for the
 libraries of course, use the -L flag. Note that build won't accept these
 flags, so you have to run first build_ext and then build! Example:
 
-    python setup.py build_ext -I/usr/local/ssl/include -L/usr/local/ssl/lib
-    python setup.py build
+  $ python setup.py build_ext -I/usr/local/ssl/include -L/usr/local/ssl/lib
+  $ python setup.py build
 
 Now you should have a directory called OpenSSL that contains e.g. SSL.so and
 __init__.py somewhere in the build dicrectory, so just:
 
-    python setup.py install
+  $ python setup.py install
 
 If you, for some arcane reason, don't want the module to appear in the
 site-packages directory, use the --prefix option.
 
 You can, of course, do
 
-    python setup.py --help
+  $ python setup.py --help
 
 to find out more about how to use the script.
 
 
 -- Building the Module on a Windows System --
 
-Big thanks to Itamar Shtull-Trauring and Oleg Orlov for their help with
-Windows build instructions. Same as for Unix systems, we have to separate
-the build_ext and the build.
+pyOpenSSL is known to build with mingw32 for Python 2.3 through Python 2.5. 
+For Python 2.6, the official Windows installer of which is built with
+Microsoft Visual Studio 2008 (version 9.0), Microsoft Visual Studio 2008
+(version 9.0) is required.  You can specify that mingw32 be used by passing
+the --compiler argument to build_ext.  You will also need to specify the
+location of the OpenSSL headers and libraries:
 
-Building the library:
+  C:\pyOpenSSL-X.Y> setup.py build_ext -c mingw32 -I C:\OpenSSL\include ^
+                      -L C:\OpenSSL bdist_msi
 
-    setup.py build_ext -I ...\openssl\inc32 -L ...\openssl\out32dll
-    setup.py build
+The correct header and library paths depend on how you have OpenSSL
+installed.  The above paths are correct for the default installation of
+(<http://www.slproweb.com/products/Win32OpenSSL.html>).
 
-Where ...\openssl is of course the location of your OpenSSL installation.
+The bdist_msi command will build an MSI installer.  It can be substituted
+with another bdist command if another kind of installer is desired.
 
-Installation is the same as for Unix systems:
+To build with MSVC instead, omit the -c option and pass a slightly different
+library directory:
 
-    setup.py install
+  C:\pyOpenSSL-X.Y> setup.py build_ext -I C:\OpenSSL\include ^
+                      -L C:\OpenSSL\lib bdist_msi
+
+The resulting binary distribution will be placed in the dist directory. To
+install it, dDepending on what kind of distribution you create, run it,
+unzip it, or copy it to Python installation's site-packages.
 
 And similarily, you can do
 
@@ -59,6 +71,9 @@
 
 to get more information.
 
+Big thanks to Itamar Shtull-Trauring, Oleg Orlov, Zooko O'Whielacronx, Chris
+Galvan, and #python and #distutils on FreeNode for their help with Windows
+build instructions.
 
 -- Documentation --
 
diff --git a/doc/pyOpenSSL.tex b/doc/pyOpenSSL.tex
index 3d2ce8f..cea48e9 100644
--- a/doc/pyOpenSSL.tex
+++ b/doc/pyOpenSSL.tex
@@ -188,8 +188,11 @@
 See \class{X509Extension}.
 \end{datadesc}
 
-\begin{classdesc}{X509Extension}{typename, critical, value}
-A class representing an X.509 v3 certificate extensions.
+\begin{classdesc}{X509Extension}{typename, critical, value\optional{, subject}\optional{, issuer}}
+A class representing an X.509 v3 certificate extensions.  
+See \url{http://openssl.org/docs/apps/x509v3_config.html\#STANDARD_EXTENSIONS} 
+for \var{typename} strings and their options.
+Optional parameters \var{subject} and \var{issuer} must be X509 objects.
 \end{classdesc}
 
 \begin{datadesc}{NetscapeSPKIType}
diff --git a/setup.py b/setup.py
index 06d477b..a6a446c 100755
--- a/setup.py
+++ b/setup.py
@@ -42,34 +42,27 @@
 
 # Add more platforms here when needed
 if os.name == 'nt' or sys.platform == 'win32':
-    Libraries = ['eay32', 'Ws2_32']
-    # Try to find it...
-    for path in ["C:\\OpenSSL\\lib\\MinGW", "C:\\Python23\\libs",
-                 "C:\\Python24\\libs", "C:\\Python25\\libs", "C:\\Python26\\libs"]:
-        # The .a is the "export library".  It's the thing we need to link
-        # against to let us use the .dll.
-        ssleay32 = os.path.join(path, "ssleay32.a")
-        if os.path.exists(ssleay32):
-            ExtraObjects = [ssleay32]
-            break
-    else:
-        raise SystemExit("Cannot find ssleay32.a, aborting")
+
+    Libraries = ['Ws2_32']
+    def makeTellMeIf(original, what):
+        class tellMeIf(original):
+            def __init__(*a, **kw):
+                Libraries.extend(what)
+                return original.__init__(*a, **kw)
+        return tellMeIf
+
+    from distutils import cygwinccompiler
+    cygwinccompiler.Mingw32CCompiler = makeTellMeIf(cygwinccompiler.Mingw32CCompiler, ['eay32', 'ssl32'])
+    from distutils import msvccompiler
+    msvccompiler.MSVCCompiler = makeTellMeIf(msvccompiler.MSVCCompiler, ['libeay32', 'ssleay32'])
+
+    import shutil
+    shutil.copy("C:\\OpenSSL\\ssleay32.dll", os.path.split(os.path.abspath(__file__))[0])
+    shutil.copy("C:\\OpenSSL\\libeay32.dll", os.path.split(os.path.abspath(__file__))[0])
+    package_data = {'': ['ssleay32.dll', 'libeay32.dll']}
 else:
     Libraries = ['ssl', 'crypto']
-    ExtraObjects = []
-
-if sys.platform == 'darwin':
-    IncludeDirs = ['/sw/include']
-    LibraryDirs = ['/sw/lib']
-
-# On Windows, make sure the necessary .dll's get added to the egg.
-data_files = []
-if sys.platform == 'win32':
-    import ctypes.util
-    libeay32 = ctypes.util.find_library("libeay32")
-    if libeay32 is None:
-        raise SystemExit("Cannot find libeay32.dll, aborting")
-    data_files = [("OpenSSL", [libeay32])]
+    package_data = {}
 
 
 def mkExtension(name):
@@ -77,10 +70,11 @@
     src = globals()[name.lower() + '_src']
     dep = globals()[name.lower() + '_dep']
     return Extension(modname, src, libraries=Libraries, depends=dep,
-                     include_dirs=IncludeDirs, library_dirs=LibraryDirs,
-                     extra_objects=ExtraObjects)
+                     include_dirs=IncludeDirs, library_dirs=LibraryDirs)
+
 
 setup(name='pyOpenSSL', version=__version__,
+      packages = ['OpenSSL'],
       package_dir = {'OpenSSL': '.'},
       ext_modules = [mkExtension('crypto'), mkExtension('rand'),
                      mkExtension('SSL')],
@@ -90,7 +84,8 @@
                      'OpenSSL.test.test_crypto',
                      'OpenSSL.test.test_rand',
                      'OpenSSL.test.test_ssl'],
-      data_files = data_files,
+      zip_safe = False,
+      package_data = package_data,
       description = 'Python wrapper module around the OpenSSL library',
       author = 'Martin Sjögren, AB Strakt',
       author_email = 'msjogren@gmail.com',
diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h
index 5d0bf27..b5e6b65 100644
--- a/src/crypto/crypto.h
+++ b/src/crypto/crypto.h
@@ -49,7 +49,7 @@
 
 #define crypto_X509Extension_New_NUM    5
 #define crypto_X509Extension_New_RETURN crypto_X509ExtensionObj *
-#define crypto_X509Extension_New_PROTO  (char *, int, char *)
+#define crypto_X509Extension_New_PROTO  (char *, int, char *, crypto_X509Obj *, crypto_X509Obj *)
 
 #define crypto_PKCS7_New_NUM            6
 #define crypto_PKCS7_New_RETURN         crypto_PKCS7Obj *
diff --git a/src/crypto/x509ext.c b/src/crypto/x509ext.c
index e7ab5e1..90ef543 100644
--- a/src/crypto/x509ext.c
+++ b/src/crypto/x509ext.c
@@ -72,20 +72,44 @@
  * Arguments: type_name - ???
  *            critical  - ???
  *            value     - ???
+ *            subject   - An x509v3 certificate which is the subject for this extension.
+ *            issuer    - An x509v3 certificate which is the issuer for this extension.
  * Returns:   The newly created X509Extension object
  */
 crypto_X509ExtensionObj *
-crypto_X509Extension_New(char *type_name, int critical, char *value)
-{
+crypto_X509Extension_New(char *type_name, int critical, char *value,
+                         crypto_X509Obj *subject, crypto_X509Obj  *issuer) {
     X509V3_CTX ctx;
     crypto_X509ExtensionObj *self;
     char* value_with_critical = NULL;
 
-    /* We have no configuration database - but perhaps we should.  Anyhow, the
-     * context is necessary for any extension which uses the r2i conversion
-     * method.  That is, X509V3_EXT_nconf may segfault if passed a NULL ctx. */
+
+    /*
+     * A context is necessary for any extension which uses the r2i conversion
+     * method.  That is, X509V3_EXT_nconf may segfault if passed a NULL ctx.
+     * Start off by initializing most of the fields to NULL.
+     */
+    X509V3_set_ctx(&ctx, NULL, NULL, NULL, NULL, 0);
+
+    /*
+     * We have no configuration database - but perhaps we should (some
+     * extensions may require it).
+     */
     X509V3_set_ctx_nodb(&ctx);
 
+    /*
+     * Initialize the subject and issuer, if appropriate.  ctx is a local, and
+     * as far as I can tell none of the X509V3_* APIs invoked here steal any
+     * references, so no need to incref subject or issuer.
+     */
+    if (subject) {
+            ctx.subject_cert = subject->x509;
+    }
+
+    if (issuer) {
+            ctx.issuer_cert = issuer->x509;
+    }
+
     self = PyObject_New(crypto_X509ExtensionObj, &crypto_X509Extension_Type);
 
     if (self == NULL) {
@@ -137,27 +161,40 @@
 }
 
 static char crypto_X509Extension_doc[] = "\n\
-X509Extension(typename, critical, value) -> X509Extension instance\n\
+X509Extension(typename, critical, value[, subject][, issuer]) -> \n\
+                X509Extension instance\n\
 \n\
 @param typename: The name of the extension to create.\n\
 @type typename: C{str}\n\
 @param critical: A flag indicating whether this is a critical extension.\n\
 @param value: The value of the extension.\n\
 @type value: C{str}\n\
+@param subject: Optional X509 cert to use as subject.\n\
+@type subject: C{X509}\n\
+@param issuer: Optional X509 cert to use as issuer.\n\
+@type issuer: C{X509}\n\
 @return: The X509Extension object\n\
 ";
 
 static PyObject *
-crypto_X509Extension_new(PyTypeObject *subtype, PyObject *args, PyObject *kwargs) {
+crypto_X509Extension_new(PyTypeObject *subtype, PyObject *args,
+                         PyObject *kwargs) {
     char *type_name, *value;
-    int critical;
+    int critical = 0;
+    crypto_X509Obj * subject = NULL;
+    crypto_X509Obj * issuer = NULL;
+    static char *kwlist[] = {"type_name", "critical", "value", "subject",
+                             "issuer", NULL};
 
-    if (!PyArg_ParseTuple(args, "sis:X509Extension", &type_name, &critical,
-                          &value)) {
+    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sis|O!O!:X509Extension",
+                                     kwlist, &type_name, &critical, &value,
+                                     &crypto_X509_Type, &subject,
+                                     &crypto_X509_Type, &issuer )) {
         return NULL;
     }
 
-    return (PyObject *)crypto_X509Extension_New(type_name, critical, value);
+    return (PyObject *)crypto_X509Extension_New(type_name, critical, value,
+                                                subject, issuer);
 }
 
 /*
diff --git a/test/test_crypto.py b/test/test_crypto.py
index dcc8cef..312a1b0 100644
--- a/test/test_crypto.py
+++ b/test/test_crypto.py
@@ -7,6 +7,7 @@
 from unittest import main
 
 from os import popen2
+from datetime import datetime, timedelta
 
 from OpenSSL.crypto import TYPE_RSA, TYPE_DSA, Error, PKey, PKeyType
 from OpenSSL.crypto import X509, X509Type, X509Name, X509NameType
@@ -225,8 +226,44 @@
 """
 
 
-
 class X509ExtTests(TestCase):
+    """
+    Tests for L{OpenSSL.crypto.X509Extension}.
+    """
+
+    def setUp(self):
+        """
+        Create a new private key and start a certificate request (for a test
+        method to finish in one way or another).
+        """
+        # Basic setup stuff to generate a certificate
+        self.pkey = PKey()
+        self.pkey.generate_key(TYPE_RSA, 384)
+        self.req = X509Req()
+        self.req.set_pubkey(self.pkey)
+        # Authority good you have.
+        self.req.get_subject().commonName = "Yoda root CA"
+        self.x509 = X509()
+        self.subject = self.x509.get_subject()
+        self.subject.commonName = self.req.get_subject().commonName
+        self.x509.set_issuer(self.subject)
+        self.x509.set_pubkey(self.pkey)
+        now = datetime.now().strftime("%Y%m%d%H%M%SZ")
+        expire  = (datetime.now() + timedelta(days=100)).strftime("%Y%m%d%H%M%SZ")
+        self.x509.set_notBefore(now)
+        self.x509.set_notAfter(expire)
+
+
+    def test_type(self):
+        """
+        L{X509Extension} and L{X509ExtensionType} refer to the same type object
+        and can be used to create instances of that type.
+        """
+        self.assertIdentical(X509Extension, X509ExtensionType)
+        self.assertConsistentType(
+            X509Extension, 'X509Extension', 'basicConstraints', True, 'CA:true')
+
+
     def test_construction(self):
         """
         L{X509Extension} accepts an extension type name, a critical flag,
@@ -286,14 +323,122 @@
         self.assertEqual(ext.get_short_name(), 'nsComment')
 
 
+    def test_unused_subject(self):
+        """
+        The C{subject} parameter to L{X509Extension} may be provided for an
+        extension which does not use it and is ignored in this case.
+        """
+        ext1 = X509Extension('basicConstraints', False, 'CA:TRUE', subject=self.x509)
+        self.x509.add_extensions([ext1])
+        self.x509.sign(self.pkey, 'sha1')
+        # This is a little lame.  Can we think of a better way?
+        text = dump_certificate(FILETYPE_TEXT, self.x509)
+        self.assertTrue('X509v3 Basic Constraints:' in text)
+        self.assertTrue('CA:TRUE' in text)
+
+
+    def test_subject(self):
+        """
+        If an extension requires a subject, the C{subject} parameter to
+        L{X509Extension} provides its value.
+        """
+        ext3 = X509Extension('subjectKeyIdentifier', False, 'hash', subject=self.x509)
+        self.x509.add_extensions([ext3])
+        self.x509.sign(self.pkey, 'sha1')
+        text = dump_certificate(FILETYPE_TEXT, self.x509)
+        self.assertTrue('X509v3 Subject Key Identifier:' in text)
+
+
+    def test_missing_subject(self):
+        """
+        If an extension requires a subject and the C{subject} parameter is
+        given no value, something happens.
+        """
+        self.assertRaises(
+            Error, X509Extension, 'subjectKeyIdentifier', False, 'hash')
+
+
+    def test_invalid_subject(self):
+        """
+        If the C{subject} parameter is given a value which is not an L{X509}
+        instance, L{TypeError} is raised.
+        """
+        for badObj in [True, object(), "hello", [], self]:
+            self.assertRaises(
+                TypeError,
+                X509Extension,
+                'basicConstraints', False, 'CA:TRUE', subject=badObj)
+
+
+    def test_unused_issuer(self):
+        """
+        The C{issuer} parameter to L{X509Extension} may be provided for an
+        extension which does not use it and is ignored in this case.
+        """
+        ext1 = X509Extension('basicConstraints', False, 'CA:TRUE', issuer=self.x509)
+        self.x509.add_extensions([ext1])
+        self.x509.sign(self.pkey, 'sha1')
+        text = dump_certificate(FILETYPE_TEXT, self.x509)
+        self.assertTrue('X509v3 Basic Constraints:' in text)
+        self.assertTrue('CA:TRUE' in text)
+
+
+    def test_issuer(self):
+        """
+        If an extension requires a issuer, the C{issuer} parameter to
+        L{X509Extension} provides its value.
+        """
+        ext2 = X509Extension(
+            'authorityKeyIdentifier', False, 'issuer:always',
+            issuer=self.x509)
+        self.x509.add_extensions([ext2])
+        self.x509.sign(self.pkey, 'sha1')
+        text = dump_certificate(FILETYPE_TEXT, self.x509)
+        self.assertTrue('X509v3 Authority Key Identifier:' in text)
+        self.assertTrue('DirName:/CN=Yoda root CA' in text)
+
+
+    def test_missing_issuer(self):
+        """
+        If an extension requires an issue and the C{issuer} parameter is given
+        no value, something happens.
+        """
+        self.assertRaises(
+            Error,
+            X509Extension,
+            'authorityKeyIdentifier', False, 'keyid:always,issuer:always')
+
+
+    def test_invalid_issuer(self):
+        """
+        If the C{issuer} parameter is given a value which is not an L{X509}
+        instance, L{TypeError} is raised.
+        """
+        for badObj in [True, object(), "hello", [], self]:
+            self.assertRaises(
+                TypeError,
+                X509Extension,
+                'authorityKeyIdentifier', False, 'keyid:always,issuer:always',
+                issuer=badObj)
+
+
 
 class PKeyTests(TestCase):
     """
     Unit tests for L{OpenSSL.crypto.PKey}.
     """
+    def test_type(self):
+        """
+        L{PKey} and L{PKeyType} refer to the same type object and can be used
+        to create instances of that type.
+        """
+        self.assertIdentical(PKey, PKeyType)
+        self.assertConsistentType(PKey, 'PKey')
+
+
     def test_construction(self):
         """
-        L{PKey} takes no arguments and returns a new L{PKeyType} instance.
+        L{PKey} takes no arguments and returns a new L{PKey} instance.
         """
         self.assertRaises(TypeError, PKey, None)
         key = PKey()
@@ -402,6 +547,21 @@
         return name
 
 
+    def test_type(self):
+        """
+        The type of X509Name objects is L{X509NameType}.
+        """
+        self.assertIdentical(X509Name, X509NameType)
+        self.assertEqual(X509NameType.__name__, 'X509Name')
+        self.assertTrue(isinstance(X509NameType, type))
+
+        name = self._x509name()
+        self.assertTrue(
+            isinstance(name, X509NameType),
+            "%r is of type %r, should be %r" % (
+                name, type(name), X509NameType))
+
+
     def test_attributes(self):
         """
         L{X509NameType} instances have attributes for each standard (?)
@@ -613,6 +773,15 @@
         return X509Req()
 
 
+    def test_type(self):
+        """
+        L{X509Req} and L{X509ReqType} refer to the same type object and can be
+        used to create instances of that type.
+        """
+        self.assertIdentical(X509Req, X509ReqType)
+        self.assertConsistentType(X509Req, 'X509Req')
+
+
     def test_construction(self):
         """
         L{X509Req} takes no arguments and returns an L{X509ReqType} instance.
@@ -669,6 +838,15 @@
         return X509()
 
 
+    def test_type(self):
+        """
+        L{X509} and L{X509Type} refer to the same type object and can be used
+        to create instances of that type.
+        """
+        self.assertIdentical(X509, X509Type)
+        self.assertConsistentType(X509, 'X509')
+
+
     def test_construction(self):
         """
         L{X509} takes no arguments and returns an instance of L{X509Type}.
@@ -679,6 +857,10 @@
             "%r is of type %r, should be %r" % (certificate,
                                                 type(certificate),
                                                 X509Type))
+        self.assertEqual(type(X509Type).__name__, 'type')
+        self.assertEqual(type(certificate).__name__, 'X509')
+        self.assertEqual(type(certificate), X509Type)
+        self.assertEqual(type(certificate), X509)
 
 
     def test_serial_number(self):
@@ -1218,10 +1400,51 @@
 
 
 
+class PKCS7Tests(TestCase):
+    """
+    Tests for L{PKCS7Type}.
+    """
+    def test_type(self):
+        """
+        L{PKCS7Type} is a type object.
+        """
+        self.assertTrue(isinstance(PKCS7Type, type))
+        self.assertEqual(PKCS7Type.__name__, 'PKCS7')
+
+        # XXX This doesn't currently work.
+        # self.assertIdentical(PKCS7, PKCS7Type)
+
+
+
+class PKCS12Tests(TestCase):
+    """
+    Tests for L{PKCS12Type}.
+    """
+    def test_type(self):
+        """
+        L{PKCS12Type} is a type object.
+        """
+        self.assertTrue(isinstance(PKCS12Type, type))
+        self.assertEqual(PKCS12Type.__name__, 'PKCS12')
+
+        # XXX This doesn't currently work.
+        # self.assertIdentical(PKCS12, PKCS12Type)
+
+
+
 class NetscapeSPKITests(TestCase):
     """
     Tests for L{OpenSSL.crypto.NetscapeSPKI}.
     """
+    def test_type(self):
+        """
+        L{NetscapeSPKI} and L{NetscapeSPKIType} refer to the same type object
+        and can be used to create instances of that type.
+        """
+        self.assertIdentical(NetscapeSPKI, NetscapeSPKIType)
+        self.assertConsistentType(NetscapeSPKI, 'NetscapeSPKI')
+
+
     def test_construction(self):
         """
         L{NetscapeSPKI} returns an instance of L{NetscapeSPKIType}.
diff --git a/test/test_ssl.py b/test/test_ssl.py
index 9eb8946..5d386a9 100644
--- a/test/test_ssl.py
+++ b/test/test_ssl.py
@@ -6,14 +6,14 @@
 
 from sys import platform
 from socket import socket
-from os import makedirs, symlink
+from os import makedirs
 from os.path import join
 from unittest import main
 
 from OpenSSL.crypto import TYPE_RSA, FILETYPE_PEM, PKey, dump_privatekey, load_certificate, load_privatekey
-from OpenSSL.SSL import WantReadError, Context, Connection, Error
+from OpenSSL.SSL import WantReadError, Context, ContextType, Connection, ConnectionType, Error
 from OpenSSL.SSL import SSLv2_METHOD, SSLv3_METHOD, SSLv23_METHOD, TLSv1_METHOD
-from OpenSSL.SSL import OP_NO_SSLv2, OP_NO_SSLv3, OP_SINGLE_DH_USE 
+from OpenSSL.SSL import OP_NO_SSLv2, OP_NO_SSLv3, OP_SINGLE_DH_USE
 from OpenSSL.SSL import VERIFY_PEER, VERIFY_FAIL_IF_NO_PEER_CERT, VERIFY_CLIENT_ONCE
 from OpenSSL.test.util import TestCase
 from OpenSSL.test.test_crypto import cleartextCertificatePEM, cleartextPrivateKeyPEM
@@ -34,8 +34,7 @@
 
 def socket_pair():
     """
-    Establish and return a pair of network sockets connected 
-    to each other.
+    Establish and return a pair of network sockets connected to each other.
     """
     # Connect a pair of sockets
     port = socket()
@@ -43,7 +42,7 @@
     port.listen(1)
     client = socket()
     client.setblocking(False)
-    client.connect_ex(port.getsockname())
+    client.connect_ex(("127.0.0.1", port.getsockname()[1]))
     client.setblocking(True)
     server = port.accept()[0]
 
@@ -78,6 +77,15 @@
         self.assertRaises(ValueError, Context, 10)
 
 
+    def test_type(self):
+        """
+        L{Context} and L{ContextType} refer to the same type object and can be
+        used to create instances of that type.
+        """
+        self.assertIdentical(Context, ContextType)
+        self.assertConsistentType(Context, 'Context', TLSv1_METHOD)
+
+
     def test_use_privatekey(self):
         """
         L{Context.use_privatekey} takes an L{OpenSSL.crypto.PKey} instance.
@@ -216,49 +224,47 @@
         """
         capath = self.mktemp()
         makedirs(capath)
-        cafile = join(capath, 'cert.pem')
+        # Hash value computed manually with c_rehash to avoid depending on
+        # c_rehash in the test suite.
+        cafile = join(capath, 'c7adac82.0')
         fObj = file(cafile, 'w')
         fObj.write(cleartextCertificatePEM)
         fObj.close()
 
-        # Hash value computed manually with c_rehash to avoid depending on
-        # c_rehash in the test suite.
-        symlink('cert.pem', join(capath, 'c7adac82.0'))
-
         self._load_verify_locations_test(None, capath)
 
 
-    def test_set_default_verify_paths(self):
-        """
-        L{Context.set_default_verify_paths} causes the platform-specific CA
-        certificate locations to be used for verification purposes.
-        """
-        # Testing this requires a server with a certificate signed by one of
-        # the CAs in the platform CA location.  Getting one of those costs
-        # money.  Fortunately (or unfortunately, depending on your
-        # perspective), it's easy to think of a public server on the
-        # internet which has such a certificate.  Connecting to the network
-        # in a unit test is bad, but it's the only way I can think of to
-        # really test this. -exarkun
+    if platform in ("darwin", "win32"):
+        "set_default_verify_paths appears not to work on OS X or Windows"
+        "See LP#404343 and LP#404344."
+    else:
+        def test_set_default_verify_paths(self):
+            """
+            L{Context.set_default_verify_paths} causes the platform-specific CA
+            certificate locations to be used for verification purposes.
+            """
+            # Testing this requires a server with a certificate signed by one of
+            # the CAs in the platform CA location.  Getting one of those costs
+            # money.  Fortunately (or unfortunately, depending on your
+            # perspective), it's easy to think of a public server on the
+            # internet which has such a certificate.  Connecting to the network
+            # in a unit test is bad, but it's the only way I can think of to
+            # really test this. -exarkun
 
-        # Arg, verisign.com doesn't speak TLSv1
-        context = Context(SSLv3_METHOD)
-        context.set_default_verify_paths()
-        context.set_verify(
-            VERIFY_PEER, 
-            lambda conn, cert, errno, depth, preverify_ok: preverify_ok)
+            # Arg, verisign.com doesn't speak TLSv1
+            context = Context(SSLv3_METHOD)
+            context.set_default_verify_paths()
+            context.set_verify(
+                VERIFY_PEER, 
+                lambda conn, cert, errno, depth, preverify_ok: preverify_ok)
 
-        client = socket()
-        client.connect(('verisign.com', 443))
-        clientSSL = Connection(context, client)
-        clientSSL.set_connect_state()
-        clientSSL.do_handshake()
-        clientSSL.send('GET / HTTP/1.0\r\n\r\n')
-        self.assertTrue(clientSSL.recv(1024))
-    if platform == "darwin":
-        test_set_default_verify_paths.todo = (
-            "set_default_verify_paths appears not to work on OS X - a "
-            "problem with the supplied OpenSSL, perhaps?")
+            client = socket()
+            client.connect(('verisign.com', 443))
+            clientSSL = Connection(context, client)
+            clientSSL.set_connect_state()
+            clientSSL.do_handshake()
+            clientSSL.send('GET / HTTP/1.0\r\n\r\n')
+            self.assertTrue(clientSSL.recv(1024))
 
 
     def test_set_default_verify_paths_signature(self):
@@ -273,6 +279,34 @@
 
 
 
+class ConnectionTests(TestCase):
+    """
+    Unit tests for L{OpenSSL.SSL.Connection}.
+    """
+    def test_type(self):
+        """
+        L{Connection} and L{ConnectionType} refer to the same type object and
+        can be used to create instances of that type.
+        """
+        self.assertIdentical(Connection, ConnectionType)
+        ctx = Context(TLSv1_METHOD)
+        self.assertConsistentType(Connection, 'Connection', ctx, None)
+
+
+
+class ErrorTests(TestCase):
+    """
+    Unit tests for L{OpenSSL.SSL.Error}.
+    """
+    def test_type(self):
+        """
+        L{Error} is an exception type.
+        """
+        self.assertTrue(issubclass(Error, Exception))
+        self.assertEqual(Error.__name__, 'Error')
+
+
+
 class ConstantsTests(TestCase):
     """
     Tests for the values of constants exposed in L{OpenSSL.SSL}.
diff --git a/test/util.py b/test/util.py
index d3572db..d195d95 100644
--- a/test/util.py
+++ b/test/util.py
@@ -11,6 +11,7 @@
 import os, os.path
 from tempfile import mktemp
 from unittest import TestCase
+import sys
 
 from OpenSSL.crypto import Error, _exception_from_error_queue
 
@@ -88,10 +89,10 @@
         except exception, inst:
             return inst
         except:
-            raise self.failureException('%s raised instead of %s:\n %s'
+            raise self.failureException('%s raised instead of %s'
                                         % (sys.exc_info()[0],
                                            exception.__name__,
-                                           failure.Failure().getTraceback()))
+                                          ))
         else:
             raise self.failureException('%s not raised (%r returned)'
                                         % (exception.__name__, result))
@@ -117,3 +118,22 @@
 
     def assertFalse(self, *a, **kw):
         return self.failIf(*a, **kw)
+
+
+    # Other stuff
+    def assertConsistentType(self, theType, name, *constructionArgs):
+        """
+        Perform various assertions about C{theType} to ensure that it is a
+        well-defined type.  This is useful for extension types, where it's
+        pretty easy to do something wacky.  If something about the type is
+        unusual, an exception will be raised.
+
+        @param theType: The type object about which to make assertions.
+        @param name: A string giving the name of the type.
+        @param constructionArgs: Positional arguments to use with C{theType} to
+            create an instance of it.
+        """
+        self.assertEqual(theType.__name__, name)
+        self.assertTrue(isinstance(theType, type))
+        instance = theType(*constructionArgs)
+        self.assertIdentical(type(instance), theType)