Simplify support for building on Windows; make sure to include all the necessary dlls when making binary distributions
diff --git a/ChangeLog b/ChangeLog
index a2085a4..d9d45f8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,58 @@
+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
+	  no errors were left in the OpenSSL error queue by the test.
+	* src/crypto/crypto.c: Add a private helper in support of the
+	  TestCase.tearDown change.
+	* src/crypto/x509name.c: Changed X509Name's getattr implementation
+	  to clean up the error queue.  Fixes LP#314814.
+	* test/util.c: Changed flush_error_queue to avoid a reference
+	  counting bug caused by macro expansion.
+
+2009-07-16  Rick Dean  <rick@fdd.com>
+
+	* src/rand.c: Added OpenSSL.rand.bytes to get random bytes directly.
+	* src/util.c: Added generic exceptions_from_error_queue to replace
+	  the various other implementations of this function.  Also updated
+	  the rest of the codebase to use this version instead.
+
+2009-07-05  Jean-Paul Calderone  <exarkun@twistedmatrix.com>
+
+	* test/util.py, test/test_ssl.py, test/test_crypto.py: Fold the
+	  Python 2.3 compatibility TestCase mixin into the TestCase defined
+	  in util.py.
+
+2009-07-05  Jean-Paul Calderone  <exarkun@twistedmatrix.com>
+
+	* test/util.py, test/test_ssl.py, test/test_crypto.py: Stop trying
+	  to use Twisted's TestCase even when it's available.  Instead,
+	  always use the stdlib TestCase with a few enhancements.
+
+2009-07-04  Jean-Paul Calderone  <exarkun@twistedmatrix.com>
+
+	* Changed most extension types so that they can be instantiated
+	  using the type object rather than a factory function.  The old
+	  factory functions are now aliases for the type objects.
+	  Fixes LP#312786.
+
+2009-05-27  Jean-Paul Calderone  <exarkun@twistedmatrix.com>
+
+	* Changed all docstrings in extension modules to be friendlier
+	  towards Python programmers.  Fixes LP#312787.
+
+2009-05-27  Jean-Paul Calderone  <exarkun@twistedmatrix.com>
+
+	* src/crypto/x509ext.c: Correctly deallocate the new Extension
+	  instance when there is an error initializing it and it is not
+	  going to be returned.  Resolves LP#368043.
+
 2009-05-11  Jean-Paul Calderone  <exarkun@twistedmatrix.com>
 
 	* test/test_crypto.py: Use binary mode for the pipe to talk to the
diff --git a/doc/README b/doc/README
new file mode 100644
index 0000000..0ceff15
--- /dev/null
+++ b/doc/README
@@ -0,0 +1,18 @@
+
+Only the .tex format documentation is original,
+because the others are derived from it, so don't
+edit them directly.  To build the other formats
+use a command of ...
+
+  make all
+
+
+To build the documentation you will need to have
+latex2html and lynx installed.  On Fedora both can
+be obtained with ...
+
+  sudo yum install latex2html lynx
+
+Or on Debian or Ubuntu ...
+
+  sudo apt-get install latex2html lynx
diff --git a/doc/pyOpenSSL.tex b/doc/pyOpenSSL.tex
index b9d1f20..bd83d6d 100644
--- a/doc/pyOpenSSL.tex
+++ b/doc/pyOpenSSL.tex
@@ -138,40 +138,43 @@
 \modulesynopsis{Generic cryptographic module}
 
 \begin{datadesc}{X509Type}
-A Python type object representing the X509 object type.
+See \class{X509}.
 \end{datadesc}
 
-\begin{funcdesc}{X509}{}
-Factory function that creates an X509 object.
-\end{funcdesc}
+\begin{classdesc}{X509}{}
+A class representing X.509 certificates.
+\end{classdesc}
 
 \begin{datadesc}{X509NameType}
-A Python type object representing the X509Name object type.
+See \class{X509Name}.
 \end{datadesc}
 
-\begin{funcdesc}{X509Name}{x509name}
-Factory function that creates a copy of \var{x509name}.
-\end{funcdesc}
+\begin{classdesc}{X509Name}{x509name}
+A class representing X.509 Distinguished Names.
+
+This constructor creates a copy of \var{x509name} which should be an
+instance of \class{X509Name}.
+\end{classdesc}
 
 \begin{datadesc}{X509ReqType}
-A Python type object representing the X509Req object type.
+See \class{X509Req}.
 \end{datadesc}
 
-\begin{funcdesc}{X509Req}{}
-Factory function that creates an X509Req object.
-\end{funcdesc}
+\begin{classdesc}{X509Req}{}
+A class representing X.509 certificate requests.
+\end{classdesc}
 
 \begin{datadesc}{X509StoreType}
 A Python type object representing the X509Store object type.
 \end{datadesc}
 
 \begin{datadesc}{PKeyType}
-A Python type object representing the PKey object type.
+See \class{PKey}.
 \end{datadesc}
 
-\begin{funcdesc}{PKey}{}
-Factory function that creates a PKey object.
-\end{funcdesc}
+\begin{classdesc}{PKey}{}
+A class representing DSA or RSA keys.
+\end{classdesc}
 
 \begin{datadesc}{PKCS7Type}
 A Python type object representing the PKCS7 object type.
@@ -182,22 +185,27 @@
 \end{datadesc}
 
 \begin{datadesc}{X509ExtensionType}
-A Python type object representing the X509Extension object type.
+See \class{X509Extension}.
 \end{datadesc}
 
-\begin{funcdesc}{X509Extension}{typename, critical, value}
-Factory function that creates a X509Extension object.
-\end{funcdesc}
+\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}
-A Python type object representing the NetscapeSPKI object type.
+See \class{NetscapeSPKI}.
 \end{datadesc}
 
-\begin{funcdesc}{NetscapeSPKI}{\optional{enc}}
-Factory function that creates a NetscapeSPKI object. If the \var{enc} argument
-is present, it should be a base64-encoded string representing a NetscapeSPKI
-object, as returned by the \method{b64_encode} method.
-\end{funcdesc}
+\begin{classdesc}{NetscapeSPKI}{\optional{enc}}
+A class representing Netscape SPKI objects.
+
+If the \var{enc} argument is present, it should be a base64-encoded string
+representing a NetscapeSPKI object, as returned by the \method{b64_encode}
+method.
+\end{classdesc}
 
 \begin{datadesc}{FILETYPE_PEM}
 \dataline{FILETYPE_ASN1}
@@ -588,6 +596,18 @@
 \var{string}, measured in bytes. For more information, see e.g. \rfc{1750}.
 \end{funcdesc}
 
+\begin{funcdesc}{bytes}{num_bytes}
+Get some random bytes from the PRNG as a string.
+
+This is a wrapper for the C function \function{RAND_bytes}.
+\end{funcdesc}
+
+\begin{funcdesc}{cleanup}{}
+Erase the memory used by the PRNG.
+
+This is a wrapper for the C function \function{RAND_cleanup}.
+\end{funcdesc}
+
 \begin{funcdesc}{egd}{path\optional{, bytes}}
 Query the Entropy Gathering Daemon\footnote{See
 \url{http://www.lothar.com/tech/crypto/}} on socket \var{path} for \var{bytes}
@@ -619,6 +639,16 @@
 file can then be used with \function{load_file} to seed the PRNG again.
 \end{funcdesc}
 
+\begin{excdesc}{Error}
+If the current RAND method supports any errors, this is raised when needed.  
+The default method does not raise this when the entropy pool is depleted.
+
+Whenever this exception is raised directly, it has a list of error messages
+from the OpenSSL error queue, where each item is a tuple \code{(\var{lib},
+\var{function}, \var{reason})}. Here \var{lib}, \var{function} and \var{reason}
+are all strings, describing where and what the problem is. See \manpage{err}{3}
+for more information.
+\end{excdesc}
 
 
 % % % SSL module
@@ -667,27 +697,32 @@
 \end{datadesc}
 
 \begin{datadesc}{ContextType}
-A Python type object representing the Context object type.
+See \class{Context}.
 \end{datadesc}
 
-\begin{funcdesc}{Context}{method}
-Factory function that creates a new Context object given an SSL method. The
-method should be \constant{SSLv2_METHOD}, \constant{SSLv3_METHOD},
+\begin{classdesc}{Context}{method}
+A class representing SSL contexts.  Contexts define the parameters of one or
+more SSL connections.
+
+\var{method} should be \constant{SSLv2_METHOD}, \constant{SSLv3_METHOD},
 \constant{SSLv23_METHOD} or \constant{TLSv1_METHOD}.
-\end{funcdesc}
+\end{classdesc}
 
 \begin{datadesc}{ConnectionType}
-A Python type object representing the Connection object type.
+See \class{Connection}.
 \end{datadesc}
 
-\begin{funcdesc}{Connection}{context, socket}
-Factory function that creates a new Connection object given an SSL context and
-a socket \footnote{Actually, all that is required is an object that
-  \emph{behaves} like a socket, you could even use files, even though it'd be
-  tricky to get the handshakes right!} object.  \var{socket} may be \var{None};
-in this case, the Connection is created with a memory BIO: see the
-\method{bio_read}, \method{bio_write}, and \method{bio_shutdown} methods.
-\end{funcdesc}
+\begin{classdesc}{Connection}{context, socket}
+A class representing SSL connections.
+
+\var{context} should be an instance of \class{Context} and \var{socket}
+should be a socket \footnote{Actually, all that is required is an object
+that \emph{behaves} like a socket, you could even use files, even though
+it'd be tricky to get the handshakes right!} object.  \var{socket} may be
+\var{None}; in this case, the Connection is created with a memory BIO: see
+the \method{bio_read}, \method{bio_write}, and \method{bio_shutdown}
+methods.
+\end{classdesc}
 
 \begin{excdesc}{Error}
 This exception is used as a base class for the other SSL-related
@@ -715,10 +750,19 @@
 The operation did not complete; the same I/O method should be called again
 later, with the same arguments. Any I/O method can lead to this since new
 handshakes can occur at any time.
+
+The wanted read is for \emph{dirty} data sent over the network, not the
+\emph{clean} data inside the tunnel.  For a socket based SSL connection,
+\emph{read} means data coming at us over the network.  Until that read
+succeeds, the attempted \method{OpenSSL.SSL.Connection.recv},
+\method{OpenSSL.SSL.Connection.send}, or
+\method{OpenSSL.SSL.Connection.do_handshake} is prevented or incomplete. You
+probably want to \method{select()} on the socket before trying again.
 \end{excdesc}
 
 \begin{excdesc}{WantWriteError}
-See \exception{WantReadError}.
+See \exception{WantReadError}.  The socket send buffer may be too full to
+write more data.
 \end{excdesc}
 
 \begin{excdesc}{WantX509LookupError}
diff --git a/setup.py b/setup.py
index 19cfc8c..a6a446c 100755
--- a/setup.py
+++ b/setup.py
@@ -80,7 +80,9 @@
                      mkExtension('SSL')],
       py_modules  = ['OpenSSL.__init__', 'OpenSSL.tsafe',
                      'OpenSSL.version', 'OpenSSL.test.__init__',
+                     'OpenSSL.test.util',
                      'OpenSSL.test.test_crypto',
+                     'OpenSSL.test.test_rand',
                      'OpenSSL.test.test_ssl'],
       zip_safe = False,
       package_data = package_data,
diff --git a/src/crypto/crypto.c b/src/crypto/crypto.c
index 257c016..21501c1 100644
--- a/src/crypto/crypto.c
+++ b/src/crypto/crypto.c
@@ -2,7 +2,7 @@
  * crypto.c
  *
  * Copyright (C) AB Strakt 2001, All rights reserved
- * Copyright (C) Jean-Paul Calderone 2008, All rights reserved
+ * Copyright (C) Jean-Paul Calderone 2008-2009, All rights reserved
  *
  * Main file of crypto sub module.
  * See the file RATIONALE for a short explanation of why this module was written.
@@ -49,14 +49,13 @@
 static char crypto_load_privatekey_doc[] = "\n\
 Load a private key from a buffer\n\
 \n\
-Arguments: spam - Always NULL\n\
-           args - The Python argument tuple, should be:\n\
-             type       - The file type (one of FILETYPE_PEM, FILETYPE_ASN1)\n\
-             buffer     - The buffer the key is stored in\n\
-             passphrase - (optional) if encrypted PEM format, this can be\n\
-                          either the passphrase to use, or a callback for\n\
-                          providing the passphrase.\n\
-Returns:   The PKey object\n\
+@param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)\n\
+@param buffer: The buffer the key is stored in\n\
+@param passphrase: (optional) if encrypted PEM format, this can be\n\
+                   either the passphrase to use, or a callback for\n\
+                   providing the passphrase.\n\
+\n\
+@return: The PKey object\n\
 ";
 
 static PyObject *
@@ -113,7 +112,7 @@
 
     if (pkey == NULL)
     {
-        exception_from_error_queue();
+        exception_from_error_queue(crypto_Error);
         return NULL;
     }
 
@@ -123,16 +122,15 @@
 static char crypto_dump_privatekey_doc[] = "\n\
 Dump a private key to a buffer\n\
 \n\
-Arguments: spam - Always NULL\n\
-           args - The Python argument tuple, should be:\n\
-             type       - The file type (one of FILETYPE_PEM, FILETYPE_ASN1)\n\
-             pkey       - The PKey to dump\n\
-             cipher     - (optional) if encrypted PEM format, the cipher to\n\
-                          use\n\
-             passphrase - (optional) if encrypted PEM format, this can be either\n\
-                          the passphrase to use, or a callback for providing the\n\
-                          passphrase.\n\
-Returns:   The buffer with the dumped key in\n\
+@param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)\n\
+@param pkey: The PKey to dump\n\
+@param cipher: (optional) if encrypted PEM format, the cipher to\n\
+               use\n\
+@param passphrase - (optional) if encrypted PEM format, this can be either\n\
+                    the passphrase to use, or a callback for providing the\n\
+                    passphrase.\n\
+@return: The buffer with the dumped key in\n\
+@rtype: C{str}\n\
 ";
 
 static PyObject *
@@ -215,7 +213,7 @@
     if (ret == 0)
     {
         BIO_free(bio);
-        exception_from_error_queue();
+        exception_from_error_queue(crypto_Error);
         return NULL;
     }
 
@@ -229,11 +227,9 @@
 static char crypto_load_certificate_doc[] = "\n\
 Load a certificate from a buffer\n\
 \n\
-Arguments: spam - Always NULL\n\
-           args - The Python argument tuple, should be:\n\
-             type   - The file type (one of FILETYPE_PEM, FILETYPE_ASN1)\n\
+@param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)\n\
              buffer - The buffer the certificate is stored in\n\
-Returns:   The X509 object\n\
+@return: The X509 object\n\
 ";
 
 static PyObject *
@@ -268,7 +264,7 @@
 
     if (cert == NULL)
     {
-        exception_from_error_queue();
+        exception_from_error_queue(crypto_Error);
         return NULL;
     }
 
@@ -278,11 +274,9 @@
 static char crypto_dump_certificate_doc[] = "\n\
 Dump a certificate to a buffer\n\
 \n\
-Arguments: spam - Always NULL\n\
-           args - The Python argument tuple, should be:\n\
-             type - The file type (one of FILETYPE_PEM, FILETYPE_ASN1)\n\
-             cert - The certificate to dump\n\
-Returns:   The buffer with the dumped certificate in\n\
+@param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)\n\
+@param cert: The certificate to dump\n\
+@return: The buffer with the dumped certificate in\n\
 ";
 
 static PyObject *
@@ -322,7 +316,7 @@
     if (ret == 0)
     {
         BIO_free(bio);
-        exception_from_error_queue();
+        exception_from_error_queue(crypto_Error);
         return NULL;
     }
 
@@ -336,11 +330,9 @@
 static char crypto_load_certificate_request_doc[] = "\n\
 Load a certificate request from a buffer\n\
 \n\
-Arguments: spam - Always NULL\n\
-           args - The Python argument tuple, should be:\n\
-             type   - The file type (one of FILETYPE_PEM, FILETYPE_ASN1)\n\
+@param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)\n\
              buffer - The buffer the certificate request is stored in\n\
-Returns:   The X509Req object\n\
+@return: The X509Req object\n\
 ";
 
 static PyObject *
@@ -375,7 +367,7 @@
 
     if (req == NULL)
     {
-        exception_from_error_queue();
+        exception_from_error_queue(crypto_Error);
         return NULL;
     }
 
@@ -385,11 +377,9 @@
 static char crypto_dump_certificate_request_doc[] = "\n\
 Dump a certificate request to a buffer\n\
 \n\
-Arguments: spam - Always NULL\n\
-           args - The Python argument tuple, should be:\n\
-             type - The file type (one of FILETYPE_PEM, FILETYPE_ASN1)\n\
+@param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1)\n\
              req  - The certificate request to dump\n\
-Returns:   The buffer with the dumped certificate request in\n\
+@return: The buffer with the dumped certificate request in\n\
 ";
 
 static PyObject *
@@ -429,7 +419,7 @@
     if (ret == 0)
     {
         BIO_free(bio);
-        exception_from_error_queue();
+        exception_from_error_queue(crypto_Error);
         return NULL;
     }
 
@@ -443,11 +433,9 @@
 static char crypto_load_pkcs7_data_doc[] = "\n\
 Load pkcs7 data from a buffer\n\
 \n\
-Arguments: spam - Always NULL\n\
-           args - The argument tuple, should be:\n\
-             type - The file type (one of FILETYPE_PEM or FILETYPE_ASN1)\n\
+@param type: The file type (one of FILETYPE_PEM or FILETYPE_ASN1)\n\
              buffer - The buffer with the pkcs7 data.\n\
-Returns: The PKCS7 object\n\
+@return: The PKCS7 object\n\
 ";
 
 static PyObject *
@@ -487,7 +475,7 @@
      */
     if (pkcs7 == NULL)
     {
-        exception_from_error_queue();
+        exception_from_error_queue(crypto_Error);
         return NULL;
     }
 
@@ -497,11 +485,9 @@
 static char crypto_load_pkcs12_doc[] = "\n\
 Load a PKCS12 object from a buffer\n\
 \n\
-Arguments: spam - Always NULL\n\
-           args - The Python argument tuple, should be:\n\
-             buffer - The buffer the certificate is stored in\n\
-             passphrase (Optional) - The password to decrypt the PKCS12 lump\n\
-Returns:   The PKCS12 object\n\
+@param buffer: The buffer the certificate is stored in\n\
+               passphrase (Optional) - The password to decrypt the PKCS12 lump\n\
+@returns: The PKCS12 object\n\
 ";
 
 static PyObject *
@@ -520,7 +506,7 @@
     if ((p12 = d2i_PKCS12_bio(bio, NULL)) == NULL)
     {
       BIO_free(bio);
-      exception_from_error_queue();
+      exception_from_error_queue(crypto_Error);
       return NULL;
     }
     BIO_free(bio);
@@ -529,149 +515,11 @@
 }
 
 
-static char crypto_X509_doc[] = "\n\
-The factory function inserted in the module dictionary to create X509\n\
-objects\n\
-\n\
-Arguments: spam - Always NULL\n\
-           args - The Python argument tuple, should be empty\n\
-Returns:   The X509 object\n\
-";
-
-static PyObject *
-crypto_X509(PyObject *spam, PyObject *args)
-{
-    if (!PyArg_ParseTuple(args, ":X509"))
-        return NULL;
-
-    return (PyObject *)crypto_X509_New(X509_new(), 1);
-}
-
-static char crypto_X509Name_doc[] = "\n\
-The factory function inserted in the module dictionary as a copy\n\
-constructor for X509Name objects.\n\
-\n\
-Arguments: spam - Always NULL\n\
-           args - The Python argument tuple, should be:\n\
-             name - An X509Name object to copy\n\
-Returns:   The X509Name object\n\
-";
-
-static PyObject *
-crypto_X509Name(PyObject *spam, PyObject *args)
-{
-    crypto_X509NameObj *name;
-
-    if (!PyArg_ParseTuple(args, "O!:X509Name", &crypto_X509Name_Type, &name))
-        return NULL;
-
-    return (PyObject *)crypto_X509Name_New(X509_NAME_dup(name->x509_name), 1);
-}
-
-static char crypto_X509Req_doc[] = "\n\
-The factory function inserted in the module dictionary to create X509Req\n\
-objects\n\
-\n\
-Arguments: spam - Always NULL\n\
-           args - The Python argument tuple, should be empty\n\
-Returns:   The X509Req object\n\
-";
-
-static PyObject *
-crypto_X509Req(PyObject *spam, PyObject *args)
-{
-    if (!PyArg_ParseTuple(args, ":X509Req"))
-        return NULL;
-
-    return (PyObject *)crypto_X509Req_New(X509_REQ_new(), 1);
-}
-
-static char crypto_PKey_doc[] = "\n\
-The factory function inserted in the module dictionary to create PKey\n\
-objects\n\
-\n\
-Arguments: spam - Always NULL\n\
-           args - The Python argument tuple, should be empty\n\
-Returns:   The PKey object\n\
-";
-
-static PyObject *
-crypto_PKey(PyObject *spam, PyObject *args)
-{
-    crypto_PKeyObj *py_pkey;
-
-    if (!PyArg_ParseTuple(args, ":PKey"))
-        return NULL;
-
-    py_pkey = crypto_PKey_New(EVP_PKEY_new(), 1);
-    if (py_pkey) {
-	py_pkey->initialized = 0;
-    }
-    return (PyObject *)py_pkey;
-}
-
-static char crypto_X509Extension_doc[] = "\n\
-The factory function inserted in the module dictionary to create\n\
-X509Extension objects.\n\
-\n\
-Arguments: spam - Always NULL\n\
-           args - The Python argument tuple, should be\n\
-             typename - ???\n\
-             critical - ???\n\
-             value    - ???\n\
-Returns:   The X509Extension object\n\
-";
-
-static PyObject *
-crypto_X509Extension(PyObject *spam, PyObject *args)
-{
-    char *type_name, *value;
-    int critical;
-
-    if (!PyArg_ParseTuple(args, "sis:X509Extension", &type_name, &critical,
-                &value))
-        return NULL;
-
-    return (PyObject *)crypto_X509Extension_New(type_name, critical, value);
-}
-
-static char crypto_NetscapeSPKI_doc[] = "\n\
-The factory function inserted in the module dictionary to create NetscapeSPKI\n\
-objects\n\
-\n\
-Arguments: spam - Always NULL\n\
-           args - The Python argument tuple, should be empty or, optionally\n\
-             enc - Base64 encoded NetscapeSPKI object.\n\
-Returns:   The NetscapeSPKI object\n\
-";
-
-static PyObject *
-crypto_NetscapeSPKI(PyObject *spam, PyObject *args)
-{
-    char *enc = NULL;
-    int enc_len = -1;
-    NETSCAPE_SPKI *spki;
-
-    if (!PyArg_ParseTuple(args, "|s#:NetscapeSPKI", &enc, &enc_len))
-        return NULL;
-
-    if (enc_len >= 0)
-        spki = NETSCAPE_SPKI_b64_decode(enc, enc_len);
-    else
-        spki = NETSCAPE_SPKI_new();
-    if (spki == NULL)
-    {
-        exception_from_error_queue();
-        return NULL;
-    }
-    return (PyObject *)crypto_NetscapeSPKI_New(spki, 1);
-}
-
 static char crypto_X509_verify_cert_error_string_doc[] = "\n\
 Get X509 verify certificate error string.\n\
 \n\
-Arguments: errnum - Error number\n\
-Returns:   Error string as a Python string\n\
+@param errnum: The error number.\n\
+@return: Error string as a Python string\n\
 ";
 
 static PyObject *
@@ -687,6 +535,17 @@
     return PyString_FromString(str);
 }
 
