blob: d7e04dad772a0c0ad7c85fc66ac2077ce97cc707 [file] [log] [blame]
Jean-Paul Calderone8b63d452008-03-21 18:31:12 -04001# Copyright (C) Jean-Paul Calderone 2008, All rights reserved
2
Jean-Paul Calderone30c09ea2008-03-21 17:04:05 -04003"""
4Unit tests for L{OpenSSL.SSL}.
5"""
6
Jean-Paul Calderone52f0d8b2009-03-07 09:10:19 -05007from sys import platform
Jean-Paul Calderone5ef86512008-04-26 19:06:28 -04008from socket import socket
Jean-Paul Calderonea65cf6c2009-07-19 10:26:52 -04009from os import makedirs
Jean-Paul Calderone1cb5d022008-09-07 20:58:50 -040010from os.path import join
Jean-Paul Calderone0b88b6a2009-07-05 12:44:41 -040011from unittest import main
Jean-Paul Calderone460cc1f2009-03-07 11:31:12 -050012
Jean-Paul Calderone5ef86512008-04-26 19:06:28 -040013from OpenSSL.crypto import TYPE_RSA, FILETYPE_PEM, PKey, dump_privatekey, load_certificate, load_privatekey
Rick Deane15b1472009-07-09 15:53:42 -050014from OpenSSL.SSL import WantReadError, Context, ContextType, Connection, ConnectionType, Error
Jean-Paul Calderone30c09ea2008-03-21 17:04:05 -040015from OpenSSL.SSL import SSLv2_METHOD, SSLv3_METHOD, SSLv23_METHOD, TLSv1_METHOD
Jean-Paul Calderone68649052009-07-17 21:14:27 -040016from OpenSSL.SSL import OP_NO_SSLv2, OP_NO_SSLv3, OP_SINGLE_DH_USE
Rick Deanb71c0d22009-04-01 14:09:23 -050017from OpenSSL.SSL import VERIFY_PEER, VERIFY_FAIL_IF_NO_PEER_CERT, VERIFY_CLIENT_ONCE
Jean-Paul Calderone0b88b6a2009-07-05 12:44:41 -040018from OpenSSL.test.util import TestCase
Jean-Paul Calderone18808652009-07-05 12:54:05 -040019from OpenSSL.test.test_crypto import cleartextCertificatePEM, cleartextPrivateKeyPEM
Rick Dean94e46fd2009-07-18 14:51:24 -050020from OpenSSL.test.test_crypto import client_cert_pem, client_key_pem, server_cert_pem, server_key_pem, root_cert_pem
Jean-Paul Calderone4bccf5e2008-12-28 22:50:42 -050021try:
22 from OpenSSL.SSL import OP_NO_QUERY_MTU
23except ImportError:
24 OP_NO_QUERY_MTU = None
25try:
26 from OpenSSL.SSL import OP_COOKIE_EXCHANGE
27except ImportError:
28 OP_COOKIE_EXCHANGE = None
29try:
30 from OpenSSL.SSL import OP_NO_TICKET
31except ImportError:
32 OP_NO_TICKET = None
Jean-Paul Calderone5ef86512008-04-26 19:06:28 -040033
Jean-Paul Calderone30c09ea2008-03-21 17:04:05 -040034
Rick Deanb1ccd562009-07-09 23:52:39 -050035def socket_pair():
Jean-Paul Calderone1a9613b2009-07-16 12:13:36 -040036 """
Jean-Paul Calderone68649052009-07-17 21:14:27 -040037 Establish and return a pair of network sockets connected to each other.
Jean-Paul Calderone1a9613b2009-07-16 12:13:36 -040038 """
39 # Connect a pair of sockets
Rick Deanb1ccd562009-07-09 23:52:39 -050040 port = socket()
41 port.bind(('', 0))
42 port.listen(1)
43 client = socket()
44 client.setblocking(False)
Jean-Paul Calderonef23c5d92009-07-23 17:58:15 -040045 client.connect_ex(("127.0.0.1", port.getsockname()[1]))
Jean-Paul Calderone94b24a82009-07-16 19:11:38 -040046 client.setblocking(True)
Rick Deanb1ccd562009-07-09 23:52:39 -050047 server = port.accept()[0]
Rick Deanb1ccd562009-07-09 23:52:39 -050048
Jean-Paul Calderone1a9613b2009-07-16 12:13:36 -040049 # Let's pass some unencrypted data to make sure our socket connection is
50 # fine. Just one byte, so we don't have to worry about buffers getting
51 # filled up or fragmentation.
52 server.send("x")
53 assert client.recv(1024) == "x"
54 client.send("y")
55 assert server.recv(1024) == "y"
Rick Deanb1ccd562009-07-09 23:52:39 -050056
Jean-Paul Calderone94b24a82009-07-16 19:11:38 -040057 # All our callers want non-blocking sockets, make it easy for them.
58 server.setblocking(False)
59 client.setblocking(False)
60
Rick Deanb1ccd562009-07-09 23:52:39 -050061 return (server, client)
62
63
Jean-Paul Calderone94b24a82009-07-16 19:11:38 -040064
Jean-Paul Calderone18808652009-07-05 12:54:05 -040065class ContextTests(TestCase):
Jean-Paul Calderone30c09ea2008-03-21 17:04:05 -040066 """
67 Unit tests for L{OpenSSL.SSL.Context}.
68 """
69 def test_method(self):
70 """
71 L{Context} can be instantiated with one of L{SSLv2_METHOD},
72 L{SSLv3_METHOD}, L{SSLv23_METHOD}, or L{TLSv1_METHOD}.
73 """
74 for meth in [SSLv2_METHOD, SSLv3_METHOD, SSLv23_METHOD, TLSv1_METHOD]:
75 Context(meth)
76 self.assertRaises(TypeError, Context, "")
77 self.assertRaises(ValueError, Context, 10)
78
79
Rick Deane15b1472009-07-09 15:53:42 -050080 def test_type(self):
81 """
Jean-Paul Calderone68649052009-07-17 21:14:27 -040082 L{Context} and L{ContextType} refer to the same type object and can be
83 used to create instances of that type.
Rick Deane15b1472009-07-09 15:53:42 -050084 """
Jean-Paul Calderone68649052009-07-17 21:14:27 -040085 self.assertIdentical(Context, ContextType)
86 self.assertConsistentType(Context, 'Context', TLSv1_METHOD)
Rick Deane15b1472009-07-09 15:53:42 -050087
88
Jean-Paul Calderone30c09ea2008-03-21 17:04:05 -040089 def test_use_privatekey(self):
90 """
91 L{Context.use_privatekey} takes an L{OpenSSL.crypto.PKey} instance.
92 """
93 key = PKey()
94 key.generate_key(TYPE_RSA, 128)
95 ctx = Context(TLSv1_METHOD)
96 ctx.use_privatekey(key)
97 self.assertRaises(TypeError, ctx.use_privatekey, "")
Jean-Paul Calderone828c9cb2008-04-26 18:06:54 -040098
99
100 def test_set_passwd_cb(self):
101 """
102 L{Context.set_passwd_cb} accepts a callable which will be invoked when
103 a private key is loaded from an encrypted PEM.
104 """
105 key = PKey()
106 key.generate_key(TYPE_RSA, 128)
107 pemFile = self.mktemp()
108 fObj = file(pemFile, 'w')
109 passphrase = "foobar"
110 fObj.write(dump_privatekey(FILETYPE_PEM, key, "blowfish", passphrase))
111 fObj.close()
112
113 calledWith = []
114 def passphraseCallback(maxlen, verify, extra):
115 calledWith.append((maxlen, verify, extra))
116 return passphrase
117 context = Context(TLSv1_METHOD)
118 context.set_passwd_cb(passphraseCallback)
119 context.use_privatekey_file(pemFile)
120 self.assertTrue(len(calledWith), 1)
121 self.assertTrue(isinstance(calledWith[0][0], int))
122 self.assertTrue(isinstance(calledWith[0][1], int))
123 self.assertEqual(calledWith[0][2], None)
Jean-Paul Calderone5ef86512008-04-26 19:06:28 -0400124
125
126 def test_set_info_callback(self):
127 """
128 L{Context.set_info_callback} accepts a callable which will be invoked
129 when certain information about an SSL connection is available.
130 """
Rick Deanb1ccd562009-07-09 23:52:39 -0500131 (server, client) = socket_pair()
Jean-Paul Calderone5ef86512008-04-26 19:06:28 -0400132
133 clientSSL = Connection(Context(TLSv1_METHOD), client)
134 clientSSL.set_connect_state()
135
136 called = []
137 def info(conn, where, ret):
138 called.append((conn, where, ret))
139 context = Context(TLSv1_METHOD)
140 context.set_info_callback(info)
141 context.use_certificate(
142 load_certificate(FILETYPE_PEM, cleartextCertificatePEM))
143 context.use_privatekey(
144 load_privatekey(FILETYPE_PEM, cleartextPrivateKeyPEM))
145
Jean-Paul Calderone5ef86512008-04-26 19:06:28 -0400146 serverSSL = Connection(context, server)
147 serverSSL.set_accept_state()
148
149 while not called:
150 for ssl in clientSSL, serverSSL:
151 try:
152 ssl.do_handshake()
153 except WantReadError:
154 pass
155
156 # Kind of lame. Just make sure it got called somehow.
157 self.assertTrue(called)
Jean-Paul Calderonee1bd4322008-09-07 20:17:17 -0400158
159
Jean-Paul Calderone1cb5d022008-09-07 20:58:50 -0400160 def _load_verify_locations_test(self, *args):
Rick Deanb1ccd562009-07-09 23:52:39 -0500161 (server, client) = socket_pair()
Jean-Paul Calderonee1bd4322008-09-07 20:17:17 -0400162
Jean-Paul Calderonee1bd4322008-09-07 20:17:17 -0400163 clientContext = Context(TLSv1_METHOD)
Jean-Paul Calderone1cb5d022008-09-07 20:58:50 -0400164 clientContext.load_verify_locations(*args)
Jean-Paul Calderonee1bd4322008-09-07 20:17:17 -0400165 # Require that the server certificate verify properly or the
166 # connection will fail.
167 clientContext.set_verify(
168 VERIFY_PEER,
169 lambda conn, cert, errno, depth, preverify_ok: preverify_ok)
170
171 clientSSL = Connection(clientContext, client)
172 clientSSL.set_connect_state()
173
Jean-Paul Calderonee1bd4322008-09-07 20:17:17 -0400174 serverContext = Context(TLSv1_METHOD)
175 serverContext.use_certificate(
176 load_certificate(FILETYPE_PEM, cleartextCertificatePEM))
177 serverContext.use_privatekey(
178 load_privatekey(FILETYPE_PEM, cleartextPrivateKeyPEM))
179
180 serverSSL = Connection(serverContext, server)
181 serverSSL.set_accept_state()
182
183 for i in range(3):
184 for ssl in clientSSL, serverSSL:
185 try:
186 # Without load_verify_locations above, the handshake
187 # will fail:
188 # Error: [('SSL routines', 'SSL3_GET_SERVER_CERTIFICATE',
189 # 'certificate verify failed')]
190 ssl.do_handshake()
191 except WantReadError:
192 pass
193
194 cert = clientSSL.get_peer_certificate()
Jean-Paul Calderone20131f52009-04-01 12:05:45 -0400195 self.assertEqual(cert.get_subject().CN, 'Testing Root CA')
Jean-Paul Calderone5075fce2008-09-07 20:18:55 -0400196
Jean-Paul Calderone12608a82009-11-07 10:35:15 -0500197
Jean-Paul Calderone1cb5d022008-09-07 20:58:50 -0400198 def test_load_verify_file(self):
199 """
200 L{Context.load_verify_locations} accepts a file name and uses the
201 certificates within for verification purposes.
202 """
203 cafile = self.mktemp()
204 fObj = file(cafile, 'w')
205 fObj.write(cleartextCertificatePEM)
206 fObj.close()
207
208 self._load_verify_locations_test(cafile)
209
Jean-Paul Calderone5075fce2008-09-07 20:18:55 -0400210
211 def test_load_verify_invalid_file(self):
212 """
213 L{Context.load_verify_locations} raises L{Error} when passed a
214 non-existent cafile.
215 """
216 clientContext = Context(TLSv1_METHOD)
217 self.assertRaises(
218 Error, clientContext.load_verify_locations, self.mktemp())
Jean-Paul Calderone1cb5d022008-09-07 20:58:50 -0400219
220
221 def test_load_verify_directory(self):
222 """
223 L{Context.load_verify_locations} accepts a directory name and uses
224 the certificates within for verification purposes.
225 """
226 capath = self.mktemp()
227 makedirs(capath)
Jean-Paul Calderonea65cf6c2009-07-19 10:26:52 -0400228 # Hash value computed manually with c_rehash to avoid depending on
229 # c_rehash in the test suite.
230 cafile = join(capath, 'c7adac82.0')
Jean-Paul Calderone1cb5d022008-09-07 20:58:50 -0400231 fObj = file(cafile, 'w')
232 fObj.write(cleartextCertificatePEM)
233 fObj.close()
234
Jean-Paul Calderone1cb5d022008-09-07 20:58:50 -0400235 self._load_verify_locations_test(None, capath)
236
237
Jean-Paul Calderone28fb8f02009-07-24 18:01:31 -0400238 if platform in ("darwin", "win32"):
239 "set_default_verify_paths appears not to work on OS X or Windows"
240 "See LP#404343 and LP#404344."
241 else:
242 def test_set_default_verify_paths(self):
243 """
244 L{Context.set_default_verify_paths} causes the platform-specific CA
245 certificate locations to be used for verification purposes.
246 """
247 # Testing this requires a server with a certificate signed by one of
248 # the CAs in the platform CA location. Getting one of those costs
249 # money. Fortunately (or unfortunately, depending on your
250 # perspective), it's easy to think of a public server on the
251 # internet which has such a certificate. Connecting to the network
252 # in a unit test is bad, but it's the only way I can think of to
253 # really test this. -exarkun
Jean-Paul Calderone1cb5d022008-09-07 20:58:50 -0400254
Jean-Paul Calderone28fb8f02009-07-24 18:01:31 -0400255 # Arg, verisign.com doesn't speak TLSv1
256 context = Context(SSLv3_METHOD)
257 context.set_default_verify_paths()
258 context.set_verify(
Ziga Seilnacht44611bf2009-08-31 20:49:30 +0200259 VERIFY_PEER,
Jean-Paul Calderone28fb8f02009-07-24 18:01:31 -0400260 lambda conn, cert, errno, depth, preverify_ok: preverify_ok)
Jean-Paul Calderone1cb5d022008-09-07 20:58:50 -0400261
Jean-Paul Calderone28fb8f02009-07-24 18:01:31 -0400262 client = socket()
263 client.connect(('verisign.com', 443))
264 clientSSL = Connection(context, client)
265 clientSSL.set_connect_state()
266 clientSSL.do_handshake()
267 clientSSL.send('GET / HTTP/1.0\r\n\r\n')
268 self.assertTrue(clientSSL.recv(1024))
Jean-Paul Calderone9eadb962008-09-07 21:20:44 -0400269
270
271 def test_set_default_verify_paths_signature(self):
272 """
273 L{Context.set_default_verify_paths} takes no arguments and raises
274 L{TypeError} if given any.
275 """
276 context = Context(TLSv1_METHOD)
277 self.assertRaises(TypeError, context.set_default_verify_paths, None)
278 self.assertRaises(TypeError, context.set_default_verify_paths, 1)
279 self.assertRaises(TypeError, context.set_default_verify_paths, "")
Jean-Paul Calderone327d8f92008-12-28 21:55:56 -0500280
Jean-Paul Calderone12608a82009-11-07 10:35:15 -0500281 def test_add_extra_chain_cert_invalid_cert(self):
282 """
283 L{Context.add_extra_chain_cert} raises L{TypeError} if called with
284 other than one argument or if called with an object which is not an
285 instance of L{X509}.
286 """
287 context = Context(TLSv1_METHOD)
288 self.assertRaises(TypeError, context.add_extra_chain_cert)
289 self.assertRaises(TypeError, context.add_extra_chain_cert, object())
290 self.assertRaises(TypeError, context.add_extra_chain_cert, object(), object())
291
292
293 def test_add_extra_chain_cert(self):
294 """
295 L{Context.add_extra_chain_cert} accepts an L{X509} instance to add to
296 the certificate chain.
297 """
298 context = Context(TLSv1_METHOD)
299 context.add_extra_chain_cert(load_certificate(FILETYPE_PEM, cleartextCertificatePEM))
300 # XXX Oh no, actually asserting something about its behavior would be really hard.
301 # See #477521.
302
Jean-Paul Calderone327d8f92008-12-28 21:55:56 -0500303
304
Rick Deane15b1472009-07-09 15:53:42 -0500305class ConnectionTests(TestCase):
306 """
307 Unit tests for L{OpenSSL.SSL.Connection}.
308 """
309 def test_type(self):
310 """
Jean-Paul Calderone68649052009-07-17 21:14:27 -0400311 L{Connection} and L{ConnectionType} refer to the same type object and
312 can be used to create instances of that type.
Rick Deane15b1472009-07-09 15:53:42 -0500313 """
Jean-Paul Calderone68649052009-07-17 21:14:27 -0400314 self.assertIdentical(Connection, ConnectionType)
Rick Deane15b1472009-07-09 15:53:42 -0500315 ctx = Context(TLSv1_METHOD)
Jean-Paul Calderone68649052009-07-17 21:14:27 -0400316 self.assertConsistentType(Connection, 'Connection', ctx, None)
Rick Deane15b1472009-07-09 15:53:42 -0500317
Jean-Paul Calderone68649052009-07-17 21:14:27 -0400318
Jean-Paul Calderone4fd058a2009-11-22 11:46:42 -0500319 def test_get_context(self):
320 """
321 L{Connection.get_context} returns the L{Context} instance used to
322 construct the L{Connection} instance.
323 """
324 context = Context(TLSv1_METHOD)
325 connection = Connection(context, None)
326 self.assertIdentical(connection.get_context(), context)
327
328
329 def test_get_context_wrong_args(self):
330 """
331 L{Connection.get_context} raises L{TypeError} if called with any
332 arguments.
333 """
334 connection = Connection(Context(TLSv1_METHOD), None)
335 self.assertRaises(TypeError, connection.get_context, None)
336
337
Jean-Paul Calderone68649052009-07-17 21:14:27 -0400338
339class ErrorTests(TestCase):
340 """
341 Unit tests for L{OpenSSL.SSL.Error}.
342 """
343 def test_type(self):
344 """
345 L{Error} is an exception type.
346 """
347 self.assertTrue(issubclass(Error, Exception))
Rick Deane15b1472009-07-09 15:53:42 -0500348 self.assertEqual(Error.__name__, 'Error')
Rick Deane15b1472009-07-09 15:53:42 -0500349
350
351
Jean-Paul Calderone327d8f92008-12-28 21:55:56 -0500352class ConstantsTests(TestCase):
353 """
354 Tests for the values of constants exposed in L{OpenSSL.SSL}.
355
356 These are values defined by OpenSSL intended only to be used as flags to
357 OpenSSL APIs. The only assertions it seems can be made about them is
358 their values.
359 """
Jean-Paul Calderoned811b682008-12-28 22:59:15 -0500360 # unittest.TestCase has no skip mechanism
361 if OP_NO_QUERY_MTU is not None:
362 def test_op_no_query_mtu(self):
363 """
364 The value of L{OpenSSL.SSL.OP_NO_QUERY_MTU} is 0x1000, the value of
365 I{SSL_OP_NO_QUERY_MTU} defined by I{openssl/ssl.h}.
366 """
367 self.assertEqual(OP_NO_QUERY_MTU, 0x1000)
368 else:
369 "OP_NO_QUERY_MTU unavailable - OpenSSL version may be too old"
Jean-Paul Calderone327d8f92008-12-28 21:55:56 -0500370
371
Jean-Paul Calderoned811b682008-12-28 22:59:15 -0500372 if OP_COOKIE_EXCHANGE is not None:
373 def test_op_cookie_exchange(self):
374 """
375 The value of L{OpenSSL.SSL.OP_COOKIE_EXCHANGE} is 0x2000, the value
376 of I{SSL_OP_COOKIE_EXCHANGE} defined by I{openssl/ssl.h}.
377 """
378 self.assertEqual(OP_COOKIE_EXCHANGE, 0x2000)
379 else:
380 "OP_COOKIE_EXCHANGE unavailable - OpenSSL version may be too old"
Jean-Paul Calderone327d8f92008-12-28 21:55:56 -0500381
382
Jean-Paul Calderoned811b682008-12-28 22:59:15 -0500383 if OP_NO_TICKET is not None:
384 def test_op_no_ticket(self):
385 """
386 The value of L{OpenSSL.SSL.OP_NO_TICKET} is 0x4000, the value of
387 I{SSL_OP_NO_TICKET} defined by I{openssl/ssl.h}.
388 """
389 self.assertEqual(OP_NO_TICKET, 0x4000)
390 else:
391 "OP_NO_TICKET unavailable - OpenSSL version may be too old"
Rick Dean5b7b6372009-04-01 11:34:06 -0500392
393
Jean-Paul Calderoneeeee26a2009-04-27 11:24:30 -0400394
Rick Deanb71c0d22009-04-01 14:09:23 -0500395def verify_cb(conn, cert, errnum, depth, ok):
396 return ok
397
Jean-Paul Calderone958299e2009-04-27 12:59:12 -0400398class MemoryBIOTests(TestCase):
Rick Deanb71c0d22009-04-01 14:09:23 -0500399 """
Jean-Paul Calderone958299e2009-04-27 12:59:12 -0400400 Tests for L{OpenSSL.SSL.Connection} using a memory BIO.
Rick Deanb71c0d22009-04-01 14:09:23 -0500401 """
Jean-Paul Calderonece8324d2009-07-16 12:22:52 -0400402 def _server(self, sock):
403 """
404 Create a new server-side SSL L{Connection} object wrapped around
405 C{sock}.
406 """
Jean-Paul Calderoneaff0fc42009-04-27 17:13:34 -0400407 # Create the server side Connection. This is mostly setup boilerplate
408 # - use TLSv1, use a particular certificate, etc.
409 server_ctx = Context(TLSv1_METHOD)
410 server_ctx.set_options(OP_NO_SSLv2 | OP_NO_SSLv3 | OP_SINGLE_DH_USE )
411 server_ctx.set_verify(VERIFY_PEER|VERIFY_FAIL_IF_NO_PEER_CERT|VERIFY_CLIENT_ONCE, verify_cb)
412 server_store = server_ctx.get_cert_store()
413 server_ctx.use_privatekey(load_privatekey(FILETYPE_PEM, server_key_pem))
414 server_ctx.use_certificate(load_certificate(FILETYPE_PEM, server_cert_pem))
415 server_ctx.check_privatekey()
416 server_store.add_cert(load_certificate(FILETYPE_PEM, root_cert_pem))
Rick Deanb1ccd562009-07-09 23:52:39 -0500417 # Here the Connection is actually created. If None is passed as the 2nd
418 # parameter, it indicates a memory BIO should be created.
419 server_conn = Connection(server_ctx, sock)
Jean-Paul Calderoneaff0fc42009-04-27 17:13:34 -0400420 server_conn.set_accept_state()
421 return server_conn
422
423
Jean-Paul Calderonece8324d2009-07-16 12:22:52 -0400424 def _client(self, sock):
425 """
426 Create a new client-side SSL L{Connection} object wrapped around
427 C{sock}.
428 """
429 # Now create the client side Connection. Similar boilerplate to the
430 # above.
Jean-Paul Calderoneaff0fc42009-04-27 17:13:34 -0400431 client_ctx = Context(TLSv1_METHOD)
432 client_ctx.set_options(OP_NO_SSLv2 | OP_NO_SSLv3 | OP_SINGLE_DH_USE )
433 client_ctx.set_verify(VERIFY_PEER|VERIFY_FAIL_IF_NO_PEER_CERT|VERIFY_CLIENT_ONCE, verify_cb)
434 client_store = client_ctx.get_cert_store()
435 client_ctx.use_privatekey(load_privatekey(FILETYPE_PEM, client_key_pem))
436 client_ctx.use_certificate(load_certificate(FILETYPE_PEM, client_cert_pem))
437 client_ctx.check_privatekey()
438 client_store.add_cert(load_certificate(FILETYPE_PEM, root_cert_pem))
Rick Deanb1ccd562009-07-09 23:52:39 -0500439 client_conn = Connection(client_ctx, sock)
Jean-Paul Calderoneaff0fc42009-04-27 17:13:34 -0400440 client_conn.set_connect_state()
441 return client_conn
442
443
Jean-Paul Calderone958299e2009-04-27 12:59:12 -0400444 def _loopback(self, client_conn, server_conn):
445 """
446 Try to read application bytes from each of the two L{Connection}
447 objects. Copy bytes back and forth between their send/receive buffers
448 for as long as there is anything to copy. When there is nothing more
449 to copy, return C{None}. If one of them actually manages to deliver
450 some application bytes, return a two-tuple of the connection from which
451 the bytes were read and the bytes themselves.
452 """
453 wrote = True
454 while wrote:
455 # Loop until neither side has anything to say
456 wrote = False
457
458 # Copy stuff from each side's send buffer to the other side's
459 # receive buffer.
460 for (read, write) in [(client_conn, server_conn),
461 (server_conn, client_conn)]:
462
463 # Give the side a chance to generate some more bytes, or
464 # succeed.
465 try:
Jean-Paul Calderoneaff0fc42009-04-27 17:13:34 -0400466 bytes = read.recv(2 ** 16)
Jean-Paul Calderone958299e2009-04-27 12:59:12 -0400467 except WantReadError:
468 # It didn't succeed, so we'll hope it generated some
469 # output.
470 pass
471 else:
472 # It did succeed, so we'll stop now and let the caller deal
473 # with it.
474 return (read, bytes)
475
476 while True:
477 # Keep copying as long as there's more stuff there.
478 try:
479 dirty = read.bio_read(4096)
480 except WantReadError:
481 # Okay, nothing more waiting to be sent. Stop
482 # processing this send buffer.
483 break
484 else:
485 # Keep track of the fact that someone generated some
486 # output.
487 wrote = True
488 write.bio_write(dirty)
489
490
Jean-Paul Calderonece8324d2009-07-16 12:22:52 -0400491 def test_memoryConnect(self):
Jean-Paul Calderone958299e2009-04-27 12:59:12 -0400492 """
493 Two L{Connection}s which use memory BIOs can be manually connected by
494 reading from the output of each and writing those bytes to the input of
495 the other and in this way establish a connection and exchange
496 application-level bytes with each other.
497 """
Jean-Paul Calderonece8324d2009-07-16 12:22:52 -0400498 server_conn = self._server(None)
499 client_conn = self._client(None)
Rick Deanb71c0d22009-04-01 14:09:23 -0500500
Jean-Paul Calderone958299e2009-04-27 12:59:12 -0400501 # There should be no key or nonces yet.
502 self.assertIdentical(server_conn.master_key(), None)
503 self.assertIdentical(server_conn.client_random(), None)
504 self.assertIdentical(server_conn.server_random(), None)
Rick Deanb71c0d22009-04-01 14:09:23 -0500505
Jean-Paul Calderone958299e2009-04-27 12:59:12 -0400506 # First, the handshake needs to happen. We'll deliver bytes back and
507 # forth between the client and server until neither of them feels like
508 # speaking any more.
509 self.assertIdentical(self._loopback(client_conn, server_conn), None)
510
511 # Now that the handshake is done, there should be a key and nonces.
512 self.assertNotIdentical(server_conn.master_key(), None)
513 self.assertNotIdentical(server_conn.client_random(), None)
514 self.assertNotIdentical(server_conn.server_random(), None)
Jean-Paul Calderone6c051e62009-07-05 13:50:34 -0400515 self.assertEquals(server_conn.client_random(), client_conn.client_random())
516 self.assertEquals(server_conn.server_random(), client_conn.server_random())
517 self.assertNotEquals(server_conn.client_random(), server_conn.server_random())
518 self.assertNotEquals(client_conn.client_random(), client_conn.server_random())
Jean-Paul Calderone958299e2009-04-27 12:59:12 -0400519
520 # Here are the bytes we'll try to send.
Rick Deanb71c0d22009-04-01 14:09:23 -0500521 important_message = 'One if by land, two if by sea.'
522
Jean-Paul Calderone958299e2009-04-27 12:59:12 -0400523 server_conn.write(important_message)
524 self.assertEquals(
525 self._loopback(client_conn, server_conn),
526 (client_conn, important_message))
527
528 client_conn.write(important_message[::-1])
529 self.assertEquals(
530 self._loopback(client_conn, server_conn),
531 (server_conn, important_message[::-1]))
Rick Deanb71c0d22009-04-01 14:09:23 -0500532
533
Jean-Paul Calderonece8324d2009-07-16 12:22:52 -0400534 def test_socketConnect(self):
Rick Deanb1ccd562009-07-09 23:52:39 -0500535 """
Jean-Paul Calderonece8324d2009-07-16 12:22:52 -0400536 Just like L{test_memoryConnect} but with an actual socket.
537
538 This is primarily to rule out the memory BIO code as the source of
539 any problems encountered while passing data over a L{Connection} (if
540 this test fails, there must be a problem outside the memory BIO
541 code, as no memory BIO is involved here). Even though this isn't a
542 memory BIO test, it's convenient to have it here.
Rick Deanb1ccd562009-07-09 23:52:39 -0500543 """
544 (server, client) = socket_pair()
545
546 # Let the encryption begin...
547 client_conn = self._client(client)
Rick Deanb1ccd562009-07-09 23:52:39 -0500548 server_conn = self._server(server)
Jean-Paul Calderone7903cbd2009-07-16 12:23:34 -0400549
Rick Deanb1ccd562009-07-09 23:52:39 -0500550 # Establish the connection
551 established = False
552 while not established:
553 established = True # assume the best
554 for ssl in client_conn, server_conn:
555 try:
Ziga Seilnacht44611bf2009-08-31 20:49:30 +0200556 # Generally a recv() or send() could also work instead
557 # of do_handshake(), and we would stop on the first
Rick Deanb1ccd562009-07-09 23:52:39 -0500558 # non-exception.
559 ssl.do_handshake()
560 except WantReadError:
561 established = False
562
563 important_message = "Help me Obi Wan Kenobi, you're my only hope."
564 client_conn.send(important_message)
565 msg = server_conn.recv(1024)
566 self.assertEqual(msg, important_message)
567
568 # Again in the other direction, just for fun.
569 important_message = important_message[::-1]
570 server_conn.send(important_message)
571 msg = client_conn.recv(1024)
572 self.assertEqual(msg, important_message)
573
574
Jean-Paul Calderonefc4ed0f2009-04-27 11:51:27 -0400575 def test_socketOverridesMemory(self):
Rick Deanb71c0d22009-04-01 14:09:23 -0500576 """
577 Test that L{OpenSSL.SSL.bio_read} and L{OpenSSL.SSL.bio_write} don't
578 work on L{OpenSSL.SSL.Connection}() that use sockets.
579 """
580 context = Context(SSLv3_METHOD)
581 client = socket()
582 clientSSL = Connection(context, client)
583 self.assertRaises( TypeError, clientSSL.bio_read, 100)
584 self.assertRaises( TypeError, clientSSL.bio_write, "foo")
Jean-Paul Calderone07acf3f2009-05-05 13:23:28 -0400585 self.assertRaises( TypeError, clientSSL.bio_shutdown )
Jean-Paul Calderoneaff0fc42009-04-27 17:13:34 -0400586
587
588 def test_outgoingOverflow(self):
589 """
590 If more bytes than can be written to the memory BIO are passed to
591 L{Connection.send} at once, the number of bytes which were written is
592 returned and that many bytes from the beginning of the input can be
593 read from the other end of the connection.
594 """
Jean-Paul Calderonece8324d2009-07-16 12:22:52 -0400595 server = self._server(None)
596 client = self._client(None)
Jean-Paul Calderoneaff0fc42009-04-27 17:13:34 -0400597
598 self._loopback(client, server)
599
600 size = 2 ** 15
601 sent = client.send("x" * size)
602 # Sanity check. We're trying to test what happens when the entire
603 # input can't be sent. If the entire input was sent, this test is
604 # meaningless.
605 self.assertTrue(sent < size)
606
607 receiver, received = self._loopback(client, server)
608 self.assertIdentical(receiver, server)
609
610 # We can rely on all of these bytes being received at once because
611 # _loopback passes 2 ** 16 to recv - more than 2 ** 15.
612 self.assertEquals(len(received), sent)
Jean-Paul Calderone3ad85d42009-04-30 20:24:35 -0400613
614
615 def test_shutdown(self):
616 """
617 L{Connection.bio_shutdown} signals the end of the data stream from
618 which the L{Connection} reads.
619 """
Jean-Paul Calderonece8324d2009-07-16 12:22:52 -0400620 server = self._server(None)
Jean-Paul Calderone3ad85d42009-04-30 20:24:35 -0400621 server.bio_shutdown()
622 e = self.assertRaises(Error, server.recv, 1024)
623 # We don't want WantReadError or ZeroReturnError or anything - it's a
624 # handshake failure.
625 self.assertEquals(e.__class__, Error)
Jean-Paul Calderone0b88b6a2009-07-05 12:44:41 -0400626
627
Ziga Seilnachtf93bf102009-10-23 09:51:07 +0200628 def _check_client_ca_list(self, func):
Jean-Paul Calderone911c9112009-10-24 11:12:00 -0400629 """
630 Verify the return value of the C{get_client_ca_list} method for server and client connections.
631
632 @param func: A function which will be called with the server context
633 before the client and server are connected to each other. This
634 function should specify a list of CAs for the server to send to the
635 client and return that same list. The list will be used to verify
636 that C{get_client_ca_list} returns the proper value at various
637 times.
638 """
Ziga Seilnacht679c4262009-09-01 01:32:29 +0200639 server = self._server(None)
640 client = self._client(None)
Ziga Seilnachtf93bf102009-10-23 09:51:07 +0200641 self.assertEqual(client.get_client_ca_list(), [])
642 self.assertEqual(server.get_client_ca_list(), [])
Ziga Seilnacht679c4262009-09-01 01:32:29 +0200643 ctx = server.get_context()
644 expected = func(ctx)
Ziga Seilnachtf93bf102009-10-23 09:51:07 +0200645 self.assertEqual(client.get_client_ca_list(), [])
646 self.assertEqual(server.get_client_ca_list(), expected)
Ziga Seilnacht679c4262009-09-01 01:32:29 +0200647 self._loopback(client, server)
Ziga Seilnachtf93bf102009-10-23 09:51:07 +0200648 self.assertEqual(client.get_client_ca_list(), expected)
649 self.assertEqual(server.get_client_ca_list(), expected)
Ziga Seilnacht679c4262009-09-01 01:32:29 +0200650
651
Jean-Paul Calderone911c9112009-10-24 11:12:00 -0400652 def test_set_client_ca_list_errors(self):
Ziga Seilnacht679c4262009-09-01 01:32:29 +0200653 """
Jean-Paul Calderone911c9112009-10-24 11:12:00 -0400654 L{Context.set_client_ca_list} raises a L{TypeError} if called with a
655 non-list or a list that contains objects other than X509Names.
Ziga Seilnacht679c4262009-09-01 01:32:29 +0200656 """
657 ctx = Context(TLSv1_METHOD)
Ziga Seilnachtf93bf102009-10-23 09:51:07 +0200658 self.assertRaises(TypeError, ctx.set_client_ca_list, "spam")
659 self.assertRaises(TypeError, ctx.set_client_ca_list, ["spam"])
660 self.assertIdentical(ctx.set_client_ca_list([]), None)
Ziga Seilnacht679c4262009-09-01 01:32:29 +0200661
662
Jean-Paul Calderone911c9112009-10-24 11:12:00 -0400663 def test_set_empty_ca_list(self):
Ziga Seilnacht679c4262009-09-01 01:32:29 +0200664 """
Jean-Paul Calderone911c9112009-10-24 11:12:00 -0400665 If passed an empty list, L{Context.set_client_ca_list} configures the
666 context to send no CA names to the client and, on both the server and
667 client sides, L{Connection.get_client_ca_list} returns an empty list
668 after the connection is set up.
669 """
670 def no_ca(ctx):
671 ctx.set_client_ca_list([])
672 return []
673 self._check_client_ca_list(no_ca)
674
675
676 def test_set_one_ca_list(self):
677 """
678 If passed a list containing a single X509Name,
679 L{Context.set_client_ca_list} configures the context to send that CA
680 name to the client and, on both the server and client sides,
681 L{Connection.get_client_ca_list} returns a list containing that
682 X509Name after the connection is set up.
683 """
684 cacert = load_certificate(FILETYPE_PEM, root_cert_pem)
685 cadesc = cacert.get_subject()
686 def single_ca(ctx):
687 ctx.set_client_ca_list([cadesc])
688 return [cadesc]
689 self._check_client_ca_list(single_ca)
690
691
692 def test_set_multiple_ca_list(self):
693 """
694 If passed a list containing multiple X509Name objects,
695 L{Context.set_client_ca_list} configures the context to send those CA
696 names to the client and, on both the server and client sides,
697 L{Connection.get_client_ca_list} returns a list containing those
698 X509Names after the connection is set up.
699 """
700 secert = load_certificate(FILETYPE_PEM, server_cert_pem)
701 clcert = load_certificate(FILETYPE_PEM, server_cert_pem)
702
703 sedesc = secert.get_subject()
704 cldesc = clcert.get_subject()
705
706 def multiple_ca(ctx):
707 L = [sedesc, cldesc]
708 ctx.set_client_ca_list(L)
709 return L
710 self._check_client_ca_list(multiple_ca)
711
712
713 def test_reset_ca_list(self):
714 """
715 If called multiple times, only the X509Names passed to the final call
716 of L{Context.set_client_ca_list} are used to configure the CA names
717 sent to the client.
Ziga Seilnacht679c4262009-09-01 01:32:29 +0200718 """
719 cacert = load_certificate(FILETYPE_PEM, root_cert_pem)
720 secert = load_certificate(FILETYPE_PEM, server_cert_pem)
721 clcert = load_certificate(FILETYPE_PEM, server_cert_pem)
722
723 cadesc = cacert.get_subject()
724 sedesc = secert.get_subject()
725 cldesc = clcert.get_subject()
726
Ziga Seilnachtf93bf102009-10-23 09:51:07 +0200727 def changed_ca(ctx):
728 ctx.set_client_ca_list([sedesc, cldesc])
729 ctx.set_client_ca_list([cadesc])
Ziga Seilnacht679c4262009-09-01 01:32:29 +0200730 return [cadesc]
Ziga Seilnachtf93bf102009-10-23 09:51:07 +0200731 self._check_client_ca_list(changed_ca)
Ziga Seilnacht679c4262009-09-01 01:32:29 +0200732
Jean-Paul Calderone911c9112009-10-24 11:12:00 -0400733
734 def test_mutated_ca_list(self):
735 """
736 If the list passed to L{Context.set_client_ca_list} is mutated
737 afterwards, this does not affect the list of CA names sent to the
738 client.
739 """
740 cacert = load_certificate(FILETYPE_PEM, root_cert_pem)
741 secert = load_certificate(FILETYPE_PEM, server_cert_pem)
742
743 cadesc = cacert.get_subject()
744 sedesc = secert.get_subject()
745
Ziga Seilnachtf93bf102009-10-23 09:51:07 +0200746 def mutated_ca(ctx):
Ziga Seilnacht679c4262009-09-01 01:32:29 +0200747 L = [cadesc]
Ziga Seilnachtf93bf102009-10-23 09:51:07 +0200748 ctx.set_client_ca_list([cadesc])
Ziga Seilnacht679c4262009-09-01 01:32:29 +0200749 L.append(sedesc)
750 return [cadesc]
Ziga Seilnachtf93bf102009-10-23 09:51:07 +0200751 self._check_client_ca_list(mutated_ca)
Ziga Seilnacht679c4262009-09-01 01:32:29 +0200752
753
Jean-Paul Calderone911c9112009-10-24 11:12:00 -0400754 def test_add_client_ca_errors(self):
Ziga Seilnacht679c4262009-09-01 01:32:29 +0200755 """
Jean-Paul Calderone911c9112009-10-24 11:12:00 -0400756 L{Context.add_client_ca} raises L{TypeError} if called with a non-X509
757 object or with a number of arguments other than one.
Ziga Seilnacht679c4262009-09-01 01:32:29 +0200758 """
759 ctx = Context(TLSv1_METHOD)
760 cacert = load_certificate(FILETYPE_PEM, root_cert_pem)
Jean-Paul Calderone911c9112009-10-24 11:12:00 -0400761 self.assertRaises(TypeError, ctx.add_client_ca)
Ziga Seilnachtf93bf102009-10-23 09:51:07 +0200762 self.assertRaises(TypeError, ctx.add_client_ca, "spam")
Jean-Paul Calderone911c9112009-10-24 11:12:00 -0400763 self.assertRaises(TypeError, ctx.add_client_ca, cacert, cacert)
Ziga Seilnacht679c4262009-09-01 01:32:29 +0200764
765
Jean-Paul Calderone055a9172009-10-24 13:45:11 -0400766 def test_one_add_client_ca(self):
Ziga Seilnacht679c4262009-09-01 01:32:29 +0200767 """
Jean-Paul Calderone055a9172009-10-24 13:45:11 -0400768 A certificate's subject can be added as a CA to be sent to the client
769 with L{Context.add_client_ca}.
770 """
771 cacert = load_certificate(FILETYPE_PEM, root_cert_pem)
772 cadesc = cacert.get_subject()
773 def single_ca(ctx):
774 ctx.add_client_ca(cacert)
775 return [cadesc]
776 self._check_client_ca_list(single_ca)
777
778
779 def test_multiple_add_client_ca(self):
780 """
781 Multiple CA names can be sent to the client by calling
782 L{Context.add_client_ca} with multiple X509 objects.
783 """
784 cacert = load_certificate(FILETYPE_PEM, root_cert_pem)
785 secert = load_certificate(FILETYPE_PEM, server_cert_pem)
786
787 cadesc = cacert.get_subject()
788 sedesc = secert.get_subject()
789
790 def multiple_ca(ctx):
791 ctx.add_client_ca(cacert)
792 ctx.add_client_ca(secert)
793 return [cadesc, sedesc]
794 self._check_client_ca_list(multiple_ca)
795
796
797 def test_set_and_add_client_ca(self):
798 """
799 A call to L{Context.set_client_ca_list} followed by a call to
800 L{Context.add_client_ca} results in using the CA names from the first
801 call and the CA name from the second call.
Ziga Seilnacht679c4262009-09-01 01:32:29 +0200802 """
803 cacert = load_certificate(FILETYPE_PEM, root_cert_pem)
804 secert = load_certificate(FILETYPE_PEM, server_cert_pem)
805 clcert = load_certificate(FILETYPE_PEM, server_cert_pem)
806
807 cadesc = cacert.get_subject()
808 sedesc = secert.get_subject()
809 cldesc = clcert.get_subject()
810
Ziga Seilnachtf93bf102009-10-23 09:51:07 +0200811 def mixed_set_add_ca(ctx):
812 ctx.set_client_ca_list([cadesc, sedesc])
813 ctx.add_client_ca(clcert)
Ziga Seilnacht679c4262009-09-01 01:32:29 +0200814 return [cadesc, sedesc, cldesc]
Ziga Seilnachtf93bf102009-10-23 09:51:07 +0200815 self._check_client_ca_list(mixed_set_add_ca)
Ziga Seilnacht679c4262009-09-01 01:32:29 +0200816
Jean-Paul Calderone055a9172009-10-24 13:45:11 -0400817
818 def test_set_after_add_client_ca(self):
819 """
820 A call to L{Context.set_client_ca_list} after a call to
821 L{Context.add_client_ca} replaces the CA name specified by the former
822 call with the names specified by the latter cal.
823 """
824 cacert = load_certificate(FILETYPE_PEM, root_cert_pem)
825 secert = load_certificate(FILETYPE_PEM, server_cert_pem)
826 clcert = load_certificate(FILETYPE_PEM, server_cert_pem)
827
828 cadesc = cacert.get_subject()
829 sedesc = secert.get_subject()
830 cldesc = clcert.get_subject()
831
Ziga Seilnachtf93bf102009-10-23 09:51:07 +0200832 def set_replaces_add_ca(ctx):
833 ctx.add_client_ca(clcert)
834 ctx.set_client_ca_list([cadesc])
835 ctx.add_client_ca(secert)
Ziga Seilnacht679c4262009-09-01 01:32:29 +0200836 return [cadesc, sedesc]
Ziga Seilnachtf93bf102009-10-23 09:51:07 +0200837 self._check_client_ca_list(set_replaces_add_ca)
Ziga Seilnacht679c4262009-09-01 01:32:29 +0200838
Jean-Paul Calderone0b88b6a2009-07-05 12:44:41 -0400839
Ziga Seilnacht44611bf2009-08-31 20:49:30 +0200840
Jean-Paul Calderone0b88b6a2009-07-05 12:44:41 -0400841if __name__ == '__main__':
842 main()