Add a bunch of tests which assert that extension types are defined nicely.
diff --git a/ChangeLog b/ChangeLog
index 197c472..d9d45f8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,28 @@
+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
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 cf69e0f..bd83d6d 100644
--- a/doc/pyOpenSSL.tex
+++ b/doc/pyOpenSSL.tex
@@ -188,8 +188,11 @@
 See \class{X509Extension}.
 \end{datadesc}
 
-\begin{classdesc}{X509Extension}{typename, critical, value}
-A class representing an X.509 v3 certificate extensions.
+\begin{classdesc}{X509Extension}{typename, critical, value\optional{, subject}\optional{, issuer}}
+A class representing an X.509 v3 certificate extensions.  
+See \url{http://openssl.org/docs/apps/x509v3_config.html\#STANDARD_EXTENSIONS} 
+for \var{typename} strings and their options.
+Optional parameters \var{subject} and \var{issuer} must be X509 objects.
 \end{classdesc}
 
 \begin{datadesc}{NetscapeSPKIType}
@@ -593,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}
@@ -624,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
@@ -725,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 645e459..06d477b 100755
--- a/setup.py
+++ b/setup.py
@@ -88,6 +88,7 @@
                      'OpenSSL.version', 'OpenSSL.test.__init__',
                      'OpenSSL.test.util',
                      'OpenSSL.test.test_crypto',
+                     'OpenSSL.test.test_rand',
                      'OpenSSL.test.test_ssl'],
       data_files = data_files,
       description = 'Python wrapper module around the OpenSSL library',
diff --git a/src/crypto/crypto.c b/src/crypto/crypto.c
index 2240df0..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.
@@ -112,7 +112,7 @@
 
     if (pkey == NULL)
     {
-        exception_from_error_queue();
+        exception_from_error_queue(crypto_Error);
         return NULL;
     }
 
@@ -213,7 +213,7 @@
     if (ret == 0)
     {
         BIO_free(bio);
-        exception_from_error_queue();
+        exception_from_error_queue(crypto_Error);
         return NULL;
     }
 
@@ -264,7 +264,7 @@
 
     if (cert == NULL)
     {
-        exception_from_error_queue();
+        exception_from_error_queue(crypto_Error);
         return NULL;
     }
 
@@ -316,7 +316,7 @@
     if (ret == 0)
     {
         BIO_free(bio);
-        exception_from_error_queue();
+        exception_from_error_queue(crypto_Error);
         return NULL;
     }
 
@@ -367,7 +367,7 @@
 
     if (req == NULL)
     {
-        exception_from_error_queue();
+        exception_from_error_queue(crypto_Error);
         return NULL;
     }
 
@@ -419,7 +419,7 @@
     if (ret == 0)
     {
         BIO_free(bio);
-        exception_from_error_queue();
+        exception_from_error_queue(crypto_Error);
         return NULL;
     }
 
@@ -475,7 +475,7 @@
      */
     if (pkcs7 == NULL)
     {
-        exception_from_error_queue();
+        exception_from_error_queue(crypto_Error);
         return NULL;
     }
 
@@ -506,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);
@@ -535,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 */
@@ -547,6 +558,7 @@
     { "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 },
     { "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 }
 };
 
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 d4255f0..4fa9d8d 100644
--- a/src/crypto/netscape_spki.c
+++ b/src/crypto/netscape_spki.c
@@ -57,7 +57,7 @@
         spki = NETSCAPE_SPKI_new();
     if (spki == NULL)
     {
-        exception_from_error_queue();
+        exception_from_error_queue(crypto_Error);
         return NULL;
     }
     return (PyObject *)crypto_NetscapeSPKI_New(spki, 1);
@@ -107,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;
     }
 
@@ -133,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;
     }
 
@@ -176,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;
     }
 
@@ -200,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;
     }
 
diff --git a/src/crypto/pkcs12.c b/src/crypto/pkcs12.c
index 71ebcdd..28ea2fe 100644
--- a/src/crypto/pkcs12.c
+++ b/src/crypto/pkcs12.c
@@ -110,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;
     }
 
diff --git a/src/crypto/pkey.c b/src/crypto/pkey.c
index 6632abe..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)
     
diff --git a/src/crypto/x509.c b/src/crypto/x509.c
index 119c048..e089d40 100644
--- a/src/crypto/x509.c
+++ b/src/crypto/x509.c
@@ -136,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 {
@@ -144,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);
@@ -221,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;
     }
 