+static char crypto_exception_from_error_queue_doc[] = "\n\
+Raise an exception from the current OpenSSL error queue.\n\
+";
+
+static PyObject *
+crypto_exception_from_error_queue(PyObject *spam, PyObject *eggs) {
+    exception_from_error_queue(crypto_Error);
+    return NULL;
+}
+
+
 /* Methods in the OpenSSL.crypto module (i.e. none) */
 static PyMethodDef crypto_methods[] = {
     /* Module functions */
@@ -698,14 +557,8 @@
     { "dump_certificate_request", (PyCFunction)crypto_dump_certificate_request, METH_VARARGS, crypto_dump_certificate_request_doc },
     { "load_pkcs7_data", (PyCFunction)crypto_load_pkcs7_data, METH_VARARGS, crypto_load_pkcs7_data_doc },
     { "load_pkcs12", (PyCFunction)crypto_load_pkcs12, METH_VARARGS, crypto_load_pkcs12_doc },
-    /* Factory functions */
-    { "X509",    (PyCFunction)crypto_X509,    METH_VARARGS, crypto_X509_doc },
-    { "X509Name",(PyCFunction)crypto_X509Name,METH_VARARGS, crypto_X509Name_doc },
-    { "X509Req", (PyCFunction)crypto_X509Req, METH_VARARGS, crypto_X509Req_doc },
-    { "PKey",    (PyCFunction)crypto_PKey,    METH_VARARGS, crypto_PKey_doc },
-    { "X509Extension", (PyCFunction)crypto_X509Extension, METH_VARARGS, crypto_X509Extension_doc },
-    { "NetscapeSPKI", (PyCFunction)crypto_NetscapeSPKI, METH_VARARGS, crypto_NetscapeSPKI_doc },
     { "X509_verify_cert_error_string", (PyCFunction)crypto_X509_verify_cert_error_string, METH_VARARGS, crypto_X509_verify_cert_error_string_doc },
+    { "_exception_from_error_queue", (PyCFunction)crypto_exception_from_error_queue, METH_NOARGS, crypto_exception_from_error_queue_doc },
     { NULL, NULL }
 };
 
@@ -787,7 +640,7 @@
 {
     static void *crypto_API[crypto_API_pointers];
     PyObject *c_api_object;
-    PyObject *module, *dict;
+    PyObject *module;
 
     ERR_load_crypto_strings();
     OpenSSL_add_all_algorithms();
@@ -821,31 +674,29 @@
     PyModule_AddIntConstant(module, "TYPE_RSA", crypto_TYPE_RSA);
     PyModule_AddIntConstant(module, "TYPE_DSA", crypto_TYPE_DSA);
 
-    dict = PyModule_GetDict(module);
 #ifdef WITH_THREAD
     if (!init_openssl_threads())
         goto error;
 #endif
-    if (!init_crypto_x509(dict))
+    if (!init_crypto_x509(module))
         goto error;
-    if (!init_crypto_x509name(dict))
+    if (!init_crypto_x509name(module))
         goto error;
-    if (!init_crypto_x509store(dict))
+    if (!init_crypto_x509store(module))
         goto error;
-    if (!init_crypto_x509req(dict))
+    if (!init_crypto_x509req(module))
         goto error;
-    if (!init_crypto_pkey(dict))
+    if (!init_crypto_pkey(module))
         goto error;
-    if (!init_crypto_x509extension(dict))
+    if (!init_crypto_x509extension(module))
         goto error;
-    if (!init_crypto_pkcs7(dict))
+    if (!init_crypto_pkcs7(module))
         goto error;
-    if (!init_crypto_pkcs12(dict))
+    if (!init_crypto_pkcs12(module))
         goto error;
-    if (!init_crypto_netscape_spki(dict))
+    if (!init_crypto_netscape_spki(module))
         goto error;
 
 error:
     ;
 }
-
diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h
index 2322720..b5e6b65 100644
--- a/src/crypto/crypto.h
+++ b/src/crypto/crypto.h
@@ -27,15 +27,6 @@
 
 extern PyObject *crypto_Error;
 
-#ifdef exception_from_error_queue
-#  undef exception_from_error_queue
-#endif
-#define exception_from_error_queue()    do { \
-    PyObject *errlist = error_queue_to_list(); \
-    PyErr_SetObject(crypto_Error, errlist); \
-    Py_DECREF(errlist); \
-} while (0)
-
 #define crypto_X509_New_NUM             0
 #define crypto_X509_New_RETURN          crypto_X509Obj *
 #define crypto_X509_New_PROTO           (X509 *, int)
@@ -58,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/netscape_spki.c b/src/crypto/netscape_spki.c
index e9f2553..4fa9d8d 100644
--- a/src/crypto/netscape_spki.c
+++ b/src/crypto/netscape_spki.c
@@ -33,6 +33,37 @@
     return self;
 }
 
+
+static char crypto_NetscapeSPKI_doc[] = "\n\
+NetscapeSPKI([enc]) -> NetscapeSPKI instance\n\
+\n\
+@param enc: Base64 encoded NetscapeSPKI object.\n\
+@type enc: C{str}\n\
+@return: The NetscapeSPKI object\n\
+";
+
+static PyObject *
+crypto_NetscapeSPKI_new(PyTypeObject *subtype, PyObject *args, PyObject *kwargs) {
+    char *enc = NULL;
+    int enc_len = -1;
+    NETSCAPE_SPKI *spki;
+
+    if (!PyArg_ParseTuple(args, "|s#:NetscapeSPKI", &enc, &enc_len))
+        return NULL;
+
+    if (enc_len >= 0)
+        spki = NETSCAPE_SPKI_b64_decode(enc, enc_len);
+    else
+        spki = NETSCAPE_SPKI_new();
+    if (spki == NULL)
+    {
+        exception_from_error_queue(crypto_Error);
+        return NULL;
+    }
+    return (PyObject *)crypto_NetscapeSPKI_New(spki, 1);
+}
+
+
 /*
  * Deallocate the memory used by the NetscapeSPKI object
  *
@@ -52,11 +83,9 @@
 static char crypto_NetscapeSPKI_sign_doc[] = "\n\
 Sign the certificate request using the supplied key and digest\n\
 \n\
-Arguments: self - The NetscapeSPKI object\n\
-           args - The Python argument tuple, should be:\n\
-             pkey   - The key to sign with\n\
-             digest - The message digest to use\n\
-Returns:   None\n\
+@param pkey: The key to sign with\n\
+@param digest: The message digest to use\n\
+@return: None\n\
 ";
 
 static PyObject *
@@ -78,7 +107,7 @@
 
     if (!NETSCAPE_SPKI_sign(self->netscape_spki, pkey->pkey, digest))
     {
-        exception_from_error_queue();
+        exception_from_error_queue(crypto_Error);
         return NULL;
     }
 
@@ -88,11 +117,9 @@
 
 static char crypto_NetscapeSPKI_verify_doc[] = "\n\
 Verifies a certificate request using the supplied public key\n\
- \n\
-Arguments: self - NetscapeSPKI object\n\
-           args - The Python argument tuple, should be:\n\
-             key - a public key\n\
-Returns:   True, if the signature is correct, 0 otherwise.\n\
+\n\
+@param key: a public key\n\
+@return: True if the signature is correct, False otherwise.\n\
 ";
 
 PyObject *
@@ -106,7 +133,7 @@
 
     if ((answer = NETSCAPE_SPKI_verify(self->netscape_spki, pkey->pkey)) < 0)
     {
-        exception_from_error_queue();
+        exception_from_error_queue(crypto_Error);
         return NULL;
     }
 
@@ -115,10 +142,8 @@
 
 static char crypto_NetscapeSPKI_b64_encode_doc[] = "\n\
 Generate a base64 encoded string from an SPKI\n\
- \n\
-Arguments: self - NetscapeSPKI object\n\
-           args - The Python argument tuple, should be empty\n\
-Returns:   The base64 encoded string\n\
+\n\
+@return: The base64 encoded string\n\
 ";
 
 PyObject *
@@ -137,9 +162,7 @@
 static char crypto_NetscapeSPKI_get_pubkey_doc[] = "\n\
 Get the public key of the certificate\n\
 \n\
-Arguments: self - The NETSCAPE_SPKI object\n\
-           args - The Python argument tuple, should be empty\n\
-Returns:   The public key\n\
+@return: The public key\n\
 ";
 
 static PyObject *
@@ -153,7 +176,7 @@
 
     if ((pkey = NETSCAPE_SPKI_get_pubkey(self->netscape_spki)) == NULL)
     {
-        exception_from_error_queue();
+        exception_from_error_queue(crypto_Error);
         return NULL;
     }
 
@@ -163,10 +186,8 @@
 static char crypto_NetscapeSPKI_set_pubkey_doc[] = "\n\
 Set the public key of the certificate\n\
 \n\
-Arguments: self - The Netscape SPKI object\n\
-           args - The Python argument tuple, should be:\n\
-             pkey - The public key\n\
-Returns:   None\n\
+@param pkey: The public key\n\
+@return: None\n\
 ";
 
 static PyObject *
@@ -179,7 +200,7 @@
 
     if (!NETSCAPE_SPKI_set_pubkey(self->netscape_spki, pkey->pkey))
     {
-        exception_from_error_queue();
+        exception_from_error_queue(crypto_Error);
         return NULL;
     }
 
@@ -234,21 +255,53 @@
     NULL, /* as_number */
     NULL, /* as_sequence */
     NULL, /* as_mapping */
-    NULL  /* hash */
+    NULL,  /* hash */
+    NULL, /* call */
+    NULL, /* str */
+    NULL, /* getattro */
+    NULL, /* setattro */
+    NULL, /* as_buffer */
+    Py_TPFLAGS_DEFAULT,
+    crypto_NetscapeSPKI_doc, /* doc */
+    NULL, /* traverse */
+    NULL, /* clear */
+    NULL, /* tp_richcompare */
+    0, /* tp_weaklistoffset */
+    NULL, /* tp_iter */
+    NULL, /* tp_iternext */
+    crypto_NetscapeSPKI_methods, /* tp_methods */
+    NULL, /* tp_members */
+    NULL, /* tp_getset */
+    NULL, /* tp_base */
+    NULL, /* tp_dict */
+    NULL, /* tp_descr_get */
+    NULL, /* tp_descr_set */
+    0, /* tp_dictoffset */
+    NULL, /* tp_init */
+    NULL, /* tp_alloc */
+    crypto_NetscapeSPKI_new, /* tp_new */
 };
 
 
 /*
  * Initialize the X509Name part of the crypto module
  *
- * Arguments: dict - The crypto module dictionary
+ * Arguments: module - The crypto module
  * Returns:   None
  */
 int
-init_crypto_netscape_spki(PyObject *dict)
-{
-    crypto_NetscapeSPKI_Type.ob_type = &PyType_Type;
-    Py_INCREF(&crypto_NetscapeSPKI_Type);
-    PyDict_SetItemString(dict, "NetscapeSPKIType", (PyObject *)&crypto_NetscapeSPKI_Type);
+init_crypto_netscape_spki(PyObject *module) {
+    if (PyType_Ready(&crypto_NetscapeSPKI_Type) < 0) {
+        return 0;
+    }
+
+    if (PyModule_AddObject(module, "NetscapeSPKI", (PyObject *)&crypto_NetscapeSPKI_Type) != 0) {
+        return 0;
+    }
+
+    if (PyModule_AddObject(module, "NetscapeSPKIType", (PyObject *)&crypto_NetscapeSPKI_Type) != 0) {
+        return 0;
+    }
+
     return 1;
 }
diff --git a/src/crypto/pkcs12.c b/src/crypto/pkcs12.c
index adbd0dc..28ea2fe 100644
--- a/src/crypto/pkcs12.c
+++ b/src/crypto/pkcs12.c
@@ -24,9 +24,7 @@
 static char crypto_PKCS12_get_certificate_doc[] = "\n\
 Return certificate portion of the PKCS12 structure\n\
 \n\
-Arguments: self - The PKCS12 object\n\
-           args - The Python argument tuple, should be empty\n\
-Returns:   X509 object containing the certificate\n\
+@return: X509 object containing the certificate\n\
 ";
 static PyObject *
 crypto_PKCS12_get_certificate(crypto_PKCS12Obj *self, PyObject *args)
@@ -41,9 +39,7 @@
 static char crypto_PKCS12_get_privatekey_doc[] = "\n\
 Return private key portion of the PKCS12 structure\n\
 \n\
-Arguments: self - The PKCS12 object\n\
-           args - The Python argument tuple, should be empty\n\
-Returns:   PKey object containing the private key\n\
+@returns: PKey object containing the private key\n\
 ";
 static PyObject *
 crypto_PKCS12_get_privatekey(crypto_PKCS12Obj *self, PyObject *args)
@@ -58,10 +54,8 @@
 static char crypto_PKCS12_get_ca_certificates_doc[] = "\n\
 Return CA certificates within of the PKCS12 object\n\
 \n\
-Arguments: self - The PKCS12 object\n\
-           args - The Python argument tuple, should be empty\n\
-Returns:   A newly created tuple containing the CA certificates in the chain,\n\
-           if any are present, or None if no CA certificates are present.\n\
+@return: A newly created tuple containing the CA certificates in the chain,\n\
+         if any are present, or None if no CA certificates are present.\n\
 ";
 static PyObject *
 crypto_PKCS12_get_ca_certificates(crypto_PKCS12Obj *self, PyObject *args)
@@ -116,7 +110,7 @@
     /* parse the PKCS12 lump */
     if (!(cacerts && PKCS12_parse(p12, passphrase, &pkey, &cert, &cacerts)))
     {
-        exception_from_error_queue();
+        exception_from_error_queue(crypto_Error);
         return NULL;
     }
 
@@ -259,15 +253,19 @@
 /*
  * Initialize the PKCS12 part of the crypto sub module
  *
- * Arguments: dict - The crypto module dictionary
+ * Arguments: module - The crypto module
  * Returns:   None
  */
 int
-init_crypto_pkcs12(PyObject *dict)
-{
-    crypto_PKCS12_Type.ob_type = &PyType_Type;
-    Py_INCREF(&crypto_PKCS12_Type);
-    PyDict_SetItemString(dict, "PKCS12Type", (PyObject *)&crypto_PKCS12_Type);
+init_crypto_pkcs12(PyObject *module) {
+    if (PyType_Ready(&crypto_PKCS12_Type) < 0) {
+        return 0;
+    }
+
+    if (PyModule_AddObject(module, "PKCS12Type", (PyObject *)&crypto_PKCS12_Type) != 0) {
+        return 0;
+    }
+
     return 1;
 }
 
diff --git a/src/crypto/pkcs7.c b/src/crypto/pkcs7.c
index 4a2c066..1cb0813 100644
--- a/src/crypto/pkcs7.c
+++ b/src/crypto/pkcs7.c
@@ -14,9 +14,7 @@
 static char crypto_PKCS7_type_is_signed_doc[] = "\n\
 Check if this NID_pkcs7_signed object\n\
 \n\
-Arguments: self - The PKCS7 object\n\
-           args - An empty argument tuple\n\
-Returns:   True if the PKCS7 is of type signed\n\
+@return: True if the PKCS7 is of type signed\n\
 ";
 
 static PyObject *
@@ -34,9 +32,7 @@
 static char crypto_PKCS7_type_is_enveloped_doc[] = "\n\
 Check if this NID_pkcs7_enveloped object\n\
 \n\
-Arguments: self - The PKCS7 object\n\
-           args - An empty argument tuple\n\
-Returns:   True if the PKCS7 is of type enveloped\n\
+@returns: True if the PKCS7 is of type enveloped\n\
 ";
 
 static PyObject *
@@ -54,9 +50,7 @@
 static char crypto_PKCS7_type_is_signedAndEnveloped_doc[] = "\n\
 Check if this NID_pkcs7_signedAndEnveloped object\n\
 \n\
-Arguments: self - The PKCS7 object\n\
-           args - An empty argument tuple\n\
-Returns:   True if the PKCS7 is of type signedAndEnveloped\n\
+@returns: True if the PKCS7 is of type signedAndEnveloped\n\
 ";
 
 static PyObject *
@@ -74,9 +68,7 @@
 static char crypto_PKCS7_type_is_data_doc[] = "\n\
 Check if this NID_pkcs7_data object\n\
 \n\
-Arguments: self - The PKCS7 object\n\
-           args - An empty argument tuple\n\
-Returns:   True if the PKCS7 is of type data\n\
+@return: True if the PKCS7 is of type data\n\
 ";
 
 static PyObject *
@@ -94,9 +86,7 @@
 static char crypto_PKCS7_get_type_name_doc[] = "\n\
 Returns the type name of the PKCS7 structure\n\
 \n\
-Arguments: self - The PKCS7 object\n\
-           args - An empty argument tuple\n\
-Returns:   A string with the typename\n\
+@return: A string with the typename\n\
 ";
 
 static PyObject *
@@ -207,15 +197,19 @@
 /*
  * Initialize the PKCS7 part of the crypto sub module
  *
- * Arguments: dict - The crypto module dictionary
+ * Arguments: module - The crypto module
  * Returns:   None
  */
 int
-init_crypto_pkcs7(PyObject *dict)
-{
-    crypto_PKCS7_Type.ob_type = &PyType_Type;
-    Py_INCREF(&crypto_PKCS7_Type);
-    PyDict_SetItemString(dict, "PKCS7Type", (PyObject *)&crypto_PKCS7_Type);
+init_crypto_pkcs7(PyObject *module) {
+    if (PyType_Ready(&crypto_PKCS7_Type) < 0) {
+        return 0;
+    }
+
+    if (PyModule_AddObject(module, "PKCS7Type", (PyObject *)&crypto_PKCS7_Type) != 0) {
+        return 0;
+    }
+
     return 1;
 }
 
diff --git a/src/crypto/pkey.c b/src/crypto/pkey.c
index fee3e81..583a2a1 100644
--- a/src/crypto/pkey.c
+++ b/src/crypto/pkey.c
@@ -21,7 +21,7 @@
  */
 #define FAIL() \
 do {                                    \
-    exception_from_error_queue();       \
+    exception_from_error_queue(crypto_Error); \
     return NULL;                        \
 } while (0)
     
@@ -29,11 +29,9 @@
 static char crypto_PKey_generate_key_doc[] = "\n\
 Generate a key of a given type, with a given number of a bits\n\
 \n\
-Arguments: self - The PKey object\n\
-           args - The Python argument tuple, should be:\n\
-             type - The key type (TYPE_RSA or TYPE_DSA)\n\
-             bits - The number of bits\n\
-Returns:   None\n\
+@param type: The key type (TYPE_RSA or TYPE_DSA)\n\
+@param bits: The number of bits\n\
+@return: None\n\
 ";
 
 static PyObject *
@@ -81,9 +79,7 @@
 static char crypto_PKey_bits_doc[] = "\n\
 Returns the number of bits of the key\n\
 \n\
-Arguments: self - The PKey object\n\
-           args - The Python argument tuple, should be empty\n\
-Returns: The number of bits of the key.\n\
+@return: The number of bits of the key.\n\
 ";
 
 static PyObject *
@@ -98,9 +94,7 @@
 static char crypto_PKey_type_doc[] = "\n\
 Returns the type of the key\n\
 \n\
-Arguments: self - The PKey object\n\
-           args - The Python argument tuple, should be empty\n\
-Returns: The type of the key.\n\
+@return: The type of the key.\n\
 ";
 
 static PyObject *
@@ -162,6 +156,30 @@
     return self;
 }
 
+static char crypto_PKey_doc[] = "\n\
+PKey() -> PKey instance\n\
+\n\
+Create a new PKey object.\n\
+\n\
+@return: The PKey object\n\
+";
+static PyObject*
+crypto_PKey_new(PyTypeObject *subtype, PyObject *args, PyObject *kwargs) {
+    crypto_PKeyObj *self;
+
+    if (!PyArg_ParseTuple(args, ":PKey")) {
+        return NULL;
+    }
+
+    self = crypto_PKey_New(EVP_PKEY_new(), 1);
+    if (self) {
+	self->initialized = 0;
+    }
+
+    return (PyObject *)self;
+}
+
+
 /*
  * Deallocate the memory used by the PKey object
  *
@@ -195,7 +213,7 @@
 PyTypeObject crypto_PKey_Type = {
     PyObject_HEAD_INIT(NULL)
     0,
-    "PKey",
+    "OpenSSL.crypto.PKey",
     sizeof(crypto_PKeyObj),
     0,
     (destructor)crypto_PKey_dealloc,
@@ -208,21 +226,54 @@
     NULL, /* as_sequence */
     NULL, /* as_mapping */
     NULL, /* hash */
+    NULL, /* call */
+    NULL, /* str */
+    NULL, /* getattro */
+    NULL, /* setattro */
+    NULL, /* as_buffer */
+    Py_TPFLAGS_DEFAULT,
+    crypto_PKey_doc, /* doc */
+    NULL, /* traverse */
+    NULL, /* clear */
+    NULL, /* tp_richcompare */
+    0, /* tp_weaklistoffset */
+    NULL, /* tp_iter */
+    NULL, /* tp_iternext */
+    crypto_PKey_methods, /* tp_methods */
+    NULL, /* tp_members */
+    NULL, /* tp_getset */
+    NULL, /* tp_base */
+    NULL, /* tp_dict */
+    NULL, /* tp_descr_get */
+    NULL, /* tp_descr_set */
+    0, /* tp_dictoffset */
+    NULL, /* tp_init */
+    NULL, /* tp_alloc */
+    crypto_PKey_new, /* tp_new */
 };
 
 
 /*
  * Initialize the PKey part of the crypto sub module
  *
- * Arguments: dict - The crypto module dictionary
+ * Arguments: module - The crypto module
  * Returns:   None
  */
 int
-init_crypto_pkey(PyObject *dict)
+init_crypto_pkey(PyObject *module)
 {
-    crypto_PKey_Type.ob_type = &PyType_Type;
-    Py_INCREF(&crypto_PKey_Type);
-    PyDict_SetItemString(dict, "PKeyType", (PyObject *)&crypto_PKey_Type);
+    if (PyType_Ready(&crypto_PKey_Type) < 0) {
+        return 0;
+    }
+
+    if (PyModule_AddObject(module, "PKey", (PyObject *)&crypto_PKey_Type) != 0) {
+        return 0;
+    }
+
+    if (PyModule_AddObject(module, "PKeyType", (PyObject *)&crypto_PKey_Type) != 0) {
+        return 0;
+    }
+
     return 1;
 }
 
diff --git a/src/crypto/x509.c b/src/crypto/x509.c
index 90a213b..e089d40 100644
--- a/src/crypto/x509.c
+++ b/src/crypto/x509.c
@@ -21,9 +21,7 @@
 static char crypto_X509_get_version_doc[] = "\n\
 Return version number of the certificate\n\
 \n\
-Arguments: self - The X509 object\n\
-           args - The Python argument tuple, should be empty\n\
-Returns:   Version number as a Python integer\n\
+@return: Version number as a Python integer\n\
 ";
 
 static PyObject *
@@ -38,10 +36,8 @@
 static char crypto_X509_set_version_doc[] = "\n\
 Set version number of the certificate\n\
 \n\
-Arguments: self - The X509 object\n\
-           args - The Python argument tuple, should be:\n\
-             version - The version number\n\
-Returns:   None\n\
+@param version: The version number\n\
+@return: None\n\
 ";
 
 static PyObject *
@@ -61,9 +57,7 @@
 static char crypto_X509_get_serial_number_doc[] = "\n\
 Return serial number of the certificate\n\
 \n\
-Arguments: self - The X509 object\n\
-           args - The Python argument tuple, should be empty\n\
-Returns:   Serial number as a Python integer\n\
+@return: Serial number as a Python integer\n\
 ";
 
 static PyObject *
@@ -89,10 +83,8 @@
 static char crypto_X509_set_serial_number_doc[] = "\n\
 Set serial number of the certificate\n\
 \n\
-Arguments: self - The X509 object\n\
-           args - The Python argument tuple, should be:\n\
-             serial - The serial number\n\
-Returns:   None\n\
+@param serial: The serial number\n\
+@return: None\n\
 ";
 
 static PyObject *
@@ -144,7 +136,7 @@
 
     if (bignum == NULL) {
         if (ASN1_INTEGER_set(X509_get_serialNumber(self->x509), small_serial)) {
-            exception_from_error_queue();
+            exception_from_error_queue(crypto_Error);
             goto err;
         }
     } else {
@@ -152,11 +144,11 @@
         BN_free(bignum);
         bignum = NULL;
         if (asn1_i == NULL) {
-            exception_from_error_queue();
+            exception_from_error_queue(crypto_Error);
             goto err;
         }
         if (!X509_set_serialNumber(self->x509, asn1_i)) {
-            exception_from_error_queue();
+            exception_from_error_queue(crypto_Error);
             goto err;
         }
         ASN1_INTEGER_free(asn1_i);
@@ -188,9 +180,7 @@
 static char crypto_X509_get_issuer_doc[] = "\n\
 Create an X509Name object for the issuer of the certificate\n\
 \n\
-Arguments: self - The X509 object\n\
-           args - The Python argument tuple, should be empty\n\
-Returns:   An X509Name object\n\
+@return: An X509Name object\n\
 ";
 
 static PyObject *
@@ -215,10 +205,9 @@
 static char crypto_X509_set_issuer_doc[] = "\n\
 Set the issuer of the certificate\n\
 \n\
-Arguments: self - The X509 object\n\
-           args - The Python argument tuple, should be:\n\
-             issuer - The issuer name\n\
-Returns:   None\n\
+@param issuer: The issuer name\n\
+@type issuer: L{X509Name}\n\
+@return: None\n\
 ";
 
 static PyObject *
@@ -232,7 +221,7 @@
 
     if (!X509_set_issuer_name(self->x509, issuer->x509_name))
     {
-        exception_from_error_queue();
+        exception_from_error_queue(crypto_Error);
         return NULL;
     }
 
@@ -243,9 +232,7 @@
 static char crypto_X509_get_subject_doc[] = "\n\
 Create an X509Name object for the subject of the certificate\n\
 \n\
-Arguments: self - The X509 object\n\
-           args - The Python argument tuple, should be empty\n\
-Returns:   An X509Name object\n\
+@return: An X509Name object\n\
 ";
 
 static PyObject *
@@ -270,10 +257,9 @@
 static char crypto_X509_set_subject_doc[] = "\n\
 Set the subject of the certificate\n\
 \n\
-Arguments: self - The X509 object\n\
-           args - The Python argument tuple, should be:\n\
-             subject - The subject name\n\
-Returns:   None\n\
+@param subject: The subject name\n\
+@type subject: L{X509Name}\n\
+@return: None\n\
 ";
 
 static PyObject *
@@ -287,7 +273,7 @@
 
     if (!X509_set_subject_name(self->x509, subject->x509_name))
     {
-        exception_from_error_queue();
+        exception_from_error_queue(crypto_Error);
         return NULL;
     }
 
@@ -298,9 +284,7 @@
 static char crypto_X509_get_pubkey_doc[] = "\n\
 Get the public key of the certificate\n\
 \n\
-Arguments: self - The X509 object\n\
-           args - The Python argument tuple, should be empty\n\
-Returns:   The public key\n\
+@return: The public key\n\
 ";
 
 static PyObject *
@@ -315,7 +299,7 @@
 
     if ((pkey = X509_get_pubkey(self->x509)) == NULL)
     {
-        exception_from_error_queue();
+        exception_from_error_queue(crypto_Error);
         return NULL;
     }
 
@@ -329,10 +313,8 @@
 static char crypto_X509_set_pubkey_doc[] = "\n\
 Set the public key of the certificate\n\
 \n\
-Arguments: self - The X509 object\n\
-           args - The Python argument tuple, should be:\n\
-             pkey - The public key\n\
-Returns:   None\n\
+@param pkey: The public key\n\
+@return: None\n\
 ";
 
 static PyObject *
@@ -345,7 +327,7 @@
 
     if (!X509_set_pubkey(self->x509, pkey->pkey))
     {
-        exception_from_error_queue();
+        exception_from_error_queue(crypto_Error);
         return NULL;
     }
 
@@ -380,15 +362,13 @@
 static char crypto_X509_set_notBefore_doc[] = "\n\
 Set the time stamp for when the certificate starts being valid\n\
 \n\
-Arguments: self - The X509 object\n\
-           args - The Python argument tuple, should be:\n\
-             when - A string giving the timestamp, in the format:\n\
+@param when: A string giving the timestamp, in the format:\n\
 \n\
                  YYYYMMDDhhmmssZ\n\
                  YYYYMMDDhhmmss+hhmm\n\
                  YYYYMMDDhhmmss-hhmm\n\
 \n\
-Returns:   None\n\
+@return: None\n\
 ";
 
 static PyObject*
@@ -401,15 +381,13 @@
 static char crypto_X509_set_notAfter_doc[] = "\n\
 Set the time stamp for when the certificate stops being valid\n\
 \n\
-Arguments: self - The X509 object\n\
-           args - The Python argument tuple, should be:\n\
-             when - A string giving the timestamp, in the format:\n\
+@param when: A string giving the timestamp, in the format:\n\
 \n\
                  YYYYMMDDhhmmssZ\n\
                  YYYYMMDDhhmmss+hhmm\n\
                  YYYYMMDDhhmmss-hhmm\n\
 \n\
-Returns:   None\n\
+@return: None\n\
 ";
 
 static PyObject*
@@ -444,7 +422,7 @@
 	} else {
 		ASN1_TIME_to_generalizedtime(timestamp, &gt_timestamp);
 		if (gt_timestamp == NULL) {
-			exception_from_error_queue();
+			exception_from_error_queue(crypto_Error);
 			return NULL;
 		} else {
 			py_timestamp = PyString_FromString((char *)gt_timestamp->data);
@@ -457,10 +435,7 @@
 static char crypto_X509_get_notBefore_doc[] = "\n\
 Retrieve the time stamp for when the certificate starts being valid\n\
 \n\
-Arguments: self - The X509 object\n\
-           args - The Python argument tuple, should be empty.\n\
-\n\
-Returns:   A string giving the timestamp, in the format:\n\
+@return: A string giving the timestamp, in the format:\n\
 \n\
                  YYYYMMDDhhmmssZ\n\
                  YYYYMMDDhhmmss+hhmm\n\
@@ -482,10 +457,7 @@
 static char crypto_X509_get_notAfter_doc[] = "\n\
 Retrieve the time stamp for when the certificate stops being valid\n\
 \n\
-Arguments: self - The X509 object\n\
-           args - The Python argument tuple, should be empty.\n\
-\n\
-Returns:   A string giving the timestamp, in the format:\n\
+@return: A string giving the timestamp, in the format:\n\
 \n\
                  YYYYMMDDhhmmssZ\n\
                  YYYYMMDDhhmmss+hhmm\n\
@@ -508,21 +480,20 @@
 Change the timestamp for when the certificate starts being valid to the current\n\
 time plus an offset.\n \
 \n\
-Arguments: self - The X509 object\n\
-           args - The Python argument tuple, should be:\n\
-             i - The adjustment\n\
-Returns:   None\n\
+@param amount: The number of seconds by which to adjust the starting validity\n\
+               time.\n\
+@return: None\n\
 ";
 
 static PyObject *
 crypto_X509_gmtime_adj_notBefore(crypto_X509Obj *self, PyObject *args)
 {
-    long i;
+    long amount;
 
-    if (!PyArg_ParseTuple(args, "l:gmtime_adj_notBefore", &i))
+    if (!PyArg_ParseTuple(args, "l:gmtime_adj_notBefore", &amount))
         return NULL;
 
-    X509_gmtime_adj(X509_get_notBefore(self->x509), i);
+    X509_gmtime_adj(X509_get_notBefore(self->x509), amount);
 
     Py_INCREF(Py_None);
     return Py_None;
@@ -531,21 +502,20 @@
 static char crypto_X509_gmtime_adj_notAfter_doc[] = "\n\
 Adjust the time stamp for when the certificate stops being valid\n\
 \n\
-Arguments: self - The X509 object\n\
-           args - The Python argument tuple, should be:\n\
-             i - The adjustment\n\
-Returns:   None\n\
+@param amount: The number of seconds by which to adjust the ending validity\n\
+               time.\n\
+@return: None\n\
 ";
 
 static PyObject *
 crypto_X509_gmtime_adj_notAfter(crypto_X509Obj *self, PyObject *args)
 {
-    long i;
+    long amount;
 
-    if (!PyArg_ParseTuple(args, "l:gmtime_adj_notAfter", &i))
+    if (!PyArg_ParseTuple(args, "l:gmtime_adj_notAfter", &amount))
         return NULL;
 
-    X509_gmtime_adj(X509_get_notAfter(self->x509), i);
+    X509_gmtime_adj(X509_get_notAfter(self->x509), amount);
 
     Py_INCREF(Py_None);
     return Py_None;
@@ -554,11 +524,9 @@
 static char crypto_X509_sign_doc[] = "\n\
 Sign the certificate using the supplied key and digest\n\
 \n\
-Arguments: self - The X509 object\n\
-           args - The Python argument tuple, should be:\n\
-             pkey   - The key to sign with\n\
-             digest - The message digest to use\n\
-Returns:   None\n\
+@param pkey: The key to sign with\n\
+@param digest: The message digest to use\n\
+@return: None\n\
 ";
 
 static PyObject *
@@ -590,7 +558,7 @@
 
     if (!X509_sign(self->x509, pkey->pkey, digest))
     {
-        exception_from_error_queue();
+        exception_from_error_queue(crypto_Error);
         return NULL;
     }
 
@@ -601,9 +569,7 @@
 static char crypto_X509_has_expired_doc[] = "\n\
 Check whether the certificate has expired.\n\
 \n\
-Arguments: self - The X509 object\n\
-           args - The Python argument tuple, should be empty\n\
-Returns:   True if the certificate has expired, false otherwise\n\
+@return: True if the certificate has expired, false otherwise\n\
 ";
 
 static PyObject *
@@ -624,9 +590,7 @@
 static char crypto_X509_subject_name_hash_doc[] = "\n\
 Return the hash of the X509 subject.\n\
 \n\
-Arguments: self - The X509 object\n\
-           args - The Python argument tuple, should be empty\n\
-Returns:   The hash of the subject\n\
+@return: The hash of the subject\n\
 ";
 
 static PyObject *
@@ -641,9 +605,7 @@
 static char crypto_X509_digest_doc[] = "\n\
 Return the digest of the X509 object.\n\
 \n\
-Arguments: self - The X509 object\n\
-           args - The Python argument tuple, should be empty\n\
-Returns:   The digest of the object\n\
+@return: The digest of the object\n\
 ";
 
 static PyObject *
@@ -667,7 +629,7 @@
 
     if (!X509_digest(self->x509,digest,fp,&len))
     {
-        exception_from_error_queue();
+        exception_from_error_queue(crypto_Error);
     }
     tmp = malloc(3*len+1);
     memset(tmp, 0, 3*len+1);
@@ -684,10 +646,8 @@
 static char crypto_X509_add_extensions_doc[] = "\n\
 Add extensions to the certificate.\n\
 \n\
-Arguments: self - X509 object\n\
-           args - The Python argument tuple, should be:\n\
-             extensions - a sequence of X509Extension objects\n\
-Returns:   None\n\
+@param extensions: a sequence of X509Extension objects\n\
+@return: None\n\
 ";
 
 static PyObject *
@@ -719,7 +679,7 @@
         if (!X509_add_ext(self->x509, ext->x509_extension, -1))
         {
             Py_DECREF(seq);
-            exception_from_error_queue();
+            exception_from_error_queue(crypto_Error);
             return NULL;
         }
     }
@@ -787,6 +747,26 @@
     return self;
 }
 
+
+static char crypto_X509_doc[] = "\n\
+X509() -> X509 instance\n\
+\n\
+Create a new X509 object.\n\
+\n\
+@returns: The X509 object\n\
+";
+
+static PyObject *
+crypto_X509_new(PyTypeObject *subtype, PyObject *args, PyObject *kwargs)
+{
+    if (!PyArg_ParseTuple(args, ":X509")) {
+        return NULL;
+    }
+
+    return (PyObject *)crypto_X509_New(X509_new(), 1);
+}
+
+
 /*
  * Deallocate the memory used by the X509 object
  *
@@ -826,20 +806,60 @@
     (destructor)crypto_X509_dealloc,
     NULL, /* print */
     (getattrfunc)crypto_X509_getattr,
+    NULL, /* setattr */
+    NULL, /* compare */
+    NULL, /* repr */
+    NULL, /* as_number */
+    NULL, /* as_sequence */
+    NULL, /* as_mapping */
+    NULL, /* hash */
+    NULL, /* call */
+    NULL, /* str */
+    NULL, /* getattro */
+    NULL, /* setattro */
+    NULL, /* as_buffer */
+    Py_TPFLAGS_DEFAULT,
+    crypto_X509_doc, /* doc */
+    NULL, /* traverse */
+    NULL, /* clear */
+    NULL, /* tp_richcompare */
+    0, /* tp_weaklistoffset */
+    NULL, /* tp_iter */
+    NULL, /* tp_iternext */
+    crypto_X509_methods, /* tp_methods */
+    NULL, /* tp_members */
+    NULL, /* tp_getset */
+    NULL, /* tp_base */
+    NULL, /* tp_dict */
+    NULL, /* tp_descr_get */
+    NULL, /* tp_descr_set */
+    0, /* tp_dictoffset */
+    NULL, /* tp_init */
+    NULL, /* tp_alloc */
+    crypto_X509_new, /* tp_new */
 };
 
 /*
  * Initialize the X509 part of the crypto sub module
  *
- * Arguments: dict - The crypto module dictionary
+ * Arguments: module - The crypto module
  * Returns:   None
  */
 int
-init_crypto_x509(PyObject *dict)
+init_crypto_x509(PyObject *module)
 {
-    crypto_X509_Type.ob_type = &PyType_Type;
-    Py_INCREF(&crypto_X509_Type);
-    PyDict_SetItemString(dict, "X509Type", (PyObject *)&crypto_X509_Type);
+    if (PyType_Ready(&crypto_X509_Type) < 0) {
+        return 0;
+    }
+
+    if (PyModule_AddObject(module, "X509", (PyObject *)&crypto_X509_Type) != 0) {
+        return 0;
+    }
+
+    if (PyModule_AddObject(module, "X509Type", (PyObject *)&crypto_X509_Type) != 0) {
+        return 0;
+    }
+
     return 1;
 }
 
diff --git a/src/crypto/x509ext.c b/src/crypto/x509ext.c
index 3b3c814..90ef543 100644
--- a/src/crypto/x509ext.c
+++ b/src/crypto/x509ext.c
@@ -16,9 +16,7 @@
 static char crypto_X509Extension_get_critical_doc[] = "\n\
 Returns the critical field of the X509Extension\n\
 \n\
-Arguments: self - The X509Extension object\n\
-           args - The argument tuple, should be empty\n\
-Returns: The critical field.\n\
+@return: The critical field.\n\
 ";
 
 static PyObject *
@@ -33,9 +31,7 @@
 static char crypto_X509Extension_get_short_name_doc[] = "\n\
 Returns the short version of the type name of the X509Extension\n\
 \n\
-Arguments: self - The X509Extension object\n\
-           args - The argument tuple, should be empty\n\
-Returns: The short type name.\n\
+@return: The short type name.\n\
 ";
 
 static PyObject *
@@ -76,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) {
@@ -130,16 +150,53 @@
     return self;
 
   nconf_error:
-    exception_from_error_queue();
+    exception_from_error_queue(crypto_Error);
 
   critical_malloc_error:
-    PyObject_Free(self);
+    Py_XDECREF(self);
 
   error:
     return NULL;
 
 }
 
+static char crypto_X509Extension_doc[] = "\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) {
+    char *type_name, *value;
+    int critical = 0;
+    crypto_X509Obj * subject = NULL;
+    crypto_X509Obj * issuer = NULL;
+    static char *kwlist[] = {"type_name", "critical", "value", "subject",
+                             "issuer", NULL};
+
+    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,
+                                                subject, issuer);
+}
+
 /*
  * Deallocate the memory used by the X509Extension object
  *
@@ -184,7 +241,7 @@
     if (!X509V3_EXT_print(bio, self->x509_extension, 0, 0))
     {
         BIO_free(bio);
-        exception_from_error_queue();
+        exception_from_error_queue(crypto_Error);
         return NULL;
     }
 
@@ -213,22 +270,53 @@
     NULL, /* as_mapping */
     NULL, /* hash */
     NULL, /* call */
