Merge lp:~exarkun/pyopenssl/mem-bio into lp:~exarkun/pyopenssl/trunk

Proposed by Jean-Paul Calderone
Status: Merged
Merged at revision: not available
Proposed branch: lp:~exarkun/pyopenssl/mem-bio
Merge into: lp:~exarkun/pyopenssl/trunk
Diff against target: None lines
To merge this branch: bzr merge lp:~exarkun/pyopenssl/mem-bio
Reviewer Review Type Date Requested Status
Jean-Paul Calderone Pending
Review via email: mp+6225@code.launchpad.net
To post a comment you must log in.
lp:~exarkun/pyopenssl/mem-bio updated
110. By Jean-Paul Calderone

Make bio_shutdown raise an exception when called on a socket-based Connection

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'doc/pyOpenSSL.tex'
--- doc/pyOpenSSL.tex 2009-04-25 12:30:11 +0000
+++ doc/pyOpenSSL.tex 2009-05-03 23:45:07 +0000
@@ -681,10 +681,12 @@
681\end{datadesc}681\end{datadesc}
682682
683\begin{funcdesc}{Connection}{context, socket}683\begin{funcdesc}{Connection}{context, socket}
684Factory fucnction that creates a new Connection object given an SSL context and684Factory function that creates a new Connection object given an SSL context and
685a socket \footnote{Actually, all that is required is an object that685a socket \footnote{Actually, all that is required is an object that
686\emph{behaves} like a socket, you could even use files, even though it'd be686 \emph{behaves} like a socket, you could even use files, even though it'd be
687tricky to get the handshakes right!} object.687 tricky to get the handshakes right!} object. \var{socket} may be \var{None};
688in this case, the Connection is created with a memory BIO: see the
689\method{bio_read}, \method{bio_write}, and \method{bio_shutdown} methods.
688\end{funcdesc}690\end{funcdesc}
689691
690\begin{excdesc}{Error}692\begin{excdesc}{Error}
@@ -978,6 +980,12 @@
978by \var{bufsize}.980by \var{bufsize}.
979\end{methoddesc}981\end{methoddesc}
980982
983\begin{methoddesc}[Connection]{bio_write}{bytes}
984If the Connection was created with a memory BIO, this method can be used to add
985bytes to the read end of that memory BIO. The Connection can then read the
986bytes (for example, in response to a call to \method{recv}).
987\end{methoddesc}
988
981\begin{methoddesc}[Connection]{renegotiate}{}989\begin{methoddesc}[Connection]{renegotiate}{}
982Renegotiate the SSL session. Call this if you wish to change cipher suites or990Renegotiate the SSL session. Call this if you wish to change cipher suites or
983anything like that.991anything like that.
@@ -987,6 +995,13 @@
987Send the \var{string} data to the Connection.995Send the \var{string} data to the Connection.
988\end{methoddesc}996\end{methoddesc}
989997
998\begin{methoddesc}[Connection]{bio_read}{bufsize}
999If the Connection was created with a memory BIO, this method can be used to
1000read bytes from the write end of that memory BIO. Many Connection methods will
1001add bytes which must be read in this manner or the buffer will eventually fill
1002up and the Connection will be able to take no further actions.
1003\end{methoddesc}
1004
990\begin{methoddesc}[Connection]{sendall}{string}1005\begin{methoddesc}[Connection]{sendall}{string}
991Send all of the \var{string} data to the Connection. This calls \method{send}1006Send all of the \var{string} data to the Connection. This calls \method{send}
992repeatedly until all data is sent. If an error occurs, it's impossible to tell1007repeatedly until all data is sent. If an error occurs, it's impossible to tell
@@ -1037,10 +1052,28 @@
1037Call the \method{shutdown} method of the underlying socket.1052Call the \method{shutdown} method of the underlying socket.
1038\end{methoddesc}1053\end{methoddesc}
10391054
1055\begin{methoddesc}[Connection]{bio_shutdown}{}
1056If the Connection was created with a memory BIO, this method can be used to
1057indicate that ``end of file'' has been reached on the read end of that memory
1058BIO.
1059\end{methoddesc}
1060
1040\begin{methoddesc}[Connection]{state_string}{}1061\begin{methoddesc}[Connection]{state_string}{}
1041Retrieve a verbose string detailing the state of the Connection.1062Retrieve a verbose string detailing the state of the Connection.
1042\end{methoddesc}1063\end{methoddesc}
10431064
1065\begin{methoddesc}[Connection]{client_random}{}
1066Retrieve the random value used with the client hello message.
1067\end{methoddesc}
1068
1069\begin{methoddesc}[Connection]{server_random}{}
1070Retrieve the random value used with the server hello message.
1071\end{methoddesc}
1072
1073\begin{methoddesc}[Connection]{master_key}{}
1074Retrieve the value of the master key for this session.
1075\end{methoddesc}
1076
1044\begin{methoddesc}[Connection]{want_read}{}1077\begin{methoddesc}[Connection]{want_read}{}
1045Checks if more data has to be read from the transport layer to complete an1078Checks if more data has to be read from the transport layer to complete an
1046operation.1079operation.
10471080
=== modified file 'src/ssl/connection.c'
--- src/ssl/connection.c 2008-03-21 22:31:12 +0000
+++ src/ssl/connection.c 2009-05-01 00:24:35 +0000
@@ -23,8 +23,8 @@
23#endif23#endif
2424
25#define SSL_MODULE25#define SSL_MODULE
26#include <openssl/bio.h>
26#include <openssl/err.h>27#include <openssl/err.h>
27
28#include "ssl.h"28#include "ssl.h"
2929
30/**30/**
@@ -125,6 +125,50 @@
125}125}
126126
127/*127/*
128 * Handle errors raised by BIO functions.
129 *
130 * Arguments: bio - The BIO object
131 * ret - The return value of the BIO_ function.
132 * Returns: None, the calling function should return NULL;
133 */
134static void
135handle_bio_errors(BIO* bio, int ret)
136{
137 if (BIO_should_retry(bio)) {
138 if (BIO_should_read(bio)) {
139 PyErr_SetNone(ssl_WantReadError);
140 } else if (BIO_should_write(bio)) {
141 PyErr_SetNone(ssl_WantWriteError);
142 } else if (BIO_should_io_special(bio)) {
143 /*
144 * It's somewhat unclear what this means. From the OpenSSL source,
145 * it seems like it should not be triggered by the memory BIO, so
146 * for the time being, this case shouldn't come up. The SSL BIO
147 * (which I think should be named the socket BIO) may trigger this
148 * case if its socket is not yet connected or it is busy doing
149 * something related to x509.
150 */
151 PyErr_SetString(PyExc_ValueError, "BIO_should_io_special");
152 } else {
153 /*
154 * I hope this is dead code. The BIO documentation suggests that
155 * one of the above three checks should always be true.
156 */
157 PyErr_SetString(PyExc_ValueError, "unknown bio failure");
158 }
159 } else {
160 /*
161 * If we aren't to retry, it's really an error, so fall back to the
162 * normal error reporting code. However, the BIO interface does not
163 * specify a uniform error reporting mechanism. We can only hope that
164 * the code which triggered the error also kindly pushed something onto
165 * the error stack.
166 */
167 exception_from_error_queue();
168 }
169}
170
171/*
128 * Handle errors raised by SSL I/O functions. NOTE: Not SSL_shutdown ;)172 * Handle errors raised by SSL I/O functions. NOTE: Not SSL_shutdown ;)
129 *173 *
130 * Arguments: ssl - The SSL object174 * Arguments: ssl - The SSL object
@@ -239,6 +283,49 @@
239 return PyInt_FromLong((long)ret);283 return PyInt_FromLong((long)ret);
240}284}
241 285
286static char ssl_Connection_bio_write_doc[] = "\n\
287When using non-socket connections this function sends\n\
288\"dirty\" data that would have traveled in on the network.\n\
289\n\
290Arguments: self - The Connection object\n\
291 args - The Python argument tuple, should be:\n\
292 buf - The string to bio_write\n\
293Returns: The number of bytes written\n\
294";
295static PyObject *
296ssl_Connection_bio_write(ssl_ConnectionObj *self, PyObject *args)
297{
298 char *buf;
299 int len, ret;
300
301 if(self->into_ssl == NULL)
302 {
303 PyErr_SetString(PyExc_TypeError, "Connection sock was not None");
304 return NULL;
305 }
306
307 if (!PyArg_ParseTuple(args, "s#|i:bio_write", &buf, &len))
308 return NULL;
309
310 ret = BIO_write(self->into_ssl, buf, len);
311
312 if (PyErr_Occurred())
313 {
314 flush_error_queue();
315 return NULL;
316 }
317
318 if (ret <= 0) {
319 /*
320 * There was a problem with the BIO_write of some sort.
321 */
322 handle_bio_errors(self->into_ssl, ret);
323 return NULL;
324 }
325
326 return PyInt_FromLong((long)ret);
327}
328
242static char ssl_Connection_send_doc[] = "\n\329static char ssl_Connection_send_doc[] = "\n\
243Send data on the connection. NOTE: If you get one of the WantRead,\n\330Send data on the connection. NOTE: If you get one of the WantRead,\n\
244WantWrite or WantX509Lookup exceptions on this, you have to call the\n\331WantWrite or WantX509Lookup exceptions on this, you have to call the\n\
@@ -384,6 +471,63 @@
384 }471 }
385}472}
386473
474static char ssl_Connection_bio_read_doc[] = "\n\
475When using non-socket connections this function reads\n\
476the \"dirty\" data that would have traveled away on the network.\n\
477\n\
478Arguments: self - The Connection object\n\
479 args - The Python argument tuple, should be:\n\
480 bufsiz - The maximum number of bytes to read\n\
481Returns: The string read.\n\
482";
483static PyObject *
484ssl_Connection_bio_read(ssl_ConnectionObj *self, PyObject *args)
485{
486 int bufsiz, ret;
487 PyObject *buf;
488
489 if(self->from_ssl == NULL)
490 {
491 PyErr_SetString(PyExc_TypeError, "Connection sock was not None");
492 return NULL;
493 }
494
495 if (!PyArg_ParseTuple(args, "i:bio_read", &bufsiz))
496 return NULL;
497
498 buf = PyString_FromStringAndSize(NULL, bufsiz);
499 if (buf == NULL)
500 return NULL;
501
502 ret = BIO_read(self->from_ssl, PyString_AsString(buf), bufsiz);
503
504 if (PyErr_Occurred())
505 {
506 Py_DECREF(buf);
507 flush_error_queue();
508 return NULL;
509 }
510
511 if (ret <= 0) {
512 /*
513 * There was a problem with the BIO_read of some sort.
514 */
515 handle_bio_errors(self->from_ssl, ret);
516 Py_DECREF(buf);
517 return NULL;
518 }
519
520 /*
521 * Shrink the string to match the number of bytes we actually read.
522 */
523 if (ret != bufsiz && _PyString_Resize(&buf, ret) < 0)
524 {
525 Py_DECREF(buf);
526 return NULL;
527 }
528 return buf;
529}
530
387static char ssl_Connection_renegotiate_doc[] = "\n\531static char ssl_Connection_renegotiate_doc[] = "\n\
388Renegotiate the session\n\532Renegotiate the session\n\
389\n\533\n\
@@ -626,6 +770,25 @@
626 return tuple;770 return tuple;
627}771}
628772
773static char ssl_Connection_bio_shutdown_doc[] = "\n\
774When using non-socket connections this function signals end of\n\
775data on the input for this connection.\n\
776\n\
777Arguments: self - The Connection object\n\
778 args - The Python argument tuple, should be empty.\n\
779Returns: Nothing\n\
780";
781
782static PyObject *
783ssl_Connection_bio_shutdown(ssl_ConnectionObj *self, PyObject *args)
784{
785 BIO_set_mem_eof_return(self->into_ssl, 0);
786 Py_INCREF(Py_None);
787 return Py_None;
788}
789
790
791
629static char ssl_Connection_shutdown_doc[] = "\n\792static char ssl_Connection_shutdown_doc[] = "\n\
630Send closure alert\n\793Send closure alert\n\
631\n\794\n\
@@ -810,6 +973,66 @@
810 return PyString_FromString(SSL_state_string_long(self->ssl));973 return PyString_FromString(SSL_state_string_long(self->ssl));
811}974}
812975
976static char ssl_Connection_client_random_doc[] = "\n\
977Get a copy of the client hello nonce.\n\
978\n\
979Arguments: self - The Connection object\n\
980 args - The Python argument tuple, should be empty\n\
981Returns: A string representing the state\n\
982";
983static PyObject *
984ssl_Connection_client_random(ssl_ConnectionObj *self, PyObject *args)
985{
986 if (!PyArg_ParseTuple(args, ":client_random"))
987 return NULL;
988
989 if( self->ssl->session == NULL) {
990 Py_INCREF(Py_None);
991 return Py_None;
992 }
993 return PyString_FromStringAndSize( (const char *) self->ssl->s3->client_random, SSL3_RANDOM_SIZE);
994}
995
996static char ssl_Connection_server_random_doc[] = "\n\
997Get a copy of the server hello nonce.\n\
998\n\
999Arguments: self - The Connection object\n\
1000 args - The Python argument tuple, should be empty\n\
1001Returns: A string representing the state\n\
1002";
1003static PyObject *
1004ssl_Connection_server_random(ssl_ConnectionObj *self, PyObject *args)
1005{
1006 if (!PyArg_ParseTuple(args, ":server_random"))
1007 return NULL;
1008
1009 if( self->ssl->session == NULL) {
1010 Py_INCREF(Py_None);
1011 return Py_None;
1012 }
1013 return PyString_FromStringAndSize( (const char *) self->ssl->s3->server_random, SSL3_RANDOM_SIZE);
1014}
1015
1016static char ssl_Connection_master_key_doc[] = "\n\
1017Get a copy of the master key.\n\
1018\n\
1019Arguments: self - The Connection object\n\
1020 args - The Python argument tuple, should be empty\n\
1021Returns: A string representing the state\n\
1022";
1023static PyObject *
1024ssl_Connection_master_key(ssl_ConnectionObj *self, PyObject *args)
1025{
1026 if (!PyArg_ParseTuple(args, ":master_key"))
1027 return NULL;
1028
1029 if( self->ssl->session == NULL) {
1030 Py_INCREF(Py_None);
1031 return Py_None;
1032 }
1033 return PyString_FromStringAndSize( (const char *) self->ssl->session->master_key, self->ssl->session->master_key_length);
1034}
1035
813static char ssl_Connection_sock_shutdown_doc[] = "\n\1036static char ssl_Connection_sock_shutdown_doc[] = "\n\
814See shutdown(2)\n\1037See shutdown(2)\n\
815\n\1038\n\
@@ -912,6 +1135,8 @@
912 ADD_METHOD(sendall),1135 ADD_METHOD(sendall),
913 ADD_METHOD(recv),1136 ADD_METHOD(recv),
914 ADD_ALIAS (read, recv),1137 ADD_ALIAS (read, recv),
1138 ADD_METHOD(bio_read),
1139 ADD_METHOD(bio_write),
915 ADD_METHOD(renegotiate),1140 ADD_METHOD(renegotiate),
916 ADD_METHOD(do_handshake),1141 ADD_METHOD(do_handshake),
917#if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x00907000L1142#if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x00907000L
@@ -921,6 +1146,7 @@
921 ADD_METHOD(connect),1146 ADD_METHOD(connect),
922 ADD_METHOD(connect_ex),1147 ADD_METHOD(connect_ex),
923 ADD_METHOD(accept),1148 ADD_METHOD(accept),
1149 ADD_METHOD(bio_shutdown),
924 ADD_METHOD(shutdown),1150 ADD_METHOD(shutdown),
925 ADD_METHOD(get_cipher_list),1151 ADD_METHOD(get_cipher_list),
926 ADD_METHOD(makefile),1152 ADD_METHOD(makefile),
@@ -929,6 +1155,9 @@
929 ADD_METHOD(get_shutdown),1155 ADD_METHOD(get_shutdown),
930 ADD_METHOD(set_shutdown),1156 ADD_METHOD(set_shutdown),
931 ADD_METHOD(state_string),1157 ADD_METHOD(state_string),
1158 ADD_METHOD(server_random),
1159 ADD_METHOD(client_random),
1160 ADD_METHOD(master_key),
932 ADD_METHOD(sock_shutdown),1161 ADD_METHOD(sock_shutdown),
933 ADD_METHOD(get_peer_certificate),1162 ADD_METHOD(get_peer_certificate),
934 ADD_METHOD(want_read),1163 ADD_METHOD(want_read),
@@ -965,26 +1194,50 @@
965 self->socket = sock;1194 self->socket = sock;
9661195
967 self->ssl = NULL;1196 self->ssl = NULL;
1197 self->from_ssl = NULL;
1198 self->into_ssl = NULL;
9681199
969 Py_INCREF(Py_None);1200 Py_INCREF(Py_None);
970 self->app_data = Py_None;1201 self->app_data = Py_None;
9711202
972 self->tstate = NULL;1203 self->tstate = NULL;
9731204
974 fd = PyObject_AsFileDescriptor(self->socket);
975 if (fd < 0)
976 {
977 Py_DECREF(self);
978 return NULL;
979 }
980
981 self->ssl = SSL_new(self->context->ctx);1205 self->ssl = SSL_new(self->context->ctx);
982 SSL_set_app_data(self->ssl, self);1206 SSL_set_app_data(self->ssl, self);
983 SSL_set_fd(self->ssl, (SOCKET_T)fd);1207
1208 if(self->socket == Py_None)
1209 {
1210 /* If it's not a socket or file, treat it like a memory buffer,
1211 * so crazy people can do things like EAP-TLS. */
1212 self->into_ssl = BIO_new(BIO_s_mem());
1213 self->from_ssl = BIO_new(BIO_s_mem());
1214 if(self->into_ssl == NULL || self->from_ssl == NULL)
1215 goto error;
1216 SSL_set_bio(self->ssl, self->into_ssl, self->from_ssl);
1217 }
1218 else
1219 {
1220 fd = PyObject_AsFileDescriptor(self->socket);
1221 if (fd < 0)
1222 {
1223 Py_DECREF(self);
1224 return NULL;
1225 }
1226 else
1227 {
1228 SSL_set_fd(self->ssl, (SOCKET_T)fd);
1229 }
1230 }
9841231
985 PyObject_GC_Track(self);1232 PyObject_GC_Track(self);
9861233
987 return self;1234 return self;
1235
1236error:
1237 BIO_free(self->into_ssl); /* NULL safe */
1238 BIO_free(self->from_ssl); /* NULL safe */
1239 Py_DECREF(self);
1240 return NULL;
988}1241}
9891242
990/*1243/*
@@ -1050,6 +1303,8 @@
1050 self->socket = NULL;1303 self->socket = NULL;
1051 Py_XDECREF(self->app_data);1304 Py_XDECREF(self->app_data);
1052 self->app_data = NULL;1305 self->app_data = NULL;
1306 self->into_ssl = NULL; /* was cleaned up by SSL_free() */
1307 self->from_ssl = NULL; /* was cleaned up by SSL_free() */
1053 return 0;1308 return 0;
1054}1309}
10551310
10561311
=== modified file 'src/ssl/connection.h'
--- src/ssl/connection.h 2008-09-21 21:42:34 +0000
+++ src/ssl/connection.h 2009-04-01 19:09:23 +0000
@@ -44,6 +44,7 @@
44 PyObject *socket;44 PyObject *socket;
45 PyThreadState *tstate; /* This field is no longer used. */45 PyThreadState *tstate; /* This field is no longer used. */
46 PyObject *app_data;46 PyObject *app_data;
47 BIO *into_ssl, *from_ssl; /* for connections without file descriptors */
47} ssl_ConnectionObj;48} ssl_ConnectionObj;
4849
4950
5051
=== modified file 'test/test_crypto.py'
--- test/test_crypto.py 2009-04-01 18:42:32 +0000
+++ test/test_crypto.py 2009-05-04 22:27:52 +0000
@@ -732,7 +732,7 @@
732 Run the command line openssl tool with the given arguments and write732 Run the command line openssl tool with the given arguments and write
733 the given PEM to its stdin.733 the given PEM to its stdin.
734 """734 """
735 write, read = popen2(" ".join(("openssl",) + args))735 write, read = popen2(" ".join(("openssl",) + args), "b")
736 write.write(pem)736 write.write(pem)
737 write.close()737 write.close()
738 return read.read()738 return read.read()
739739
=== modified file 'test/test_ssl.py'
--- test/test_ssl.py 2009-04-01 16:34:06 +0000
+++ test/test_ssl.py 2009-05-01 00:24:35 +0000
@@ -15,12 +15,13 @@
15 from twisted.trial.unittest import TestCase15 from twisted.trial.unittest import TestCase
16except ImportError:16except ImportError:
17 # Fall back to the stdlib TestCase though, since it kind of works.17 # Fall back to the stdlib TestCase though, since it kind of works.
18 from unittest import TestCase, main18 from unittest import TestCase
1919
20from OpenSSL.crypto import TYPE_RSA, FILETYPE_PEM, PKey, dump_privatekey, load_certificate, load_privatekey20from OpenSSL.crypto import TYPE_RSA, FILETYPE_PEM, PKey, dump_privatekey, load_certificate, load_privatekey
21from OpenSSL.SSL import WantReadError, Context, Connection, Error21from OpenSSL.SSL import WantReadError, Context, Connection, Error
22from OpenSSL.SSL import SSLv2_METHOD, SSLv3_METHOD, SSLv23_METHOD, TLSv1_METHOD22from OpenSSL.SSL import SSLv2_METHOD, SSLv3_METHOD, SSLv23_METHOD, TLSv1_METHOD
23from OpenSSL.SSL import VERIFY_PEER23from OpenSSL.SSL import OP_NO_SSLv2, OP_NO_SSLv3, OP_SINGLE_DH_USE
24from OpenSSL.SSL import VERIFY_PEER, VERIFY_FAIL_IF_NO_PEER_CERT, VERIFY_CLIENT_ONCE
24from OpenSSL.test.test_crypto import _Python23TestCaseHelper, cleartextCertificatePEM, cleartextPrivateKeyPEM25from OpenSSL.test.test_crypto import _Python23TestCaseHelper, cleartextCertificatePEM, cleartextPrivateKeyPEM
25try:26try:
26 from OpenSSL.SSL import OP_NO_QUERY_MTU27 from OpenSSL.SSL import OP_NO_QUERY_MTU
@@ -313,6 +314,286 @@
313 "OP_NO_TICKET unavailable - OpenSSL version may be too old"314 "OP_NO_TICKET unavailable - OpenSSL version may be too old"
314315
315316
316if __name__ == '__main__':317
317 main()318root_cert_pem = """-----BEGIN CERTIFICATE-----
318319MIIC7TCCAlagAwIBAgIIPQzE4MbeufQwDQYJKoZIhvcNAQEFBQAwWDELMAkGA1UE
320BhMCVVMxCzAJBgNVBAgTAklMMRAwDgYDVQQHEwdDaGljYWdvMRAwDgYDVQQKEwdU
321ZXN0aW5nMRgwFgYDVQQDEw9UZXN0aW5nIFJvb3QgQ0EwIhgPMjAwOTAzMjUxMjM2
322NThaGA8yMDE3MDYxMTEyMzY1OFowWDELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAklM
323MRAwDgYDVQQHEwdDaGljYWdvMRAwDgYDVQQKEwdUZXN0aW5nMRgwFgYDVQQDEw9U
324ZXN0aW5nIFJvb3QgQ0EwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAPmaQumL
325urpE527uSEHdL1pqcDRmWzu+98Y6YHzT/J7KWEamyMCNZ6fRW1JCR782UQ8a07fy
3262xXsKy4WdKaxyG8CcatwmXvpvRQ44dSANMihHELpANTdyVp6DCysED6wkQFurHlF
3271dshEaJw8b/ypDhmbVIo6Ci1xvCJqivbLFnbAgMBAAGjgbswgbgwHQYDVR0OBBYE
328FINVdy1eIfFJDAkk51QJEo3IfgSuMIGIBgNVHSMEgYAwfoAUg1V3LV4h8UkMCSTn
329VAkSjch+BK6hXKRaMFgxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJJTDEQMA4GA1UE
330BxMHQ2hpY2FnbzEQMA4GA1UEChMHVGVzdGluZzEYMBYGA1UEAxMPVGVzdGluZyBS
331b290IENBggg9DMTgxt659DAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GB
332AGGCDazMJGoWNBpc03u6+smc95dEead2KlZXBATOdFT1VesY3+nUOqZhEhTGlDMi
333hkgaZnzoIq/Uamidegk4hirsCT/R+6vsKAAxNTcBjUeZjlykCJWy5ojShGftXIKY
334w/njVbKMXrvc83qmTdGl3TAM0fxQIpqgcglFLveEBgzn
335-----END CERTIFICATE-----
336"""
337
338root_key_pem = """-----BEGIN RSA PRIVATE KEY-----
339MIICXQIBAAKBgQD5mkLpi7q6ROdu7khB3S9aanA0Zls7vvfGOmB80/yeylhGpsjA
340jWen0VtSQke/NlEPGtO38tsV7CsuFnSmschvAnGrcJl76b0UOOHUgDTIoRxC6QDU
3413claegwsrBA+sJEBbqx5RdXbIRGicPG/8qQ4Zm1SKOgotcbwiaor2yxZ2wIDAQAB
342AoGBAPCgMpmLxzwDaUmcFbTJUvlLW1hoxNNYSu2jIZm1k/hRAcE60JYwvBkgz3UB
343yMEh0AtLxYe0bFk6EHah11tMUPgscbCq73snJ++8koUw+csk22G65hOs51bVb7Aa
3446JBe67oLzdtvgCUFAA2qfrKzWRZzAdhUirQUZgySZk+Xq1pBAkEA/kZG0A6roTSM
345BVnx7LnPfsycKUsTumorpXiylZJjTi9XtmzxhrYN6wgZlDOOwOLgSQhszGpxVoMD
346u3gByT1b2QJBAPtL3mSKdvwRu/+40zaZLwvSJRxaj0mcE4BJOS6Oqs/hS1xRlrNk
347PpQ7WJ4yM6ZOLnXzm2mKyxm50Mv64109FtMCQQDOqS2KkjHaLowTGVxwC0DijMfr
348I9Lf8sSQk32J5VWCySWf5gGTfEnpmUa41gKTMJIbqZZLucNuDcOtzUaeWZlZAkA8
349ttXigLnCqR486JDPTi9ZscoZkZ+w7y6e/hH8t6d5Vjt48JVyfjPIaJY+km58LcN3
3506AWSeGAdtRFHVzR7oHjVAkB4hutvxiOeiIVQNBhM6RSI9aBPMI21DoX2JRoxvNW2
351cbvAhow217X9V0dVerEOKxnNYspXRrh36h7k4mQA+sDq
352-----END RSA PRIVATE KEY-----
353"""
354
355server_cert_pem = """-----BEGIN CERTIFICATE-----
356MIICKDCCAZGgAwIBAgIJAJn/HpR21r/8MA0GCSqGSIb3DQEBBQUAMFgxCzAJBgNV
357BAYTAlVTMQswCQYDVQQIEwJJTDEQMA4GA1UEBxMHQ2hpY2FnbzEQMA4GA1UEChMH
358VGVzdGluZzEYMBYGA1UEAxMPVGVzdGluZyBSb290IENBMCIYDzIwMDkwMzI1MTIz
359NzUzWhgPMjAxNzA2MTExMjM3NTNaMBgxFjAUBgNVBAMTDWxvdmVseSBzZXJ2ZXIw
360gZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAL6m+G653V0tpBC/OKl22VxOi2Cv
361lK4TYu9LHSDP9uDVTe7V5D5Tl6qzFoRRx5pfmnkqT5B+W9byp2NU3FC5hLm5zSAr
362b45meUhjEJ/ifkZgbNUjHdBIGP9MAQUHZa5WKdkGIJvGAvs8UzUqlr4TBWQIB24+
363lJ+Ukk/CRgasrYwdAgMBAAGjNjA0MB0GA1UdDgQWBBS4kC7Ij0W1TZXZqXQFAM2e
364gKEG2DATBgNVHSUEDDAKBggrBgEFBQcDATANBgkqhkiG9w0BAQUFAAOBgQBh30Li
365dJ+NlxIOx5343WqIBka3UbsOb2kxWrbkVCrvRapCMLCASO4FqiKWM+L0VDBprqIp
3662mgpFQ6FHpoIENGvJhdEKpptQ5i7KaGhnDNTfdy3x1+h852G99f1iyj0RmbuFcM8
367uzujnS8YXWvM7DM1Ilozk4MzPug8jzFp5uhKCQ==
368-----END CERTIFICATE-----
369"""
370
371server_key_pem = """-----BEGIN RSA PRIVATE KEY-----
372MIICWwIBAAKBgQC+pvhuud1dLaQQvzipdtlcTotgr5SuE2LvSx0gz/bg1U3u1eQ+
373U5eqsxaEUceaX5p5Kk+QflvW8qdjVNxQuYS5uc0gK2+OZnlIYxCf4n5GYGzVIx3Q
374SBj/TAEFB2WuVinZBiCbxgL7PFM1Kpa+EwVkCAduPpSflJJPwkYGrK2MHQIDAQAB
375AoGAbwuZ0AR6JveahBaczjfnSpiFHf+mve2UxoQdpyr6ROJ4zg/PLW5K/KXrC48G
376j6f3tXMrfKHcpEoZrQWUfYBRCUsGD5DCazEhD8zlxEHahIsqpwA0WWssJA2VOLEN
377j6DuV2pCFbw67rfTBkTSo32ahfXxEKev5KswZk0JIzH3ooECQQDgzS9AI89h0gs8
378Dt+1m11Rzqo3vZML7ZIyGApUzVan+a7hbc33nbGRkAXjHaUBJO31it/H6dTO+uwX
379msWwNG5ZAkEA2RyFKs5xR5USTFaKLWCgpH/ydV96KPOpBND7TKQx62snDenFNNbn
380FwwOhpahld+vqhYk+pfuWWUpQciE+Bu7ZQJASjfT4sQv4qbbKK/scePicnDdx9th
3814e1EeB9xwb+tXXXUo/6Bor/AcUNwfiQ6Zt9PZOK9sR3lMZSsP7rMi7kzuQJABie6
3821sXXjFH7nNJvRG4S39cIxq8YRYTy68II/dlB2QzGpKxV/POCxbJ/zu0CU79tuYK7
383NaeNCFfH3aeTrX0LyQJAMBWjWmeKM2G2sCExheeQK0ROnaBC8itCECD4Jsve4nqf
384r50+LF74iLXFwqysVCebPKMOpDWp/qQ1BbJQIPs7/A==
385-----END RSA PRIVATE KEY-----
386"""
387
388client_cert_pem = """-----BEGIN CERTIFICATE-----
389MIICJjCCAY+gAwIBAgIJAKxpFI5lODkjMA0GCSqGSIb3DQEBBQUAMFgxCzAJBgNV
390BAYTAlVTMQswCQYDVQQIEwJJTDEQMA4GA1UEBxMHQ2hpY2FnbzEQMA4GA1UEChMH
391VGVzdGluZzEYMBYGA1UEAxMPVGVzdGluZyBSb290IENBMCIYDzIwMDkwMzI1MTIz
392ODA1WhgPMjAxNzA2MTExMjM4MDVaMBYxFDASBgNVBAMTC3VnbHkgY2xpZW50MIGf
393MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDAZh/SRtNm5ntMT4qb6YzEpTroMlq2
394rn+GrRHRiZ+xkCw/CGNhbtPir7/QxaUj26BSmQrHw1bGKEbPsWiW7bdXSespl+xK
395iku4G/KvnnmWdeJHqsiXeUZtqurMELcPQAw9xPHEuhqqUJvvEoMTsnCEqGM+7Dtb
396oCRajYyHfluARQIDAQABozYwNDAdBgNVHQ4EFgQUNQB+qkaOaEVecf1J3TTUtAff
3970fAwEwYDVR0lBAwwCgYIKwYBBQUHAwIwDQYJKoZIhvcNAQEFBQADgYEAyv/Jh7gM
398Q3OHvmsFEEvRI+hsW8y66zK4K5de239Y44iZrFYkt7Q5nBPMEWDj4F2hLYWL/qtI
3999Zdr0U4UDCU9SmmGYh4o7R4TZ5pGFvBYvjhHbkSFYFQXZxKUi+WUxplP6I0wr2KJ
400PSTJCjJOn3xo2NTKRgV1gaoTf2EhL+RG8TQ=
401-----END CERTIFICATE-----
402"""
403
404client_key_pem = """-----BEGIN RSA PRIVATE KEY-----
405MIICXgIBAAKBgQDAZh/SRtNm5ntMT4qb6YzEpTroMlq2rn+GrRHRiZ+xkCw/CGNh
406btPir7/QxaUj26BSmQrHw1bGKEbPsWiW7bdXSespl+xKiku4G/KvnnmWdeJHqsiX
407eUZtqurMELcPQAw9xPHEuhqqUJvvEoMTsnCEqGM+7DtboCRajYyHfluARQIDAQAB
408AoGATkZ+NceY5Glqyl4mD06SdcKfV65814vg2EL7V9t8+/mi9rYL8KztSXGlQWPX
409zuHgtRoMl78yQ4ZJYOBVo+nsx8KZNRCEBlE19bamSbQLCeQMenWnpeYyQUZ908gF
410h6L9qsFVJepgA9RDgAjyDoS5CaWCdCCPCH2lDkdcqC54SVUCQQDseuduc4wi8h4t
411V8AahUn9fn9gYfhoNuM0gdguTA0nPLVWz4hy1yJiWYQe0H7NLNNTmCKiLQaJpAbb
412TC6vE8C7AkEA0Ee8CMJUc20BnGEmxwgWcVuqFWaKCo8jTH1X38FlATUsyR3krjW2
413dL3yDD9NwHxsYP7nTKp/U8MV7U9IBn4y/wJBAJl7H0/BcLeRmuJk7IqJ7b635iYB
414D/9beFUw3MUXmQXZUfyYz39xf6CDZsu1GEdEC5haykeln3Of4M9d/4Kj+FcCQQCY
415si6xwT7GzMDkk/ko684AV3KPc/h6G0yGtFIrMg7J3uExpR/VdH2KgwMkZXisSMvw
416JJEQjOMCVsEJlRk54WWjAkEAzoZNH6UhDdBK5F38rVt/y4SEHgbSfJHIAmPS32Kq
417f6GGcfNpip0Uk7q7udTKuX7Q/buZi/C4YW7u3VKAquv9NA==
418-----END RSA PRIVATE KEY-----
419"""
420
421def verify_cb(conn, cert, errnum, depth, ok):
422 return ok
423
424class MemoryBIOTests(TestCase):
425 """
426 Tests for L{OpenSSL.SSL.Connection} using a memory BIO.
427 """
428 def _server(self):
429 # Create the server side Connection. This is mostly setup boilerplate
430 # - use TLSv1, use a particular certificate, etc.
431 server_ctx = Context(TLSv1_METHOD)
432 server_ctx.set_options(OP_NO_SSLv2 | OP_NO_SSLv3 | OP_SINGLE_DH_USE )
433 server_ctx.set_verify(VERIFY_PEER|VERIFY_FAIL_IF_NO_PEER_CERT|VERIFY_CLIENT_ONCE, verify_cb)
434 server_store = server_ctx.get_cert_store()
435 server_ctx.use_privatekey(load_privatekey(FILETYPE_PEM, server_key_pem))
436 server_ctx.use_certificate(load_certificate(FILETYPE_PEM, server_cert_pem))
437 server_ctx.check_privatekey()
438 server_store.add_cert(load_certificate(FILETYPE_PEM, root_cert_pem))
439 # Here the Connection is actually created. None is passed as the 2nd
440 # parameter, indicating a memory BIO should be created.
441 server_conn = Connection(server_ctx, None)
442 server_conn.set_accept_state()
443 return server_conn
444
445
446 def _client(self):
447 # Now create the client side Connection. Similar boilerplate to the above.
448 client_ctx = Context(TLSv1_METHOD)
449 client_ctx.set_options(OP_NO_SSLv2 | OP_NO_SSLv3 | OP_SINGLE_DH_USE )
450 client_ctx.set_verify(VERIFY_PEER|VERIFY_FAIL_IF_NO_PEER_CERT|VERIFY_CLIENT_ONCE, verify_cb)
451 client_store = client_ctx.get_cert_store()
452 client_ctx.use_privatekey(load_privatekey(FILETYPE_PEM, client_key_pem))
453 client_ctx.use_certificate(load_certificate(FILETYPE_PEM, client_cert_pem))
454 client_ctx.check_privatekey()
455 client_store.add_cert(load_certificate(FILETYPE_PEM, root_cert_pem))
456 # Again, None to create a new memory BIO.
457 client_conn = Connection(client_ctx, None)
458 client_conn.set_connect_state()
459 return client_conn
460
461
462 def _loopback(self, client_conn, server_conn):
463 """
464 Try to read application bytes from each of the two L{Connection}
465 objects. Copy bytes back and forth between their send/receive buffers
466 for as long as there is anything to copy. When there is nothing more
467 to copy, return C{None}. If one of them actually manages to deliver
468 some application bytes, return a two-tuple of the connection from which
469 the bytes were read and the bytes themselves.
470 """
471 wrote = True
472 while wrote:
473 # Loop until neither side has anything to say
474 wrote = False
475
476 # Copy stuff from each side's send buffer to the other side's
477 # receive buffer.
478 for (read, write) in [(client_conn, server_conn),
479 (server_conn, client_conn)]:
480
481 # Give the side a chance to generate some more bytes, or
482 # succeed.
483 try:
484 bytes = read.recv(2 ** 16)
485 except WantReadError:
486 # It didn't succeed, so we'll hope it generated some
487 # output.
488 pass
489 else:
490 # It did succeed, so we'll stop now and let the caller deal
491 # with it.
492 return (read, bytes)
493
494 while True:
495 # Keep copying as long as there's more stuff there.
496 try:
497 dirty = read.bio_read(4096)
498 except WantReadError:
499 # Okay, nothing more waiting to be sent. Stop
500 # processing this send buffer.
501 break
502 else:
503 # Keep track of the fact that someone generated some
504 # output.
505 wrote = True
506 write.bio_write(dirty)
507
508
509 def test_connect(self):
510 """
511 Two L{Connection}s which use memory BIOs can be manually connected by
512 reading from the output of each and writing those bytes to the input of
513 the other and in this way establish a connection and exchange
514 application-level bytes with each other.
515 """
516 server_conn = self._server()
517 client_conn = self._client()
518
519 # There should be no key or nonces yet.
520 self.assertIdentical(server_conn.master_key(), None)
521 self.assertIdentical(server_conn.client_random(), None)
522 self.assertIdentical(server_conn.server_random(), None)
523
524 # First, the handshake needs to happen. We'll deliver bytes back and
525 # forth between the client and server until neither of them feels like
526 # speaking any more.
527 self.assertIdentical(self._loopback(client_conn, server_conn), None)
528
529 # Now that the handshake is done, there should be a key and nonces.
530 self.assertNotIdentical(server_conn.master_key(), None)
531 self.assertNotIdentical(server_conn.client_random(), None)
532 self.assertNotIdentical(server_conn.server_random(), None)
533 self.assertNotIdentical(server_conn.client_random(), client_conn.client_random())
534 self.assertNotIdentical(server_conn.server_random(), client_conn.server_random())
535
536 # Here are the bytes we'll try to send.
537 important_message = 'One if by land, two if by sea.'
538
539 server_conn.write(important_message)
540 self.assertEquals(
541 self._loopback(client_conn, server_conn),
542 (client_conn, important_message))
543
544 client_conn.write(important_message[::-1])
545 self.assertEquals(
546 self._loopback(client_conn, server_conn),
547 (server_conn, important_message[::-1]))
548
549
550 def test_socketOverridesMemory(self):
551 """
552 Test that L{OpenSSL.SSL.bio_read} and L{OpenSSL.SSL.bio_write} don't
553 work on L{OpenSSL.SSL.Connection}() that use sockets.
554 """
555 context = Context(SSLv3_METHOD)
556 client = socket()
557 clientSSL = Connection(context, client)
558 self.assertRaises( TypeError, clientSSL.bio_read, 100)
559 self.assertRaises( TypeError, clientSSL.bio_write, "foo")
560
561
562 def test_outgoingOverflow(self):
563 """
564 If more bytes than can be written to the memory BIO are passed to
565 L{Connection.send} at once, the number of bytes which were written is
566 returned and that many bytes from the beginning of the input can be
567 read from the other end of the connection.
568 """
569 server = self._server()
570 client = self._client()
571
572 self._loopback(client, server)
573
574 size = 2 ** 15
575 sent = client.send("x" * size)
576 # Sanity check. We're trying to test what happens when the entire
577 # input can't be sent. If the entire input was sent, this test is
578 # meaningless.
579 self.assertTrue(sent < size)
580
581 receiver, received = self._loopback(client, server)
582 self.assertIdentical(receiver, server)
583
584 # We can rely on all of these bytes being received at once because
585 # _loopback passes 2 ** 16 to recv - more than 2 ** 15.
586 self.assertEquals(len(received), sent)
587
588
589 def test_shutdown(self):
590 """
591 L{Connection.bio_shutdown} signals the end of the data stream from
592 which the L{Connection} reads.
593 """
594 server = self._server()
595 server.bio_shutdown()
596 e = self.assertRaises(Error, server.recv, 1024)
597 # We don't want WantReadError or ZeroReturnError or anything - it's a
598 # handshake failure.
599 self.assertEquals(e.__class__, Error)

Subscribers

People subscribed via source and target branches

to status/vote changes: