Add support for in-memory BIOs

OpenSSL.SSL.Connection now accepts None as the value for the socket/file object to
run over.  In this case, it creates an in-memory buffer to use for reading and writing
instead.  Connection objects also have several new methods; some for interacting with
this in-memory buffer, and others for inspecting the state of the SSL handshake (in
particular, for extracting the master, client, and session keys).

A bug in the crypto tests which caused them to fail on Windows has also been fixed.
diff --git a/ChangeLog b/ChangeLog
index 32067d8..842f857 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2009-05-11  Jean-Paul Calderone  <exarkun@twistedmatrix.com>
+
+	* test/test_crypto.py: Use binary mode for the pipe to talk to the
+	  external openssl binary.  The data being transported over this
+	  pipe is indeed binary, so previously it would often be truncated
+	  or otherwise mangled.
+
+	* src/ssl/connection.h, src/ssl/connection.c, test/test_ssl.py:
+	  Extend the Connection class with support for in-memory BIOs.  This
+	  allows SSL to be run without a real socket, useful for
+	  implementing EAP-TLS or using SSL with Windows IO completion
+	  ports, for example.
+
 2009-04-25  Jean-Paul Calderone  <exarkun@twistedmatrix.com>
 
 	* Release 0.9
diff --git a/doc/pyOpenSSL.tex b/doc/pyOpenSSL.tex
index d0b5f17..b9d1f20 100644
--- a/doc/pyOpenSSL.tex
+++ b/doc/pyOpenSSL.tex
@@ -681,10 +681,12 @@
 \end{datadesc}
 
 \begin{funcdesc}{Connection}{context, socket}
-Factory fucnction that creates a new Connection object given an SSL context and
+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.
+  \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{excdesc}{Error}
@@ -978,6 +980,12 @@
 by \var{bufsize}.
 \end{methoddesc}
 
+\begin{methoddesc}[Connection]{bio_write}{bytes}
+If the Connection was created with a memory BIO, this method can be used to add
+bytes to the read end of that memory BIO.  The Connection can then read the
+bytes (for example, in response to a call to \method{recv}).
+\end{methoddesc}
+
 \begin{methoddesc}[Connection]{renegotiate}{}
 Renegotiate the SSL session. Call this if you wish to change cipher suites or
 anything like that.
@@ -987,6 +995,13 @@
 Send the \var{string} data to the Connection.
 \end{methoddesc}
 
+\begin{methoddesc}[Connection]{bio_read}{bufsize}
+If the Connection was created with a memory BIO, this method can be used to
+read bytes from the write end of that memory BIO.  Many Connection methods will
+add bytes which must be read in this manner or the buffer will eventually fill
+up and the Connection will be able to take no further actions.
+\end{methoddesc}
+
 \begin{methoddesc}[Connection]{sendall}{string}
 Send all of the \var{string} data to the Connection. This calls \method{send}
 repeatedly until all data is sent. If an error occurs, it's impossible to tell
@@ -1037,10 +1052,28 @@
 Call the \method{shutdown} method of the underlying socket.
 \end{methoddesc}
 
+\begin{methoddesc}[Connection]{bio_shutdown}{}
+If the Connection was created with a memory BIO, this method can be used to
+indicate that ``end of file'' has been reached on the read end of that memory
+BIO.
+\end{methoddesc}
+
 \begin{methoddesc}[Connection]{state_string}{}
 Retrieve a verbose string detailing the state of the Connection.
 \end{methoddesc}
 
+\begin{methoddesc}[Connection]{client_random}{}
+Retrieve the random value used with the client hello message.
+\end{methoddesc}
+
+\begin{methoddesc}[Connection]{server_random}{}
+Retrieve the random value used with the server hello message.
+\end{methoddesc}
+
+\begin{methoddesc}[Connection]{master_key}{}
+Retrieve the value of the master key for this session.
+\end{methoddesc}
+
 \begin{methoddesc}[Connection]{want_read}{}
 Checks if more data has to be read from the transport layer to complete an
 operation.
diff --git a/src/ssl/connection.c b/src/ssl/connection.c
index a9778de..f78e93f 100755
--- a/src/ssl/connection.c
+++ b/src/ssl/connection.c
@@ -23,8 +23,8 @@
 #endif
 
 #define SSL_MODULE