-    (reprfunc)crypto_X509Extension_str /* str */
+    (reprfunc)crypto_X509Extension_str, /* str */
+    NULL, /* getattro */
+    NULL, /* setattro */
+    NULL, /* as_buffer */
+    Py_TPFLAGS_DEFAULT,
+    crypto_X509Extension_doc, /* doc */
+    NULL, /* traverse */
+    NULL, /* clear */
+    NULL, /* tp_richcompare */
+    0, /* tp_weaklistoffset */
+    NULL, /* tp_iter */
+    NULL, /* tp_iternext */
+    crypto_X509Extension_methods, /* tp_methods */
+    NULL, /* tp_members */
+    NULL, /* tp_getset */
+    NULL, /* tp_base */
+    NULL, /* tp_dict */
+    NULL, /* tp_descr_get */
+    NULL, /* tp_descr_set */
+    0, /* tp_dictoffset */
+    NULL, /* tp_init */
+    NULL, /* tp_alloc */
+    crypto_X509Extension_new, /* tp_new */
 };
 
 /*
  * Initialize the X509Extension part of the crypto module
  *
- * Arguments: dict - The crypto module dictionary
+ * Arguments: dict - The crypto module
  * Returns:   None
  */
 int
-init_crypto_x509extension(PyObject *dict)
+init_crypto_x509extension(PyObject *module)
 {
-    crypto_X509Extension_Type.ob_type = &PyType_Type;
-    Py_INCREF(&crypto_X509Extension_Type);
-    PyDict_SetItemString(dict, "X509ExtensionType",
-            (PyObject *)&crypto_X509Extension_Type);
+    if (PyType_Ready(&crypto_X509Extension_Type) < 0) {
+        return 0;
+    }
+
+    if (PyModule_AddObject(module, "X509Extension",
+                           (PyObject *)&crypto_X509Extension_Type) != 0) {
+        return 0;
+    }
+
+    if (PyModule_AddObject(module, "X509ExtensionType",
+                           (PyObject *)&crypto_X509Extension_Type) != 0) {
+        return 0;
+    }
+
     return 1;
 }
-
diff --git a/src/crypto/x509name.c b/src/crypto/x509name.c
index 8871ab1..39fdcf8 100644
--- a/src/crypto/x509name.c
+++ b/src/crypto/x509name.c
@@ -2,7 +2,7 @@
  * x509name.c
  *
  * Copyright (C) AB Strakt 2001, All rights reserved
- * Copyright (C) Jean-Paul Calderone 2008, All rights reserved
+ * Copyright (C) Jean-Paul Calderone 2008-2009, All rights reserved
  *
  * X.509 Name handling, mostly thin wrapping.
  * See the file RATIONALE for a short explanation of why this module was written.
@@ -41,6 +41,29 @@
     return self;
 }
 
+
+static char crypto_X509Name_doc[] = "\n\
+X509Name(name) -> New X509Name object\n\
+\n\
+Create a new X509Name, copying the given X509Name instance.\n\
+\n\
+@param name: An X509Name object to copy\n\
+@return: The X509Name object\n\
+";
+
+static PyObject *
+crypto_X509Name_new(PyTypeObject *subtype, PyObject *args, PyObject *kwargs)
+{
+    crypto_X509NameObj *name;
+
+    if (!PyArg_ParseTuple(args, "O!:X509Name", &crypto_X509Name_Type, &name)) {
+        return NULL;
+    }
+
+    return (PyObject *)crypto_X509Name_New(X509_NAME_dup(name->x509_name), 1);
+}
+
+
 /*
  * Return a name string given a X509_NAME object and a name identifier. Used
  * by the getattr function.
@@ -65,7 +88,7 @@
     data = X509_NAME_ENTRY_get_data(entry);
     if ((len = ASN1_STRING_to_UTF8((unsigned char **)utf8string, data)) < 0)
     {
-        exception_from_error_queue();
+        exception_from_error_queue(crypto_Error);
         return -1;
     }
 
@@ -106,7 +129,7 @@
 				    (unsigned char *)utf8string,
 				    -1, -1, 0))
     {
-        exception_from_error_queue();
+        exception_from_error_queue(crypto_Error);
         return -1;
     }
     return 0;
@@ -130,8 +153,15 @@
     int nid, len;
     char *utf8string;
 
-    if ((nid = OBJ_txt2nid(name)) == NID_undef)
-    {
+    if ((nid = OBJ_txt2nid(name)) == NID_undef) {
+        /*
+         * This is a bit weird.  OBJ_txt2nid indicated failure, but it seems
+         * a lower level function, a2d_ASN1_OBJECT, also feels the need to
+         * push something onto the error queue.  If we don't clean that up
+         * now, someone else will bump into it later and be quite confused. 
+         * See lp#314814.
+         */
+        flush_error_queue();
         return Py_FindMethod(crypto_X509Name_methods, (PyObject *)self, name);
     }
 
@@ -213,7 +243,7 @@
 
     if (X509_NAME_oneline(self->x509_name, tmpbuf, 512) == NULL)
     {
-        exception_from_error_queue();
+        exception_from_error_queue(crypto_Error);
         return NULL;
     }
     else
@@ -225,11 +255,9 @@
 }
 
 static char crypto_X509Name_hash_doc[] = "\n\
-Return the has value of this name\n\
+Return the hash value of this name\n\
 \n\
-Arguments: self - The X509 object\n\
-           args - The Python argument tuple, should be empty\n\
-Returns:   None\n\
+@return: None\n\
 ";
 
 /*
@@ -251,11 +279,9 @@
 }
 
 static char crypto_X509Name_der_doc[] = "\n\
-Return the DER encodeing of this name\n\
+Return the DER encoding of this name\n\
 \n\
-Arguments: self - The X509 object\n\
-           args - The Python argument tuple, should be empty\n\
-Returns:   None\n\
+@return: None\n\
 ";
 
 /*
@@ -278,9 +304,7 @@
 static char crypto_X509Name_get_components_doc[] = "\n\
 Returns the split-up components of this name.\n\
 \n\
-Arguments: self - The X509 object\n\
-           args - The Python argument tuple, should be empty\n\
-Returns:   List of tuples (name, value).\n\
+@return: List of tuples (name, value).\n\
 ";
 
 static PyObject *
@@ -418,22 +442,46 @@
     NULL, /* setattro */
     NULL, /* as_buffer */
     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
-    NULL, /* tp_doc */
+    crypto_X509Name_doc, /* tp_doc */
     (traverseproc)crypto_X509Name_traverse, /* tp_traverse */
     (inquiry)crypto_X509Name_clear, /* tp_clear */
+    NULL, /* tp_richcompare */
+    0, /* tp_weaklistoffset */
+    NULL, /* tp_iter */
+    NULL, /* tp_iternext */
+    crypto_X509Name_methods, /* tp_methods */
+    NULL, /* tp_members */
+    NULL, /* tp_getset */
+    NULL, /* tp_base */
+    NULL, /* tp_dict */
+    NULL, /* tp_descr_get */
+    NULL, /* tp_descr_set */
+    0, /* tp_dictoffset */
+    NULL, /* tp_init */
+    NULL, /* tp_alloc */
+    crypto_X509Name_new, /* tp_new */
 };
 
 /*
  * Initialize the X509Name part of the crypto module
  *
- * Arguments: dict - The crypto module dictionary
+ * Arguments: module - The crypto module
  * Returns:   None
  */
 int
-init_crypto_x509name(PyObject *dict)
+init_crypto_x509name(PyObject *module)
 {
-    crypto_X509Name_Type.ob_type = &PyType_Type;
-    Py_INCREF(&crypto_X509Name_Type);
-    PyDict_SetItemString(dict, "X509NameType", (PyObject *)&crypto_X509Name_Type);
+    if (PyType_Ready(&crypto_X509Name_Type) < 0) {
+        return 0;
+    }
+
+    if (PyModule_AddObject(module, "X509Name", (PyObject *)&crypto_X509Name_Type) != 0) {
+        return 0;
+    }
+
+    if (PyModule_AddObject(module, "X509NameType", (PyObject *)&crypto_X509Name_Type) != 0) {
+        return 0;
+    }
+
     return 1;
 }
diff --git a/src/crypto/x509req.c b/src/crypto/x509req.c
index bb6385f..07bd44b 100644
--- a/src/crypto/x509req.c
+++ b/src/crypto/x509req.c
@@ -15,9 +15,7 @@
 static char crypto_X509Req_get_subject_doc[] = "\n\
 Create an X509Name object for the subject of the certificate request\n\
 \n\
-Arguments: self - The X509Req object\n\
-           args - The Python argument tuple, should be empty\n\
-Returns:   An X509Name object\n\
+@return: An X509Name object\n\
 ";
 
 static PyObject *
@@ -32,7 +30,7 @@
 
     if ((name = X509_REQ_get_subject_name(self->x509_req)) == NULL)
     {
-        exception_from_error_queue();
+        exception_from_error_queue(crypto_Error);
         return NULL;
     }
     if ((pyname = crypto_X509Name_New(name, 0)) != NULL) {
@@ -45,9 +43,7 @@
 static char crypto_X509Req_get_pubkey_doc[] = "\n\
 Get the public key from the certificate request\n\
 \n\
-Arguments: self - The X509Req object\n\
-           args - The Python argument tuple, should be empty\n\
-Returns:   The public key\n\
+@return: The public key\n\
 ";
 
 static PyObject *
@@ -62,7 +58,7 @@
 
     if ((pkey = X509_REQ_get_pubkey(self->x509_req)) == NULL)
     {
-        exception_from_error_queue();
+        exception_from_error_queue(crypto_Error);
         return NULL;
     }
 
@@ -76,10 +72,8 @@
 static char crypto_X509Req_set_pubkey_doc[] = "\n\
 Set the public key of the certificate request\n\
 \n\
-Arguments: self - The X509Req object\n\
-           args - The Python argument tuple, should be:\n\
-             pkey - The public key to use\n\
-Returns:   None\n\
+@param pkey: The public key to use\n\
+@return: None\n\
 ";
 
 static PyObject *
@@ -92,7 +86,7 @@
 
     if (!X509_REQ_set_pubkey(self->x509_req, pkey->pkey))
     {
-        exception_from_error_queue();
+        exception_from_error_queue(crypto_Error);
         return NULL;
     }
 
@@ -103,11 +97,9 @@
 static char crypto_X509Req_sign_doc[] = "\n\
 Sign the certificate request using the supplied key and digest\n\
 \n\
-Arguments: self - The X509Req object\n\
-           args - The Python argument tuple, should be:\n\
-             pkey   - The key to sign with\n\
-             digest - The message digest to use\n\
-Returns:   None\n\
+@param pkey: The key to sign with\n\
+@param digest: The message digest to use\n\
+@return: None\n\
 ";
 
 static PyObject *
@@ -139,7 +131,7 @@
 
     if (!X509_REQ_sign(self->x509_req, pkey->pkey, digest))
     {
-        exception_from_error_queue();
+        exception_from_error_queue(crypto_Error);
         return NULL;
     }
 
@@ -149,11 +141,9 @@
  
 static char crypto_X509Req_verify_doc[] = "\n\
 Verifies a certificate request using the supplied public key\n\
- \n\
-Arguments: self - X509Req object\n\
-           args - The Python argument tuple, should be:\n\
-             key - a public key\n\
-Returns:   True, if the signature is correct, 0 otherwise.\n\
+\n\
+@param key: a public key\n\
+@return: True if the signature is correct, False otherwise.\n\
 ";
 
 PyObject *
@@ -170,7 +160,7 @@
 
     if ((answer = X509_REQ_verify(self->x509_req, key->pkey)) < 0)
     {
-        exception_from_error_queue();
+        exception_from_error_queue(crypto_Error);
         return NULL;
     }
 
@@ -180,10 +170,8 @@
 static char crypto_X509Req_add_extensions_doc[] = "\n\
 Add extensions to the request.\n\
 \n\
-Arguments: self - X509Req object\n\
-           args - The Python argument tuple, should be:\n\
-             extensions - a sequence of X509Extension objects\n\
-Returns:   None\n\
+@param extensions: a sequence of X509Extension objects\n\
+@return: None\n\
 ";
 
 static PyObject *
@@ -206,7 +194,7 @@
     /* Make a STACK_OF(X509_EXTENSION) from sequence */
     if ((exts = sk_X509_EXTENSION_new_null()) == NULL)
     {
-        exception_from_error_queue();
+        exception_from_error_queue(crypto_Error);
         return NULL;
     }
 
@@ -229,7 +217,7 @@
     if (!X509_REQ_add_extensions(self->x509_req, exts))
     {
         sk_X509_EXTENSION_free(exts);
-        exception_from_error_queue();
+        exception_from_error_queue(crypto_Error);
         return NULL;
     }
 
@@ -243,10 +231,8 @@
 Set the version subfield (RFC 2459, section 4.1.2.1) of the certificate\n\
 request.\n\
 \n\
-Arguments: self - X509Req object\n\
-           args - The Python argument tuple, should be:\n\
-             version - The version number\n\
-Returns:   None\n\
+@param version: The version number\n\
+@return: None\n\
 ";
 
 static PyObject *
@@ -270,9 +256,7 @@
 Get the version subfield (RFC 2459, section 4.1.2.1) of the certificate\n\
 request.\n\
 \n\
-Arguments: self - X509Req object\n\
-           args - The Python argument tuple, should be empty.\n\
-Returns:   an integer giving the value of the version subfield\n\
+@return: an integer giving the value of the version subfield\n\
 ";
 
 static PyObject *
@@ -335,6 +319,25 @@
     return self;
 }
 
+
+static char crypto_X509Req_doc[] = "\n\
+X509Req() -> X509Req instance\n\
+\n\
+Create a new X509Req object.\n\
+\n\
+@return: The X509Req object\n\
+";
+
+static PyObject *
+crypto_X509Req_new(PyTypeObject *subtype, PyObject *args, PyObject *kwargs) {
+    if (!PyArg_ParseTuple(args, ":X509Req")) {
+        return NULL;
+    }
+
+    return (PyObject *)crypto_X509Req_New(X509_REQ_new(), 1);
+}
+
+
 /*
  * Deallocate the memory used by the X509Req object
  *
@@ -375,20 +378,60 @@
     (destructor)crypto_X509Req_dealloc,
     NULL, /* print */
     (getattrfunc)crypto_X509Req_getattr,
+    NULL, /* setattr */
+    NULL, /* compare */
+    NULL, /* repr */
+    NULL, /* as_number */
+    NULL, /* as_sequence */
+    NULL, /* as_mapping */
+    NULL, /* hash */
+    NULL, /* call */
+    NULL, /* str */
+    NULL, /* getattro */
+    NULL, /* setattro */
+    NULL, /* as_buffer */
+    Py_TPFLAGS_DEFAULT,
+    crypto_X509Req_doc, /* doc */
+    NULL, /* traverse */
+    NULL, /* clear */
+    NULL, /* tp_richcompare */
+    0, /* tp_weaklistoffset */
+    NULL, /* tp_iter */
+    NULL, /* tp_iternext */
+    crypto_X509Req_methods, /* tp_methods */
+    NULL, /* tp_members */
+    NULL, /* tp_getset */
+    NULL, /* tp_base */
+    NULL, /* tp_dict */
+    NULL, /* tp_descr_get */
+    NULL, /* tp_descr_set */
+    0, /* tp_dictoffset */
+    NULL, /* tp_init */
+    NULL, /* tp_alloc */
+    crypto_X509Req_new, /* tp_new */
 };
 
 
 /*
  * Initialize the X509Req part of the crypto module
  *
- * Arguments: dict - The crypto module dictionary
+ * Arguments: module - The crypto module
  * Returns:   None
  */
 int
-init_crypto_x509req(PyObject *dict)
+init_crypto_x509req(PyObject *module)
 {
-    crypto_X509Req_Type.ob_type = &PyType_Type;
-    Py_INCREF(&crypto_X509Req_Type);
-    PyDict_SetItemString(dict, "X509ReqType", (PyObject *)&crypto_X509Req_Type);
+    if (PyType_Ready(&crypto_X509Req_Type) < 0) {
+        return 0;
+    }
+
+    if (PyModule_AddObject(module, "X509Req", (PyObject *)&crypto_X509Req_Type) != 0) {
+        return 0;
+    }
+
+    if (PyModule_AddObject(module, "X509ReqType", (PyObject *)&crypto_X509Req_Type) != 0) {
+        return 0;
+    }
+
     return 1;
 }
diff --git a/src/crypto/x509store.c b/src/crypto/x509store.c
index 442c2d5..16af3b0 100644
--- a/src/crypto/x509store.c
+++ b/src/crypto/x509store.c
@@ -13,10 +13,8 @@
 static char crypto_X509Store_add_cert_doc[] = "\n\
 Add a certificate\n\
 \n\
-Arguments: self - The X509Store object\n\
-           args - The Python argument tuple, should be:\n\
-             cert - The certificate to add\n\
-Returns:   None\n\
+@param cert: The certificate to add\n\
+@return: None\n\
 ";
 
 static PyObject *
@@ -29,7 +27,7 @@
 
     if (!X509_STORE_add_cert(self->x509_store, cert->x509))
     {
-        exception_from_error_queue();
+        exception_from_error_queue(crypto_Error);
         return NULL;
     }
 
@@ -130,14 +128,19 @@
 /*
  * Initialize the X509Store part of the crypto module
  *
- * Arguments: dict - The crypto module dictionary
+ * Arguments: module - The crypto module
  * Returns:   None
  */
 int
-init_crypto_x509store(PyObject *dict)
+init_crypto_x509store(PyObject *module)
 {
-    crypto_X509Store_Type.ob_type = &PyType_Type;
-    Py_INCREF(&crypto_X509Store_Type);
-    PyDict_SetItemString(dict, "X509StoreType", (PyObject *)&crypto_X509Store_Type);
+    if (PyType_Ready(&crypto_X509Store_Type) < 0) {
+        return 0;
+    }
+
+    if (PyModule_AddObject(module, "X509StoreType", (PyObject *)&crypto_X509Store_Type) != 0) {
+        return 0;
+    }
+
     return 1;
 }
diff --git a/src/rand/rand.c b/src/rand/rand.c
index ff89ebb..e922e08 100644
--- a/src/rand/rand.c
+++ b/src/rand/rand.c
@@ -21,6 +21,9 @@
 #  endif
 #endif
 #include <openssl/rand.h>
+#include "../util.h"
+
+PyObject *rand_Error;
 
 static char rand_doc[] = "\n\
 PRNG management routines, thin wrappers.\n\
@@ -30,11 +33,9 @@
 static char rand_add_doc[] = "\n\
 Add data with a given entropy to the PRNG\n\
 \n\
-Arguments: spam - Always NULL\n\
-           args - The Python argument tuple, should be:\n\
-             buffer  - Buffer with random data\n\
-             entropy - The entropy (in bytes) measurement of the buffer\n\
-Returns:   None\n\
+@param buffer: Buffer with random data\n\
+@param entropy: The entropy (in bytes) measurement of the buffer\n\
+@return: None\n\
 ";
 
 static PyObject *
@@ -56,10 +57,8 @@
 static char rand_seed_doc[] = "\n\
 Alias for rand_add, with entropy equal to length\n\
 \n\
-Arguments: spam - Always NULL\n\
-           args - The Python argument tuple, should be:\n\
-             buffer - Buffer with random data\n\
-Returns:   None\n\
+@param buffer: Buffer with random data\n\
+@return: None\n\
 ";
 
 static PyObject *
@@ -80,9 +79,7 @@
 static char rand_status_doc[] = "\n\
 Retrieve the status of the PRNG\n\
 \n\
-Arguments: spam - Always NULL\n\
-           args - The Python argument tuple, should be empty\n\
-Returns:   True if the PRNG is seeded enough, false otherwise\n\
+@return: True if the PRNG is seeded enough, false otherwise\n\
 ";
 
 static PyObject *
@@ -99,9 +96,7 @@
 Add the current contents of the screen to the PRNG state. Availability:\n\
 Windows.\n\
 \n\
-Arguments: spam - Always NULL\n\
-           args - The Python argument tuple, should be empty\n\
-Returns:   None\n\
+@return: None\n\
 ";
 
 static PyObject *
@@ -121,12 +116,10 @@
 PRNG. I haven't found any problems when the socket is missing, the function\n\
 just returns 0.\n\
 \n\
-Arguments: spam - Always NULL\n\
-           args - The Python argument tuple, should be:\n\
-             path  - The path to the EGD socket\n\
-             bytes - (optional) The number of bytes to read, default is 255\n\
-Returns:   The number of bytes read (NB: a value of 0 isn't necessarily an\n\
-           error, check rand.status())\n\
+@param path: The path to the EGD socket\n\
+@param bytes: (optional) The number of bytes to read, default is 255\n\
+@returns: The number of bytes read (NB: a value of 0 isn't necessarily an\n\
+          error, check rand.status())\n\
 ";
 
 static PyObject *
@@ -144,9 +137,7 @@
 static char rand_cleanup_doc[] = "\n\
 Erase the memory used by the PRNG.\n\
 \n\
-Arguments: spam - Always NULL\n\
-           args - The Python argument tuple, should be empty\n\
-Returns:   None\n\
+@return: None\n\
 ";
 
 static PyObject *
@@ -164,12 +155,10 @@
 static char rand_load_file_doc[] = "\n\
 Seed the PRNG with data from a file\n\
 \n\
-Arguments: spam - Always NULL\n\
-           args - The Python argument tuple, should be:\n\
-             filename - The file to read data from\n\
-             maxbytes - (optional) The number of bytes to read, default is\n\
-                        to read the entire file\n\
-Returns:   The number of bytes read\n\
+@param filename: The file to read data from\n\
+@param maxbytes: (optional) The number of bytes to read, default is\n\
+                 to read the entire file\n\
+@return: The number of bytes read\n\
 ";
 
 static PyObject *
@@ -187,10 +176,8 @@
 static char rand_write_file_doc[] = "\n\
 Save PRNG state to a file\n\
 \n\
-Arguments: spam - Always NULL\n\
-           args - The Python argument tuple, should be:\n\
-             filename - The file to write data to\n\
-Returns:   The number of bytes written\n\
+@param filename: The file to write data to\n\
+@return: The number of bytes written\n\
 ";
 
 static PyObject *
@@ -204,6 +191,42 @@
     return PyInt_FromLong((long)RAND_write_file(filename));
 }
 