@@ -273,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;
     }
 
@@ -299,7 +299,7 @@
 
     if ((pkey = X509_get_pubkey(self->x509)) == NULL)
     {
-        exception_from_error_queue();
+        exception_from_error_queue(crypto_Error);
         return NULL;
     }
 
@@ -327,7 +327,7 @@
 
     if (!X509_set_pubkey(self->x509, pkey->pkey))
     {
-        exception_from_error_queue();
+        exception_from_error_queue(crypto_Error);
         return NULL;
     }
 
@@ -422,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);
@@ -558,7 +558,7 @@
 
     if (!X509_sign(self->x509, pkey->pkey, digest))
     {
-        exception_from_error_queue();
+        exception_from_error_queue(crypto_Error);
         return NULL;
     }
 
@@ -629,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);
@@ -679,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;
         }
     }
diff --git a/src/crypto/x509ext.c b/src/crypto/x509ext.c
index cd169d2..90ef543 100644
--- a/src/crypto/x509ext.c
+++ b/src/crypto/x509ext.c
@@ -72,20 +72,44 @@
  * Arguments: type_name - ???
  *            critical  - ???
  *            value     - ???
+ *            subject   - An x509v3 certificate which is the subject for this extension.
+ *            issuer    - An x509v3 certificate which is the issuer for this extension.
  * Returns:   The newly created X509Extension object
  */
 crypto_X509ExtensionObj *