+#include <openssl/bio.h>
 #include <openssl/err.h>
-
 #include "ssl.h"
 
 /**
@@ -125,6 +125,50 @@
 }
 
 /*
+ * Handle errors raised by BIO functions.
+ *
+ * Arguments: bio - The BIO object
+ *            ret - The return value of the BIO_ function.
+ * Returns: None, the calling function should return NULL;
+ */
+static void
+handle_bio_errors(BIO* bio, int ret)
+{
+    if (BIO_should_retry(bio)) {
+        if (BIO_should_read(bio)) {
+            PyErr_SetNone(ssl_WantReadError);
+        } else if (BIO_should_write(bio)) {
+            PyErr_SetNone(ssl_WantWriteError);
+        } else if (BIO_should_io_special(bio)) {
+            /*
+             * It's somewhat unclear what this means.  From the OpenSSL source,
+             * it seems like it should not be triggered by the memory BIO, so
+             * for the time being, this case shouldn't come up.  The SSL BIO
+             * (which I think should be named the socket BIO) may trigger this
+             * case if its socket is not yet connected or it is busy doing
+             * something related to x509.
+             */
+            PyErr_SetString(PyExc_ValueError, "BIO_should_io_special");
+        } else {
+            /*
+             * I hope this is dead code.  The BIO documentation suggests that
+             * one of the above three checks should always be true.
+             */
+            PyErr_SetString(PyExc_ValueError, "unknown bio failure");
+        }
+    } else {
+        /*
+         * If we aren't to retry, it's really an error, so fall back to the
+         * normal error reporting code.  However, the BIO interface does not
+         * specify a uniform error reporting mechanism.  We can only hope that
+         * the code which triggered the error also kindly pushed something onto
+         * the error stack.
+         */
+        exception_from_error_queue();
+    }
+}
+
+/*
  * Handle errors raised by SSL I/O functions. NOTE: Not SSL_shutdown ;)
  *
  * Arguments: ssl - The SSL object
@@ -239,6 +283,49 @@
     return PyInt_FromLong((long)ret);
 }
     
+static char ssl_Connection_bio_write_doc[] = "\n\
+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\
+";
+static PyObject *
+ssl_Connection_bio_write(ssl_ConnectionObj *self, PyObject *args)
+{
+    char *buf;
+    int len, ret;
+
+    if (self->into_ssl == NULL) 
+    {
+            PyErr_SetString(PyExc_TypeError, "Connection sock was not None");
+            return NULL;
+    }
+
+    if (!PyArg_ParseTuple(args, "s#|i:bio_write", &buf, &len))
+        return NULL;
+
+    ret = BIO_write(self->into_ssl, buf, len);
+
+    if (PyErr_Occurred())
+    {
+        flush_error_queue();
+        return NULL;
+    }
+
+    if (ret <= 0) {
+        /*
+         * There was a problem with the BIO_write of some sort.
+         */
+        handle_bio_errors(self->into_ssl, ret);
+        return NULL;
+    }
+
+    return PyInt_FromLong((long)ret);
+}
+
 static char ssl_Connection_send_doc[] = "\n\
 Send data on the connection. NOTE: If you get one of the WantRead,\n\
 WantWrite or WantX509Lookup exceptions on this, you have to call the\n\
@@ -384,6 +471,63 @@
     }
 }
 
+static char ssl_Connection_bio_read_doc[] = "\n\
+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\
+";
+static PyObject *
+ssl_Connection_bio_read(ssl_ConnectionObj *self, PyObject *args)
+{
+    int bufsiz, ret;
+    PyObject *buf;
+
+    if (self->from_ssl == NULL) 
+    {
+            PyErr_SetString(PyExc_TypeError, "Connection sock was not None");
+            return NULL;
+    }
+
+    if (!PyArg_ParseTuple(args, "i:bio_read", &bufsiz))
+        return NULL;
+
+    buf = PyString_FromStringAndSize(NULL, bufsiz);
+    if (buf == NULL)
+        return NULL;
+
+    ret = BIO_read(self->from_ssl, PyString_AsString(buf), bufsiz);
+
+    if (PyErr_Occurred())
+    {
+        Py_DECREF(buf);
+        flush_error_queue();
+        return NULL;
+    }
+
+    if (ret <= 0) {
+        /*
+         * There was a problem with the BIO_read of some sort.
+         */
+        handle_bio_errors(self->from_ssl, ret);
+        Py_DECREF(buf);
+        return NULL;
+    }
+
+    /*
+     * Shrink the string to match the number of bytes we actually read.
+     */
+    if (ret != bufsiz && _PyString_Resize(&buf, ret) < 0)
+    {
+        Py_DECREF(buf);
+        return NULL;
+    }
+    return buf;
+}
+
 static char ssl_Connection_renegotiate_doc[] = "\n\
 Renegotiate the session\n\
 \n\
@@ -626,6 +770,31 @@
     return tuple;
 }
 