+static char rand_bytes_doc[] = "\n\
+Get some randomm bytes as a string.\n\
+\n\
+@param num_bytes: The number of bytes to fetch\n\
+@return: A string of random bytes\n\
+";
+
+static PyObject *
+rand_bytes(PyObject *spam, PyObject *args, PyObject *keywds)
+{
+    int num_bytes;
+    static char *kwlist[] = {"num_bytes", NULL};
+    char *buf;
+    unsigned int rc;
+    PyObject *obj = NULL;
+
+    if (!PyArg_ParseTupleAndKeywords(args, keywds, "i:bytes", kwlist, &num_bytes))
+        return NULL;
+    if(num_bytes < 0) {
+        PyErr_SetString(PyExc_ValueError, "num_bytes must not be negative");
+        return NULL;
+    }
+    buf = malloc(num_bytes);
+    if (buf == NULL)   /* out of memory  */
+        return NULL;
+    rc = RAND_bytes((unsigned char *) buf, num_bytes);
+    if(rc != 1) {  /* if unsuccessful */
+        exception_from_error_queue(rand_Error);
+        goto done;
+    }
+    obj = PyString_FromStringAndSize(buf, (unsigned) num_bytes);
+ done:
+    free(buf);
+    return obj;
+}
+
 
 /* Methods in the OpenSSL.rand module */
 static PyMethodDef rand_methods[] = {
@@ -217,6 +240,7 @@
     { "cleanup",   (PyCFunction)rand_cleanup,      METH_VARARGS, rand_cleanup_doc },
     { "load_file", (PyCFunction)rand_load_file,    METH_VARARGS, rand_load_file_doc },
     { "write_file",(PyCFunction)rand_write_file,   METH_VARARGS, rand_write_file_doc },
+    { "bytes",     (PyCFunction)rand_bytes,        METH_VARARGS|METH_KEYWORDS, rand_bytes_doc },
     { NULL, NULL }
 };
 
@@ -236,5 +260,13 @@
 
     if ((module = Py_InitModule3("rand", rand_methods, rand_doc)) == NULL)
         return;
+
+    rand_Error = PyErr_NewException("OpenSSL.rand.Error", NULL, NULL);
+    if (rand_Error == NULL)
+        goto error;
+    if (PyModule_AddObject(module, "Error", rand_Error) != 0)
+        goto error;
+ error:
+    ;
 }
 
diff --git a/src/ssl/connection.c b/src/ssl/connection.c
index f78e93f..e10989b 100755
--- a/src/ssl/connection.c
+++ b/src/ssl/connection.c
@@ -164,7 +164,7 @@
          * the code which triggered the error also kindly pushed something onto
          * the error stack.
          */
-        exception_from_error_queue();
+        exception_from_error_queue(ssl_Error);
     }
 }
 
@@ -238,7 +238,7 @@
         case SSL_ERROR_SSL:
             ;
         default:
-	    exception_from_error_queue();
+	    exception_from_error_queue(ssl_Error);
             break;
     }
 }
@@ -250,9 +250,7 @@
 static char ssl_Connection_get_context_doc[] = "\n\
 Get session context\n\
 \n\
-Arguments: self - The Connection object\n\
-           args - The Python argument tuple, should be empty\n\
-Returns:   A Context object\n\
+@return: A Context object\n\
 ";
 static PyObject *
 ssl_Connection_get_context(ssl_ConnectionObj *self, PyObject *args)
@@ -267,9 +265,7 @@
 static char ssl_Connection_pending_doc[] = "\n\
 Get the number of bytes that can be safely read from the connection\n\
 \n\
-Arguments: self - The Connection object\n\
-           args - The Python argument tuple, should be empty\n\
-Returns:   \n\
+@return: The number of bytes available in the receive buffer.\n\
 ";
 static PyObject *
 ssl_Connection_pending(ssl_ConnectionObj *self, PyObject *args)
@@ -287,10 +283,8 @@
 When using non-socket connections this function sends\n\
 \"dirty\" data that would have traveled in on the network.\n\
 \n\
-Arguments: self - The Connection object\n\
-           args - The Python argument tuple, should be:\n\
-             buf   - The string to bio_write\n\
-Returns:   The number of bytes written\n\
+@param buf: The string to put into the memory BIO.\n\
+@return: The number of bytes written\n\
 ";
 static PyObject *
 ssl_Connection_bio_write(ssl_ConnectionObj *self, PyObject *args)
@@ -331,12 +325,10 @@
 WantWrite or WantX509Lookup exceptions on this, you have to call the\n\
 method again with the SAME buffer.\n\
 \n\
-Arguments: self - The Connection object\n\
-           args - The Python argument tuple, should be:\n\
-             buf   - The string to send\n\
-             flags - (optional) Included for compatability with the socket\n\
-                     API, the value is ignored\n\
-Returns:   The number of bytes written\n\
+@param buf: The string to send\n\
+@param flags: (optional) Included for compatability with the socket\n\
+              API, the value is ignored\n\
+@return: The number of bytes written\n\
 ";
 static PyObject *
 ssl_Connection_send(ssl_ConnectionObj *self, PyObject *args)
@@ -374,12 +366,10 @@
 all data is sent. If an error occurs, it's impossible to tell how much data\n\
 has been sent.\n\
 \n\
-Arguments: self - The Connection object\n\
-           args - The Python argument tuple, should be:\n\
-             buf   - The string to send\n\
-             flags - (optional) Included for compatability with the socket\n\
-                     API, the value is ignored\n\
-Returns:   The number of bytes written\n\
+@param buf: The string to send\n\
+@param flags: (optional) Included for compatability with the socket\n\
+              API, the value is ignored\n\
+@return: The number of bytes written\n\
 ";
 static PyObject *
 ssl_Connection_sendall(ssl_ConnectionObj *self, PyObject *args)
@@ -425,12 +415,10 @@
 WantWrite or WantX509Lookup exceptions on this, you have to call the\n\
 method again with the SAME buffer.\n\
 \n\
-Arguments: self - The Connection object\n\
-           args - The Python argument tuple, should be:\n\
-             bufsiz - The maximum number of bytes to read\n\
-             flags  - (optional) Included for compatability with the socket\n\
-                      API, the value is ignored\n\
-Returns:   The number of bytes read\n\
+@param bufsiz: The maximum number of bytes to read\n\
+@param flags: (optional) Included for compatability with the socket\n\
+              API, the value is ignored\n\
+@return: The string read from the Connection\n\
 ";
 static PyObject *
 ssl_Connection_recv(ssl_ConnectionObj *self, PyObject *args)
@@ -475,10 +463,8 @@
 When using non-socket connections this function reads\n\
 the \"dirty\" data that would have traveled away on the network.\n\
 \n\
-Arguments: self - The Connection object\n\
-           args - The Python argument tuple, should be:\n\
-             bufsiz - The maximum number of bytes to read\n\
-Returns:   The string read.\n\
+@param bufsiz: The maximum number of bytes to read\n\
+@return: The string read.\n\
 ";
 static PyObject *
 ssl_Connection_bio_read(ssl_ConnectionObj *self, PyObject *args)
@@ -531,9 +517,7 @@
 static char ssl_Connection_renegotiate_doc[] = "\n\
 Renegotiate the session\n\
 \n\
-Arguments: self - The Connection object\n\
-           args - The Python argument tuple, should be empty\n\
-Returns:   True if the renegotiation can be started, false otherwise\n\
+@return: True if the renegotiation can be started, false otherwise\n\
 ";
 static PyObject *
 ssl_Connection_renegotiate(ssl_ConnectionObj *self, PyObject *args)
@@ -560,9 +544,7 @@
 Perform an SSL handshake (usually called after renegotiate() or one of\n\
 set_*_state()). This can raise the same exceptions as send and recv.\n\
 \n\
-Arguments: self - The Connection object\n\
-           args - The Python argument tuple, should be empty\n\
-Returns:   None.\n\
+@return: None.\n\
 ";
 static PyObject *
 ssl_Connection_do_handshake(ssl_ConnectionObj *self, PyObject *args)
@@ -600,9 +582,7 @@
 Check if there's a renegotiation in progress, it will return false once\n\
 a renegotiation is finished.\n\
 \n\
-Arguments: self - The Connection object\n\
-           args - The Python argument tuple, should be empty\n\
-Returns:   Whether there's a renegotiation in progress\n\
+@return: Whether there's a renegotiation in progress\n\
 ";
 static PyObject *
 ssl_Connection_renegotiate_pending(ssl_ConnectionObj *self, PyObject *args)
@@ -617,9 +597,7 @@
 static char ssl_Connection_total_renegotiations_doc[] = "\n\
 Find out the total number of renegotiations.\n\
 \n\
-Arguments: self - The Connection object\n\
-           args - The Python argument tuple, should be empty\n\
-Returns:   The number of renegotiations.\n\
+@return: The number of renegotiations.\n\
 ";
 static PyObject *
 ssl_Connection_total_renegotiations(ssl_ConnectionObj *self, PyObject *args)
@@ -634,9 +612,7 @@
 Set the connection to work in server mode. The handshake will be handled\n\
 automatically by read/write.\n\
 \n\
-Arguments: self - The Connection object\n\
-           args - The Python argument tuple, should be empty\n\
-Returns:   None\n\
+@return: None\n\
 ";
 static PyObject *
 ssl_Connection_set_accept_state(ssl_ConnectionObj *self, PyObject *args)
@@ -654,9 +630,7 @@
 Set the connection to work in client mode. The handshake will be handled\n\
 automatically by read/write.\n\
 \n\
-Arguments: self - The Connection object\n\
-           args - The Python argument tuple, should be empty\n\
-Returns:   None\n\
+@return: None\n\
 ";
 static PyObject *
 ssl_Connection_set_connect_state(ssl_ConnectionObj *self, PyObject *args)
@@ -673,10 +647,8 @@
 static char ssl_Connection_connect_doc[] = "\n\
 Connect to remote host and set up client-side SSL\n\
 \n\
-Arguments: self - The Connection object\n\
-           args - The Python argument tuple, should be:\n\
-             addr - A remote address\n\
-Returns:   What the socket's connect method returns\n\
+@param addr: A remote address\n\
+@return: What the socket's connect method returns\n\
 ";
 static PyObject *
 ssl_Connection_connect(ssl_ConnectionObj *self, PyObject *args)
@@ -700,10 +672,8 @@
 Connect to remote host and set up client-side SSL. Note that if the socket's\n\
 connect_ex method doesn't return 0, SSL won't be initialized.\n\
 \n\
-Arguments: self - The Connection object\n\
-           args - The Python argument tuple, should be:\n\
-             addr - A remove address\n\
-Returns:   What the socket's connect_ex method returns\n\
+@param addr: A remove address\n\
+@return: What the socket's connect_ex method returns\n\
 ";
 static PyObject *
 ssl_Connection_connect_ex(ssl_ConnectionObj *self, PyObject *args)
@@ -728,10 +698,8 @@
 static char ssl_Connection_accept_doc[] = "\n\
 Accept incoming connection and set up SSL on it\n\
 \n\
-Arguments: self - The Connection object\n\
-           args - The Python argument tuple, should be empty\n\
-Returns:   A (conn,addr) pair where conn is a Connection and addr is an\n\
-           address\n\
+@return: A (conn,addr) pair where conn is a Connection and addr is an\n\
+         address\n\
 ";
 static PyObject *
 ssl_Connection_accept(ssl_ConnectionObj *self, PyObject *args)
@@ -774,9 +742,7 @@
 When using non-socket connections this function signals end of\n\
 data on the input for this connection.\n\
 \n\
-Arguments: self - The Connection object\n\
-           args - The Python argument tuple, should be empty.\n\
-Returns:   Nothing\n\
+@return: None\n\
 ";
 
 static PyObject *
@@ -798,11 +764,9 @@
 static char ssl_Connection_shutdown_doc[] = "\n\
 Send closure alert\n\
 \n\
-Arguments: self - The Connection object\n\
-           args - The Python argument tuple, should be empty\n\
-Returns:   True if the shutdown completed successfully (i.e. both sides\n\
-           have sent closure alerts), false otherwise (i.e. you have to\n\
-           wait for a ZeroReturnError on a recv() method call\n\
+@return: True if the shutdown completed successfully (i.e. both sides\n\
+         have sent closure alerts), false otherwise (i.e. you have to\n\
+         wait for a ZeroReturnError on a recv() method call\n\
 ";
 static PyObject *
 ssl_Connection_shutdown(ssl_ConnectionObj *self, PyObject *args)
@@ -824,7 +788,7 @@
 
     if (ret < 0)
     {
-        exception_from_error_queue();
+        exception_from_error_queue(ssl_Error);
         return NULL;
     }
     else if (ret > 0)
@@ -841,12 +805,8 @@
 
 static char ssl_Connection_get_cipher_list_doc[] = "\n\
 Get the session cipher list\n\
-WARNING: API change! This used to take an optional argument, and return a\n\
-string.\n\
 \n\
-Arguments: self - The Connection object\n\
-           args - The Python argument tuple, should be empty\n\
-Returns:   A list of cipher strings\n\
+@return: A list of cipher strings\n\
 ";
 static PyObject *
 ssl_Connection_get_cipher_list(ssl_ConnectionObj *self, PyObject *args)
@@ -872,11 +832,8 @@
 static char ssl_Connection_makefile_doc[] = "\n\
 The makefile() method is not implemented, since there is no dup semantics\n\
 for SSL connections\n\
-XXX: Return self instead?\n\
 \n\
-Arguments: self - The Connection object\n\
-           args - The Python argument tuple, should be empty\n\
-Returns:   NULL\n\
+@raise NotImplementedError\n\
 ";
 static PyObject *
 ssl_Connection_makefile(ssl_ConnectionObj *self, PyObject *args)
@@ -888,9 +845,7 @@
 static char ssl_Connection_get_app_data_doc[] = "\n\
 Get application data\n\
 \n\
-Arguments: self - The Connection object\n\
-           args - The Python argument tuple, should be empty\n\
-Returns:   The application data\n\
+@return: The application data\n\
 ";
 static PyObject *
 ssl_Connection_get_app_data(ssl_ConnectionObj *self, PyObject *args)
@@ -905,10 +860,8 @@
 static char ssl_Connection_set_app_data_doc[] = "\n\
 Set application data\n\
 \n\
-Arguments: self - The Connection object\n\
-           args - The Python argument tuple, should be\n\
-             data - The application data\n\
-Returns:   None\n\
+@param data - The application data\n\
+@return: None\n\
 ";
 static PyObject *
 ssl_Connection_set_app_data(ssl_ConnectionObj *self, PyObject *args)
@@ -929,9 +882,7 @@
 static char ssl_Connection_get_shutdown_doc[] = "\n\
 Get shutdown state\n\
 \n\
-Arguments: self - The Connection object\n\
-           args - The Python argument tuple, should be empty\n\
-Returns:   The shutdown state, a bitmask of SENT_SHUTDOWN, RECEIVED_SHUTDOWN.\n\
+@return: The shutdown state, a bitvector of SENT_SHUTDOWN, RECEIVED_SHUTDOWN.\n\
 ";
 static PyObject *
 ssl_Connection_get_shutdown(ssl_ConnectionObj *self, PyObject *args)
@@ -945,10 +896,8 @@
 static char ssl_Connection_set_shutdown_doc[] = "\n\
 Set shutdown state\n\
 \n\
-Arguments: self - The Connection object\n\
-           args - The Python argument tuple, should be\n\
-             shutdown state - bitmask of SENT_SHUTDOWN, RECEIVED_SHUTDOWN.\n\
-Returns:   None\n\
+@param state - bitvector of SENT_SHUTDOWN, RECEIVED_SHUTDOWN.\n\
+@return: None\n\
 ";
 static PyObject *
 ssl_Connection_set_shutdown(ssl_ConnectionObj *self, PyObject *args)
@@ -966,9 +915,7 @@
 static char ssl_Connection_state_string_doc[] = "\n\
 Get a verbose state description\n\
 \n\
-Arguments: self - The Connection object\n\
-           args - The Python argument tuple, should be empty\n\
-Returns:   A string representing the state\n\
+@return: A string representing the state\n\
 ";
 static PyObject *
 ssl_Connection_state_string(ssl_ConnectionObj *self, PyObject *args)
@@ -982,9 +929,7 @@
 static char ssl_Connection_client_random_doc[] = "\n\
 Get a copy of the client hello nonce.\n\
 \n\
-Arguments: self - The Connection object\n\
-           args - The Python argument tuple, should be empty\n\
-Returns:   A string representing the state\n\
+@return: A string representing the state\n\
 ";
 static PyObject *
 ssl_Connection_client_random(ssl_ConnectionObj *self, PyObject *args)
@@ -1002,9 +947,7 @@
 static char ssl_Connection_server_random_doc[] = "\n\
 Get a copy of the server hello nonce.\n\
 \n\
-Arguments: self - The Connection object\n\
-           args - The Python argument tuple, should be empty\n\
-Returns:   A string representing the state\n\
+@return: A string representing the state\n\
 ";
 static PyObject *
 ssl_Connection_server_random(ssl_ConnectionObj *self, PyObject *args)
@@ -1022,9 +965,7 @@
 static char ssl_Connection_master_key_doc[] = "\n\
 Get a copy of the master key.\n\
 \n\
-Arguments: self - The Connection object\n\
-           args - The Python argument tuple, should be empty\n\
-Returns:   A string representing the state\n\
+@return: A string representing the state\n\
 ";
 static PyObject *
 ssl_Connection_master_key(ssl_ConnectionObj *self, PyObject *args)
@@ -1042,10 +983,7 @@
 static char ssl_Connection_sock_shutdown_doc[] = "\n\
 See shutdown(2)\n\
 \n\
-Arguments: self - The Connection object\n\
-           args - The Python argument tuple, should be whatever the\n\
-                  socket's shutdown() method expects\n\
-Returns:   What the socket's shutdown() method returns\n\
+@return: What the socket's shutdown() method returns\n\
 ";
 static PyObject *
 ssl_Connection_sock_shutdown(ssl_ConnectionObj *self, PyObject *args)
@@ -1062,9 +1000,7 @@
 static char ssl_Connection_get_peer_certificate_doc[] = "\n\
 Retrieve the other side's certificate (if any)\n\
 \n\
-Arguments: self - The Connection object\n\
-           args - The Python argument tuple, should be empty\n\
-Returns:   The peer's certificate\n\
+@return: The peer's certificate\n\
 ";
 static PyObject *
 ssl_Connection_get_peer_certificate(ssl_ConnectionObj *self, PyObject *args)
@@ -1090,9 +1026,7 @@
 Checks if more data has to be read from the transport layer to complete an\n\
 operation.\n\
 \n\
-Arguments: self - The Connection object\n\
-           args - The Python argument tuple, should be empty\n\
-Returns:   True iff more data has to be read\n\
+@return: True iff more data has to be read\n\
 ";
 static PyObject *
 ssl_Connection_want_read(ssl_ConnectionObj *self, PyObject *args)
@@ -1107,9 +1041,7 @@
 Checks if there is data to write to the transport layer to complete an\n\
 operation.\n\
 \n\
-Arguments: self - The Connection object\n\
-           args - The Python argument tuple, should be empty\n\
-Returns:   True iff there is data to write\n\
+@return: True iff there is data to write\n\
 ";
 static PyObject *
 ssl_Connection_want_write(ssl_ConnectionObj *self, PyObject *args)
@@ -1175,24 +1107,25 @@
 #undef ADD_ALIAS
 #undef ADD_METHOD
 
+static char ssl_Connection_doc[] = "\n\
+Connection(context, socket) -> Connection instance\n\
+\n\
+Create a new Connection object, using the given OpenSSL.SSL.Context instance\n\
+and socket.\n\
+\n\
+@param context: An SSL Context to use for this connection\n\
+@param socket: The socket to use for transport layer\n\
+";
 
 /*
- * Constructor for Connection objects
- *
- * Arguments: ctx  - An SSL Context to use for this connection
- *            sock - The socket to use for transport layer
- * Returns:   The newly created Connection object
+ * Initializer used by ssl_Connection_new and ssl_Connection_New.  *Not*
+ * tp_init.  This takes an already allocated ssl_ConnectionObj, a context, and
+ * a optionally a socket, and glues them all together.
  */
-ssl_ConnectionObj *
-ssl_Connection_New(ssl_ContextObj *ctx, PyObject *sock)
-{
-    ssl_ConnectionObj *self;
+static ssl_ConnectionObj*
+ssl_Connection_init(ssl_ConnectionObj *self, ssl_ContextObj *ctx, PyObject *sock) {
     int fd;
 
-    self = PyObject_GC_New(ssl_ConnectionObj, &ssl_Connection_Type);
-    if (self == NULL)
-        return NULL;
-
     Py_INCREF(ctx);
     self->context = ctx;
 
@@ -1234,9 +1167,6 @@
             SSL_set_fd(self->ssl, (SOCKET_T)fd);
         }
     }