-crypto_X509Extension_New(char *type_name, int critical, char *value)
-{
+crypto_X509Extension_New(char *type_name, int critical, char *value,
+                         crypto_X509Obj *subject, crypto_X509Obj  *issuer) {
     X509V3_CTX ctx;
     crypto_X509ExtensionObj *self;
     char* value_with_critical = NULL;
 
-    /* We have no configuration database - but perhaps we should.  Anyhow, the
-     * context is necessary for any extension which uses the r2i conversion
-     * method.  That is, X509V3_EXT_nconf may segfault if passed a NULL ctx. */
+
+    /*
+     * A context is necessary for any extension which uses the r2i conversion
+     * method.  That is, X509V3_EXT_nconf may segfault if passed a NULL ctx.
+     * Start off by initializing most of the fields to NULL.
+     */
+    X509V3_set_ctx(&ctx, NULL, NULL, NULL, NULL, 0);
+
+    /*
+     * We have no configuration database - but perhaps we should (some
+     * extensions may require it).
+     */
     X509V3_set_ctx_nodb(&ctx);
 
+    /*
+     * Initialize the subject and issuer, if appropriate.  ctx is a local, and
+     * as far as I can tell none of the X509V3_* APIs invoked here steal any
+     * references, so no need to incref subject or issuer.
+     */
+    if (subject) {
+            ctx.subject_cert = subject->x509;
+    }
+
+    if (issuer) {
+            ctx.issuer_cert = issuer->x509;
+    }
+
     self = PyObject_New(crypto_X509ExtensionObj, &crypto_X509Extension_Type);
 
     if (self == NULL) {
@@ -126,7 +150,7 @@
     return self;
 
   nconf_error:
-    exception_from_error_queue();
+    exception_from_error_queue(crypto_Error);
 
   critical_malloc_error:
     Py_XDECREF(self);
@@ -137,27 +161,40 @@
 }
 
 static char crypto_X509Extension_doc[] = "\n\
-X509Extension(typename, critical, value) -> X509Extension instance\n\
+X509Extension(typename, critical, value[, subject][, issuer]) -> \n\
+                X509Extension instance\n\
 \n\
 @param typename: The name of the extension to create.\n\
 @type typename: C{str}\n\
 @param critical: A flag indicating whether this is a critical extension.\n\
 @param value: The value of the extension.\n\
 @type value: C{str}\n\
+@param subject: Optional X509 cert to use as subject.\n\
+@type subject: C{X509}\n\
+@param issuer: Optional X509 cert to use as issuer.\n\
+@type issuer: C{X509}\n\
 @return: The X509Extension object\n\
 ";
 
 static PyObject *
-crypto_X509Extension_new(PyTypeObject *subtype, PyObject *args, PyObject *kwargs) {
+crypto_X509Extension_new(PyTypeObject *subtype, PyObject *args,
+                         PyObject *kwargs) {
     char *type_name, *value;
-    int critical;
+    int critical = 0;
+    crypto_X509Obj * subject = NULL;
+    crypto_X509Obj * issuer = NULL;
+    static char *kwlist[] = {"type_name", "critical", "value", "subject",
+                             "issuer", NULL};
 
-    if (!PyArg_ParseTuple(args, "sis:X509Extension", &type_name, &critical,
-                          &value)) {
+    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sis|O!O!:X509Extension",
+                                     kwlist, &type_name, &critical, &value,
+                                     &crypto_X509_Type, &subject,
+                                     &crypto_X509_Type, &issuer )) {
         return NULL;
     }
 
-    return (PyObject *)crypto_X509Extension_New(type_name, critical, value);
+    return (PyObject *)crypto_X509Extension_New(type_name, critical, value,
+                                                subject, issuer);
 }
 
 /*
@@ -204,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;
     }
 
diff --git a/src/crypto/x509name.c b/src/crypto/x509name.c
index 5d49430..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.
@@ -88,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;
     }
 
@@ -129,7 +129,7 @@
 				    (unsigned char *)utf8string,
 				    -1, -1, 0))
     {
-        exception_from_error_queue();
+        exception_from_error_queue(crypto_Error);
         return -1;
     }
     return 0;
@@ -153,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);
     }
 
@@ -236,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
diff --git a/src/crypto/x509req.c b/src/crypto/x509req.c
index a1325e9..07bd44b 100644
--- a/src/crypto/x509req.c
+++ b/src/crypto/x509req.c
@@ -30,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) {
@@ -58,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;
     }
 
@@ -86,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;
     }
 
@@ -131,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;
     }
 
@@ -160,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;
     }
 
@@ -194,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;
     }
 
@@ -217,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;
     }
 
diff --git a/src/crypto/x509store.c b/src/crypto/x509store.c
index 9f46029..16af3b0 100644
--- a/src/crypto/x509store.c
+++ b/src/crypto/x509store.c
@@ -27,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;
     }
 
diff --git a/src/rand/rand.c b/src/rand/rand.c
index f1c8440..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\
@@ -188,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[] = {
@@ -201,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 }
 };
 
@@ -220,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 a5fdc51..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;
     }
 }
@@ -788,7 +788,7 @@
 
     if (ret < 0)
     {
-        exception_from_error_queue();
+        exception_from_error_queue(ssl_Error);
         return NULL;
     }
     else if (ret > 0)
diff --git a/src/ssl/context.c b/src/ssl/context.c
index ae669d0..df7411f 100644
--- a/src/ssl/context.c
+++ b/src/ssl/context.c
@@ -265,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
@@ -291,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);
@@ -388,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
@@ -422,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
@@ -451,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
@@ -478,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
@@ -516,7 +516,7 @@
 
     if (!ret)
     {
-        exception_from_error_queue();
+        exception_from_error_queue(ssl_Error);
         return NULL;
     }
     else
@@ -565,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
@@ -588,7 +588,7 @@
 
     if (!SSL_CTX_check_private_key(self->ctx))
     {
-        exception_from_error_queue();
+        exception_from_error_queue(ssl_Error);
         return NULL;
     }
     else
@@ -637,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
@@ -779,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
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 6d88ec1..fce2441 100644
--- a/test/test_crypto.py
+++ b/test/test_crypto.py
@@ -7,6 +7,7 @@
 from unittest import main
 
 from os import popen2
+from datetime import datetime, timedelta
 
 from OpenSSL.crypto import TYPE_RSA, TYPE_DSA, Error, PKey, PKeyType
 from OpenSSL.crypto import X509, X509Type, X509Name, X509NameType
@@ -173,8 +174,44 @@
 """
 
 
-
 class X509ExtTests(TestCase):
+    """
+    Tests for L{OpenSSL.crypto.X509Extension}.
+    """
+
+    def setUp(self):
+        """
+        Create a new private key and start a certificate request (for a test
+        method to finish in one way or another).
+        """
+        # Basic setup stuff to generate a certificate
+        self.pkey = PKey()
+        self.pkey.generate_key(TYPE_RSA, 384)
+        self.req = X509Req()
+        self.req.set_pubkey(self.pkey)
+        # Authority good you have.
+        self.req.get_subject().commonName = "Yoda root CA"
+        self.x509 = X509()
+        self.subject = self.x509.get_subject()
+        self.subject.commonName = self.req.get_subject().commonName
+        self.x509.set_issuer(self.subject)
+        self.x509.set_pubkey(self.pkey)
+        now = datetime.now().strftime("%Y%m%d%H%M%SZ")
+        expire  = (datetime.now() + timedelta(days=100)).strftime("%Y%m%d%H%M%SZ")
+        self.x509.set_notBefore(now)
+        self.x509.set_notAfter(expire)
+
+
+    def test_type(self):
+        """
+        L{X509Extension} and L{X509ExtensionType} refer to the same type object
+        and can be used to create instances of that type.
+        """
+        self.assertIdentical(X509Extension, X509ExtensionType)
+        self.assertConsistentType(
+            X509Extension, 'X509Extension', 'basicConstraints', True, 'CA:true')
+
+
     def test_construction(self):
         """
         L{X509Extension} accepts an extension type name, a critical flag,
@@ -191,10 +228,6 @@
             isinstance(comment, X509ExtensionType),
             "%r is of type %r, should be %r" % (
                 comment, type(comment), X509ExtensionType))
-        self.assertEqual(type(X509ExtensionType).__name__, 'type')
-        self.assertEqual(type(basic).__name__, 'X509Extension')
-        self.assertEqual(type(basic), X509ExtensionType)
-        self.assertEqual(type(basic), X509Extension)
 
 
     def test_invalid_extension(self):
@@ -238,24 +271,128 @@
         self.assertEqual(ext.get_short_name(), 'nsComment')
 
 
+    def test_unused_subject(self):
+        """
+        The C{subject} parameter to L{X509Extension} may be provided for an
+        extension which does not use it and is ignored in this case.
+        """
+        ext1 = X509Extension('basicConstraints', False, 'CA:TRUE', subject=self.x509)
+        self.x509.add_extensions([ext1])
+        self.x509.sign(self.pkey, 'sha1')
+        # This is a little lame.  Can we think of a better way?
+        text = dump_certificate(FILETYPE_TEXT, self.x509)
+        self.assertTrue('X509v3 Basic Constraints:' in text)
+        self.assertTrue('CA:TRUE' in text)
+
+
+    def test_subject(self):
+        """
+        If an extension requires a subject, the C{subject} parameter to
+        L{X509Extension} provides its value.
+        """
+        ext3 = X509Extension('subjectKeyIdentifier', False, 'hash', subject=self.x509)
+        self.x509.add_extensions([ext3])
+        self.x509.sign(self.pkey, 'sha1')
+        text = dump_certificate(FILETYPE_TEXT, self.x509)
+        self.assertTrue('X509v3 Subject Key Identifier:' in text)
+
+
+    def test_missing_subject(self):
+        """
+        If an extension requires a subject and the C{subject} parameter is
+        given no value, something happens.
+        """
+        self.assertRaises(
+            Error, X509Extension, 'subjectKeyIdentifier', False, 'hash')
+
+
+    def test_invalid_subject(self):
+        """
+        If the C{subject} parameter is given a value which is not an L{X509}
+        instance, L{TypeError} is raised.
+        """
+        for badObj in [True, object(), "hello", [], self]:
+            self.assertRaises(
+                TypeError,
+                X509Extension,
+                'basicConstraints', False, 'CA:TRUE', subject=badObj)
+
+
+    def test_unused_issuer(self):
+        """
+        The C{issuer} parameter to L{X509Extension} may be provided for an
+        extension which does not use it and is ignored in this case.
+        """
+        ext1 = X509Extension('basicConstraints', False, 'CA:TRUE', issuer=self.x509)
+        self.x509.add_extensions([ext1])
+        self.x509.sign(self.pkey, 'sha1')
+        text = dump_certificate(FILETYPE_TEXT, self.x509)
+        self.assertTrue('X509v3 Basic Constraints:' in text)
+        self.assertTrue('CA:TRUE' in text)
+
+
+    def test_issuer(self):
+        """
+        If an extension requires a issuer, the C{issuer} parameter to
+        L{X509Extension} provides its value.
+        """
+        ext2 = X509Extension(
+            'authorityKeyIdentifier', False, 'issuer:always',
+            issuer=self.x509)
+        self.x509.add_extensions([ext2])
+        self.x509.sign(self.pkey, 'sha1')
+        text = dump_certificate(FILETYPE_TEXT, self.x509)
+        self.assertTrue('X509v3 Authority Key Identifier:' in text)
+        self.assertTrue('DirName:/CN=Yoda root CA' in text)
+
+
+    def test_missing_issuer(self):
+        """
+        If an extension requires an issue and the C{issuer} parameter is given
+        no value, something happens.
+        """
+        self.assertRaises(
+            Error,
+            X509Extension,
+            'authorityKeyIdentifier', False, 'keyid:always,issuer:always')
+
+
+    def test_invalid_issuer(self):
+        """
+        If the C{issuer} parameter is given a value which is not an L{X509}
+        instance, L{TypeError} is raised.
+        """
+        for badObj in [True, object(), "hello", [], self]:
+            self.assertRaises(
+                TypeError,
+                X509Extension,
+                'authorityKeyIdentifier', False, 'keyid:always,issuer:always',
+                issuer=badObj)
+
+
 
 class PKeyTests(TestCase):
     """
     Unit tests for L{OpenSSL.crypto.PKey}.
     """
+    def test_type(self):
+        """
+        L{PKey} and L{PKeyType} refer to the same type object and can be used
+        to create instances of that type.
+        """
+        self.assertIdentical(PKey, PKeyType)
+        self.assertConsistentType(PKey, 'PKey')
+
+
     def test_construction(self):
         """
-        L{PKey} takes no arguments and returns a new L{PKeyType} instance.
+        L{PKey} takes no arguments and returns a new L{PKey} instance.
         """
         self.assertRaises(TypeError, PKey, None)
         key = PKey()
         self.assertTrue(
             isinstance(key, PKeyType),
             "%r is of type %r, should be %r" % (key, type(key), PKeyType))
-        self.assertEqual(type(PKeyType).__name__, 'type')
-        self.assertEqual(type(key).__name__, 'PKey')
-        self.assertEqual(type(key), PKeyType)
-        self.assertEqual(type(key), PKey)
 
 
     def test_pregeneration(self):
@@ -360,18 +497,17 @@
 
     def test_type(self):
         """
-        L{X509NameType} is a type, and matches the type of a
-        X509Name.
+        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))
-        self.assertEqual(type(X509NameType).__name__, 'type')
-        self.assertEqual(type(name).__name__, 'X509Name')
-        self.assertEqual(type(name), X509NameType)
-        self.assertEqual(type(name), X509Name)
 
 
     def test_attributes(self):
@@ -582,12 +718,16 @@
         """
         Create and return a new L{X509Req}.
         """
-        req = X509Req()
-        self.assertEqual(type(X509ReqType).__name__, 'type')
-        self.assertEqual(type(req).__name__, 'X509Req')
-        self.assertEqual(type(req), X509ReqType)
-        self.assertEqual(type(req), X509Req)
-        return req
+        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):
@@ -646,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}.
@@ -928,10 +1077,6 @@
         """
         pkcs7 = load_pkcs7_data(FILETYPE_PEM, pkcs7Data)
         self.assertTrue(isinstance(pkcs7, PKCS7Type))
-        self.assertEqual(type(PKCS7Type).__name__, 'type')
-        self.assertEqual(type(pkcs7).__name__, 'PKCS7')
-        self.assertEqual(type(pkcs7), PKCS7Type)
-        #self.assertEqual(type(pkcs7), PKCS7)  # needs to be fixed
 
 
     def test_load_pkcs12(self):
@@ -941,10 +1086,38 @@
         """
         pkcs12 = load_pkcs12(pkcs12Data)
         self.assertTrue(isinstance(pkcs12, PKCS12Type))
-        self.assertEqual(type(PKCS12Type).__name__, 'type')
-        self.assertEqual(type(pkcs12).__name__, 'PKCS12')
-        self.assertEqual(type(pkcs12), PKCS12Type)
-        #self.assertEqual(type(pkcs12), PKCS12)  # needs to be fixed
+
+
+
+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)
 
 
 
@@ -952,16 +1125,21 @@
     """
     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))
-        self.assertEqual(type(NetscapeSPKIType).__name__, 'type')
-        self.assertEqual(type(nspki).__name__, 'NetscapeSPKI')
-        self.assertEqual(type(nspki), NetscapeSPKIType)
-        self.assertEqual(type(nspki), NetscapeSPKI)
 
 
 
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 1b4e3b7..bf28ca3 100644
--- a/test/test_ssl.py
+++ b/test/test_ssl.py
@@ -13,7 +13,7 @@
 from OpenSSL.crypto import TYPE_RSA, FILETYPE_PEM, PKey, dump_privatekey, load_certificate, load_privatekey
 from OpenSSL.SSL import WantReadError, Context, ContextType, Connection, ConnectionType, Error
 from OpenSSL.SSL import SSLv2_METHOD, SSLv3_METHOD, SSLv23_METHOD, TLSv1_METHOD
-from OpenSSL.SSL import OP_NO_SSLv2, OP_NO_SSLv3, OP_SINGLE_DH_USE 
+from OpenSSL.SSL import OP_NO_SSLv2, OP_NO_SSLv3, OP_SINGLE_DH_USE
 from OpenSSL.SSL import VERIFY_PEER, VERIFY_FAIL_IF_NO_PEER_CERT, VERIFY_CLIENT_ONCE
 from OpenSSL.test.util import TestCase
 from OpenSSL.test.test_crypto import cleartextCertificatePEM, cleartextPrivateKeyPEM
@@ -31,6 +31,36 @@
     OP_NO_TICKET = None
 
 
+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}.
@@ -48,14 +78,11 @@
 
     def test_type(self):
         """
-        L{Context} must be of type L{ContextType}.
+        L{Context} and L{ContextType} refer to the same type object and can be
+        used to create instances of that type.
         """
-        ctx = Context(TLSv1_METHOD)
-        self.assertTrue(isinstance(ctx, ContextType))
-        self.assertEqual(type(ContextType).__name__, 'type')
-        self.assertEqual(type(ctx).__name__, 'Context')
-        self.assertEqual(type(ctx), ContextType)
-        self.assertEqual(type(ctx), Context)
+        self.assertIdentical(Context, ContextType)
+        self.assertConsistentType(Context, 'Context', TLSv1_METHOD)
 
 
     def test_use_privatekey(self):
@@ -100,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()
@@ -121,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()
 
@@ -139,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)
@@ -158,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))
@@ -277,18 +286,25 @@
     """
     def test_type(self):
         """
-        L{Connection} must be of type L{ConnectionType}.
+        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)
-        conn = Connection(ctx, None)
-        self.assertTrue(isinstance(conn, ConnectionType))
-        self.assertEqual(type(ConnectionType).__name__, 'type')
-        self.assertEqual(type(conn).__name__, 'Connection')
-        self.assertEqual(type(conn), ConnectionType)
-        self.assertEqual(type(conn), Connection)
+        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')
-        self.assertEqual(type(Error).__name__, 'type')
 
 
 
@@ -445,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)
@@ -456,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)
@@ -473,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
 
@@ -526,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)
@@ -569,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
@@ -589,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)
 
@@ -614,7 +679,7 @@
         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
diff --git a/test/util.py b/test/util.py
index fdc9348..d195d95 100644
--- a/test/util.py
+++ b/test/util.py
@@ -11,6 +11,9 @@
 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):
@@ -30,7 +33,12 @@
                     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):
         """
@@ -81,10 +89,10 @@
         except exception, inst:
             return inst
         except:
-            raise self.failureException('%s raised instead of %s:\n %s'
+            raise self.failureException('%s raised instead of %s'
                                         % (sys.exc_info()[0],
                                            exception.__name__,
-                                           failure.Failure().getTraceback()))
+                                          ))
         else:
             raise self.failureException('%s not raised (%r returned)'
                                         % (exception.__name__, result))
@@ -110,3 +118,22 @@
 
     def assertFalse(self, *a, **kw):
         return self.failIf(*a, **kw)
+
+
+    # Other stuff
+    def assertConsistentType(self, theType, name, *constructionArgs):
+        """
+        Perform various assertions about C{theType} to ensure that it is a
+        well-defined type.  This is useful for extension types, where it's
+        pretty easy to do something wacky.  If something about the type is
+        unusual, an exception will be raised.
+
+        @param theType: The type object about which to make assertions.
+        @param name: A string giving the name of the type.
+        @param constructionArgs: Positional arguments to use with C{theType} to
+            create an instance of it.
+        """
+        self.assertEqual(theType.__name__, name)
+        self.assertTrue(isinstance(theType, type))
+        instance = theType(*constructionArgs)
+        self.assertIdentical(type(instance), theType)