+static char ssl_Connection_bio_shutdown_doc[] = "\n\
+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\
+";
+
+static PyObject *
+ssl_Connection_bio_shutdown(ssl_ConnectionObj *self, PyObject *args)
+{
+    if (self->from_ssl == NULL) 
+    {
+            PyErr_SetString(PyExc_TypeError, "Connection sock was not None");
+            return NULL;
+    }
+
+    BIO_set_mem_eof_return(self->into_ssl, 0);
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+
+
 static char ssl_Connection_shutdown_doc[] = "\n\
 Send closure alert\n\
 \n\
@@ -810,6 +979,66 @@
     return PyString_FromString(SSL_state_string_long(self->ssl));
 }
 
+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\
+";
+static PyObject *
+ssl_Connection_client_random(ssl_ConnectionObj *self, PyObject *args)
+{
+    if (!PyArg_ParseTuple(args, ":client_random"))
+        return NULL;
+
+    if (self->ssl->session == NULL) {
+        Py_INCREF(Py_None);
+        return Py_None;
+    }
+    return PyString_FromStringAndSize( (const char *) self->ssl->s3->client_random, SSL3_RANDOM_SIZE);
+}
+
+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\
+";
+static PyObject *
+ssl_Connection_server_random(ssl_ConnectionObj *self, PyObject *args)
+{
+    if (!PyArg_ParseTuple(args, ":server_random"))
+        return NULL;
+
+    if (self->ssl->session == NULL) {
+        Py_INCREF(Py_None);
+        return Py_None;
+    }
+    return PyString_FromStringAndSize( (const char *) self->ssl->s3->server_random, SSL3_RANDOM_SIZE);
+}
+
+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\
+";
+static PyObject *
+ssl_Connection_master_key(ssl_ConnectionObj *self, PyObject *args)
+{
+    if (!PyArg_ParseTuple(args, ":master_key"))
+        return NULL;
+
+    if (self->ssl->session == NULL) {
+        Py_INCREF(Py_None);
+        return Py_None;
+    }
+    return PyString_FromStringAndSize( (const char *) self->ssl->session->master_key, self->ssl->session->master_key_length);
+}
+
 static char ssl_Connection_sock_shutdown_doc[] = "\n\
 See shutdown(2)\n\
 \n\
@@ -912,6 +1141,8 @@
     ADD_METHOD(sendall),
     ADD_METHOD(recv),
     ADD_ALIAS (read, recv),
+    ADD_METHOD(bio_read),
+    ADD_METHOD(bio_write),
     ADD_METHOD(renegotiate),
     ADD_METHOD(do_handshake),
 #if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x00907000L
@@ -921,6 +1152,7 @@
     ADD_METHOD(connect),
     ADD_METHOD(connect_ex),
     ADD_METHOD(accept),
+    ADD_METHOD(bio_shutdown),
     ADD_METHOD(shutdown),
     ADD_METHOD(get_cipher_list),
     ADD_METHOD(makefile),
@@ -929,6 +1161,9 @@
     ADD_METHOD(get_shutdown),
     ADD_METHOD(set_shutdown),
     ADD_METHOD(state_string),
+    ADD_METHOD(server_random),
+    ADD_METHOD(client_random),
+    ADD_METHOD(master_key),
     ADD_METHOD(sock_shutdown),
     ADD_METHOD(get_peer_certificate),
     ADD_METHOD(want_read),
@@ -965,26 +1200,50 @@
     self->socket = sock;
 
     self->ssl = NULL;
+    self->from_ssl = NULL;
+    self->into_ssl = NULL;
 
     Py_INCREF(Py_None);
     self->app_data = Py_None;
 
     self->tstate = NULL;
 