-
-    PyObject_GC_Track(self);
-
     return self;
 
 error:
@@ -1247,6 +1177,49 @@
 }
 
 /*
+ * Constructor for Connection objects
+ *
+ * Arguments: ctx  - An SSL Context to use for this connection
+ *            sock - The socket to use for transport layer
+ * Returns:   The newly created Connection object
+ */
+ssl_ConnectionObj *
+ssl_Connection_New(ssl_ContextObj *ctx, PyObject *sock) {
+    ssl_ConnectionObj *self;
+
+    self = PyObject_GC_New(ssl_ConnectionObj, &ssl_Connection_Type);
+    if (self == NULL) {
+        return NULL;
+    }
+    self = ssl_Connection_init(self, ctx, sock);
+    if (self == NULL) {
+        return NULL;
+    }
+    PyObject_GC_Track((PyObject *)self);
+    return self;
+}
+
+static PyObject*
+ssl_Connection_new(PyTypeObject *subtype, PyObject *args, PyObject *kwargs) {
+    ssl_ConnectionObj *self;
+    ssl_ContextObj *ctx;
+    PyObject *sock;
+    static char *kwlist[] = {"context", "socket", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O:Connection", kwlist,
+                                     &ssl_Context_Type, &ctx, &sock)) {
+        return NULL;
+    }
+
+    self = (ssl_ConnectionObj *)subtype->tp_alloc(subtype, 1);
+    if (self == NULL) {
+        return NULL;
+    }
+
+    return (PyObject *)ssl_Connection_init(self, ctx, sock);
+}
+
+/*
  * Find attribute
  *
  * Arguments: self - The Connection object
@@ -1333,12 +1306,12 @@
 PyTypeObject ssl_Connection_Type = {
     PyObject_HEAD_INIT(NULL)
     0,
-    "Connection",
+    "OpenSSL.SSL.Connection",
     sizeof(ssl_ConnectionObj),
     0,
     (destructor)ssl_Connection_dealloc,
     NULL, /* print */
-    (getattrfunc)ssl_Connection_getattr,
+    (getattrfunc)ssl_Connection_getattr, /* tp_getattr */
     NULL, /* setattr */
     NULL, /* compare */
     NULL, /* repr */
@@ -1352,25 +1325,47 @@
     NULL, /* setattro */
     NULL, /* as_buffer */
     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
-    NULL, /* doc */
+    ssl_Connection_doc, /* doc */
     (traverseproc)ssl_Connection_traverse,
     (inquiry)ssl_Connection_clear,
+    NULL, /* tp_richcompare */
+    0, /* tp_weaklistoffset */
+    NULL, /* tp_iter */
+    NULL, /* tp_iternext */
+    ssl_Connection_methods, /* tp_methods */
+    NULL, /* tp_members */
+    NULL, /* tp_getset */
+    NULL, /* tp_base */
+    NULL, /* tp_dict */
+    NULL, /* tp_descr_get */
+    NULL, /* tp_descr_set */
+    0, /* tp_dictoffset */
+    NULL, /* tp_init */
+    NULL, /* tp_alloc */
+    ssl_Connection_new, /* tp_new */
 };
 
 
 /*
  * Initiailze the Connection part of the SSL sub module
  *
- * Arguments: dict - Dictionary of the OpenSSL.SSL module
+ * Arguments: dict - The OpenSSL.SSL module
  * Returns:   1 for success, 0 otherwise
  */
 int
-init_ssl_connection(PyObject *dict)
-{
-    ssl_Connection_Type.ob_type = &PyType_Type;
-    Py_INCREF(&ssl_Connection_Type);
-    if (PyDict_SetItemString(dict, "ConnectionType", (PyObject *)&ssl_Connection_Type) != 0)
+init_ssl_connection(PyObject *module) {
+
+    if (PyType_Ready(&ssl_Connection_Type) < 0) {
         return 0;
+    }
+
+    if (PyModule_AddObject(module, "Connection", (PyObject *)&ssl_Connection_Type) != 0) {
+        return 0;
+    }
+
+    if (PyModule_AddObject(module, "ConnectionType", (PyObject *)&ssl_Connection_Type) != 0) {
+        return 0;
+    }
 
     return 1;
 }
diff --git a/src/ssl/context.c b/src/ssl/context.c
index 1fecc9b..df7411f 100644
--- a/src/ssl/context.c
+++ b/src/ssl/context.c
@@ -236,17 +236,23 @@
 }
 
 