-    fd = PyObject_AsFileDescriptor(self->socket);
-    if (fd < 0)
-    {
-        Py_DECREF(self);
-        return NULL;
-    }
-
     self->ssl = SSL_new(self->context->ctx);
     SSL_set_app_data(self->ssl, self);
-    SSL_set_fd(self->ssl, (SOCKET_T)fd);
+
+    if (self->socket == Py_None)
+    {
+        /* If it's not a socket or file, treat it like a memory buffer, 
+         * so crazy people can do things like EAP-TLS. */
+        self->into_ssl = BIO_new(BIO_s_mem());
+        self->from_ssl = BIO_new(BIO_s_mem());
+        if (self->into_ssl == NULL || self->from_ssl == NULL)
+            goto error;
+        SSL_set_bio(self->ssl, self->into_ssl, self->from_ssl);
+    } 
+    else 
+    {
+        fd = PyObject_AsFileDescriptor(self->socket);
+        if (fd < 0)
+        {
+            Py_DECREF(self);
+            return NULL;
+        } 
+        else 
+        {
+            SSL_set_fd(self->ssl, (SOCKET_T)fd);
+        }
+    }
 
     PyObject_GC_Track(self);
 
     return self;
+
+error:
+    BIO_free(self->into_ssl);  /* NULL safe */
+    BIO_free(self->from_ssl);  /* NULL safe */
+    Py_DECREF(self);
+    return NULL;
 }
 
 /*
@@ -1050,6 +1309,8 @@
     self->socket = NULL;
     Py_XDECREF(self->app_data);
     self->app_data = NULL;
+    self->into_ssl = NULL; /* was cleaned up by SSL_free() */
+    self->from_ssl = NULL; /* was cleaned up by SSL_free() */
     return 0;
 }
 
diff --git a/src/ssl/connection.h b/src/ssl/connection.h
index 13f42f0..4e1e4d2 100644
--- a/src/ssl/connection.h
+++ b/src/ssl/connection.h
@@ -44,6 +44,7 @@
     PyObject            *socket;
     PyThreadState       *tstate; /* This field is no longer used. */
     PyObject            *app_data;
+    BIO                 *into_ssl, *from_ssl;  /* for connections without file descriptors */
 } ssl_ConnectionObj;
 
 
diff --git a/test/test_crypto.py b/test/test_crypto.py
index 214a4b8..87e9048 100644
--- a/test/test_crypto.py
+++ b/test/test_crypto.py
@@ -732,7 +732,7 @@
         Run the command line openssl tool with the given arguments and write
         the given PEM to its stdin.
         """
-        write, read = popen2(" ".join(("openssl",) + args))
+        write, read = popen2(" ".join(("openssl",) + args), "b")
         write.write(pem)
         write.close()
         return read.read()
diff --git a/test/test_ssl.py b/test/test_ssl.py
index 32d8f74..51ff5c7 100644
--- a/test/test_ssl.py
+++ b/test/test_ssl.py
@@ -15,12 +15,13 @@
     from twisted.trial.unittest import TestCase
 except ImportError:
     # Fall back to the stdlib TestCase though, since it kind of works.
-    from unittest import TestCase, main
+    from unittest import TestCase
 
 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 SSLv2_METHOD, SSLv3_METHOD, SSLv23_METHOD, TLSv1_METHOD
-from OpenSSL.SSL import VERIFY_PEER
+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
 try:
     from OpenSSL.SSL import OP_NO_QUERY_MTU
@@ -313,6 +314,287 @@
         "OP_NO_TICKET unavailable - OpenSSL version may be too old"
 
 
-if __name__ == '__main__':
-    main()
 
+root_cert_pem = """-----BEGIN CERTIFICATE-----
+MIIC7TCCAlagAwIBAgIIPQzE4MbeufQwDQYJKoZIhvcNAQEFBQAwWDELMAkGA1UE
+BhMCVVMxCzAJBgNVBAgTAklMMRAwDgYDVQQHEwdDaGljYWdvMRAwDgYDVQQKEwdU
+ZXN0aW5nMRgwFgYDVQQDEw9UZXN0aW5nIFJvb3QgQ0EwIhgPMjAwOTAzMjUxMjM2
+NThaGA8yMDE3MDYxMTEyMzY1OFowWDELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAklM
+MRAwDgYDVQQHEwdDaGljYWdvMRAwDgYDVQQKEwdUZXN0aW5nMRgwFgYDVQQDEw9U
+ZXN0aW5nIFJvb3QgQ0EwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAPmaQumL
+urpE527uSEHdL1pqcDRmWzu+98Y6YHzT/J7KWEamyMCNZ6fRW1JCR782UQ8a07fy
+2xXsKy4WdKaxyG8CcatwmXvpvRQ44dSANMihHELpANTdyVp6DCysED6wkQFurHlF
+1dshEaJw8b/ypDhmbVIo6Ci1xvCJqivbLFnbAgMBAAGjgbswgbgwHQYDVR0OBBYE
+FINVdy1eIfFJDAkk51QJEo3IfgSuMIGIBgNVHSMEgYAwfoAUg1V3LV4h8UkMCSTn
+VAkSjch+BK6hXKRaMFgxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJJTDEQMA4GA1UE
+BxMHQ2hpY2FnbzEQMA4GA1UEChMHVGVzdGluZzEYMBYGA1UEAxMPVGVzdGluZyBS
+b290IENBggg9DMTgxt659DAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GB
+AGGCDazMJGoWNBpc03u6+smc95dEead2KlZXBATOdFT1VesY3+nUOqZhEhTGlDMi
+hkgaZnzoIq/Uamidegk4hirsCT/R+6vsKAAxNTcBjUeZjlykCJWy5ojShGftXIKY
+w/njVbKMXrvc83qmTdGl3TAM0fxQIpqgcglFLveEBgzn
+-----END CERTIFICATE-----
+"""
+
+root_key_pem = """-----BEGIN RSA PRIVATE KEY-----
+MIICXQIBAAKBgQD5mkLpi7q6ROdu7khB3S9aanA0Zls7vvfGOmB80/yeylhGpsjA
+jWen0VtSQke/NlEPGtO38tsV7CsuFnSmschvAnGrcJl76b0UOOHUgDTIoRxC6QDU
+3claegwsrBA+sJEBbqx5RdXbIRGicPG/8qQ4Zm1SKOgotcbwiaor2yxZ2wIDAQAB
+AoGBAPCgMpmLxzwDaUmcFbTJUvlLW1hoxNNYSu2jIZm1k/hRAcE60JYwvBkgz3UB
+yMEh0AtLxYe0bFk6EHah11tMUPgscbCq73snJ++8koUw+csk22G65hOs51bVb7Aa
+6JBe67oLzdtvgCUFAA2qfrKzWRZzAdhUirQUZgySZk+Xq1pBAkEA/kZG0A6roTSM
+BVnx7LnPfsycKUsTumorpXiylZJjTi9XtmzxhrYN6wgZlDOOwOLgSQhszGpxVoMD
+u3gByT1b2QJBAPtL3mSKdvwRu/+40zaZLwvSJRxaj0mcE4BJOS6Oqs/hS1xRlrNk
+PpQ7WJ4yM6ZOLnXzm2mKyxm50Mv64109FtMCQQDOqS2KkjHaLowTGVxwC0DijMfr
+I9Lf8sSQk32J5VWCySWf5gGTfEnpmUa41gKTMJIbqZZLucNuDcOtzUaeWZlZAkA8
+ttXigLnCqR486JDPTi9ZscoZkZ+w7y6e/hH8t6d5Vjt48JVyfjPIaJY+km58LcN3
+6AWSeGAdtRFHVzR7oHjVAkB4hutvxiOeiIVQNBhM6RSI9aBPMI21DoX2JRoxvNW2
+cbvAhow217X9V0dVerEOKxnNYspXRrh36h7k4mQA+sDq
+-----END RSA PRIVATE KEY-----
+"""
+
+server_cert_pem = """-----BEGIN CERTIFICATE-----
+MIICKDCCAZGgAwIBAgIJAJn/HpR21r/8MA0GCSqGSIb3DQEBBQUAMFgxCzAJBgNV
+BAYTAlVTMQswCQYDVQQIEwJJTDEQMA4GA1UEBxMHQ2hpY2FnbzEQMA4GA1UEChMH
+VGVzdGluZzEYMBYGA1UEAxMPVGVzdGluZyBSb290IENBMCIYDzIwMDkwMzI1MTIz
+NzUzWhgPMjAxNzA2MTExMjM3NTNaMBgxFjAUBgNVBAMTDWxvdmVseSBzZXJ2ZXIw
+gZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAL6m+G653V0tpBC/OKl22VxOi2Cv
+lK4TYu9LHSDP9uDVTe7V5D5Tl6qzFoRRx5pfmnkqT5B+W9byp2NU3FC5hLm5zSAr
+b45meUhjEJ/ifkZgbNUjHdBIGP9MAQUHZa5WKdkGIJvGAvs8UzUqlr4TBWQIB24+
+lJ+Ukk/CRgasrYwdAgMBAAGjNjA0MB0GA1UdDgQWBBS4kC7Ij0W1TZXZqXQFAM2e
+gKEG2DATBgNVHSUEDDAKBggrBgEFBQcDATANBgkqhkiG9w0BAQUFAAOBgQBh30Li
+dJ+NlxIOx5343WqIBka3UbsOb2kxWrbkVCrvRapCMLCASO4FqiKWM+L0VDBprqIp
+2mgpFQ6FHpoIENGvJhdEKpptQ5i7KaGhnDNTfdy3x1+h852G99f1iyj0RmbuFcM8
+uzujnS8YXWvM7DM1Ilozk4MzPug8jzFp5uhKCQ==
+-----END CERTIFICATE-----
+"""
+
+server_key_pem = """-----BEGIN RSA PRIVATE KEY-----
+MIICWwIBAAKBgQC+pvhuud1dLaQQvzipdtlcTotgr5SuE2LvSx0gz/bg1U3u1eQ+
+U5eqsxaEUceaX5p5Kk+QflvW8qdjVNxQuYS5uc0gK2+OZnlIYxCf4n5GYGzVIx3Q
+SBj/TAEFB2WuVinZBiCbxgL7PFM1Kpa+EwVkCAduPpSflJJPwkYGrK2MHQIDAQAB
+AoGAbwuZ0AR6JveahBaczjfnSpiFHf+mve2UxoQdpyr6ROJ4zg/PLW5K/KXrC48G
+j6f3tXMrfKHcpEoZrQWUfYBRCUsGD5DCazEhD8zlxEHahIsqpwA0WWssJA2VOLEN
+j6DuV2pCFbw67rfTBkTSo32ahfXxEKev5KswZk0JIzH3ooECQQDgzS9AI89h0gs8
+Dt+1m11Rzqo3vZML7ZIyGApUzVan+a7hbc33nbGRkAXjHaUBJO31it/H6dTO+uwX
+msWwNG5ZAkEA2RyFKs5xR5USTFaKLWCgpH/ydV96KPOpBND7TKQx62snDenFNNbn
+FwwOhpahld+vqhYk+pfuWWUpQciE+Bu7ZQJASjfT4sQv4qbbKK/scePicnDdx9th
+4e1EeB9xwb+tXXXUo/6Bor/AcUNwfiQ6Zt9PZOK9sR3lMZSsP7rMi7kzuQJABie6
+1sXXjFH7nNJvRG4S39cIxq8YRYTy68II/dlB2QzGpKxV/POCxbJ/zu0CU79tuYK7
+NaeNCFfH3aeTrX0LyQJAMBWjWmeKM2G2sCExheeQK0ROnaBC8itCECD4Jsve4nqf
+r50+LF74iLXFwqysVCebPKMOpDWp/qQ1BbJQIPs7/A==
+-----END RSA PRIVATE KEY-----
+"""
+
+client_cert_pem = """-----BEGIN CERTIFICATE-----
+MIICJjCCAY+gAwIBAgIJAKxpFI5lODkjMA0GCSqGSIb3DQEBBQUAMFgxCzAJBgNV
+BAYTAlVTMQswCQYDVQQIEwJJTDEQMA4GA1UEBxMHQ2hpY2FnbzEQMA4GA1UEChMH
+VGVzdGluZzEYMBYGA1UEAxMPVGVzdGluZyBSb290IENBMCIYDzIwMDkwMzI1MTIz
+ODA1WhgPMjAxNzA2MTExMjM4MDVaMBYxFDASBgNVBAMTC3VnbHkgY2xpZW50MIGf
+MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDAZh/SRtNm5ntMT4qb6YzEpTroMlq2
+rn+GrRHRiZ+xkCw/CGNhbtPir7/QxaUj26BSmQrHw1bGKEbPsWiW7bdXSespl+xK
+iku4G/KvnnmWdeJHqsiXeUZtqurMELcPQAw9xPHEuhqqUJvvEoMTsnCEqGM+7Dtb
+oCRajYyHfluARQIDAQABozYwNDAdBgNVHQ4EFgQUNQB+qkaOaEVecf1J3TTUtAff
+0fAwEwYDVR0lBAwwCgYIKwYBBQUHAwIwDQYJKoZIhvcNAQEFBQADgYEAyv/Jh7gM
+Q3OHvmsFEEvRI+hsW8y66zK4K5de239Y44iZrFYkt7Q5nBPMEWDj4F2hLYWL/qtI
+9Zdr0U4UDCU9SmmGYh4o7R4TZ5pGFvBYvjhHbkSFYFQXZxKUi+WUxplP6I0wr2KJ
+PSTJCjJOn3xo2NTKRgV1gaoTf2EhL+RG8TQ=
+-----END CERTIFICATE-----
+"""
+
+client_key_pem = """-----BEGIN RSA PRIVATE KEY-----
+MIICXgIBAAKBgQDAZh/SRtNm5ntMT4qb6YzEpTroMlq2rn+GrRHRiZ+xkCw/CGNh
+btPir7/QxaUj26BSmQrHw1bGKEbPsWiW7bdXSespl+xKiku4G/KvnnmWdeJHqsiX
+eUZtqurMELcPQAw9xPHEuhqqUJvvEoMTsnCEqGM+7DtboCRajYyHfluARQIDAQAB
+AoGATkZ+NceY5Glqyl4mD06SdcKfV65814vg2EL7V9t8+/mi9rYL8KztSXGlQWPX
+zuHgtRoMl78yQ4ZJYOBVo+nsx8KZNRCEBlE19bamSbQLCeQMenWnpeYyQUZ908gF
+h6L9qsFVJepgA9RDgAjyDoS5CaWCdCCPCH2lDkdcqC54SVUCQQDseuduc4wi8h4t
+V8AahUn9fn9gYfhoNuM0gdguTA0nPLVWz4hy1yJiWYQe0H7NLNNTmCKiLQaJpAbb
+TC6vE8C7AkEA0Ee8CMJUc20BnGEmxwgWcVuqFWaKCo8jTH1X38FlATUsyR3krjW2
+dL3yDD9NwHxsYP7nTKp/U8MV7U9IBn4y/wJBAJl7H0/BcLeRmuJk7IqJ7b635iYB
+D/9beFUw3MUXmQXZUfyYz39xf6CDZsu1GEdEC5haykeln3Of4M9d/4Kj+FcCQQCY
+si6xwT7GzMDkk/ko684AV3KPc/h6G0yGtFIrMg7J3uExpR/VdH2KgwMkZXisSMvw
+JJEQjOMCVsEJlRk54WWjAkEAzoZNH6UhDdBK5F38rVt/y4SEHgbSfJHIAmPS32Kq
+f6GGcfNpip0Uk7q7udTKuX7Q/buZi/C4YW7u3VKAquv9NA==
+-----END RSA PRIVATE KEY-----
+"""
+
+def verify_cb(conn, cert, errnum, depth, ok):
+    return ok
+
+class MemoryBIOTests(TestCase):
+    """
+    Tests for L{OpenSSL.SSL.Connection} using a memory BIO.
+    """
+    def _server(self):
+        # Create the server side Connection.  This is mostly setup boilerplate
+        # - use TLSv1, use a particular certificate, etc.
+        server_ctx = Context(TLSv1_METHOD)
+        server_ctx.set_options(OP_NO_SSLv2 | OP_NO_SSLv3 | OP_SINGLE_DH_USE )
+        server_ctx.set_verify(VERIFY_PEER|VERIFY_FAIL_IF_NO_PEER_CERT|VERIFY_CLIENT_ONCE, verify_cb)
+        server_store = server_ctx.get_cert_store()
+        server_ctx.use_privatekey(load_privatekey(FILETYPE_PEM, server_key_pem))
+        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)
+        server_conn.set_accept_state()
+        return server_conn
+
+
+    def _client(self):
+        # 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)
+        client_store = client_ctx.get_cert_store()
+        client_ctx.use_privatekey(load_privatekey(FILETYPE_PEM, client_key_pem))
+        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.set_connect_state()
+        return client_conn
+
+
+    def _loopback(self, client_conn, server_conn):
+        """
+        Try to read application bytes from each of the two L{Connection}
+        objects.  Copy bytes back and forth between their send/receive buffers
+        for as long as there is anything to copy.  When there is nothing more
+        to copy, return C{None}.  If one of them actually manages to deliver
+        some application bytes, return a two-tuple of the connection from which
+        the bytes were read and the bytes themselves.
+        """
+        wrote = True
+        while wrote:
+            # Loop until neither side has anything to say
+            wrote = False
+
+            # Copy stuff from each side's send buffer to the other side's
+            # receive buffer.
+            for (read, write) in [(client_conn, server_conn),
+                                  (server_conn, client_conn)]:
+
+                # Give the side a chance to generate some more bytes, or
+                # succeed.
+                try:
+                    bytes = read.recv(2 ** 16)
+                except WantReadError:
+                    # It didn't succeed, so we'll hope it generated some
+                    # output.
+                    pass
+                else:
+                    # It did succeed, so we'll stop now and let the caller deal
+                    # with it.
+                    return (read, bytes)
+
+                while True:
+                    # Keep copying as long as there's more stuff there.
+                    try:
+                        dirty = read.bio_read(4096)
+                    except WantReadError:
+                        # Okay, nothing more waiting to be sent.  Stop
+                        # processing this send buffer.
+                        break
+                    else:
+                        # Keep track of the fact that someone generated some
+                        # output.
+                        wrote = True
+                        write.bio_write(dirty)
+
+
+    def test_connect(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()
+
+        # There should be no key or nonces yet.
+        self.assertIdentical(server_conn.master_key(), None)
+        self.assertIdentical(server_conn.client_random(), None)
+        self.assertIdentical(server_conn.server_random(), None)
+
+        # First, the handshake needs to happen.  We'll deliver bytes back and
+        # forth between the client and server until neither of them feels like
+        # speaking any more.
+        self.assertIdentical(self._loopback(client_conn, server_conn), None)
+
+        # Now that the handshake is done, there should be a key and nonces.
+        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())
+
+        # Here are the bytes we'll try to send.
+        important_message = 'One if by land, two if by sea.'
+
+        server_conn.write(important_message)
+        self.assertEquals(
+            self._loopback(client_conn, server_conn),
+            (client_conn, important_message))
+
+        client_conn.write(important_message[::-1])
+        self.assertEquals(
+            self._loopback(client_conn, server_conn),
+            (server_conn, important_message[::-1]))
+
+
+    def test_socketOverridesMemory(self):
+        """
+        Test that L{OpenSSL.SSL.bio_read} and L{OpenSSL.SSL.bio_write} don't
+        work on L{OpenSSL.SSL.Connection}() that use sockets.
+        """
+        context = Context(SSLv3_METHOD)
+        client = socket()
+        clientSSL = Connection(context, client)
+        self.assertRaises( TypeError, clientSSL.bio_read, 100)
+        self.assertRaises( TypeError, clientSSL.bio_write, "foo")
+        self.assertRaises( TypeError, clientSSL.bio_shutdown )
+
+
+    def test_outgoingOverflow(self):
+        """
+        If more bytes than can be written to the memory BIO are passed to
+        L{Connection.send} at once, the number of bytes which were written is
+        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()
+
+        self._loopback(client, server)
+
+        size = 2 ** 15
+        sent = client.send("x" * size)
+        # Sanity check.  We're trying to test what happens when the entire
+        # input can't be sent.  If the entire input was sent, this test is
+        # meaningless.
+        self.assertTrue(sent < size)
+
+        receiver, received = self._loopback(client, server)
+        self.assertIdentical(receiver, server)
+
+        # We can rely on all of these bytes being received at once because
+        # _loopback passes 2 ** 16 to recv - more than 2 ** 15.
+        self.assertEquals(len(received), sent)
+
+
+    def test_shutdown(self):
+        """
+        L{Connection.bio_shutdown} signals the end of the data stream from
+        which the L{Connection} reads.
+        """
+        server = self._server()
+        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)