-
+static char ssl_Context_doc[] = "\n\
+Context(method) -> Context instance\n\
+\n\
+OpenSSL.SSL.Context instances define the parameters for setting up new SSL\n\
+connections.\n\
+\n\
+@param method: One of SSLv2_METHOD, SSLv3_METHOD, SSLv23_METHOD, or\n\
+               TLSv1_METHOD.\n\
+";
 
 static char ssl_Context_load_verify_locations_doc[] = "\n\
 Let SSL know where we can find trusted certificates for the certificate\n\
 chain\n\
 \n\
-Arguments: self - The Context object\n\
-           args - The Python argument tuple, should be:\n\
-             cafile - In which file we can find the certificates\n\
-             capath - In which directory we can find the certificates\r\
-Returns:   None\n\
+@param cafile: In which file we can find the certificates\n\
+@param capath: In which directory we can find the certificates\n\
+@return: None\n\
 ";
 static PyObject *
 ssl_Context_load_verify_locations(ssl_ContextObj *self, PyObject *args) {
@@ -259,7 +265,7 @@
 
     if (!SSL_CTX_load_verify_locations(self->ctx, cafile, capath))
     {
-        exception_from_error_queue();
+        exception_from_error_queue(ssl_Error);
         return NULL;
     }
     else
@@ -272,10 +278,7 @@
 static char ssl_Context_set_default_verify_paths_doc[] = "\n\
 Use the platform-specific CA certificate locations\n\
 \n\
-Arguments: self - The Context object\n\
-           args - None\n\
-\n\
-Returns:   None\n\
+@return: None\n\
 ";
 static PyObject *
 ssl_Context_set_default_verify_paths(ssl_ContextObj *self, PyObject *args) {
@@ -288,7 +291,7 @@
      * -exarkun
      */
     if (!SSL_CTX_set_default_verify_paths(self->ctx)) {
-        exception_from_error_queue();
+        exception_from_error_queue(ssl_Error);
         return NULL;
     }
     Py_INCREF(Py_None);
@@ -299,12 +302,10 @@
 static char ssl_Context_set_passwd_cb_doc[] = "\n\
 Set the passphrase callback\n\
 \n\
-Arguments: self - The Context object\n\
-           args - The Python argument tuple, should be:\n\
-             callback - The Python callback to use\n\
-             userdata - (optional) A Python object which will be given as\n\
-                        argument to the callback\n\
-Returns:   None\n\
+@param callback: The Python callback to use\n\
+@param userdata: (optional) A Python object which will be given as\n\
+                 argument to the callback\n\
+@return: None\n\
 ";
 static PyObject *
 ssl_Context_set_passwd_cb(ssl_ContextObj *self, PyObject *args)
@@ -371,10 +372,8 @@
 static char ssl_Context_add_extra_chain_cert_doc[] = "\n\
 Add certificate to chain\n\
 \n\
-Arguments: self - The Context object\n\
-           args - The Python argument tuple, should be:\n\
-             certobj - The X509 certificate object to add to the chain\n\
-Returns:   None\n\
+@param certobj: The X509 certificate object to add to the chain\n\
+@return: None\n\
 ";
 
 static PyObject *
@@ -389,14 +388,14 @@
     }
     if (!(cert_original = X509_dup(cert->x509)))
     {
-        /* exception_from_error_queue(); */
+        /* exception_from_error_queue(ssl_Error); */
         PyErr_SetString(PyExc_RuntimeError, "X509_dup failed");
         return NULL;
     }
     if (!SSL_CTX_add_extra_chain_cert(self->ctx, cert_original))
     {
         X509_free(cert_original);
-        exception_from_error_queue();
+        exception_from_error_queue(ssl_Error);
         return NULL;
     }
     else
@@ -410,10 +409,8 @@
 static char ssl_Context_use_certificate_chain_file_doc[] = "\n\
 Load a certificate chain from a file\n\
 \n\
-Arguments: self - The Context object\n\
-           args - The Python argument tuple, should be:\n\
-             certfile - The name of the certificate chain file\n\
-Returns:   None\n\
+@param certfile: The name of the certificate chain file\n\
+@return: None\n\
 ";
 static PyObject *
 ssl_Context_use_certificate_chain_file(ssl_ContextObj *self, PyObject *args)
@@ -425,7 +422,7 @@
 
     if (!SSL_CTX_use_certificate_chain_file(self->ctx, certfile))
     {
-        exception_from_error_queue();
+        exception_from_error_queue(ssl_Error);
         return NULL;
     }
     else
@@ -439,11 +436,9 @@
 static char ssl_Context_use_certificate_file_doc[] = "\n\
 Load a certificate from a file\n\
 \n\
-Arguments: self - The Context object\n\
-           args - The Python argument tuple, should be:\n\
-             certfile - The name of the certificate file\n\
-             filetype - (optional) The encoding of the file, default is PEM\n\
-Returns:   None\n\
+@param certfile: The name of the certificate file\n\
+@param filetype: (optional) The encoding of the file, default is PEM\n\
+@return: None\n\
 ";
 static PyObject *
 ssl_Context_use_certificate_file(ssl_ContextObj *self, PyObject *args)
@@ -456,7 +451,7 @@
 
     if (!SSL_CTX_use_certificate_file(self->ctx, certfile, filetype))
     {
-        exception_from_error_queue();
+        exception_from_error_queue(ssl_Error);
         return NULL;
     }
     else
@@ -469,10 +464,8 @@
 static char ssl_Context_use_certificate_doc[] = "\n\
 Load a certificate from a X509 object\n\
 \n\
-Arguments: self - The Context object\n\
-           args - The Python argument tuple, should be:\n\
-             cert - The X509 object\n\
-Returns:   None\n\
+@param cert: The X509 object\n\
+@return: None\n\
 ";
 static PyObject *
 ssl_Context_use_certificate(ssl_ContextObj *self, PyObject *args)
@@ -485,7 +478,7 @@
     
     if (!SSL_CTX_use_certificate(self->ctx, cert->x509))
     {
-        exception_from_error_queue();
+        exception_from_error_queue(ssl_Error);
         return NULL;
     }
     else
@@ -498,11 +491,9 @@
 static char ssl_Context_use_privatekey_file_doc[] = "\n\
 Load a private key from a file\n\
 \n\
-Arguments: self - The Context object\n\
-           args - The Python argument tuple, should be:\n\
-             keyfile  - The name of the key file\n\
-             filetype - (optional) The encoding of the file, default is PEM\n\
-Returns:   None\n\
+@param keyfile: The name of the key file\n\
+@param filetype: (optional) The encoding of the file, default is PEM\n\
+@return: None\n\
 ";
 static PyObject *
 ssl_Context_use_privatekey_file(ssl_ContextObj *self, PyObject *args)
@@ -525,7 +516,7 @@
 
     if (!ret)
     {
-        exception_from_error_queue();
+        exception_from_error_queue(ssl_Error);
         return NULL;
     }
     else
@@ -538,10 +529,8 @@
 static char ssl_Context_use_privatekey_doc[] = "\n\
 Load a private key from a PKey object\n\
 \n\
-Arguments: self - The Context object\n\
-           args - The Python argument tuple, should be:\n\
-             pkey - The PKey object\n\
-Returns:   None\n\
+@param pkey: The PKey object\n\
+@return: None\n\
 ";
 static PyObject *
 ssl_Context_use_privatekey(ssl_ContextObj *self, PyObject *args)
@@ -561,7 +550,7 @@
 	if (!PyArg_ParseTuple(args, "O:use_privatekey", &pkey))
 	    return NULL;
 
-	if (strcmp(pkey->ob_type->tp_name, "PKey") != 0 ||
+	if (strcmp(pkey->ob_type->tp_name, "OpenSSL.crypto.PKey") != 0 ||
 	    pkey->ob_type->tp_basicsize != sizeof(crypto_PKeyObj))
 	{
 	    PyErr_SetString(PyExc_TypeError, "Expected a PKey object");
@@ -576,7 +565,7 @@
 
     if (!SSL_CTX_use_PrivateKey(self->ctx, pkey->pkey))
     {
-        exception_from_error_queue();
+        exception_from_error_queue(ssl_Error);
         return NULL;
     }
     else
@@ -589,9 +578,7 @@
 static char ssl_Context_check_privatekey_doc[] = "\n\
 Check that the private key and certificate match up\n\
 \n\
-Arguments: self - The Context object\n\
-           args - The Python argument tuple, should be empty\n\
-Returns:   None (raises an exception if something's wrong)\n\
+@return: None (raises an exception if something's wrong)\n\
 ";
 static PyObject *
 ssl_Context_check_privatekey(ssl_ContextObj *self, PyObject *args)
@@ -601,7 +588,7 @@
 
     if (!SSL_CTX_check_private_key(self->ctx))
     {
-        exception_from_error_queue();
+        exception_from_error_queue(ssl_Error);
         return NULL;
     }
     else
@@ -615,10 +602,8 @@
 Load the trusted certificates that will be sent to the client (basically\n\
 telling the client \"These are the guys I trust\")\n\
 \n\
-Arguments: self - The Context object\n\
-           args - The Python argument tuple, should be:\n\
-             cafile - The name of the certificates file\n\
-Returns:   None\n\
+@param cafile: The name of the certificates file\n\
+@return: None\n\
 ";
 static PyObject *
 ssl_Context_load_client_ca(ssl_ContextObj *self, PyObject *args)
@@ -638,10 +623,8 @@
 Set the session identifier, this is needed if you want to do session\n\
 resumption (which, ironically, isn't implemented yet)\n\
 \n\
-Arguments: self - The Context object\n\
-           args - The Python argument tuple, should be:\n\
-             buf - A Python object that can be safely converted to a string\n\
-Returns:   None\n\
+@param buf: A Python object that can be safely converted to a string\n\
+@returns: None\n\
 ";
 static PyObject *
 ssl_Context_set_session_id(ssl_ContextObj *self, PyObject *args)
@@ -654,7 +637,7 @@
 
     if (!SSL_CTX_set_session_id_context(self->ctx, buf, len))
     {
-        exception_from_error_queue();
+        exception_from_error_queue(ssl_Error);
         return NULL;
     }
     else
@@ -667,12 +650,10 @@
 static char ssl_Context_set_verify_doc[] = "\n\
 Set the verify mode and verify callback\n\
 \n\
-Arguments: self - The Context object\n\
-           args - The Python argument tuple, should be:\n\
-             mode     - The verify mode, this is either VERIFY_NONE or\n\
-                        VERIFY_PEER combined with possible other flags\n\
-             callback - The Python callback to use\n\
-Returns:   None\n\
+@param mode: The verify mode, this is either VERIFY_NONE or\n\
+             VERIFY_PEER combined with possible other flags\n\
+@param callback: The Python callback to use\n\
+@return: None\n\
 \n\
 See SSL_CTX_set_verify(3SSL) for further details.\n\
 ";
@@ -703,10 +684,8 @@
 static char ssl_Context_set_verify_depth_doc[] = "\n\
 Set the verify depth\n\
 \n\
-Arguments: self - The Context object\n\
-           args - The Python argument tuple, should be:\n\
-             depth - An integer specifying the verify depth\n\
-Returns:   None\n\
+@param depth: An integer specifying the verify depth\n\
+@return: None\n\
 ";
 static PyObject *
 ssl_Context_set_verify_depth(ssl_ContextObj *self, PyObject *args)
@@ -724,9 +703,7 @@
 static char ssl_Context_get_verify_mode_doc[] = "\n\
 Get the verify mode\n\
 \n\
-Arguments: self - The Context object\n\
-           args - The Python argument tuple, should be empty\n\
-Returns:   The verify mode\n\
+@return: The verify mode\n\
 ";
 static PyObject *
 ssl_Context_get_verify_mode(ssl_ContextObj *self, PyObject *args)
@@ -743,9 +720,7 @@
 static char ssl_Context_get_verify_depth_doc[] = "\n\
 Get the verify depth\n\
 \n\
-Arguments: self - The Context object\n\
-           args - The Python argument tuple, should be empty\n\
-Returns:   The verify depth\n\
+@return: The verify depth\n\
 ";
 static PyObject *
 ssl_Context_get_verify_depth(ssl_ContextObj *self, PyObject *args)
@@ -762,10 +737,8 @@
 static char ssl_Context_load_tmp_dh_doc[] = "\n\
 Load parameters for Ephemeral Diffie-Hellman\n\
 \n\
-Arguments: self - The Context object\n\
-           args - The Python argument tuple, should be:\n\
-             dhfile - The file to load EDH parameters from\n\
-Returns:   None\n\
+@param dhfile: The file to load EDH parameters from\n\
+@return: None\n\
 ";
 static PyObject *
 ssl_Context_load_tmp_dh(ssl_ContextObj *self, PyObject *args)
@@ -793,10 +766,8 @@
 static char ssl_Context_set_cipher_list_doc[] = "\n\
 Change the cipher list\n\
 \n\
-Arguments: self - The Context object\n\
-           args - The Python argument tuple, should be:\n\
-             cipher_list - A cipher list, see ciphers(1)\n\
-Returns:   None\n\
+@param cipher_list: A cipher list, see ciphers(1)\n\
+@return: None\n\
 ";
 static PyObject *
 ssl_Context_set_cipher_list(ssl_ContextObj *self, PyObject *args)
@@ -808,7 +779,7 @@
 
     if (!SSL_CTX_set_cipher_list(self->ctx, cipher_list))
     {
-        exception_from_error_queue();
+        exception_from_error_queue(ssl_Error);
         return NULL;
     }
     else
@@ -821,10 +792,8 @@
 static char ssl_Context_set_timeout_doc[] = "\n\
 Set session timeout\n\
 \n\
-Arguments: self - The Context object\n\
-           args - The Python argument tuple, should be:\n\
-             t - The timeout in seconds\n\
-Returns:   The previous session timeout\n\
+@param timeout: The timeout in seconds\n\
+@return: The previous session timeout\n\
 ";
 static PyObject *
 ssl_Context_set_timeout(ssl_ContextObj *self, PyObject *args)
@@ -841,9 +810,7 @@
 static char ssl_Context_get_timeout_doc[] = "\n\
 Get the session timeout\n\
 \n\
-Arguments: self - The Context object\n\
-           args - The Python argument tuple, should be empty\n\
-Returns:   The session timeout\n\
+@return: The session timeout\n\
 ";
 static PyObject *
 ssl_Context_get_timeout(ssl_ContextObj *self, PyObject *args)
@@ -860,10 +827,8 @@
 static char ssl_Context_set_info_callback_doc[] = "\n\
 Set the info callback\n\
 \n\
-Arguments: self - The Context object\n\
-           args - The Python argument tuple, should be:\n\
-             callback - The Python callback to use\n\
-Returns:   None\n\
+@param callback: The Python callback to use\n\
+@return: None\n\
 ";
 static PyObject *
 ssl_Context_set_info_callback(ssl_ContextObj *self, PyObject *args)
@@ -891,9 +856,7 @@
 static char ssl_Context_get_app_data_doc[] = "\n\
 Get the application data (supplied via set_app_data())\n\
 \n\
-Arguments: self - The Context object\n\
-           args - The Python argument tuple, should be empty\n\
-Returns:   The application data\n\
+@return: The application data\n\
 ";
 static PyObject *
 ssl_Context_get_app_data(ssl_ContextObj *self, PyObject *args)
@@ -908,10 +871,8 @@
 static char ssl_Context_set_app_data_doc[] = "\n\
 Set the application data (will be returned from get_app_data())\n\
 \n\
-Arguments: self - The Context object\n\
-           args - The Python argument tuple, should be:\n\
-             data - Any Python object\n\
-Returns:   None\n\
+@param data: Any Python object\n\
+@return: None\n\
 ";
 static PyObject *
 ssl_Context_set_app_data(ssl_ContextObj *self, PyObject *args)
@@ -932,9 +893,7 @@
 static char ssl_Context_get_cert_store_doc[] = "\n\
 Get the certificate store for the context\n\
 \n\
-Arguments: self - The Context object\n\
-           args - The Python argument tuple, should be empty\n\
-Returns:   A X509Store object\n\
+@return: A X509Store object\n\
 ";
 static PyObject *
 ssl_Context_get_cert_store(ssl_ContextObj *self, PyObject *args)
@@ -958,10 +917,8 @@
 static char ssl_Context_set_options_doc[] = "\n\
 Add options. Options set before are not cleared!\n\
 \n\
-Arguments: self - The Context object\n\
-           args - The Python argument tuple, should be:\n\
-             options - The options to add.\n\
-Returns:   The new option bitmask.\n\
+@param options: The options to add.\n\
+@return: The new option bitmask.\n\
 ";
 static PyObject *
 ssl_Context_set_options(ssl_ContextObj *self, PyObject *args)
@@ -1014,38 +971,33 @@
 };
 #undef ADD_METHOD
 
-
-/* Constructor, takes an int specifying which method to use */
 /*
- * Constructor for Context objects
- *
- * Arguments: i_method - The SSL method to use, one of the SSLv2_METHOD,
- *                       SSLv3_METHOD, SSLv23_METHOD and TLSv1_METHOD
- *                       constants.
- * Returns:   The newly created Context object
+ * Despite the name which might suggest otherwise, this is not the tp_init for
+ * the Context type.  It's just the common initialization code shared by the
+ * two _{Nn}ew functions below.
  */
-ssl_ContextObj *
-ssl_Context_New(int i_method)
-{
+static ssl_ContextObj*
+ssl_Context_init(ssl_ContextObj *self, int i_method) {
     SSL_METHOD *method;
-    ssl_ContextObj *self;
 
-    switch (i_method)
-    {
-        /* Too bad TLSv1 servers can't accept SSLv3 clients */
-        case ssl_SSLv2_METHOD:    method = SSLv2_method();  break;
-        case ssl_SSLv23_METHOD:   method = SSLv23_method(); break;
-        case ssl_SSLv3_METHOD:    method = SSLv3_method();  break;
-        case ssl_TLSv1_METHOD:    method = TLSv1_method();  break;
+    switch (i_method) {
+        case ssl_SSLv2_METHOD:
+            method = SSLv2_method();
+            break;
+        case ssl_SSLv23_METHOD:
+            method = SSLv23_method();
+            break;
+        case ssl_SSLv3_METHOD:
+            method = SSLv3_method();
+            break;
+        case ssl_TLSv1_METHOD:
+            method = TLSv1_method();
+            break;
         default:
             PyErr_SetString(PyExc_ValueError, "No such protocol");
             return NULL;
     }
 
-    self = PyObject_GC_New(ssl_ContextObj, &ssl_Context_Type);
-    if (self == NULL)
-        return (ssl_ContextObj *)PyErr_NoMemory();
-
     self->ctx = SSL_CTX_new(method);
     Py_INCREF(Py_None);
     self->passphrase_callback = Py_None;
@@ -1067,23 +1019,46 @@
                                 SSL_MODE_AUTO_RETRY);
 
     self->tstate = NULL;
-    PyObject_GC_Track((PyObject *)self);
 
     return self;
 }
 
 /*
- * Find attribute
- *
- * Arguments: self - The Context object
- *            name - The attribute name
- * Returns:   A Python object for the attribute, or NULL if something went
- *            wrong
+ * This one is exposed in the CObject API.  I want to deprecate it.
  */
-static PyObject *
-ssl_Context_getattr(ssl_ContextObj *self, char *name)
-{
-    return Py_FindMethod(ssl_Context_methods, (PyObject *)self, name);
+ssl_ContextObj*
+ssl_Context_New(int i_method) {
+    ssl_ContextObj *self;
+
+    self = PyObject_GC_New(ssl_ContextObj, &ssl_Context_Type);
+    if (self == NULL) {
+       return (ssl_ContextObj *)PyErr_NoMemory();
+    }
+    self = ssl_Context_init(self, i_method);
+    PyObject_GC_Track((PyObject *)self);
+    return self;
+}
+
+
+/*
+ * This one is the tp_new of the Context type.  It's great.
+ */
+static PyObject*
+ssl_Context_new(PyTypeObject *subtype, PyObject *args, PyObject *kwargs) {
+    int i_method;
+    ssl_ContextObj *self;
+    static char *kwlist[] = {"method", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i:Context", kwlist, &i_method)) {
+        return NULL;
+    }
+
+    self = (ssl_ContextObj *)subtype->tp_alloc(subtype, 1);
+    if (self == NULL) {
+        return NULL;
+    }
+
+    return (PyObject *)ssl_Context_init(self, i_method);
 }
 
 /*
@@ -1154,12 +1129,12 @@
 PyTypeObject ssl_Context_Type = {
     PyObject_HEAD_INIT(NULL)
     0,
-    "Context",
+    "OpenSSL.SSL.Context",
     sizeof(ssl_ContextObj),
     0,
-    (destructor)ssl_Context_dealloc,
+    (destructor)ssl_Context_dealloc, /* tp_dealloc */
     NULL, /* print */
-    (getattrfunc)ssl_Context_getattr,
+    NULL, /* tp_getattr */
     NULL, /* setattr */
     NULL, /* compare */
     NULL, /* repr */
@@ -1172,26 +1147,48 @@
     NULL, /* getattro */
     NULL, /* setattro */
     NULL, /* as_buffer */
-    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
-    NULL, /* doc */
-    (traverseproc)ssl_Context_traverse,
-    (inquiry)ssl_Context_clear,
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE, /* tp_flags */
+    ssl_Context_doc, /* tp_doc */
+    (traverseproc)ssl_Context_traverse, /* tp_traverse */
+    (inquiry)ssl_Context_clear, /* tp_clear */
+    NULL, /* tp_richcompare */
+    0, /* tp_weaklistoffset */
+    NULL, /* tp_iter */
+    NULL, /* tp_iternext */
+    ssl_Context_methods, /* tp_methods */
+    NULL, /* tp_members */
+    NULL, /* tp_getset */
+    NULL, /* tp_base */
+    NULL, /* tp_dict */
+    NULL, /* tp_descr_get */
+    NULL, /* tp_descr_set */
+    0, /* tp_dictoffset */
+    NULL, /* tp_init */
+    NULL, /* tp_alloc */
+    ssl_Context_new, /* tp_new */
 };
 
 
 /*
  * Initialize the Context part of the SSL sub module
  *
- * Arguments: dict - Dictionary of the OpenSSL.SSL module
+ * Arguments: dict - The OpenSSL.SSL module
  * Returns:   1 for success, 0 otherwise
  */
 int
-init_ssl_context(PyObject *dict)
-{
-    ssl_Context_Type.ob_type = &PyType_Type;
-    Py_INCREF(&ssl_Context_Type);
-    if (PyDict_SetItemString(dict, "ContextType", (PyObject *)&ssl_Context_Type) != 0)
+init_ssl_context(PyObject *module) {
+
+    if (PyType_Ready(&ssl_Context_Type) < 0) {
         return 0;
+    }
+
+    if (PyModule_AddObject(module, "Context", (PyObject *)&ssl_Context_Type) < 0) {
+        return 0;
+    }
+
+    if (PyModule_AddObject(module, "ContextType", (PyObject *)&ssl_Context_Type) < 0) {
+        return 0;
+    }
 
     return 1;
 }
diff --git a/src/ssl/ssl.c b/src/ssl/ssl.c
index f1c51aa..94d4844 100644
--- a/src/ssl/ssl.c
+++ b/src/ssl/ssl.c
@@ -42,55 +42,9 @@
          *ssl_WantX509LookupError,     /* ...                     */
          *ssl_SysCallError;            /* Uses (errno,errstr)     */
 
-static char ssl_Context_doc[] = "\n\
-The factory function inserted in the module dictionary to create Context\n\
-objects\n\
-\n\
-Arguments: spam - Always NULL\n\
-           args - The Python argument tuple, should be:\n\
-             method - The SSL method to use\n\
-Returns:   The Context object\n\
-";
-
-static PyObject *
-ssl_Context(PyObject *spam, PyObject *args)
-{
-    int method;
-
-    if (!PyArg_ParseTuple(args, "i:Context", &method))
-        return NULL;
-
-    return (PyObject *)ssl_Context_New(method);
-}
-
-static char ssl_Connection_doc[] = "\n\
-The factory function inserted in the module dictionary to create Connection\n\
-objects\n\
-\n\
-Arguments: spam - Always NULL\n\
-           args - The Python argument tuple, should be:\n\
-             ctx  - An SSL Context to use for this connection\n\
-             sock - The socket to use for transport layer\n\
-Returns:   The Connection object\n\
-";
-
-static PyObject *
-ssl_Connection(PyObject *spam, PyObject *args)
-{
-    ssl_ContextObj *ctx;
-    PyObject *sock;
-
-    if (!PyArg_ParseTuple(args, "O!O:Connection", &ssl_Context_Type, &ctx, &sock))
-        return NULL;
-
-    return (PyObject *)ssl_Connection_New(ctx, sock);
-}
-
 
 /* Methods in the OpenSSL.SSL module */
 static PyMethodDef ssl_methods[] = {
-    { "Context",        ssl_Context,    METH_VARARGS, ssl_Context_doc },
-    { "Connection",     ssl_Connection, METH_VARARGS, ssl_Connection_doc },
     { NULL, NULL }
 };
 
@@ -105,15 +59,16 @@
 {
     static void *ssl_API[ssl_API_pointers];
     PyObject *ssl_api_object;
-    PyObject *module, *dict;
+    PyObject *module;
 
     SSL_library_init();
     ERR_load_SSL_strings();
 
     import_crypto();
 
-    if ((module = Py_InitModule3("SSL", ssl_methods, ssl_doc)) == NULL)
+    if ((module = Py_InitModule3("SSL", ssl_methods, ssl_doc)) == NULL) {
         return;
+    }
 
     /* Initialize the C API pointer array */
     ssl_API[ssl_Context_New_NUM]    = (void *)ssl_Context_New;
@@ -210,10 +165,9 @@
     PyModule_AddIntConstant(module, "SENT_SHUTDOWN", SSL_SENT_SHUTDOWN);
     PyModule_AddIntConstant(module, "RECEIVED_SHUTDOWN", SSL_RECEIVED_SHUTDOWN);
 
-    dict = PyModule_GetDict(module);
-    if (!init_ssl_context(dict))
+    if (!init_ssl_context(module))
         goto error;
-    if (!init_ssl_connection(dict))
+    if (!init_ssl_connection(module))
         goto error;
 
 #ifdef WITH_THREAD
diff --git a/src/ssl/ssl.h b/src/ssl/ssl.h
index 9cf0186..ba7ba8b 100644
--- a/src/ssl/ssl.h
+++ b/src/ssl/ssl.h
@@ -27,15 +27,6 @@
                 *ssl_WantX509LookupError, /* ...                     */
                 *ssl_SysCallError;        /* Uses (errno,errstr)     */
 
-#ifdef exception_from_error_queue
-#  undef exception_from_error_queue
-#endif
-#define exception_from_error_queue()    do { \
-    PyObject *errlist = error_queue_to_list(); \
-    PyErr_SetObject(ssl_Error, errlist); \
-    Py_DECREF(errlist); \
-} while (0)
-
 #define ssl_Context_New_NUM       0
 #define ssl_Context_New_RETURN    ssl_ContextObj *
 #define ssl_Context_New_PROTO     (int method)
diff --git a/src/util.c b/src/util.c
index aa9d238..ae6ee5e 100644
--- a/src/util.c
+++ b/src/util.c
@@ -2,6 +2,7 @@
  * util.c
  *
  * Copyright (C) AB Strakt 2001, All rights reserved
+ * Copyright (C) Jean-Paul Calderone 2009, All rights reserved
  *
  * Utility functions.
  * See the file RATIONALE for a short explanation of why this module was written.
@@ -19,15 +20,13 @@
  * Returns:   A list of errors (new reference)
  */
 PyObject *
-error_queue_to_list(void)
-{
+error_queue_to_list(void) {
     PyObject *errlist, *tuple;
     long err;
 
     errlist = PyList_New(0);
 
-    while ((err = ERR_get_error()) != 0)
-    {
+    while ((err = ERR_get_error()) != 0) {
 	tuple = Py_BuildValue("(sss)", ERR_lib_error_string(err),
 		                       ERR_func_error_string(err),
 				       ERR_reason_error_string(err));
@@ -38,6 +37,12 @@
     return errlist;
 }
 
+void exception_from_error_queue(PyObject *the_Error) { 
+    PyObject *errlist = error_queue_to_list();
+    PyErr_SetObject(the_Error, errlist);
+    Py_DECREF(errlist);
+} 
+
 /*
  * Flush OpenSSL's error queue and ignore the result
  *
@@ -45,8 +50,12 @@
  * Returns:   None
  */
 void
-flush_error_queue(void)
-{
-    Py_DECREF(error_queue_to_list());
+flush_error_queue(void) {
+    /*
+     * Make sure to save the errors to a local.  Py_DECREF might expand such
+     * that it evaluates its argument more than once, which would lead to
+     * very nasty things if we just invoked it with error_queue_to_list().
+     */
+    PyObject *list = error_queue_to_list();
+    Py_DECREF(list);
 }
-
diff --git a/src/util.h b/src/util.h
index 1774956..d9dc7d2 100644
--- a/src/util.h
+++ b/src/util.h
@@ -23,6 +23,7 @@
 #include "pymemcompat.h"
 
 extern  PyObject *error_queue_to_list(void);
+extern void exception_from_error_queue(PyObject *the_Error);
 extern  void      flush_error_queue(void);
 
 /*
diff --git a/test/test_crypto.py b/test/test_crypto.py
index 87e9048..fce2441 100644
--- a/test/test_crypto.py
+++ b/test/test_crypto.py
@@ -4,8 +4,10 @@
 Unit tests for L{OpenSSL.crypto}.
 """
 
-from unittest import TestCase, main
+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
@@ -15,6 +17,10 @@
 from OpenSSL.crypto import FILETYPE_PEM, FILETYPE_ASN1, FILETYPE_TEXT
 from OpenSSL.crypto import dump_certificate, load_certificate_request
 from OpenSSL.crypto import dump_certificate_request, dump_privatekey
+from OpenSSL.crypto import PKCS7Type, load_pkcs7_data
+from OpenSSL.crypto import PKCS12Type, load_pkcs12
+from OpenSSL.crypto import NetscapeSPKI, NetscapeSPKIType
+from OpenSSL.test.util import TestCase
 
 
 cleartextCertificatePEM = """-----BEGIN CERTIFICATE-----
@@ -88,19 +94,124 @@
 """
 encryptedPrivateKeyPEMPassphrase = "foobar"
 
+# Some PKCS12 data, base64 encoded.  The data itself was constructed using the
+# openssl command line:
+#
+#    openssl pkcs12 -export -in s.pem -out o.p12 -inkey s.pem -certfile s.pem
+#
+# With s.pem containing a private key and certificate.  The contents of the
+# generated file, o.p12, were then base64 encoded to produce this value.
+pkcs12Data = """\
+MIIJGQIBAzCCCN8GCSqGSIb3DQEHAaCCCNAEggjMMIIIyDCCBucGCSqGSIb3DQEHBqCCBtgwggbU
+AgEAMIIGzQYJKoZIhvcNAQcBMBwGCiqGSIb3DQEMAQYwDgQIdwchN+KDjC8CAggAgIIGoOh59lWQ
+vz7FB2ewPHduY3pBhJX1W7ioN1k2xAoelE04v30CvNNa0A8qIjk6U7WLRXL74jG1xPq+WcAUtNtk
+3ZfTaPTPR+q5xVNBZFHeKDirt7yherl8Xs16OEl0IgNpNHRLeHxi4JeBqkGReq1vkybus2ALyQ/B
+FgbrNJiaGpvUx64A3FnHKbT0pVIvsg5iqcpCQ2SDLeJnqKFuP/2+SE5WnNvM6SBG20HMNOR9+SM5
+tPETapeu7AFkJ03FY3OF+fllHnv8fyXXDkv7F1bX8P2q6wQSRK6DXq6DO1Qjqzmrrtk4Pq6Hne2x
+onN2Bx9yUR83tNn4bQWNDasbnQpdI3Fsgg6RS5+B7y9tw37nygyND9ME0NcCysDov5zIG84gsZHn
+3LDFQkP4M7iBscNCund18FNQomrqAmPvejos+OXMQlNd/la15UQgUqv33V91WIMNmDDt80eVdxp8
+0D4gCvIl3xPp0Lp1EwhXwQxmx7LS3Fj0yCaiBOVevqhp9uq0i5hhdPA4a/XyIAeuJCS07s21fAe3
+Ay3S7olg1DTtN9wSJL6C1wus3VDMicB82ZC4+wAbfheedseenA0ubMDj38JqHgUtb02jMb9Ff3QR
+Hj6qzv5nJIJjmCG+cBatMh775f/9y/7wuElZYjv/vPb9S4Oraxz3ZgLtkU15PVeLjFHsHWRnrhVC
+ORaDEdX42kXfTMTaDsqFPg10ZS4fb7kCqD+ef0U4nCB0pfKyDo3hyDxHxGMqEVwyhKrl2UKljmcz
+02AGKxf6SERGdApGX4ENSuEG8v37CJTnmf1Tvf+K3fcCwBWTVDjhCgyCYrqaR02r8ixjRCU47L7e
+fe0c6WcTIYcXwWPPwqk6lUm8jH/IFSohUxrGaLRsvtYMK5O1ss3fGnv5DysLoWRRHNsp9EqJ+nXP
+bC5KRS01M78twFHXyIVgML13sMwox3aMCADP4HAFisUTQjSq0LlrHHVSIdIz3dEC3jsIs2bRxaVE
+dGaMorvVhoCNucGtdXD778EHsPy6ierUd6LijOYGs+yxUKVdeSAHYiQqBB/0uwo5tqeUjc1xte4V
+7o68M0TnaeXZk6eJj8cy+Z7uvlKrEWG/d+yDp6ZrS/uuCUqlfakSUQVLwhpupRs6bOfbU9VWmuuW
+T/whDpJHkGRqz15d3K43wkF6gWx7tpnwps2boB3fjQVlQ20xJ+4QjYV6Yu/0dlhyU69/sZEHQXvL
+xdZsLwkjEHhGPoMkVSpSZF7mSgM4iI8nFkPbfNOSBGpW8GTYUQN+YI+GjQYwk2zGpB3Fhfc9lVuK
+QqlYUtGkj2UauO9diqS1rVOIQORJ49EmA0w0VJz6A3teklGRQvdfSiTdTmg+PcYtdllquni0MMJO
+3t7fpOnfmZRxvOx9J8WsLlz18uvq8+jDGs0InNFGxUf5v+iTBjY2ByzaMZDa84xqu6+cVuGcQGRu
+NJCpxWNOyfKrDnJ+TOg1/AV3dHiuBNeyOE6XkwzhfEH0TaAWvqtmqRFBIjhsMwkg9qooeJwWANUP
+fq+UxpR8M5UDMBEKcwk+paSLtzAL/Xznk2q9U2JKPrmcD79bSNafDZ33/5U05mGq3CmY5DVjoy+C
+qhbfIQssrNhWxN3yCtHDDOrXVwEb/DAKSIfVz07mRKP/9jW2aC3nmRSt8Gd+JYy4nNRFAcatIcoC
+IHB5rtEXdhHHfZsAaVPGPgfpeVGIK8FXZTSLYGSGHsjXAXG0xS9nXX/8mHyKP3SKd5/h1H9llYhh
+nXXBM7lY6W8A6wRmMmOTkHn5Ovi+mavWeCioKiGfqoUQDRow/PdfwVLUVhe1OTCx4G5F8mXLpIWp
+1wzrOqMfOGDKD+RCgz/5sqVzAvgj0LTttoRKGipJjVb5luaLZswKCtlemD9xRb8J/PRp/6YHvrxW
+2taIJyZPBmbiqXAIFCiwjnurnP9WK4h6ss+bwj8lY3fB8CPwRAyy2p7dpXeNFby0ZkWPlBqKEXgZ
+03uQ8mUGXrty5ha03z7Gzab3RqAUu7l21i4DBbZjcn8j5NPrc3cNVpbJMic/0NDvojI3pIqsQ3yv
+3JbYdkVzlmEmapHCgF/SGVkZMo28uoC1upZMHRvb4zIrRlj1CVlUxmQu00q8GudNBcPOrQVONt5+
+eBvxD/Dco26wHPusPieUMlkj9VP9FS24bdocKXOL7KHOnsZ5oLS1S4hA7l7wEtzfoRHt1M1x8UCQ
+hYcQEbZsOrxqmKlbgm0B6bBsdK0IxGNhgdtKHUCdxHYkpSEYLXwwggHZBgkqhkiG9w0BBwGgggHK
+BIIBxjCCAcIwggG+BgsqhkiG9w0BDAoBAqCCAYYwggGCMBwGCiqGSIb3DQEMAQMwDgQIZ+Y92Rjm
+N5cCAggABIIBYD2z0NOajj7NlnWDRO8hlRiDIo8UTZ3E2UjP4rSbKh7ZLGULHALuH+gcwD3814U7
+VukIkyhiE1VvqPMXb2m4VTCp9BE4oXda0S2Mao1nKxbeMTZ3GE3+C7HPIuTTNQnsnpspIctNAarC
+IIuhgSQmjdILrkmX0QjH5vrQFbdpcDDb/IRba13hws8FM2OrduM+MDEM6xkwiG3AGDgKEPYsd1Ai
+uP8EMX4dzZ9BvEJHaAynzSpUxWy13ntMxNfeIuOKAT9HNsHr0MQgDDpVEhRY26IAZhNFfjtWdAjI
+OiMxk3BjixMUof9i1Xh+4yQsrzLcBJazCyphtb6YvnorQQxWUnaQXWjmU4QS36ajuyOXgFf1Z3jk
+6CLztf6kq3rY4uQ7aQIUJjUcWP0dUGr6LLZRVYP4uL/N/QSasliQGhTxrjEHywyPqRQjKVgV9c6D
+ueHmII59hoZPA6a2cYpQnsuFoeAxJTAjBgkqhkiG9w0BCRUxFgQUVFyHPk/34xv0OdgMn18Sjffj
+7lcwMTAhMAkGBSsOAwIaBQAEFBxVa/flSZttaXvzg+oLJBqgUWuVBAh0s4gPVAEKHAICCAA=
+""".decode('base64')
 
-class _Python23TestCaseHelper:
-    # Python 2.3 compatibility.
-    def assertTrue(self, *a, **kw):
-        return self.failUnless(*a, **kw)
+# Some PKCS#7 stuff.  Generated with the openssl command line:
+#
+#    openssl crl2pkcs7 -inform pem -outform pem -certfile s.pem -nocrl
+#
+# with a certificate and key (but the key should be irrelevant) in s.pem
+pkcs7Data = """\
+-----BEGIN PKCS7-----
+MIIDNwYJKoZIhvcNAQcCoIIDKDCCAyQCAQExADALBgkqhkiG9w0BBwGgggMKMIID
+BjCCAm+gAwIBAgIBATANBgkqhkiG9w0BAQQFADB7MQswCQYDVQQGEwJTRzERMA8G
+A1UEChMITTJDcnlwdG8xFDASBgNVBAsTC00yQ3J5cHRvIENBMSQwIgYDVQQDExtN
+MkNyeXB0byBDZXJ0aWZpY2F0ZSBNYXN0ZXIxHTAbBgkqhkiG9w0BCQEWDm5ncHNA
+cG9zdDEuY29tMB4XDTAwMDkxMDA5NTEzMFoXDTAyMDkxMDA5NTEzMFowUzELMAkG
+A1UEBhMCU0cxETAPBgNVBAoTCE0yQ3J5cHRvMRIwEAYDVQQDEwlsb2NhbGhvc3Qx
+HTAbBgkqhkiG9w0BCQEWDm5ncHNAcG9zdDEuY29tMFwwDQYJKoZIhvcNAQEBBQAD
+SwAwSAJBAKy+e3dulvXzV7zoTZWc5TzgApr8DmeQHTYC8ydfzH7EECe4R1Xh5kwI
+zOuuFfn178FBiS84gngaNcrFi0Z5fAkCAwEAAaOCAQQwggEAMAkGA1UdEwQCMAAw
+LAYJYIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0G
+A1UdDgQWBBTPhIKSvnsmYsBVNWjj0m3M2z0qVTCBpQYDVR0jBIGdMIGagBT7hyNp
+65w6kxXlxb8pUU/+7Sg4AaF/pH0wezELMAkGA1UEBhMCU0cxETAPBgNVBAoTCE0y
+Q3J5cHRvMRQwEgYDVQQLEwtNMkNyeXB0byBDQTEkMCIGA1UEAxMbTTJDcnlwdG8g
+Q2VydGlmaWNhdGUgTWFzdGVyMR0wGwYJKoZIhvcNAQkBFg5uZ3BzQHBvc3QxLmNv
+bYIBADANBgkqhkiG9w0BAQQFAAOBgQA7/CqT6PoHycTdhEStWNZde7M/2Yc6BoJu
+VwnW8YxGO8Sn6UJ4FeffZNcYZddSDKosw8LtPOeWoK3JINjAk5jiPQ2cww++7QGG
+/g5NDjxFZNDJP1dGiLAxPW6JXwov4v0FmdzfLOZ01jDcgQQZqEpYlgpuI5JEWUQ9
+Ho4EzbYCOaEAMQA=
+-----END PKCS7-----
+"""
 
 
-    def assertFalse(self, *a, **kw):
-        return self.failIf(*a, **kw)
+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')
 
-class X509ExtTests(TestCase, _Python23TestCaseHelper):
+
     def test_construction(self):
         """
         L{X509Extension} accepts an extension type name, a critical flag,
@@ -160,14 +271,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)
 
-class PKeyTests(TestCase, _Python23TestCaseHelper):
+
+    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()
@@ -261,7 +480,7 @@
 
 
 
-class X509NameTests(TestCase, _Python23TestCaseHelper):
+class X509NameTests(TestCase):
     """
     Unit tests for L{OpenSSL.crypto.X509Name}.
     """
@@ -276,6 +495,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 (?)
@@ -476,7 +710,7 @@
 
 
 
-class X509ReqTests(TestCase, _PKeyInteractionTestsMixin, _Python23TestCaseHelper):
+class X509ReqTests(TestCase, _PKeyInteractionTestsMixin):
     """
     Tests for L{OpenSSL.crypto.X509Req}.
     """
@@ -487,6 +721,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.
@@ -530,7 +773,7 @@
 
 
 
-class X509Tests(TestCase, _PKeyInteractionTestsMixin, _Python23TestCaseHelper):
+class X509Tests(TestCase, _PKeyInteractionTestsMixin):
     """
     Tests for L{OpenSSL.crypto.X509}.
     """
@@ -543,6 +786,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}.
@@ -553,6 +805,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):
@@ -658,7 +914,7 @@
 
 
 
-class FunctionTests(TestCase, _Python23TestCaseHelper):
+class FunctionTests(TestCase):
     """
     Tests for free-functions in the L{OpenSSL.crypto} module.
     """
@@ -814,5 +1070,78 @@
         self.assertEqual(loadedKey.bits(), key.bits())
 
 
+    def test_load_pkcs7_data(self):
+        """
+        L{load_pkcs7_data} accepts a PKCS#7 string and returns an instance of
+        L{PKCS7Type}.
+        """
+        pkcs7 = load_pkcs7_data(FILETYPE_PEM, pkcs7Data)
+        self.assertTrue(isinstance(pkcs7, PKCS7Type))
+
+
+    def test_load_pkcs12(self):
+        """
+        L{load_pkcs12} accepts a PKCS#12 string and returns an instance of
+        L{PKCS12Type}.
+        """
+        pkcs12 = load_pkcs12(pkcs12Data)
+        self.assertTrue(isinstance(pkcs12, PKCS12Type))
+
+
+
+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}.
+        """
+        nspki = NetscapeSPKI()
+        self.assertTrue(isinstance(nspki, NetscapeSPKIType))
+
+
+
 if __name__ == '__main__':
     main()
diff --git a/test/test_rand.py b/test/test_rand.py
new file mode 100644
index 0000000..05bf8c8
--- /dev/null
+++ b/test/test_rand.py
@@ -0,0 +1,80 @@
+# Copyright (C) Frederick Dean 2009, All rights reserved
+
+"""
+Unit tests for L{OpenSSL.rand}.
+"""
+
+from unittest import main
+import os 
+import stat
+
+from OpenSSL.test.util import TestCase
+from OpenSSL import rand
+
+
+class RandTests(TestCase):
+    def test_bytes(self):
+        """
+        Verify that we can obtain bytes from rand_bytes() and
+        that they are different each time.  Test the parameter
+        of rand_bytes() for bad values.
+        """
+        b1 = rand.bytes(50)
+        self.assertEqual(len(b1), 50)
+        b2 = rand.bytes(num_bytes=50)  # parameter by name
+        self.assertNotEqual(b1, b2)  #  Hip, Hip, Horay! FIPS complaince
+        b3 = rand.bytes(num_bytes=0) 
+        self.assertEqual(len(b3), 0)
+        exc = self.assertRaises(ValueError, rand.bytes, -1)
+        self.assertEqual(str(exc), "num_bytes must not be negative")
+
+
+    def test_add(self):
+        """
+        L{OpenSSL.rand.add} adds entropy to the PRNG.
+        """
+        rand.add('hamburger', 3)
+
+
+    def test_seed(self):
+        """
+        L{OpenSSL.rand.seed} adds entropy to the PRNG.
+        """
+        rand.seed('milk shake')
+
+
+    def test_status(self):
+        """
+        L{OpenSSL.rand.status} returns C{True} if the PRNG has sufficient
+        entropy, C{False} otherwise.
+        """
+        # It's hard to know what it is actually going to return.  Different
+        # OpenSSL random engines decide differently whether they have enough
+        # entropy or not.
+        self.assertTrue(rand.status() in (1, 2))
+
+
+    def test_files(self):
+        """
+        Test reading and writing of files via rand functions.
+        """
+        # Write random bytes to a file 
+        tmpfile = self.mktemp()
+        # Make sure it exists (so cleanup definitely succeeds)
+        fObj = file(tmpfile, 'w')
+        fObj.close()
+        try:
+            rand.write_file(tmpfile)
+            # Verify length of written file
+            size = os.stat(tmpfile)[stat.ST_SIZE]
+            self.assertEquals(size, 1024)
+            # Read random bytes from file 
+            rand.load_file(tmpfile)
+            rand.load_file(tmpfile, 4)  # specify a length
+        finally:
+            # Cleanup
+            os.unlink(tmpfile)
+
+
+if __name__ == '__main__':
+    main()
diff --git a/test/test_ssl.py b/test/test_ssl.py
index 51ff5c7..bf28ca3 100644
--- a/test/test_ssl.py
+++ b/test/test_ssl.py
@@ -5,24 +5,18 @@
 """
 
 from sys import platform
-from tempfile import mktemp
 from socket import socket
 from os import makedirs, symlink
 from os.path import join
-
-try:
-    # Prefer Twisted's TestCase, since it supports things like skips.
-    from twisted.trial.unittest import TestCase
-except ImportError:
-    # Fall back to the stdlib TestCase though, since it kind of works.
-    from unittest import TestCase
+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.test_crypto import _Python23TestCaseHelper, cleartextCertificatePEM, cleartextPrivateKeyPEM
+from OpenSSL.test.util import TestCase
+from OpenSSL.test.test_crypto import cleartextCertificatePEM, cleartextPrivateKeyPEM
 try:
     from OpenSSL.SSL import OP_NO_QUERY_MTU
 except ImportError:
@@ -37,17 +31,40 @@
     OP_NO_TICKET = None
 
 
-class ContextTests(TestCase, _Python23TestCaseHelper):
+def socket_pair():
+    """
+    Establish and return a pair of network sockets connected to each other.
+    """
+    # Connect a pair of sockets
+    port = socket()
+    port.bind(('', 0))
+    port.listen(1)
+    client = socket()
+    client.setblocking(False)
+    client.connect_ex(port.getsockname())
+    client.setblocking(True)
+    server = port.accept()[0]
+
+    # Let's pass some unencrypted data to make sure our socket connection is
+    # fine.  Just one byte, so we don't have to worry about buffers getting
+    # filled up or fragmentation.
+    server.send("x")
+    assert client.recv(1024) == "x"
+    client.send("y")
+    assert server.recv(1024) == "y"
+
+    # All our callers want non-blocking sockets, make it easy for them.
+    server.setblocking(False)
+    client.setblocking(False)
+
+    return (server, client)
+
+
+
+class ContextTests(TestCase):
     """
     Unit tests for L{OpenSSL.SSL.Context}.
     """
-    def mktemp(self):
-        """
-        Pathetic substitute for twisted.trial.unittest.TestCase.mktemp.
-        """
-        return mktemp(dir=".")
-
-
     def test_method(self):
         """
         L{Context} can be instantiated with one of L{SSLv2_METHOD},
@@ -59,6 +76,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.
@@ -101,13 +127,7 @@
         L{Context.set_info_callback} accepts a callable which will be invoked
         when certain information about an SSL connection is available.
         """
-        port = socket()
-        port.bind(('', 0))
-        port.listen(1)
-
-        client = socket()
-        client.setblocking(False)
-        client.connect_ex(port.getsockname())
+        (server, client) = socket_pair()
 
         clientSSL = Connection(Context(TLSv1_METHOD), client)
         clientSSL.set_connect_state()
@@ -122,9 +142,6 @@
         context.use_privatekey(
             load_privatekey(FILETYPE_PEM, cleartextPrivateKeyPEM))
 
-        server, ignored = port.accept()
-        server.setblocking(False)
-
         serverSSL = Connection(context, server)
         serverSSL.set_accept_state()
 
@@ -140,13 +157,7 @@
 
 
     def _load_verify_locations_test(self, *args):
-        port = socket()
-        port.bind(('', 0))
-        port.listen(1)
-
-        client = socket()
-        client.setblocking(False)
-        client.connect_ex(port.getsockname())
+        (server, client) = socket_pair()
 
         clientContext = Context(TLSv1_METHOD)
         clientContext.load_verify_locations(*args)
@@ -159,9 +170,6 @@
         clientSSL = Connection(clientContext, client)
         clientSSL.set_connect_state()
 
-        server, _ = port.accept()
-        server.setblocking(False)
-
         serverContext = Context(TLSv1_METHOD)
         serverContext.use_certificate(
             load_certificate(FILETYPE_PEM, cleartextCertificatePEM))
@@ -272,6 +280,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}.
@@ -425,7 +461,11 @@
     """
     Tests for L{OpenSSL.SSL.Connection} using a memory BIO.
     """
-    def _server(self):
+    def _server(self, sock):
+        """
+        Create a new server-side SSL L{Connection} object wrapped around
+        C{sock}.
+        """
         # Create the server side Connection.  This is mostly setup boilerplate
         # - use TLSv1, use a particular certificate, etc.
         server_ctx = Context(TLSv1_METHOD)
@@ -436,15 +476,20 @@
         server_ctx.use_certificate(load_certificate(FILETYPE_PEM, server_cert_pem))
         server_ctx.check_privatekey()
         server_store.add_cert(load_certificate(FILETYPE_PEM, root_cert_pem))
-        # Here the Connection is actually created.  None is passed as the 2nd
-        # parameter, indicating a memory BIO should be created.
-        server_conn = Connection(server_ctx, None)
+        # Here the Connection is actually created.  If None is passed as the 2nd
+        # parameter, it indicates a memory BIO should be created.
+        server_conn = Connection(server_ctx, sock)
         server_conn.set_accept_state()
         return server_conn
 
 
-    def _client(self):
-        # Now create the client side Connection.  Similar boilerplate to the above.
+    def _client(self, sock):
+        """
+        Create a new client-side SSL L{Connection} object wrapped around
+        C{sock}.
+        """
+        # Now create the client side Connection.  Similar boilerplate to the
+        # above.
         client_ctx = Context(TLSv1_METHOD)
         client_ctx.set_options(OP_NO_SSLv2 | OP_NO_SSLv3 | OP_SINGLE_DH_USE )
         client_ctx.set_verify(VERIFY_PEER|VERIFY_FAIL_IF_NO_PEER_CERT|VERIFY_CLIENT_ONCE, verify_cb)
@@ -453,8 +498,7 @@
         client_ctx.use_certificate(load_certificate(FILETYPE_PEM, client_cert_pem))
         client_ctx.check_privatekey()
         client_store.add_cert(load_certificate(FILETYPE_PEM, root_cert_pem))
-        # Again, None to create a new memory BIO.
-        client_conn = Connection(client_ctx, None)
+        client_conn = Connection(client_ctx, sock)
         client_conn.set_connect_state()
         return client_conn
 
@@ -506,15 +550,15 @@
                         write.bio_write(dirty)
 
 
-    def test_connect(self):
+    def test_memoryConnect(self):
         """
         Two L{Connection}s which use memory BIOs can be manually connected by
         reading from the output of each and writing those bytes to the input of
         the other and in this way establish a connection and exchange
         application-level bytes with each other.
         """
-        server_conn = self._server()
-        client_conn = self._client()
+        server_conn = self._server(None)
+        client_conn = self._client(None)
 
         # There should be no key or nonces yet.
         self.assertIdentical(server_conn.master_key(), None)
@@ -530,8 +574,10 @@
         self.assertNotIdentical(server_conn.master_key(), None)
         self.assertNotIdentical(server_conn.client_random(), None)
         self.assertNotIdentical(server_conn.server_random(), None)
-        self.assertNotIdentical(server_conn.client_random(), client_conn.client_random())
-        self.assertNotIdentical(server_conn.server_random(), client_conn.server_random())
+        self.assertEquals(server_conn.client_random(), client_conn.client_random())
+        self.assertEquals(server_conn.server_random(), client_conn.server_random())
+        self.assertNotEquals(server_conn.client_random(), server_conn.server_random())
+        self.assertNotEquals(client_conn.client_random(), client_conn.server_random())
 
         # Here are the bytes we'll try to send.
         important_message = 'One if by land, two if by sea.'
@@ -547,6 +593,47 @@
             (server_conn, important_message[::-1]))
 
 
+    def test_socketConnect(self):
+        """
+        Just like L{test_memoryConnect} but with an actual socket.
+
+        This is primarily to rule out the memory BIO code as the source of
+        any problems encountered while passing data over a L{Connection} (if
+        this test fails, there must be a problem outside the memory BIO
+        code, as no memory BIO is involved here).  Even though this isn't a
+        memory BIO test, it's convenient to have it here.
+        """
+        (server, client) = socket_pair()
+
+        # Let the encryption begin...
+        client_conn = self._client(client)
+        server_conn = self._server(server)
+
+        # Establish the connection
+        established = False
+        while not established:
+            established = True  # assume the best
+            for ssl in client_conn, server_conn:
+                try:
+                    # Generally a recv() or send() could also work instead 
+                    # of do_handshake(), and we would stop on the first 
+                    # non-exception.
+                    ssl.do_handshake()
+                except WantReadError:
+                    established = False
+
+        important_message = "Help me Obi Wan Kenobi, you're my only hope."
+        client_conn.send(important_message)
+        msg = server_conn.recv(1024)
+        self.assertEqual(msg, important_message)
+
+        # Again in the other direction, just for fun.
+        important_message = important_message[::-1]
+        server_conn.send(important_message)
+        msg = client_conn.recv(1024)
+        self.assertEqual(msg, important_message)
+
+
     def test_socketOverridesMemory(self):
         """
         Test that L{OpenSSL.SSL.bio_read} and L{OpenSSL.SSL.bio_write} don't
@@ -567,8 +654,8 @@
         returned and that many bytes from the beginning of the input can be
         read from the other end of the connection.
         """
-        server = self._server()
-        client = self._client()
+        server = self._server(None)
+        client = self._client(None)
 
         self._loopback(client, server)
 
@@ -592,9 +679,14 @@
         L{Connection.bio_shutdown} signals the end of the data stream from
         which the L{Connection} reads.
         """
-        server = self._server()
+        server = self._server(None)
         server.bio_shutdown()
         e = self.assertRaises(Error, server.recv, 1024)
         # We don't want WantReadError or ZeroReturnError or anything - it's a
         # handshake failure.
         self.assertEquals(e.__class__, Error)
+
+
+
+if __name__ == '__main__':
+    main()
diff --git a/test/util.py b/test/util.py
new file mode 100644
index 0000000..d195d95
--- /dev/null
+++ b/test/util.py
@@ -0,0 +1,139 @@
+# Copyright (C) Jean-Paul Calderone 2009, All rights reserved
+# Copyright (c) 2001-2009 Twisted Matrix Laboratories.
+# See LICENSE for details.
+
+"""
+Helpers for the OpenSSL test suite, largely copied from
+U{Twisted<http://twistedmatrix.com/>}.
+"""
+
+import shutil
+import os, os.path
+from tempfile import mktemp
+from unittest import TestCase
+import sys
+
+from OpenSSL.crypto import Error, _exception_from_error_queue
+
+
+class TestCase(TestCase):
+    """
+    L{TestCase} adds useful testing functionality beyond what is available
+    from the standard library L{unittest.TestCase}.
+    """
+    def tearDown(self):
+        """
+        Clean up any files or directories created using L{TestCase.mktemp}.
+        Subclasses must invoke this method if they override it or the
+        cleanup will not occur.
+        """
+        if self._temporaryFiles is not None:
+            for temp in self._temporaryFiles:
+                if os.path.isdir(temp):
+                    shutil.rmtree(temp)
+                elif os.path.exists(temp):
+                    os.unlink(temp)
+        try:
+            _exception_from_error_queue()
+        except Error, e:
+            if e.args != ([],):
+                self.fail("Left over errors in OpenSSL error queue: " + repr(e))
+
+
+    def failUnlessIdentical(self, first, second, msg=None):
+        """
+        Fail the test if C{first} is not C{second}.  This is an
+        obect-identity-equality test, not an object equality
+        (i.e. C{__eq__}) test.
+
+        @param msg: if msg is None, then the failure message will be
+        '%r is not %r' % (first, second)
+        """
+        if first is not second:
+            raise self.failureException(msg or '%r is not %r' % (first, second))
+        return first
+    assertIdentical = failUnlessIdentical
+
+
+    def failIfIdentical(self, first, second, msg=None):
+        """
+        Fail the test if C{first} is C{second}.  This is an
+        obect-identity-equality test, not an object equality
+        (i.e. C{__eq__}) test.
+
+        @param msg: if msg is None, then the failure message will be
+        '%r is %r' % (first, second)
+        """
+        if first is second:
+            raise self.failureException(msg or '%r is %r' % (first, second))
+        return first
+    assertNotIdentical = failIfIdentical
+
+
+    def failUnlessRaises(self, exception, f, *args, **kwargs):
+        """
+        Fail the test unless calling the function C{f} with the given
+        C{args} and C{kwargs} raises C{exception}. The failure will report
+        the traceback and call stack of the unexpected exception.
+
+        @param exception: exception type that is to be expected
+        @param f: the function to call
+
+        @return: The raised exception instance, if it is of the given type.
+        @raise self.failureException: Raised if the function call does
+            not raise an exception or if it raises an exception of a
+            different type.
+        """
+        try:
+            result = f(*args, **kwargs)
+        except exception, inst:
+            return inst
+        except:
+            raise self.failureException('%s raised instead of %s'
+                                        % (sys.exc_info()[0],
+                                           exception.__name__,
+                                          ))
+        else:
+            raise self.failureException('%s not raised (%r returned)'
+                                        % (exception.__name__, result))
+    assertRaises = failUnlessRaises
+
+
+    _temporaryFiles = None
+    def mktemp(self):
+        """
+        Pathetic substitute for twisted.trial.unittest.TestCase.mktemp.
+        """
+        if self._temporaryFiles is None:
+            self._temporaryFiles = []
+        temp = mktemp(dir=".")
+        self._temporaryFiles.append(temp)
+        return temp
+
+
+    # Python 2.3 compatibility.
+    def assertTrue(self, *a, **kw):
+        return self.failUnless(*a, **kw)
+
+
+    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)